Individual Origins + Normal = Broken Again (works in 2.90, broken in 2.83 LTS) #78424

Closed
opened 2020-06-29 09:41:10 +02:00 by Eugene Du · 14 comments

System Information
Operating system: Windows-10-10.0.18362-SP0 64 Bits
Graphics card: GeForce GTX 1650 SUPER/PCIe/SSE2 NVIDIA Corporation 4.5.0 NVIDIA 446.14

Blender Version
Broken: version: 2.83.2
Worked: version: 2.90.0 Alpha, branch: master, commit date: 2020-06-26 17:24, hash: b7b57e7155

Short description of error
Individual Origins with Transform Orientation "Normal" partially broken in 2.83 and work as expected in 2.90.

Exact steps for others to reproduce the error
updated post below

**System Information** Operating system: Windows-10-10.0.18362-SP0 64 Bits Graphics card: GeForce GTX 1650 SUPER/PCIe/SSE2 NVIDIA Corporation 4.5.0 NVIDIA 446.14 **Blender Version** Broken: version: 2.83.2 Worked: version: 2.90.0 Alpha, branch: master, commit date: 2020-06-26 17:24, hash: `b7b57e7155` **Short description of error** Individual Origins with Transform Orientation "Normal" partially broken in 2.83 and work as expected in 2.90. **Exact steps for others to reproduce the error** updated post below
Author

Added subscriber: @APEC

Added subscriber: @APEC

Added subscriber: @dfelinto

Added subscriber: @dfelinto

Changed status from 'Needs Triage' to: 'Needs User Info'

Changed status from 'Needs Triage' to: 'Needs User Info'

Could you please specify a version where things were working as expected for you?

Could you please specify a version where things were working as expected for you?
Author

This comment was removed by @APEC

*This comment was removed by @APEC*
Author

This comment was removed by @APEC

*This comment was removed by @APEC*
Author

Need to update my observation because 2.83.2 is out

In 2.83.2 we can tweak Z parameter which is perpendicular to the normal, but tweaking it should do nothing in this case (with one face per selection)
2.83.2_individual_origin_bug.mp4
In 2.90.0 it work as expected
2.90.0_individual_origin_ok.mp4

Need to update my observation because 2.83.2 is out In 2.83.2 we can tweak Z parameter which is perpendicular to the normal, but tweaking it should do nothing in this case (with one face per selection) [2.83.2_individual_origin_bug.mp4](https://archive.blender.org/developer/F8684070/2.83.2_individual_origin_bug.mp4) In 2.90.0 it work as expected [2.90.0_individual_origin_ok.mp4](https://archive.blender.org/developer/F8684075/2.90.0_individual_origin_ok.mp4)
Campbell Barton changed title from Individual Origins + Normal = Broken Again to Individual Origins + Normal = Broken Again (works in 2.90, broken in 2.83 LTS) 2020-07-19 09:54:11 +02:00

Changed status from 'Needs User Info' to: 'Confirmed'

Changed status from 'Needs User Info' to: 'Confirmed'

Changed status from 'Confirmed' to: 'Resolved'

Changed status from 'Confirmed' to: 'Resolved'
Dalai Felinto self-assigned this 2020-07-22 09:58:21 +02:00

If it works in 2.90 then we consider it fixed as far as the tracker goes.

If you know the fix that solved that in 2.90 you can contact the LTS maintainer on #blender-coders in blender.chat to make sure he is aware of it (in case it is not listed on #77348)

If it works in 2.90 then we consider it fixed as far as the tracker goes. If you know the fix that solved that in 2.90 you can contact the LTS maintainer on #blender-coders in blender.chat to make sure he is aware of it (in case it is not listed on #77348)
Author

How to find fix that solved this bug? Because 2.83 get already two LTS updates and bug is still exist in 2.83.4...

How to find fix that solved this bug? Because 2.83 get already two LTS updates and bug is still exist in 2.83.4...
Member

Added subscribers: @mano-wii, @Jeroen-Bakker, @lichtwerk

Added subscribers: @mano-wii, @Jeroen-Bakker, @lichtwerk
Member

@Jeroen-Bakker : this was fixed between 13abd3784a and 375a50dad9

Candidates:
c57e4418bb
ea77584d36
185e1d5395

Talked to @mano-wii, maybe he can provide the neccessary info [code has been refactored here, so might have to make a separate patch for this]

@Jeroen-Bakker : this was fixed between 13abd3784a and 375a50dad9 Candidates: c57e4418bb ea77584d36 185e1d5395 Talked to @mano-wii, maybe he can provide the neccessary info [code has been refactored here, so might have to make a separate patch for this]

Here the patch with the fix for 2.83
P1606: Fix for #78424: Individual Origins + Normal

From 342945cf2c7bcabc8a5c62117b94284abe451452 Mon Sep 17 00:00:00 2001
From: Germano Cavalcante <germano.costa@ig.com.br>
Date: Wed, 26 Aug 2020 10:25:54 -0300
Subject: Transform Orientation Refactor


diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h
index beba4a7199b..403e7d79781 100644
--- a/source/blender/editors/include/ED_transform.h
+++ b/source/blender/editors/include/ED_transform.h
@@ -179,16 +179,16 @@ void ED_widgetgroup_gizmo2d_rotate_callbacks_set(struct wmGizmoGroupType *gzgt);
 #define SNAP_INCREMENTAL_ANGLE DEG2RAD(5.0)
 
 void ED_transform_calc_orientation_from_type(const struct bContext *C, float r_mat- [x][3]);
-void ED_transform_calc_orientation_from_type_ex(const struct bContext *C,
-                                                float r_mat- [x][3],
-                                                /* extra args */
-                                                struct Scene *scene,
-                                                struct RegionView3D *rv3d,
-                                                struct Object *ob,
-                                                struct Object *obedit,
-                                                const short orientation_type,
-                                                int orientation_index_custom,
-                                                const int pivot_point);
+short ED_transform_calc_orientation_from_type_ex(const struct bContext *C,
+                                                 float r_mat- [x][3],
+                                                 /* extra args */
+                                                 struct Scene *scene,
+                                                 struct RegionView3D *rv3d,
+                                                 struct Object *ob,
+                                                 struct Object *obedit,
+                                                 const short orientation_type,
+                                                 int orientation_index_custom,
+                                                 const int pivot_point);
 
 struct TransformBounds {
   float center- [x];      /* Center for transform widget. */
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index d0973cf8298..ae9b64acf93 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -779,9 +779,10 @@ wmKeyMap *transform_modal_keymap(wmKeyConfig *keyconf)
   return keymap;
 }
 
-static void transform_event_xyz_constraint(TransInfo *t, short key_type, char cmode, bool is_plane)
+static void transform_event_xyz_constraint(TransInfo *t, short key_type, bool is_plane)
 {
   if (!(t->flag & T_NO_CONSTRAINT)) {
+    char cmode = constraintModeToChar(t);
     int constraint_axis, constraint_plane;
     const bool edit_2d = (t->flag & T_2D_EDIT) != 0;
     const char *msg1 = "", *msg2 = "", *msg3 = "";
@@ -825,11 +826,17 @@ static void transform_event_xyz_constraint(TransInfo *t, short key_type, char cm
       }
     }
     else if (!edit_2d) {
-      if (cmode != axis) {
-        /* First press, constraint to an axis. */
-        t->orientation.index = 0;
-        const short *orientation_ptr = t->orientation.types[t->orientation.index];
-        const short orientation = orientation_ptr ? *orientation_ptr : V3D_ORIENT_GLOBAL;
+      if (t->orient_curr == 0 || ELEM(cmode, '\0', axis)) {
+        /* Successive presses on existing axis, cycle orientation modes. */
+        t->orient_curr = (short)((t->orient_curr + 1) % (int)ARRAY_SIZE(t->orient));
+        transform_orientations_current_set(t, t->orient_curr);
+      }
+
+      if (t->orient_curr == 0) {
+        stopConstraint(t);
+      }
+      else {
+        const short orientation = t->orient[t->orient_curr].type;
         if (is_plane == false) {
           setUserConstraint(t, orientation, constraint_axis, msg2);
         }
@@ -837,24 +844,6 @@ static void transform_event_xyz_constraint(TransInfo *t, short key_type, char cm
           setUserConstraint(t, orientation, constraint_plane, msg3);
         }
       }
-      else {
-        /* Successive presses on existing axis, cycle orientation modes. */
-        t->orientation.index = (t->orientation.index + 1) % ARRAY_SIZE(t->orientation.types);
-
-        if (t->orientation.index == 0) {
-          stopConstraint(t);
-        }
-        else {
-          const short *orientation_ptr = t->orientation.types[t->orientation.index];
-          const short orientation = orientation_ptr ? *orientation_ptr : V3D_ORIENT_GLOBAL;
-          if (is_plane == false) {
-            setUserConstraint(t, orientation, constraint_axis, msg2);
-          }
-          else {
-            setUserConstraint(t, orientation, constraint_plane, msg3);
-          }
-        }
-      }
     }
     t->redraw |= TREDRAW_HARD;
   }
@@ -862,7 +851,6 @@ static void transform_event_xyz_constraint(TransInfo *t, short key_type, char cm
 
 int transformEvent(TransInfo *t, const wmEvent *event)
 {
-  char cmode = constraintModeToChar(t);
   bool handled = false;
   const int modifiers_prev = t->modifiers;
   const int mode_prev = t->mode;
@@ -909,74 +897,59 @@ int transformEvent(TransInfo *t, const wmEvent *event)
         break;
       case TFM_MODAL_TRANSLATE:
         /* only switch when... */
-        if (ELEM(t->mode,
-                 TFM_ROTATION,
-                 TFM_RESIZE,
-                 TFM_TRACKBALL,
-                 TFM_EDGE_SLIDE,
-                 TFM_VERT_SLIDE)) {
-          restoreTransObjects(t);
-          resetTransModal(t);
-          resetTransRestrictions(t);
-          transform_mode_init(t, NULL, TFM_TRANSLATION);
-          initSnapping(t, NULL);  // need to reinit after mode change
-          t->redraw |= TREDRAW_HARD;
-          handled = true;
-        }
-        else if (t->mode == TFM_SEQ_SLIDE) {
-          t->flag ^= T_ALT_TRANSFORM;
-          t->redraw |= TREDRAW_HARD;
-          handled = true;
-        }
-        else {
-          if (t->obedit_type == OB_MESH) {
-            if ((t->mode == TFM_TRANSLATION) && (t->spacetype == SPACE_VIEW3D)) {
-              restoreTransObjects(t);
+        if (t->mode == TFM_TRANSLATION) {
+          if ((t->obedit_type == OB_MESH) && (t->spacetype == SPACE_VIEW3D)) {
+            restoreTransObjects(t);
+            resetTransModal(t);
+            resetTransRestrictions(t);
+
+            /* first try edge slide */
+            transform_mode_init(t, NULL, TFM_EDGE_SLIDE);
+            /* if that fails, do vertex slide */
+            if (t->state == TRANS_CANCEL) {
               resetTransModal(t);
+              t->state = TRANS_STARTING;
+              transform_mode_init(t, NULL, TFM_VERT_SLIDE);
+            }
+            /* vert slide can fail on unconnected vertices (rare but possible) */
+            if (t->state == TRANS_CANCEL) {
+              resetTransModal(t);
+              t->state = TRANS_STARTING;
+              restoreTransObjects(t);
               resetTransRestrictions(t);
-
-              /* first try edge slide */
-              transform_mode_init(t, NULL, TFM_EDGE_SLIDE);
-              /* if that fails, do vertex slide */
-              if (t->state == TRANS_CANCEL) {
-                resetTransModal(t);
-                t->state = TRANS_STARTING;
-                transform_mode_init(t, NULL, TFM_VERT_SLIDE);
-              }
-              /* vert slide can fail on unconnected vertices (rare but possible) */
-              if (t->state == TRANS_CANCEL) {
-                resetTransModal(t);
-                t->state = TRANS_STARTING;
-                restoreTransObjects(t);
-                resetTransRestrictions(t);
-                transform_mode_init(t, NULL, TFM_TRANSLATION);
-              }
-              initSnapping(t, NULL);  // need to reinit after mode change
-              t->redraw |= TREDRAW_HARD;
-              handled = true;
+              transform_mode_init(t, NULL, TFM_TRANSLATION);
             }
+            initSnapping(t, NULL);  // need to reinit after mode change
+            t->redraw |= TREDRAW_HARD;
+            handled = true;
           }
           else if (t->options & (CTX_MOVIECLIP | CTX_MASK)) {
-            if (t->mode == TFM_TRANSLATION) {
-              restoreTransObjects(t);
+            restoreTransObjects(t);
 
-              t->flag ^= T_ALT_TRANSFORM;
-              t->redraw |= TREDRAW_HARD;
-              handled = true;
-            }
+            t->flag ^= T_ALT_TRANSFORM;
+            t->redraw |= TREDRAW_HARD;
+            handled = true;
           }
         }
+        else if (t->mode == TFM_SEQ_SLIDE) {
+          t->flag ^= T_ALT_TRANSFORM;
+          t->redraw |= TREDRAW_HARD;
+          handled = true;
+        }
+        else if (transform_mode_is_changeable(t->mode)) {
+          restoreTransObjects(t);
+          resetTransModal(t);
+          resetTransRestrictions(t);
+          transform_mode_init(t, NULL, TFM_TRANSLATION);
+          initSnapping(t, NULL);  // need to reinit after mode change
+          t->redraw |= TREDRAW_HARD;
+          handled = true;
+        }
         break;
       case TFM_MODAL_ROTATE:
         /* only switch when... */
         if (!(t->options & CTX_TEXTURE) && !(t->options & (CTX_MOVIECLIP | CTX_MASK))) {
-          if (ELEM(t->mode,
-                   TFM_ROTATION,
-                   TFM_RESIZE,
-                   TFM_TRACKBALL,
-                   TFM_TRANSLATION,
-                   TFM_EDGE_SLIDE,
-                   TFM_VERT_SLIDE)) {
+          if (transform_mode_is_changeable(t->mode)) {
             restoreTransObjects(t);
             resetTransModal(t);
             resetTransRestrictions(t);
@@ -995,15 +968,23 @@ int transformEvent(TransInfo *t, const wmEvent *event)
         break;
       case TFM_MODAL_RESIZE:
         /* only switch when... */
-        if (ELEM(t->mode,
-                 TFM_ROTATION,
-                 TFM_TRANSLATION,
-                 TFM_TRACKBALL,
-                 TFM_EDGE_SLIDE,
-                 TFM_VERT_SLIDE)) {
+        if (t->mode == TFM_RESIZE) {
+          if (t->options & CTX_MOVIECLIP) {
+            restoreTransObjects(t);
 
+            t->flag ^= T_ALT_TRANSFORM;
+            t->redraw |= TREDRAW_HARD;
+            handled = true;
+          }
+        }
+        else if (t->mode == TFM_SHRINKFATTEN) {
+          t->flag ^= T_ALT_TRANSFORM;
+          t->redraw |= TREDRAW_HARD;
+          handled = true;
+        }
+        else if (transform_mode_is_changeable(t->mode)) {
           /* Scale isn't normally very useful after extrude along normals, see #39756 */
-          if ((t->con.mode & CON_APPLY) && (t->con.orientation == V3D_ORIENT_NORMAL)) {
+          if ((t->con.mode & CON_APPLY) && (t->orient[t->orient_curr].type == V3D_ORIENT_NORMAL)) {
             stopConstraint(t);
           }
 
@@ -1015,20 +996,6 @@ int transformEvent(TransInfo *t, const wmEvent *event)
           t->redraw |= TREDRAW_HARD;
           handled = true;
         }
-        else if (t->mode == TFM_SHRINKFATTEN) {
-          t->flag ^= T_ALT_TRANSFORM;
-          t->redraw |= TREDRAW_HARD;
-          handled = true;
-        }
-        else if (t->mode == TFM_RESIZE) {
-          if (t->options & CTX_MOVIECLIP) {
-            restoreTransObjects(t);
-
-            t->flag ^= T_ALT_TRANSFORM;
-            t->redraw |= TREDRAW_HARD;
-            handled = true;
-          }
-        }
         break;
 
       case TFM_MODAL_SNAP_INV_ON:
@@ -1048,42 +1015,42 @@ int transformEvent(TransInfo *t, const wmEvent *event)
         break;
       case TFM_MODAL_AXIS_X:
         if (!(t->flag & T_NO_CONSTRAINT)) {
-          transform_event_xyz_constraint(t, EVT_XKEY, cmode, false);
+          transform_event_xyz_constraint(t, EVT_XKEY, false);
           t->redraw |= TREDRAW_HARD;
           handled = true;
         }
         break;
       case TFM_MODAL_AXIS_Y:
         if ((t->flag & T_NO_CONSTRAINT) == 0) {
-          transform_event_xyz_constraint(t, EVT_YKEY, cmode, false);
+          transform_event_xyz_constraint(t, EVT_YKEY, false);
           t->redraw |= TREDRAW_HARD;
           handled = true;
         }
         break;
       case TFM_MODAL_AXIS_Z:
         if ((t->flag & (T_NO_CONSTRAINT)) == 0) {
-          transform_event_xyz_constraint(t, EVT_ZKEY, cmode, false);
+          transform_event_xyz_constraint(t, EVT_ZKEY, false);
           t->redraw |= TREDRAW_HARD;
           handled = true;
         }
         break;
       case TFM_MODAL_PLANE_X:
         if ((t->flag & (T_NO_CONSTRAINT | T_2D_EDIT)) == 0) {
-          transform_event_xyz_constraint(t, EVT_XKEY, cmode, true);
+          transform_event_xyz_constraint(t, EVT_XKEY, true);
           t->redraw |= TREDRAW_HARD;
           handled = true;
         }
         break;
       case TFM_MODAL_PLANE_Y:
         if ((t->flag & (T_NO_CONSTRAINT | T_2D_EDIT)) == 0) {
-          transform_event_xyz_constraint(t, EVT_YKEY, cmode, true);
+          transform_event_xyz_constraint(t, EVT_YKEY, true);
           t->redraw |= TREDRAW_HARD;
           handled = true;
         }
         break;
       case TFM_MODAL_PLANE_Z:
         if ((t->flag & (T_NO_CONSTRAINT | T_2D_EDIT)) == 0) {
-          transform_event_xyz_constraint(t, EVT_ZKEY, cmode, true);
+          transform_event_xyz_constraint(t, EVT_ZKEY, true);
           t->redraw |= TREDRAW_HARD;
           handled = true;
         }
@@ -1229,17 +1196,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
               stopConstraint(t);
             }
             else {
-              if (event->shift) {
-                /* bit hackish... but it prevents mmb select to print the
-                 * orientation from menu */
-                float mati- [x][3];
-                strcpy(t->spacename, "global");
-                unit_m3(mati);
-                initSelectConstraint(t, mati);
-              }
-              else {
-                initSelectConstraint(t, t->spacemtx);
-              }
+              initSelectConstraint(t);
               postSelectConstraint(t);
             }
           }
@@ -1252,7 +1209,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
           break;
         }
         /* only switch when... */
-        if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL)) {
+        if (t->mode != TFM_TRANSLATION && transform_mode_is_changeable(t->mode)) {
           restoreTransObjects(t);
           resetTransModal(t);
           resetTransRestrictions(t);
@@ -1267,7 +1224,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
           break;
         }
         /* only switch when... */
-        if (ELEM(t->mode, TFM_ROTATION, TFM_TRANSLATION, TFM_TRACKBALL)) {
+        if (t->mode != TFM_RESIZE && transform_mode_is_changeable(t->mode)) {
           restoreTransObjects(t);
           resetTransModal(t);
           resetTransRestrictions(t);
@@ -1283,7 +1240,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
         }
         /* only switch when... */
         if (!(t->options & CTX_TEXTURE)) {
-          if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_TRANSLATION)) {
+          if (transform_mode_is_changeable(t->mode)) {
             restoreTransObjects(t);
             resetTransModal(t);
             resetTransRestrictions(t);
@@ -1638,6 +1595,25 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
   int proportional = 0;
   PropertyRNA *prop;
 
+  if (!(t->con.mode & CON_APPLY) && (t->flag & T_MODAL) &&
+      ELEM(t->mode, TFM_TRANSLATION, TFM_RESIZE)) {
+    /* When redoing these modes the first time, it's more convenient to save
+     * in the Global orientation. */
+    if (t->mode == TFM_TRANSLATION) {
+      mul_m3_v3(t->spacemtx, t->values_final);
+    }
+    else {
+      float tmat- [x]- [x], sizemat- [x][3];
+      size_to_mat3(sizemat, t->values_final);
+      mul_m3_m3m3(tmat, t->spacemtx, sizemat);
+      mat3_to_size(t->values_final, tmat);
+    }
+
+    BLI_assert(t->orient_curr == 0);
+    unit_m3(t->spacemtx);
+    t->orient- [x].type = V3D_ORIENT_GLOBAL;
+  }
+
   // Save back mode in case we're in the generic operator
   if ((prop = RNA_struct_find_property(op->ptr, "mode"))) {
     RNA_property_enum_set(op->ptr, prop, t->mode);
@@ -1700,18 +1676,6 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
         ts->prop_mode = t->prop_mode;
       }
     }
-
-    if (t->spacetype == SPACE_VIEW3D) {
-      if ((prop = RNA_struct_find_property(op->ptr, "orient_type")) &&
-          !RNA_property_is_set(op->ptr, prop) &&
-          (t->orientation.user != V3D_ORIENT_CUSTOM_MATRIX)) {
-        TransformOrientationSlot *orient_slot = &t->scene->orientation_slots[SCE_ORIENT_DEFAULT];
-        orient_slot->type = t->orientation.user;
-        BLI_assert(((orient_slot->index_custom == -1) && (t->orientation.custom == NULL)) ||
-                   (BKE_scene_transform_orientation_get_index(t->scene, t->orientation.custom) ==
-                    orient_slot->index_custom));
-      }
-    }
   }
 
   if (t->flag & T_MODAL) {
@@ -1741,34 +1705,6 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
     RNA_property_boolean_set(op->ptr, prop, (t->flag & T_NO_MIRROR) == 0);
   }
 
-  /* Orientation used for redo. */
-  const bool use_orient_axis = (t->orient_matrix_is_set &&
-                                (RNA_struct_find_property(op->ptr, "orient_axis") != NULL));
-  short orientation;
-  if (t->con.mode & CON_APPLY) {
-    orientation = t->con.orientation;
-    if (orientation == V3D_ORIENT_CUSTOM) {
-      const int orientation_index_custom = BKE_scene_transform_orientation_get_index(
-          t->scene, t->orientation.custom);
-      /* Maybe we need a t->con.custom_orientation?
-       * Seems like it would always match t->orientation.custom. */
-      orientation = V3D_ORIENT_CUSTOM + orientation_index_custom;
-      BLI_assert(orientation >= V3D_ORIENT_CUSTOM);
-    }
-  }
-  else if ((t->orientation.user == V3D_ORIENT_CUSTOM_MATRIX) &&
-           (prop = RNA_struct_find_property(op->ptr, "orient_matrix_type"))) {
-    orientation = RNA_property_enum_get(op->ptr, prop);
-  }
-  else if (use_orient_axis) {
-    /* We're not using an orientation, use the fallback. */
-    orientation = t->orientation.unset;
-  }
-  else {
-    orientation = V3D_ORIENT_GLOBAL;
-    unit_m3(t->spacemtx);
-  }
-
   if ((prop = RNA_struct_find_property(op->ptr, "orient_axis"))) {
     if (t->flag & T_MODAL) {
       if (t->con.mode & CON_APPLY) {
@@ -1788,56 +1724,41 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
     }
   }
 
-  if ((prop = RNA_struct_find_property(op->ptr, "orient_matrix"))) {
-    if (t->flag & T_MODAL) {
-      if (orientation != V3D_ORIENT_CUSTOM_MATRIX) {
-        if (t->flag & T_MODAL) {
-          RNA_enum_set(op->ptr, "orient_matrix_type", orientation);
-        }
-      }
-      if (t->con.mode & CON_APPLY) {
-        RNA_float_set_array(op->ptr, "orient_matrix", &t->con.mtx- [x][0]);
-      }
-      else if (use_orient_axis) {
-        RNA_float_set_array(op->ptr, "orient_matrix", &t->orient_matrix- [x][0]);
-      }
-      else {
-        RNA_float_set_array(op->ptr, "orient_matrix", &t->spacemtx- [x][0]);
-      }
-    }
-  }
-
   if ((prop = RNA_struct_find_property(op->ptr, "orient_type"))) {
-    /* constraint orientation can be global, even if user selects something else
-     * so use the orientation in the constraint if set */
+    short orient_type_set, orient_type_curr;
+    orient_type_set = RNA_property_is_set(op->ptr, prop) ? RNA_property_enum_get(op->ptr, prop) :
+                                                           -1;
+    orient_type_curr = t->orient[t->orient_curr].type;
 
-    /* Use 'orient_matrix' instead. */
-    if (t->flag & T_MODAL) {
-      if (orientation != V3D_ORIENT_CUSTOM_MATRIX) {
-        RNA_property_enum_set(op->ptr, prop, orientation);
-      }
+    if (!ELEM(orient_type_curr, orient_type_set, V3D_ORIENT_CUSTOM_MATRIX)) {
+      RNA_property_enum_set(op->ptr, prop, orient_type_curr);
+      orient_type_set = orient_type_curr;
+    }
+
+    if (((prop = RNA_struct_find_property(op->ptr, "orient_matrix_type")) &&
+         !RNA_property_is_set(op->ptr, prop))) {
+      /* Set the first time to register on redo. */
+      RNA_property_enum_set(op->ptr, prop, orient_type_set);
+      RNA_float_set_array(op->ptr, "orient_matrix", &t->spacemtx- [x][0]);
     }
   }
 
   if ((prop = RNA_struct_find_property(op->ptr, "constraint_axis"))) {
     bool constraint_axis- [x] = {false, false, false};
-    if (t->flag & T_MODAL) {
-      /* Only set if needed, so we can hide in the UI when nothing is set.
-       * See 'transform_poll_property'. */
-      if (t->con.mode & CON_APPLY) {
-        if (t->con.mode & CON_AXIS0) {
-          constraint_axis- [x] = true;
-        }
-        if (t->con.mode & CON_AXIS1) {
-          constraint_axis- [x] = true;
-        }
-        if (t->con.mode & CON_AXIS2) {
-          constraint_axis- [x] = true;
-        }
+    if (t->con.mode & CON_APPLY) {
+      if (t->con.mode & CON_AXIS0) {
+        constraint_axis- [x] = true;
       }
-      if (ELEM(true, UNPACK3(constraint_axis))) {
-        RNA_property_boolean_set_array(op->ptr, prop, constraint_axis);
+      if (t->con.mode & CON_AXIS1) {
+        constraint_axis- [x] = true;
       }
+      if (t->con.mode & CON_AXIS2) {
+        constraint_axis- [x] = true;
+      }
+      RNA_property_boolean_set_array(op->ptr, prop, constraint_axis);
+    }
+    else {
+      RNA_property_unset(op->ptr, prop);
     }
   }
 
@@ -1938,13 +1859,6 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
     }
   }
 
-  if (CTX_wm_view3d(C) != NULL) {
-    Object *ob = CTX_data_active_object(C);
-    if (ob && ob->mode == OB_MODE_SCULPT && ob->sculpt) {
-      options |= CTX_SCULPT;
-    }
-  }
-
   t->options = options;
 
   t->mode = mode;
@@ -1963,7 +1877,10 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
   unit_m3(t->spacemtx);
 
   initTransInfo(C, t, op, event);
-  initTransformOrientation(C, t);
+
+  /* Use the custom orientation when it is set. */
+  short orient_index = t->orient- [x].type == V3D_ORIENT_CUSTOM_MATRIX ? 0 : t->orient_curr;
+  transform_orientations_current_set(t, orient_index);
 
   if (t->spacetype == SPACE_VIEW3D) {
     t->draw_handle_apply = ED_region_draw_cb_activate(
@@ -2088,33 +2005,6 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
   calculatePropRatio(t);
   calculateCenter(t);
 
-  /* Overwrite initial values if operator supplied a non-null vector.
-   *
-   * Run before init functions so 'values_modal_offset' can be applied on mouse input.
-   */
-  BLI_assert(is_zero_v4(t->values_modal_offset));
-  if ((prop = RNA_struct_find_property(op->ptr, "value")) && RNA_property_is_set(op->ptr, prop)) {
-    float values- [x] = {0}; /* in case value isn't length 4, avoid uninitialized memory  */
-
-    if (RNA_property_array_check(prop)) {
-      RNA_float_get_array(op->ptr, "value", values);
-    }
-    else {
-      values- [x] = RNA_float_get(op->ptr, "value");
-    }
-
-    copy_v4_v4(t->values, values);
-
-    if (t->flag & T_MODAL) {
-      copy_v4_v4(t->values_modal_offset, values);
-      t->redraw = TREDRAW_HARD;
-    }
-    else {
-      copy_v4_v4(t->values, values);
-      t->flag |= T_INPUT_IS_VALUES_FINAL;
-    }
-  }
-
   if (event) {
     /* Initialize accurate transform to settings requested by keymap. */
     bool use_accurate = false;
@@ -2145,38 +2035,8 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
   }
 
   /* Constraint init from operator */
-  if ((t->flag & T_MODAL) ||
-      /* For mirror operator the constraint axes are effectively the values. */
-      (RNA_struct_find_property(op->ptr, "value") == NULL)) {
-    if ((prop = RNA_struct_find_property(op->ptr, "constraint_axis")) &&
-        RNA_property_is_set(op->ptr, prop)) {
-      bool constraint_axis[3];
-
-      RNA_property_boolean_get_array(op->ptr, prop, constraint_axis);
-
-      if (constraint_axis- [x] || constraint_axis- [x] || constraint_axis[2]) {
-        t->con.mode |= CON_APPLY;
-
-        if (constraint_axis[0]) {
-          t->con.mode |= CON_AXIS0;
-        }
-        if (constraint_axis[1]) {
-          t->con.mode |= CON_AXIS1;
-        }
-        if (constraint_axis[2]) {
-          t->con.mode |= CON_AXIS2;
-        }
-
-        setUserConstraint(t, t->orientation.user, t->con.mode, "%s");
-      }
-    }
-  }
-  else {
-    /* So we can adjust in non global orientation. */
-    if (t->orientation.user != V3D_ORIENT_GLOBAL) {
-      t->con.mode |= CON_APPLY | CON_AXIS0 | CON_AXIS1 | CON_AXIS2;
-      setUserConstraint(t, t->orientation.user, t->con.mode, "%s");
-    }
+  if (t->con.mode & CON_APPLY) {
+    setUserConstraint(t, t->orient[t->orient_curr].type, t->con.mode, "%s");
   }
 
   /* Don't write into the values when non-modal because they are already set from operator redo
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index 7a68266ce6c..6a88c9d4a5a 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -113,13 +113,8 @@ typedef struct TransSnap {
 } TransSnap;
 
 typedef struct TransCon {
-  short orientation;
   /** Description of the constraint for header_print. */
   char text[50];
-  /** Matrix of the constraint space. */
-  float mtx- [x][3];
-  /** Inverse matrix of the constraint space. */
-  float imtx- [x][3];
   /** Projection constraint matrix (same as #imtx with some axis == 0). */
   float pmtx- [x][3];
   /** Initial mouse value for visual calculation
@@ -139,8 +134,7 @@ typedef struct TransCon {
                    struct TransDataContainer *tc,
                    struct TransData *td,
                    const float in[3],
-                   float out[3],
-                   float pvec[3]);
+                   float out[3]);
   /** Apply function pointer for size transformation. */
   void (*applySize)(struct TransInfo *t,
                     struct TransDataContainer *tc,
@@ -520,6 +514,7 @@ typedef struct TransInfo {
 
   /** orientation matrix of the current space. */
   float spacemtx- [x][3];
+  float spacemtx_inv- [x][3];
   /** name of the current space, MAX_NAME. */
   char spacename[64];
 
@@ -531,18 +526,11 @@ typedef struct TransInfo {
   bool is_launch_event_tweak;
 
   struct {
-    /** Orientation type when when we're not constrained.
-     * nearly always global except for rotate which defaults to screen-space orientation. */
-    short unset;
-    /** Orientation to use when a key is pressed. */
-    short user;
-    /* Used when user is global. */
-    short user_alt;
-    short index;
-    short *types[2];
-    /* this gets used when custom_orientation is V3D_ORIENT_CUSTOM */
-    struct TransformOrientation *custom;
-  } orientation;
+    short type;
+    float matrix- [x][3];
+  } orient[3];
+  short orient_curr;
+
   /** backup from view3d, to restore on end. */
   short gizmo_flag;
 
@@ -566,15 +554,6 @@ typedef struct TransInfo {
   /** Secondary axis, shear uses this. */
   int orient_axis_ortho;
 
-  /** Often this matrix has similar usage to #TransInfo.spacemtx however this
-   * is used to define extra axes to operate on, not necessarily a space.
-   *
-   * For example, by default rotation operates on the view (`orient_matrix[2]`),
-   * even when the current space isn't set to the view. */
-  float orient_matrix- [x][3];
-  /** Don't overwrite when set by operator redo defines the orientation axis. */
-  bool orient_matrix_is_set;
-
   /** remove elements if operator is canceled. */
   bool remove_on_cancel;
 
@@ -922,8 +901,13 @@ void getViewVector(const TransInfo *t, const float coord- [x], float vec[3]);
 void transform_data_ext_rotate(TransData *td, float mat- [x]- [x], bool use_drot);
 
 /*********************** Transform Orientations ******************************/
-
-void initTransformOrientation(struct bContext *C, TransInfo *t);
+short transform_orientation_matrix_get(struct bContext *C,
+                                       TransInfo *t,
+                                       const short orientation,
+                                       const float custom- [x][3],
+                                       float r_spacemtx- [x][3]);
+const char *transform_orientations_spacename_get(TransInfo *t, const short orient_type);
+void transform_orientations_current_set(struct TransInfo *t, const short orient_index);
 
 /* Those two fill in mat and return non-zero on success */
 bool createSpaceNormal(float mat- [x]- [x], const float normal[3]);
diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c
index cdff9fdf750..ec4c678d4ae 100644
--- a/source/blender/editors/transform/transform_constraints.c
+++ b/source/blender/editors/transform/transform_constraints.c
@@ -57,7 +57,49 @@
 
 static void drawObjectConstraint(TransInfo *t);
 
+static void projection_matrix_calc(const TransInfo *t, float r_pmtx- [x][3])
+{
+  unit_m3(r_pmtx);
+
+  if (!(t->con.mode & CON_AXIS0)) {
+    zero_v3(r_pmtx[0]);
+  }
+
+  if (!(t->con.mode & CON_AXIS1)) {
+    zero_v3(r_pmtx[1]);
+  }
+
+  if (!(t->con.mode & CON_AXIS2)) {
+    zero_v3(r_pmtx[2]);
+  }
+
+  float mat- [x][3];
+  mul_m3_m3m3(mat, r_pmtx, t->spacemtx_inv);
+  mul_m3_m3m3(r_pmtx, t->spacemtx, mat);
+}
+
 /* ************************** CONSTRAINTS ************************* */
+#define CONSTRAIN_EPSILON 0.0001f
+
+static void constraint_plane_calc(TransInfo *t, float r_plane[4])
+{
+  const float *constraint_vector[2];
+  int n = 0;
+  for (int i = 0; i < 3; i++) {
+    if (t->con.mode & (CON_AXIS0 << i)) {
+      constraint_vector[n++] = t->spacemtx[i];
+      if (n == 2) {
+        break;
+      }
+    }
+  }
+  BLI_assert(n == 2);
+
+  cross_v3_v3v3(r_plane, constraint_vector- [x], constraint_vector[1]);
+  normalize_v3(r_plane);
+  r_plane- [x] = -dot_v3v3(r_plane, t->center_global);
+}
+
 static void constraintValuesFinal(TransInfo *t, float vec[3])
 {
   int mode = t->con.mode;
@@ -121,11 +163,9 @@ void constraintNumInput(TransInfo *t, float vec[3])
   }
 }
 
-static void postConstraintChecks(TransInfo *t, float vec- [x], float pvec[3])
+static void postConstraintChecks(TransInfo *t, float vec[3])
 {
-  int i = 0;
-
-  mul_m3_v3(t->con.imtx, vec);
+  mul_m3_v3(t->spacemtx_inv, vec);
 
   snapGridIncrement(t, vec);
 
@@ -155,17 +195,7 @@ static void postConstraintChecks(TransInfo *t, float vec- [x], float pvec[3])
     /* inverse transformation at the end */
   }
 
-  if (t->con.mode & CON_AXIS0) {
-    pvec[i++] = vec[0];
-  }
-  if (t->con.mode & CON_AXIS1) {
-    pvec[i++] = vec[1];
-  }
-  if (t->con.mode & CON_AXIS2) {
-    pvec[i++] = vec[2];
-  }
-
-  mul_m3_v3(t->con.mtx, vec);
+  mul_m3_v3(t->spacemtx, vec);
 }
 
 static void viewAxisCorrectCenter(const TransInfo *t, float t_con_center[3])
@@ -291,29 +321,13 @@ static void axisProjection(const TransInfo *t,
  * Return true if the 2x axis are both aligned when projected into the view.
  * In this case, we can't usefully project the cursor onto the plane.
  */
-static bool isPlaneProjectionViewAligned(const TransInfo *t)
+static bool isPlaneProjectionViewAligned(const TransInfo *t, const float plane[4])
 {
   const float eps = 0.001f;
-  const float *constraint_vector[2];
-  int n = 0;
-  for (int i = 0; i < 3; i++) {
-    if (t->con.mode & (CON_AXIS0 << i)) {
-      constraint_vector[n++] = t->con.mtx[i];
-      if (n == 2) {
-        break;
-      }
-    }
-  }
-  BLI_assert(n == 2);
-
-  float view_to_plane- [x], plane_normal[3];
-
+  float view_to_plane[3];
   getViewVector(t, t->center_global, view_to_plane);
 
-  cross_v3_v3v3(plane_normal, constraint_vector- [x], constraint_vector[1]);
-  normalize_v3(plane_normal);
-
-  float factor = dot_v3v3(plane_normal, view_to_plane);
+  float factor = dot_v3v3(plane, view_to_plane);
   return fabsf(factor) < eps;
 }
 
@@ -346,23 +360,22 @@ static void planeProjection(const TransInfo *t, const float in- [x], float out[3])
  * (in perspective mode, the view vector is relative to the position on screen)
  */
 
-static void applyAxisConstraintVec(TransInfo *t,
-                                   TransDataContainer *UNUSED(tc),
-                                   TransData *td,
-                                   const float in[3],
-                                   float out[3],
-                                   float pvec[3])
+static void applyAxisConstraintVec(
+    TransInfo *t, TransDataContainer *UNUSED(tc), TransData *td, const float in- [x], float out[3])
 {
   copy_v3_v3(out, in);
   if (!td && t->con.mode & CON_APPLY) {
     mul_m3_v3(t->con.pmtx, out);
 
-    // With snap, a projection is alright, no need to correct for view alignment
+    /* With snap points, a projection is alright, no adjustments needed. */
     if (!validSnap(t)) {
       const int dims = getConstraintSpaceDimension(t);
       if (dims == 2) {
         if (!is_zero_v3(out)) {
-          if (!isPlaneProjectionViewAligned(t)) {
+          float plane[4];
+          constraint_plane_calc(t, plane);
+          /* View alignment correction. */
+          if (!isPlaneProjectionViewAligned(t, plane)) {
             planeProjection(t, in, out);
           }
         }
@@ -371,25 +384,27 @@ static void applyAxisConstraintVec(TransInfo *t,
         float c[3];
 
         if (t->con.mode & CON_AXIS0) {
-          copy_v3_v3(c, t->con.mtx[0]);
+          copy_v3_v3(c, t->spacemtx[0]);
         }
         else if (t->con.mode & CON_AXIS1) {
-          copy_v3_v3(c, t->con.mtx[1]);
+          copy_v3_v3(c, t->spacemtx[1]);
         }
         else if (t->con.mode & CON_AXIS2) {
-          copy_v3_v3(c, t->con.mtx[2]);
+          copy_v3_v3(c, t->spacemtx[2]);
         }
+
+        /* View alignment correction. */
         axisProjection(t, c, in, out);
       }
     }
-    postConstraintChecks(t, out, pvec);
+    postConstraintChecks(t, out);
   }
 }
 
 /*
  * Generic callback for object based spatial constraints applied to linear motion
  *
- * At first, the following is applied to the first data in the array
+ * At first, the following is applied without orientation
  * The IN vector in projected into the constrained space and then further
  * projected along the view vector.
  * (in perspective mode, the view vector is relative to the position on screen)
@@ -397,57 +412,17 @@ static void applyAxisConstraintVec(TransInfo *t,
  * Further down, that vector is mapped to each data's space.
  */
 
-static void applyObjectConstraintVec(TransInfo *t,
-                                     TransDataContainer *tc,
-                                     TransData *td,
-                                     const float in[3],
-                                     float out[3],
-                                     float pvec[3])
+static void applyObjectConstraintVec(
+    TransInfo *t, TransDataContainer *tc, TransData *td, const float in- [x], float out[3])
 {
-  copy_v3_v3(out, in);
-  if (t->con.mode & CON_APPLY) {
-    if (!td) {
-      mul_m3_v3(t->con.pmtx, out);
-
-      const int dims = getConstraintSpaceDimension(t);
-      if (dims == 2) {
-        if (!is_zero_v3(out)) {
-          if (!isPlaneProjectionViewAligned(t)) {
-            planeProjection(t, in, out);
-          }
-        }
-      }
-      else if (dims == 1) {
-        float c[3];
-
-        if (t->con.mode & CON_AXIS0) {
-          copy_v3_v3(c, t->con.mtx[0]);
-        }
-        else if (t->con.mode & CON_AXIS1) {
-          copy_v3_v3(c, t->con.mtx[1]);
-        }
-        else if (t->con.mode & CON_AXIS2) {
-          copy_v3_v3(c, t->con.mtx[2]);
-        }
-        axisProjection(t, c, in, out);
-      }
-      postConstraintChecks(t, out, pvec);
-      copy_v3_v3(out, pvec);
-    }
-    else {
-      int i = 0;
-
-      out- [x] = out- [x] = out- [x] = 0.0f;
-      if (t->con.mode & CON_AXIS0) {
-        out- [x] = in[i++];
-      }
-      if (t->con.mode & CON_AXIS1) {
-        out- [x] = in[i++];
-      }
-      if (t->con.mode & CON_AXIS2) {
-        out- [x] = in[i++];
-      }
-
+  if (!td) {
+    applyAxisConstraintVec(t, tc, td, in, out);
+  }
+  else {
+    /* Specific TransData's space. */
+    copy_v3_v3(out, in);
+    if (t->con.mode & CON_APPLY) {
+      mul_m3_v3(t->spacemtx_inv, out);
       mul_m3_v3(td->axismtx, out);
       if (t->flag & T_EDIT) {
         mul_m3_v3(tc->mat3_unit, out);
@@ -478,8 +453,8 @@ static void applyAxisConstraintSize(TransInfo *t,
       smat- [x]- [x] = 1.0f;
     }
 
-    mul_m3_m3m3(tmat, smat, t->con.imtx);
-    mul_m3_m3m3(smat, t->con.mtx, tmat);
+    mul_m3_m3m3(tmat, smat, t->spacemtx_inv);
+    mul_m3_m3m3(smat, t->spacemtx, tmat);
   }
 }
 
@@ -539,15 +514,15 @@ static void applyAxisConstraintRot(
     switch (mode) {
       case CON_AXIS0:
       case (CON_AXIS1 | CON_AXIS2):
-        copy_v3_v3(vec, t->con.mtx[0]);
+        copy_v3_v3(vec, t->spacemtx[0]);
         break;
       case CON_AXIS1:
       case (CON_AXIS0 | CON_AXIS2):
-        copy_v3_v3(vec, t->con.mtx[1]);
+        copy_v3_v3(vec, t->spacemtx[1]);
         break;
       case CON_AXIS2:
       case (CON_AXIS0 | CON_AXIS1):
-        copy_v3_v3(vec, t->con.mtx[2]);
+        copy_v3_v3(vec, t->spacemtx[2]);
         break;
     }
     /* don't flip axis if asked to or if num input */
@@ -620,12 +595,11 @@ static void applyObjectConstraintRot(
 
 /*--------------------- INTERNAL SETUP CALLS ------------------*/
 
-void setConstraint(TransInfo *t, float space- [x]- [x], int mode, const char text[])
+void setConstraint(TransInfo *t, int mode, const char text[])
 {
   BLI_strncpy(t->con.text + 1, text, sizeof(t->con.text) - 1);
-  copy_m3_m3(t->con.mtx, space);
   t->con.mode = mode;
-  getConstraintMatrix(t);
+  projection_matrix_calc(t, t->con.pmtx);
 
   startConstraint(t);
 
@@ -639,41 +613,25 @@ void setConstraint(TransInfo *t, float space- [x]- [x], int mode, const char text[])
 /* applies individual td->axismtx constraints */
 void setAxisMatrixConstraint(TransInfo *t, int mode, const char text[])
 {
-  TransDataContainer *tc = t->data_container;
-  if (t->data_len_all == 1) {
-    float axismtx- [x][3];
-    if (t->flag & T_EDIT) {
-      mul_m3_m3m3(axismtx, tc->mat3_unit, tc->data->axismtx);
-    }
-    else {
-      copy_m3_m3(axismtx, tc->data->axismtx);
-    }
-
-    setConstraint(t, axismtx, mode, text);
-  }
-  else {
-    BLI_strncpy(t->con.text + 1, text, sizeof(t->con.text) - 1);
-    copy_m3_m3(t->con.mtx, tc->data->axismtx);
-    t->con.mode = mode;
-    getConstraintMatrix(t);
+  BLI_strncpy(t->con.text + 1, text, sizeof(t->con.text) - 1);
+  t->con.mode = mode;
+  projection_matrix_calc(t, t->con.pmtx);
 
-    startConstraint(t);
+  startConstraint(t);
 
-    t->con.drawExtra = drawObjectConstraint;
-    t->con.applyVec = applyObjectConstraintVec;
-    t->con.applySize = applyObjectConstraintSize;
-    t->con.applyRot = applyObjectConstraintRot;
-    t->redraw = TREDRAW_HARD;
-  }
+  t->con.drawExtra = drawObjectConstraint;
+  t->con.applyVec = applyObjectConstraintVec;
+  t->con.applySize = applyObjectConstraintSize;
+  t->con.applyRot = applyObjectConstraintRot;
+  t->redraw = TREDRAW_HARD;
 }
 
 void setLocalConstraint(TransInfo *t, int mode, const char text[])
 {
-  /* edit-mode now allows local transforms too */
   if (t->flag & T_EDIT) {
-    /* Use the active (first) edit object. */
-    TransDataContainer *tc = t->data_container;
-    setConstraint(t, tc->mat3_unit, mode, text);
+    /* Although in edit-mode each object has its local space, use the
+     * orientation of the active object. */
+    setConstraint(t, mode, text);
   }
   else {
     setAxisMatrixConstraint(t, mode, text);
@@ -689,59 +647,30 @@ void setLocalConstraint(TransInfo *t, int mode, const char text[])
 void setUserConstraint(TransInfo *t, short orientation, int mode, const char ftext[])
 {
   char text[256];
+  const char *spacename = transform_orientations_spacename_get(t, orientation);
+  BLI_snprintf(text, sizeof(text), ftext, spacename);
 
   switch (orientation) {
-    case V3D_ORIENT_GLOBAL: {
-      float mtx- [x][3];
-      BLI_snprintf(text, sizeof(text), ftext, TIP_("global"));
-      unit_m3(mtx);
-      setConstraint(t, mtx, mode, text);
-      break;
-    }
     case V3D_ORIENT_LOCAL:
-      BLI_snprintf(text, sizeof(text), ftext, TIP_("local"));
       setLocalConstraint(t, mode, text);
       break;
     case V3D_ORIENT_NORMAL:
-      BLI_snprintf(text, sizeof(text), ftext, TIP_("normal"));
       if (checkUseAxisMatrix(t)) {
         setAxisMatrixConstraint(t, mode, text);
+        break;
       }
-      else {
-        setConstraint(t, t->spacemtx, mode, text);
-      }
-      break;
+      ATTR_FALLTHROUGH;
+    case V3D_ORIENT_GLOBAL:
     case V3D_ORIENT_VIEW:
-      BLI_snprintf(text, sizeof(text), ftext, TIP_("view"));
-      setConstraint(t, t->spacemtx, mode, text);
-      break;
     case V3D_ORIENT_CURSOR:
-      BLI_snprintf(text, sizeof(text), ftext, TIP_("cursor"));
-      setConstraint(t, t->spacemtx, mode, text);
-      break;
     case V3D_ORIENT_GIMBAL:
-      BLI_snprintf(text, sizeof(text), ftext, TIP_("gimbal"));
-      setConstraint(t, t->spacemtx, mode, text);
-      break;
     case V3D_ORIENT_CUSTOM_MATRIX:
-      BLI_snprintf(text, sizeof(text), ftext, TIP_("custom matrix"));
-      setConstraint(t, t->spacemtx, mode, text);
-      break;
-    case V3D_ORIENT_CUSTOM: {
-      char orientation_str[128];
-      BLI_snprintf(orientation_str,
-                   sizeof(orientation_str),
-                   "%s \"%s\"",
-                   TIP_("custom orientation"),
-                   t->orientation.custom->name);
-      BLI_snprintf(text, sizeof(text), ftext, orientation_str);
-      setConstraint(t, t->spacemtx, mode, text);
+    case V3D_ORIENT_CUSTOM:
+    default: {
+      setConstraint(t, mode, text);
       break;
     }
   }
-
-  t->con.orientation = orientation;
-
   t->con.mode |= CON_USER;
 }
 
@@ -772,9 +701,9 @@ void drawConstraint(TransInfo *t)
       convertViewVec(t, vec, (t->mval- [x] - t->con.imval- [x]), (t->mval- [x] - t->con.imval[1]));
       add_v3_v3(vec, t->center_global);
 
-      drawLine(t, t->center_global, tc->mtx- [x], 'X', 0);
-      drawLine(t, t->center_global, tc->mtx- [x], 'Y', 0);
-      drawLine(t, t->center_global, tc->mtx- [x], 'Z', 0);
+      drawLine(t, t->center_global, t->spacemtx- [x], 'X', 0);
+      drawLine(t, t->center_global, t->spacemtx- [x], 'Y', 0);
+      drawLine(t, t->center_global, t->spacemtx- [x], 'Z', 0);
 
       depth_test_enabled = GPU_depth_test_enabled();
       if (depth_test_enabled) {
@@ -808,13 +737,13 @@ void drawConstraint(TransInfo *t)
     }
 
     if (tc->mode & CON_AXIS0) {
-      drawLine(t, t->center_global, tc->mtx- [x], 'X', DRAWLIGHT);
+      drawLine(t, t->center_global, t->spacemtx- [x], 'X', DRAWLIGHT);
     }
     if (tc->mode & CON_AXIS1) {
-      drawLine(t, t->center_global, tc->mtx- [x], 'Y', DRAWLIGHT);
+      drawLine(t, t->center_global, t->spacemtx- [x], 'Y', DRAWLIGHT);
     }
     if (tc->mode & CON_AXIS2) {
-      drawLine(t, t->center_global, tc->mtx- [x], 'Z', DRAWLIGHT);
+      drawLine(t, t->center_global, t->spacemtx- [x], 'Z', DRAWLIGHT);
     }
   }
 }
@@ -911,11 +840,7 @@ static void drawObjectConstraint(TransInfo *t)
         }
       }
 
-      if (t->flag & T_OBJECT) {
-        copy_v3_v3(co, td->ob->obmat[3]);
-        axismtx = td->axismtx;
-      }
-      else if (t->flag & T_EDIT) {
+      if (t->flag & T_EDIT) {
         mul_v3_m4v3(co, tc->mat, td->center);
 
         mul_m3_m3m3(tmp_axismtx, tc->mat3_unit, td->axismtx);
@@ -960,41 +885,18 @@ void stopConstraint(TransInfo *t)
   t->num.idx_max = t->idx_max;
 }
 
-void getConstraintMatrix(TransInfo *t)
-{
-  float mat- [x][3];
-  invert_m3_m3(t->con.imtx, t->con.mtx);
-  unit_m3(t->con.pmtx);
-
-  if (!(t->con.mode & CON_AXIS0)) {
-    zero_v3(t->con.pmtx[0]);
-  }
-
-  if (!(t->con.mode & CON_AXIS1)) {
-    zero_v3(t->con.pmtx[1]);
-  }
-
-  if (!(t->con.mode & CON_AXIS2)) {
-    zero_v3(t->con.pmtx[2]);
-  }
-
-  mul_m3_m3m3(mat, t->con.pmtx, t->con.imtx);
-  mul_m3_m3m3(t->con.pmtx, t->con.mtx, mat);
-}
-
 /*------------------------- MMB Select -------------------------------*/
 
-void initSelectConstraint(TransInfo *t, float mtx- [x][3])
+void initSelectConstraint(TransInfo *t)
 {
-  copy_m3_m3(t->con.mtx, mtx);
-  t->con.mode |= CON_APPLY;
-  t->con.mode |= CON_SELECT;
+  if (t->orient_curr == 0) {
+    t->orient_curr = 1;
+    transform_orientations_current_set(t, t->orient_curr);
+  }
 
+  short orientation = t->orient[t->orient_curr].type;
+  setUserConstraint(t, orientation, CON_APPLY | CON_SELECT, "%s");
   setNearestAxis(t);
-  t->con.drawExtra = NULL;
-  t->con.applyVec = applyAxisConstraintVec;
-  t->con.applySize = applyAxisConstraintSize;
-  t->con.applyRot = applyAxisConstraintRot;
 }
 
 void selectConstraint(TransInfo *t)
@@ -1060,7 +962,7 @@ static void setNearestAxis3d(TransInfo *t)
   for (i = 0; i < 3; i++) {
     float axis- [x], axis_2d[2];
 
-    copy_v3_v3(axis, t->con.mtx[i]);
+    copy_v3_v3(axis, t->spacemtx[i]);
 
     mul_v3_fl(axis, zfac);
     /* now we can project to get window coordinate */
@@ -1129,7 +1031,7 @@ void setNearestAxis(TransInfo *t)
     setNearestAxis2d(t);
   }
 
-  getConstraintMatrix(t);
+  projection_matrix_calc(t, t->con.pmtx);
 }
 
 /*-------------- HELPER FUNCTIONS ----------------*/
diff --git a/source/blender/editors/transform/transform_constraints.h b/source/blender/editors/transform/transform_constraints.h
index 8938ca93ad8..c41b9361ca4 100644
--- a/source/blender/editors/transform/transform_constraints.h
+++ b/source/blender/editors/transform/transform_constraints.h
@@ -27,7 +27,7 @@
 struct TransInfo;
 
 void constraintNumInput(TransInfo *t, float vec[3]);
-void setConstraint(TransInfo *t, float space- [x]- [x], int mode, const char text[]);
+void setConstraint(TransInfo *t, int mode, const char text[]);
 void setAxisMatrixConstraint(TransInfo *t, int mode, const char text[]);
 void setLocalConstraint(TransInfo *t, int mode, const char text[]);
 void setUserConstraint(TransInfo *t, short orientation, int mode, const char text[]);
@@ -35,8 +35,7 @@ void drawConstraint(TransInfo *t);
 void drawPropCircle(const struct bContext *C, TransInfo *t);
 void startConstraint(TransInfo *t);
 void stopConstraint(TransInfo *t);
-void getConstraintMatrix(TransInfo *t);
-void initSelectConstraint(TransInfo *t, float mtx- [x][3]);
+void initSelectConstraint(TransInfo *t);
 void selectConstraint(TransInfo *t);
 void postSelectConstraint(TransInfo *t);
 void setNearestAxis(TransInfo *t);
diff --git a/source/blender/editors/transform/transform_convert.h b/source/blender/editors/transform/transform_convert.h
index d4139898419..b50d4c7365a 100644
--- a/source/blender/editors/transform/transform_convert.h
+++ b/source/blender/editors/transform/transform_convert.h
@@ -163,7 +163,7 @@ void createTransParticleVerts(bContext *C, TransInfo *t);
 /* transform_convert_sculpt.c */
 void createTransSculpt(TransInfo *t);
 
-/* transform_convert_sequence.c */
+/* transform_convert_sequencer.c */
 void createTransSeqData(TransInfo *t);
 
 /* transform_convert_tracking.c */
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index f42a15a0ec3..69655011e60 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -1432,11 +1432,6 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
 
   unit_m3(t->mat);
 
-  unit_m3(t->orient_matrix);
-  negate_m3(t->orient_matrix);
-  /* Leave 't->orient_matrix_is_set' to false,
-   * so we overwrite it when we have a useful value. */
-
   /* Default to rotate on the Z axis. */
   t->orient_axis = 2;
   t->orient_axis_ortho = 1;
@@ -1514,22 +1509,6 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
       t->around = V3D_AROUND_CURSOR;
     }
 
-    TransformOrientationSlot *orient_slot = &t->scene->orientation_slots[SCE_ORIENT_DEFAULT];
-    t->orientation.unset = V3D_ORIENT_GLOBAL;
-    t->orientation.user = orient_slot->type;
-    t->orientation.custom = BKE_scene_transform_orientation_find(t->scene,
-                                                                 orient_slot->index_custom);
-
-    t->orientation.index = 0;
-    ARRAY_SET_ITEMS(t->orientation.types, &t->orientation.user, NULL);
-
-    /* Make second orientation local if both are global. */
-    if (t->orientation.user == V3D_ORIENT_GLOBAL) {
-      t->orientation.user_alt = V3D_ORIENT_LOCAL;
-      t->orientation.types- [x] = &t->orientation.user_alt;
-      SWAP(short *, t->orientation.types- [x], t->orientation.types[1]);
-    }
-
     /* exceptional case */
     if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
       if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL)) {
@@ -1618,48 +1597,153 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
     t->around = V3D_AROUND_CENTER_BOUNDS;
   }
 
-  if (op && (prop = RNA_struct_find_property(op->ptr, "orient_axis"))) {
-    t->orient_axis = RNA_property_enum_get(op->ptr, prop);
-  }
-  if (op && (prop = RNA_struct_find_property(op->ptr, "orient_axis_ortho"))) {
-    t->orient_axis_ortho = RNA_property_enum_get(op->ptr, prop);
-  }
+  BLI_assert(is_zero_v4(t->values_modal_offset));
+  bool t_values_set_is_array = false;
+  if (op && (prop = RNA_struct_find_property(op->ptr, "value")) &&
+      RNA_property_is_set(op->ptr, prop)) {
+    float values- [x] = {0}; /* in case value isn't length 4, avoid uninitialized memory  */
+    if (RNA_property_array_check(prop)) {
+      RNA_float_get_array(op->ptr, "value", values);
+      t_values_set_is_array = true;
+    }
+    else {
+      values- [x] = RNA_float_get(op->ptr, "value");
+    }
 
-  if (op &&
-      ((prop = RNA_struct_find_property(op->ptr, "orient_matrix")) &&
-       RNA_property_is_set(op->ptr, prop)) &&
-      ((t->flag & T_MODAL) ||
-       /* When using redo, don't use the custom constraint matrix
-        * if the user selects a different orientation. */
-       (RNA_enum_get(op->ptr, "orient_type") == RNA_enum_get(op->ptr, "orient_matrix_type")))) {
-    RNA_property_float_get_array(op->ptr, prop, &t->orient_matrix- [x][0]);
-    copy_m3_m3(t->spacemtx, t->orient_matrix);
-    /* Some transform modes use this to operate on an axis. */
-    t->orient_matrix_is_set = true;
-    t->orientation.user = V3D_ORIENT_CUSTOM_MATRIX;
-    t->orientation.custom = 0;
+    copy_v4_v4(t->values, values);
     if (t->flag & T_MODAL) {
-      RNA_enum_set(op->ptr, "orient_matrix_type", RNA_enum_get(op->ptr, "orient_type"));
+      /* Run before init functions so 'values_modal_offset' can be applied on mouse input. */
+      copy_v4_v4(t->values_modal_offset, values);
+    }
+    else {
+      copy_v4_v4(t->values, values);
+      t->flag |= T_INPUT_IS_VALUES_FINAL;
+    }
+  }
+
+  if (op && (prop = RNA_struct_find_property(op->ptr, "constraint_axis"))) {
+    bool constraint_axis- [x] = {false, false, false};
+    if (RNA_property_is_set(op->ptr, prop)) {
+      RNA_property_boolean_get_array(op->ptr, prop, constraint_axis);
+    }
+
+    if (t_values_set_is_array && t->flag & T_INPUT_IS_VALUES_FINAL) {
+      /* For operators whose `t->values` is array, set constraint so that the
+       * orientation is more intuitive in the Redo Panel. */
+      for (int i = 3; i--;) {
+        constraint_axis- [x] |= t->values- [x] != 0.0f;
+      }
+    }
+
+    if (constraint_axis- [x] || constraint_axis- [x] || constraint_axis[2]) {
+      t->con.mode |= CON_APPLY;
+
+      if (constraint_axis[0]) {
+        t->con.mode |= CON_AXIS0;
+      }
+      if (constraint_axis[1]) {
+        t->con.mode |= CON_AXIS1;
+      }
+      if (constraint_axis[2]) {
+        t->con.mode |= CON_AXIS2;
+      }
     }
   }
-  else if (op && ((prop = RNA_struct_find_property(op->ptr, "orient_type")) &&
-                  RNA_property_is_set(op->ptr, prop))) {
-    short orientation = RNA_property_enum_get(op->ptr, prop);
-    TransformOrientation *custom_orientation = NULL;
 
-    if (orientation >= V3D_ORIENT_CUSTOM) {
-      if (orientation >= V3D_ORIENT_CUSTOM + BIF_countTransformOrientation(C)) {
-        orientation = V3D_ORIENT_GLOBAL;
+  {
+    short orient_type_set = -1;
+    short orient_type_matrix_set = -1;
+    short orient_type_scene = V3D_ORIENT_GLOBAL;
+
+    if ((t->spacetype == SPACE_VIEW3D) && (t->region->regiontype == RGN_TYPE_WINDOW)) {
+      TransformOrientationSlot *orient_slot = &t->scene->orientation_slots[SCE_ORIENT_DEFAULT];
+      orient_type_scene = orient_slot->type;
+      if (orient_type_scene == V3D_ORIENT_CUSTOM) {
+        const int index_custom = orient_slot->index_custom;
+        orient_type_scene += index_custom;
+      }
+    }
+
+    short orient_types[3];
+    float custom_matrix- [x][3];
+    bool use_orient_axis = false;
+
+    if (op && (prop = RNA_struct_find_property(op->ptr, "orient_axis"))) {
+      t->orient_axis = RNA_property_enum_get(op->ptr, prop);
+      use_orient_axis = true;
+    }
+    if (op && (prop = RNA_struct_find_property(op->ptr, "orient_axis_ortho"))) {
+      t->orient_axis_ortho = RNA_property_enum_get(op->ptr, prop);
+    }
+
+    if (op && ((prop = RNA_struct_find_property(op->ptr, "orient_type")) &&
+               RNA_property_is_set(op->ptr, prop))) {
+      orient_type_set = RNA_property_enum_get(op->ptr, prop);
+      if (orient_type_set >= V3D_ORIENT_CUSTOM) {
+        if (orient_type_set >= V3D_ORIENT_CUSTOM + BIF_countTransformOrientation(C)) {
+          orient_type_set = V3D_ORIENT_GLOBAL;
+        }
+      }
+
+      /* Change the default orientation to be used when redoing. */
+      orient_types- [x] = orient_type_set;
+      orient_types- [x] = orient_type_set;
+      orient_types- [x] = orient_type_scene;
+    }
+    else {
+      if ((t->flag & T_MODAL) && (use_orient_axis || transform_mode_is_changeable(t->mode)) &&
+          (t->mode != TFM_ALIGN)) {
+        orient_types- [x] = V3D_ORIENT_VIEW;
       }
       else {
-        custom_orientation = BKE_scene_transform_orientation_find(t->scene,
-                                                                  orientation - V3D_ORIENT_CUSTOM);
-        orientation = V3D_ORIENT_CUSTOM;
+        orient_types- [x] = orient_type_scene;
+      }
+      orient_types- [x] = orient_type_scene;
+      orient_types- [x] = orient_type_scene != V3D_ORIENT_GLOBAL ? V3D_ORIENT_GLOBAL :
+                                                                 V3D_ORIENT_LOCAL;
+    }
+
+    if (op && ((prop = RNA_struct_find_property(op->ptr, "orient_matrix")) &&
+               RNA_property_is_set(op->ptr, prop))) {
+      RNA_property_float_get_array(op->ptr, prop, &custom_matrix- [x][0]);
+
+      if ((prop = RNA_struct_find_property(op->ptr, "orient_matrix_type")) &&
+          RNA_property_is_set(op->ptr, prop)) {
+        orient_type_matrix_set = RNA_property_enum_get(op->ptr, prop);
+      }
+      else if (orient_type_set != -1) {
+        orient_type_matrix_set = orient_type_set;
+      }
+      else {
+        orient_type_matrix_set = orient_type_set = V3D_ORIENT_GLOBAL;
+      }
+
+      if (orient_type_matrix_set == orient_type_set) {
+        /* Constraints are forced to use the custom matrix when redoing. */
+        orient_types- [x] = V3D_ORIENT_CUSTOM_MATRIX;
       }
     }
 
-    t->orientation.user = orientation;
-    t->orientation.custom = custom_orientation;
+    if (t->con.mode & CON_APPLY) {
+      t->orient_curr = 1;
+    }
+
+    /* For efficiency, avoid calculating the same orientation twice. */
+    for (int i = 1; i < 3; i++) {
+      t->orient- [x].type = transform_orientation_matrix_get(
+          C, t, orient_types- [x], custom_matrix, t->orient- [x].matrix);
+    }
+
+    if (orient_types- [x] != orient_types[1]) {
+      t->orient- [x].type = transform_orientation_matrix_get(
+          C, t, orient_types- [x], custom_matrix, t->orient- [x].matrix);
+    }
+    else {
+      memcpy(&t->orient- [x], &t->orient- [x], sizeof(t->orient[0]));
+    }
+
+    const char *spacename = transform_orientations_spacename_get(t, orient_types[0]);
+    BLI_strncpy(t->spacename, spacename, sizeof(t->spacename));
   }
 
   if (op && ((prop = RNA_struct_find_property(op->ptr, "release_confirm")) &&
@@ -1694,45 +1778,45 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
   /* setting PET flag only if property exist in operator. Otherwise, assume it's not supported */
   if (op && (prop = RNA_struct_find_property(op->ptr, "use_proportional_edit"))) {
     if (RNA_property_is_set(op->ptr, prop)) {
-      int proportional = 0;
       if (RNA_property_boolean_get(op->ptr, prop)) {
-        proportional |= PROP_EDIT_USE;
+        t->flag |= T_PROP_EDIT;
         if (RNA_boolean_get(op->ptr, "use_proportional_connected")) {
-          proportional |= PROP_EDIT_CONNECTED;
+          t->flag |= T_PROP_CONNECTED;
         }
         if (RNA_boolean_get(op->ptr, "use_proportional_projected")) {
-          proportional |= PROP_EDIT_PROJECTED;
+          t->flag |= T_PROP_PROJECTED;
         }
       }
-      t->flag |= initTransInfo_edit_pet_to_flag(proportional);
     }
     else {
       /* use settings from scene only if modal */
       if (t->flag & T_MODAL) {
         if ((t->options & CTX_NO_PET) == 0) {
+          bool use_prop_edit = false;
           if (t->spacetype == SPACE_GRAPH) {
-            t->flag |= initTransInfo_edit_pet_to_flag(ts->proportional_fcurve);
+            use_prop_edit = ts->proportional_fcurve;
           }
           else if (t->spacetype == SPACE_ACTION) {
-            t->flag |= initTransInfo_edit_pet_to_flag(ts->proportional_action);
+            use_prop_edit = ts->proportional_action;
           }
-          else if (t->obedit_type != -1) {
-            t->flag |= initTransInfo_edit_pet_to_flag(ts->proportional_edit);
+          else if (t->options & CTX_MASK) {
+            use_prop_edit = ts->proportional_mask;
           }
-          else if (t->options & CTX_GPENCIL_STROKES) {
-            t->flag |= initTransInfo_edit_pet_to_flag(ts->proportional_edit);
+          else if (obact && obact->mode == OB_MODE_OBJECT) {
+            use_prop_edit = ts->proportional_objects;
           }
-          else if (t->options & CTX_MASK) {
-            if (ts->proportional_mask) {
-              t->flag |= T_PROP_EDIT;
-
-              if (ts->proportional_edit & PROP_EDIT_CONNECTED) {
-                t->flag |= T_PROP_CONNECTED;
-              }
-            }
+          else {
+            use_prop_edit = (ts->proportional_edit & PROP_EDIT_USE) != 0;
           }
-          else if (!(t->options & CTX_CURSOR) && ts->proportional_objects) {
+
+          if (use_prop_edit) {
             t->flag |= T_PROP_EDIT;
+            if (ts->proportional_edit & PROP_EDIT_CONNECTED) {
+              t->flag |= T_PROP_CONNECTED;
+            }
+            if (ts->proportional_edit & PROP_EDIT_PROJECTED) {
+              t->flag |= T_PROP_PROJECTED;
+            }
           }
         }
       }
diff --git a/source/blender/editors/transform/transform_gizmo_3d.c b/source/blender/editors/transform/transform_gizmo_3d.c
index cbb20847f36..ef860fba2a8 100644
--- a/source/blender/editors/transform/transform_gizmo_3d.c
+++ b/source/blender/editors/transform/transform_gizmo_3d.c
@@ -637,99 +637,6 @@ bool gimbal_axis(Object *ob, float gmat- [x][3])
   return 0;
 }
 
-void ED_transform_calc_orientation_from_type(const bContext *C, float r_mat- [x][3])
-{
-  ARegion *region = CTX_wm_region(C);
-  Scene *scene = CTX_data_scene(C);
-  ViewLayer *view_layer = CTX_data_view_layer(C);
-  Object *obedit = CTX_data_edit_object(C);
-  RegionView3D *rv3d = region->regiondata;
-  Object *ob = OBACT(view_layer);
-  const short orientation_type = scene->orientation_slots[SCE_ORIENT_DEFAULT].type;
-  const short orientation_index_custom = scene->orientation_slots[SCE_ORIENT_DEFAULT].index_custom;
-  const int pivot_point = scene->toolsettings->transform_pivot_point;
-
-  ED_transform_calc_orientation_from_type_ex(
-      C, r_mat, scene, rv3d, ob, obedit, orientation_type, orientation_index_custom, pivot_point);
-}
-
-void ED_transform_calc_orientation_from_type_ex(const bContext *C,
-                                                float r_mat- [x][3],
-                                                /* extra args (can be accessed from context) */
-                                                Scene *scene,
-                                                RegionView3D *rv3d,
-                                                Object *ob,
-                                                Object *obedit,
-                                                const short orientation_type,
-                                                int orientation_index_custom,
-                                                const int pivot_point)
-{
-  bool ok = false;
-
-  switch (orientation_type) {
-    case V3D_ORIENT_GLOBAL: {
-      break; /* nothing to do */
-    }
-    case V3D_ORIENT_GIMBAL: {
-      if (gimbal_axis(ob, r_mat)) {
-        ok = true;
-        break;
-      }
-      /* if not gimbal, fall through to normal */
-      ATTR_FALLTHROUGH;
-    }
-    case V3D_ORIENT_NORMAL: {
-      if (obedit || ob->mode & OB_MODE_POSE) {
-        ED_getTransformOrientationMatrix(C, r_mat, pivot_point);
-        ok = true;
-        break;
-      }
-      /* no break we define 'normal' as 'local' in Object mode */
-      ATTR_FALLTHROUGH;
-    }
-    case V3D_ORIENT_LOCAL: {
-      if (ob->mode & OB_MODE_POSE) {
-        /* each bone moves on its own local axis, but  to avoid confusion,
-         * use the active pones axis for display [#33575], this works as expected on a single bone
-         * and users who select many bones will understand what's going on and what local means
-         * when they start transforming */
-        ED_getTransformOrientationMatrix(C, r_mat, pivot_point);
-        ok = true;
-        break;
-      }
-      copy_m3_m4(r_mat, ob->obmat);
-      normalize_m3(r_mat);
-      ok = true;
-      break;
-    }
-    case V3D_ORIENT_VIEW: {
-      if (rv3d != NULL) {
-        copy_m3_m4(r_mat, rv3d->viewinv);
-        normalize_m3(r_mat);
-        ok = true;
-      }
-      break;
-    }
-    case V3D_ORIENT_CURSOR: {
-      BKE_scene_cursor_rot_to_mat3(&scene->cursor, r_mat);
-      ok = true;
-      break;
-    }
-    case V3D_ORIENT_CUSTOM: {
-      TransformOrientation *custom_orientation = BKE_scene_transform_orientation_find(
-          scene, orientation_index_custom);
-      if (applyTransformOrientation(custom_orientation, r_mat, NULL)) {
-        ok = true;
-      }
-      break;
-    }
-  }
-
-  if (!ok) {
-    unit_m3(r_mat);
-  }
-}
-
 /* centroid, boundbox, of selection */
 /* returns total items selected */
 int ED_transform_calc_gizmo_stats(const bContext *C,
@@ -1390,21 +1297,21 @@ void drawDial3d(const TransInfo *t)
     if (tc->mode & CON_APPLY) {
       if (tc->mode & CON_AXIS0) {
         axis_idx = MAN_AXIS_ROT_X;
-        negate_v3_v3(mat_basis- [x], tc->mtx[0]);
+        negate_v3_v3(mat_basis- [x], t->spacemtx[0]);
       }
       else if (tc->mode & CON_AXIS1) {
         axis_idx = MAN_AXIS_ROT_Y;
-        negate_v3_v3(mat_basis- [x], tc->mtx[1]);
+        negate_v3_v3(mat_basis- [x], t->spacemtx[1]);
       }
       else {
         BLI_assert((tc->mode & CON_AXIS2) != 0);
         axis_idx = MAN_AXIS_ROT_Z;
-        negate_v3_v3(mat_basis- [x], tc->mtx[2]);
+        negate_v3_v3(mat_basis- [x], t->spacemtx[2]);
       }
     }
     else {
       axis_idx = MAN_AXIS_ROT_C;
-      negate_v3_v3(mat_basis- [x], t->orient_matrix[t->orient_axis]);
+      copy_v3_v3(mat_basis- [x], t->spacemtx[t->orient_axis]);
       scale *= 1.2f;
       line_with -= 1.0f;
     }
diff --git a/source/blender/editors/transform/transform_mode.c b/source/blender/editors/transform/transform_mode.c
index a2b3a891031..a951a38420f 100644
--- a/source/blender/editors/transform/transform_mode.c
+++ b/source/blender/editors/transform/transform_mode.c
@@ -61,6 +61,18 @@ bool transdata_check_local_center(TransInfo *t, short around)
            (t->options & (CTX_MOVIECLIP | CTX_MASK | CTX_PAINT_CURVE))));
 }
 
+/* Informs if the mode can be switched during modal. */
+bool transform_mode_is_changeable(const int mode)
+{
+  return ELEM(mode,
+              TFM_ROTATION,
+              TFM_RESIZE,
+              TFM_TRACKBALL,
+              TFM_TRANSLATION,
+              TFM_EDGE_SLIDE,
+              TFM_VERT_SLIDE);
+}
+
 /* -------------------------------------------------------------------- */
 /** \name Transform Locks
  * \{ */
@@ -529,7 +541,7 @@ void headerRotation(TransInfo *t, char str[UI_MAX_DRAW_STR], float final)
 void postInputRotation(TransInfo *t, float values[3])
 {
   float axis_final[3];
-  copy_v3_v3(axis_final, t->orient_matrix[t->orient_axis]);
+  copy_v3_v3(axis_final, t->spacemtx[t->orient_axis]);
   if ((t->con.mode & CON_APPLY) && t->con.applyRot) {
     t->con.applyRot(t, NULL, NULL, axis_final, values);
   }
@@ -870,7 +882,7 @@ void headerResize(TransInfo *t, const float vec- [x], char str[UI_MAX_DRAW_STR])
  *
  * \note this is a tricky area, before making changes see: #29633, #42444
  */
-static void TransMat3ToSize(float mat- [x]- [x], float smat- [x]- [x], float size[3])
+static void TransMat3ToSize(const float mat- [x]- [x], const float smat- [x]- [x], float size[3])
 {
   float rmat- [x][3];
 
diff --git a/source/blender/editors/transform/transform_mode.h b/source/blender/editors/transform/transform_mode.h
index 6180f6d3477..074e89390c2 100644
--- a/source/blender/editors/transform/transform_mode.h
+++ b/source/blender/editors/transform/transform_mode.h
@@ -41,6 +41,7 @@ typedef struct TransDataGenericSlideVert {
 
 /* transform_mode.c */
 bool transdata_check_local_center(TransInfo *t, short around);
+bool transform_mode_is_changeable(const int mode);
 void protectedTransBits(short protectflag, float vec[3]);
 void constraintTransLim(TransInfo *t, TransData *td);
 void postInputRotation(TransInfo *t, float values[3]);
diff --git a/source/blender/editors/transform/transform_mode_bbone_resize.c b/source/blender/editors/transform/transform_mode_bbone_resize.c
index c81049ac379..88a1c099755 100644
--- a/source/blender/editors/transform/transform_mode_bbone_resize.c
+++ b/source/blender/editors/transform/transform_mode_bbone_resize.c
@@ -87,7 +87,10 @@ static void headerBoneSize(TransInfo *t, const float vec- [x], char str[UI_MAX_DRA
   }
 }
 
-static void ElementBoneSize(TransInfo *t, TransDataContainer *tc, TransData *td, float mat- [x][3])
+static void ElementBoneSize(TransInfo *t,
+                            TransDataContainer *tc,
+                            TransData *td,
+                            const float mat- [x][3])
 {
   float tmat- [x]- [x], smat- [x]- [x], oldy;
   float sizemat- [x][3];
@@ -132,6 +135,11 @@ static void applyBoneSize(TransInfo *t, const int UNUSED(mval[2]))
 
   if (t->con.applySize) {
     t->con.applySize(t, NULL, NULL, mat);
+    for (i = 0; i < 3; i++) {
+      if (!(t->con.mode & (CON_AXIS0 << i))) {
+        t->values_final- [x] = 1.0f;
+      }
+    }
   }
 
   copy_m3_m3(t->mat, mat);  // used in gizmo
diff --git a/source/blender/editors/transform/transform_mode_edge_rotate_normal.c b/source/blender/editors/transform/transform_mode_edge_rotate_normal.c
index 18149a09f20..fde0d5b187e 100644
--- a/source/blender/editors/transform/transform_mode_edge_rotate_normal.c
+++ b/source/blender/editors/transform/transform_mode_edge_rotate_normal.c
@@ -81,7 +81,7 @@ static void applyNormalRotation(TransInfo *t, const int UNUSED(mval[2]))
   char str[UI_MAX_DRAW_STR];
 
   float axis_final[3];
-  copy_v3_v3(axis_final, t->orient_matrix[t->orient_axis]);
+  copy_v3_v3(axis_final, t->spacemtx[t->orient_axis]);
 
   if ((t->con.mode & CON_APPLY) && t->con.applyRot) {
     t->con.applyRot(t, NULL, NULL, axis_final, NULL);
diff --git a/source/blender/editors/transform/transform_mode_edge_seq_slide.c b/source/blender/editors/transform/transform_mode_edge_seq_slide.c
index ee91459dcdd..8690cd54a3b 100644
--- a/source/blender/editors/transform/transform_mode_edge_seq_slide.c
+++ b/source/blender/editors/transform/transform_mode_edge_seq_slide.c
@@ -101,9 +101,8 @@ static void applySeqSlide(TransInfo *t, const int mval[2])
   snapSequenceBounds(t, mval);
 
   if (t->con.mode & CON_APPLY) {
-    float pvec- [x] = {0.0f, 0.0f, 0.0f};
     float tvec[3];
-    t->con.applyVec(t, NULL, NULL, t->values, tvec, pvec);
+    t->con.applyVec(t, NULL, NULL, t->values, tvec);
     copy_v3_v3(t->values_final, tvec);
   }
   else {
diff --git a/source/blender/editors/transform/transform_mode_rotate.c b/source/blender/editors/transform/transform_mode_rotate.c
index 6c2b3dc77d2..55c97630487 100644
--- a/source/blender/editors/transform/transform_mode_rotate.c
+++ b/source/blender/editors/transform/transform_mode_rotate.c
@@ -146,7 +146,8 @@ static void applyRotation(TransInfo *t, const int UNUSED(mval[2]))
   snapGridIncrement(t, &final);
 
   float axis_final[3];
-  copy_v3_v3(axis_final, t->orient_matrix[t->orient_axis]);
+  /* Use the negative axis to match the default Z axis of the view matrix. */
+  negate_v3_v3(axis_final, t->spacemtx[t->orient_axis]);
 
   if ((t->con.mode & CON_APPLY) && t->con.applyRot) {
     t->con.applyRot(t, NULL, NULL, axis_final, NULL);
diff --git a/source/blender/editors/transform/transform_mode_shear.c b/source/blender/editors/transform/transform_mode_shear.c
index ba79f5f3c7b..3eeb8a1e758 100644
--- a/source/blender/editors/transform/transform_mode_shear.c
+++ b/source/blender/editors/transform/transform_mode_shear.c
@@ -53,10 +53,10 @@ static void initShear_mouseInputMode(TransInfo *t)
 {
   float dir[3];
   bool dir_flip = false;
-  copy_v3_v3(dir, t->orient_matrix[t->orient_axis_ortho]);
+  copy_v3_v3(dir, t->spacemtx[t->orient_axis_ortho]);
 
   /* Needed for axis aligned view gizmo. */
-  if (t->orientation.user == V3D_ORIENT_VIEW) {
+  if (t->orient[t->orient_curr].type == V3D_ORIENT_VIEW) {
     if (t->orient_axis_ortho == 0) {
       if (t->center2d- [x] > t->mouse.imval[1]) {
         dir_flip = !dir_flip;
@@ -154,8 +154,8 @@ static void applyShear(TransInfo *t, const int UNUSED(mval[2]))
   unit_m3(smat);
   smat- [x]- [x] = value;
 
-  copy_v3_v3(axismat_inv- [x], t->orient_matrix[t->orient_axis_ortho]);
-  copy_v3_v3(axismat_inv- [x], t->orient_matrix[t->orient_axis]);
+  copy_v3_v3(axismat_inv- [x], t->spacemtx[t->orient_axis_ortho]);
+  copy_v3_v3(axismat_inv- [x], t->spacemtx[t->orient_axis]);
   cross_v3_v3v3(axismat_inv- [x], axismat_inv- [x], axismat_inv[2]);
   invert_m3_m3(axismat, axismat_inv);
 
diff --git a/source/blender/editors/transform/transform_mode_shrink_fatten.c b/source/blender/editors/transform/transform_mode_shrink_fatten.c
index ed082e86b6d..ad6cdbbea69 100644
--- a/source/blender/editors/transform/transform_mode_shrink_fatten.c
+++ b/source/blender/editors/transform/transform_mode_shrink_fatten.c
@@ -54,13 +54,13 @@ static void applyShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
   char str[UI_MAX_DRAW_STR];
   size_t ofs = 0;
 
-  distance = -t->values[0];
+  distance = t->values[0];
 
   snapGridIncrement(t, &distance);
 
   applyNumInput(&t->num, &distance);
 
-  t->values_final- [x] = -distance;
+  t->values_final- [x] = distance;
 
   /* header print for NumInput */
   ofs += BLI_strncpy_rlen(str + ofs, TIP_("Shrink/Fatten:"), sizeof(str) - ofs);
diff --git a/source/blender/editors/transform/transform_mode_translate.c b/source/blender/editors/transform/transform_mode_translate.c
index 0a7d8bd90d3..696cd1d0a2d 100644
--- a/source/blender/editors/transform/transform_mode_translate.c
+++ b/source/blender/editors/transform/transform_mode_translate.c
@@ -34,6 +34,7 @@
 #include "BKE_report.h"
 #include "BKE_unit.h"
 
+#include "ED_node.h"
 #include "ED_screen.h"
 
 #include "WM_api.h"
@@ -67,15 +68,27 @@ static void headerTranslation(TransInfo *t, const float vec- [x], char str[UI_MAX_
   }
   else {
     float dvec[3];
-
-    copy_v3_v3(dvec, vec);
-    applyAspectRatio(t, dvec);
+    if (!(t->flag & T_2D_EDIT) && t->con.mode & CON_APPLY) {
+      int i = 0;
+      zero_v3(dvec);
+      if (t->con.mode & CON_AXIS0) {
+        dvec[i++] = vec[0];
+      }
+      if (t->con.mode & CON_AXIS1) {
+        dvec[i++] = vec[1];
+      }
+      if (t->con.mode & CON_AXIS2) {
+        dvec[i++] = vec[2];
+      }
+    }
+    else {
+      copy_v3_v3(dvec, vec);
+      applyAspectRatio(t, dvec);
+    }
 
     dist = len_v3(vec);
     if (!(t->flag & T_2D_EDIT) && t->scene->unit.system) {
-      int i;
-
-      for (i = 0; i < 3; i++) {
+      for (int i = 0; i < 3; i++) {
         bUnit_AsString2(&tvec[NUM_STR_REP_LEN * i],
                         NUM_STR_REP_LEN,
                         dvec- [x] * t->scene->unit.scale_length,
@@ -277,8 +290,7 @@ static void applyTranslationValue(TransInfo *t, const float vec[3])
       }
 
       if (t->con.applyVec) {
-        float pvec[3];
-        t->con.applyVec(t, tc, td, vec, tvec, pvec);
+        t->con.applyVec(t, tc, td, vec, tvec);
       }
       else {
         copy_v3_v3(tvec, vec);
@@ -319,57 +331,53 @@ static void applyTranslationValue(TransInfo *t, const float vec[3])
 static void applyTranslation(TransInfo *t, const int UNUSED(mval[2]))
 {
   char str[UI_MAX_DRAW_STR];
-  float values_final[3];
+  float global_dir[3];
 
   if (t->flag & T_INPUT_IS_VALUES_FINAL) {
-    copy_v3_v3(t->values_final, t->values);
+    mul_v3_m3v3(global_dir, t->spacemtx, t->values);
   }
   else {
-    copy_v3_v3(t->values_final, t->values);
+    copy_v3_v3(global_dir, t->values);
     if ((t->con.mode & CON_APPLY) == 0) {
-      snapGridIncrement(t, t->values_final);
+      snapGridIncrement(t, global_dir);
     }
 
-    if (applyNumInput(&t->num, t->values_final)) {
-      removeAspectRatio(t, t->values_final);
+    if (applyNumInput(&t->num, global_dir)) {
+      removeAspectRatio(t, global_dir);
     }
 
-    applySnapping(t, t->values_final);
+    applySnapping(t, global_dir);
   }
-  copy_v3_v3(values_final, t->values_final);
 
   if (t->con.mode & CON_APPLY) {
-    float pvec- [x] = {0.0f, 0.0f, 0.0f};
-    t->con.applyVec(t, NULL, NULL, t->values_final, values_final, pvec);
-    headerTranslation(t, pvec, str);
-
-    /* only so we have re-usable value with redo, see blender/blender-addons#46741. */
-    mul_v3_m3v3(t->values_final, t->con.imtx, values_final);
+    float in[3];
+    copy_v3_v3(in, global_dir);
+    t->con.applyVec(t, NULL, NULL, in, global_dir);
+    headerTranslation(t, global_dir, str);
   }
   else {
-    headerTranslation(t, t->values_final, str);
-    copy_v3_v3(values_final, t->values_final);
+    headerTranslation(t, global_dir, str);
   }
 
-  /* don't use 't->values' now on */
-
-  applyTranslationValue(t, values_final);
+  applyTranslationValue(t, global_dir);
 
   /* evil hack - redo translation if clipping needed */
-  if (t->flag & T_CLIP_UV && clipUVTransform(t, values_final, 0)) {
-    applyTranslationValue(t, values_final);
+  if (t->flag & T_CLIP_UV && clipUVTransform(t, global_dir, 0)) {
+    applyTranslationValue(t, global_dir);
 
     /* In proportional edit it can happen that */
     /* vertices in the radius of the brush end */
     /* outside the clipping area               */
     /* XXX HACK - dg */
-    if (t->flag & T_PROP_EDIT_ALL) {
+    if (t->flag & T_PROP_EDIT) {
       clipUVData(t);
     }
   }
 
-  recalcData(t);
+  /* Set the redo value. */
+  mul_v3_m3v3(t->values_final, t->spacemtx_inv, global_dir);
 
+  recalcData(t);
   ED_area_status_text(t->area, str);
 }
 
diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c
index 36f42992573..2f8b2dc9a5e 100644
--- a/source/blender/editors/transform/transform_ops.c
+++ b/source/blender/editors/transform/transform_ops.c
@@ -20,7 +20,6 @@
 
 #include "MEM_guardedalloc.h"
 
-#include "DNA_mesh_types.h"
 #include "DNA_object_types.h"
 #include "DNA_scene_types.h"
 
@@ -32,7 +31,6 @@
 #include "BKE_context.h"
 #include "BKE_editmesh.h"
 #include "BKE_global.h"
-#include "BKE_layer.h"
 #include "BKE_report.h"
 #include "BKE_scene.h"
 
@@ -1042,11 +1040,11 @@ static void TRANSFORM_OT_bbone_resize(struct wmOperatorType *ot)
   ot->exec = transform_exec;
   ot->modal = transform_modal;
   ot->cancel = transform_cancel;
-  ot->poll = ED_operator_editarmature;
+  ot->poll = ED_operator_object_active;
   ot->poll_property = transform_poll_property;
 
   RNA_def_float_translation(
-      ot->srna, "value", 2, VecOne, -FLT_MAX, FLT_MAX, "Display Size", "", -FLT_MAX, FLT_MAX);
+      ot->srna, "value", 3, VecOne, -FLT_MAX, FLT_MAX, "Display Size", "", -FLT_MAX, FLT_MAX);
 
   WM_operatortype_props_advanced_begin(ot);
 
diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c
index 76823adfd20..7ebe419adb7 100644
--- a/source/blender/editors/transform/transform_orientations.c
+++ b/source/blender/editors/transform/transform_orientations.c
@@ -32,7 +32,6 @@
 #include "DNA_screen_types.h"
 #include "DNA_space_types.h"
 #include "DNA_view3d_types.h"
-#include "DNA_workspace_types.h"
 
 #include "BLI_listbase.h"
 #include "BLI_math.h"
@@ -47,7 +46,6 @@
 #include "BKE_layer.h"
 #include "BKE_report.h"
 #include "BKE_scene.h"
-#include "BKE_workspace.h"
 
 #include "BLT_translation.h"
 
@@ -433,94 +431,179 @@ static int count_bone_select(bArmature *arm, ListBase *lb, const bool do_it)
   return total;
 }
 
-void initTransformOrientation(bContext *C, TransInfo *t)
+void ED_transform_calc_orientation_from_type(const bContext *C, float r_mat- [x][3])
 {
-  Object *ob = CTX_data_active_object(C);
-  Object *obedit = CTX_data_active_object(C);
+  ARegion *region = CTX_wm_region(C);
+  Scene *scene = CTX_data_scene(C);
+  ViewLayer *view_layer = CTX_data_view_layer(C);
+  Object *obedit = CTX_data_edit_object(C);
+  RegionView3D *rv3d = region->regiondata;
+  Object *ob = OBACT(view_layer);
+  const short orientation_type = scene->orientation_slots[SCE_ORIENT_DEFAULT].type;
+  const short orientation_index_custom = scene->orientation_slots[SCE_ORIENT_DEFAULT].index_custom;
+  const int pivot_point = scene->toolsettings->transform_pivot_point;
 
-  switch (t->orientation.user) {
-    case V3D_ORIENT_GLOBAL:
-      unit_m3(t->spacemtx);
-      BLI_strncpy(t->spacename, TIP_("global"), sizeof(t->spacename));
-      break;
+  ED_transform_calc_orientation_from_type_ex(
+      C, r_mat, scene, rv3d, ob, obedit, orientation_type, orientation_index_custom, pivot_point);
+}
 
-    case V3D_ORIENT_GIMBAL:
-      unit_m3(t->spacemtx);
-      if (ob && gimbal_axis(ob, t->spacemtx)) {
-        BLI_strncpy(t->spacename, TIP_("gimbal"), sizeof(t->spacename));
-        break;
+short ED_transform_calc_orientation_from_type_ex(const bContext *C,
+                                                 float r_mat- [x][3],
+                                                 /* extra args (can be accessed from context) */
+                                                 Scene *scene,
+                                                 RegionView3D *rv3d,
+                                                 Object *ob,
+                                                 Object *obedit,
+                                                 const short orientation_type,
+                                                 int orientation_index_custom,
+                                                 const int pivot_point)
+{
+  switch (orientation_type) {
+    case V3D_ORIENT_GLOBAL: {
+      unit_m3(r_mat);
+      return V3D_ORIENT_GLOBAL;
+    }
+    case V3D_ORIENT_GIMBAL: {
+      if (ob && gimbal_axis(ob, r_mat)) {
+        return V3D_ORIENT_GIMBAL;
       }
-      ATTR_FALLTHROUGH; /* no gimbal fallthrough to normal */
-    case V3D_ORIENT_NORMAL:
+      /* if not gimbal, fall through to normal */
+      ATTR_FALLTHROUGH;
+    }
+    case V3D_ORIENT_NORMAL: {
       if (obedit || (ob && ob->mode & OB_MODE_POSE)) {
-        BLI_strncpy(t->spacename, TIP_("normal"), sizeof(t->spacename));
-        ED_getTransformOrientationMatrix(C, t->spacemtx, t->around);
-        break;
+        ED_getTransformOrientationMatrix(C, r_mat, pivot_point);
+        return V3D_ORIENT_NORMAL;
       }
-      ATTR_FALLTHROUGH; /* we define 'normal' as 'local' in Object mode */
-    case V3D_ORIENT_LOCAL:
-      BLI_strncpy(t->spacename, TIP_("local"), sizeof(t->spacename));
-
+      /* no break we define 'normal' as 'local' in Object mode */
+      ATTR_FALLTHROUGH;
+    }
+    case V3D_ORIENT_LOCAL: {
       if (ob) {
-        copy_m3_m4(t->spacemtx, ob->obmat);
-        normalize_m3(t->spacemtx);
-      }
-      else {
-        unit_m3(t->spacemtx);
+        if (ob->mode & OB_MODE_POSE) {
+          /* each bone moves on its own local axis, but  to avoid confusion,
+           * use the active pones axis for display [#33575], this works as expected on a single
+           * bone and users who select many bones will understand what's going on and what local
+           * means when they start transforming */
+          ED_getTransformOrientationMatrix(C, r_mat, pivot_point);
+        }
+        else {
+          copy_m3_m4(r_mat, ob->obmat);
+          normalize_m3(r_mat);
+        }
+        return V3D_ORIENT_LOCAL;
       }
-
-      break;
-
-    case V3D_ORIENT_VIEW:
-      if ((t->spacetype == SPACE_VIEW3D) && (t->region->regiontype == RGN_TYPE_WINDOW)) {
-        RegionView3D *rv3d = t->region->regiondata;
-        float mat- [x][3];
-
-        BLI_strncpy(t->spacename, TIP_("view"), sizeof(t->spacename));
-        copy_m3_m4(mat, rv3d->viewinv);
-        normalize_m3(mat);
-        copy_m3_m3(t->spacemtx, mat);
+      unit_m3(r_mat);
+      return V3D_ORIENT_GLOBAL;
+    }
+    case V3D_ORIENT_VIEW: {
+      if (rv3d != NULL) {
+        copy_m3_m4(r_mat, rv3d->viewinv);
+        normalize_m3(r_mat);
       }
       else {
-        unit_m3(t->spacemtx);
+        unit_m3(r_mat);
       }
-      break;
+      return V3D_ORIENT_VIEW;
+    }
     case V3D_ORIENT_CURSOR: {
-      BLI_strncpy(t->spacename, TIP_("cursor"), sizeof(t->spacename));
-      BKE_scene_cursor_rot_to_mat3(&t->scene->cursor, t->spacemtx);
-      break;
+      BKE_scene_cursor_rot_to_mat3(&scene->cursor, r_mat);
+      return V3D_ORIENT_CURSOR;
     }
-    case V3D_ORIENT_CUSTOM_MATRIX:
-      /* Already set. */
-      BLI_strncpy(t->spacename, TIP_("custom"), sizeof(t->spacename));
+    case V3D_ORIENT_CUSTOM_MATRIX: {
+      /* Do nothing. */;
       break;
+    }
     case V3D_ORIENT_CUSTOM:
-      BLI_strncpy(t->spacename, t->orientation.custom->name, sizeof(t->spacename));
-
-      if (applyTransformOrientation(t->orientation.custom, t->spacemtx, t->spacename)) {
-        /* pass */
-      }
-      else {
-        unit_m3(t->spacemtx);
-      }
+    default: {
+      BLI_assert(orientation_type >= V3D_ORIENT_CUSTOM);
+      TransformOrientation *custom_orientation = BKE_scene_transform_orientation_find(
+          scene, orientation_index_custom);
+      applyTransformOrientation(custom_orientation, r_mat, NULL);
       break;
+    }
   }
 
-  if (t->orient_matrix_is_set == false) {
-    t->orient_matrix_is_set = true;
-    if (t->flag & T_MODAL) {
-      /* Rotate for example defaults to operating on the view plane. */
-      t->orientation.unset = V3D_ORIENT_VIEW;
-      copy_m3_m4(t->orient_matrix, t->viewinv);
-      normalize_m3(t->orient_matrix);
-      negate_m3(t->orient_matrix);
-    }
-    else {
-      copy_m3_m3(t->orient_matrix, t->spacemtx);
+  return orientation_type;
+}
+
+/* Sets the matrix of the specified space orientation.
+ * If the matrix cannot be obtained, an orientation different from the one
+ * informed is returned */
+short transform_orientation_matrix_get(bContext *C,
+                                       TransInfo *t,
+                                       const short orientation,
+                                       const float custom- [x][3],
+                                       float r_spacemtx- [x][3])
+{
+  if (orientation == V3D_ORIENT_CUSTOM_MATRIX) {
+    copy_m3_m3(r_spacemtx, custom);
+    return V3D_ORIENT_CUSTOM_MATRIX;
+  }
+
+  if ((t->spacetype == SPACE_VIEW3D) && (t->region->regiontype == RGN_TYPE_WINDOW)) {
+    Object *ob = CTX_data_active_object(C);
+    Object *obedit = CTX_data_active_object(C);
+    RegionView3D *rv3d = t->region->regiondata;
+    int orientation_index_custom = 0;
+
+    if (orientation >= V3D_ORIENT_CUSTOM) {
+      orientation_index_custom = orientation - V3D_ORIENT_CUSTOM;
     }
+
+    return ED_transform_calc_orientation_from_type_ex(
+        C,
+        r_spacemtx,
+        /* extra args (can be accessed from context) */
+        t->scene,
+        rv3d,
+        ob,
+        obedit,
+        orientation,
+        orientation_index_custom,
+        t->around);
+  }
+
+  unit_m3(r_spacemtx);
+  return V3D_ORIENT_GLOBAL;
+}
+
+const char *transform_orientations_spacename_get(TransInfo *t, const short orient_type)
+{
+  switch (orient_type) {
+    case V3D_ORIENT_GLOBAL:
+      return TIP_("global");
+    case V3D_ORIENT_GIMBAL:
+      return TIP_("gimbal");
+    case V3D_ORIENT_NORMAL:
+      return TIP_("normal");
+    case V3D_ORIENT_LOCAL:
+      return TIP_("local");
+    case V3D_ORIENT_VIEW:
+      return TIP_("view");
+    case V3D_ORIENT_CURSOR:
+      return TIP_("cursor");
+    case V3D_ORIENT_CUSTOM_MATRIX:
+      return TIP_("custom");
+    case V3D_ORIENT_CUSTOM:
+    default:
+      BLI_assert(orient_type >= V3D_ORIENT_CUSTOM);
+      TransformOrientation *ts = BKE_scene_transform_orientation_find(
+          t->scene, orient_type - V3D_ORIENT_CUSTOM);
+      return ts->name;
   }
 }
 
+void transform_orientations_current_set(TransInfo *t, const short orient_index)
+{
+  const short orientation = t->orient[orient_index].type;
+  const char *spacename = transform_orientations_spacename_get(t, orientation);
+
+  BLI_strncpy(t->spacename, spacename, sizeof(t->spacename));
+  copy_m3_m3(t->spacemtx, t->orient[orient_index].matrix);
+  invert_m3_m3(t->spacemtx_inv, t->spacemtx);
+}
+
 /**
  * utility function - get first n, selected vert/edge/faces
  */
diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c
index 154af6c8ae2..3eb6c6763fd 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -1366,13 +1366,12 @@ short snapObjectsTransform(
   return ED_transform_snap_object_project_view3d_ex(
       t->tsnap.object_context,
       t->depsgraph,
-      t->scene->toolsettings->snap_mode,
+      t->settings->snap_mode,
       &(const struct SnapObjectParams){
           .snap_select = t->tsnap.modeSelect,
           .use_object_edit_cage = (t->flag & T_EDIT) != 0,
-          .use_occlusion_test = t->scene->toolsettings->snap_mode != SCE_SNAP_MODE_FACE,
-          .use_backface_culling = (t->scene->toolsettings->snap_flag &
-                                   SCE_SNAP_BACKFACE_CULLING) != 0,
+          .use_occlusion_test = t->settings->snap_mode != SCE_SNAP_MODE_FACE,
+          .use_backface_culling = (t->settings->snap_flag & SCE_SNAP_BACKFACE_CULLING) != 0,
       },
       mval,
       target,
@@ -1749,8 +1748,8 @@ static void applyGridIncrement(
           float local_axis[3];
           float pos_on_axis[3];
 
-          copy_v3_v3(local_axis, t->con.mtx[i]);
-          copy_v3_v3(pos_on_axis, t->con.mtx[i]);
+          copy_v3_v3(local_axis, t->spacemtx[i]);
+          copy_v3_v3(pos_on_axis, t->spacemtx[i]);
 
           /* amount of movement on axis from initial pos */
           mul_v3_fl(pos_on_axis, val[i]);

Here the patch with the fix for 2.83 [P1606: Fix for #78424: Individual Origins + Normal](https://archive.blender.org/developer/P1606.txt) ```diff From 342945cf2c7bcabc8a5c62117b94284abe451452 Mon Sep 17 00:00:00 2001 From: Germano Cavalcante <germano.costa@ig.com.br> Date: Wed, 26 Aug 2020 10:25:54 -0300 Subject: Transform Orientation Refactor diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h index beba4a7199b..403e7d79781 100644 --- a/source/blender/editors/include/ED_transform.h +++ b/source/blender/editors/include/ED_transform.h @@ -179,16 +179,16 @@ void ED_widgetgroup_gizmo2d_rotate_callbacks_set(struct wmGizmoGroupType *gzgt); #define SNAP_INCREMENTAL_ANGLE DEG2RAD(5.0) void ED_transform_calc_orientation_from_type(const struct bContext *C, float r_mat- [x][3]); -void ED_transform_calc_orientation_from_type_ex(const struct bContext *C, - float r_mat- [x][3], - /* extra args */ - struct Scene *scene, - struct RegionView3D *rv3d, - struct Object *ob, - struct Object *obedit, - const short orientation_type, - int orientation_index_custom, - const int pivot_point); +short ED_transform_calc_orientation_from_type_ex(const struct bContext *C, + float r_mat- [x][3], + /* extra args */ + struct Scene *scene, + struct RegionView3D *rv3d, + struct Object *ob, + struct Object *obedit, + const short orientation_type, + int orientation_index_custom, + const int pivot_point); struct TransformBounds { float center- [x]; /* Center for transform widget. */ diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index d0973cf8298..ae9b64acf93 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -779,9 +779,10 @@ wmKeyMap *transform_modal_keymap(wmKeyConfig *keyconf) return keymap; } -static void transform_event_xyz_constraint(TransInfo *t, short key_type, char cmode, bool is_plane) +static void transform_event_xyz_constraint(TransInfo *t, short key_type, bool is_plane) { if (!(t->flag & T_NO_CONSTRAINT)) { + char cmode = constraintModeToChar(t); int constraint_axis, constraint_plane; const bool edit_2d = (t->flag & T_2D_EDIT) != 0; const char *msg1 = "", *msg2 = "", *msg3 = ""; @@ -825,11 +826,17 @@ static void transform_event_xyz_constraint(TransInfo *t, short key_type, char cm } } else if (!edit_2d) { - if (cmode != axis) { - /* First press, constraint to an axis. */ - t->orientation.index = 0; - const short *orientation_ptr = t->orientation.types[t->orientation.index]; - const short orientation = orientation_ptr ? *orientation_ptr : V3D_ORIENT_GLOBAL; + if (t->orient_curr == 0 || ELEM(cmode, '\0', axis)) { + /* Successive presses on existing axis, cycle orientation modes. */ + t->orient_curr = (short)((t->orient_curr + 1) % (int)ARRAY_SIZE(t->orient)); + transform_orientations_current_set(t, t->orient_curr); + } + + if (t->orient_curr == 0) { + stopConstraint(t); + } + else { + const short orientation = t->orient[t->orient_curr].type; if (is_plane == false) { setUserConstraint(t, orientation, constraint_axis, msg2); } @@ -837,24 +844,6 @@ static void transform_event_xyz_constraint(TransInfo *t, short key_type, char cm setUserConstraint(t, orientation, constraint_plane, msg3); } } - else { - /* Successive presses on existing axis, cycle orientation modes. */ - t->orientation.index = (t->orientation.index + 1) % ARRAY_SIZE(t->orientation.types); - - if (t->orientation.index == 0) { - stopConstraint(t); - } - else { - const short *orientation_ptr = t->orientation.types[t->orientation.index]; - const short orientation = orientation_ptr ? *orientation_ptr : V3D_ORIENT_GLOBAL; - if (is_plane == false) { - setUserConstraint(t, orientation, constraint_axis, msg2); - } - else { - setUserConstraint(t, orientation, constraint_plane, msg3); - } - } - } } t->redraw |= TREDRAW_HARD; } @@ -862,7 +851,6 @@ static void transform_event_xyz_constraint(TransInfo *t, short key_type, char cm int transformEvent(TransInfo *t, const wmEvent *event) { - char cmode = constraintModeToChar(t); bool handled = false; const int modifiers_prev = t->modifiers; const int mode_prev = t->mode; @@ -909,74 +897,59 @@ int transformEvent(TransInfo *t, const wmEvent *event) break; case TFM_MODAL_TRANSLATE: /* only switch when... */ - if (ELEM(t->mode, - TFM_ROTATION, - TFM_RESIZE, - TFM_TRACKBALL, - TFM_EDGE_SLIDE, - TFM_VERT_SLIDE)) { - restoreTransObjects(t); - resetTransModal(t); - resetTransRestrictions(t); - transform_mode_init(t, NULL, TFM_TRANSLATION); - initSnapping(t, NULL); // need to reinit after mode change - t->redraw |= TREDRAW_HARD; - handled = true; - } - else if (t->mode == TFM_SEQ_SLIDE) { - t->flag ^= T_ALT_TRANSFORM; - t->redraw |= TREDRAW_HARD; - handled = true; - } - else { - if (t->obedit_type == OB_MESH) { - if ((t->mode == TFM_TRANSLATION) && (t->spacetype == SPACE_VIEW3D)) { - restoreTransObjects(t); + if (t->mode == TFM_TRANSLATION) { + if ((t->obedit_type == OB_MESH) && (t->spacetype == SPACE_VIEW3D)) { + restoreTransObjects(t); + resetTransModal(t); + resetTransRestrictions(t); + + /* first try edge slide */ + transform_mode_init(t, NULL, TFM_EDGE_SLIDE); + /* if that fails, do vertex slide */ + if (t->state == TRANS_CANCEL) { resetTransModal(t); + t->state = TRANS_STARTING; + transform_mode_init(t, NULL, TFM_VERT_SLIDE); + } + /* vert slide can fail on unconnected vertices (rare but possible) */ + if (t->state == TRANS_CANCEL) { + resetTransModal(t); + t->state = TRANS_STARTING; + restoreTransObjects(t); resetTransRestrictions(t); - - /* first try edge slide */ - transform_mode_init(t, NULL, TFM_EDGE_SLIDE); - /* if that fails, do vertex slide */ - if (t->state == TRANS_CANCEL) { - resetTransModal(t); - t->state = TRANS_STARTING; - transform_mode_init(t, NULL, TFM_VERT_SLIDE); - } - /* vert slide can fail on unconnected vertices (rare but possible) */ - if (t->state == TRANS_CANCEL) { - resetTransModal(t); - t->state = TRANS_STARTING; - restoreTransObjects(t); - resetTransRestrictions(t); - transform_mode_init(t, NULL, TFM_TRANSLATION); - } - initSnapping(t, NULL); // need to reinit after mode change - t->redraw |= TREDRAW_HARD; - handled = true; + transform_mode_init(t, NULL, TFM_TRANSLATION); } + initSnapping(t, NULL); // need to reinit after mode change + t->redraw |= TREDRAW_HARD; + handled = true; } else if (t->options & (CTX_MOVIECLIP | CTX_MASK)) { - if (t->mode == TFM_TRANSLATION) { - restoreTransObjects(t); + restoreTransObjects(t); - t->flag ^= T_ALT_TRANSFORM; - t->redraw |= TREDRAW_HARD; - handled = true; - } + t->flag ^= T_ALT_TRANSFORM; + t->redraw |= TREDRAW_HARD; + handled = true; } } + else if (t->mode == TFM_SEQ_SLIDE) { + t->flag ^= T_ALT_TRANSFORM; + t->redraw |= TREDRAW_HARD; + handled = true; + } + else if (transform_mode_is_changeable(t->mode)) { + restoreTransObjects(t); + resetTransModal(t); + resetTransRestrictions(t); + transform_mode_init(t, NULL, TFM_TRANSLATION); + initSnapping(t, NULL); // need to reinit after mode change + t->redraw |= TREDRAW_HARD; + handled = true; + } break; case TFM_MODAL_ROTATE: /* only switch when... */ if (!(t->options & CTX_TEXTURE) && !(t->options & (CTX_MOVIECLIP | CTX_MASK))) { - if (ELEM(t->mode, - TFM_ROTATION, - TFM_RESIZE, - TFM_TRACKBALL, - TFM_TRANSLATION, - TFM_EDGE_SLIDE, - TFM_VERT_SLIDE)) { + if (transform_mode_is_changeable(t->mode)) { restoreTransObjects(t); resetTransModal(t); resetTransRestrictions(t); @@ -995,15 +968,23 @@ int transformEvent(TransInfo *t, const wmEvent *event) break; case TFM_MODAL_RESIZE: /* only switch when... */ - if (ELEM(t->mode, - TFM_ROTATION, - TFM_TRANSLATION, - TFM_TRACKBALL, - TFM_EDGE_SLIDE, - TFM_VERT_SLIDE)) { + if (t->mode == TFM_RESIZE) { + if (t->options & CTX_MOVIECLIP) { + restoreTransObjects(t); + t->flag ^= T_ALT_TRANSFORM; + t->redraw |= TREDRAW_HARD; + handled = true; + } + } + else if (t->mode == TFM_SHRINKFATTEN) { + t->flag ^= T_ALT_TRANSFORM; + t->redraw |= TREDRAW_HARD; + handled = true; + } + else if (transform_mode_is_changeable(t->mode)) { /* Scale isn't normally very useful after extrude along normals, see #39756 */ - if ((t->con.mode & CON_APPLY) && (t->con.orientation == V3D_ORIENT_NORMAL)) { + if ((t->con.mode & CON_APPLY) && (t->orient[t->orient_curr].type == V3D_ORIENT_NORMAL)) { stopConstraint(t); } @@ -1015,20 +996,6 @@ int transformEvent(TransInfo *t, const wmEvent *event) t->redraw |= TREDRAW_HARD; handled = true; } - else if (t->mode == TFM_SHRINKFATTEN) { - t->flag ^= T_ALT_TRANSFORM; - t->redraw |= TREDRAW_HARD; - handled = true; - } - else if (t->mode == TFM_RESIZE) { - if (t->options & CTX_MOVIECLIP) { - restoreTransObjects(t); - - t->flag ^= T_ALT_TRANSFORM; - t->redraw |= TREDRAW_HARD; - handled = true; - } - } break; case TFM_MODAL_SNAP_INV_ON: @@ -1048,42 +1015,42 @@ int transformEvent(TransInfo *t, const wmEvent *event) break; case TFM_MODAL_AXIS_X: if (!(t->flag & T_NO_CONSTRAINT)) { - transform_event_xyz_constraint(t, EVT_XKEY, cmode, false); + transform_event_xyz_constraint(t, EVT_XKEY, false); t->redraw |= TREDRAW_HARD; handled = true; } break; case TFM_MODAL_AXIS_Y: if ((t->flag & T_NO_CONSTRAINT) == 0) { - transform_event_xyz_constraint(t, EVT_YKEY, cmode, false); + transform_event_xyz_constraint(t, EVT_YKEY, false); t->redraw |= TREDRAW_HARD; handled = true; } break; case TFM_MODAL_AXIS_Z: if ((t->flag & (T_NO_CONSTRAINT)) == 0) { - transform_event_xyz_constraint(t, EVT_ZKEY, cmode, false); + transform_event_xyz_constraint(t, EVT_ZKEY, false); t->redraw |= TREDRAW_HARD; handled = true; } break; case TFM_MODAL_PLANE_X: if ((t->flag & (T_NO_CONSTRAINT | T_2D_EDIT)) == 0) { - transform_event_xyz_constraint(t, EVT_XKEY, cmode, true); + transform_event_xyz_constraint(t, EVT_XKEY, true); t->redraw |= TREDRAW_HARD; handled = true; } break; case TFM_MODAL_PLANE_Y: if ((t->flag & (T_NO_CONSTRAINT | T_2D_EDIT)) == 0) { - transform_event_xyz_constraint(t, EVT_YKEY, cmode, true); + transform_event_xyz_constraint(t, EVT_YKEY, true); t->redraw |= TREDRAW_HARD; handled = true; } break; case TFM_MODAL_PLANE_Z: if ((t->flag & (T_NO_CONSTRAINT | T_2D_EDIT)) == 0) { - transform_event_xyz_constraint(t, EVT_ZKEY, cmode, true); + transform_event_xyz_constraint(t, EVT_ZKEY, true); t->redraw |= TREDRAW_HARD; handled = true; } @@ -1229,17 +1196,7 @@ int transformEvent(TransInfo *t, const wmEvent *event) stopConstraint(t); } else { - if (event->shift) { - /* bit hackish... but it prevents mmb select to print the - * orientation from menu */ - float mati- [x][3]; - strcpy(t->spacename, "global"); - unit_m3(mati); - initSelectConstraint(t, mati); - } - else { - initSelectConstraint(t, t->spacemtx); - } + initSelectConstraint(t); postSelectConstraint(t); } } @@ -1252,7 +1209,7 @@ int transformEvent(TransInfo *t, const wmEvent *event) break; } /* only switch when... */ - if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL)) { + if (t->mode != TFM_TRANSLATION && transform_mode_is_changeable(t->mode)) { restoreTransObjects(t); resetTransModal(t); resetTransRestrictions(t); @@ -1267,7 +1224,7 @@ int transformEvent(TransInfo *t, const wmEvent *event) break; } /* only switch when... */ - if (ELEM(t->mode, TFM_ROTATION, TFM_TRANSLATION, TFM_TRACKBALL)) { + if (t->mode != TFM_RESIZE && transform_mode_is_changeable(t->mode)) { restoreTransObjects(t); resetTransModal(t); resetTransRestrictions(t); @@ -1283,7 +1240,7 @@ int transformEvent(TransInfo *t, const wmEvent *event) } /* only switch when... */ if (!(t->options & CTX_TEXTURE)) { - if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_TRANSLATION)) { + if (transform_mode_is_changeable(t->mode)) { restoreTransObjects(t); resetTransModal(t); resetTransRestrictions(t); @@ -1638,6 +1595,25 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op) int proportional = 0; PropertyRNA *prop; + if (!(t->con.mode & CON_APPLY) && (t->flag & T_MODAL) && + ELEM(t->mode, TFM_TRANSLATION, TFM_RESIZE)) { + /* When redoing these modes the first time, it's more convenient to save + * in the Global orientation. */ + if (t->mode == TFM_TRANSLATION) { + mul_m3_v3(t->spacemtx, t->values_final); + } + else { + float tmat- [x]- [x], sizemat- [x][3]; + size_to_mat3(sizemat, t->values_final); + mul_m3_m3m3(tmat, t->spacemtx, sizemat); + mat3_to_size(t->values_final, tmat); + } + + BLI_assert(t->orient_curr == 0); + unit_m3(t->spacemtx); + t->orient- [x].type = V3D_ORIENT_GLOBAL; + } + // Save back mode in case we're in the generic operator if ((prop = RNA_struct_find_property(op->ptr, "mode"))) { RNA_property_enum_set(op->ptr, prop, t->mode); @@ -1700,18 +1676,6 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op) ts->prop_mode = t->prop_mode; } } - - if (t->spacetype == SPACE_VIEW3D) { - if ((prop = RNA_struct_find_property(op->ptr, "orient_type")) && - !RNA_property_is_set(op->ptr, prop) && - (t->orientation.user != V3D_ORIENT_CUSTOM_MATRIX)) { - TransformOrientationSlot *orient_slot = &t->scene->orientation_slots[SCE_ORIENT_DEFAULT]; - orient_slot->type = t->orientation.user; - BLI_assert(((orient_slot->index_custom == -1) && (t->orientation.custom == NULL)) || - (BKE_scene_transform_orientation_get_index(t->scene, t->orientation.custom) == - orient_slot->index_custom)); - } - } } if (t->flag & T_MODAL) { @@ -1741,34 +1705,6 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op) RNA_property_boolean_set(op->ptr, prop, (t->flag & T_NO_MIRROR) == 0); } - /* Orientation used for redo. */ - const bool use_orient_axis = (t->orient_matrix_is_set && - (RNA_struct_find_property(op->ptr, "orient_axis") != NULL)); - short orientation; - if (t->con.mode & CON_APPLY) { - orientation = t->con.orientation; - if (orientation == V3D_ORIENT_CUSTOM) { - const int orientation_index_custom = BKE_scene_transform_orientation_get_index( - t->scene, t->orientation.custom); - /* Maybe we need a t->con.custom_orientation? - * Seems like it would always match t->orientation.custom. */ - orientation = V3D_ORIENT_CUSTOM + orientation_index_custom; - BLI_assert(orientation >= V3D_ORIENT_CUSTOM); - } - } - else if ((t->orientation.user == V3D_ORIENT_CUSTOM_MATRIX) && - (prop = RNA_struct_find_property(op->ptr, "orient_matrix_type"))) { - orientation = RNA_property_enum_get(op->ptr, prop); - } - else if (use_orient_axis) { - /* We're not using an orientation, use the fallback. */ - orientation = t->orientation.unset; - } - else { - orientation = V3D_ORIENT_GLOBAL; - unit_m3(t->spacemtx); - } - if ((prop = RNA_struct_find_property(op->ptr, "orient_axis"))) { if (t->flag & T_MODAL) { if (t->con.mode & CON_APPLY) { @@ -1788,56 +1724,41 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op) } } - if ((prop = RNA_struct_find_property(op->ptr, "orient_matrix"))) { - if (t->flag & T_MODAL) { - if (orientation != V3D_ORIENT_CUSTOM_MATRIX) { - if (t->flag & T_MODAL) { - RNA_enum_set(op->ptr, "orient_matrix_type", orientation); - } - } - if (t->con.mode & CON_APPLY) { - RNA_float_set_array(op->ptr, "orient_matrix", &t->con.mtx- [x][0]); - } - else if (use_orient_axis) { - RNA_float_set_array(op->ptr, "orient_matrix", &t->orient_matrix- [x][0]); - } - else { - RNA_float_set_array(op->ptr, "orient_matrix", &t->spacemtx- [x][0]); - } - } - } - if ((prop = RNA_struct_find_property(op->ptr, "orient_type"))) { - /* constraint orientation can be global, even if user selects something else - * so use the orientation in the constraint if set */ + short orient_type_set, orient_type_curr; + orient_type_set = RNA_property_is_set(op->ptr, prop) ? RNA_property_enum_get(op->ptr, prop) : + -1; + orient_type_curr = t->orient[t->orient_curr].type; - /* Use 'orient_matrix' instead. */ - if (t->flag & T_MODAL) { - if (orientation != V3D_ORIENT_CUSTOM_MATRIX) { - RNA_property_enum_set(op->ptr, prop, orientation); - } + if (!ELEM(orient_type_curr, orient_type_set, V3D_ORIENT_CUSTOM_MATRIX)) { + RNA_property_enum_set(op->ptr, prop, orient_type_curr); + orient_type_set = orient_type_curr; + } + + if (((prop = RNA_struct_find_property(op->ptr, "orient_matrix_type")) && + !RNA_property_is_set(op->ptr, prop))) { + /* Set the first time to register on redo. */ + RNA_property_enum_set(op->ptr, prop, orient_type_set); + RNA_float_set_array(op->ptr, "orient_matrix", &t->spacemtx- [x][0]); } } if ((prop = RNA_struct_find_property(op->ptr, "constraint_axis"))) { bool constraint_axis- [x] = {false, false, false}; - if (t->flag & T_MODAL) { - /* Only set if needed, so we can hide in the UI when nothing is set. - * See 'transform_poll_property'. */ - if (t->con.mode & CON_APPLY) { - if (t->con.mode & CON_AXIS0) { - constraint_axis- [x] = true; - } - if (t->con.mode & CON_AXIS1) { - constraint_axis- [x] = true; - } - if (t->con.mode & CON_AXIS2) { - constraint_axis- [x] = true; - } + if (t->con.mode & CON_APPLY) { + if (t->con.mode & CON_AXIS0) { + constraint_axis- [x] = true; } - if (ELEM(true, UNPACK3(constraint_axis))) { - RNA_property_boolean_set_array(op->ptr, prop, constraint_axis); + if (t->con.mode & CON_AXIS1) { + constraint_axis- [x] = true; } + if (t->con.mode & CON_AXIS2) { + constraint_axis- [x] = true; + } + RNA_property_boolean_set_array(op->ptr, prop, constraint_axis); + } + else { + RNA_property_unset(op->ptr, prop); } } @@ -1938,13 +1859,6 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve } } - if (CTX_wm_view3d(C) != NULL) { - Object *ob = CTX_data_active_object(C); - if (ob && ob->mode == OB_MODE_SCULPT && ob->sculpt) { - options |= CTX_SCULPT; - } - } - t->options = options; t->mode = mode; @@ -1963,7 +1877,10 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve unit_m3(t->spacemtx); initTransInfo(C, t, op, event); - initTransformOrientation(C, t); + + /* Use the custom orientation when it is set. */ + short orient_index = t->orient- [x].type == V3D_ORIENT_CUSTOM_MATRIX ? 0 : t->orient_curr; + transform_orientations_current_set(t, orient_index); if (t->spacetype == SPACE_VIEW3D) { t->draw_handle_apply = ED_region_draw_cb_activate( @@ -2088,33 +2005,6 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve calculatePropRatio(t); calculateCenter(t); - /* Overwrite initial values if operator supplied a non-null vector. - * - * Run before init functions so 'values_modal_offset' can be applied on mouse input. - */ - BLI_assert(is_zero_v4(t->values_modal_offset)); - if ((prop = RNA_struct_find_property(op->ptr, "value")) && RNA_property_is_set(op->ptr, prop)) { - float values- [x] = {0}; /* in case value isn't length 4, avoid uninitialized memory */ - - if (RNA_property_array_check(prop)) { - RNA_float_get_array(op->ptr, "value", values); - } - else { - values- [x] = RNA_float_get(op->ptr, "value"); - } - - copy_v4_v4(t->values, values); - - if (t->flag & T_MODAL) { - copy_v4_v4(t->values_modal_offset, values); - t->redraw = TREDRAW_HARD; - } - else { - copy_v4_v4(t->values, values); - t->flag |= T_INPUT_IS_VALUES_FINAL; - } - } - if (event) { /* Initialize accurate transform to settings requested by keymap. */ bool use_accurate = false; @@ -2145,38 +2035,8 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve } /* Constraint init from operator */ - if ((t->flag & T_MODAL) || - /* For mirror operator the constraint axes are effectively the values. */ - (RNA_struct_find_property(op->ptr, "value") == NULL)) { - if ((prop = RNA_struct_find_property(op->ptr, "constraint_axis")) && - RNA_property_is_set(op->ptr, prop)) { - bool constraint_axis[3]; - - RNA_property_boolean_get_array(op->ptr, prop, constraint_axis); - - if (constraint_axis- [x] || constraint_axis- [x] || constraint_axis[2]) { - t->con.mode |= CON_APPLY; - - if (constraint_axis[0]) { - t->con.mode |= CON_AXIS0; - } - if (constraint_axis[1]) { - t->con.mode |= CON_AXIS1; - } - if (constraint_axis[2]) { - t->con.mode |= CON_AXIS2; - } - - setUserConstraint(t, t->orientation.user, t->con.mode, "%s"); - } - } - } - else { - /* So we can adjust in non global orientation. */ - if (t->orientation.user != V3D_ORIENT_GLOBAL) { - t->con.mode |= CON_APPLY | CON_AXIS0 | CON_AXIS1 | CON_AXIS2; - setUserConstraint(t, t->orientation.user, t->con.mode, "%s"); - } + if (t->con.mode & CON_APPLY) { + setUserConstraint(t, t->orient[t->orient_curr].type, t->con.mode, "%s"); } /* Don't write into the values when non-modal because they are already set from operator redo diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index 7a68266ce6c..6a88c9d4a5a 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -113,13 +113,8 @@ typedef struct TransSnap { } TransSnap; typedef struct TransCon { - short orientation; /** Description of the constraint for header_print. */ char text[50]; - /** Matrix of the constraint space. */ - float mtx- [x][3]; - /** Inverse matrix of the constraint space. */ - float imtx- [x][3]; /** Projection constraint matrix (same as #imtx with some axis == 0). */ float pmtx- [x][3]; /** Initial mouse value for visual calculation @@ -139,8 +134,7 @@ typedef struct TransCon { struct TransDataContainer *tc, struct TransData *td, const float in[3], - float out[3], - float pvec[3]); + float out[3]); /** Apply function pointer for size transformation. */ void (*applySize)(struct TransInfo *t, struct TransDataContainer *tc, @@ -520,6 +514,7 @@ typedef struct TransInfo { /** orientation matrix of the current space. */ float spacemtx- [x][3]; + float spacemtx_inv- [x][3]; /** name of the current space, MAX_NAME. */ char spacename[64]; @@ -531,18 +526,11 @@ typedef struct TransInfo { bool is_launch_event_tweak; struct { - /** Orientation type when when we're not constrained. - * nearly always global except for rotate which defaults to screen-space orientation. */ - short unset; - /** Orientation to use when a key is pressed. */ - short user; - /* Used when user is global. */ - short user_alt; - short index; - short *types[2]; - /* this gets used when custom_orientation is V3D_ORIENT_CUSTOM */ - struct TransformOrientation *custom; - } orientation; + short type; + float matrix- [x][3]; + } orient[3]; + short orient_curr; + /** backup from view3d, to restore on end. */ short gizmo_flag; @@ -566,15 +554,6 @@ typedef struct TransInfo { /** Secondary axis, shear uses this. */ int orient_axis_ortho; - /** Often this matrix has similar usage to #TransInfo.spacemtx however this - * is used to define extra axes to operate on, not necessarily a space. - * - * For example, by default rotation operates on the view (`orient_matrix[2]`), - * even when the current space isn't set to the view. */ - float orient_matrix- [x][3]; - /** Don't overwrite when set by operator redo defines the orientation axis. */ - bool orient_matrix_is_set; - /** remove elements if operator is canceled. */ bool remove_on_cancel; @@ -922,8 +901,13 @@ void getViewVector(const TransInfo *t, const float coord- [x], float vec[3]); void transform_data_ext_rotate(TransData *td, float mat- [x]- [x], bool use_drot); /*********************** Transform Orientations ******************************/ - -void initTransformOrientation(struct bContext *C, TransInfo *t); +short transform_orientation_matrix_get(struct bContext *C, + TransInfo *t, + const short orientation, + const float custom- [x][3], + float r_spacemtx- [x][3]); +const char *transform_orientations_spacename_get(TransInfo *t, const short orient_type); +void transform_orientations_current_set(struct TransInfo *t, const short orient_index); /* Those two fill in mat and return non-zero on success */ bool createSpaceNormal(float mat- [x]- [x], const float normal[3]); diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c index cdff9fdf750..ec4c678d4ae 100644 --- a/source/blender/editors/transform/transform_constraints.c +++ b/source/blender/editors/transform/transform_constraints.c @@ -57,7 +57,49 @@ static void drawObjectConstraint(TransInfo *t); +static void projection_matrix_calc(const TransInfo *t, float r_pmtx- [x][3]) +{ + unit_m3(r_pmtx); + + if (!(t->con.mode & CON_AXIS0)) { + zero_v3(r_pmtx[0]); + } + + if (!(t->con.mode & CON_AXIS1)) { + zero_v3(r_pmtx[1]); + } + + if (!(t->con.mode & CON_AXIS2)) { + zero_v3(r_pmtx[2]); + } + + float mat- [x][3]; + mul_m3_m3m3(mat, r_pmtx, t->spacemtx_inv); + mul_m3_m3m3(r_pmtx, t->spacemtx, mat); +} + /* ************************** CONSTRAINTS ************************* */ +#define CONSTRAIN_EPSILON 0.0001f + +static void constraint_plane_calc(TransInfo *t, float r_plane[4]) +{ + const float *constraint_vector[2]; + int n = 0; + for (int i = 0; i < 3; i++) { + if (t->con.mode & (CON_AXIS0 << i)) { + constraint_vector[n++] = t->spacemtx[i]; + if (n == 2) { + break; + } + } + } + BLI_assert(n == 2); + + cross_v3_v3v3(r_plane, constraint_vector- [x], constraint_vector[1]); + normalize_v3(r_plane); + r_plane- [x] = -dot_v3v3(r_plane, t->center_global); +} + static void constraintValuesFinal(TransInfo *t, float vec[3]) { int mode = t->con.mode; @@ -121,11 +163,9 @@ void constraintNumInput(TransInfo *t, float vec[3]) } } -static void postConstraintChecks(TransInfo *t, float vec- [x], float pvec[3]) +static void postConstraintChecks(TransInfo *t, float vec[3]) { - int i = 0; - - mul_m3_v3(t->con.imtx, vec); + mul_m3_v3(t->spacemtx_inv, vec); snapGridIncrement(t, vec); @@ -155,17 +195,7 @@ static void postConstraintChecks(TransInfo *t, float vec- [x], float pvec[3]) /* inverse transformation at the end */ } - if (t->con.mode & CON_AXIS0) { - pvec[i++] = vec[0]; - } - if (t->con.mode & CON_AXIS1) { - pvec[i++] = vec[1]; - } - if (t->con.mode & CON_AXIS2) { - pvec[i++] = vec[2]; - } - - mul_m3_v3(t->con.mtx, vec); + mul_m3_v3(t->spacemtx, vec); } static void viewAxisCorrectCenter(const TransInfo *t, float t_con_center[3]) @@ -291,29 +321,13 @@ static void axisProjection(const TransInfo *t, * Return true if the 2x axis are both aligned when projected into the view. * In this case, we can't usefully project the cursor onto the plane. */ -static bool isPlaneProjectionViewAligned(const TransInfo *t) +static bool isPlaneProjectionViewAligned(const TransInfo *t, const float plane[4]) { const float eps = 0.001f; - const float *constraint_vector[2]; - int n = 0; - for (int i = 0; i < 3; i++) { - if (t->con.mode & (CON_AXIS0 << i)) { - constraint_vector[n++] = t->con.mtx[i]; - if (n == 2) { - break; - } - } - } - BLI_assert(n == 2); - - float view_to_plane- [x], plane_normal[3]; - + float view_to_plane[3]; getViewVector(t, t->center_global, view_to_plane); - cross_v3_v3v3(plane_normal, constraint_vector- [x], constraint_vector[1]); - normalize_v3(plane_normal); - - float factor = dot_v3v3(plane_normal, view_to_plane); + float factor = dot_v3v3(plane, view_to_plane); return fabsf(factor) < eps; } @@ -346,23 +360,22 @@ static void planeProjection(const TransInfo *t, const float in- [x], float out[3]) * (in perspective mode, the view vector is relative to the position on screen) */ -static void applyAxisConstraintVec(TransInfo *t, - TransDataContainer *UNUSED(tc), - TransData *td, - const float in[3], - float out[3], - float pvec[3]) +static void applyAxisConstraintVec( + TransInfo *t, TransDataContainer *UNUSED(tc), TransData *td, const float in- [x], float out[3]) { copy_v3_v3(out, in); if (!td && t->con.mode & CON_APPLY) { mul_m3_v3(t->con.pmtx, out); - // With snap, a projection is alright, no need to correct for view alignment + /* With snap points, a projection is alright, no adjustments needed. */ if (!validSnap(t)) { const int dims = getConstraintSpaceDimension(t); if (dims == 2) { if (!is_zero_v3(out)) { - if (!isPlaneProjectionViewAligned(t)) { + float plane[4]; + constraint_plane_calc(t, plane); + /* View alignment correction. */ + if (!isPlaneProjectionViewAligned(t, plane)) { planeProjection(t, in, out); } } @@ -371,25 +384,27 @@ static void applyAxisConstraintVec(TransInfo *t, float c[3]; if (t->con.mode & CON_AXIS0) { - copy_v3_v3(c, t->con.mtx[0]); + copy_v3_v3(c, t->spacemtx[0]); } else if (t->con.mode & CON_AXIS1) { - copy_v3_v3(c, t->con.mtx[1]); + copy_v3_v3(c, t->spacemtx[1]); } else if (t->con.mode & CON_AXIS2) { - copy_v3_v3(c, t->con.mtx[2]); + copy_v3_v3(c, t->spacemtx[2]); } + + /* View alignment correction. */ axisProjection(t, c, in, out); } } - postConstraintChecks(t, out, pvec); + postConstraintChecks(t, out); } } /* * Generic callback for object based spatial constraints applied to linear motion * - * At first, the following is applied to the first data in the array + * At first, the following is applied without orientation * The IN vector in projected into the constrained space and then further * projected along the view vector. * (in perspective mode, the view vector is relative to the position on screen) @@ -397,57 +412,17 @@ static void applyAxisConstraintVec(TransInfo *t, * Further down, that vector is mapped to each data's space. */ -static void applyObjectConstraintVec(TransInfo *t, - TransDataContainer *tc, - TransData *td, - const float in[3], - float out[3], - float pvec[3]) +static void applyObjectConstraintVec( + TransInfo *t, TransDataContainer *tc, TransData *td, const float in- [x], float out[3]) { - copy_v3_v3(out, in); - if (t->con.mode & CON_APPLY) { - if (!td) { - mul_m3_v3(t->con.pmtx, out); - - const int dims = getConstraintSpaceDimension(t); - if (dims == 2) { - if (!is_zero_v3(out)) { - if (!isPlaneProjectionViewAligned(t)) { - planeProjection(t, in, out); - } - } - } - else if (dims == 1) { - float c[3]; - - if (t->con.mode & CON_AXIS0) { - copy_v3_v3(c, t->con.mtx[0]); - } - else if (t->con.mode & CON_AXIS1) { - copy_v3_v3(c, t->con.mtx[1]); - } - else if (t->con.mode & CON_AXIS2) { - copy_v3_v3(c, t->con.mtx[2]); - } - axisProjection(t, c, in, out); - } - postConstraintChecks(t, out, pvec); - copy_v3_v3(out, pvec); - } - else { - int i = 0; - - out- [x] = out- [x] = out- [x] = 0.0f; - if (t->con.mode & CON_AXIS0) { - out- [x] = in[i++]; - } - if (t->con.mode & CON_AXIS1) { - out- [x] = in[i++]; - } - if (t->con.mode & CON_AXIS2) { - out- [x] = in[i++]; - } - + if (!td) { + applyAxisConstraintVec(t, tc, td, in, out); + } + else { + /* Specific TransData's space. */ + copy_v3_v3(out, in); + if (t->con.mode & CON_APPLY) { + mul_m3_v3(t->spacemtx_inv, out); mul_m3_v3(td->axismtx, out); if (t->flag & T_EDIT) { mul_m3_v3(tc->mat3_unit, out); @@ -478,8 +453,8 @@ static void applyAxisConstraintSize(TransInfo *t, smat- [x]- [x] = 1.0f; } - mul_m3_m3m3(tmat, smat, t->con.imtx); - mul_m3_m3m3(smat, t->con.mtx, tmat); + mul_m3_m3m3(tmat, smat, t->spacemtx_inv); + mul_m3_m3m3(smat, t->spacemtx, tmat); } } @@ -539,15 +514,15 @@ static void applyAxisConstraintRot( switch (mode) { case CON_AXIS0: case (CON_AXIS1 | CON_AXIS2): - copy_v3_v3(vec, t->con.mtx[0]); + copy_v3_v3(vec, t->spacemtx[0]); break; case CON_AXIS1: case (CON_AXIS0 | CON_AXIS2): - copy_v3_v3(vec, t->con.mtx[1]); + copy_v3_v3(vec, t->spacemtx[1]); break; case CON_AXIS2: case (CON_AXIS0 | CON_AXIS1): - copy_v3_v3(vec, t->con.mtx[2]); + copy_v3_v3(vec, t->spacemtx[2]); break; } /* don't flip axis if asked to or if num input */ @@ -620,12 +595,11 @@ static void applyObjectConstraintRot( /*--------------------- INTERNAL SETUP CALLS ------------------*/ -void setConstraint(TransInfo *t, float space- [x]- [x], int mode, const char text[]) +void setConstraint(TransInfo *t, int mode, const char text[]) { BLI_strncpy(t->con.text + 1, text, sizeof(t->con.text) - 1); - copy_m3_m3(t->con.mtx, space); t->con.mode = mode; - getConstraintMatrix(t); + projection_matrix_calc(t, t->con.pmtx); startConstraint(t); @@ -639,41 +613,25 @@ void setConstraint(TransInfo *t, float space- [x]- [x], int mode, const char text[]) /* applies individual td->axismtx constraints */ void setAxisMatrixConstraint(TransInfo *t, int mode, const char text[]) { - TransDataContainer *tc = t->data_container; - if (t->data_len_all == 1) { - float axismtx- [x][3]; - if (t->flag & T_EDIT) { - mul_m3_m3m3(axismtx, tc->mat3_unit, tc->data->axismtx); - } - else { - copy_m3_m3(axismtx, tc->data->axismtx); - } - - setConstraint(t, axismtx, mode, text); - } - else { - BLI_strncpy(t->con.text + 1, text, sizeof(t->con.text) - 1); - copy_m3_m3(t->con.mtx, tc->data->axismtx); - t->con.mode = mode; - getConstraintMatrix(t); + BLI_strncpy(t->con.text + 1, text, sizeof(t->con.text) - 1); + t->con.mode = mode; + projection_matrix_calc(t, t->con.pmtx); - startConstraint(t); + startConstraint(t); - t->con.drawExtra = drawObjectConstraint; - t->con.applyVec = applyObjectConstraintVec; - t->con.applySize = applyObjectConstraintSize; - t->con.applyRot = applyObjectConstraintRot; - t->redraw = TREDRAW_HARD; - } + t->con.drawExtra = drawObjectConstraint; + t->con.applyVec = applyObjectConstraintVec; + t->con.applySize = applyObjectConstraintSize; + t->con.applyRot = applyObjectConstraintRot; + t->redraw = TREDRAW_HARD; } void setLocalConstraint(TransInfo *t, int mode, const char text[]) { - /* edit-mode now allows local transforms too */ if (t->flag & T_EDIT) { - /* Use the active (first) edit object. */ - TransDataContainer *tc = t->data_container; - setConstraint(t, tc->mat3_unit, mode, text); + /* Although in edit-mode each object has its local space, use the + * orientation of the active object. */ + setConstraint(t, mode, text); } else { setAxisMatrixConstraint(t, mode, text); @@ -689,59 +647,30 @@ void setLocalConstraint(TransInfo *t, int mode, const char text[]) void setUserConstraint(TransInfo *t, short orientation, int mode, const char ftext[]) { char text[256]; + const char *spacename = transform_orientations_spacename_get(t, orientation); + BLI_snprintf(text, sizeof(text), ftext, spacename); switch (orientation) { - case V3D_ORIENT_GLOBAL: { - float mtx- [x][3]; - BLI_snprintf(text, sizeof(text), ftext, TIP_("global")); - unit_m3(mtx); - setConstraint(t, mtx, mode, text); - break; - } case V3D_ORIENT_LOCAL: - BLI_snprintf(text, sizeof(text), ftext, TIP_("local")); setLocalConstraint(t, mode, text); break; case V3D_ORIENT_NORMAL: - BLI_snprintf(text, sizeof(text), ftext, TIP_("normal")); if (checkUseAxisMatrix(t)) { setAxisMatrixConstraint(t, mode, text); + break; } - else { - setConstraint(t, t->spacemtx, mode, text); - } - break; + ATTR_FALLTHROUGH; + case V3D_ORIENT_GLOBAL: case V3D_ORIENT_VIEW: - BLI_snprintf(text, sizeof(text), ftext, TIP_("view")); - setConstraint(t, t->spacemtx, mode, text); - break; case V3D_ORIENT_CURSOR: - BLI_snprintf(text, sizeof(text), ftext, TIP_("cursor")); - setConstraint(t, t->spacemtx, mode, text); - break; case V3D_ORIENT_GIMBAL: - BLI_snprintf(text, sizeof(text), ftext, TIP_("gimbal")); - setConstraint(t, t->spacemtx, mode, text); - break; case V3D_ORIENT_CUSTOM_MATRIX: - BLI_snprintf(text, sizeof(text), ftext, TIP_("custom matrix")); - setConstraint(t, t->spacemtx, mode, text); - break; - case V3D_ORIENT_CUSTOM: { - char orientation_str[128]; - BLI_snprintf(orientation_str, - sizeof(orientation_str), - "%s \"%s\"", - TIP_("custom orientation"), - t->orientation.custom->name); - BLI_snprintf(text, sizeof(text), ftext, orientation_str); - setConstraint(t, t->spacemtx, mode, text); + case V3D_ORIENT_CUSTOM: + default: { + setConstraint(t, mode, text); break; } } - - t->con.orientation = orientation; - t->con.mode |= CON_USER; } @@ -772,9 +701,9 @@ void drawConstraint(TransInfo *t) convertViewVec(t, vec, (t->mval- [x] - t->con.imval- [x]), (t->mval- [x] - t->con.imval[1])); add_v3_v3(vec, t->center_global); - drawLine(t, t->center_global, tc->mtx- [x], 'X', 0); - drawLine(t, t->center_global, tc->mtx- [x], 'Y', 0); - drawLine(t, t->center_global, tc->mtx- [x], 'Z', 0); + drawLine(t, t->center_global, t->spacemtx- [x], 'X', 0); + drawLine(t, t->center_global, t->spacemtx- [x], 'Y', 0); + drawLine(t, t->center_global, t->spacemtx- [x], 'Z', 0); depth_test_enabled = GPU_depth_test_enabled(); if (depth_test_enabled) { @@ -808,13 +737,13 @@ void drawConstraint(TransInfo *t) } if (tc->mode & CON_AXIS0) { - drawLine(t, t->center_global, tc->mtx- [x], 'X', DRAWLIGHT); + drawLine(t, t->center_global, t->spacemtx- [x], 'X', DRAWLIGHT); } if (tc->mode & CON_AXIS1) { - drawLine(t, t->center_global, tc->mtx- [x], 'Y', DRAWLIGHT); + drawLine(t, t->center_global, t->spacemtx- [x], 'Y', DRAWLIGHT); } if (tc->mode & CON_AXIS2) { - drawLine(t, t->center_global, tc->mtx- [x], 'Z', DRAWLIGHT); + drawLine(t, t->center_global, t->spacemtx- [x], 'Z', DRAWLIGHT); } } } @@ -911,11 +840,7 @@ static void drawObjectConstraint(TransInfo *t) } } - if (t->flag & T_OBJECT) { - copy_v3_v3(co, td->ob->obmat[3]); - axismtx = td->axismtx; - } - else if (t->flag & T_EDIT) { + if (t->flag & T_EDIT) { mul_v3_m4v3(co, tc->mat, td->center); mul_m3_m3m3(tmp_axismtx, tc->mat3_unit, td->axismtx); @@ -960,41 +885,18 @@ void stopConstraint(TransInfo *t) t->num.idx_max = t->idx_max; } -void getConstraintMatrix(TransInfo *t) -{ - float mat- [x][3]; - invert_m3_m3(t->con.imtx, t->con.mtx); - unit_m3(t->con.pmtx); - - if (!(t->con.mode & CON_AXIS0)) { - zero_v3(t->con.pmtx[0]); - } - - if (!(t->con.mode & CON_AXIS1)) { - zero_v3(t->con.pmtx[1]); - } - - if (!(t->con.mode & CON_AXIS2)) { - zero_v3(t->con.pmtx[2]); - } - - mul_m3_m3m3(mat, t->con.pmtx, t->con.imtx); - mul_m3_m3m3(t->con.pmtx, t->con.mtx, mat); -} - /*------------------------- MMB Select -------------------------------*/ -void initSelectConstraint(TransInfo *t, float mtx- [x][3]) +void initSelectConstraint(TransInfo *t) { - copy_m3_m3(t->con.mtx, mtx); - t->con.mode |= CON_APPLY; - t->con.mode |= CON_SELECT; + if (t->orient_curr == 0) { + t->orient_curr = 1; + transform_orientations_current_set(t, t->orient_curr); + } + short orientation = t->orient[t->orient_curr].type; + setUserConstraint(t, orientation, CON_APPLY | CON_SELECT, "%s"); setNearestAxis(t); - t->con.drawExtra = NULL; - t->con.applyVec = applyAxisConstraintVec; - t->con.applySize = applyAxisConstraintSize; - t->con.applyRot = applyAxisConstraintRot; } void selectConstraint(TransInfo *t) @@ -1060,7 +962,7 @@ static void setNearestAxis3d(TransInfo *t) for (i = 0; i < 3; i++) { float axis- [x], axis_2d[2]; - copy_v3_v3(axis, t->con.mtx[i]); + copy_v3_v3(axis, t->spacemtx[i]); mul_v3_fl(axis, zfac); /* now we can project to get window coordinate */ @@ -1129,7 +1031,7 @@ void setNearestAxis(TransInfo *t) setNearestAxis2d(t); } - getConstraintMatrix(t); + projection_matrix_calc(t, t->con.pmtx); } /*-------------- HELPER FUNCTIONS ----------------*/ diff --git a/source/blender/editors/transform/transform_constraints.h b/source/blender/editors/transform/transform_constraints.h index 8938ca93ad8..c41b9361ca4 100644 --- a/source/blender/editors/transform/transform_constraints.h +++ b/source/blender/editors/transform/transform_constraints.h @@ -27,7 +27,7 @@ struct TransInfo; void constraintNumInput(TransInfo *t, float vec[3]); -void setConstraint(TransInfo *t, float space- [x]- [x], int mode, const char text[]); +void setConstraint(TransInfo *t, int mode, const char text[]); void setAxisMatrixConstraint(TransInfo *t, int mode, const char text[]); void setLocalConstraint(TransInfo *t, int mode, const char text[]); void setUserConstraint(TransInfo *t, short orientation, int mode, const char text[]); @@ -35,8 +35,7 @@ void drawConstraint(TransInfo *t); void drawPropCircle(const struct bContext *C, TransInfo *t); void startConstraint(TransInfo *t); void stopConstraint(TransInfo *t); -void getConstraintMatrix(TransInfo *t); -void initSelectConstraint(TransInfo *t, float mtx- [x][3]); +void initSelectConstraint(TransInfo *t); void selectConstraint(TransInfo *t); void postSelectConstraint(TransInfo *t); void setNearestAxis(TransInfo *t); diff --git a/source/blender/editors/transform/transform_convert.h b/source/blender/editors/transform/transform_convert.h index d4139898419..b50d4c7365a 100644 --- a/source/blender/editors/transform/transform_convert.h +++ b/source/blender/editors/transform/transform_convert.h @@ -163,7 +163,7 @@ void createTransParticleVerts(bContext *C, TransInfo *t); /* transform_convert_sculpt.c */ void createTransSculpt(TransInfo *t); -/* transform_convert_sequence.c */ +/* transform_convert_sequencer.c */ void createTransSeqData(TransInfo *t); /* transform_convert_tracking.c */ diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index f42a15a0ec3..69655011e60 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -1432,11 +1432,6 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve unit_m3(t->mat); - unit_m3(t->orient_matrix); - negate_m3(t->orient_matrix); - /* Leave 't->orient_matrix_is_set' to false, - * so we overwrite it when we have a useful value. */ - /* Default to rotate on the Z axis. */ t->orient_axis = 2; t->orient_axis_ortho = 1; @@ -1514,22 +1509,6 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve t->around = V3D_AROUND_CURSOR; } - TransformOrientationSlot *orient_slot = &t->scene->orientation_slots[SCE_ORIENT_DEFAULT]; - t->orientation.unset = V3D_ORIENT_GLOBAL; - t->orientation.user = orient_slot->type; - t->orientation.custom = BKE_scene_transform_orientation_find(t->scene, - orient_slot->index_custom); - - t->orientation.index = 0; - ARRAY_SET_ITEMS(t->orientation.types, &t->orientation.user, NULL); - - /* Make second orientation local if both are global. */ - if (t->orientation.user == V3D_ORIENT_GLOBAL) { - t->orientation.user_alt = V3D_ORIENT_LOCAL; - t->orientation.types- [x] = &t->orientation.user_alt; - SWAP(short *, t->orientation.types- [x], t->orientation.types[1]); - } - /* exceptional case */ if (t->around == V3D_AROUND_LOCAL_ORIGINS) { if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL)) { @@ -1618,48 +1597,153 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve t->around = V3D_AROUND_CENTER_BOUNDS; } - if (op && (prop = RNA_struct_find_property(op->ptr, "orient_axis"))) { - t->orient_axis = RNA_property_enum_get(op->ptr, prop); - } - if (op && (prop = RNA_struct_find_property(op->ptr, "orient_axis_ortho"))) { - t->orient_axis_ortho = RNA_property_enum_get(op->ptr, prop); - } + BLI_assert(is_zero_v4(t->values_modal_offset)); + bool t_values_set_is_array = false; + if (op && (prop = RNA_struct_find_property(op->ptr, "value")) && + RNA_property_is_set(op->ptr, prop)) { + float values- [x] = {0}; /* in case value isn't length 4, avoid uninitialized memory */ + if (RNA_property_array_check(prop)) { + RNA_float_get_array(op->ptr, "value", values); + t_values_set_is_array = true; + } + else { + values- [x] = RNA_float_get(op->ptr, "value"); + } - if (op && - ((prop = RNA_struct_find_property(op->ptr, "orient_matrix")) && - RNA_property_is_set(op->ptr, prop)) && - ((t->flag & T_MODAL) || - /* When using redo, don't use the custom constraint matrix - * if the user selects a different orientation. */ - (RNA_enum_get(op->ptr, "orient_type") == RNA_enum_get(op->ptr, "orient_matrix_type")))) { - RNA_property_float_get_array(op->ptr, prop, &t->orient_matrix- [x][0]); - copy_m3_m3(t->spacemtx, t->orient_matrix); - /* Some transform modes use this to operate on an axis. */ - t->orient_matrix_is_set = true; - t->orientation.user = V3D_ORIENT_CUSTOM_MATRIX; - t->orientation.custom = 0; + copy_v4_v4(t->values, values); if (t->flag & T_MODAL) { - RNA_enum_set(op->ptr, "orient_matrix_type", RNA_enum_get(op->ptr, "orient_type")); + /* Run before init functions so 'values_modal_offset' can be applied on mouse input. */ + copy_v4_v4(t->values_modal_offset, values); + } + else { + copy_v4_v4(t->values, values); + t->flag |= T_INPUT_IS_VALUES_FINAL; + } + } + + if (op && (prop = RNA_struct_find_property(op->ptr, "constraint_axis"))) { + bool constraint_axis- [x] = {false, false, false}; + if (RNA_property_is_set(op->ptr, prop)) { + RNA_property_boolean_get_array(op->ptr, prop, constraint_axis); + } + + if (t_values_set_is_array && t->flag & T_INPUT_IS_VALUES_FINAL) { + /* For operators whose `t->values` is array, set constraint so that the + * orientation is more intuitive in the Redo Panel. */ + for (int i = 3; i--;) { + constraint_axis- [x] |= t->values- [x] != 0.0f; + } + } + + if (constraint_axis- [x] || constraint_axis- [x] || constraint_axis[2]) { + t->con.mode |= CON_APPLY; + + if (constraint_axis[0]) { + t->con.mode |= CON_AXIS0; + } + if (constraint_axis[1]) { + t->con.mode |= CON_AXIS1; + } + if (constraint_axis[2]) { + t->con.mode |= CON_AXIS2; + } } } - else if (op && ((prop = RNA_struct_find_property(op->ptr, "orient_type")) && - RNA_property_is_set(op->ptr, prop))) { - short orientation = RNA_property_enum_get(op->ptr, prop); - TransformOrientation *custom_orientation = NULL; - if (orientation >= V3D_ORIENT_CUSTOM) { - if (orientation >= V3D_ORIENT_CUSTOM + BIF_countTransformOrientation(C)) { - orientation = V3D_ORIENT_GLOBAL; + { + short orient_type_set = -1; + short orient_type_matrix_set = -1; + short orient_type_scene = V3D_ORIENT_GLOBAL; + + if ((t->spacetype == SPACE_VIEW3D) && (t->region->regiontype == RGN_TYPE_WINDOW)) { + TransformOrientationSlot *orient_slot = &t->scene->orientation_slots[SCE_ORIENT_DEFAULT]; + orient_type_scene = orient_slot->type; + if (orient_type_scene == V3D_ORIENT_CUSTOM) { + const int index_custom = orient_slot->index_custom; + orient_type_scene += index_custom; + } + } + + short orient_types[3]; + float custom_matrix- [x][3]; + bool use_orient_axis = false; + + if (op && (prop = RNA_struct_find_property(op->ptr, "orient_axis"))) { + t->orient_axis = RNA_property_enum_get(op->ptr, prop); + use_orient_axis = true; + } + if (op && (prop = RNA_struct_find_property(op->ptr, "orient_axis_ortho"))) { + t->orient_axis_ortho = RNA_property_enum_get(op->ptr, prop); + } + + if (op && ((prop = RNA_struct_find_property(op->ptr, "orient_type")) && + RNA_property_is_set(op->ptr, prop))) { + orient_type_set = RNA_property_enum_get(op->ptr, prop); + if (orient_type_set >= V3D_ORIENT_CUSTOM) { + if (orient_type_set >= V3D_ORIENT_CUSTOM + BIF_countTransformOrientation(C)) { + orient_type_set = V3D_ORIENT_GLOBAL; + } + } + + /* Change the default orientation to be used when redoing. */ + orient_types- [x] = orient_type_set; + orient_types- [x] = orient_type_set; + orient_types- [x] = orient_type_scene; + } + else { + if ((t->flag & T_MODAL) && (use_orient_axis || transform_mode_is_changeable(t->mode)) && + (t->mode != TFM_ALIGN)) { + orient_types- [x] = V3D_ORIENT_VIEW; } else { - custom_orientation = BKE_scene_transform_orientation_find(t->scene, - orientation - V3D_ORIENT_CUSTOM); - orientation = V3D_ORIENT_CUSTOM; + orient_types- [x] = orient_type_scene; + } + orient_types- [x] = orient_type_scene; + orient_types- [x] = orient_type_scene != V3D_ORIENT_GLOBAL ? V3D_ORIENT_GLOBAL : + V3D_ORIENT_LOCAL; + } + + if (op && ((prop = RNA_struct_find_property(op->ptr, "orient_matrix")) && + RNA_property_is_set(op->ptr, prop))) { + RNA_property_float_get_array(op->ptr, prop, &custom_matrix- [x][0]); + + if ((prop = RNA_struct_find_property(op->ptr, "orient_matrix_type")) && + RNA_property_is_set(op->ptr, prop)) { + orient_type_matrix_set = RNA_property_enum_get(op->ptr, prop); + } + else if (orient_type_set != -1) { + orient_type_matrix_set = orient_type_set; + } + else { + orient_type_matrix_set = orient_type_set = V3D_ORIENT_GLOBAL; + } + + if (orient_type_matrix_set == orient_type_set) { + /* Constraints are forced to use the custom matrix when redoing. */ + orient_types- [x] = V3D_ORIENT_CUSTOM_MATRIX; } } - t->orientation.user = orientation; - t->orientation.custom = custom_orientation; + if (t->con.mode & CON_APPLY) { + t->orient_curr = 1; + } + + /* For efficiency, avoid calculating the same orientation twice. */ + for (int i = 1; i < 3; i++) { + t->orient- [x].type = transform_orientation_matrix_get( + C, t, orient_types- [x], custom_matrix, t->orient- [x].matrix); + } + + if (orient_types- [x] != orient_types[1]) { + t->orient- [x].type = transform_orientation_matrix_get( + C, t, orient_types- [x], custom_matrix, t->orient- [x].matrix); + } + else { + memcpy(&t->orient- [x], &t->orient- [x], sizeof(t->orient[0])); + } + + const char *spacename = transform_orientations_spacename_get(t, orient_types[0]); + BLI_strncpy(t->spacename, spacename, sizeof(t->spacename)); } if (op && ((prop = RNA_struct_find_property(op->ptr, "release_confirm")) && @@ -1694,45 +1778,45 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve /* setting PET flag only if property exist in operator. Otherwise, assume it's not supported */ if (op && (prop = RNA_struct_find_property(op->ptr, "use_proportional_edit"))) { if (RNA_property_is_set(op->ptr, prop)) { - int proportional = 0; if (RNA_property_boolean_get(op->ptr, prop)) { - proportional |= PROP_EDIT_USE; + t->flag |= T_PROP_EDIT; if (RNA_boolean_get(op->ptr, "use_proportional_connected")) { - proportional |= PROP_EDIT_CONNECTED; + t->flag |= T_PROP_CONNECTED; } if (RNA_boolean_get(op->ptr, "use_proportional_projected")) { - proportional |= PROP_EDIT_PROJECTED; + t->flag |= T_PROP_PROJECTED; } } - t->flag |= initTransInfo_edit_pet_to_flag(proportional); } else { /* use settings from scene only if modal */ if (t->flag & T_MODAL) { if ((t->options & CTX_NO_PET) == 0) { + bool use_prop_edit = false; if (t->spacetype == SPACE_GRAPH) { - t->flag |= initTransInfo_edit_pet_to_flag(ts->proportional_fcurve); + use_prop_edit = ts->proportional_fcurve; } else if (t->spacetype == SPACE_ACTION) { - t->flag |= initTransInfo_edit_pet_to_flag(ts->proportional_action); + use_prop_edit = ts->proportional_action; } - else if (t->obedit_type != -1) { - t->flag |= initTransInfo_edit_pet_to_flag(ts->proportional_edit); + else if (t->options & CTX_MASK) { + use_prop_edit = ts->proportional_mask; } - else if (t->options & CTX_GPENCIL_STROKES) { - t->flag |= initTransInfo_edit_pet_to_flag(ts->proportional_edit); + else if (obact && obact->mode == OB_MODE_OBJECT) { + use_prop_edit = ts->proportional_objects; } - else if (t->options & CTX_MASK) { - if (ts->proportional_mask) { - t->flag |= T_PROP_EDIT; - - if (ts->proportional_edit & PROP_EDIT_CONNECTED) { - t->flag |= T_PROP_CONNECTED; - } - } + else { + use_prop_edit = (ts->proportional_edit & PROP_EDIT_USE) != 0; } - else if (!(t->options & CTX_CURSOR) && ts->proportional_objects) { + + if (use_prop_edit) { t->flag |= T_PROP_EDIT; + if (ts->proportional_edit & PROP_EDIT_CONNECTED) { + t->flag |= T_PROP_CONNECTED; + } + if (ts->proportional_edit & PROP_EDIT_PROJECTED) { + t->flag |= T_PROP_PROJECTED; + } } } } diff --git a/source/blender/editors/transform/transform_gizmo_3d.c b/source/blender/editors/transform/transform_gizmo_3d.c index cbb20847f36..ef860fba2a8 100644 --- a/source/blender/editors/transform/transform_gizmo_3d.c +++ b/source/blender/editors/transform/transform_gizmo_3d.c @@ -637,99 +637,6 @@ bool gimbal_axis(Object *ob, float gmat- [x][3]) return 0; } -void ED_transform_calc_orientation_from_type(const bContext *C, float r_mat- [x][3]) -{ - ARegion *region = CTX_wm_region(C); - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - Object *obedit = CTX_data_edit_object(C); - RegionView3D *rv3d = region->regiondata; - Object *ob = OBACT(view_layer); - const short orientation_type = scene->orientation_slots[SCE_ORIENT_DEFAULT].type; - const short orientation_index_custom = scene->orientation_slots[SCE_ORIENT_DEFAULT].index_custom; - const int pivot_point = scene->toolsettings->transform_pivot_point; - - ED_transform_calc_orientation_from_type_ex( - C, r_mat, scene, rv3d, ob, obedit, orientation_type, orientation_index_custom, pivot_point); -} - -void ED_transform_calc_orientation_from_type_ex(const bContext *C, - float r_mat- [x][3], - /* extra args (can be accessed from context) */ - Scene *scene, - RegionView3D *rv3d, - Object *ob, - Object *obedit, - const short orientation_type, - int orientation_index_custom, - const int pivot_point) -{ - bool ok = false; - - switch (orientation_type) { - case V3D_ORIENT_GLOBAL: { - break; /* nothing to do */ - } - case V3D_ORIENT_GIMBAL: { - if (gimbal_axis(ob, r_mat)) { - ok = true; - break; - } - /* if not gimbal, fall through to normal */ - ATTR_FALLTHROUGH; - } - case V3D_ORIENT_NORMAL: { - if (obedit || ob->mode & OB_MODE_POSE) { - ED_getTransformOrientationMatrix(C, r_mat, pivot_point); - ok = true; - break; - } - /* no break we define 'normal' as 'local' in Object mode */ - ATTR_FALLTHROUGH; - } - case V3D_ORIENT_LOCAL: { - if (ob->mode & OB_MODE_POSE) { - /* each bone moves on its own local axis, but to avoid confusion, - * use the active pones axis for display [#33575], this works as expected on a single bone - * and users who select many bones will understand what's going on and what local means - * when they start transforming */ - ED_getTransformOrientationMatrix(C, r_mat, pivot_point); - ok = true; - break; - } - copy_m3_m4(r_mat, ob->obmat); - normalize_m3(r_mat); - ok = true; - break; - } - case V3D_ORIENT_VIEW: { - if (rv3d != NULL) { - copy_m3_m4(r_mat, rv3d->viewinv); - normalize_m3(r_mat); - ok = true; - } - break; - } - case V3D_ORIENT_CURSOR: { - BKE_scene_cursor_rot_to_mat3(&scene->cursor, r_mat); - ok = true; - break; - } - case V3D_ORIENT_CUSTOM: { - TransformOrientation *custom_orientation = BKE_scene_transform_orientation_find( - scene, orientation_index_custom); - if (applyTransformOrientation(custom_orientation, r_mat, NULL)) { - ok = true; - } - break; - } - } - - if (!ok) { - unit_m3(r_mat); - } -} - /* centroid, boundbox, of selection */ /* returns total items selected */ int ED_transform_calc_gizmo_stats(const bContext *C, @@ -1390,21 +1297,21 @@ void drawDial3d(const TransInfo *t) if (tc->mode & CON_APPLY) { if (tc->mode & CON_AXIS0) { axis_idx = MAN_AXIS_ROT_X; - negate_v3_v3(mat_basis- [x], tc->mtx[0]); + negate_v3_v3(mat_basis- [x], t->spacemtx[0]); } else if (tc->mode & CON_AXIS1) { axis_idx = MAN_AXIS_ROT_Y; - negate_v3_v3(mat_basis- [x], tc->mtx[1]); + negate_v3_v3(mat_basis- [x], t->spacemtx[1]); } else { BLI_assert((tc->mode & CON_AXIS2) != 0); axis_idx = MAN_AXIS_ROT_Z; - negate_v3_v3(mat_basis- [x], tc->mtx[2]); + negate_v3_v3(mat_basis- [x], t->spacemtx[2]); } } else { axis_idx = MAN_AXIS_ROT_C; - negate_v3_v3(mat_basis- [x], t->orient_matrix[t->orient_axis]); + copy_v3_v3(mat_basis- [x], t->spacemtx[t->orient_axis]); scale *= 1.2f; line_with -= 1.0f; } diff --git a/source/blender/editors/transform/transform_mode.c b/source/blender/editors/transform/transform_mode.c index a2b3a891031..a951a38420f 100644 --- a/source/blender/editors/transform/transform_mode.c +++ b/source/blender/editors/transform/transform_mode.c @@ -61,6 +61,18 @@ bool transdata_check_local_center(TransInfo *t, short around) (t->options & (CTX_MOVIECLIP | CTX_MASK | CTX_PAINT_CURVE)))); } +/* Informs if the mode can be switched during modal. */ +bool transform_mode_is_changeable(const int mode) +{ + return ELEM(mode, + TFM_ROTATION, + TFM_RESIZE, + TFM_TRACKBALL, + TFM_TRANSLATION, + TFM_EDGE_SLIDE, + TFM_VERT_SLIDE); +} + /* -------------------------------------------------------------------- */ /** \name Transform Locks * \{ */ @@ -529,7 +541,7 @@ void headerRotation(TransInfo *t, char str[UI_MAX_DRAW_STR], float final) void postInputRotation(TransInfo *t, float values[3]) { float axis_final[3]; - copy_v3_v3(axis_final, t->orient_matrix[t->orient_axis]); + copy_v3_v3(axis_final, t->spacemtx[t->orient_axis]); if ((t->con.mode & CON_APPLY) && t->con.applyRot) { t->con.applyRot(t, NULL, NULL, axis_final, values); } @@ -870,7 +882,7 @@ void headerResize(TransInfo *t, const float vec- [x], char str[UI_MAX_DRAW_STR]) * * \note this is a tricky area, before making changes see: #29633, #42444 */ -static void TransMat3ToSize(float mat- [x]- [x], float smat- [x]- [x], float size[3]) +static void TransMat3ToSize(const float mat- [x]- [x], const float smat- [x]- [x], float size[3]) { float rmat- [x][3]; diff --git a/source/blender/editors/transform/transform_mode.h b/source/blender/editors/transform/transform_mode.h index 6180f6d3477..074e89390c2 100644 --- a/source/blender/editors/transform/transform_mode.h +++ b/source/blender/editors/transform/transform_mode.h @@ -41,6 +41,7 @@ typedef struct TransDataGenericSlideVert { /* transform_mode.c */ bool transdata_check_local_center(TransInfo *t, short around); +bool transform_mode_is_changeable(const int mode); void protectedTransBits(short protectflag, float vec[3]); void constraintTransLim(TransInfo *t, TransData *td); void postInputRotation(TransInfo *t, float values[3]); diff --git a/source/blender/editors/transform/transform_mode_bbone_resize.c b/source/blender/editors/transform/transform_mode_bbone_resize.c index c81049ac379..88a1c099755 100644 --- a/source/blender/editors/transform/transform_mode_bbone_resize.c +++ b/source/blender/editors/transform/transform_mode_bbone_resize.c @@ -87,7 +87,10 @@ static void headerBoneSize(TransInfo *t, const float vec- [x], char str[UI_MAX_DRA } } -static void ElementBoneSize(TransInfo *t, TransDataContainer *tc, TransData *td, float mat- [x][3]) +static void ElementBoneSize(TransInfo *t, + TransDataContainer *tc, + TransData *td, + const float mat- [x][3]) { float tmat- [x]- [x], smat- [x]- [x], oldy; float sizemat- [x][3]; @@ -132,6 +135,11 @@ static void applyBoneSize(TransInfo *t, const int UNUSED(mval[2])) if (t->con.applySize) { t->con.applySize(t, NULL, NULL, mat); + for (i = 0; i < 3; i++) { + if (!(t->con.mode & (CON_AXIS0 << i))) { + t->values_final- [x] = 1.0f; + } + } } copy_m3_m3(t->mat, mat); // used in gizmo diff --git a/source/blender/editors/transform/transform_mode_edge_rotate_normal.c b/source/blender/editors/transform/transform_mode_edge_rotate_normal.c index 18149a09f20..fde0d5b187e 100644 --- a/source/blender/editors/transform/transform_mode_edge_rotate_normal.c +++ b/source/blender/editors/transform/transform_mode_edge_rotate_normal.c @@ -81,7 +81,7 @@ static void applyNormalRotation(TransInfo *t, const int UNUSED(mval[2])) char str[UI_MAX_DRAW_STR]; float axis_final[3]; - copy_v3_v3(axis_final, t->orient_matrix[t->orient_axis]); + copy_v3_v3(axis_final, t->spacemtx[t->orient_axis]); if ((t->con.mode & CON_APPLY) && t->con.applyRot) { t->con.applyRot(t, NULL, NULL, axis_final, NULL); diff --git a/source/blender/editors/transform/transform_mode_edge_seq_slide.c b/source/blender/editors/transform/transform_mode_edge_seq_slide.c index ee91459dcdd..8690cd54a3b 100644 --- a/source/blender/editors/transform/transform_mode_edge_seq_slide.c +++ b/source/blender/editors/transform/transform_mode_edge_seq_slide.c @@ -101,9 +101,8 @@ static void applySeqSlide(TransInfo *t, const int mval[2]) snapSequenceBounds(t, mval); if (t->con.mode & CON_APPLY) { - float pvec- [x] = {0.0f, 0.0f, 0.0f}; float tvec[3]; - t->con.applyVec(t, NULL, NULL, t->values, tvec, pvec); + t->con.applyVec(t, NULL, NULL, t->values, tvec); copy_v3_v3(t->values_final, tvec); } else { diff --git a/source/blender/editors/transform/transform_mode_rotate.c b/source/blender/editors/transform/transform_mode_rotate.c index 6c2b3dc77d2..55c97630487 100644 --- a/source/blender/editors/transform/transform_mode_rotate.c +++ b/source/blender/editors/transform/transform_mode_rotate.c @@ -146,7 +146,8 @@ static void applyRotation(TransInfo *t, const int UNUSED(mval[2])) snapGridIncrement(t, &final); float axis_final[3]; - copy_v3_v3(axis_final, t->orient_matrix[t->orient_axis]); + /* Use the negative axis to match the default Z axis of the view matrix. */ + negate_v3_v3(axis_final, t->spacemtx[t->orient_axis]); if ((t->con.mode & CON_APPLY) && t->con.applyRot) { t->con.applyRot(t, NULL, NULL, axis_final, NULL); diff --git a/source/blender/editors/transform/transform_mode_shear.c b/source/blender/editors/transform/transform_mode_shear.c index ba79f5f3c7b..3eeb8a1e758 100644 --- a/source/blender/editors/transform/transform_mode_shear.c +++ b/source/blender/editors/transform/transform_mode_shear.c @@ -53,10 +53,10 @@ static void initShear_mouseInputMode(TransInfo *t) { float dir[3]; bool dir_flip = false; - copy_v3_v3(dir, t->orient_matrix[t->orient_axis_ortho]); + copy_v3_v3(dir, t->spacemtx[t->orient_axis_ortho]); /* Needed for axis aligned view gizmo. */ - if (t->orientation.user == V3D_ORIENT_VIEW) { + if (t->orient[t->orient_curr].type == V3D_ORIENT_VIEW) { if (t->orient_axis_ortho == 0) { if (t->center2d- [x] > t->mouse.imval[1]) { dir_flip = !dir_flip; @@ -154,8 +154,8 @@ static void applyShear(TransInfo *t, const int UNUSED(mval[2])) unit_m3(smat); smat- [x]- [x] = value; - copy_v3_v3(axismat_inv- [x], t->orient_matrix[t->orient_axis_ortho]); - copy_v3_v3(axismat_inv- [x], t->orient_matrix[t->orient_axis]); + copy_v3_v3(axismat_inv- [x], t->spacemtx[t->orient_axis_ortho]); + copy_v3_v3(axismat_inv- [x], t->spacemtx[t->orient_axis]); cross_v3_v3v3(axismat_inv- [x], axismat_inv- [x], axismat_inv[2]); invert_m3_m3(axismat, axismat_inv); diff --git a/source/blender/editors/transform/transform_mode_shrink_fatten.c b/source/blender/editors/transform/transform_mode_shrink_fatten.c index ed082e86b6d..ad6cdbbea69 100644 --- a/source/blender/editors/transform/transform_mode_shrink_fatten.c +++ b/source/blender/editors/transform/transform_mode_shrink_fatten.c @@ -54,13 +54,13 @@ static void applyShrinkFatten(TransInfo *t, const int UNUSED(mval[2])) char str[UI_MAX_DRAW_STR]; size_t ofs = 0; - distance = -t->values[0]; + distance = t->values[0]; snapGridIncrement(t, &distance); applyNumInput(&t->num, &distance); - t->values_final- [x] = -distance; + t->values_final- [x] = distance; /* header print for NumInput */ ofs += BLI_strncpy_rlen(str + ofs, TIP_("Shrink/Fatten:"), sizeof(str) - ofs); diff --git a/source/blender/editors/transform/transform_mode_translate.c b/source/blender/editors/transform/transform_mode_translate.c index 0a7d8bd90d3..696cd1d0a2d 100644 --- a/source/blender/editors/transform/transform_mode_translate.c +++ b/source/blender/editors/transform/transform_mode_translate.c @@ -34,6 +34,7 @@ #include "BKE_report.h" #include "BKE_unit.h" +#include "ED_node.h" #include "ED_screen.h" #include "WM_api.h" @@ -67,15 +68,27 @@ static void headerTranslation(TransInfo *t, const float vec- [x], char str[UI_MAX_ } else { float dvec[3]; - - copy_v3_v3(dvec, vec); - applyAspectRatio(t, dvec); + if (!(t->flag & T_2D_EDIT) && t->con.mode & CON_APPLY) { + int i = 0; + zero_v3(dvec); + if (t->con.mode & CON_AXIS0) { + dvec[i++] = vec[0]; + } + if (t->con.mode & CON_AXIS1) { + dvec[i++] = vec[1]; + } + if (t->con.mode & CON_AXIS2) { + dvec[i++] = vec[2]; + } + } + else { + copy_v3_v3(dvec, vec); + applyAspectRatio(t, dvec); + } dist = len_v3(vec); if (!(t->flag & T_2D_EDIT) && t->scene->unit.system) { - int i; - - for (i = 0; i < 3; i++) { + for (int i = 0; i < 3; i++) { bUnit_AsString2(&tvec[NUM_STR_REP_LEN * i], NUM_STR_REP_LEN, dvec- [x] * t->scene->unit.scale_length, @@ -277,8 +290,7 @@ static void applyTranslationValue(TransInfo *t, const float vec[3]) } if (t->con.applyVec) { - float pvec[3]; - t->con.applyVec(t, tc, td, vec, tvec, pvec); + t->con.applyVec(t, tc, td, vec, tvec); } else { copy_v3_v3(tvec, vec); @@ -319,57 +331,53 @@ static void applyTranslationValue(TransInfo *t, const float vec[3]) static void applyTranslation(TransInfo *t, const int UNUSED(mval[2])) { char str[UI_MAX_DRAW_STR]; - float values_final[3]; + float global_dir[3]; if (t->flag & T_INPUT_IS_VALUES_FINAL) { - copy_v3_v3(t->values_final, t->values); + mul_v3_m3v3(global_dir, t->spacemtx, t->values); } else { - copy_v3_v3(t->values_final, t->values); + copy_v3_v3(global_dir, t->values); if ((t->con.mode & CON_APPLY) == 0) { - snapGridIncrement(t, t->values_final); + snapGridIncrement(t, global_dir); } - if (applyNumInput(&t->num, t->values_final)) { - removeAspectRatio(t, t->values_final); + if (applyNumInput(&t->num, global_dir)) { + removeAspectRatio(t, global_dir); } - applySnapping(t, t->values_final); + applySnapping(t, global_dir); } - copy_v3_v3(values_final, t->values_final); if (t->con.mode & CON_APPLY) { - float pvec- [x] = {0.0f, 0.0f, 0.0f}; - t->con.applyVec(t, NULL, NULL, t->values_final, values_final, pvec); - headerTranslation(t, pvec, str); - - /* only so we have re-usable value with redo, see blender/blender-addons#46741. */ - mul_v3_m3v3(t->values_final, t->con.imtx, values_final); + float in[3]; + copy_v3_v3(in, global_dir); + t->con.applyVec(t, NULL, NULL, in, global_dir); + headerTranslation(t, global_dir, str); } else { - headerTranslation(t, t->values_final, str); - copy_v3_v3(values_final, t->values_final); + headerTranslation(t, global_dir, str); } - /* don't use 't->values' now on */ - - applyTranslationValue(t, values_final); + applyTranslationValue(t, global_dir); /* evil hack - redo translation if clipping needed */ - if (t->flag & T_CLIP_UV && clipUVTransform(t, values_final, 0)) { - applyTranslationValue(t, values_final); + if (t->flag & T_CLIP_UV && clipUVTransform(t, global_dir, 0)) { + applyTranslationValue(t, global_dir); /* In proportional edit it can happen that */ /* vertices in the radius of the brush end */ /* outside the clipping area */ /* XXX HACK - dg */ - if (t->flag & T_PROP_EDIT_ALL) { + if (t->flag & T_PROP_EDIT) { clipUVData(t); } } - recalcData(t); + /* Set the redo value. */ + mul_v3_m3v3(t->values_final, t->spacemtx_inv, global_dir); + recalcData(t); ED_area_status_text(t->area, str); } diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c index 36f42992573..2f8b2dc9a5e 100644 --- a/source/blender/editors/transform/transform_ops.c +++ b/source/blender/editors/transform/transform_ops.c @@ -20,7 +20,6 @@ #include "MEM_guardedalloc.h" -#include "DNA_mesh_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" @@ -32,7 +31,6 @@ #include "BKE_context.h" #include "BKE_editmesh.h" #include "BKE_global.h" -#include "BKE_layer.h" #include "BKE_report.h" #include "BKE_scene.h" @@ -1042,11 +1040,11 @@ static void TRANSFORM_OT_bbone_resize(struct wmOperatorType *ot) ot->exec = transform_exec; ot->modal = transform_modal; ot->cancel = transform_cancel; - ot->poll = ED_operator_editarmature; + ot->poll = ED_operator_object_active; ot->poll_property = transform_poll_property; RNA_def_float_translation( - ot->srna, "value", 2, VecOne, -FLT_MAX, FLT_MAX, "Display Size", "", -FLT_MAX, FLT_MAX); + ot->srna, "value", 3, VecOne, -FLT_MAX, FLT_MAX, "Display Size", "", -FLT_MAX, FLT_MAX); WM_operatortype_props_advanced_begin(ot); diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c index 76823adfd20..7ebe419adb7 100644 --- a/source/blender/editors/transform/transform_orientations.c +++ b/source/blender/editors/transform/transform_orientations.c @@ -32,7 +32,6 @@ #include "DNA_screen_types.h" #include "DNA_space_types.h" #include "DNA_view3d_types.h" -#include "DNA_workspace_types.h" #include "BLI_listbase.h" #include "BLI_math.h" @@ -47,7 +46,6 @@ #include "BKE_layer.h" #include "BKE_report.h" #include "BKE_scene.h" -#include "BKE_workspace.h" #include "BLT_translation.h" @@ -433,94 +431,179 @@ static int count_bone_select(bArmature *arm, ListBase *lb, const bool do_it) return total; } -void initTransformOrientation(bContext *C, TransInfo *t) +void ED_transform_calc_orientation_from_type(const bContext *C, float r_mat- [x][3]) { - Object *ob = CTX_data_active_object(C); - Object *obedit = CTX_data_active_object(C); + ARegion *region = CTX_wm_region(C); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + Object *obedit = CTX_data_edit_object(C); + RegionView3D *rv3d = region->regiondata; + Object *ob = OBACT(view_layer); + const short orientation_type = scene->orientation_slots[SCE_ORIENT_DEFAULT].type; + const short orientation_index_custom = scene->orientation_slots[SCE_ORIENT_DEFAULT].index_custom; + const int pivot_point = scene->toolsettings->transform_pivot_point; - switch (t->orientation.user) { - case V3D_ORIENT_GLOBAL: - unit_m3(t->spacemtx); - BLI_strncpy(t->spacename, TIP_("global"), sizeof(t->spacename)); - break; + ED_transform_calc_orientation_from_type_ex( + C, r_mat, scene, rv3d, ob, obedit, orientation_type, orientation_index_custom, pivot_point); +} - case V3D_ORIENT_GIMBAL: - unit_m3(t->spacemtx); - if (ob && gimbal_axis(ob, t->spacemtx)) { - BLI_strncpy(t->spacename, TIP_("gimbal"), sizeof(t->spacename)); - break; +short ED_transform_calc_orientation_from_type_ex(const bContext *C, + float r_mat- [x][3], + /* extra args (can be accessed from context) */ + Scene *scene, + RegionView3D *rv3d, + Object *ob, + Object *obedit, + const short orientation_type, + int orientation_index_custom, + const int pivot_point) +{ + switch (orientation_type) { + case V3D_ORIENT_GLOBAL: { + unit_m3(r_mat); + return V3D_ORIENT_GLOBAL; + } + case V3D_ORIENT_GIMBAL: { + if (ob && gimbal_axis(ob, r_mat)) { + return V3D_ORIENT_GIMBAL; } - ATTR_FALLTHROUGH; /* no gimbal fallthrough to normal */ - case V3D_ORIENT_NORMAL: + /* if not gimbal, fall through to normal */ + ATTR_FALLTHROUGH; + } + case V3D_ORIENT_NORMAL: { if (obedit || (ob && ob->mode & OB_MODE_POSE)) { - BLI_strncpy(t->spacename, TIP_("normal"), sizeof(t->spacename)); - ED_getTransformOrientationMatrix(C, t->spacemtx, t->around); - break; + ED_getTransformOrientationMatrix(C, r_mat, pivot_point); + return V3D_ORIENT_NORMAL; } - ATTR_FALLTHROUGH; /* we define 'normal' as 'local' in Object mode */ - case V3D_ORIENT_LOCAL: - BLI_strncpy(t->spacename, TIP_("local"), sizeof(t->spacename)); - + /* no break we define 'normal' as 'local' in Object mode */ + ATTR_FALLTHROUGH; + } + case V3D_ORIENT_LOCAL: { if (ob) { - copy_m3_m4(t->spacemtx, ob->obmat); - normalize_m3(t->spacemtx); - } - else { - unit_m3(t->spacemtx); + if (ob->mode & OB_MODE_POSE) { + /* each bone moves on its own local axis, but to avoid confusion, + * use the active pones axis for display [#33575], this works as expected on a single + * bone and users who select many bones will understand what's going on and what local + * means when they start transforming */ + ED_getTransformOrientationMatrix(C, r_mat, pivot_point); + } + else { + copy_m3_m4(r_mat, ob->obmat); + normalize_m3(r_mat); + } + return V3D_ORIENT_LOCAL; } - - break; - - case V3D_ORIENT_VIEW: - if ((t->spacetype == SPACE_VIEW3D) && (t->region->regiontype == RGN_TYPE_WINDOW)) { - RegionView3D *rv3d = t->region->regiondata; - float mat- [x][3]; - - BLI_strncpy(t->spacename, TIP_("view"), sizeof(t->spacename)); - copy_m3_m4(mat, rv3d->viewinv); - normalize_m3(mat); - copy_m3_m3(t->spacemtx, mat); + unit_m3(r_mat); + return V3D_ORIENT_GLOBAL; + } + case V3D_ORIENT_VIEW: { + if (rv3d != NULL) { + copy_m3_m4(r_mat, rv3d->viewinv); + normalize_m3(r_mat); } else { - unit_m3(t->spacemtx); + unit_m3(r_mat); } - break; + return V3D_ORIENT_VIEW; + } case V3D_ORIENT_CURSOR: { - BLI_strncpy(t->spacename, TIP_("cursor"), sizeof(t->spacename)); - BKE_scene_cursor_rot_to_mat3(&t->scene->cursor, t->spacemtx); - break; + BKE_scene_cursor_rot_to_mat3(&scene->cursor, r_mat); + return V3D_ORIENT_CURSOR; } - case V3D_ORIENT_CUSTOM_MATRIX: - /* Already set. */ - BLI_strncpy(t->spacename, TIP_("custom"), sizeof(t->spacename)); + case V3D_ORIENT_CUSTOM_MATRIX: { + /* Do nothing. */; break; + } case V3D_ORIENT_CUSTOM: - BLI_strncpy(t->spacename, t->orientation.custom->name, sizeof(t->spacename)); - - if (applyTransformOrientation(t->orientation.custom, t->spacemtx, t->spacename)) { - /* pass */ - } - else { - unit_m3(t->spacemtx); - } + default: { + BLI_assert(orientation_type >= V3D_ORIENT_CUSTOM); + TransformOrientation *custom_orientation = BKE_scene_transform_orientation_find( + scene, orientation_index_custom); + applyTransformOrientation(custom_orientation, r_mat, NULL); break; + } } - if (t->orient_matrix_is_set == false) { - t->orient_matrix_is_set = true; - if (t->flag & T_MODAL) { - /* Rotate for example defaults to operating on the view plane. */ - t->orientation.unset = V3D_ORIENT_VIEW; - copy_m3_m4(t->orient_matrix, t->viewinv); - normalize_m3(t->orient_matrix); - negate_m3(t->orient_matrix); - } - else { - copy_m3_m3(t->orient_matrix, t->spacemtx); + return orientation_type; +} + +/* Sets the matrix of the specified space orientation. + * If the matrix cannot be obtained, an orientation different from the one + * informed is returned */ +short transform_orientation_matrix_get(bContext *C, + TransInfo *t, + const short orientation, + const float custom- [x][3], + float r_spacemtx- [x][3]) +{ + if (orientation == V3D_ORIENT_CUSTOM_MATRIX) { + copy_m3_m3(r_spacemtx, custom); + return V3D_ORIENT_CUSTOM_MATRIX; + } + + if ((t->spacetype == SPACE_VIEW3D) && (t->region->regiontype == RGN_TYPE_WINDOW)) { + Object *ob = CTX_data_active_object(C); + Object *obedit = CTX_data_active_object(C); + RegionView3D *rv3d = t->region->regiondata; + int orientation_index_custom = 0; + + if (orientation >= V3D_ORIENT_CUSTOM) { + orientation_index_custom = orientation - V3D_ORIENT_CUSTOM; } + + return ED_transform_calc_orientation_from_type_ex( + C, + r_spacemtx, + /* extra args (can be accessed from context) */ + t->scene, + rv3d, + ob, + obedit, + orientation, + orientation_index_custom, + t->around); + } + + unit_m3(r_spacemtx); + return V3D_ORIENT_GLOBAL; +} + +const char *transform_orientations_spacename_get(TransInfo *t, const short orient_type) +{ + switch (orient_type) { + case V3D_ORIENT_GLOBAL: + return TIP_("global"); + case V3D_ORIENT_GIMBAL: + return TIP_("gimbal"); + case V3D_ORIENT_NORMAL: + return TIP_("normal"); + case V3D_ORIENT_LOCAL: + return TIP_("local"); + case V3D_ORIENT_VIEW: + return TIP_("view"); + case V3D_ORIENT_CURSOR: + return TIP_("cursor"); + case V3D_ORIENT_CUSTOM_MATRIX: + return TIP_("custom"); + case V3D_ORIENT_CUSTOM: + default: + BLI_assert(orient_type >= V3D_ORIENT_CUSTOM); + TransformOrientation *ts = BKE_scene_transform_orientation_find( + t->scene, orient_type - V3D_ORIENT_CUSTOM); + return ts->name; } } +void transform_orientations_current_set(TransInfo *t, const short orient_index) +{ + const short orientation = t->orient[orient_index].type; + const char *spacename = transform_orientations_spacename_get(t, orientation); + + BLI_strncpy(t->spacename, spacename, sizeof(t->spacename)); + copy_m3_m3(t->spacemtx, t->orient[orient_index].matrix); + invert_m3_m3(t->spacemtx_inv, t->spacemtx); +} + /** * utility function - get first n, selected vert/edge/faces */ diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index 154af6c8ae2..3eb6c6763fd 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -1366,13 +1366,12 @@ short snapObjectsTransform( return ED_transform_snap_object_project_view3d_ex( t->tsnap.object_context, t->depsgraph, - t->scene->toolsettings->snap_mode, + t->settings->snap_mode, &(const struct SnapObjectParams){ .snap_select = t->tsnap.modeSelect, .use_object_edit_cage = (t->flag & T_EDIT) != 0, - .use_occlusion_test = t->scene->toolsettings->snap_mode != SCE_SNAP_MODE_FACE, - .use_backface_culling = (t->scene->toolsettings->snap_flag & - SCE_SNAP_BACKFACE_CULLING) != 0, + .use_occlusion_test = t->settings->snap_mode != SCE_SNAP_MODE_FACE, + .use_backface_culling = (t->settings->snap_flag & SCE_SNAP_BACKFACE_CULLING) != 0, }, mval, target, @@ -1749,8 +1748,8 @@ static void applyGridIncrement( float local_axis[3]; float pos_on_axis[3]; - copy_v3_v3(local_axis, t->con.mtx[i]); - copy_v3_v3(pos_on_axis, t->con.mtx[i]); + copy_v3_v3(local_axis, t->spacemtx[i]); + copy_v3_v3(pos_on_axis, t->spacemtx[i]); /* amount of movement on axis from initial pos */ mul_v3_fl(pos_on_axis, val[i]); ```
Sign in to join this conversation.
No Label
Interest
Alembic
Interest
Animation & Rigging
Interest
Asset Browser
Interest
Asset Browser Project Overview
Interest
Audio
Interest
Automated Testing
Interest
Blender Asset Bundle
Interest
BlendFile
Interest
Collada
Interest
Compatibility
Interest
Compositing
Interest
Core
Interest
Cycles
Interest
Dependency Graph
Interest
Development Management
Interest
EEVEE
Interest
EEVEE & Viewport
Interest
Freestyle
Interest
Geometry Nodes
Interest
Grease Pencil
Interest
ID Management
Interest
Images & Movies
Interest
Import Export
Interest
Line Art
Interest
Masking
Interest
Metal
Interest
Modeling
Interest
Modifiers
Interest
Motion Tracking
Interest
Nodes & Physics
Interest
OpenGL
Interest
Overlay
Interest
Overrides
Interest
Performance
Interest
Physics
Interest
Pipeline, Assets & IO
Interest
Platforms, Builds & Tests
Interest
Python API
Interest
Render & Cycles
Interest
Render Pipeline
Interest
Sculpt, Paint & Texture
Interest
Text Editor
Interest
Translations
Interest
Triaging
Interest
Undo
Interest
USD
Interest
User Interface
Interest
UV Editing
Interest
VFX & Video
Interest
Video Sequencer
Interest
Virtual Reality
Interest
Vulkan
Interest
Wayland
Interest
Workbench
Interest: X11
Legacy
Blender 2.8 Project
Legacy
Milestone 1: Basic, Local Asset Browser
Legacy
OpenGL Error
Meta
Good First Issue
Meta
Papercut
Meta
Retrospective
Meta
Security
Module
Animation & Rigging
Module
Core
Module
Development Management
Module
EEVEE & Viewport
Module
Grease Pencil
Module
Modeling
Module
Nodes & Physics
Module
Pipeline, Assets & IO
Module
Platforms, Builds & Tests
Module
Python API
Module
Render & Cycles
Module
Sculpt, Paint & Texture
Module
Triaging
Module
User Interface
Module
VFX & Video
Platform
FreeBSD
Platform
Linux
Platform
macOS
Platform
Windows
Priority
High
Priority
Low
Priority
Normal
Priority
Unbreak Now!
Status
Archived
Status
Confirmed
Status
Duplicate
Status
Needs Info from Developers
Status
Needs Information from User
Status
Needs Triage
Status
Resolved
Type
Bug
Type
Design
Type
Known Issue
Type
Patch
Type
Report
Type
To Do
No Milestone
No project
No Assignees
5 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: blender/blender#78424
No description provided.