Merge branch 'master' into blender2.8
[blender.git] / source / blender / editors / transform / transform_generics.c
index 477e1ab..053647c 100644 (file)
 #include "BLI_rand.h"
 #include "BLI_utildefines.h"
 
+#include "PIL_time.h"
+
 #include "BLT_translation.h"
 
 #include "RNA_access.h"
 
-#include "BIF_gl.h"
-#include "BIF_glutil.h"
+#include "GPU_immediate.h"
+#include "GPU_matrix.h"
 
 #include "BIK_api.h"
 
@@ -71,7 +73,6 @@
 #include "BKE_action.h"
 #include "BKE_armature.h"
 #include "BKE_curve.h"
-#include "BKE_depsgraph.h"
 #include "BKE_fcurve.h"
 #include "BKE_lattice.h"
 #include "BKE_library.h"
 #include "BKE_editmesh.h"
 #include "BKE_tracking.h"
 #include "BKE_mask.h"
+#include "BKE_workspace.h"
+#include "BKE_layer.h"
+#include "BKE_scene.h"
+
+#include "DEG_depsgraph.h"
 
 #include "ED_anim_api.h"
 #include "ED_armature.h"
 #include "WM_types.h"
 #include "WM_api.h"
 
+#include "RE_engine.h"
+
 #include "UI_resources.h"
 #include "UI_view2d.h"
 
@@ -124,98 +132,101 @@ void getViewVector(const TransInfo *t, const float coord[3], float vec[3])
 /* ************************** GENERICS **************************** */
 
 
-static void clipMirrorModifier(TransInfo *t, Object *ob)
+static void clipMirrorModifier(TransInfo *t)
 {
-       ModifierData *md = ob->modifiers.first;
-       float tolerance[3] = {0.0f, 0.0f, 0.0f};
-       int axis = 0;
-
-       for (; md; md = md->next) {
-               if ((md->type == eModifierType_Mirror) && (md->mode & eModifierMode_Realtime)) {
-                       MirrorModifierData *mmd = (MirrorModifierData *) md;
-
-                       if (mmd->flag & MOD_MIR_CLIPPING) {
-                               axis = 0;
-                               if (mmd->flag & MOD_MIR_AXIS_X) {
-                                       axis |= 1;
-                                       tolerance[0] = mmd->tolerance;
-                               }
-                               if (mmd->flag & MOD_MIR_AXIS_Y) {
-                                       axis |= 2;
-                                       tolerance[1] = mmd->tolerance;
-                               }
-                               if (mmd->flag & MOD_MIR_AXIS_Z) {
-                                       axis |= 4;
-                                       tolerance[2] = mmd->tolerance;
-                               }
-                               if (axis) {
-                                       float mtx[4][4], imtx[4][4];
-                                       int i;
-                                       TransData *td = t->data;
+       FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+               Object *ob = tc->obedit;
+               ModifierData *md = ob->modifiers.first;
+               float tolerance[3] = {0.0f, 0.0f, 0.0f};
+               int axis = 0;
+
+               for (; md; md = md->next) {
+                       if ((md->type == eModifierType_Mirror) && (md->mode & eModifierMode_Realtime)) {
+                               MirrorModifierData *mmd = (MirrorModifierData *) md;
+
+                               if (mmd->flag & MOD_MIR_CLIPPING) {
+                                       axis = 0;
+                                       if (mmd->flag & MOD_MIR_AXIS_X) {
+                                               axis |= 1;
+                                               tolerance[0] = mmd->tolerance;
+                                       }
+                                       if (mmd->flag & MOD_MIR_AXIS_Y) {
+                                               axis |= 2;
+                                               tolerance[1] = mmd->tolerance;
+                                       }
+                                       if (mmd->flag & MOD_MIR_AXIS_Z) {
+                                               axis |= 4;
+                                               tolerance[2] = mmd->tolerance;
+                                       }
+                                       if (axis) {
+                                               float mtx[4][4], imtx[4][4];
+                                               int i;
 
-                                       if (mmd->mirror_ob) {
-                                               float obinv[4][4];
+                                               if (mmd->mirror_ob) {
+                                                       float obinv[4][4];
 
-                                               invert_m4_m4(obinv, mmd->mirror_ob->obmat);
-                                               mul_m4_m4m4(mtx, obinv, ob->obmat);
-                                               invert_m4_m4(imtx, mtx);
-                                       }
+                                                       invert_m4_m4(obinv, mmd->mirror_ob->obmat);
+                                                       mul_m4_m4m4(mtx, obinv, ob->obmat);
+                                                       invert_m4_m4(imtx, mtx);
+                                               }
 
-                                       for (i = 0; i < t->total; i++, td++) {
-                                               int clip;
-                                               float loc[3], iloc[3];
+                                               TransData *td = tc->data;
+                                               for (i = 0; i < tc->data_len; i++, td++) {
+                                                       int clip;
+                                                       float loc[3], iloc[3];
 
-                                               if (td->flag & TD_NOACTION)
-                                                       break;
-                                               if (td->loc == NULL)
-                                                       break;
+                                                       if (td->flag & TD_NOACTION)
+                                                               break;
+                                                       if (td->loc == NULL)
+                                                               break;
 
-                                               if (td->flag & TD_SKIP)
-                                                       continue;
+                                                       if (td->flag & TD_SKIP)
+                                                               continue;
 
-                                               copy_v3_v3(loc,  td->loc);
-                                               copy_v3_v3(iloc, td->iloc);
+                                                       copy_v3_v3(loc,  td->loc);
+                                                       copy_v3_v3(iloc, td->iloc);
 
-                                               if (mmd->mirror_ob) {
-                                                       mul_m4_v3(mtx, loc);
-                                                       mul_m4_v3(mtx, iloc);
-                                               }
+                                                       if (mmd->mirror_ob) {
+                                                               mul_m4_v3(mtx, loc);
+                                                               mul_m4_v3(mtx, iloc);
+                                                       }
 
-                                               clip = 0;
-                                               if (axis & 1) {
-                                                       if (fabsf(iloc[0]) <= tolerance[0] ||
-                                                           loc[0] * iloc[0] < 0.0f)
-                                                       {
-                                                               loc[0] = 0.0f;
-                                                               clip = 1;
+                                                       clip = 0;
+                                                       if (axis & 1) {
+                                                               if (fabsf(iloc[0]) <= tolerance[0] ||
+                                                                   loc[0] * iloc[0] < 0.0f)
+                                                               {
+                                                                       loc[0] = 0.0f;
+                                                                       clip = 1;
+                                                               }
                                                        }
-                                               }
 
-                                               if (axis & 2) {
-                                                       if (fabsf(iloc[1]) <= tolerance[1] ||
-                                                           loc[1] * iloc[1] < 0.0f)
-                                                       {
-                                                               loc[1] = 0.0f;
-                                                               clip = 1;
+                                                       if (axis & 2) {
+                                                               if (fabsf(iloc[1]) <= tolerance[1] ||
+                                                                   loc[1] * iloc[1] < 0.0f)
+                                                               {
+                                                                       loc[1] = 0.0f;
+                                                                       clip = 1;
+                                                               }
                                                        }
-                                               }
-                                               if (axis & 4) {
-                                                       if (fabsf(iloc[2]) <= tolerance[2] ||
-                                                           loc[2] * iloc[2] < 0.0f)
-                                                       {
-                                                               loc[2] = 0.0f;
-                                                               clip = 1;
+                                                       if (axis & 4) {
+                                                               if (fabsf(iloc[2]) <= tolerance[2] ||
+                                                                   loc[2] * iloc[2] < 0.0f)
+                                                               {
+                                                                       loc[2] = 0.0f;
+                                                                       clip = 1;
+                                                               }
                                                        }
-                                               }
-                                               if (clip) {
-                                                       if (mmd->mirror_ob) {
-                                                               mul_m4_v3(imtx, loc);
+                                                       if (clip) {
+                                                               if (mmd->mirror_ob) {
+                                                                       mul_m4_v3(imtx, loc);
+                                                               }
+                                                               copy_v3_v3(td->loc, loc);
                                                        }
-                                                       copy_v3_v3(td->loc, loc);
                                                }
                                        }
-                               }
 
+                               }
                        }
                }
        }
@@ -224,27 +235,29 @@ static void clipMirrorModifier(TransInfo *t, Object *ob)
 /* assumes obedit set to mesh object */
 static void editbmesh_apply_to_mirror(TransInfo *t)
 {
-       TransData *td = t->data;
-       BMVert *eve;
-       int i;
+       FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+               TransData *td = tc->data;
+               BMVert *eve;
+               int i;
 
-       for (i = 0; i < t->total; i++, td++) {
-               if (td->flag & TD_NOACTION)
-                       break;
-               if (td->loc == NULL)
-                       break;
-               if (td->flag & TD_SKIP)
-                       continue;
+               for (i = 0; i < tc->data_len; i++, td++) {
+                       if (td->flag & TD_NOACTION)
+                               break;
+                       if (td->loc == NULL)
+                               break;
+                       if (td->flag & TD_SKIP)
+                               continue;
 
-               eve = td->extra;
-               if (eve) {
-                       eve->co[0] = -td->loc[0];
-                       eve->co[1] = td->loc[1];
-                       eve->co[2] = td->loc[2];
-               }
+                       eve = td->extra;
+                       if (eve) {
+                               eve->co[0] = -td->loc[0];
+                               eve->co[1] = td->loc[1];
+                               eve->co[2] = td->loc[2];
+                       }
 
-               if (td->flag & TD_MIRROR_EDGE) {
-                       td->loc[0] = 0;
+                       if (td->flag & TD_MIRROR_EDGE) {
+                               td->loc[0] = 0;
+                       }
                }
        }
 }
@@ -339,7 +352,7 @@ static bool fcu_test_selected(FCurve *fcu)
 /* helper for recalcData() - for Action Editor transforms */
 static void recalcData_actedit(TransInfo *t)
 {
-       Scene *scene = t->scene;
+       ViewLayer *view_layer = t->view_layer;
        SpaceAction *saction = (SpaceAction *)t->sa->spacedata.first;
 
        bAnimContext ac = {NULL};
@@ -351,7 +364,8 @@ static void recalcData_actedit(TransInfo *t)
        /* NOTE: sync this with the code in ANIM_animdata_get_context() */
        ac.bmain = CTX_data_main(t->context);
        ac.scene = t->scene;
-       ac.obact = OBACT;
+       ac.view_layer = t->view_layer;
+       ac.obact = OBACT(view_layer);
        ac.sa = t->sa;
        ac.ar = t->ar;
        ac.sl = (t->sa) ? t->sa->spacedata.first : NULL;
@@ -376,7 +390,7 @@ static void recalcData_actedit(TransInfo *t)
                if ((saction->flag & SACTION_NOREALTIMEUPDATES) == 0) {
                        for (ale = anim_data.first; ale; ale = ale->next) {
                                /* set refresh tags for objects using this animation */
-                               ANIM_list_elem_update(CTX_data_main(t->context), scene, ale);
+                               ANIM_list_elem_update(CTX_data_main(t->context), t->scene, ale);
                        }
                }
 
@@ -388,7 +402,7 @@ static void recalcData_actedit(TransInfo *t)
 static void recalcData_graphedit(TransInfo *t)
 {
        SpaceIpo *sipo = (SpaceIpo *)t->sa->spacedata.first;
-       Scene *scene;
+       ViewLayer *view_layer = t->view_layer;
 
        ListBase anim_data = {NULL, NULL};
        bAnimContext ac = {NULL};
@@ -400,8 +414,9 @@ static void recalcData_graphedit(TransInfo *t)
        /* initialize relevant anim-context 'context' data from TransInfo data */
        /* NOTE: sync this with the code in ANIM_animdata_get_context() */
        ac.bmain = CTX_data_main(t->context);
-       scene = ac.scene = t->scene;
-       ac.obact = OBACT;
+       ac.scene = t->scene;
+       ac.view_layer = t->view_layer;
+       ac.obact = OBACT(view_layer);
        ac.sa = t->sa;
        ac.ar = t->ar;
        ac.sl = (t->sa) ? t->sa->spacedata.first : NULL;
@@ -454,11 +469,13 @@ static void recalcData_nla(TransInfo *t)
        double secf = FPS;
        int i;
 
+       TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
        /* for each strip we've got, perform some additional validation of the values that got set before
         * using RNA to set the value (which does some special operations when setting these values to make
         * sure that everything works ok)
         */
-       for (i = 0; i < t->total; i++, tdn++) {
+       for (i = 0; i < tc->data_len; i++, tdn++) {
                NlaStrip *strip = tdn->strip;
                PointerRNA strip_ptr;
                short pExceeded, nExceeded, iter;
@@ -663,7 +680,7 @@ static void recalcData_mask_common(TransInfo *t)
 
        flushTransMasking(t);
 
-       DAG_id_tag_update(&mask->id, 0);
+       DEG_id_tag_update(&mask->id, 0);
 }
 
 /* helper for recalcData() - for Image Editor transforms */
@@ -675,14 +692,18 @@ static void recalcData_image(TransInfo *t)
        else if (t->options & CTX_PAINT_CURVE) {
                flushTransPaintCurve(t);
        }
-       else if (t->obedit && t->obedit->type == OB_MESH) {
+       else if ((t->flag & T_EDIT) && t->obedit_type == OB_MESH) {
                SpaceImage *sima = t->sa->spacedata.first;
 
                flushTransUVs(t);
                if (sima->flag & SI_LIVE_UNWRAP)
                        ED_uvedit_live_unwrap_re_solve();
 
-               DAG_id_tag_update(t->obedit->data, 0);
+               FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+                       if (tc->data_len) {
+                               DEG_id_tag_update(tc->obedit->data, 0);
+                       }
+               }
        }
 }
 
@@ -725,7 +746,7 @@ static void recalcData_spaceclip(TransInfo *t)
                        track = track->next;
                }
 
-               DAG_id_tag_update(&clip->id, 0);
+               DEG_id_tag_update(&clip->id, 0);
        }
        else if (t->options & CTX_MASK) {
                recalcData_mask_common(t);
@@ -735,55 +756,59 @@ static void recalcData_spaceclip(TransInfo *t)
 /* helper for recalcData() - for object transforms, typically in the 3D view */
 static void recalcData_objects(TransInfo *t)
 {
-       Main *bmain = CTX_data_main(t->context);
-       Base *base = t->scene->basact;
+       Base *base = t->view_layer->basact;
 
-       if (t->obedit) {
-               if (ELEM(t->obedit->type, OB_CURVE, OB_SURF)) {
-                       Curve *cu = t->obedit->data;
-                       ListBase *nurbs = BKE_curve_editNurbs_get(cu);
-                       Nurb *nu = nurbs->first;
+       if (t->obedit_type != -1) {
+               if (ELEM(t->obedit_type, OB_CURVE, OB_SURF)) {
 
                        if (t->state != TRANS_CANCEL) {
-                               clipMirrorModifier(t, t->obedit);
+                               clipMirrorModifier(t);
                                applyProject(t);
                        }
 
-                       DAG_id_tag_update(t->obedit->data, 0);  /* sets recalc flags */
+                       FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+                               Curve *cu = tc->obedit->data;
+                               ListBase *nurbs = BKE_curve_editNurbs_get(cu);
+                               Nurb *nu = nurbs->first;
 
-                       if (t->state == TRANS_CANCEL) {
-                               while (nu) {
-                                       BKE_nurb_handles_calc(nu); /* Cant do testhandlesNurb here, it messes up the h1 and h2 flags */
-                                       nu = nu->next;
+                               DEG_id_tag_update(tc->obedit->data, 0);  /* sets recalc flags */
+
+                               if (t->state == TRANS_CANCEL) {
+                                       while (nu) {
+                                               BKE_nurb_handles_calc(nu); /* Cant do testhandlesNurb here, it messes up the h1 and h2 flags */
+                                               nu = nu->next;
+                                       }
                                }
-                       }
-                       else {
-                               /* Normal updating */
-                               while (nu) {
-                                       BKE_nurb_test2D(nu);
-                                       BKE_nurb_handles_calc(nu);
-                                       nu = nu->next;
+                               else {
+                                       /* Normal updating */
+                                       while (nu) {
+                                               BKE_nurb_test2D(nu);
+                                               BKE_nurb_handles_calc(nu);
+                                               nu = nu->next;
+                                       }
                                }
                        }
                }
-               else if (t->obedit->type == OB_LATTICE) {
-                       Lattice *la = t->obedit->data;
+               else if (t->obedit_type == OB_LATTICE) {
 
                        if (t->state != TRANS_CANCEL) {
                                applyProject(t);
                        }
 
-                       DAG_id_tag_update(t->obedit->data, 0);  /* sets recalc flags */
-
-                       if (la->editlatt->latt->flag & LT_OUTSIDE) outside_lattice(la->editlatt->latt);
+                       FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+                               Lattice *la = tc->obedit->data;
+                               DEG_id_tag_update(tc->obedit->data, 0);  /* sets recalc flags */
+                               if (la->editlatt->latt->flag & LT_OUTSIDE) {
+                                       outside_lattice(la->editlatt->latt);
+                               }
+                       }
                }
-               else if (t->obedit->type == OB_MESH) {
-                       BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
+               else if (t->obedit_type == OB_MESH) {
                        /* mirror modifier clipping? */
                        if (t->state != TRANS_CANCEL) {
                                /* apply clipping after so we never project past the clip plane [#25423] */
                                applyProject(t);
-                               clipMirrorModifier(t, t->obedit);
+                               clipMirrorModifier(t);
                        }
                        if ((t->options & CTX_NO_MIRROR) == 0 && (t->flag & T_MIRROR))
                                editbmesh_apply_to_mirror(t);
@@ -795,135 +820,152 @@ static void recalcData_objects(TransInfo *t)
                                projectVertSlideData(t, false);
                        }
 
-                       DAG_id_tag_update(t->obedit->data, 0);  /* sets recalc flags */
-
-                       EDBM_mesh_normals_update(em);
-                       BKE_editmesh_tessface_calc(em);
+                       FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+                               DEG_id_tag_update(tc->obedit->data, 0);  /* sets recalc flags */
+                               BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
+                               EDBM_mesh_normals_update(em);
+                               BKE_editmesh_tessface_calc(em);
+                       }
                }
-               else if (t->obedit->type == OB_ARMATURE) { /* no recalc flag, does pose */
-                       bArmature *arm = t->obedit->data;
-                       ListBase *edbo = arm->edbo;
-                       EditBone *ebo, *ebo_parent;
-                       TransData *td = t->data;
-                       int i;
+               else if (t->obedit_type == OB_ARMATURE) { /* no recalc flag, does pose */
 
                        if (t->state != TRANS_CANCEL) {
                                applyProject(t);
                        }
 
-                       /* Ensure all bones are correctly adjusted */
-                       for (ebo = edbo->first; ebo; ebo = ebo->next) {
-                               ebo_parent = (ebo->flag & BONE_CONNECTED) ? ebo->parent : NULL;
+                       FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+                               bArmature *arm = tc->obedit->data;
+                               ListBase *edbo = arm->edbo;
+                               EditBone *ebo, *ebo_parent;
+                               TransData *td = tc->data;
+                               int i;
 
-                               if (ebo_parent) {
-                                       /* If this bone has a parent tip that has been moved */
-                                       if (ebo_parent->flag & BONE_TIPSEL) {
-                                               copy_v3_v3(ebo->head, ebo_parent->tail);
-                                               if (t->mode == TFM_BONE_ENVELOPE) ebo->rad_head = ebo_parent->rad_tail;
-                                       }
-                                       /* If this bone has a parent tip that has NOT been moved */
-                                       else {
-                                               copy_v3_v3(ebo_parent->tail, ebo->head);
-                                               if (t->mode == TFM_BONE_ENVELOPE) ebo_parent->rad_tail = ebo->rad_head;
-                                       }
-                               }
+                               /* Ensure all bones are correctly adjusted */
+                               for (ebo = edbo->first; ebo; ebo = ebo->next) {
+                                       ebo_parent = (ebo->flag & BONE_CONNECTED) ? ebo->parent : NULL;
 
-                               /* on extrude bones, oldlength==0.0f, so we scale radius of points */
-                               ebo->length = len_v3v3(ebo->head, ebo->tail);
-                               if (ebo->oldlength == 0.0f) {
-                                       ebo->rad_head = 0.25f * ebo->length;
-                                       ebo->rad_tail = 0.10f * ebo->length;
-                                       ebo->dist = 0.25f * ebo->length;
-                                       if (ebo->parent) {
-                                               if (ebo->rad_head > ebo->parent->rad_tail)
-                                                       ebo->rad_head = ebo->parent->rad_tail;
+                                       if (ebo_parent) {
+                                               /* If this bone has a parent tip that has been moved */
+                                               if (ebo_parent->flag & BONE_TIPSEL) {
+                                                       copy_v3_v3(ebo->head, ebo_parent->tail);
+                                                       if (t->mode == TFM_BONE_ENVELOPE) ebo->rad_head = ebo_parent->rad_tail;
+                                               }
+                                               /* If this bone has a parent tip that has NOT been moved */
+                                               else {
+                                                       copy_v3_v3(ebo_parent->tail, ebo->head);
+                                                       if (t->mode == TFM_BONE_ENVELOPE) ebo_parent->rad_tail = ebo->rad_head;
+                                               }
                                        }
-                               }
-                               else if (t->mode != TFM_BONE_ENVELOPE) {
-                                       /* if bones change length, lets do that for the deform distance as well */
-                                       ebo->dist *= ebo->length / ebo->oldlength;
-                                       ebo->rad_head *= ebo->length / ebo->oldlength;
-                                       ebo->rad_tail *= ebo->length / ebo->oldlength;
-                                       ebo->oldlength = ebo->length;
 
-                                       if (ebo_parent) {
-                                               ebo_parent->rad_tail = ebo->rad_head;
+                                       /* on extrude bones, oldlength==0.0f, so we scale radius of points */
+                                       ebo->length = len_v3v3(ebo->head, ebo->tail);
+                                       if (ebo->oldlength == 0.0f) {
+                                               ebo->rad_head = 0.25f * ebo->length;
+                                               ebo->rad_tail = 0.10f * ebo->length;
+                                               ebo->dist = 0.25f * ebo->length;
+                                               if (ebo->parent) {
+                                                       if (ebo->rad_head > ebo->parent->rad_tail)
+                                                               ebo->rad_head = ebo->parent->rad_tail;
+                                               }
+                                       }
+                                       else if (t->mode != TFM_BONE_ENVELOPE) {
+                                               /* if bones change length, lets do that for the deform distance as well */
+                                               ebo->dist *= ebo->length / ebo->oldlength;
+                                               ebo->rad_head *= ebo->length / ebo->oldlength;
+                                               ebo->rad_tail *= ebo->length / ebo->oldlength;
+                                               ebo->oldlength = ebo->length;
+
+                                               if (ebo_parent) {
+                                                       ebo_parent->rad_tail = ebo->rad_head;
+                                               }
                                        }
                                }
-                       }
 
-                       if (!ELEM(t->mode, TFM_BONE_ROLL, TFM_BONE_ENVELOPE, TFM_BONE_ENVELOPE_DIST, TFM_BONESIZE)) {
-                               /* fix roll */
-                               for (i = 0; i < t->total; i++, td++) {
-                                       if (td->extra) {
-                                               float vec[3], up_axis[3];
-                                               float qrot[4];
-                                               float roll;
+                               if (!ELEM(t->mode, TFM_BONE_ROLL, TFM_BONE_ENVELOPE, TFM_BONE_ENVELOPE_DIST, TFM_BONESIZE)) {
+                                       /* fix roll */
+                                       for (i = 0; i < tc->data_len; i++, td++) {
+                                               if (td->extra) {
+                                                       float vec[3], up_axis[3];
+                                                       float qrot[4];
+                                                       float roll;
 
-                                               ebo = td->extra;
+                                                       ebo = td->extra;
 
-                                               if (t->state == TRANS_CANCEL) {
-                                                       /* restore roll */
-                                                       ebo->roll = td->ival;
-                                               }
-                                               else {
-                                                       copy_v3_v3(up_axis, td->axismtx[2]);
+                                                       if (t->state == TRANS_CANCEL) {
+                                                               /* restore roll */
+                                                               ebo->roll = td->ival;
+                                                       }
+                                                       else {
+                                                               copy_v3_v3(up_axis, td->axismtx[2]);
 
-                                                       sub_v3_v3v3(vec, ebo->tail, ebo->head);
-                                                       normalize_v3(vec);
-                                                       rotation_between_vecs_to_quat(qrot, td->axismtx[1], vec);
-                                                       mul_qt_v3(qrot, up_axis);
+                                                               sub_v3_v3v3(vec, ebo->tail, ebo->head);
+                                                               normalize_v3(vec);
+                                                               rotation_between_vecs_to_quat(qrot, td->axismtx[1], vec);
+                                                               mul_qt_v3(qrot, up_axis);
 
-                                                       /* roll has a tendency to flip in certain orientations - [#34283], [#33974] */
-                                                       roll = ED_armature_ebone_roll_to_vector(ebo, up_axis, false);
-                                                       ebo->roll = angle_compat_rad(roll, td->ival);
+                                                               /* roll has a tendency to flip in certain orientations - [#34283], [#33974] */
+                                                               roll = ED_armature_ebone_roll_to_vector(ebo, up_axis, false);
+                                                               ebo->roll = angle_compat_rad(roll, td->ival);
+                                                       }
                                                }
                                        }
                                }
-                       }
 
-                       if (arm->flag & ARM_MIRROR_EDIT) {
-                               if (t->state != TRANS_CANCEL)
-                                       ED_armature_edit_transform_mirror_update(t->obedit);
-                               else
-                                       restoreBones(t);
+                               if (arm->flag & ARM_MIRROR_EDIT) {
+                                       if (t->state != TRANS_CANCEL) {
+                                               ED_armature_edit_transform_mirror_update(tc->obedit);
+                                       }
+                                       else {
+                                               restoreBones(tc);
+                                       }
+                               }
                        }
                }
                else {
                        if (t->state != TRANS_CANCEL) {
                                applyProject(t);
                        }
-                       DAG_id_tag_update(t->obedit->data, 0);  /* sets recalc flags */
+                       FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+                               if (tc->data_len) {
+                                       DEG_id_tag_update(tc->obedit->data, 0);  /* sets recalc flags */
+                               }
+                       }
                }
+
        }
-       else if ((t->flag & T_POSE) && t->poseobj) {
-               Object *ob = t->poseobj;
-               bArmature *arm = ob->data;
+       else if (t->flag & T_POSE) {
+               FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+                       Object *ob = tc->poseobj;
+                       bArmature *arm = ob->data;
 
-               /* if animtimer is running, and the object already has animation data,
-                * check if the auto-record feature means that we should record 'samples'
-                * (i.e. uneditable animation values)
-                *
-                * context is needed for keying set poll() functions.
-                */
-               // TODO: autokeyframe calls need some setting to specify to add samples (FPoints) instead of keyframes?
-               if ((t->animtimer) && (t->context) && IS_AUTOKEY_ON(t->scene)) {
-                       int targetless_ik = (t->flag & T_AUTOIK); // XXX this currently doesn't work, since flags aren't set yet!
+                       /* if animtimer is running, and the object already has animation data,
+                        * check if the auto-record feature means that we should record 'samples'
+                        * (i.e. uneditable animation values)
+                        *
+                        * context is needed for keying set poll() functions.
+                        */
+                       // TODO: autokeyframe calls need some setting to specify to add samples (FPoints) instead of keyframes?
+                       if ((t->animtimer) && (t->context) && IS_AUTOKEY_ON(t->scene)) {
+                               int targetless_ik = (t->flag & T_AUTOIK); // XXX this currently doesn't work, since flags aren't set yet!
 
-                       animrecord_check_state(t->scene, &ob->id, t->animtimer);
-                       autokeyframe_pose_cb_func(t->context, t->scene, (View3D *)t->view, ob, t->mode, targetless_ik);
-               }
+                               animrecord_check_state(t->scene, &ob->id, t->animtimer);
+                               autokeyframe_pose_cb_func(t->context, t->scene, ob, t->mode, targetless_ik);
+                       }
 
-               /* old optimize trick... this enforces to bypass the depgraph */
-               if (!(arm->flag & ARM_DELAYDEFORM)) {
-                       DAG_id_tag_update(&ob->id, OB_RECALC_DATA);  /* sets recalc flags */
-                       /* transformation of pose may affect IK tree, make sure it is rebuilt */
-                       BIK_clear_data(ob->pose);
+                       /* old optimize trick... this enforces to bypass the depgraph */
+                       if (!(arm->flag & ARM_DELAYDEFORM)) {
+                               DEG_id_tag_update(&ob->id, OB_RECALC_DATA);  /* sets recalc flags */
+                               /* transformation of pose may affect IK tree, make sure it is rebuilt */
+                               BIK_clear_data(ob->pose);
+                       }
+                       else {
+                               BKE_pose_where_is(t->depsgraph, t->scene, ob);
+                       }
                }
-               else
-                       BKE_pose_where_is(t->scene, ob);
        }
-       else if (base && (base->object->mode & OB_MODE_PARTICLE_EDIT) && PE_get_current(bmain, t->scene, base->object)) {
+       else if (base && (base->object->mode & OB_MODE_PARTICLE_EDIT) &&
+                PE_get_current(t->scene, base->object))
+       {
                if (t->state != TRANS_CANCEL) {
                        applyProject(t);
                }
@@ -936,37 +978,45 @@ static void recalcData_objects(TransInfo *t)
                        applyProject(t);
                }
 
-               for (i = 0; i < t->total; i++) {
-                       TransData *td = t->data + i;
-                       Object *ob = td->ob;
+               FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+                       TransData *td = tc->data;
 
-                       if (td->flag & TD_NOACTION)
-                               break;
+                       for (i = 0; i < tc->data_len; i++, td++) {
+                               Object *ob = td->ob;
 
-                       if (td->flag & TD_SKIP)
-                               continue;
+                               if (td->flag & TD_NOACTION)
+                                       break;
 
-                       /* if animtimer is running, and the object already has animation data,
-                        * check if the auto-record feature means that we should record 'samples'
-                        * (i.e. uneditable animation values)
-                        */
-                       // TODO: autokeyframe calls need some setting to specify to add samples (FPoints) instead of keyframes?
-                       if ((t->animtimer) && IS_AUTOKEY_ON(t->scene)) {
-                               animrecord_check_state(t->scene, &ob->id, t->animtimer);
-                               autokeyframe_ob_cb_func(t->context, t->scene, (View3D *)t->view, ob, t->mode);
-                       }
+                               if (td->flag & TD_SKIP)
+                                       continue;
 
-                       /* sets recalc flags fully, instead of flushing existing ones
-                        * otherwise proxies don't function correctly
-                        */
-                       DAG_id_tag_update(&ob->id, OB_RECALC_OB);
+                               /* if animtimer is running, and the object already has animation data,
+                                * check if the auto-record feature means that we should record 'samples'
+                                * (i.e. uneditable animation values)
+                                */
+                               // TODO: autokeyframe calls need some setting to specify to add samples (FPoints) instead of keyframes?
+                               if ((t->animtimer) && IS_AUTOKEY_ON(t->scene)) {
+                                       animrecord_check_state(t->scene, &ob->id, t->animtimer);
+                                       autokeyframe_ob_cb_func(t->context, t->scene, t->view_layer, ob, t->mode);
+                               }
+
+                               /* sets recalc flags fully, instead of flushing existing ones
+                                * otherwise proxies don't function correctly
+                                */
+                               DEG_id_tag_update(&ob->id, OB_RECALC_OB);
 
-                       if (t->flag & T_TEXTURE)
-                               DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+                               if (t->flag & T_TEXTURE)
+                                       DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+                       }
                }
        }
 }
 
+static void recalcData_cursor(TransInfo *t)
+{
+       DEG_id_tag_update(&t->scene->id, DEG_TAG_COPY_ON_WRITE);
+}
+
 /* helper for recalcData() - for sequencer transforms */
 static void recalcData_sequencer(TransInfo *t)
 {
@@ -974,7 +1024,9 @@ static void recalcData_sequencer(TransInfo *t)
        int a;
        Sequence *seq_prev = NULL;
 
-       for (a = 0, td = t->data; a < t->total; a++, td++) {
+       TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
+       for (a = 0, td = tc->data; a < tc->data_len; a++, td++) {
                TransDataSeq *tdsq = (TransDataSeq *) td->extra;
                Sequence *seq = tdsq->seq;
 
@@ -999,8 +1051,10 @@ static void recalcData_sequencer(TransInfo *t)
 /* force recalculation of triangles during transformation */
 static void recalcData_gpencil_strokes(TransInfo *t)
 {
-       TransData *td = t->data;
-       for (int i = 0; i < t->total; i++, td++) {
+       TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
+       TransData *td = tc->data;
+       for (int i = 0; i < tc->data_len; i++, td++) {
                bGPDstroke *gps = td->extra;
                if (gps != NULL) {
                        gps->flag |= GP_STROKE_RECALC_CACHES;
@@ -1012,7 +1066,10 @@ static void recalcData_gpencil_strokes(TransInfo *t)
 void recalcData(TransInfo *t)
 {
        /* if tests must match createTransData for correct updates */
-       if (t->options & CTX_TEXTURE) {
+       if (t->options & CTX_CURSOR) {
+               recalcData_cursor(t);
+       }
+       else if (t->options & CTX_TEXTURE) {
                recalcData_objects(t);
        }
        else if (t->options & CTX_EDGE) {
@@ -1059,10 +1116,7 @@ void drawLine(TransInfo *t, const float center[3], const float dir[3], char axis
        if (t->spacetype == SPACE_VIEW3D) {
                View3D *v3d = t->view;
 
-               glPushMatrix();
-
-               //if (t->obedit) glLoadMatrixf(t->obedit->obmat);       // sets opengl viewing
-
+               gpuPushMatrix();
 
                copy_v3_v3(v3, dir);
                mul_v3_fl(v3, v3d->far);
@@ -1077,15 +1131,20 @@ void drawLine(TransInfo *t, const float center[3], const float dir[3], char axis
                        UI_GetThemeColor3ubv(TH_GRID, col);
                }
                UI_make_axis_color(col, col2, axis);
-               glColor3ubv(col2);
 
-               setlinestyle(0);
-               glBegin(GL_LINES);
-               glVertex3fv(v1);
-               glVertex3fv(v2);
-               glEnd();
+               unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+
+               immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+               immUniformColor3ubv(col2);
+
+               immBegin(GWN_PRIM_LINES, 2);
+               immVertex3fv(pos, v1);
+               immVertex3fv(pos, v2);
+               immEnd();
+
+               immUnbindProgram();
 
-               glPopMatrix();
+               gpuPopMatrix();
        }
 }
 
@@ -1094,12 +1153,7 @@ void drawLine(TransInfo *t, const float center[3], const float dir[3], char axis
  */
 void resetTransModal(TransInfo *t)
 {
-       if (t->mode == TFM_EDGE_SLIDE) {
-               freeEdgeSlideVerts(t, &t->custom.mode);
-       }
-       else if (t->mode == TFM_VERT_SLIDE) {
-               freeVertSlideVerts(t, &t->custom.mode);
-       }
+       freeTransCustomDataForMode(t);
 }
 
 void resetTransRestrictions(TransInfo *t)
@@ -1121,6 +1175,53 @@ static int initTransInfo_edit_pet_to_flag(const int proportional)
        }
 }
 
+void initTransDataContainers_FromObjectData(TransInfo *t)
+{
+       const eObjectMode object_mode = OBACT(t->view_layer) ? OBACT(t->view_layer)->mode : OB_MODE_OBJECT;
+       const short object_type = OBACT(t->view_layer) ? OBACT(t->view_layer)->type : -1;
+
+       if ((object_mode & OB_MODE_EDIT) ||
+           ((object_mode & OB_MODE_POSE) && (object_type == OB_ARMATURE)))
+       {
+               if (t->data_container) {
+                       MEM_freeN(t->data_container);
+               }
+               uint objects_len;
+               Object **objects = BKE_view_layer_array_from_objects_in_mode(
+                       t->view_layer, &objects_len, {
+                           .object_mode = object_mode,
+                           .no_dup_data = true});
+               t->data_container = MEM_callocN(sizeof(*t->data_container) * objects_len, __func__);
+               t->data_container_len = objects_len;
+
+               for (int i = 0; i < objects_len; i++) {
+                       TransDataContainer *tc = &t->data_container[i];
+                       if (object_mode & OB_MODE_EDIT) {
+                               tc->obedit = objects[i];
+                               /* Check needed for UV's */
+                               if ((t->flag & T_2D_EDIT) == 0) {
+                                       tc->use_local_mat = true;
+                               }
+                       }
+                       else if (object_mode & OB_MODE_POSE) {
+                               tc->poseobj = objects[i];
+                               tc->use_local_mat = true;
+                       }
+
+                       if (tc->use_local_mat) {
+                               BLI_assert((t->flag & T_2D_EDIT) == 0);
+                               copy_m4_m4(tc->mat, objects[i]->obmat);
+                               copy_m3_m4(tc->mat3, tc->mat);
+                               invert_m4_m4(tc->imat, tc->mat);
+                               invert_m3_m3(tc->imat3, tc->mat3);
+                               normalize_m3_m3(tc->mat3_unit, tc->mat3);
+                       }
+                       /* Otherwise leave as zero. */
+               }
+               MEM_freeN(objects);
+       }
+}
+
 /**
  * Setup internal data, mouse, vectors
  *
@@ -1130,34 +1231,38 @@ static int initTransInfo_edit_pet_to_flag(const int proportional)
  */
 void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *event)
 {
+       Depsgraph *depsgraph = CTX_data_depsgraph(C);
        Scene *sce = CTX_data_scene(C);
+       ViewLayer *view_layer = CTX_data_view_layer(C);
+       const eObjectMode object_mode = OBACT(view_layer) ? OBACT(view_layer)->mode : OB_MODE_OBJECT;
+       const short object_type = OBACT(view_layer) ? OBACT(view_layer)->type : -1;
        ToolSettings *ts = CTX_data_tool_settings(C);
        ARegion *ar = CTX_wm_region(C);
        ScrArea *sa = CTX_wm_area(C);
-       Object *obedit = CTX_data_edit_object(C);
-       Object *ob = CTX_data_active_object(C);
+
        bGPdata *gpd = CTX_data_gpencil_data(C);
        PropertyRNA *prop;
 
+       t->depsgraph = depsgraph;
        t->scene = sce;
+       t->view_layer = view_layer;
        t->sa = sa;
        t->ar = ar;
-       t->obedit = obedit;
        t->settings = ts;
        t->reports = op ? op->reports : NULL;
 
-       if (obedit) {
-               copy_m3_m4(t->obedit_mat, obedit->obmat);
-               normalize_m3(t->obedit_mat);
-       }
-
-       t->data = NULL;
-       t->ext = NULL;
-
        t->helpline = HLP_NONE;
 
        t->flag = 0;
 
+       t->obedit_type = (object_mode == OB_MODE_EDIT) ? object_type : -1;
+
+       /* Many kinds of transform only use a single handle. */
+       if (t->data_container == NULL) {
+               t->data_container = MEM_callocN(sizeof(*t->data_container), __func__);
+               t->data_container_len = 1;
+       }
+
        t->redraw = TREDRAW_HARD;  /* redraw first time */
 
        if (event) {
@@ -1178,12 +1283,11 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
        t->transform        = NULL;
        t->handleEvent      = NULL;
 
-       t->total            = 0;
+       t->data_len_all = 0;
 
        t->val = 0.0f;
 
        zero_v3(t->vec);
-       zero_v3(t->center);
        zero_v3(t->center_global);
 
        unit_m3(t->mat);
@@ -1232,9 +1336,7 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
                        prop_id = "use_even_offset";
                }
 
-               if (prop_id && (prop = RNA_struct_find_property(op->ptr, prop_id)) &&
-                   RNA_property_is_set(op->ptr, prop))
-               {
+               if (prop_id && (prop = RNA_struct_find_property(op->ptr, prop_id))) {
                        SET_FLAG_FROM_TEST(t->flag, RNA_property_boolean_get(op->ptr, prop), T_ALT_TRANSFORM);
                }
        }
@@ -1247,34 +1349,37 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
                t->animtimer = (animscreen) ? animscreen->animtimer : NULL;
 
                /* turn manipulator off during transform */
-               // FIXME: but don't do this when USING the manipulator...
                if (t->flag & T_MODAL) {
-                       t->twtype = v3d->twtype;
-                       v3d->twtype = 0;
+                       t->twflag = v3d->twflag;
+                       v3d->twflag = 0;
                }
 
-               if (v3d->flag & V3D_ALIGN) t->flag |= T_V3D_ALIGN;
-               t->around = v3d->around;
+               if (t->scene->toolsettings->transform_flag & SCE_XFORM_AXIS_ALIGN) {
+                       t->flag |= T_V3D_ALIGN;
+               }
+               t->around = t->scene->toolsettings->transform_pivot_point;
 
                /* bend always uses the cursor */
                if (t->mode == TFM_BEND) {
                        t->around = V3D_AROUND_CURSOR;
                }
 
-               t->current_orientation = v3d->twmode;
+               t->current_orientation = t->scene->orientation_type;
+               t->custom_orientation = BKE_scene_transform_orientation_find(
+                       t->scene, t->scene->orientation_index_custom);
 
                /* exceptional case */
                if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
                        if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL)) {
                                const bool use_island = transdata_check_local_islands(t, t->around);
 
-                               if (obedit && !use_island) {
+                               if ((t->obedit_type != -1) && !use_island) {
                                        t->options |= CTX_NO_PET;
                                }
                        }
                }
 
-               if (ob && ob->mode & OB_MODE_ALL_PAINT) {
+               if (object_mode & OB_MODE_ALL_PAINT) {
                        Paint *p = BKE_paint_get_active_from_context(C);
                        if (p && p->brush && (p->brush->flag & BRUSH_CURVE)) {
                                t->options |= CTX_PAINT_CURVE;
@@ -1303,7 +1408,7 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
                t->view = &ar->v2d;
                t->around = sima->around;
 
-               if (ED_space_image_show_uvedit(sima, t->obedit)) {
+               if (ED_space_image_show_uvedit(sima, OBACT(t->view_layer))) {
                        /* UV transform */
                }
                else if (sima->mode == SI_MODE_MASK) {
@@ -1352,11 +1457,22 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
        if (op && ((prop = RNA_struct_find_property(op->ptr, "constraint_orientation")) &&
                   RNA_property_is_set(op->ptr, prop)))
        {
-               t->current_orientation = RNA_property_enum_get(op->ptr, prop);
+               short orientation = RNA_property_enum_get(op->ptr, prop);
+               TransformOrientation *custom_orientation = NULL;
 
-               if (t->current_orientation >= V3D_MANIP_CUSTOM + BIF_countTransformOrientation(C)) {
-                       t->current_orientation = V3D_MANIP_GLOBAL;
+               if (orientation >= V3D_MANIP_CUSTOM) {
+                       if (orientation >= V3D_MANIP_CUSTOM + BIF_countTransformOrientation(C)) {
+                               orientation = V3D_MANIP_GLOBAL;
+                       }
+                       else {
+                               custom_orientation = BKE_scene_transform_orientation_find(
+                                       t->scene, orientation - V3D_MANIP_CUSTOM);
+                               orientation = V3D_MANIP_CUSTOM;
+                       }
                }
+
+               t->current_orientation = orientation;
+               t->custom_orientation = custom_orientation;
        }
 
        if (op && ((prop = RNA_struct_find_property(op->ptr, "release_confirm")) &&
@@ -1382,7 +1498,8 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
        }
        // Need stuff to take it from edit mesh or whatnot here
        else if (t->spacetype == SPACE_VIEW3D) {
-               if (t->obedit && t->obedit->type == OB_MESH && (((Mesh *)t->obedit->data)->editflag & ME_EDIT_MIRROR_X)) {
+               /* TODO(campbell): xform, get mirror from each object. */
+               if (t->obedit_type == OB_MESH && (((Mesh *)OBACT(t->view_layer)->data)->editflag & ME_EDIT_MIRROR_X)) {
                        t->flag |= T_MIRROR;
                        t->mirror = 1;
                }
@@ -1403,7 +1520,7 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
                                        else if (t->spacetype == SPACE_ACTION) {
                                                t->flag |= initTransInfo_edit_pet_to_flag(ts->proportional_action);
                                        }
-                                       else if (t->obedit) {
+                                       else if (t->obedit_type != -1) {
                                                t->flag |= initTransInfo_edit_pet_to_flag(ts->proportional);
                                        }
                                        else if (t->options & CTX_GPENCIL_STROKES) {
@@ -1418,7 +1535,7 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
                                                        }
                                                }
                                        }
-                                       else if (t->obedit == NULL && ts->proportional_objects) {
+                                       else if ((t->obedit_type == -1) && ts->proportional_objects) {
                                                t->flag |= T_PROP_EDIT;
                                        }
                                }
@@ -1464,8 +1581,8 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
        setTransformViewAspect(t, t->aspect);
 
        if (op && (prop = RNA_struct_find_property(op->ptr, "center_override")) && RNA_property_is_set(op->ptr, prop)) {
-               RNA_property_float_get_array(op->ptr, prop, t->center);
-               mul_v3_v3(t->center, t->aspect);
+               RNA_property_float_get_array(op->ptr, prop, t->center_global);
+               mul_v3_v3(t->center_global, t->aspect);
                t->flag |= T_OVERRIDE_CENTER;
        }
 
@@ -1473,11 +1590,47 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
        initNumInput(&t->num);
 }
 
+
+static void freeTransCustomData(
+        TransInfo *t, TransDataContainer *tc,
+        TransCustomData *custom_data)
+{
+       if (custom_data->free_cb) {
+               /* Can take over freeing t->data and data_2d etc... */
+               custom_data->free_cb(t, tc, custom_data);
+               BLI_assert(custom_data->data == NULL);
+       }
+       else if ((custom_data->data != NULL) && custom_data->use_free) {
+               MEM_freeN(custom_data->data);
+               custom_data->data = NULL;
+       }
+       /* In case modes are switched in the same transform session. */
+       custom_data->free_cb = false;
+       custom_data->use_free = false;
+}
+
+static void freeTransCustomDataContainer(TransInfo *t, TransDataContainer *tc, TransCustomDataContainer *tcdc)
+{
+       TransCustomData *custom_data = &tcdc->first_elem;
+       for (int i = 0; i < TRANS_CUSTOM_DATA_ELEM_MAX; i++, custom_data++) {
+               freeTransCustomData(t, tc, custom_data);
+       }
+}
+
+/**
+ * Needed for mode switching.
+ */
+void freeTransCustomDataForMode(TransInfo *t)
+{
+       freeTransCustomData(t, NULL, &t->custom.mode);
+       FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+               freeTransCustomData(t, tc, &tc->custom.mode);
+       }
+}
+
 /* Here I would suggest only TransInfo related issues, like free data & reset vars. Not redraws */
 void postTrans(bContext *C, TransInfo *t)
 {
-       TransData *td;
-
        if (t->draw_handle_view)
                ED_region_draw_cb_exit(t->ar->type, t->draw_handle_view);
        if (t->draw_handle_apply)
@@ -1487,46 +1640,41 @@ void postTrans(bContext *C, TransInfo *t)
        if (t->draw_handle_cursor)
                WM_paint_cursor_end(CTX_wm_manager(C), t->draw_handle_cursor);
 
+       if (t->flag & T_MODAL_CURSOR_SET) {
+               WM_cursor_modal_restore(CTX_wm_window(C));
+       }
+
        /* Free all custom-data */
-       {
-               TransCustomData *custom_data = &t->custom.first_elem;
-               for (int i = 0; i < TRANS_CUSTOM_DATA_ELEM_MAX; i++, custom_data++) {
-                       if (custom_data->free_cb) {
-                               /* Can take over freeing t->data and data2d etc... */
-                               custom_data->free_cb(t, custom_data);
-                               BLI_assert(custom_data->data == NULL);
-                       }
-                       else if ((custom_data->data != NULL) && custom_data->use_free) {
-                               MEM_freeN(custom_data->data);
-                               custom_data->data = NULL;
-                       }
-               }
+       freeTransCustomDataContainer(t, NULL, &t->custom);
+       FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+               freeTransCustomDataContainer(t, tc, &tc->custom);
        }
 
        /* postTrans can be called when nothing is selected, so data is NULL already */
-       if (t->data) {
-
-               /* free data malloced per trans-data */
-               if ((t->obedit && ELEM(t->obedit->type, OB_CURVE, OB_SURF)) ||
-                   (t->spacetype == SPACE_IPO))
-               {
-                       int a;
-                       for (a = 0, td = t->data; a < t->total; a++, td++) {
-                               if (td->flag & TD_BEZTRIPLE) {
-                                       MEM_freeN(td->hdata);
+       if (t->data_len_all != 0) {
+               FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+                       /* free data malloced per trans-data */
+                       if (ELEM(t->obedit_type, OB_CURVE, OB_SURF) ||
+                           (t->spacetype == SPACE_IPO))
+                       {
+                               TransData *td = tc->data;
+                               for (int a = 0; a < tc->data_len; a++, td++) {
+                                       if (td->flag & TD_BEZTRIPLE) {
+                                               MEM_freeN(td->hdata);
+                                       }
                                }
                        }
+                       MEM_freeN(tc->data);
+
+                       MEM_SAFE_FREE(tc->data_ext);
+                       MEM_SAFE_FREE(tc->data_2d);
                }
-               MEM_freeN(t->data);
        }
 
-       BLI_freelistN(&t->tsnap.points);
+       MEM_SAFE_FREE(t->data_container);
+       t->data_container = NULL;
 
-       if (t->ext) MEM_freeN(t->ext);
-       if (t->data2d) {
-               MEM_freeN(t->data2d);
-               t->data2d = NULL;
-       }
+       BLI_freelistN(&t->tsnap.points);
 
        if (t->spacetype == SPACE_IMAGE) {
                if (t->options & (CTX_MASK | CTX_PAINT_CURVE)) {
@@ -1542,7 +1690,7 @@ void postTrans(bContext *C, TransInfo *t)
                View3D *v3d = t->sa->spacedata.first;
                /* restore manipulator */
                if (t->flag & T_MODAL) {
-                       v3d->twtype = t->twtype;
+                       v3d->twflag = t->twflag;
                }
        }
 
@@ -1550,14 +1698,20 @@ void postTrans(bContext *C, TransInfo *t)
                MEM_freeN(t->mouse.data);
        }
 
+       if (t->rng != NULL) {
+               BLI_rng_free(t->rng);
+       }
+
        freeSnapping(t);
 }
 
 void applyTransObjects(TransInfo *t)
 {
+       TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+
        TransData *td;
 
-       for (td = t->data; td < t->data + t->total; td++) {
+       for (td = tc->data; td < tc->data + tc->data_len; td++) {
                copy_v3_v3(td->iloc, td->loc);
                if (td->ext->rot) {
                        copy_v3_v3(td->ext->irot, td->ext->rot);
@@ -1606,25 +1760,29 @@ static void restoreElement(TransData *td)
 
 void restoreTransObjects(TransInfo *t)
 {
-       TransData *td;
-       TransData2D *td2d;
+       FOREACH_TRANS_DATA_CONTAINER (t, tc) {
 
-       for (td = t->data; td < t->data + t->total; td++) {
-               restoreElement(td);
-       }
+               TransData *td;
+               TransData2D *td2d;
 
-       for (td2d = t->data2d; t->data2d && td2d < t->data2d + t->total; td2d++) {
-               if (td2d->h1) {
-                       td2d->h1[0] = td2d->ih1[0];
-                       td2d->h1[1] = td2d->ih1[1];
+               for (td = tc->data; td < tc->data + tc->data_len; td++) {
+                       restoreElement(td);
                }
-               if (td2d->h2) {
-                       td2d->h2[0] = td2d->ih2[0];
-                       td2d->h2[1] = td2d->ih2[1];
+
+               for (td2d = tc->data_2d; tc->data_2d && td2d < tc->data_2d + tc->data_len; td2d++) {
+                       if (td2d->h1) {
+                               td2d->h1[0] = td2d->ih1[0];
+                               td2d->h1[1] = td2d->ih1[1];
+                       }
+                       if (td2d->h2) {
+                               td2d->h2[0] = td2d->ih2[0];
+                               td2d->h2[1] = td2d->ih2[1];
+                       }
                }
-       }
 
-       unit_m3(t->mat);
+               unit_m3(t->mat);
+
+       }
 
        recalcData(t);
 }
@@ -1632,32 +1790,21 @@ void restoreTransObjects(TransInfo *t)
 void calculateCenter2D(TransInfo *t)
 {
        BLI_assert(!is_zero_v3(t->aspect));
-
-       if (t->flag & (T_EDIT | T_POSE)) {
-               Object *ob = t->obedit ? t->obedit : t->poseobj;
-               float vec[3];
-
-               copy_v3_v3(vec, t->center);
-               mul_m4_v3(ob->obmat, vec);
-               projectFloatView(t, vec, t->center2d);
-       }
-       else {
-               projectFloatView(t, t->center, t->center2d);
-       }
+       projectFloatView(t, t->center_global, t->center2d);
 }
 
-void calculateCenterGlobal(
-        TransInfo *t, const float center_local[3],
-        float r_center_global[3])
+void calculateCenterLocal(
+        TransInfo *t, const float center_global[3])
 {
        /* setting constraint center */
        /* note, init functions may over-ride t->center */
-       if (t->flag & (T_EDIT | T_POSE)) {
-               Object *ob = t->obedit ? t->obedit : t->poseobj;
-               mul_v3_m4v3(r_center_global, ob->obmat, center_local);
-       }
-       else {
-               copy_v3_v3(r_center_global, center_local);
+       FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+               if (tc->use_local_mat) {
+                       mul_v3_m4v3(tc->center_local, tc->imat, center_global);
+               }
+               else {
+                       copy_v3_v3(tc->center_local, center_global);
+               }
        }
 }
 
@@ -1665,20 +1812,11 @@ void calculateCenterCursor(TransInfo *t, float r_center[3])
 {
        const float *cursor;
 
-       cursor = ED_view3d_cursor3d_get(t->scene, t->view);
+       cursor = ED_view3d_cursor3d_get(t->scene, t->view)->location;
        copy_v3_v3(r_center, cursor);
 
        /* If edit or pose mode, move cursor in local space */
-       if (t->flag & (T_EDIT | T_POSE)) {
-               Object *ob = t->obedit ? t->obedit : t->poseobj;
-               float mat[3][3], imat[3][3];
-
-               sub_v3_v3v3(r_center, r_center, ob->obmat[3]);
-               copy_m3_m4(mat, ob->obmat);
-               invert_m3_m3(imat, mat);
-               mul_m3_v3(imat, r_center);
-       }
-       else if (t->options & CTX_PAINT_CURVE) {
+       if (t->options & CTX_PAINT_CURVE) {
                if (ED_view3d_project_float_global(t->ar, cursor, r_center, V3D_PROJ_TEST_NOP) != V3D_PROJ_RET_OK) {
                        r_center[0] = t->ar->winx / 2.0f;
                        r_center[1] = t->ar->winy / 2.0f;
@@ -1752,13 +1890,21 @@ void calculateCenterMedian(TransInfo *t, float r_center[3])
 {
        float partial[3] = {0.0f, 0.0f, 0.0f};
        int total = 0;
-       int i;
 
-       for (i = 0; i < t->total; i++) {
-               if (t->data[i].flag & TD_SELECTED) {
-                       if (!(t->data[i].flag & TD_NOCENTER)) {
-                               add_v3_v3(partial, t->data[i].center);
-                               total++;
+       FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+               for (int i = 0; i < tc->data_len; i++) {
+                       if (tc->data[i].flag & TD_SELECTED) {
+                               if (!(tc->data[i].flag & TD_NOCENTER)) {
+                                       if (tc->use_local_mat) {
+                                               float v[3];
+                                               mul_v3_m4v3(v, tc->mat, tc->data[i].center);
+                                               add_v3_v3(partial, v);
+                                       }
+                                       else {
+                                               add_v3_v3(partial, tc->data[i].center);
+                                       }
+                                       total++;
+                               }
                        }
                }
        }
@@ -1770,22 +1916,29 @@ void calculateCenterMedian(TransInfo *t, float r_center[3])
 
 void calculateCenterBound(TransInfo *t, float r_center[3])
 {
-       float max[3];
-       float min[3];
-       int i;
-       for (i = 0; i < t->total; i++) {
-               if (i) {
-                       if (t->data[i].flag & TD_SELECTED) {
-                               if (!(t->data[i].flag & TD_NOCENTER))
-                                       minmax_v3v3_v3(min, max, t->data[i].center);
+       float max[3], min[3];
+       bool changed = false;
+       INIT_MINMAX(min, max);
+       FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+               for (int i = 0; i < tc->data_len; i++) {
+                       if (tc->data[i].flag & TD_SELECTED) {
+                               if (!(tc->data[i].flag & TD_NOCENTER)) {
+                                       if (tc->use_local_mat) {
+                                               float v[3];
+                                               mul_v3_m4v3(v, tc->mat, tc->data[i].center);
+                                               minmax_v3v3_v3(min, max, v);
+                                       }
+                                       else {
+                                               minmax_v3v3_v3(min, max, tc->data[i].center);
+                                       }
+                                       changed = true;
+                               }
                        }
                }
-               else {
-                       copy_v3_v3(max, t->data[i].center);
-                       copy_v3_v3(min, t->data[i].center);
-               }
        }
-       mid_v3_v3v3(r_center, min, max);
+       if (changed) {
+               mid_v3_v3v3(r_center, min, max);
+       }
 }
 
 /**
@@ -1793,26 +1946,30 @@ void calculateCenterBound(TransInfo *t, float r_center[3])
  */
 bool calculateCenterActive(TransInfo *t, bool select_only, float r_center[3])
 {
+       TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_OK(t);
+
        bool ok = false;
 
-       if (t->obedit) {
-               if (ED_object_editmode_calc_active_center(t->obedit, select_only, r_center)) {
+       if (tc->obedit) {
+               if (ED_object_editmode_calc_active_center(tc->obedit, select_only, r_center)) {
+                       mul_m4_v3(tc->obedit->obmat, r_center);
                        ok = true;
                }
        }
        else if (t->flag & T_POSE) {
-               Scene *scene = t->scene;
-               Object *ob = OBACT;
+               ViewLayer *view_layer = t->view_layer;
+               Object *ob = OBACT(view_layer);
                if (ob) {
                        bPoseChannel *pchan = BKE_pose_channel_active(ob);
                        if (pchan && (!select_only || (pchan->bone->flag & BONE_SELECTED))) {
                                copy_v3_v3(r_center, pchan->pose_head);
+                               mul_m4_v3(ob->obmat, r_center);
                                ok = true;
                        }
                }
        }
        else if (t->options & CTX_PAINT_CURVE) {
-               Paint *p = BKE_paint_get_active(t->scene);
+               Paint *p = BKE_paint_get_active(t->scene, t->view_layer);
                Brush *br = p->brush;
                PaintCurve *pc = br->paint_curve;
                copy_v3_v3(r_center, pc->points[pc->add_index - 1].bez.vec[1]);
@@ -1821,9 +1978,10 @@ bool calculateCenterActive(TransInfo *t, bool select_only, float r_center[3])
        }
        else {
                /* object mode */
-               Scene *scene = t->scene;
-               Object *ob = OBACT;
-               if (ob && (!select_only || (ob->flag & SELECT))) {
+               ViewLayer *view_layer = t->view_layer;
+               Object *ob = OBACT(view_layer);
+               Base *base = BASACT(view_layer);
+               if (ob && ((!select_only) || ((base->flag & BASE_SELECTED) != 0))) {
                        copy_v3_v3(r_center, ob->obmat[3]);
                        ok = true;
                }
@@ -1870,14 +2028,13 @@ static void calculateCenter_FromAround(TransInfo *t, int around, float r_center[
 void calculateCenter(TransInfo *t)
 {
        if ((t->flag & T_OVERRIDE_CENTER) == 0) {
-               calculateCenter_FromAround(t, t->around, t->center);
+               calculateCenter_FromAround(t, t->around, t->center_global);
        }
-       calculateCenterGlobal(t, t->center, t->center_global);
+       calculateCenterLocal(t, t->center_global);
 
        /* avoid calculating again */
        {
                TransCenterData *cd = &t->center_cache[t->around];
-               copy_v3_v3(cd->local, t->center);
                copy_v3_v3(cd->global, t->center_global);
                cd->is_set = true;
        }
@@ -1895,16 +2052,15 @@ void calculateCenter(TransInfo *t)
                                normalize_v3(axis);
 
                                /* 6.0 = 6 grid units */
-                               axis[0] = t->center[0] - 6.0f * axis[0];
-                               axis[1] = t->center[1] - 6.0f * axis[1];
-                               axis[2] = t->center[2] - 6.0f * axis[2];
+                               axis[0] = t->center_global[0] - 6.0f * axis[0];
+                               axis[1] = t->center_global[1] - 6.0f * axis[1];
+                               axis[2] = t->center_global[2] - 6.0f * axis[2];
 
                                projectFloatView(t, axis, t->center2d);
 
                                /* rotate only needs correct 2d center, grab needs ED_view3d_calc_zfac() value */
                                if (t->mode == TFM_TRANSLATION) {
-                                       copy_v3_v3(t->center, axis);
-                                       copy_v3_v3(t->center_global, t->center);
+                                       copy_v3_v3(t->center_global, axis);
                                }
                        }
                }
@@ -1938,8 +2094,7 @@ const TransCenterData *transformCenter_from_type(TransInfo *t, int around)
        BLI_assert(around <= V3D_AROUND_ACTIVE);
        TransCenterData *cd = &t->center_cache[around];
        if (cd->is_set == false) {
-               calculateCenter_FromAround(t, around, cd->local);
-               calculateCenterGlobal(t, cd->local, cd->global);
+               calculateCenter_FromAround(t, around, cd->global);
                cd->is_set = true;
        }
        return cd;
@@ -1947,7 +2102,6 @@ const TransCenterData *transformCenter_from_type(TransInfo *t, int around)
 
 void calculatePropRatio(TransInfo *t)
 {
-       TransData *td = t->data;
        int i;
        float dist;
        const bool connected = (t->flag & T_PROP_CONNECTED) != 0;
@@ -1956,75 +2110,84 @@ void calculatePropRatio(TransInfo *t)
 
        if (t->flag & T_PROP_EDIT) {
                const char *pet_id = NULL;
-               for (i = 0; i < t->total; i++, td++) {
-                       if (td->flag & TD_SELECTED) {
-                               td->factor = 1.0f;
-                       }
-                       else if (t->flag & T_MIRROR && td->loc[0] * t->mirror < -0.00001f) {
-                               td->flag |= TD_SKIP;
-                               td->factor = 0.0f;
-                               restoreElement(td);
-                       }
-                       else if ((connected && (td->flag & TD_NOTCONNECTED || td->dist > t->prop_size)) ||
-                                (connected == 0 && td->rdist > t->prop_size))
-                       {
-                               /*
-                                * The elements are sorted according to their dist member in the array,
-                                * that means we can stop when it finds one element outside of the propsize.
-                                * do not set 'td->flag |= TD_NOACTION', the prop circle is being changed.
-                                */
+               FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+                       TransData *td = tc->data;
+                       for (i = 0; i < tc->data_len; i++, td++) {
+                               if (td->flag & TD_SELECTED) {
+                                       td->factor = 1.0f;
+                               }
+                               else if (t->flag & T_MIRROR && td->loc[0] * t->mirror < -0.00001f) {
+                                       td->flag |= TD_SKIP;
+                                       td->factor = 0.0f;
+                                       restoreElement(td);
+                               }
+                               else if ((connected && (td->flag & TD_NOTCONNECTED || td->dist > t->prop_size)) ||
+                                        (connected == 0 && td->rdist > t->prop_size))
+                               {
+                                       /*
+                                        * The elements are sorted according to their dist member in the array,
+                                        * that means we can stop when it finds one element outside of the propsize.
+                                        * do not set 'td->flag |= TD_NOACTION', the prop circle is being changed.
+                                        */
 
-                               td->factor = 0.0f;
-                               restoreElement(td);
-                       }
-                       else {
-                               /* Use rdist for falloff calculations, it is the real distance */
-                               td->flag &= ~TD_NOACTION;
-
-                               if (connected)
-                                       dist = (t->prop_size - td->dist) / t->prop_size;
-                               else
-                                       dist = (t->prop_size - td->rdist) / t->prop_size;
-
-                               /*
-                                * Clamp to positive numbers.
-                                * Certain corner cases with connectivity and individual centers
-                                * can give values of rdist larger than propsize.
-                                */
-                               if (dist < 0.0f)
-                                       dist = 0.0f;
+                                       td->factor = 0.0f;
+                                       restoreElement(td);
+                               }
+                               else {
+                                       /* Use rdist for falloff calculations, it is the real distance */
+                                       td->flag &= ~TD_NOACTION;
+
+                                       if (connected)
+                                               dist = (t->prop_size - td->dist) / t->prop_size;
+                                       else
+                                               dist = (t->prop_size - td->rdist) / t->prop_size;
+
+                                       /*
+                                        * Clamp to positive numbers.
+                                        * Certain corner cases with connectivity and individual centers
+                                        * can give values of rdist larger than propsize.
+                                        */
+                                       if (dist < 0.0f)
+                                               dist = 0.0f;
 
-                               switch (t->prop_mode) {
-                                       case PROP_SHARP:
-                                               td->factor = dist * dist;
-                                               break;
-                                       case PROP_SMOOTH:
-                                               td->factor = 3.0f * dist * dist - 2.0f * dist * dist * dist;
-                                               break;
-                                       case PROP_ROOT:
-                                               td->factor = sqrtf(dist);
-                                               break;
-                                       case PROP_LIN:
-                                               td->factor = dist;
-                                               break;
-                                       case PROP_CONST:
-                                               td->factor = 1.0f;
-                                               break;
-                                       case PROP_SPHERE:
-                                               td->factor = sqrtf(2 * dist - dist * dist);
-                                               break;
-                                       case PROP_RANDOM:
-                                               td->factor = BLI_frand() * dist;
-                                               break;
-                                       case PROP_INVSQUARE:
-                                               td->factor = dist * (2.0f - dist);
-                                               break;
-                                       default:
-                                               td->factor = 1;
-                                               break;
+                                       switch (t->prop_mode) {
+                                               case PROP_SHARP:
+                                                       td->factor = dist * dist;
+                                                       break;
+                                               case PROP_SMOOTH:
+                                                       td->factor = 3.0f * dist * dist - 2.0f * dist * dist * dist;
+                                                       break;
+                                               case PROP_ROOT:
+                                                       td->factor = sqrtf(dist);
+                                                       break;
+                                               case PROP_LIN:
+                                                       td->factor = dist;
+                                                       break;
+                                               case PROP_CONST:
+                                                       td->factor = 1.0f;
+                                                       break;
+                                               case PROP_SPHERE:
+                                                       td->factor = sqrtf(2 * dist - dist * dist);
+                                                       break;
+                                               case PROP_RANDOM:
+                                                       if (t->rng == NULL) {
+                                                               /* Lazy initialization. */
+                                                               uint rng_seed = (uint)(PIL_check_seconds_timer_i() & UINT_MAX);
+                                                               t->rng = BLI_rng_new(rng_seed);
+                                                       }
+                                                       td->factor = BLI_rng_get_float(t->rng) * dist;
+                                                       break;
+                                               case PROP_INVSQUARE:
+                                                       td->factor = dist * (2.0f - dist);
+                                                       break;
+                                               default:
+                                                       td->factor = 1;
+                                                       break;
+                                       }
                                }
                        }
                }
+
                switch (t->prop_mode) {
                        case PROP_SHARP:
                                pet_id = N_("(Sharp)");
@@ -2059,8 +2222,11 @@ void calculatePropRatio(TransInfo *t)
                }
        }
        else {
-               for (i = 0; i < t->total; i++, td++) {
-                       td->factor = 1.0;
+               FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+                       TransData *td = tc->data;
+                       for (i = 0; i < tc->data_len; i++, td++) {
+                               td->factor = 1.0;
+                       }
                }
        }
 }