Merge branch 'master' into blender2.8
authorBastien Montagne <montagne29@wanadoo.fr>
Sat, 9 Jun 2018 13:18:21 +0000 (15:18 +0200)
committerBastien Montagne <montagne29@wanadoo.fr>
Sat, 9 Jun 2018 13:18:21 +0000 (15:18 +0200)
Conflicts:
source/blender/editors/space_view3d/drawobject.c

12 files changed:
1  2 
source/blender/blenkernel/BKE_modifier.h
source/blender/blenkernel/intern/modifier.c
source/blender/editors/include/ED_node.h
source/blender/editors/space_node/node_draw.c
source/blender/editors/space_node/node_edit.c
source/blender/editors/space_node/node_intern.h
source/blender/editors/space_node/node_templates.c
source/blender/editors/transform/transform_conversions.c
source/blender/makesdna/DNA_ID.h
source/blender/modifiers/intern/MOD_fluidsim_util.c
source/blender/modifiers/intern/MOD_meshcache.c
source/blender/modifiers/intern/MOD_ocean.c

index b5d3e67b9700399f5ce450c5252110c2185b0ae3,e9ce91996e08e5e77a817cf6d2ae26155f1b3b2d..b40d32203f6d3c114ff938c9c83bd28510dfe061
  #include "BKE_customdata.h"
  
  struct ID;
 +struct Depsgraph;
  struct DerivedMesh;
 -struct DagForest;
 -struct DagNode;
 +struct Mesh;
  struct Object;
  struct Scene;
 +struct ViewLayer;
  struct ListBase;
  struct bArmature;
  struct Main;
@@@ -127,21 -126,19 +127,21 @@@ typedef enum ModifierApplyFlag 
                                        */
  } ModifierApplyFlag;
  
 -
  typedef struct ModifierUpdateDepsgraphContext {
        struct Scene *scene;
        struct Object *object;
 -
 -      /* Old depsgraph node handle. */
 -      struct DagForest *forest;
 -      struct DagNode *obNode;
 -
 -      /* new depsgraph node handle. */
        struct DepsNodeHandle *node;
  } ModifierUpdateDepsgraphContext;
  
 +/* Contains the information for deformXXX and applyXXX functions below that
 + * doesn't change between consecutive modifiers. */
 +typedef struct ModifierEvalContext {
 +      struct Depsgraph *depsgraph;
 +      struct Object *object;
 +      ModifierApplyFlag flag;
 +} ModifierEvalContext;
 +
 +
  typedef struct ModifierTypeInfo {
        /* The user visible name for this modifier */
        char name[32];
         */
        void (*copyData)(const struct ModifierData *md, struct ModifierData *target);
  
 -      /********************* Deform modifier functions *********************/
 +
 +      /********************* Deform modifier functions *********************/ /* DEPRECATED */
  
        /* Only for deform types, should apply the deformation
         * to the given vertex array. If the deformer requires information from
         * the object it can obtain it from the derivedData argument if non-NULL,
         * and otherwise the ob argument.
         */
 -      void (*deformVerts)(struct ModifierData *md, struct Object *ob,
 -                          struct DerivedMesh *derivedData,
 -                          float (*vertexCos)[3], int numVerts,
 -                          ModifierApplyFlag flag);
 +      void (*deformVerts_DM)(struct ModifierData *md, const struct ModifierEvalContext *ctx,
 +                             struct DerivedMesh *derivedData,
 +                             float (*vertexCos)[3], int numVerts);
  
        /* Like deformMatricesEM but called from object mode (for supporting modifiers in sculpt mode) */
 -      void (*deformMatrices)(struct ModifierData *md, struct Object *ob,
 -                             struct DerivedMesh *derivedData,
 -                             float (*vertexCos)[3], float (*defMats)[3][3], int numVerts);
 +      void (*deformMatrices_DM)(struct ModifierData *md, const struct ModifierEvalContext *ctx,
 +                                struct DerivedMesh *derivedData,
 +                                float (*vertexCos)[3], float (*defMats)[3][3], int numVerts);
  
        /* Like deformVerts but called during editmode (for supporting modifiers)
         */
 -      void (*deformVertsEM)(struct ModifierData *md, struct Object *ob,
 -                            struct BMEditMesh *editData, struct DerivedMesh *derivedData,
 -                            float (*vertexCos)[3], int numVerts);
 +      void (*deformVertsEM_DM)(struct ModifierData *md, const struct ModifierEvalContext *ctx,
 +                               struct BMEditMesh *editData,
 +                               struct DerivedMesh *derivedData,
 +                               float (*vertexCos)[3], int numVerts);
  
        /* Set deform matrix per vertex for crazyspace correction */
 -      void (*deformMatricesEM)(struct ModifierData *md, struct Object *ob,
 -                               struct BMEditMesh *editData, struct DerivedMesh *derivedData,
 +      void (*deformMatricesEM_DM)(struct ModifierData *md, const struct ModifierEvalContext *ctx,
 +                               struct BMEditMesh *editData,
 +                               struct DerivedMesh *derivedData,
                                 float (*vertexCos)[3], float (*defMats)[3][3], int numVerts);
  
 -      /********************* Non-deform modifier functions *********************/
 +      /********************* Non-deform modifier functions *********************/ /* DEPRECATED */
  
        /* For non-deform types: apply the modifier and return a derived
         * data object (type is dependent on object type).
         * should read the object data from the derived object instead of the
         * actual object data. 
         *
 -       * The useRenderParams argument indicates if the modifier is being
 -       * applied in the service of the renderer which may alter quality
 -       * settings.
 -       *
 -       * The isFinalCalc parameter indicates if the modifier is being
 -       * calculated for a final result or for something temporary
 -       * (like orcos). This is a hack at the moment, it is meant so subsurf
 -       * can know if it is safe to reuse its internal cache.
 -       *
         * The modifier may reuse the derivedData argument (i.e. return it in
         * modified form), but must not release it.
         */
 -      struct DerivedMesh *(*applyModifier)(struct ModifierData *md, struct Object *ob,
 -                                           struct DerivedMesh *derivedData,
 -                                           ModifierApplyFlag flag);
 +      struct DerivedMesh *(*applyModifier_DM)(struct ModifierData *md, const struct ModifierEvalContext *ctx,
 +                                              struct DerivedMesh *derivedData);
  
        /* Like applyModifier but called during editmode (for supporting
         * modifiers).
         * are expected from editmode objects. The same qualifications regarding
         * derivedData apply as for applyModifier.
         */
 -      struct DerivedMesh *(*applyModifierEM)(struct ModifierData *md, struct Object *ob,
 -                                             struct BMEditMesh *editData,
 -                                             struct DerivedMesh *derivedData,
 -                                             ModifierApplyFlag flag);
 +      struct DerivedMesh *(*applyModifierEM_DM)(struct ModifierData *md, const struct ModifierEvalContext *ctx,
 +                                                struct BMEditMesh *editData,
 +                                                struct DerivedMesh *derivedData);
 +
 +
 +      /********************* Deform modifier functions *********************/
 +
 +      /* Only for deform types, should apply the deformation
 +       * to the given vertex array. If the deformer requires information from
 +       * the object it can obtain it from the mesh argument if non-NULL,
 +       * and otherwise the ob argument.
 +       */
 +      void (*deformVerts)(struct ModifierData *md,  const struct ModifierEvalContext *ctx,
 +                          struct Mesh *mesh, float (*vertexCos)[3], int numVerts);
 +
 +      /* Like deformMatricesEM but called from object mode (for supporting modifiers in sculpt mode) */
 +      void (*deformMatrices)(struct ModifierData *md,  const struct ModifierEvalContext *ctx,
 +                             struct Mesh *mesh, float (*vertexCos)[3], float (*defMats)[3][3], int numVerts);
 +
 +      /* Like deformVerts but called during editmode (for supporting modifiers)
 +       */
 +      void (*deformVertsEM)(struct ModifierData *md,  const struct ModifierEvalContext *ctx,
 +                            struct BMEditMesh *editData,
 +                            struct Mesh *mesh, float (*vertexCos)[3], int numVerts);
 +
 +      /* Set deform matrix per vertex for crazyspace correction */
 +      void (*deformMatricesEM)(struct ModifierData *md,  const struct ModifierEvalContext *ctx,
 +                               struct BMEditMesh *editData,
 +                               struct Mesh *mesh, float (*vertexCos)[3], float (*defMats)[3][3], int numVerts);
 +
 +      /********************* Non-deform modifier functions *********************/
 +
 +      /* For non-deform types: apply the modifier and return a mesh object.
 +       *
 +       * The mesh argument should always be non-NULL; the modifier
 +       * should read the object data from the mesh object instead of the
 +       * actual object data. 
 +       *
 +       * The modifier may reuse the mesh argument (i.e. return it in
 +       * modified form), but must not release it.
 +       */
 +      struct Mesh *(*applyModifier)(struct ModifierData *md, const struct ModifierEvalContext *ctx,
 +                                    struct Mesh *mesh);
 +
 +      /* Like applyModifier but called during editmode (for supporting
 +       * modifiers).
 +       * 
 +       * The mesh object that is returned must support the operations that
 +       * are expected from editmode objects. The same qualifications regarding
 +       * mesh apply as for applyModifier.
 +       */
 +      struct Mesh *(*applyModifierEM)(struct ModifierData *md, const struct ModifierEvalContext *ctx,
 +                                      struct BMEditMesh *editData,
 +                                      struct Mesh *mesh);
  
  
        /********************* Optional functions *********************/
         */
        bool (*isDisabled)(struct ModifierData *md, int userRenderParams);
  
 -      /* Add the appropriate relations to the DEP graph depending on the
 -       * modifier data. 
 -       *
 -       * This function is optional.
 -       */
 -      void (*updateDepgraph)(struct ModifierData *md,
 -                             const ModifierUpdateDepsgraphContext *ctx);
 -
        /* Add the appropriate relations to the dependency graph.
         *
         * This function is optional.
         */
 -      /* TODO(sergey): Remove once we finally switched to the new depsgraph. */
        void (*updateDepsgraph)(struct ModifierData *md,
                                const ModifierUpdateDepsgraphContext *ctx);
 -
 + 
        /* Should return true if the modifier needs to be recalculated on time
         * changes.
         *
@@@ -423,7 -387,6 +423,7 @@@ bool          modifiers_isClothEnabled(
  bool          modifiers_isParticleEnabled(struct Object *ob);
  
  struct Object *modifiers_isDeformedByArmature(struct Object *ob);
 +struct Object *modifiers_isDeformedByMeshDeform(struct Object *ob);
  struct Object *modifiers_isDeformedByLattice(struct Object *ob);
  struct Object *modifiers_isDeformedByCurve(struct Object *ob);
  bool          modifiers_usesArmature(struct Object *ob, struct bArmature *arm);
@@@ -468,97 -431,31 +468,97 @@@ void modifier_mdef_compact_influences(s
  
  void        modifier_path_init(char *path, int path_maxlen, const char *name);
  const char *modifier_path_relbase(struct Main *bmain, struct Object *ob);
+ const char *modifier_path_relbase_from_global(struct Object *ob);
  
 -/* wrappers for modifier callbacks */
 +/* wrappers for modifier callbacks that ensure valid normals */
  
  struct DerivedMesh *modwrap_applyModifier(
 -        ModifierData *md, struct Object *ob,
 -        struct DerivedMesh *dm,
 -        ModifierApplyFlag flag);
 +        ModifierData *md, const struct ModifierEvalContext *ctx,
 +        struct DerivedMesh *dm);
  
  struct DerivedMesh *modwrap_applyModifierEM(
 -        ModifierData *md, struct Object *ob,
 -        struct BMEditMesh *em,
 -        struct DerivedMesh *dm,
 -        ModifierApplyFlag flag);
 +        ModifierData *md, const struct ModifierEvalContext *ctx,
 +        struct BMEditMesh *em, struct DerivedMesh *dm);
  
  void modwrap_deformVerts(
 -        ModifierData *md, struct Object *ob,
 +        ModifierData *md, const struct ModifierEvalContext *ctx,
          struct DerivedMesh *dm,
 -        float (*vertexCos)[3], int numVerts,
 -        ModifierApplyFlag flag);
 +        float (*vertexCos)[3], int numVerts);
  
  void modwrap_deformVertsEM(
 -        ModifierData *md, struct Object *ob,
 +        ModifierData *md, const struct ModifierEvalContext *ctx,
          struct BMEditMesh *em, struct DerivedMesh *dm,
          float (*vertexCos)[3], int numVerts);
  
 +/* wrappers for modifier callbacks that accept Mesh and select the proper implementation
 + * depending on if the modifier has been ported to Mesh or is still using DerivedMesh
 + */
 +
 +void modifier_deformVerts(
 +        struct ModifierData *md, const struct ModifierEvalContext *ctx,
 +        struct Mesh *mesh, float (*vertexCos)[3], int numVerts);
 +
 +void modifier_deformVerts_ensure_normals(
 +        struct ModifierData *md, const struct ModifierEvalContext *ctx,
 +        struct Mesh *mesh, float (*vertexCos)[3], int numVerts);
 +
 +void modifier_deformMatrices(
 +        struct ModifierData *md, const struct ModifierEvalContext *ctx,
 +        struct Mesh *mesh, float (*vertexCos)[3], float (*defMats)[3][3], int numVerts);
 +
 +void modifier_deformVertsEM(
 +        struct ModifierData *md, const struct ModifierEvalContext *ctx,
 +        struct BMEditMesh *editData, struct Mesh *mesh,
 +        float (*vertexCos)[3], int numVerts);
 +
 +void modifier_deformMatricesEM(
 +        struct ModifierData *md, const struct ModifierEvalContext *ctx,
 +        struct BMEditMesh *editData, struct Mesh *mesh,
 +        float (*vertexCos)[3], float (*defMats)[3][3], int numVerts);
 +
 +struct Mesh *modifier_applyModifier(
 +        struct ModifierData *md, const struct ModifierEvalContext *ctx,
 +        struct Mesh *mesh);
 +
 +struct Mesh *modifier_applyModifier_ensure_normals(
 +        struct ModifierData *md, const struct ModifierEvalContext *ctx,
 +        struct Mesh *mesh);
 +
 +struct Mesh *modifier_applyModifierEM(
 +        struct ModifierData *md, const struct ModifierEvalContext *ctx,
 +        struct BMEditMesh *editData, struct Mesh *mesh);
 +
 +/* depricated variants of above that accept DerivedMesh */
 +
 +void modifier_deformVerts_DM_deprecated(
 +        struct ModifierData *md, const struct ModifierEvalContext *ctx,
 +        struct DerivedMesh *dm, float (*vertexCos)[3], int numVerts);
 +
 +void modifier_deformMatrices_DM_deprecated(
 +        struct ModifierData *md, const struct ModifierEvalContext *ctx,
 +        struct DerivedMesh *dm,
 +        float (*vertexCos)[3], float (*defMats)[3][3], int numVerts);
 +
 +void modifier_deformVertsEM_DM_deprecated(
 +        struct ModifierData *md, const struct ModifierEvalContext *ctx,
 +        struct BMEditMesh *editData, struct DerivedMesh *dm,
 +        float (*vertexCos)[3], int numVerts);
 +
 +void modifier_deformMatricesEM_DM_deprecated(
 +        struct ModifierData *md, const struct ModifierEvalContext *ctx,
 +        struct BMEditMesh *editData, struct DerivedMesh *dm,
 +        float (*vertexCos)[3], float (*defMats)[3][3], int numVerts);
 +
 +struct DerivedMesh *modifier_applyModifier_DM_deprecated(
 +        struct ModifierData *md, const struct ModifierEvalContext *ctx,
 +        struct DerivedMesh *dm);
 +
 +struct DerivedMesh *modifier_applyModifierEM_DM_deprecated(
 +        struct ModifierData *md, const struct ModifierEvalContext *ctx,
 +        struct BMEditMesh *editData, struct DerivedMesh *dm);
 +
 +struct Mesh *BKE_modifier_get_evaluated_mesh_from_evaluated_object(
 +        struct Object *ob_eval, bool *r_free_mesh);
 +
  #endif
  
index bd9cd6845482108b6ca5399293332784c6a72cc1,368a691e77895b436f934fe8c0dd223f7b16cd0e..0b904caf375ddbea4a6ae0fc42a455c5d524d556
@@@ -46,7 -46,6 +46,7 @@@
  #include "MEM_guardedalloc.h"
  
  #include "DNA_armature_types.h"
 +#include "DNA_mesh_types.h"
  #include "DNA_object_types.h"
  
  #include "BLI_utildefines.h"
  #include "BLT_translation.h"
  
  #include "BKE_appdir.h"
 +#include "BKE_cdderivedmesh.h"
 +#include "BKE_editmesh.h"
  #include "BKE_global.h"
 +#include "BKE_idcode.h"
  #include "BKE_key.h"
  #include "BKE_library.h"
  #include "BKE_library_query.h"
 +#include "BKE_mesh.h"
  #include "BKE_multires.h"
 +#include "BKE_object.h"
  #include "BKE_DerivedMesh.h"
  
  /* may move these, only for modifier_path_relbase */
  #include "BKE_main.h"
  /* end */
  
 +#include "DEG_depsgraph.h"
 +#include "DEG_depsgraph_query.h"
 +
  #include "MOD_modifiertypes.h"
  
  static ModifierTypeInfo *modifier_types[NUM_MODIFIER_TYPES] = {NULL};
@@@ -136,7 -127,6 +136,7 @@@ ModifierData *modifier_new(int type
  
        md->type = type;
        md->mode = eModifierMode_Realtime | eModifierMode_Render | eModifierMode_Expanded;
 +      md->flag = eModifierFlag_StaticOverride_Local;
  
        if (mti->flags & eModifierTypeFlag_EnableInEditmode)
                md->mode |= eModifierMode_Editmode;
@@@ -323,7 -313,6 +323,7 @@@ void modifier_copyData_ex(ModifierData 
        const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
  
        target->mode = md->mode;
 +      target->flag = md->flag;
  
        if (mti->copyData) {
                mti->copyData(md, target);
@@@ -630,27 -619,6 +630,27 @@@ Object *modifiers_isDeformedByArmature(
        return NULL;
  }
  
 +Object *modifiers_isDeformedByMeshDeform(Object *ob)
 +{
 +      VirtualModifierData virtualModifierData;
 +      ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
 +      MeshDeformModifierData *mdmd = NULL;
 +
 +      /* return the first selected armature, this lets us use multiple armatures */
 +      for (; md; md = md->next) {
 +              if (md->type == eModifierType_MeshDeform) {
 +                      mdmd = (MeshDeformModifierData *) md;
 +                      if (mdmd->object && (mdmd->object->flag & SELECT))
 +                              return mdmd->object;
 +              }
 +      }
 +
 +      if (mdmd) /* if were still here then return the last armature */
 +              return mdmd->object;
 +
 +      return NULL;
 +}
 +
  /* Takes an object and returns its first selected lattice, else just its lattice
   * This should work for multiple lattices per object
   */
@@@ -718,7 -686,7 +718,7 @@@ bool modifiers_usesArmature(Object *ob
  bool modifier_isCorrectableDeformed(ModifierData *md)
  {
        const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
 -      return (mti->deformMatricesEM != NULL);
 +      return (mti->deformMatricesEM != NULL) || (mti->deformMatricesEM_DM != NULL);
  }
  
  bool modifiers_isCorrectableDeformed(struct Scene *scene, Object *ob)
        ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
        int required_mode = eModifierMode_Realtime;
  
 -      if (ob->mode == OB_MODE_EDIT)
 +      if (ob->mode == OB_MODE_EDIT) {
                required_mode |= eModifierMode_Editmode;
 -      
 +      }
        for (; md; md = md->next) {
                if (!modifier_isEnabled(scene, md, required_mode)) {
                        /* pass */
@@@ -809,6 -777,18 +809,18 @@@ const char *modifier_path_relbase(Main 
        }
  }
  
+ const char *modifier_path_relbase_from_global(Object *ob)
+ {
+       if (G.relbase_valid || ID_IS_LINKED(ob)) {
+               return ID_BLEND_PATH_FROM_GLOBAL(&ob->id);
+       }
+       else {
+               /* last resort, better then using "" which resolves to the current
+                * working directory */
+               return BKE_tempdir_session();
+       }
+ }
  /* initializes the path with either */
  void modifier_path_init(char *path, int path_maxlen, const char *name)
  {
  /* wrapper around ModifierTypeInfo.applyModifier that ensures valid normals */
  
  struct DerivedMesh *modwrap_applyModifier(
 -        ModifierData *md, Object *ob,
 -        struct DerivedMesh *dm,
 -        ModifierApplyFlag flag)
 +        ModifierData *md, const ModifierEvalContext *ctx,
 +        struct DerivedMesh *dm)
  {
        const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
        BLI_assert(CustomData_has_layer(&dm->polyData, CD_NORMAL) == false);
        if (mti->dependsOnNormals && mti->dependsOnNormals(md)) {
                DM_ensure_normals(dm);
        }
 -      return mti->applyModifier(md, ob, dm, flag);
 +      return modifier_applyModifier_DM_deprecated(md, ctx, dm);
  }
  
  struct DerivedMesh *modwrap_applyModifierEM(
 -        ModifierData *md, Object *ob,
 -        struct BMEditMesh *em,
 -        DerivedMesh *dm,
 -        ModifierApplyFlag flag)
 +        ModifierData *md, const ModifierEvalContext *ctx,
 +        struct BMEditMesh *em, DerivedMesh *dm)
  {
        const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
        BLI_assert(CustomData_has_layer(&dm->polyData, CD_NORMAL) == false);
        if (mti->dependsOnNormals && mti->dependsOnNormals(md)) {
                DM_ensure_normals(dm);
        }
 -      return mti->applyModifierEM(md, ob, em, dm, flag);
 +      return modifier_applyModifierEM_DM_deprecated(md, ctx, em, dm);
  }
  
  void modwrap_deformVerts(
 -        ModifierData *md, Object *ob,
 -        DerivedMesh *dm,
 -        float (*vertexCos)[3], int numVerts,
 -        ModifierApplyFlag flag)
 +        ModifierData *md, const ModifierEvalContext *ctx,
 +        DerivedMesh *dm, float (*vertexCos)[3], int numVerts)
  {
        const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
        BLI_assert(!dm || CustomData_has_layer(&dm->polyData, CD_NORMAL) == false);
        if (dm && mti->dependsOnNormals && mti->dependsOnNormals(md)) {
                DM_ensure_normals(dm);
        }
 -      mti->deformVerts(md, ob, dm, vertexCos, numVerts, flag);
 +      modifier_deformVerts_DM_deprecated(md, ctx, dm, vertexCos, numVerts);
  }
  
  void modwrap_deformVertsEM(
 -        ModifierData *md, Object *ob,
 +        ModifierData *md, const ModifierEvalContext *ctx,
          struct BMEditMesh *em, DerivedMesh *dm,
          float (*vertexCos)[3], int numVerts)
  {
        if (dm && mti->dependsOnNormals && mti->dependsOnNormals(md)) {
                DM_ensure_normals(dm);
        }
 -      mti->deformVertsEM(md, ob, em, dm, vertexCos, numVerts);
 +      modifier_deformVertsEM_DM_deprecated(md, ctx, em, dm, vertexCos, numVerts);
  }
  /* end modifier callback wrappers */
 +
 +
 +/* wrappers for modifier callbacks that accept Mesh and select the proper implementation
 + * depending on if the modifier has been ported to Mesh or is still using DerivedMesh
 + */
 +
 +void modifier_deformVerts(struct ModifierData *md, const ModifierEvalContext *ctx,
 +      struct Mesh *mesh,
 +      float (*vertexCos)[3], int numVerts)
 +{
 +      const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
 +
 +      if (mti->deformVerts) {
 +              mti->deformVerts(md, ctx, mesh, vertexCos, numVerts);
 +      }
 +      else {
 +              DerivedMesh *dm = NULL;
 +              if (mesh) {
 +                      dm = CDDM_from_mesh_ex(mesh, CD_REFERENCE, CD_MASK_EVERYTHING);
 +              }
 +
 +              mti->deformVerts_DM(md, ctx, dm, vertexCos, numVerts);
 +
 +              if (dm) {
 +                      dm->release(dm);
 +              }
 +      }
 +}
 +
 +void modifier_deformVerts_ensure_normals(struct ModifierData *md, const ModifierEvalContext *ctx,
 +      struct Mesh *mesh,
 +      float (*vertexCos)[3], int numVerts)
 +{
 +      const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
 +      BLI_assert(!mesh || CustomData_has_layer(&mesh->pdata, CD_NORMAL) == false);
 +
 +      if (mesh && mti->dependsOnNormals && mti->dependsOnNormals(md)) {
 +              BKE_mesh_calc_normals(mesh);
 +      }
 +      modifier_deformVerts(md, ctx, mesh, vertexCos, numVerts);
 +}
 +
 +void modifier_deformMatrices(struct ModifierData *md, const ModifierEvalContext *ctx,
 +      struct Mesh *mesh,
 +      float (*vertexCos)[3], float (*defMats)[3][3], int numVerts)
 +{
 +      const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
 +
 +      if (mti->deformMatrices) {
 +              mti->deformMatrices(md, ctx, mesh, vertexCos, defMats, numVerts);
 +      }
 +      else {
 +              DerivedMesh *dm = NULL;
 +              if (mesh) {
 +                      dm = CDDM_from_mesh_ex(mesh, CD_REFERENCE, CD_MASK_EVERYTHING);
 +              }
 +
 +              mti->deformMatrices_DM(md, ctx, dm, vertexCos, defMats, numVerts);
 +
 +              if (dm) {
 +                      dm->release(dm);
 +              }
 +      }
 +}
 +
 +void modifier_deformVertsEM(struct ModifierData *md, const ModifierEvalContext *ctx,
 +      struct BMEditMesh *editData, struct Mesh *mesh,
 +      float (*vertexCos)[3], int numVerts)
 +{
 +      const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
 +
 +      if (mti->deformVertsEM) {
 +              mti->deformVertsEM(md, ctx, editData, mesh, vertexCos, numVerts);
 +      }
 +      else {
 +              DerivedMesh *dm = NULL;
 +              if (mesh) {
 +                      dm = CDDM_from_mesh_ex(mesh, CD_REFERENCE, CD_MASK_EVERYTHING);
 +              }
 +
 +              mti->deformVertsEM_DM(md, ctx, editData, dm, vertexCos, numVerts);
 +
 +              if (dm) {
 +                      dm->release(dm);
 +              }
 +      }
 +}
 +
 +void modifier_deformMatricesEM(struct ModifierData *md, const ModifierEvalContext *ctx,
 +      struct BMEditMesh *editData, struct Mesh *mesh,
 +      float (*vertexCos)[3], float (*defMats)[3][3], int numVerts)
 +{
 +      const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
 +
 +      if (mti->deformMatricesEM) {
 +              mti->deformMatricesEM(md, ctx, editData, mesh, vertexCos, defMats, numVerts);
 +      }
 +      else {
 +              DerivedMesh *dm = NULL;
 +              if (mesh) {
 +                      dm = CDDM_from_mesh_ex(mesh, CD_REFERENCE, CD_MASK_EVERYTHING);
 +              }
 +
 +              mti->deformMatricesEM_DM(md, ctx, editData, dm, vertexCos, defMats, numVerts);
 +
 +              if (dm) {
 +                      dm->release(dm);
 +              }
 +      }
 +}
 +
 +struct Mesh *modifier_applyModifier(struct ModifierData *md, const ModifierEvalContext *ctx,
 +      struct Mesh *mesh)
 +{
 +      const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
 +
 +      if (mti->applyModifier) {
 +              return mti->applyModifier(md, ctx, mesh);
 +      }
 +      else {
 +              DerivedMesh *dm = CDDM_from_mesh_ex(mesh, CD_REFERENCE, CD_MASK_EVERYTHING);
 +
 +              DerivedMesh *ndm = mti->applyModifier_DM(md, ctx, dm);
 +
 +              if (ndm != dm) {
 +                      dm->release(dm);
 +              }
 +
 +              DM_to_mesh(ndm, mesh, ctx->object, CD_MASK_EVERYTHING, true);
 +
 +              return mesh;
 +      }
 +}
 +
 +struct Mesh *modifier_applyModifier_ensure_normals(struct ModifierData *md, const ModifierEvalContext *ctx,
 +      struct Mesh *mesh)
 +{
 +      const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
 +      BLI_assert(CustomData_has_layer(&mesh->pdata, CD_NORMAL) == false);
 +
 +      if (mti->dependsOnNormals && mti->dependsOnNormals(md)) {
 +              BKE_mesh_calc_normals(mesh);
 +      }
 +      return modifier_applyModifier(md, ctx, mesh);
 +}
 +
 +struct Mesh *modifier_applyModifierEM(struct ModifierData *md, const ModifierEvalContext *ctx,
 +      struct BMEditMesh *editData,
 +      struct Mesh *mesh)
 +{
 +      const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
 +
 +      if (mti->applyModifierEM) {
 +              return mti->applyModifierEM(md, ctx, editData, mesh);
 +      }
 +      else {
 +              DerivedMesh *dm = CDDM_from_mesh_ex(mesh, CD_REFERENCE, CD_MASK_EVERYTHING);
 +
 +              DerivedMesh *ndm = mti->applyModifierEM_DM(md, ctx, editData, dm);
 +
 +              if (ndm != dm) {
 +                      dm->release(dm);
 +              }
 +
 +              DM_to_mesh(ndm, mesh, ctx->object, CD_MASK_EVERYTHING, true);
 +
 +              return mesh;
 +      }
 +}
 +
 +/* depricated variants of above that accept DerivedMesh */
 +
 +void modifier_deformVerts_DM_deprecated(struct ModifierData *md, const ModifierEvalContext *ctx,
 +      struct DerivedMesh *dm,
 +      float (*vertexCos)[3], int numVerts)
 +{
 +      const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
 +
 +      if (mti->deformVerts_DM) {
 +              mti->deformVerts_DM(md, ctx, dm, vertexCos, numVerts);
 +      }
 +      else {
 +              /* TODO(sybren): deduplicate all the copies of this code in this file. */
 +              Mesh *mesh = NULL;
 +              if (dm != NULL) {
 +                      mesh = BKE_id_new_nomain(ID_ME, NULL);
 +                      DM_to_mesh(dm, mesh, ctx->object, CD_MASK_EVERYTHING, false);
 +              }
 +
 +              mti->deformVerts(md, ctx, mesh, vertexCos, numVerts);
 +
 +              if (mesh != NULL) {
 +                      BKE_id_free(NULL, mesh);
 +              }
 +      }
 +}
 +
 +void modifier_deformMatrices_DM_deprecated(struct ModifierData *md, const ModifierEvalContext *ctx,
 +      struct DerivedMesh *dm,
 +      float (*vertexCos)[3], float (*defMats)[3][3], int numVerts)
 +{
 +
 +      const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
 +
 +      if (mti->deformMatrices_DM) {
 +              mti->deformMatrices_DM(md, ctx, dm, vertexCos, defMats, numVerts);
 +      }
 +      else {
 +              /* TODO(sybren): deduplicate all the copies of this code in this file. */
 +              Mesh *mesh = NULL;
 +              if (dm != NULL) {
 +                      mesh = BKE_id_new_nomain(ID_ME, NULL);
 +                      DM_to_mesh(dm, mesh, ctx->object, CD_MASK_EVERYTHING, false);
 +              }
 +
 +              mti->deformMatrices(md, ctx, mesh, vertexCos, defMats, numVerts);
 +
 +              if (mesh != NULL) {
 +                      BKE_id_free(NULL, mesh);
 +              }
 +      }
 +}
 +
 +void modifier_deformVertsEM_DM_deprecated(struct ModifierData *md, const ModifierEvalContext *ctx,
 +      struct BMEditMesh *editData, struct DerivedMesh *dm,
 +      float (*vertexCos)[3], int numVerts)
 +{
 +      const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
 +
 +      if (mti->deformVertsEM_DM) {
 +              mti->deformVertsEM_DM(md, ctx, editData, dm, vertexCos, numVerts);
 +      }
 +      else {
 +              /* TODO(sybren): deduplicate all the copies of this code in this file. */
 +              Mesh *mesh = NULL;
 +              if (dm != NULL) {
 +                      mesh = BKE_id_new_nomain(ID_ME, NULL);
 +                      DM_to_mesh(dm, mesh, ctx->object, CD_MASK_EVERYTHING, false);
 +              }
 +
 +              mti->deformVertsEM(md, ctx, editData, mesh, vertexCos, numVerts);
 +
 +              if (mesh != NULL) {
 +                      BKE_id_free(NULL, mesh);
 +              }
 +      }
 +}
 +
 +void modifier_deformMatricesEM_DM_deprecated(struct ModifierData *md, const ModifierEvalContext *ctx,
 +      struct BMEditMesh *editData, struct DerivedMesh *dm,
 +      float (*vertexCos)[3], float (*defMats)[3][3], int numVerts)
 +{
 +      const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
 +
 +      if (mti->deformMatricesEM_DM) {
 +              mti->deformMatricesEM_DM(md, ctx, editData, dm, vertexCos, defMats, numVerts);
 +      }
 +      else {
 +              /* TODO(sybren): deduplicate all the copies of this code in this file. */
 +              Mesh *mesh = NULL;
 +              if (dm != NULL) {
 +                      mesh = BKE_id_new_nomain(ID_ME, NULL);
 +                      DM_to_mesh(dm, mesh, ctx->object, CD_MASK_EVERYTHING, false);
 +              }
 +
 +              mti->deformMatricesEM(md, ctx, editData, mesh, vertexCos, defMats, numVerts);
 +
 +              if (mesh != NULL) {
 +                      BKE_id_free(NULL, mesh);
 +              }
 +      }
 +}
 +
 +struct DerivedMesh *modifier_applyModifier_DM_deprecated(struct ModifierData *md, const ModifierEvalContext *ctx,
 +      struct DerivedMesh *dm)
 +{
 +      const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
 +
 +      if (mti->applyModifier_DM) {
 +              return mti->applyModifier_DM(md, ctx, dm);
 +      }
 +      else {
 +              /* TODO(sybren): deduplicate all the copies of this code in this file. */
 +              Mesh *mesh = NULL;
 +              if (dm != NULL) {
 +                      mesh = BKE_id_new_nomain(ID_ME, NULL);
 +                      DM_to_mesh(dm, mesh, ctx->object, CD_MASK_EVERYTHING, false);
 +              }
 +
 +              struct Mesh *new_mesh = mti->applyModifier(md, ctx, mesh);
 +
 +              /* Make a DM that doesn't reference new_mesh so we can free the latter. */
 +              DerivedMesh *ndm = CDDM_from_mesh_ex(new_mesh, CD_DUPLICATE, CD_MASK_EVERYTHING);
 +
 +              if (new_mesh != mesh) {
 +                      BKE_id_free(NULL, new_mesh);
 +              }
 +              if (mesh != NULL) {
 +                      BKE_id_free(NULL, mesh);
 +              }
 +
 +              return ndm;
 +      }
 +}
 +
 +struct DerivedMesh *modifier_applyModifierEM_DM_deprecated(struct ModifierData *md, const ModifierEvalContext *ctx,
 +      struct BMEditMesh *editData,
 +      struct DerivedMesh *dm)
 +{
 +      const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
 +
 +      if (mti->applyModifierEM_DM) {
 +              return mti->applyModifierEM_DM(md, ctx, editData, dm);
 +      }
 +      else {
 +              /* TODO(sybren): deduplicate all the copies of this code in this file. */
 +              Mesh *mesh = NULL;
 +              if (dm != NULL) {
 +                      mesh = BKE_id_new_nomain(ID_ME, NULL);
 +                      DM_to_mesh(dm, mesh, ctx->object, CD_MASK_EVERYTHING, false);
 +              }
 +
 +              struct Mesh *new_mesh = mti->applyModifierEM(md, ctx, editData, mesh);
 +
 +              /* Make a DM that doesn't reference new_mesh so we can free the latter. */
 +              DerivedMesh *ndm = CDDM_from_mesh_ex(new_mesh, CD_DUPLICATE, CD_MASK_EVERYTHING);
 +
 +              if (new_mesh != mesh) {
 +                      BKE_id_free(NULL, new_mesh);
 +              }
 +              if (mesh != NULL) {
 +                      BKE_id_free(NULL, mesh);
 +              }
 +
 +              return ndm;
 +      }
 +}
 +
 +/**
 + * Get evaluated mesh for other evaluated object, which is used as an operand for the modifier,
 + * e.g. second operand for boolean modifier.
 + * Note thqt modifiers in stack always get fully evaluated COW ID pointers, never original ones. Makes things simpler.
 + */
 +Mesh *BKE_modifier_get_evaluated_mesh_from_evaluated_object(Object *ob_eval, bool *r_free_mesh)
 +{
 +      Mesh *me;
 +
 +      if ((ob_eval->type == OB_MESH) && (ob_eval->mode & OB_MODE_EDIT)) {
 +              /* Note: currently we have no equivalent to derived cagemesh or even final dm in BMEditMesh...
 +               * This is TODO in core depsgraph/modifier stack code still. */
 +              BMEditMesh *em = BKE_editmesh_from_object(ob_eval);
 +              me = BKE_bmesh_to_mesh_nomain(em->bm, &(struct BMeshToMeshParams){0});
 +              *r_free_mesh = true;
 +      }
 +      else {
 +              me = ob_eval->runtime.mesh_eval;
 +              *r_free_mesh = false;
 +      }
 +
 +      return me;
 +}
index 6828cedbd80c7e05ed9175119d2741ee7d8e5656,c8e89afc18aa61f6e129f4e52fdf2789b9d63854..f959b7f53ba8025b88f3bfffcbfd3bc669850fa3
@@@ -75,7 -75,7 +75,7 @@@ void ED_init_custom_node_socket_type(st
  void ED_init_standard_node_socket_type(struct bNodeSocketType *stype);
  void ED_init_node_socket_type_virtual(struct bNodeSocketType *stype);
  void ED_node_sample_set(const float col[4]);
 -void ED_node_draw_snap(struct View2D *v2d, const float cent[2], float size, NodeBorder border);
 +void ED_node_draw_snap(struct View2D *v2d, const float cent[2], float size, NodeBorder border, unsigned pos);
  
  /* node_draw.c */
  void ED_node_tree_update(const struct bContext *C);
@@@ -86,7 -86,7 +86,7 @@@ float ED_node_grid_size(void)
  
  /* node_relationships.c */
  void ED_node_link_intersect_test(struct ScrArea *sa, int test);
- void ED_node_link_insert(struct ScrArea *sa);
+ void ED_node_link_insert(struct Main *bmain, struct ScrArea *sa);
  
  /* node_edit.c */
  void ED_node_set_tree_type(struct SpaceNode *snode, struct bNodeTreeType *typeinfo);
index 92c055ed12ab7072237dcedf9073ca8ff26e33de,3b6a227d124f4fc353d6b854c108dcf3c32ff972..8089f47bce48d84a503046512846add86c3064b7
  #include "BLT_translation.h"
  
  #include "BKE_context.h"
 -#include "BKE_depsgraph.h"
  #include "BKE_library.h"
  #include "BKE_main.h"
  #include "BKE_node.h"
  
 +#include "DEG_depsgraph.h"
 +
  #include "BLF_api.h"
  
 -#include "BIF_gl.h"
  #include "BIF_glutil.h"
  
 +#include "GPU_draw.h"
 +#include "GPU_immediate.h"
 +#include "GPU_immediate_util.h"
 +#include "GPU_matrix.h"
 +
  #include "WM_api.h"
  #include "WM_types.h"
  
@@@ -133,10 -128,10 +133,10 @@@ void ED_node_tag_update_id(ID *id
         * all the users of this tree will have update
         * flushed from the tree,
         */
 -      DAG_id_tag_update(&ntree->id, 0);
 +      DEG_id_tag_update(&ntree->id, 0);
  
        if (ntree->type == NTREE_SHADER) {
 -              DAG_id_tag_update(id, 0);
 +              DEG_id_tag_update(id, 0);
  
                if (GS(id->name) == ID_MA)
                        WM_main_add_notifier(NC_MATERIAL | ND_SHADING, id);
                WM_main_add_notifier(NC_SCENE | ND_NODES, id);
        }
        else if (ntree->type == NTREE_TEXTURE) {
 -              DAG_id_tag_update(id, 0);
 +              DEG_id_tag_update(id, 0);
                WM_main_add_notifier(NC_TEXTURE | ND_NODES, id);
        }
        else if (id == &ntree->id) {
                /* node groups */
 -              DAG_id_tag_update(id, 0);
 +              DEG_id_tag_update(id, 0);
        }
  }
  
@@@ -165,7 -160,7 +165,7 @@@ void ED_node_tag_update_nodetree(Main *
  
        bool do_tag_update = true;
        if (node != NULL) {
-               if (!node_connected_to_output(ntree, node)) {
+               if (!node_connected_to_output(bmain, ntree, node)) {
                        do_tag_update = false;
                }
        }
@@@ -621,23 -616,112 +621,23 @@@ static void node_draw_mute_line(View2D 
        bNodeLink *link;
  
        glEnable(GL_BLEND);
 -      glEnable(GL_LINE_SMOOTH);
  
        for (link = node->internal_links.first; link; link = link->next)
 -              node_draw_link_bezier(v2d, snode, link, TH_REDALERT, 0, TH_WIRE, 0, TH_WIRE);
 -
 -      glDisable(GL_BLEND);
 -      glDisable(GL_LINE_SMOOTH);
 -}
 -
 -static void node_socket_shape_draw(
 -        float x, float y, float size, const float col[4], bool highlight,
 -        const float coords[][2], int coords_len)
 -{
 -      int a;
 -
 -      glColor4fv(col);
 -
 -      glEnable(GL_BLEND);
 -      glBegin(GL_POLYGON);
 -      for (a = 0; a < coords_len; a++) {
 -              glVertex2f(x + size * coords[a][0], y + size * coords[a][1]);
 -      }
 -      glEnd();
 -      glDisable(GL_BLEND);
 +              node_draw_link_bezier(v2d, snode, link, TH_REDALERT, TH_REDALERT, -1);
  
 -      if (highlight) {
 -              UI_ThemeColor(TH_TEXT_HI);
 -              glLineWidth(1.5f);
 -      }
 -      else {
 -              glColor4ub(0, 0, 0, 150);
 -      }
 -      glEnable(GL_BLEND);
 -      glEnable(GL_LINE_SMOOTH);
 -      glBegin(GL_LINE_LOOP);
 -      for (a = 0; a < coords_len; a++) {
 -              glVertex2f(x + size * coords[a][0], y + size * coords[a][1]);
 -      }
 -      glEnd();
 -      glDisable(GL_LINE_SMOOTH);
        glDisable(GL_BLEND);
  }
  
 -
 -void node_socket_draw(const bContext *C, bNodeTree *ntree, bNode *node, bNodeSocket *sock, float size, bool highlight)
 +static void node_socket_circle_draw(const bContext *C, bNodeTree *ntree, PointerRNA node_ptr, bNodeSocket *sock, unsigned pos, unsigned col)
  {
 -      PointerRNA ptr, node_ptr;
 +      PointerRNA ptr;
        float color[4];
  
        RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &ptr);
 -      RNA_pointer_create((ID *)ntree, &RNA_Node, node, &node_ptr);
        sock->typeinfo->draw_color((bContext *)C, &ptr, &node_ptr, color);
  
 -      /* 16 values of {sin, cos} function */
 -      const float shape_circle[16][2] = {
 -              {0.00000000f, 1.00000000f},
 -              {0.39435585f, 0.91895781f},
 -              {0.72479278f, 0.68896691f},
 -              {0.93775213f, 0.34730525f},
 -              {0.99871650f, -0.05064916f},
 -              {0.89780453f, -0.44039415f},
 -              {0.65137248f, -0.75875812f},
 -              {0.29936312f, -0.95413925f},
 -              {-0.10116832f, -0.99486932f},
 -              {-0.48530196f, -0.87434661f},
 -              {-0.79077573f, -0.61210598f},
 -              {-0.96807711f, -0.25065253f},
 -              {-0.98846832f, 0.15142777f},
 -              {-0.84864425f, 0.52896401f},
 -              {-0.57126821f, 0.82076344f},
 -              {-0.20129852f, 0.97952994f }
 -      };
 -
 -      const float shape_diamond[4][2] = {
 -              {0.0f, 1.2f},
 -              {1.2f, 0.0f},
 -              {0.0f, -1.2f},
 -              {-1.2f, 0.0f},
 -      };
 -
 -      const float shape_square[4][2] = {
 -              {-0.9f, 0.9f},
 -              {0.9f, 0.9f},
 -              {0.9f, -0.9f},
 -              {-0.9f, -0.9f},
 -      };
 -
 -      const float (*shape)[2];
 -      int shape_len;
 -      switch (sock->draw_shape) {
 -              default:
 -              case SOCK_DRAW_SHAPE_CIRCLE:
 -                      shape = shape_circle;
 -                      shape_len = ARRAY_SIZE(shape_circle);
 -                      break;
 -              case SOCK_DRAW_SHAPE_DIAMOND:
 -                      shape = shape_diamond;
 -                      shape_len = ARRAY_SIZE(shape_diamond);
 -                      break;
 -              case SOCK_DRAW_SHAPE_SQUARE:
 -                      shape = shape_square;
 -                      shape_len = ARRAY_SIZE(shape_square);
 -                      break;
 -      }
 -
 -      node_socket_shape_draw(sock->locx, sock->locy, size, color, highlight, shape, shape_len);
 +      immAttrib4fv(col, color);
 +      immVertex2f(pos, sock->locx, sock->locy);
  }
  
  /* **************  Socket callbacks *********** */
@@@ -646,15 -730,10 +646,15 @@@ static void node_draw_preview_backgroun
  {
        float x, y;
  
 +      Gwn_VertFormat *format = immVertexFormat();
 +      unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
 +
 +      immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
 +
        /* draw checkerboard backdrop to show alpha */
 -      glColor3ub(120, 120, 120);
 -      glRectf(rect->xmin, rect->ymin, rect->xmax, rect->ymax);
 -      glColor3ub(160, 160, 160);
 +      immUniformColor3ub(120, 120, 120);
 +      immRectf(pos, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
 +      immUniformColor3ub(160, 160, 160);
  
        for (y = rect->ymin; y < rect->ymax; y += tile * 2) {
                for (x = rect->xmin; x < rect->xmax; x += tile * 2) {
                        if (y + tile > rect->ymax)
                                tiley = rect->ymax - y;
  
 -                      glRectf(x, y, x + tilex, y + tiley);
 +                      immRectf(pos, x, y, x + tilex, y + tiley);
                }
        }
        for (y = rect->ymin + tile; y < rect->ymax; y += tile * 2) {
                        if (y + tile > rect->ymax)
                                tiley = rect->ymax - y;
  
 -                      glRectf(x, y, x + tilex, y + tiley);
 +                      immRectf(pos, x, y, x + tilex, y + tiley);
                }
        }
 +      immUnbindProgram();
  }
  
  /* not a callback */
@@@ -711,19 -789,17 +711,19 @@@ static void node_draw_preview(bNodePrev
        node_draw_preview_background(BLI_rctf_size_x(prv) / 10.0f, &draw_rect);
  
        glEnable(GL_BLEND);
 -      glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);  /* premul graphics */
 +      glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);  /* premul graphics */
  
 -      glColor4f(1.0, 1.0, 1.0, 1.0);
 -      glPixelZoom(scale, scale);
 -      glaDrawPixelsTex(draw_rect.xmin, draw_rect.ymin, preview->xsize, preview->ysize, GL_RGBA, GL_UNSIGNED_BYTE, GL_LINEAR, preview->rect);
 -      glPixelZoom(1.0f, 1.0f);
 +      IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
 +      immDrawPixelsTex(&state, draw_rect.xmin, draw_rect.ymin, preview->xsize, preview->ysize, GL_RGBA, GL_UNSIGNED_BYTE, GL_LINEAR, preview->rect,
 +                       scale, scale, NULL);
  
        glDisable(GL_BLEND);
  
 -      UI_ThemeColorShadeAlpha(TH_BACK, -15, +100);
 -      fdrawbox(draw_rect.xmin, draw_rect.ymin, draw_rect.xmax, draw_rect.ymax);
 +      unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
 +      immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
 +      immUniformThemeColorShadeAlpha(TH_BACK, -15, +100);
 +      imm_draw_box_wire_2d(pos, draw_rect.xmin, draw_rect.ymin, draw_rect.xmax, draw_rect.ymax);
 +      immUnbindProgram();
  }
  
  /* common handle function for operator buttons that need to select the node first */
@@@ -748,139 -824,32 +748,139 @@@ void node_draw_shadow(SpaceNode *snode
        else {
                const float margin = 3.0f;
  
 -              glColor4f(0.0f, 0.0f, 0.0f, 0.33f);
 -              glEnable(GL_BLEND);
 -              UI_draw_roundbox(rct->xmin - margin, rct->ymin - margin,
 -                               rct->xmax + margin, rct->ymax + margin, radius + margin);
 -              glDisable(GL_BLEND);
 +              float color[4] = {0.0f, 0.0f, 0.0f, 0.33f};
 +              UI_draw_roundbox_aa(true, rct->xmin - margin, rct->ymin - margin,
 +                                  rct->xmax + margin, rct->ymax + margin, radius + margin, color);
        }
  }
  
 +void node_draw_sockets(View2D *v2d, const bContext *C, bNodeTree *ntree, bNode *node, bool draw_outputs, bool select_all)
 +{
 +      const unsigned int total_input_ct = BLI_listbase_count(&node->inputs);
 +      const unsigned int total_output_ct = BLI_listbase_count(&node->outputs);
 +
 +      if (total_input_ct + total_output_ct == 0) {
 +              return;
 +      }
 +
 +      PointerRNA node_ptr;
 +      RNA_pointer_create((ID *)ntree, &RNA_Node, node, &node_ptr);
 +
 +      float scale;
 +      UI_view2d_scale_get(v2d, &scale, NULL);
 +
 +      Gwn_VertFormat *format = immVertexFormat();
 +      unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
 +      unsigned int col = GWN_vertformat_attr_add(format, "color", GWN_COMP_F32, 4, GWN_FETCH_FLOAT);
 +
 +      glEnable(GL_BLEND);
 +      GPU_enable_program_point_size();
 +
 +      immBindBuiltinProgram(GPU_SHADER_2D_POINT_UNIFORM_SIZE_VARYING_COLOR_OUTLINE_AA);
 +
 +      /* set handle size */
 +      immUniform1f("size", 2.0f * NODE_SOCKSIZE * scale); /* 2 * size to have diameter */
 +
 +      if (!select_all) {
 +              /* outline for unselected sockets */
 +              immUniform1f("outlineWidth", 1.0f);
 +              immUniform4f("outlineColor", 0.0f, 0.0f, 0.0f, 0.6f);
 +
 +              immBeginAtMost(GWN_PRIM_POINTS, total_input_ct + total_output_ct);
 +      }
 +
 +      /* socket inputs */
 +      short selected_input_ct = 0;
 +      bNodeSocket *sock;
 +      for (sock = node->inputs.first; sock; sock = sock->next) {
 +              if (nodeSocketIsHidden(sock))
 +                      continue;
 +              if (select_all || (sock->flag & SELECT)) {
 +                      ++selected_input_ct;
 +                      continue;
 +              }
 +
 +              node_socket_circle_draw(C, ntree, node_ptr, sock, pos, col);
 +      }
 +
 +      /* socket outputs */
 +      short selected_output_ct = 0;
 +      if (draw_outputs) {
 +              for (sock = node->outputs.first; sock; sock = sock->next) {
 +                      if (nodeSocketIsHidden(sock))
 +                              continue;
 +                      if (select_all || (sock->flag & SELECT)) {
 +                              ++selected_output_ct;
 +                              continue;
 +                      }
 +
 +                      node_socket_circle_draw(C, ntree, node_ptr, sock, pos, col);
 +              }
 +      }
 +
 +      if (!select_all) {
 +              immEnd();
 +      }
 +
 +      /* go back and draw selected sockets */
 +      if (selected_input_ct + selected_output_ct > 0) {
 +              /* outline for selected sockets */
 +              float c[3];
 +              UI_GetThemeColor3fv(TH_TEXT_HI, c);
 +              immUniform4f("outlineColor", c[0], c[1], c[2], 1.0f);
 +              immUniform1f("outlineWidth", 1.5f);
 +
 +              immBegin(GWN_PRIM_POINTS, selected_input_ct + selected_output_ct);
 +
 +              if (selected_input_ct) {
 +                      /* socket inputs */
 +                      for (sock = node->inputs.first; sock; sock = sock->next) {
 +                              if (nodeSocketIsHidden(sock))
 +                                      continue;
 +                              if (select_all || (sock->flag & SELECT)) {
 +                                      node_socket_circle_draw(C, ntree, node_ptr, sock, pos, col);
 +                                      if (--selected_input_ct == 0)
 +                                              break; /* stop as soon as last one is drawn */
 +                              }
 +                      }
 +              }
 +
 +              if (selected_output_ct) {
 +                      /* socket outputs */
 +                      for (sock = node->outputs.first; sock; sock = sock->next) {
 +                              if (nodeSocketIsHidden(sock))
 +                                      continue;
 +                              if (select_all || (sock->flag & SELECT)) {
 +                                      node_socket_circle_draw(C, ntree, node_ptr, sock, pos, col);
 +                                      if (--selected_output_ct == 0)
 +                                              break; /* stop as soon as last one is drawn */
 +                              }
 +                      }
 +              }
 +
 +              immEnd();
 +      }
 +
 +      immUnbindProgram();
 +
 +      GPU_disable_program_point_size();
 +      glDisable(GL_BLEND);
 +}
 +
  static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree, bNode *node, bNodeInstanceKey key)
  {
        bNodeInstanceHash *previews = CTX_data_pointer_get(C, "node_previews").data;
 -      bNodeSocket *sock;
        rctf *rct = &node->totr;
        float iconofs;
        /* float socket_size = NODE_SOCKSIZE*U.dpi/72; */ /* UNUSED */
        float iconbutw = 0.8f * UI_UNIT_X;
        int color_id = node_get_colorid(node);
 +      float color[4];
        char showname[128]; /* 128 used below */
        View2D *v2d = &ar->v2d;
  
 -      /* XXX hack: copy values from linked ID data where displayed as sockets */
 -      if (node->block)
 -              nodeSynchronizeID(node, false);
 -
        /* skip if out of view */
 -      if (BLI_rctf_isect(&node->totr, &ar->v2d.cur, NULL) == false) {
 +      if (BLI_rctf_isect(&node->totr, &v2d->cur, NULL) == false) {
                UI_block_end(C, node->block);
                node->block = NULL;
                return;
        /* shadow */
        node_draw_shadow(snode, node, BASIS_RAD, 1.0f);
  
 -      /* header uses color from backdrop, but we make it opaqie */
 -      if (color_id == TH_NODE) {
 -              float col[3];
 -              UI_GetThemeColorShade3fv(color_id, -20, col);
 -              glColor4f(col[0], col[1], col[2], 1.0f);
 +      if (node->flag & NODE_MUTED) {
 +              UI_GetThemeColorBlendShade4fv(color_id, TH_REDALERT, 0.5f, 0, color);
 +      }
 +      else {
 +              /* header uses color from backdrop, but we make it opaque */
 +              if (color_id == TH_NODE) {
 +                      UI_GetThemeColorShade3fv(color_id, -20, color);
 +                      color[3] = 1.0f;
 +              }
 +              else {
 +                      UI_GetThemeColor4fv(color_id, color);
 +              }
        }
 -      else
 -              UI_ThemeColor(color_id);
 -
 -      if (node->flag & NODE_MUTED)
 -              UI_ThemeColorBlend(color_id, TH_REDALERT, 0.5f);
 -
  
        glLineWidth(1.0f);
  
        UI_draw_roundbox_corner_set(UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT);
 -      UI_draw_roundbox(rct->xmin, rct->ymax - NODE_DY, rct->xmax, rct->ymax, BASIS_RAD);
 +      UI_draw_roundbox_aa(true, rct->xmin, rct->ymax - NODE_DY, rct->xmax, rct->ymax, BASIS_RAD, color);
  
        /* show/hide icons */
        iconofs = rct->xmax - 0.35f * U.widget_unit;
        }
  
        /* title */
 -      if (node->flag & SELECT)
 -              UI_ThemeColor(TH_SELECT);
 -      else
 -              UI_ThemeColorBlendShade(TH_TEXT, color_id, 0.4f, 10);
 +      if (node->flag & SELECT) {
 +              UI_GetThemeColor4fv(TH_SELECT, color);
 +      }
 +      else {
 +              UI_GetThemeColorBlendShade4fv(TH_SELECT, color_id, 0.4f, 10, color);
 +      }
  
        /* open/close entirely? */
        {
                UI_block_emboss_set(node->block, UI_EMBOSS);
  
                /* custom draw function for this button */
 -              UI_draw_icon_tri(rct->xmin + 0.5f * U.widget_unit, rct->ymax - NODE_DY / 2.0f, 'v');
 +              UI_draw_icon_tri(rct->xmin + 0.5f * U.widget_unit, rct->ymax - NODE_DY / 2.0f, 'v', color);
        }
  
 -      /* this isn't doing anything for the label, so commenting out */
 -#if 0
 -      if (node->flag & SELECT)
 -              UI_ThemeColor(TH_TEXT_HI);
 -      else
 -              UI_ThemeColor(TH_TEXT);
 -#endif
 -
        nodeLabel(ntree, node, showname, sizeof(showname));
  
        //if (node->flag & NODE_MUTED)
  
        /* body */
        if (!nodeIsRegistered(node))
 -              UI_ThemeColor4(TH_REDALERT);    /* use warning color to indicate undefined types */
 -      else if (node->flag & NODE_CUSTOM_COLOR)
 -              glColor3fv(node->color);
 +              UI_GetThemeColor4fv(TH_REDALERT, color);        /* use warning color to indicate undefined types */
 +      else if (node->flag & NODE_CUSTOM_COLOR) {
 +              rgba_float_args_set(color, node->color[0], node->color[1], node->color[2], 1.0f);
 +      }
        else
 -              UI_ThemeColor4(TH_NODE);
 -      glEnable(GL_BLEND);
 +              UI_GetThemeColor4fv(TH_NODE, color);
 +
        UI_draw_roundbox_corner_set(UI_CNR_BOTTOM_LEFT | UI_CNR_BOTTOM_RIGHT);
 -      UI_draw_roundbox(rct->xmin, rct->ymin, rct->xmax, rct->ymax - NODE_DY, BASIS_RAD);
 -      glDisable(GL_BLEND);
 +      UI_draw_roundbox_aa(true, rct->xmin, rct->ymin, rct->xmax, rct->ymax - NODE_DY, BASIS_RAD, color);
  
        /* outline active and selected emphasis */
        if (node->flag & SELECT) {
 -
 -              glEnable(GL_BLEND);
 -              glEnable(GL_LINE_SMOOTH);
 -
 -              if (node->flag & NODE_ACTIVE)
 -                      UI_ThemeColorShadeAlpha(TH_ACTIVE, 0, -40);
 -              else
 -                      UI_ThemeColorShadeAlpha(TH_SELECT, 0, -40);
 +              UI_GetThemeColorShadeAlpha4fv((node->flag & NODE_ACTIVE) ? TH_ACTIVE : TH_SELECT, 0, -40, color);
  
                UI_draw_roundbox_corner_set(UI_CNR_ALL);
 -              UI_draw_roundbox_gl_mode(GL_LINE_LOOP, rct->xmin, rct->ymin, rct->xmax, rct->ymax, BASIS_RAD);
 -
 -              glDisable(GL_LINE_SMOOTH);
 -              glDisable(GL_BLEND);
 +              UI_draw_roundbox_aa(false, rct->xmin, rct->ymin, rct->xmax, rct->ymax, BASIS_RAD, color);
        }
  
        /* disable lines */
        if (node->flag & NODE_MUTED)
                node_draw_mute_line(v2d, snode, node);
  
 -
 -      /* socket inputs, buttons */
 -      for (sock = node->inputs.first; sock; sock = sock->next) {
 -              if (nodeSocketIsHidden(sock))
 -                      continue;
 -
 -              node_socket_draw(C, ntree, node, sock, NODE_SOCKSIZE, sock->flag & SELECT);
 -      }
 -
 -      /* socket outputs */
 -      for (sock = node->outputs.first; sock; sock = sock->next) {
 -              if (nodeSocketIsHidden(sock))
 -                      continue;
 -
 -              node_socket_draw(C, ntree, node, sock, NODE_SOCKSIZE, sock->flag & SELECT);
 -      }
 +      node_draw_sockets(v2d, C, ntree, node, true, false);
  
        /* preview */
        if (node->flag & NODE_PREVIEW && previews) {
  
  static void node_draw_hidden(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree, bNode *node, bNodeInstanceKey UNUSED(key))
  {
 -      bNodeSocket *sock;
        rctf *rct = &node->totr;
        float dx, centy = BLI_rctf_cent_y(rct);
        float hiddenrad = BLI_rctf_size_y(rct) / 2.0f;
 -      float socket_size = NODE_SOCKSIZE;
        int color_id = node_get_colorid(node);
 +      float color[4];
        char showname[128]; /* 128 is used below */
 +      View2D *v2d = &ar->v2d;
 +      float scale;
 +
 +      UI_view2d_scale_get(v2d, &scale, NULL);
  
        /* shadow */
        node_draw_shadow(snode, node, hiddenrad, 1.0f);
  
        /* body */
 -      UI_ThemeColor(color_id);
        if (node->flag & NODE_MUTED)
 -              UI_ThemeColorBlend(color_id, TH_REDALERT, 0.5f);
 +              UI_GetThemeColorBlendShade4fv(color_id, TH_REDALERT, 0.5f, 0, color);
 +      else
 +              UI_GetThemeColor4fv(color_id, color);
  
 -      UI_draw_roundbox(rct->xmin, rct->ymin, rct->xmax, rct->ymax, hiddenrad);
 +      UI_draw_roundbox_aa(true, rct->xmin, rct->ymin, rct->xmax, rct->ymax, hiddenrad, color);
  
        /* outline active and selected emphasis */
        if (node->flag & SELECT) {
 -              glEnable(GL_BLEND);
 -              glEnable(GL_LINE_SMOOTH);
 +              UI_GetThemeColorShadeAlpha4fv((node->flag & NODE_ACTIVE) ? TH_ACTIVE : TH_SELECT, 0, -40, color);
  
 -              if (node->flag & NODE_ACTIVE)
 -                      UI_ThemeColorShadeAlpha(TH_ACTIVE, 0, -40);
 -              else
 -                      UI_ThemeColorShadeAlpha(TH_SELECT, 0, -40);
 -              UI_draw_roundbox_gl_mode(GL_LINE_LOOP, rct->xmin, rct->ymin, rct->xmax, rct->ymax, hiddenrad);
 -
 -              glDisable(GL_LINE_SMOOTH);
 -              glDisable(GL_BLEND);
 +              UI_draw_roundbox_aa(false, rct->xmin, rct->ymin, rct->xmax, rct->ymax, hiddenrad, color);
        }
  
        /* custom color inline */
                glEnable(GL_BLEND);
                glEnable(GL_LINE_SMOOTH);
  
 -              glColor3fv(node->color);
 -              UI_draw_roundbox_gl_mode(GL_LINE_LOOP, rct->xmin + 1, rct->ymin + 1, rct->xmax -1, rct->ymax - 1, hiddenrad);
 +              UI_draw_roundbox_3fvAlpha(false, rct->xmin + 1, rct->ymin + 1, rct->xmax -1, rct->ymax - 1, hiddenrad, node->color, 1.0f);
  
                glDisable(GL_LINE_SMOOTH);
                glDisable(GL_BLEND);
        }
  
        /* title */
 -      if (node->flag & SELECT)
 -              UI_ThemeColor(TH_SELECT);
 -      else
 -              UI_ThemeColorBlendShade(TH_TEXT, color_id, 0.4f, 10);
 +      if (node->flag & SELECT) {
 +              UI_GetThemeColor4fv(TH_SELECT, color);
 +      }
 +      else {
 +              UI_GetThemeColorBlendShade4fv(TH_SELECT, color_id, 0.4f, 10, color);
 +      }
  
        /* open entirely icon */
        {
                UI_block_emboss_set(node->block, UI_EMBOSS);
  
                /* custom draw function for this button */
 -              UI_draw_icon_tri(rct->xmin + 10.0f, centy, 'h');
 +              UI_draw_icon_tri(rct->xmin + 10.0f, centy, 'h', color);
        }
  
        /* disable lines */
        if (node->flag & NODE_MUTED)
                node_draw_mute_line(&ar->v2d, snode, node);
  
 -      if (node->flag & SELECT)
 -              UI_ThemeColor(TH_SELECT);
 -      else
 -              UI_ThemeColor(TH_TEXT);
 -
        if (node->miniwidth > 0.0f) {
                nodeLabel(ntree, node, showname, sizeof(showname));
  
        }
  
        /* scale widget thing */
 -      UI_ThemeColorShade(color_id, -10);
 +      unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
 +      immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
 +
 +      immUniformThemeColorShade(color_id, -10);
        dx = 10.0f;
 -      fdrawline(rct->xmax - dx, centy - 4.0f, rct->xmax - dx, centy + 4.0f);
 -      fdrawline(rct->xmax - dx - 3.0f * snode->aspect, centy - 4.0f, rct->xmax - dx - 3.0f * snode->aspect, centy + 4.0f);
  
 -      UI_ThemeColorShade(color_id, +30);
 +      immBegin(GWN_PRIM_LINES, 4);
 +      immVertex2f(pos, rct->xmax - dx, centy - 4.0f);
 +      immVertex2f(pos, rct->xmax - dx, centy + 4.0f);
 +
 +      immVertex2f(pos, rct->xmax - dx - 3.0f * snode->aspect, centy - 4.0f);
 +      immVertex2f(pos, rct->xmax - dx - 3.0f * snode->aspect, centy + 4.0f);
 +      immEnd();
 +
 +      immUniformThemeColorShade(color_id, 30);
        dx -= snode->aspect;
 -      fdrawline(rct->xmax - dx, centy - 4.0f, rct->xmax - dx, centy + 4.0f);
 -      fdrawline(rct->xmax - dx - 3.0f * snode->aspect, centy - 4.0f, rct->xmax - dx - 3.0f * snode->aspect, centy + 4.0f);
  
 -      /* sockets */
 -      for (sock = node->inputs.first; sock; sock = sock->next) {
 -              if (!nodeSocketIsHidden(sock)) {
 -                      node_socket_draw(C, ntree, node, sock, socket_size, sock->flag & SELECT);
 -              }
 -      }
 +      immBegin(GWN_PRIM_LINES, 4);
 +      immVertex2f(pos, rct->xmax - dx, centy - 4.0f);
 +      immVertex2f(pos, rct->xmax - dx, centy + 4.0f);
  
 -      for (sock = node->outputs.first; sock; sock = sock->next) {
 -              if (!nodeSocketIsHidden(sock)) {
 -                      node_socket_draw(C, ntree, node, sock, socket_size, sock->flag & SELECT);
 -              }
 -      }
 +      immVertex2f(pos, rct->xmax - dx - 3.0f * snode->aspect, centy - 4.0f);
 +      immVertex2f(pos, rct->xmax - dx - 3.0f * snode->aspect, centy + 4.0f);
 +      immEnd();
 +
 +      immUnbindProgram();
 +
 +      node_draw_sockets(v2d, C, ntree, node, true, false);
  
        UI_block_end(C, node->block);
        UI_block_draw(C, node->block);
@@@ -1240,12 -1241,12 +1240,12 @@@ void node_draw_nodetree(const bContext 
  
        /* node lines */
        glEnable(GL_BLEND);
 -      glEnable(GL_LINE_SMOOTH);
 +      nodelink_batch_start(snode);
        for (link = ntree->links.first; link; link = link->next) {
                if (!nodeLinkIsHidden(link))
                        node_draw_link(&ar->v2d, snode, link);
        }
 -      glDisable(GL_LINE_SMOOTH);
 +      nodelink_batch_end(snode);
        glDisable(GL_BLEND);
  
        /* draw foreground nodes, last nodes in front */
@@@ -1267,7 -1268,7 +1267,7 @@@ static void draw_tree_path(SpaceNode *s
  
        ED_node_tree_path_get_fixedbuf(snode, info, sizeof(info));
  
 -      UI_ThemeColor(TH_TEXT_HI);
 +      UI_FontThemeColor(BLF_default(), TH_TEXT_HI);
        BLF_draw_default(1.5f * UI_UNIT_X, 1.5f * UI_UNIT_Y, 0.0f, info, sizeof(info));
  }
  
@@@ -1300,14 -1301,12 +1300,14 @@@ static void draw_group_overlay(const bC
        View2D *v2d = &ar->v2d;
        rctf rect = v2d->cur;
        uiBlock *block;
 +      float color[4];
  
        /* shade node groups to separate them visually */
 -      UI_ThemeColorShadeAlpha(TH_NODE_GROUP, 0, -70);
        glEnable(GL_BLEND);
 +
 +      UI_GetThemeColorShadeAlpha4fv(TH_NODE_GROUP, 0, -70, color);
        UI_draw_roundbox_corner_set(UI_CNR_NONE);
 -      UI_draw_roundbox_gl_mode(GL_POLYGON, rect.xmin, rect.ymin, rect.xmax, rect.ymax, 0);
 +      UI_draw_roundbox_4fv(true, rect.xmin, rect.ymin, rect.xmax, rect.ymax, 0, color);
        glDisable(GL_BLEND);
  
        /* set the block bounds to clip mouse events from underlying nodes */
@@@ -1338,7 -1337,8 +1338,7 @@@ void drawnodespace(const bContext *C, A
        ED_region_draw_cb_draw(C, ar, REGION_DRAW_PRE_VIEW);
  
        /* only set once */
 -      glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 -      glEnable(GL_MAP1_VERTEX_3);
 +      glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
  
        /* nodes */
        snode_set_context(C);
                        /* backdrop */
                        draw_nodespace_back_pix(C, ar, snode, path->parent_key);
  
 +                      {
 +                              float original_proj[4][4];
 +                              gpuGetProjectionMatrix(original_proj);
 +
 +                              gpuPushMatrix();
 +                              gpuLoadIdentity();
 +
 +                              wmOrtho2_pixelspace(ar->winx, ar->winy);
 +
 +                              WM_manipulatormap_draw(ar->manipulator_map, C, WM_MANIPULATORMAP_DRAWSTEP_2D);
 +
 +                              gpuPopMatrix();
 +                              gpuLoadProjectionMatrix(original_proj);
 +                      }
 +
                        draw_nodetree(C, ar, ntree, path->parent_key);
                }
  
index 2d1af3f45786b52a31b53d8ed6693cd82cc35772,1cb387bb5273ed56c43b7f081f9a5b3309469a6f..69a372c70c42bd61d5a9e3229770d7321453664a
@@@ -41,6 -41,7 +41,6 @@@
  #include "BLI_blenlib.h"
  
  #include "BKE_context.h"
 -#include "BKE_depsgraph.h"
  #include "BKE_global.h"
  #include "BKE_image.h"
  #include "BKE_library.h"
@@@ -49,8 -50,6 +49,8 @@@
  #include "BKE_report.h"
  #include "BKE_scene.h"
  
 +#include "DEG_depsgraph.h"
 +
  #include "RE_engine.h"
  #include "RE_pipeline.h"
  
@@@ -124,7 -123,7 +124,7 @@@ static int compo_get_recalc_flags(cons
        int recalc_flags = 0;
  
        for (win = wm->windows.first; win; win = win->next) {
 -              bScreen *sc = win->screen;
 +              const bScreen *sc = WM_window_get_active_screen(win);
                ScrArea *sa;
  
                for (sa = sc->areabase.first; sa; sa = sa->next) {
@@@ -329,11 -328,11 +329,11 @@@ void snode_dag_update(bContext *C, Spac
        if (snode->edittree != snode->nodetree) {
                FOREACH_NODETREE(bmain, tntree, id) {
                        if (ntreeHasTree(tntree, snode->edittree))
 -                              DAG_id_tag_update(id, 0);
 +                              DEG_id_tag_update(id, 0);
                } FOREACH_NODETREE_END
        }
  
 -      DAG_id_tag_update(snode->id, 0);
 +      DEG_id_tag_update(snode->id, 0);
  }
  
  void snode_notify(bContext *C, SpaceNode *snode)
@@@ -383,6 -382,7 +383,6 @@@ bool ED_node_is_texture(struct SpaceNod
  /* called from shading buttons or header */
  void ED_node_shader_default(const bContext *C, ID *id)
  {
 -      Scene *scene = CTX_data_scene(C);
        bNode *in, *out;
        bNodeSocket *fromsock, *tosock, *sock;
        bNodeTree *ntree;
                        Material *ma = (Material *)id;
                        ma->nodetree = ntree;
  
 -                      if (BKE_scene_use_new_shading_nodes(scene)) {
 -                              output_type = SH_NODE_OUTPUT_MATERIAL;
 -                              shader_type = SH_NODE_BSDF_DIFFUSE;
 -                      }
 -                      else {
 -                              output_type = SH_NODE_OUTPUT;
 -                              shader_type = SH_NODE_MATERIAL;
 -                      }
 +                      output_type = SH_NODE_OUTPUT_MATERIAL;
 +                      shader_type = SH_NODE_BSDF_PRINCIPLED;
  
                        copy_v3_v3(color, &ma->r);
                        strength = 0.0f;
        nodeAddLink(ntree, in, fromsock, out, tosock);
  
        /* default values */
 -      if (BKE_scene_use_new_shading_nodes(scene)) {
 -              PointerRNA sockptr;
 -              sock = in->inputs.first;
 -              RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &sockptr);
 +      PointerRNA sockptr;
 +      sock = in->inputs.first;
 +      RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &sockptr);
  
 -              RNA_float_set_array(&sockptr, "default_value", color);
 +      RNA_float_set_array(&sockptr, "default_value", color);
  
 -              if (strength != 0.0f) {
 -                      sock = in->inputs.last;
 -                      RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &sockptr);
 -                      RNA_float_set(&sockptr, "default_value", strength);
 -              }
 +      if (strength != 0.0f) {
 +              sock = in->inputs.last;
 +              RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &sockptr);
 +              RNA_float_set(&sockptr, "default_value", strength);
        }
  
        ntreeUpdateTree(CTX_data_main(C), ntree);
@@@ -537,6 -545,12 +537,6 @@@ void snode_set_context(const bContext *
        bNodeTree *ntree = snode->nodetree;
        ID *id = snode->id, *from = snode->from;
  
 -      /* we use this to signal warnings, when node shaders are drawn in wrong render engine */
 -      if (BKE_scene_use_new_shading_nodes(CTX_data_scene(C)))
 -              snode->flag |= SNODE_NEW_SHADERS;
 -      else
 -              snode->flag &= ~SNODE_NEW_SHADERS;
 -
        /* check the tree type */
        if (!treetype ||
            (treetype->poll && !treetype->poll(C, treetype)))
@@@ -624,7 -638,7 +624,7 @@@ void ED_node_set_active(Main *bmain, bN
                        if (node->id && ELEM(GS(node->id->name), ID_MA, ID_LA, ID_WO))
                                nodeClearActiveID(ntree, ID_TE);
  
 -                      if (ELEM(node->type, SH_NODE_OUTPUT, SH_NODE_OUTPUT_MATERIAL,
 +                      if (ELEM(node->type, SH_NODE_OUTPUT_MATERIAL,
                                 SH_NODE_OUTPUT_WORLD, SH_NODE_OUTPUT_LAMP, SH_NODE_OUTPUT_LINESTYLE))
                        {
                                bNode *tnode;
                                /* addnode() doesnt link this yet... */
                                node->id = (ID *)BKE_image_verify_viewer(IMA_TYPE_COMPOSITE, "Viewer Node");
                        }
 -                      else if (node->type == CMP_NODE_R_LAYERS) {
 -                              Scene *scene;
 -
 -                              for (scene = bmain->scene.first; scene; scene = scene->id.next) {
 -                                      if (scene->nodetree && scene->use_nodes && ntreeHasTree(scene->nodetree, ntree)) {
 -                                              if (node->id == NULL || node->id == (ID *)scene) {
 -                                                      int num_layers = BLI_listbase_count(&scene->r.layers);
 -                                                      scene->r.actlay = node->custom1;
 -                                                      /* Clamp the value, because it might have come from a different
 -                                                       * scene which could have more render layers than new one.
 -                                                       */
 -                                                      scene->r.actlay = min_ff(scene->r.actlay, num_layers - 1);
 -                                              }
 -                                      }
 -                              }
 -                      }
                        else if (node->type == CMP_NODE_COMPOSITE) {
                                if (was_output == 0) {
                                        bNode *tnode;
@@@ -1102,6 -1132,7 +1102,7 @@@ static void node_duplicate_reparent_rec
  
  static int node_duplicate_exec(bContext *C, wmOperator *op)
  {
+       Main *bmain = CTX_data_main(C);
        SpaceNode *snode = CTX_wm_space_node(C);
        bNodeTree *ntree = snode->edittree;
        bNode *node, *newnode, *lastnode;
        const bool keep_inputs = RNA_boolean_get(op->ptr, "keep_inputs");
        bool do_tag_update = false;
  
-       ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
+       ED_preview_kill_jobs(CTX_wm_manager(C), bmain);
  
        lastnode = ntree->nodes.last;
        for (node = ntree->nodes.first; node; node = node->next) {
                        node->flag &= ~NODE_ACTIVE;
                        nodeSetSelected(newnode, true);
  
-                       do_tag_update |= (do_tag_update || node_connected_to_output(ntree, newnode));
+                       do_tag_update |= (do_tag_update || node_connected_to_output(bmain, ntree, newnode));
                }
  
                /* make sure we don't copy new nodes again! */
@@@ -1241,7 -1272,7 +1242,7 @@@ bool ED_node_select_check(ListBase *lb
  
  
  /* goes over all scenes, reads render layers */
 -static int node_read_renderlayers_exec(bContext *C, wmOperator *UNUSED(op))
 +static int node_read_viewlayers_exec(bContext *C, wmOperator *UNUSED(op))
  {
        Main *bmain = CTX_data_main(C);
        SpaceNode *snode = CTX_wm_space_node(C);
        return OPERATOR_FINISHED;
  }
  
 -void NODE_OT_read_renderlayers(wmOperatorType *ot)
 +void NODE_OT_read_viewlayers(wmOperatorType *ot)
  {
  
 -      ot->name = "Read Render Layers";
 -      ot->idname = "NODE_OT_read_renderlayers";
 +      ot->name = "Read View Layers";
 +      ot->idname = "NODE_OT_read_viewlayers";
        ot->description = "Read all render layers of all used scenes";
  
 -      ot->exec = node_read_renderlayers_exec;
 -
 -      ot->poll = composite_node_active;
 -
 -      /* flags */
 -      ot->flag = 0;
 -}
 -
 -static int node_read_fullsamplelayers_exec(bContext *C, wmOperator *UNUSED(op))
 -{
 -      Main *bmain = CTX_data_main(C);
 -      SpaceNode *snode = CTX_wm_space_node(C);
 -      Scene *curscene = CTX_data_scene(C);
 -      Render *re = RE_NewSceneRender(curscene);
 -
 -      WM_cursor_wait(1);
 -      RE_MergeFullSample(re, bmain, curscene, snode->nodetree);
 -      WM_cursor_wait(0);
 -
 -      /* note we are careful to send the right notifier, as otherwise the
 -       * compositor would reexecute and overwrite the full sample result */
 -      WM_event_add_notifier(C, NC_SCENE | ND_COMPO_RESULT, NULL);
 -
 -      return OPERATOR_FINISHED;
 -}
 -
 -
 -void NODE_OT_read_fullsamplelayers(wmOperatorType *ot)
 -{
 -
 -      ot->name = "Read Full Sample Layers";
 -      ot->idname = "NODE_OT_read_fullsamplelayers";
 -      ot->description = "Read all render layers of current scene, in full sample";
 -
 -      ot->exec = node_read_fullsamplelayers_exec;
 +      ot->exec = node_read_viewlayers_exec;
  
        ot->poll = composite_node_active;
  
@@@ -1297,13 -1362,13 +1298,13 @@@ int node_render_changed_exec(bContext *
                }
        }
        if (node) {
 -              SceneRenderLayer *srl = BLI_findlink(&sce->r.layers, node->custom1);
 +              ViewLayer *view_layer = BLI_findlink(&sce->view_layers, node->custom1);
  
 -              if (srl) {
 +              if (view_layer) {
                        PointerRNA op_ptr;
  
                        WM_operator_properties_create(&op_ptr, "RENDER_OT_render");
 -                      RNA_string_set(&op_ptr, "layer", srl->name);
 +                      RNA_string_set(&op_ptr, "layer", view_layer->name);
                        RNA_string_set(&op_ptr, "scene", sce->id.name + 2);
  
                        /* to keep keypositions */
@@@ -1522,18 -1587,19 +1523,19 @@@ void NODE_OT_hide_socket_toggle(wmOpera
  
  static int node_mute_exec(bContext *C, wmOperator *UNUSED(op))
  {
+       Main *bmain = CTX_data_main(C);
        SpaceNode *snode = CTX_wm_space_node(C);
        bNode *node;
        bool do_tag_update = false;
  
-       ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
+       ED_preview_kill_jobs(CTX_wm_manager(C), bmain);
  
        for (node = snode->edittree->nodes.first; node; node = node->next) {
                /* Only allow muting of nodes having a mute func! */
                if ((node->flag & SELECT) && node->typeinfo->update_internal_links) {
                        node->flag ^= NODE_MUTED;
                        snode_update(snode, node);
-                       do_tag_update |= (do_tag_update || node_connected_to_output(snode->edittree, node));
+                       do_tag_update |= (do_tag_update || node_connected_to_output(bmain, snode->edittree, node));
                }
        }
  
@@@ -1564,17 -1630,18 +1566,18 @@@ void NODE_OT_mute_toggle(wmOperatorTyp
  
  static int node_delete_exec(bContext *C, wmOperator *UNUSED(op))
  {
+       Main *bmain = CTX_data_main(C);
        SpaceNode *snode = CTX_wm_space_node(C);
        bNode *node, *next;
        bool do_tag_update = false;
  
-       ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
+       ED_preview_kill_jobs(CTX_wm_manager(C), bmain);
  
        for (node = snode->edittree->nodes.first; node; node = next) {
                next = node->next;
                if (node->flag & SELECT) {
                        /* check id user here, nodeFreeNode is called for free dbase too */
-                       do_tag_update |= (do_tag_update || node_connected_to_output(snode->edittree, node));
+                       do_tag_update |= (do_tag_update || node_connected_to_output(bmain, snode->edittree, node));
                        if (node->id)
                                id_us_min(node->id);
                        nodeFreeNode(snode->edittree, node);
index 4440b2c6ecd385632b6e4a3e2b12a4b5410d2b12,9bcbe94d2870bb854568f7b242731cb4ac05b7b1..2cc37a4e0fe8063792b48412411f01359080ab60
@@@ -41,6 -41,7 +41,7 @@@ struct ARegion
  struct ARegionType;
  struct View2D;
  struct bContext;
+ struct Main;
  struct wmWindow;
  struct bNode;
  struct bNodeSocket;
@@@ -67,11 -68,13 +68,11 @@@ void snode_group_offset(struct SpaceNod
  
  /* node_draw.c */
  int node_get_colorid(struct bNode *node);
 -void node_socket_draw(
 -        const struct bContext *C, struct bNodeTree *ntree, struct bNode *node,
 -        struct bNodeSocket *sock, float size, bool highlight);
  int node_get_resize_cursor(int directions);
  void node_draw_shadow(struct SpaceNode *snode, struct bNode *node, float radius, float alpha);
  void node_draw_default(const struct bContext *C, struct ARegion *ar, struct SpaceNode *snode,
                         struct bNodeTree *ntree, struct bNode *node, bNodeInstanceKey key);
 +void node_draw_sockets(struct View2D *v2d, const struct bContext *C, struct bNodeTree *ntree, struct bNode *node, bool draw_outputs, bool select_all);
  void node_update_default(const struct bContext *C, struct bNodeTree *ntree, struct bNode *node);
  int node_select_area_default(struct bNode *node, int x, int y);
  int node_tweak_area_default(struct bNode *node, int x, int y);
@@@ -130,11 -133,8 +131,11 @@@ void NODE_OT_backimage_fit(struct wmOpe
  void NODE_OT_backimage_sample(struct wmOperatorType *ot);
  
  /* drawnode.c */
 +void nodelink_batch_start(struct SpaceNode *snode);
 +void nodelink_batch_end(struct SpaceNode *snode);
 +
  void node_draw_link(struct View2D *v2d, struct SpaceNode *snode, struct bNodeLink *link);
 -void node_draw_link_bezier(struct View2D *v2d, struct SpaceNode *snode, struct bNodeLink *link, int th_col1, bool do_shaded, int th_col2, bool do_triple, int th_col3);
 +void node_draw_link_bezier(struct View2D *v2d, struct SpaceNode *snode, struct bNodeLink *link, int th_col1, int th_col2, int th_col3);
  bool node_link_bezier_points(struct View2D *v2d, struct SpaceNode *snode, struct bNodeLink *link, float coord_array[][2], int resol);
  // void node_draw_link_straight(View2D *v2d, SpaceNode *snode, bNodeLink *link, int th_col1, int do_shaded, int th_col2, int do_triple, int th_col3 );
  void draw_nodespace_back_pix(const struct bContext *C, struct ARegion *ar, struct SpaceNode *snode, bNodeInstanceKey parent_key);
@@@ -157,7 -157,7 +158,7 @@@ void NODE_OT_group_edit(struct wmOperat
  
  
  /* node_relationships.c */
- bool node_connected_to_output(struct bNodeTree *ntree, struct bNode *node);
+ bool node_connected_to_output(struct Main *bmain, struct bNodeTree *ntree, struct bNode *node);
  
  void NODE_OT_link(struct wmOperatorType *ot);
  void NODE_OT_link_make(struct wmOperatorType *ot);
@@@ -200,7 -200,7 +201,7 @@@ void NODE_OT_options_toggle(struct wmOp
  void NODE_OT_node_copy_color(struct wmOperatorType *ot);
  
  void NODE_OT_read_fullsamplelayers(struct wmOperatorType *ot);
 -void NODE_OT_read_renderlayers(struct wmOperatorType *ot);
 +void NODE_OT_read_viewlayers(struct wmOperatorType *ot);
  void NODE_OT_render_changed(struct wmOperatorType *ot);
  
  void NODE_OT_output_file_add_socket(struct wmOperatorType *ot);
@@@ -222,13 -222,6 +223,13 @@@ void NODE_OT_shader_script_update(struc
  void NODE_OT_viewer_border(struct wmOperatorType *ot);
  void NODE_OT_clear_viewer_border(struct wmOperatorType *ot);
  
 +/* node_widgets.c */
 +void NODE_WGT_backdrop_transform(struct wmManipulatorGroupType *wgt);
 +void NODE_WGT_backdrop_crop(struct wmManipulatorGroupType *wgt);
 +void NODE_WGT_backdrop_sun_beams(struct wmManipulatorGroupType *wgt);
 +void NODE_WGT_backdrop_corner_pin(struct wmManipulatorGroupType *wgt);
 +
 +
  extern const char *node_context_dir[];
  
  // XXXXXX
index 5a2feacf20c999ed560527e02afdc1dfe2e205a9,bba21f7f5ebf8ffaff5b6c954fe8ec8b548cef45..23fd793cdd31938cda681fd0acc54627d94db310
@@@ -82,11 -82,11 +82,11 @@@ static bool node_link_item_compare(bNod
                return true;
  }
  
- static void node_link_item_apply(bNode *node, NodeLinkItem *item)
+ static void node_link_item_apply(Main *bmain, bNode *node, NodeLinkItem *item)
  {
        if (node->type == NODE_GROUP) {
                node->id = (ID *)item->ngroup;
-               ntreeUpdateTree(G.main, item->ngroup);
+               ntreeUpdateTree(bmain, item->ngroup);
        }
        else {
                /* nothing to do for now */
@@@ -191,6 -191,7 +191,7 @@@ static void node_socket_remove(Main *bm
  static void node_socket_add_replace(const bContext *C, bNodeTree *ntree, bNode *node_to, bNodeSocket *sock_to,
                                      int type, NodeLinkItem *item)
  {
+       Main *bmain = CTX_data_main(C);
        bNode *node_from;
        bNodeSocket *sock_from_tmp;
        bNode *node_prev = NULL;
                        node_from->locy = node_to->locy - (node_from->typeinfo->height * index);
                }
  
-               node_link_item_apply(node_from, item);
+               node_link_item_apply(bmain, node_from, item);
        }
  
        nodeSetActive(ntree, node_from);
@@@ -448,7 -449,10 +449,7 @@@ static void ui_node_menu_column(NodeLin
        int compatibility = 0;
  
        if (ntree->type == NTREE_SHADER) {
 -              if (BKE_scene_use_new_shading_nodes(arg->scene))
 -                      compatibility = NODE_NEW_SHADING;
 -              else
 -                      compatibility = NODE_OLD_SHADING;
 +              compatibility = NODE_NEW_SHADING;
        }
  
        /* generate array of node types sorted by UI name */
@@@ -634,7 -638,7 +635,7 @@@ static void ui_node_draw_node(uiLayout 
  
        if (node->typeinfo->draw_buttons) {
                if (node->type != NODE_GROUP) {
 -                      split = uiLayoutSplit(layout, 0.35f, false);
 +                      split = uiLayoutSplit(layout, 0.5f, false);
                        col = uiLayoutColumn(split, false);
                        col = uiLayoutColumn(split, false);
  
@@@ -677,10 -681,10 +678,10 @@@ static void ui_node_draw_input(uiLayou
                label[i] = ' ';
        }
        label[indent] = '\0';
 -      BLI_snprintf(label + indent, UI_MAX_NAME_STR - indent, "%s:", IFACE_(input->name));
 +      BLI_snprintf(label + indent, UI_MAX_NAME_STR - indent, "%s", IFACE_(input->name));
  
        /* split in label and value */
 -      split = uiLayoutSplit(layout, 0.35f, false);
 +      split = uiLayoutSplit(layout, 0.5f, false);
  
        row = uiLayoutRow(split, true);
  
  
        uiItemL(row, label, ICON_NONE);
        bt = block->buttons.last;
 -      bt->drawflag = UI_BUT_TEXT_LEFT;
 +      bt->drawflag = UI_BUT_TEXT_RIGHT;
  
        if (dependency_loop) {
                row = uiLayoutRow(split, false);
index 45941ba6f398b6f6c08886f49f969893829bc0d6,9f2effde46a24c7d51ca22fdfc3fd455b4619706..6c608a0b5e42bd6ae423344504ed8d34f453fd01
  #include "BKE_context.h"
  #include "BKE_crazyspace.h"
  #include "BKE_curve.h"
 -#include "BKE_depsgraph.h"
  #include "BKE_fcurve.h"
  #include "BKE_global.h"
  #include "BKE_gpencil.h"
 +#include "BKE_layer.h"
  #include "BKE_key.h"
  #include "BKE_main.h"
  #include "BKE_mesh.h"
  #include "RNA_access.h"
  
  #include "DEG_depsgraph.h"
 +#include "DEG_depsgraph_build.h"
 +#include "DEG_depsgraph_query.h"
  
  #include "transform.h"
  #include "bmesh.h"
   */
  static void transform_around_single_fallback(TransInfo *t)
  {
 -      if ((t->total == 1) &&
 +      if ((t->data_len_all == 1) &&
            (ELEM(t->around, V3D_AROUND_CENTER_BOUNDS, V3D_AROUND_CENTER_MEAN, V3D_AROUND_ACTIVE)) &&
            (ELEM(t->mode, TFM_RESIZE, TFM_ROTATION, TFM_TRACKBALL)))
        {
@@@ -171,50 -169,45 +171,50 @@@ static int trans_data_compare_rdist(con
  
  void sort_trans_data_dist(TransInfo *t)
  {
 -      TransData *start = t->data;
 -      int i;
 +      FOREACH_TRANS_DATA_CONTAINER (t, tc) {
 +              TransData *start = tc->data;
 +              int i;
  
 -      for (i = 0; i < t->total && start->flag & TD_SELECTED; i++)
 -              start++;
 +              for (i = 0; i < tc->data_len && start->flag & TD_SELECTED; i++) {
 +                      start++;
 +              }
  
 -      if (i < t->total) {
 -              if (t->flag & T_PROP_CONNECTED)
 -                      qsort(start, t->total - i, sizeof(TransData), trans_data_compare_dist);
 -              else
 -                      qsort(start, t->total - i, sizeof(TransData), trans_data_compare_rdist);
 +              if (i < tc->data_len) {
 +                      if (t->flag & T_PROP_CONNECTED)
 +                              qsort(start, tc->data_len - i, sizeof(TransData), trans_data_compare_dist);
 +                      else
 +                              qsort(start, tc->data_len - i, sizeof(TransData), trans_data_compare_rdist);
 +              }
        }
  }
  
  static void sort_trans_data(TransInfo *t)
  {
 -      TransData *sel, *unsel;
 -      TransData temp;
 -      unsel = t->data;
 -      sel = t->data;
 -      sel += t->total - 1;
 -      while (sel > unsel) {
 -              while (unsel->flag & TD_SELECTED) {
 -                      unsel++;
 -                      if (unsel == sel) {
 -                              return;
 -                      }
 -              }
 -              while (!(sel->flag & TD_SELECTED)) {
 +      FOREACH_TRANS_DATA_CONTAINER (t, tc) {
 +              TransData *sel, *unsel;
 +              TransData temp;
 +              unsel = tc->data;
 +              sel = tc->data;
 +              sel += tc->data_len - 1;
 +              while (sel > unsel) {
 +                      while (unsel->flag & TD_SELECTED) {
 +                              unsel++;
 +                              if (unsel == sel) {
 +                                      return;
 +                              }
 +                      }
 +                      while (!(sel->flag & TD_SELECTED)) {
 +                              sel--;
 +                              if (unsel == sel) {
 +                                      return;
 +                              }
 +                      }
 +                      temp = *unsel;
 +                      *unsel = *sel;
 +                      *sel = temp;
                        sel--;
 -                      if (unsel == sel) {
 -                              return;
 -                      }
 +                      unsel++;
                }
 -              temp = *unsel;
 -              *unsel = *sel;
 -              *sel = temp;
 -              sel--;
 -              unsel++;
        }
  }
  
   * warning; this is loops inside loop, has minor N^2 issues, but by sorting list it is OK */
  static void set_prop_dist(TransInfo *t, const bool with_dist)
  {
 -      TransData *tob;
        int a;
  
        float _proj_vec[3];
                }
        }
  
 -      for (a = 0, tob = t->data; a < t->total; a++, tob++) {
 +      FOREACH_TRANS_DATA_CONTAINER (t, tc) {
 +              TransData *tob = tc->data;
 +              for (a = 0; a < tc->data_len; a++, tob++) {
  
 -              tob->rdist = 0.0f; // init, it was mallocced
 +                      tob->rdist = 0.0f; // init, it was mallocced
  
 -              if ((tob->flag & TD_SELECTED) == 0) {
 -                      TransData *td;
 -                      int i;
 -                      float dist_sq, vec[3];
 +                      if ((tob->flag & TD_SELECTED) == 0) {
 +                              TransData *td;
 +                              int i;
 +                              float dist_sq, vec[3];
  
 -                      tob->rdist = -1.0f; // signal for next loop
 +                              tob->rdist = -1.0f; // signal for next loop
  
 -                      for (i = 0, td = t->data; i < t->total; i++, td++) {
 -                              if (td->flag & TD_SELECTED) {
 -                                      if (use_island) {
 -                                              sub_v3_v3v3(vec, tob->iloc, td->iloc);
 -                                      }
 -                                      else {
 -                                              sub_v3_v3v3(vec, tob->center, td->center);
 -                                      }
 -                                      mul_m3_v3(tob->mtx, vec);
 +                              for (i = 0, td = tc->data; i < tc->data_len; i++, td++) {
 +                                      if (td->flag & TD_SELECTED) {
 +                                              if (use_island) {
 +                                                      sub_v3_v3v3(vec, tob->iloc, td->iloc);
 +                                              }
 +                                              else {
 +                                                      sub_v3_v3v3(vec, tob->center, td->center);
 +                                              }
 +                                              mul_m3_v3(tob->mtx, vec);
  
 -                                      if (proj_vec) {
 -                                              float vec_p[3];
 -                                              project_v3_v3v3(vec_p, vec, proj_vec);
 -                                              sub_v3_v3(vec, vec_p);
 -                                      }
 +                                              if (proj_vec) {
 +                                                      float vec_p[3];
 +                                                      project_v3_v3v3(vec_p, vec, proj_vec);
 +                                                      sub_v3_v3(vec, vec_p);
 +                                              }
  
 -                                      dist_sq = len_squared_v3(vec);
 -                                      if ((tob->rdist == -1.0f) || (dist_sq < SQUARE(tob->rdist))) {
 -                                              tob->rdist = sqrtf(dist_sq);
 -                                              if (use_island) {
 -                                                      copy_v3_v3(tob->center, td->center);
 -                                                      copy_m3_m3(tob->axismtx, td->axismtx);
 +                                              dist_sq = len_squared_v3(vec);
 +                                              if ((tob->rdist == -1.0f) || (dist_sq < SQUARE(tob->rdist))) {
 +                                                      tob->rdist = sqrtf(dist_sq);
 +                                                      if (use_island) {
 +                                                              copy_v3_v3(tob->center, td->center);
 +                                                              copy_m3_m3(tob->axismtx, td->axismtx);
 +                                                      }
                                                }
                                        }
 +                                      else {
 +                                              break;  /* by definition transdata has selected items in beginning */
 +                                      }
                                }
 -                              else {
 -                                      break;  /* by definition transdata has selected items in beginning */
 +                              if (with_dist) {
 +                                      tob->dist = tob->rdist;
                                }
                        }
 -                      if (with_dist) {
 -                              tob->dist = tob->rdist;
 -                      }
                }
        }
  }
  
  static void createTransTexspace(TransInfo *t)
  {
 -      Scene *scene = t->scene;
 +      ViewLayer *view_layer = t->view_layer;
        TransData *td;
        Object *ob;
        ID *id;
        short *texflag;
  
 -      ob = OBACT;
 +      ob = OBACT(view_layer);
  
        if (ob == NULL) { // Shouldn't logically happen, but still...
 -              t->total = 0;
                return;
        }
  
        id = ob->data;
        if (id == NULL || !ELEM(GS(id->name), ID_ME, ID_CU, ID_MB)) {
                BKE_report(t->reports, RPT_ERROR, "Unsupported object type for text-space transform");
 -              t->total = 0;
                return;
        }
  
        if (BKE_object_obdata_is_libdata(ob)) {
                BKE_report(t->reports, RPT_ERROR, "Linked data can't text-space transform");
 -              t->total = 0;
                return;
        }
  
 -      t->total = 1;
 -      td = t->data = MEM_callocN(sizeof(TransData), "TransTexspace");
 -      td->ext = t->ext = MEM_callocN(sizeof(TransDataExtension), "TransTexspace");
 +
 +      {
 +              BLI_assert(t->data_container_len == 1);
 +              TransDataContainer *tc = t->data_container;
 +              tc->data_len = 1;
 +              td = tc->data = MEM_callocN(sizeof(TransData), "TransTexspace");
 +              td->ext = tc->data_ext = MEM_callocN(sizeof(TransDataExtension), "TransTexspace");
 +      }
  
        td->flag = TD_SELECTED;
        copy_v3_v3(td->center, ob->obmat[3]);
        copy_v3_v3(td->ext->isize, td->ext->size);
  }
  
 +static void createTransCursor3D(TransInfo *t)
 +{
 +      TransData *td;
 +
 +      Scene *scene = t->scene;
 +      View3D *v3d = ((t->spacetype == SPACE_VIEW3D) && (t->ar->regiontype == RGN_TYPE_WINDOW)) ? t->view : NULL;
 +      View3DCursor *cursor = ED_view3d_cursor3d_get(scene, v3d);
 +
 +      if ((cursor == &scene->cursor) && ID_IS_LINKED(scene)) {
 +              BKE_report(t->reports, RPT_ERROR, "Linked data can't text-space transform");
 +              return;
 +      }
 +
 +      {
 +              BLI_assert(t->data_container_len == 1);
 +              TransDataContainer *tc = t->data_container;
 +              tc->data_len = 1;
 +              td = tc->data = MEM_callocN(sizeof(TransData), "TransTexspace");
 +              td->ext = tc->data_ext = MEM_callocN(sizeof(TransDataExtension), "TransTexspace");
 +      }
 +
 +      td->flag = TD_SELECTED;
 +      copy_v3_v3(td->center, cursor->location);
 +      td->ob = NULL;
 +
 +      unit_m3(td->mtx);
 +      quat_to_mat3(td->axismtx, cursor->rotation);
 +      normalize_m3(td->axismtx);
 +      pseudoinverse_m3_m3(td->smtx, td->mtx, PSEUDOINVERSE_EPSILON);
 +
 +      td->loc = cursor->location;
 +      copy_v3_v3(td->iloc, cursor->location);
 +
 +      td->ext->quat = cursor->rotation;
 +      copy_qt_qt(td->ext->iquat, cursor->rotation);
 +}
 +
  /* ********************* edge (for crease) ***** */
  
  static void createTransEdge(TransInfo *t)
  {
 -      BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
 -      TransData *td = NULL;
 -      BMEdge *eed;
 -      BMIter iter;
 -      float mtx[3][3], smtx[3][3];
 -      int count = 0, countsel = 0;
 -      const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
 -      int cd_edge_float_offset;
 +      FOREACH_TRANS_DATA_CONTAINER (t, tc) {
  
 -      BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
 -              if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
 -                      if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) countsel++;
 -                      if (is_prop_edit) count++;
 +              BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
 +              TransData *td = NULL;
 +              BMEdge *eed;
 +              BMIter iter;
 +              float mtx[3][3], smtx[3][3];
 +              int count = 0, countsel = 0;
 +              const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
 +              int cd_edge_float_offset;
 +
 +              BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
 +                      if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
 +                              if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) countsel++;
 +                              if (is_prop_edit) count++;
 +                      }
                }
 -      }
  
 -      if (countsel == 0)
 -              return;
 +              if (countsel == 0) {
 +                      tc->data_len = 0;
 +                      continue;
 +              }
  
 -      if (is_prop_edit) {
 -              t->total = count;
 -      }
 -      else {
 -              t->total = countsel;
 -      }
 +              if (is_prop_edit) {
 +                      tc->data_len = count;
 +              }
 +              else {
 +                      tc->data_len = countsel;
 +              }
  
 -      td = t->data = MEM_callocN(t->total * sizeof(TransData), "TransCrease");
 +              td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransCrease");
  
 -      copy_m3_m4(mtx, t->obedit->obmat);
 -      pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
 +              copy_m3_m4(mtx, tc->obedit->obmat);
 +              pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
  
 -      /* create data we need */
 -      if (t->mode == TFM_BWEIGHT) {
 -              BM_mesh_cd_flag_ensure(em->bm, BKE_mesh_from_object(t->obedit), ME_CDFLAG_EDGE_BWEIGHT);
 -              cd_edge_float_offset = CustomData_get_offset(&em->bm->edata, CD_BWEIGHT);
 -      }
 -      else { //if (t->mode == TFM_CREASE) {
 -              BLI_assert(t->mode == TFM_CREASE);
 -              BM_mesh_cd_flag_ensure(em->bm, BKE_mesh_from_object(t->obedit), ME_CDFLAG_EDGE_CREASE);
 -              cd_edge_float_offset = CustomData_get_offset(&em->bm->edata, CD_CREASE);
 -      }
 +              /* create data we need */
 +              if (t->mode == TFM_BWEIGHT) {
 +                      BM_mesh_cd_flag_ensure(em->bm, BKE_mesh_from_object(tc->obedit), ME_CDFLAG_EDGE_BWEIGHT);
 +                      cd_edge_float_offset = CustomData_get_offset(&em->bm->edata, CD_BWEIGHT);
 +              }
 +              else { //if (t->mode == TFM_CREASE) {
 +                      BLI_assert(t->mode == TFM_CREASE);
 +                      BM_mesh_cd_flag_ensure(em->bm, BKE_mesh_from_object(tc->obedit), ME_CDFLAG_EDGE_CREASE);
 +                      cd_edge_float_offset = CustomData_get_offset(&em->bm->edata, CD_CREASE);
 +              }
  
 -      BLI_assert(cd_edge_float_offset != -1);
 +              BLI_assert(cd_edge_float_offset != -1);
  
 -      BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
 -              if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && (BM_elem_flag_test(eed, BM_ELEM_SELECT) || is_prop_edit)) {
 -                      float *fl_ptr;
 -                      /* need to set center for center calculations */
 -                      mid_v3_v3v3(td->center, eed->v1->co, eed->v2->co);
 +              BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
 +                      if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && (BM_elem_flag_test(eed, BM_ELEM_SELECT) || is_prop_edit)) {
 +                              float *fl_ptr;
 +                              /* need to set center for center calculations */
 +                              mid_v3_v3v3(td->center, eed->v1->co, eed->v2->co);
  
 -                      td->loc = NULL;
 -                      if (BM_elem_flag_test(eed, BM_ELEM_SELECT))
 -                              td->flag = TD_SELECTED;
 -                      else
 -                              td->flag = 0;
 +                              td->loc = NULL;
 +                              if (BM_elem_flag_test(eed, BM_ELEM_SELECT))
 +                                      td->flag = TD_SELECTED;
 +                              else
 +                                      td->flag = 0;
  
 -                      copy_m3_m3(td->smtx, smtx);
 -                      copy_m3_m3(td->mtx, mtx);
 +                              copy_m3_m3(td->smtx, smtx);
 +                              copy_m3_m3(td->mtx, mtx);
  
 -                      td->ext = NULL;
 +                              td->ext = NULL;
  
 -                      fl_ptr = BM_ELEM_CD_GET_VOID_P(eed, cd_edge_float_offset);
 -                      td->val  =  fl_ptr;
 -                      td->ival = *fl_ptr;
 +                              fl_ptr = BM_ELEM_CD_GET_VOID_P(eed, cd_edge_float_offset);
 +                              td->val  =  fl_ptr;
 +                              td->ival = *fl_ptr;
  
 -                      td++;
 +                              td++;
 +                      }
                }
        }
  }
@@@ -574,7 -521,7 +574,7 @@@ static short apply_targetless_ik(Objec
        return apply;
  }
  
 -static void add_pose_transdata(TransInfo *t, bPoseChannel *pchan, Object *ob, TransData *td)
 +static void add_pose_transdata(TransInfo *t, bPoseChannel *pchan, Object *ob, TransDataContainer *tc, TransData *td)
  {
        Bone *bone = pchan->bone;
        float pmat[3][3], omat[3][3];
        normalize_m3(td->axismtx);
  
        if (ELEM(t->mode, TFM_BONESIZE, TFM_BONE_ENVELOPE_DIST)) {
 -              bArmature *arm = t->poseobj->data;
 +              bArmature *arm = tc->poseobj->data;
  
                if ((t->mode == TFM_BONE_ENVELOPE_DIST) || (arm->drawtype == ARM_ENVELOPE)) {
                        td->loc = NULL;
@@@ -748,11 -695,12 +748,11 @@@ static void bone_children_clear_transfl
  
  /* sets transform flags in the bones
   * returns total number of bones with BONE_TRANSFORM */
 -int count_set_pose_transflags(int *out_mode, short around, Object *ob)
 +int count_set_pose_transflags(Object *ob, const int mode, short around, bool has_translate_rotate[2])
  {
        bArmature *arm = ob->data;
        bPoseChannel *pchan;
        Bone *bone;
 -      int mode = *out_mode;
        int total = 0;
  
        for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
                }
        }
        /* now count, and check if we have autoIK or have to switch from translate to rotate */
 -      bool has_translation = false, has_rotation = false;
 -
        for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
                bone = pchan->bone;
                if (bone->flag & BONE_TRANSFORM) {
                        total++;
  
 -                      if (mode == TFM_TRANSLATION) {
 +                      if (has_translate_rotate != NULL) {
                                if (has_targetless_ik(pchan) == NULL) {
                                        if (pchan->parent && (pchan->bone->flag & BONE_CONNECTED)) {
 -                                              if (pchan->bone->flag & BONE_HINGE_CHILD_TRANSFORM)
 -                                                      has_translation = true;
 +                                              if (pchan->bone->flag & BONE_HINGE_CHILD_TRANSFORM) {
 +                                                      has_translate_rotate[0] = true;
 +                                              }
                                        }
                                        else {
 -                                              if ((pchan->protectflag & OB_LOCK_LOC) != OB_LOCK_LOC)
 -                                                      has_translation = true;
 +                                              if ((pchan->protectflag & OB_LOCK_LOC) != OB_LOCK_LOC) {
 +                                                      has_translate_rotate[0] = true;
 +                                              }
 +                                      }
 +                                      if ((pchan->protectflag & OB_LOCK_ROT) != OB_LOCK_ROT) {
 +                                              has_translate_rotate[1] = true;
                                        }
 -                                      if ((pchan->protectflag & OB_LOCK_ROT) != OB_LOCK_ROT)
 -                                              has_rotation = true;
                                }
 -                              else
 -                                      has_translation = true;
 +                              else {
 +                                      has_translate_rotate[1] = true;
 +                              }
                        }
                }
        }
  
 -      /* if there are no translatable bones, do rotation */
 -      if (mode == TFM_TRANSLATION && !has_translation) {
 -              if (has_rotation) {
 -                      *out_mode = TFM_ROTATION;
 -              }
 -              else {
 -                      *out_mode = TFM_RESIZE;
 -              }
 -      }
 -
        return total;
  }
  
@@@ -872,25 -828,25 +872,25 @@@ void transform_autoik_update(TransInfo 
                }
        }
  
 -      /* sanity checks (don't assume t->poseobj is set, or that it is an armature) */
 -      if (ELEM(NULL, t->poseobj, t->poseobj->pose))
 -              return;
 -
        /* apply to all pose-channels */
        bool changed = false;
 -      for (pchan = t->poseobj->pose->chanbase.first; pchan; pchan = pchan->next) {
 -              changed |= pchan_autoik_adjust(pchan, *chainlen);
 -      }
  
 -#ifdef WITH_LEGACY_DEPSGRAPH
 -      if (!DEG_depsgraph_use_legacy())
 -#endif
 -      {
 -              if (changed) {
 -                      /* TODO(sergey): Consider doing partial update only. */
 -                      DAG_relations_tag_update(bmain);
 +      FOREACH_TRANS_DATA_CONTAINER (t, tc) {
 +
 +              /* sanity checks (don't assume t->poseobj is set, or that it is an armature) */
 +              if (ELEM(NULL, tc->poseobj, tc->poseobj->pose)) {
 +                      continue;
 +              }
 +
 +              for (pchan = tc->poseobj->pose->chanbase.first; pchan; pchan = pchan->next) {
 +                      changed |= pchan_autoik_adjust(pchan, *chainlen);
                }
        }
 +
 +      if (changed) {
 +              /* TODO(sergey): Consider doing partial update only. */
 +              DEG_relations_tag_update(bmain);
 +      }
  }
  
  /* frees temporal IKs */
@@@ -899,7 -855,9 +899,7 @@@ static void pose_grab_with_ik_clear(Mai
        bKinematicConstraint *data;
        bPoseChannel *pchan;
        bConstraint *con, *next;
 -#ifdef WITH_LEGACY_DEPSGRAPH
 -      bool need_dependency_update = false;
 -#endif
 +      bool relations_changed = false;
  
        for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
                /* clear all temporary lock flags */
                        if (con->type == CONSTRAINT_TYPE_KINEMATIC) {
                                data = con->data;
                                if (data->flag & CONSTRAINT_IK_TEMP) {
 +                                      relations_changed = true;
 +
                                        /* iTaSC needs clear for removed constraints */
 -#ifdef WITH_LEGACY_DEPSGRAPH
 -                                      need_dependency_update = true;
 -#endif
                                        BIK_clear_data(ob->pose);
  
                                        BLI_remlink(&pchan->constraints, con);
                }
        }
  
 -#ifdef WITH_LEGACY_DEPSGRAPH
 -      if (!DEG_depsgraph_use_legacy() && need_dependency_update)
 -#endif
 -      {
 +      if (relations_changed) {
                /* TODO(sergey): Consider doing partial update only. */
 -              DAG_relations_tag_update(bmain);
 +              DEG_relations_tag_update(bmain);
        }
  }
  
@@@ -1086,126 -1048,89 +1086,126 @@@ static short pose_grab_with_ik(Main *bm
        /* iTaSC needs clear for new IK constraints */
        if (tot_ik) {
                BIK_clear_data(ob->pose);
 -#ifdef WITH_LEGACY_DEPSGRAPH
 -              if (!DEG_depsgraph_use_legacy())
 -#endif
 -              {
 -                      /* TODO(sergey): Consider doing partial update only. */
 -                      DAG_relations_tag_update(bmain);
 -              }
 +              /* TODO(sergey): Consider doing partial update only. */
 +              DEG_relations_tag_update(bmain);
        }
  
        return (tot_ik) ? 1 : 0;
  }
  
  
 -/* only called with pose mode active object now */
 -static void createTransPose(TransInfo *t, Object *ob)
 +/**
 + * When objects array is NULL, use 't->data_container' as is.
 + */
 +static void createTransPose(TransInfo *t, Object **objects, uint objects_len)
  {
 +      if (objects != NULL) {
 +              if (t->data_container) {
 +                      MEM_freeN(t->data_container);
 +              }
 +              t->data_container = MEM_callocN(sizeof(*t->data_container) * objects_len, __func__);
 +              t->data_container_len = objects_len;
 +              int th_index;
 +              FOREACH_TRANS_DATA_CONTAINER_INDEX (t, tc, th_index) {
 +                      tc->poseobj = objects[th_index];
 +              }
 +      }
        Main *bmain = CTX_data_main(t->context);
 -      bArmature *arm;
 -      bPoseChannel *pchan;
 -      TransData *td;
 -      TransDataExtension *tdx;
 -      short ik_on = 0;
 -      int i;
  
 -      t->total = 0;
 +      t->data_len_all = 0;
  
 -      /* check validity of state */
 -      arm = BKE_armature_from_object(ob);
 -      if ((arm == NULL) || (ob->pose == NULL)) return;
 +      bool has_translate_rotate_buf[2] = {false, false};
 +      bool *has_translate_rotate = (t->mode == TFM_TRANSLATION) ? has_translate_rotate_buf : NULL;
  
 -      if (arm->flag & ARM_RESTPOS) {
 -              if (ELEM(t->mode, TFM_DUMMY, TFM_BONESIZE) == 0) {
 -                      BKE_report(t->reports, RPT_ERROR, "Cannot change Pose when 'Rest Position' is enabled");
 -                      return;
 +      FOREACH_TRANS_DATA_CONTAINER (t, tc) {
 +              Object *ob = tc->poseobj;
 +
 +              bArmature *arm;
 +              short ik_on = 0;
 +
 +              /* check validity of state */
 +              arm = BKE_armature_from_object(tc->poseobj);
 +              if ((arm == NULL) || (ob->pose == NULL)) {
 +                      continue;
 +              }
 +
 +              if (arm->flag & ARM_RESTPOS) {
 +                      if (ELEM(t->mode, TFM_DUMMY, TFM_BONESIZE) == 0) {
 +                              BKE_report(t->reports, RPT_ERROR, "Cannot change Pose when 'Rest Position' is enabled");
 +                              return;
 +                      }
 +              }
 +
 +              /* do we need to add temporal IK chains? */
 +              if ((arm->flag & ARM_AUTO_IK) && t->mode == TFM_TRANSLATION) {
 +                      ik_on = pose_grab_with_ik(bmain, ob);
 +                      if (ik_on) t->flag |= T_AUTOIK;
                }
 +
 +              /* set flags and count total (warning, can change transform to rotate) */
 +              tc->data_len = count_set_pose_transflags(ob, t->mode, t->around, has_translate_rotate);
 +              /* len may be zero, skip next iteration. */
        }
  
 -      /* do we need to add temporal IK chains? */
 -      if ((arm->flag & ARM_AUTO_IK) && t->mode == TFM_TRANSLATION) {
 -              ik_on = pose_grab_with_ik(bmain, ob);
 -              if (ik_on) t->flag |= T_AUTOIK;
 +      /* if there are no translatable bones, do rotation */
 +      if ((t->mode == TFM_TRANSLATION) && !has_translate_rotate[0]) {
 +              if (has_translate_rotate[1]) {
 +                      t->mode = TFM_ROTATION;
 +              }
 +              else {
 +                      t->mode = TFM_RESIZE;
 +              }
        }
  
 -      /* set flags and count total (warning, can change transform to rotate) */
 -      t->total = count_set_pose_transflags(&t->mode, t->around, ob);
 +      FOREACH_TRANS_DATA_CONTAINER (t, tc) {
 +              if (tc->data_len == 0) {
 +                      continue;
 +              }
 +              Object *ob = tc->poseobj;
 +              TransData *td;
 +              TransDataExtension *tdx;
 +              short ik_on = 0;
 +              int i;
  
 -      if (t->total == 0) return;
 +              tc->poseobj = ob; /* we also allow non-active objects to be transformed, in weightpaint */
  
 -      t->flag |= T_POSE;
 -      t->poseobj = ob; /* we also allow non-active objects to be transformed, in weightpaint */
 +              /* init trans data */
 +              td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransPoseBone");
 +              tdx = tc->data_ext = MEM_callocN(tc->data_len * sizeof(TransDataExtension), "TransPoseBoneExt");
 +              for (i = 0; i < tc->data_len; i++, td++, tdx++) {
 +                      td->ext = tdx;
 +                      td->val = NULL;
 +              }
  
 -      /* disable PET, its not usable in pose mode yet [#32444] */
 -      t->flag &= ~T_PROP_EDIT_ALL;
 +              /* use pose channels to fill trans data */
 +              td = tc->data;
 +              for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
 +                      if (pchan->bone->flag & BONE_TRANSFORM) {
 +                              add_pose_transdata(t, pchan, ob, tc, td);
 +                              td++;
 +                      }
 +              }
  
 -      /* init trans data */
 -      td = t->data = MEM_callocN(t->total * sizeof(TransData), "TransPoseBone");
 -      tdx = t->ext = MEM_callocN(t->total * sizeof(TransDataExtension), "TransPoseBoneExt");
 -      for (i = 0; i < t->total; i++, td++, tdx++) {
 -              td->ext = tdx;
 -              td->val = NULL;
 -      }
 +              if (td != (tc->data + tc->data_len)) {
 +                      BKE_report(t->reports, RPT_DEBUG, "Bone selection count error");
 +              }
  
 -      /* use pose channels to fill trans data */
 -      td = t->data;
 -      for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
 -              if (pchan->bone->flag & BONE_TRANSFORM) {
 -                      add_pose_transdata(t, pchan, ob, td);
 -                      td++;
 +              /* initialize initial auto=ik chainlen's? */
 +              if (ik_on) {
 +                      transform_autoik_update(t, 0);
                }
        }
  
 -      if (td != (t->data + t->total)) {
 -              BKE_report(t->reports, RPT_DEBUG, "Bone selection count error");
 -      }
 +      t->flag |= T_POSE;
 +      /* disable PET, its not usable in pose mode yet [#32444] */
 +      t->flag &= ~T_PROP_EDIT_ALL;
  
 -      /* initialize initial auto=ik chainlen's? */
 -      if (ik_on) transform_autoik_update(t, 0);
  }
  
 -void restoreBones(TransInfo *t)
 +void restoreBones(TransDataContainer *tc)
  {
 -      bArmature *arm = t->obedit->data;
 -      BoneInitData *bid = t->custom.type.data;
 +      bArmature *arm = tc->obedit->data;
 +      BoneInitData *bid = tc->custom.type.data;
        EditBone *ebo;
  
        while (bid->bone) {
  /* ********************* armature ************** */
  static void createTransArmatureVerts(TransInfo *t)
  {
 -      EditBone *ebo, *eboflip;
 -      bArmature *arm = t->obedit->data;
 -      ListBase *edbo = arm->edbo;
 -      TransData *td, *td_old;
 -      float mtx[3][3], smtx[3][3], bonemat[3][3];
 -      bool mirror = ((arm->flag & ARM_MIRROR_EDIT) != 0);
 -      int total_mirrored = 0, i;
 -      int oldtot;
 -      BoneInitData *bid;
 -
 -      t->total = 0;
 -      for (ebo = edbo->first; ebo; ebo = ebo->next) {
 -              oldtot = t->total;
 -
 -              if (EBONE_VISIBLE(arm, ebo) && !(ebo->flag & BONE_EDITMODE_LOCKED)) {
 -                      if (ELEM(t->mode, TFM_BONESIZE, TFM_BONE_ENVELOPE_DIST)) {
 -                              if (ebo->flag & BONE_SELECTED)
 -                                      t->total++;
 -                      }
 -                      else if (t->mode == TFM_BONE_ROLL) {
 -                              if (ebo->flag & BONE_SELECTED)
 -                                      t->total++;
 +      FOREACH_TRANS_DATA_CONTAINER (t, tc) {
 +              EditBone *ebo, *eboflip;
 +              bArmature *arm = tc->obedit->data;
 +              ListBase *edbo = arm->edbo;
 +              TransData *td, *td_old;
 +              float mtx[3][3], smtx[3][3], bonemat[3][3];
 +              bool mirror = ((arm->flag & ARM_MIRROR_EDIT) != 0);
 +              int total_mirrored = 0, i;
 +              int oldtot;
 +              BoneInitData *bid;
 +
 +              tc->data_len = 0;
 +              for (ebo = edbo->first; ebo; ebo = ebo->next) {
 +                      oldtot = tc->data_len;
 +
 +                      if (EBONE_VISIBLE(arm, ebo) && !(ebo->flag & BONE_EDITMODE_LOCKED)) {
 +                              if (ELEM(t->mode, TFM_BONESIZE, TFM_BONE_ENVELOPE_DIST)) {
 +                                      if (ebo->flag & BONE_SELECTED)
 +                                              tc->data_len++;
 +                              }
 +                              else if (t->mode == TFM_BONE_ROLL) {
 +                                      if (ebo->flag & BONE_SELECTED)
 +                                              tc->data_len++;
 +                              }
 +                              else {
 +                                      if (ebo->flag & BONE_TIPSEL)
 +                                              tc->data_len++;
 +                                      if (ebo->flag & BONE_ROOTSEL)
 +                                              tc->data_len++;
 +                              }
                        }
 -                      else {
 -                              if (ebo->flag & BONE_TIPSEL)
 -                                      t->total++;
 -                              if (ebo->flag & BONE_ROOTSEL)
 -                                      t->total++;
 +
 +                      if (mirror && (oldtot < tc->data_len)) {
 +                              eboflip = ED_armature_ebone_get_mirrored(arm->edbo, ebo);
 +                              if (eboflip)
 +                                      total_mirrored++;
                        }
                }
  
 -              if (mirror && (oldtot < t->total)) {
 -                      eboflip = ED_armature_ebone_get_mirrored(arm->edbo, ebo);
 -                      if (eboflip)
 -                              total_mirrored++;
 +              if (!tc->data_len) {
 +                      continue;
                }
 -      }
  
 -      if (!t->total) return;
 +              transform_around_single_fallback(t);
  
 -      transform_around_single_fallback(t);
 +              copy_m3_m4(mtx, tc->obedit->obmat);
 +              pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
  
 -      copy_m3_m4(mtx, t->obedit->obmat);
 -      pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
 +              td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransEditBone");
  
 -      td = t->data = MEM_callocN(t->total * sizeof(TransData), "TransEditBone");
 +              if (mirror) {
 +                      tc->custom.type.data = bid = MEM_mallocN((total_mirrored + 1) * sizeof(BoneInitData), "BoneInitData");
 +                      tc->custom.type.use_free = true;
 +              }
  
 -      if (mirror) {
 -              t->custom.type.data = bid = MEM_mallocN((total_mirrored + 1) * sizeof(BoneInitData), "BoneInitData");
 -              t->custom.type.use_free = true;
 -      }
 +              i = 0;
  
 -      i = 0;
 +              for (ebo = edbo->first; ebo; ebo = ebo->next) {
 +                      td_old = td;
 +                      ebo->oldlength = ebo->length;   // length==0.0 on extrude, used for scaling radius of bone points
  
 -      for (ebo = edbo->first; ebo; ebo = ebo->next) {
 -              td_old = td;
 -              ebo->oldlength = ebo->length;   // length==0.0 on extrude, used for scaling radius of bone points
 +                      if (EBONE_VISIBLE(arm, ebo) && !(ebo->flag & BONE_EDITMODE_LOCKED)) {
 +                              if (t->mode == TFM_BONE_ENVELOPE) {
 +                                      if (ebo->flag & BONE_ROOTSEL) {
 +                                              td->val = &ebo->rad_head;
 +                                              td->ival = *td->val;
  
 -              if (EBONE_VISIBLE(arm, ebo) && !(ebo->flag & BONE_EDITMODE_LOCKED)) {
 -                      if (t->mode == TFM_BONE_ENVELOPE) {
 -                              if (ebo->flag & BONE_ROOTSEL) {
 -                                      td->val = &ebo->rad_head;
 -                                      td->ival = *td->val;
 +                                              copy_v3_v3(td->center, ebo->head);
 +                                              td->flag = TD_SELECTED;
  
 -                                      copy_v3_v3(td->center, ebo->head);
 -                                      td->flag = TD_SELECTED;
 +                                              copy_m3_m3(td->smtx, smtx);
 +                                              copy_m3_m3(td->mtx, mtx);
  
 -                                      copy_m3_m3(td->smtx, smtx);
 -                                      copy_m3_m3(td->mtx, mtx);
 +                                              td->loc = NULL;
 +                                              td->ext = NULL;
 +                                              td->ob = tc->obedit;
  
 -                                      td->loc = NULL;
 -                                      td->ext = NULL;
 -                                      td->ob = t->obedit;
 +                                              td++;
 +                                      }
 +                                      if (ebo->flag & BONE_TIPSEL) {
 +                                              td->val = &ebo->rad_tail;
 +                                              td->ival = *td->val;
 +                                              copy_v3_v3(td->center, ebo->tail);
 +                                              td->flag = TD_SELECTED;
  
 -                                      td++;
 -                              }
 -                              if (ebo->flag & BONE_TIPSEL) {
 -                                      td->val = &ebo->rad_tail;
 -                                      td->ival = *td->val;
 -                                      copy_v3_v3(td->center, ebo->tail);
 -                                      td->flag = TD_SELECTED;
 +                                              copy_m3_m3(td->smtx, smtx);
 +                                              copy_m3_m3(td->mtx, mtx);
  
 -                                      copy_m3_m3(td->smtx, smtx);
 -                                      copy_m3_m3(td->mtx, mtx);
 +                                              td->loc = NULL;
 +                                              td->ext = NULL;
 +                                              td->ob = tc->obedit;
  
 -                                      td->loc = NULL;
 -                                      td->ext = NULL;
 -                                      td->ob = t->obedit;
 +                                              td++;
 +                                      }
  
 -                                      td++;
                                }
 +                              else if (ELEM(t->mode, TFM_BONESIZE, TFM_BONE_ENVELOPE_DIST)) {
 +                                      if (ebo->flag & BONE_SELECTED) {
 +                                              if ((t->mode == TFM_BONE_ENVELOPE_DIST) || (arm->drawtype == ARM_ENVELOPE)) {
 +                                                      td->loc = NULL;
 +                                                      td->val = &ebo->dist;
 +                                                      td->ival = ebo->dist;
 +                                              }
 +                                              else {
 +                                                      // abusive storage of scale in the loc pointer :)
 +                                                      td->loc = &ebo->xwidth;
 +                                                      copy_v3_v3(td->iloc, td->loc);
 +                                                      td->val = NULL;
 +                                              }
 +                                              copy_v3_v3(td->center, ebo->head);
 +                                              td->flag = TD_SELECTED;
  
 -                      }
 -                      else if (ELEM(t->mode, TFM_BONESIZE, TFM_BONE_ENVELOPE_DIST)) {
 -                              if (ebo->flag & BONE_SELECTED) {
 -                                      if ((t->mode == TFM_BONE_ENVELOPE_DIST) || (arm->drawtype == ARM_ENVELOPE)) {
 -                                              td->loc = NULL;
 -                                              td->val = &ebo->dist;
 -                                              td->ival = ebo->dist;
 -                                      }
 -                                      else {
 -                                              // abusive storage of scale in the loc pointer :)
 -                                              td->loc = &ebo->xwidth;
 -                                              copy_v3_v3(td->iloc, td->loc);
 -                                              td->val = NULL;
 -                                      }
 -                                      copy_v3_v3(td->center, ebo->head);
 -                                      td->flag = TD_SELECTED;
 -
 -                                      /* use local bone matrix */
 -                                      ED_armature_ebone_to_mat3(ebo, bonemat);
 -                                      mul_m3_m3m3(td->mtx, mtx, bonemat);
 -                                      invert_m3_m3(td->smtx, td->mtx);
 +                                              /* use local bone matrix */
 +                                              ED_armature_ebone_to_mat3(ebo, bonemat);
 +                                              mul_m3_m3m3(td->mtx, mtx, bonemat);
 +                                              invert_m3_m3(td->smtx, td->mtx);
  
 -                                      copy_m3_m3(td->axismtx, td->mtx);
 -                                      normalize_m3(td->axismtx);
 +                                              copy_m3_m3(td->axismtx, td->mtx);
 +                                              normalize_m3(td->axismtx);
  
 -                                      td->ext = NULL;
 -                                      td->ob = t->obedit;
 +                                              td->ext = NULL;
 +                                              td->ob = tc->obedit;
  
 -                                      td++;
 +                                              td++;
 +                                      }
                                }
 -                      }
 -                      else if (t->mode == TFM_BONE_ROLL) {
 -                              if (ebo->flag & BONE_SELECTED) {
 -                                      td->loc = NULL;
 -                                      td->val = &(ebo->roll);
 -                                      td->ival = ebo->roll;
 +                              else if (t->mode == TFM_BONE_ROLL) {
 +                                      if (ebo->flag & BONE_SELECTED) {
 +                                              td->loc = NULL;
 +                                              td->val = &(ebo->roll);
 +                                              td->ival = ebo->roll;
  
 -                                      copy_v3_v3(td->center, ebo->head);
 -                                      td->flag = TD_SELECTED;
 +                                              copy_v3_v3(td->center, ebo->head);
 +                                              td->flag = TD_SELECTED;
  
 -                                      td->ext = NULL;
 -                                      td->ob = t->obedit;
 +                                              td->ext = NULL;
 +                                              td->ob = tc->obedit;
  
 -                                      td++;
 -                              }
 -                      }
 -                      else {
 -                              if (ebo->flag & BONE_TIPSEL) {
 -                                      copy_v3_v3(td->iloc, ebo->tail);
 -
 -                                      /* Don't allow single selected tips to have a modified center,
 -                                       * causes problem with snapping (see T45974).
 -                                       * However, in rotation mode, we want to keep that 'rotate bone around root with
 -                                       * only its tip selected' behavior (see T46325). */
 -                                      if ((t->around == V3D_AROUND_LOCAL_ORIGINS) &&
 -                                          ((t->mode == TFM_ROTATION) || (ebo->flag & BONE_ROOTSEL)))
 -                                      {
 -                                              copy_v3_v3(td->center, ebo->head);
 -                                      }
 -                                      else {
 -                                              copy_v3_v3(td->center, td->iloc);
 +                                              td++;
                                        }
 +                              }
 +                              else {
 +                                      if (ebo->flag & BONE_TIPSEL) {
 +                                              copy_v3_v3(td->iloc, ebo->tail);
 +
 +                                              /* Don't allow single selected tips to have a modified center,
 +                                               * causes problem with snapping (see T45974).
 +                                               * However, in rotation mode, we want to keep that 'rotate bone around root with
 +                                               * only its tip selected' behavior (see T46325). */
 +                                              if ((t->around == V3D_AROUND_LOCAL_ORIGINS) &&
 +                                                  ((t->mode == TFM_ROTATION) || (ebo->flag & BONE_ROOTSEL)))
 +                                              {
 +                                                      copy_v3_v3(td->center, ebo->head);
 +                                              }
 +                                              else {
 +                                                      copy_v3_v3(td->center, td->iloc);
 +                                              }
  
 -                                      td->loc = ebo->tail;
 -                                      td->flag = TD_SELECTED;
 -                                      if (ebo->flag & BONE_EDITMODE_LOCKED)
 -                                              td->protectflag = OB_LOCK_LOC | OB_LOCK_ROT | OB_LOCK_SCALE;
 +                                              td->loc = ebo->tail;
 +                                              td->flag = TD_SELECTED;
 +                                              if (ebo->flag & BONE_EDITMODE_LOCKED)
 +                                                      td->protectflag = OB_LOCK_LOC | OB_LOCK_ROT | OB_LOCK_SCALE;
  
 -                                      copy_m3_m3(td->smtx, smtx);
 -                                      copy_m3_m3(td->mtx, mtx);
 +                                              copy_m3_m3(td->smtx, smtx);
 +                                              copy_m3_m3(td->mtx, mtx);
  
 -                                      ED_armature_ebone_to_mat3(ebo, td->axismtx);
 +                                              ED_armature_ebone_to_mat3(ebo, td->axismtx);
  
 -                                      if ((ebo->flag & BONE_ROOTSEL) == 0) {
 -                                              td->extra = ebo;
 -                                              td->ival = ebo->roll;
 -                                      }
 +                                              if ((ebo->flag & BONE_ROOTSEL) == 0) {
 +                                                      td->extra = ebo;
 +                                                      td->ival = ebo->roll;
 +                                              }
  
 -                                      td->ext = NULL;
 -                                      td->val = NULL;
 -                                      td->ob = t->obedit;
 +                                              td->ext = NULL;
 +                                              td->val = NULL;
 +                                              td->ob = tc->obedit;
  
 -                                      td++;
 -                              }
 -                              if (ebo->flag & BONE_ROOTSEL) {
 -                                      copy_v3_v3(td->iloc, ebo->head);
 -                                      copy_v3_v3(td->center, td->iloc);
 -                                      td->loc = ebo->head;
 -                                      td->flag = TD_SELECTED;
 -                                      if (ebo->flag & BONE_EDITMODE_LOCKED)
 -                                              td->protectflag = OB_LOCK_LOC | OB_LOCK_ROT | OB_LOCK_SCALE;
 +                                              td++;
 +                                      }
 +                                      if (ebo->flag & BONE_ROOTSEL) {
 +                                              copy_v3_v3(td->iloc, ebo->head);
 +                                              copy_v3_v3(td->center, td->iloc);
 +                                              td->loc = ebo->head;
 +                                              td->flag = TD_SELECTED;
 +                                              if (ebo->flag & BONE_EDITMODE_LOCKED)
 +                                                      td->protectflag = OB_LOCK_LOC | OB_LOCK_ROT | OB_LOCK_SCALE;
  
 -                                      copy_m3_m3(td->smtx, smtx);
 -                                      copy_m3_m3(td->mtx, mtx);
 +                                              copy_m3_m3(td->smtx, smtx);
 +                                              copy_m3_m3(td->mtx, mtx);
  
 -                                      ED_armature_ebone_to_mat3(ebo, td->axismtx);
 +                                              ED_armature_ebone_to_mat3(ebo, td->axismtx);
  
 -                                      td->extra = ebo; /* to fix roll */
 -                                      td->ival = ebo->roll;
 +                                              td->extra = ebo; /* to fix roll */
 +                                              td->ival = ebo->roll;
  
 -                                      td->ext = NULL;
 -                                      td->val = NULL;
 -                                      td->ob = t->obedit;
 +                                              td->ext = NULL;
 +                                              td->val = NULL;
 +                                              td->ob = tc->obedit;
  
 -                                      td++;
 +                                              td++;
 +                                      }
                                }
                        }
 -              }
  
 -              if (mirror && (td_old != td)) {
 -                      eboflip = ED_armature_ebone_get_mirrored(arm->edbo, ebo);
 -                      if (eboflip) {
 -                              bid[i].bone = eboflip;
 -                              bid[i].dist = eboflip->dist;
 -                              bid[i].rad_tail = eboflip->rad_tail;
 -                              bid[i].roll = eboflip->roll;
 -                              bid[i].xwidth = eboflip->xwidth;
 -                              bid[i].zwidth = eboflip->zwidth;
 -                              copy_v3_v3(bid[i].head, eboflip->head);
 -                              copy_v3_v3(bid[i].tail, eboflip->tail);
 -                              i++;
 +                      if (mirror && (td_old != td)) {
 +                              eboflip = ED_armature_ebone_get_mirrored(arm->edbo, ebo);
 +                              if (eboflip) {
 +                                      bid[i].bone = eboflip;
 +                                      bid[i].dist = eboflip->dist;
 +                                      bid[i].rad_tail = eboflip->rad_tail;
 +                                      bid[i].roll = eboflip->roll;
 +                                      bid[i].xwidth = eboflip->xwidth;
 +                                      bid[i].zwidth = eboflip->zwidth;
 +                                      copy_v3_v3(bid[i].head, eboflip->head);
 +                                      copy_v3_v3(bid[i].tail, eboflip->tail);
 +                                      i++;
 +                              }
                        }
                }
 -      }
  
 -      if (mirror) {
 -              /* trick to terminate iteration */
 -              bid[total_mirrored].bone = NULL;
 +              if (mirror) {
 +                      /* trick to terminate iteration */
 +                      bid[total_mirrored].bone = NULL;
 +              }
        }
  }
  
  
  static void createTransMBallVerts(TransInfo *t)
  {
 -      MetaBall *mb = (MetaBall *)t->obedit->data;
 -      MetaElem *ml;
 -      TransData *td;
 -      TransDataExtension *tx;
 -      float mtx[3][3], smtx[3][3];
 -      int count = 0, countsel = 0;
 -      const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
 -
 -      /* count totals */
 -      for (ml = mb->editelems->first; ml; ml = ml->next) {
 -              if (ml->flag & SELECT) countsel++;
 -              if (is_prop_edit) count++;
 -      }
 +      FOREACH_TRANS_DATA_CONTAINER (t, tc) {
 +              MetaBall *mb = (MetaBall *)tc->obedit->data;
 +              MetaElem *ml;
 +              TransData *td;
 +              TransDataExtension *tx;
 +              float mtx[3][3], smtx[3][3];
 +              int count = 0, countsel = 0;
 +              const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
 +
 +              /* count totals */
 +              for (ml = mb->editelems->first; ml; ml = ml->next) {
 +                      if (ml->flag & SELECT) countsel++;
 +                      if (is_prop_edit) count++;
 +              }
  
 -      /* note: in prop mode we need at least 1 selected */
 -      if (countsel == 0) return;
 +              /* note: in prop mode we need at least 1 selected */
 +              if (countsel == 0) {
 +                      continue;
 +              }
  
 -      if (is_prop_edit) t->total = count;
 -      else t->total = countsel;
 +              if (is_prop_edit) tc->data_len = count;
 +              else tc->data_len = countsel;
  
 -      td = t->data = MEM_callocN(t->total * sizeof(TransData), "TransObData(MBall EditMode)");
 -      tx = t->ext = MEM_callocN(t->total * sizeof(TransDataExtension), "MetaElement_TransExtension");
 +              td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransObData(MBall EditMode)");
 +              tx = tc->data_ext = MEM_callocN(tc->data_len * sizeof(TransDataExtension), "MetaElement_TransExtension");
  
 -      copy_m3_m4(mtx, t->obedit->obmat);
 -      pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
 +              copy_m3_m4(mtx, tc->obedit->obmat);
 +              pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
  
 -      for (ml = mb->editelems->first; ml; ml = ml->next) {
 -              if (is_prop_edit || (ml->flag & SELECT)) {
 -                      td->loc = &ml->x;
 -                      copy_v3_v3(td->iloc, td->loc);
 -                      copy_v3_v3(td->center, td->loc);
 +              for (ml = mb->editelems->first; ml; ml = ml->next) {
 +                      if (is_prop_edit || (ml->flag & SELECT)) {
 +                              td->loc = &ml->x;
 +                              copy_v3_v3(td->iloc, td->loc);
 +                              copy_v3_v3(td->center, td->loc);
  
 -                      quat_to_mat3(td->axismtx, ml->quat);
 +                              quat_to_mat3(td->axismtx, ml->quat);
  
 -                      if (ml->flag & SELECT) td->flag = TD_SELECTED | TD_USEQUAT | TD_SINGLESIZE;
 -                      else td->flag = TD_USEQUAT;
 +                              if (ml->flag & SELECT) td->flag = TD_SELECTED | TD_USEQUAT | TD_SINGLESIZE;
 +                              else td->flag = TD_USEQUAT;
  
 -                      copy_m3_m3(td->smtx, smtx);
 -                      copy_m3_m3(td->mtx, mtx);
 +                              copy_m3_m3(td->smtx, smtx);
 +                              copy_m3_m3(td->mtx, mtx);
  
 -                      td->ext = tx;
 +                              td->ext = tx;
  
 -                      /* Radius of MetaElem (mass of MetaElem influence) */
 -                      if (ml->flag & MB_SCALE_RAD) {
 -                              td->val = &ml->rad;
 -                              td->ival = ml->rad;
 -                      }
 -                      else {
 -                              td->val = &ml->s;
 -                              td->ival = ml->s;
 -                      }
 +                              /* Radius of MetaElem (mass of MetaElem influence) */
 +                              if (ml->flag & MB_SCALE_RAD) {
 +                                      td->val = &ml->rad;
 +                                      td->ival = ml->rad;
 +                              }
 +                              else {
 +                                      td->val = &ml->s;
 +                                      td->ival = ml->s;
 +                              }
  
 -                      /* expx/expy/expz determine "shape" of some MetaElem types */
 -                      tx->size = &ml->expx;
 -                      tx->isize[0] = ml->expx;
 -                      tx->isize[1] = ml->expy;
 -                      tx->isize[2] = ml->expz;
 +                              /* expx/expy/expz determine "shape" of some MetaElem types */
 +                              tx->size = &ml->expx;
 +                              tx->isize[0] = ml->expx;
 +                              tx->isize[1] = ml->expy;
 +                              tx->isize[2] = ml->expz;
  
 -                      /* quat is used for rotation of MetaElem */
 -                      tx->quat = ml->quat;
 -                      copy_qt_qt(tx->iquat, ml->quat);
 +                              /* quat is used for rotation of MetaElem */
 +                              tx->quat = ml->quat;
 +                              copy_qt_qt(tx->iquat, ml->quat);
  
 -                      tx->rot = NULL;
 +                              tx->rot = NULL;
  
 -                      td++;
 -                      tx++;
 +                              td++;
 +                              tx++;
 +                      }
                }
        }
  }
@@@ -1655,277 -1572,271 +1655,277 @@@ static int bezt_select_to_transform_tri
  
  static void createTransCurveVerts(TransInfo *t)
  {
 -      Curve *cu = t->obedit->data;
 -      TransData *td = NULL;
 -      Nurb *nu;
 -      BezTriple *bezt;
 -      BPoint *bp;
 -      float mtx[3][3], smtx[3][3];
 -      int a;
 -      int count = 0, countsel = 0;
 -      const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
 -      short hide_handles = (cu->drawflag & CU_HIDE_HANDLES);
 -      ListBase *nurbs;
 -
 -      /* to be sure */
 -      if (cu->editnurb == NULL) return;
  
  #define SEL_F1 (1 << 0)
  #define SEL_F2 (1 << 1)
  #define SEL_F3 (1 << 2)
  
 -      /* count total of vertices, check identical as in 2nd loop for making transdata! */
 -      nurbs = BKE_curve_editNurbs_get(cu);
 -      for (nu = nurbs->first; nu; nu = nu->next) {
 -              if (nu->type == CU_BEZIER) {
 -                      for (a = 0, bezt = nu->bezt; a < nu->pntsu; a++, bezt++) {
 -                              if (bezt->hide == 0) {
 -                                      const int bezt_tx = bezt_select_to_transform_triple_flag(bezt, hide_handles);
 -                                      if (bezt_tx & SEL_F1) { countsel++; }
 -                                      if (bezt_tx & SEL_F2) { countsel++; }
 -                                      if (bezt_tx & SEL_F3) { countsel++; }
 -                                      if (is_prop_edit) count += 3;
 +      FOREACH_TRANS_DATA_CONTAINER (t, tc) {
  
 +              Curve *cu = tc->obedit->data;
 +              TransData *td = NULL;
 +              Nurb *nu;
 +              BezTriple *bezt;
 +              BPoint *bp;
 +              float mtx[3][3], smtx[3][3];
 +              int a;
 +              int count = 0, countsel = 0;
 +              const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
 +              short hide_handles = (cu->drawflag & CU_HIDE_HANDLES);
 +              ListBase *nurbs;
 +
 +              /* to be sure */
 +              if (cu->editnurb == NULL) return;
 +
 +              /* count total of vertices, check identical as in 2nd loop for making transdata! */
 +              nurbs = BKE_curve_editNurbs_get(cu);
 +              for (nu = nurbs->first; nu; nu = nu->next) {
 +                      if (nu->type == CU_BEZIER) {
 +                              for (a = 0, bezt = nu->bezt; a < nu->pntsu; a++, bezt++) {
 +                                      if (bezt->hide == 0) {
 +                                              const int bezt_tx = bezt_select_to_transform_triple_flag(bezt, hide_handles);
 +                                              if (bezt_tx & SEL_F1) { countsel++; }
 +                                              if (bezt_tx & SEL_F2) { countsel++; }
 +                                              if (bezt_tx & SEL_F3) { countsel++; }
 +                                              if (is_prop_edit) count += 3;
 +
 +                                      }
                                }
                        }
 -              }
 -              else {
 -                      for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a > 0; a--, bp++) {
 -                              if (bp->hide == 0) {
 -                                      if (is_prop_edit) count++;
 -                                      if (bp->f1 & SELECT) countsel++;
 +                      else {
 +                              for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a > 0; a--, bp++) {
 +                                      if (bp->hide == 0) {
 +                                              if (is_prop_edit) count++;
 +                                              if (bp->f1 & SELECT) countsel++;
 +                                      }
                                }
                        }
                }
 -      }
 -      /* note: in prop mode we need at least 1 selected */
 -      if (countsel == 0) return;
 +              /* note: in prop mode we need at least 1 selected */
 +              if (countsel == 0) {
 +                      tc->data_len = 0;
 +                      continue;
 +              }
  
 -      if (is_prop_edit) t->total = count;
 -      else t->total = countsel;
 -      t->data = MEM_callocN(t->total * sizeof(TransData), "TransObData(Curve EditMode)");
 +              if (is_prop_edit) tc->data_len = count;
 +              else tc->data_len = countsel;
 +              tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransObData(Curve EditMode)");
  
 -      transform_around_single_fallback(t);
 +              transform_around_single_fallback(t);
  
 -      copy_m3_m4(mtx, t->obedit->obmat);
 -      pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
 +              copy_m3_m4(mtx, tc->obedit->obmat);
 +              pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
  
 -      td = t->data;
 -      for (nu = nurbs->first; nu; nu = nu->next) {
 -              if (nu->type == CU_BEZIER) {
 -                      TransData *head, *tail;
 -                      head = tail = td;
 -                      for (a = 0, bezt = nu->bezt; a < nu->pntsu; a++, bezt++) {
 -                              if (bezt->hide == 0) {
 -                                      TransDataCurveHandleFlags *hdata = NULL;
 -                                      float axismtx[3][3];
 +              td = tc->data;
 +              for (nu = nurbs->first; nu; nu = nu->next) {
 +                      if (nu->type == CU_BEZIER) {
 +                              TransData *head, *tail;
 +                              head = tail = td;
 +                              for (a = 0, bezt = nu->bezt; a < nu->pntsu; a++, bezt++) {
 +                                      if (bezt->hide == 0) {
 +                                              TransDataCurveHandleFlags *hdata = NULL;
 +                                              float axismtx[3][3];
  
 -                                      if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
 -                                              float normal[3], plane[3];
 +                                              if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
 +                                                      float normal[3], plane[3];
  
 -                                              BKE_nurb_bezt_calc_normal(nu, bezt, normal);
 -                                              BKE_nurb_bezt_calc_plane(nu, bezt, plane);
 +                                                      BKE_nurb_bezt_calc_normal(nu, bezt, normal);
 +                                                      BKE_nurb_bezt_calc_plane(nu, bezt, plane);
  
 -                                              if (createSpaceNormalTangent(axismtx, normal, plane)) {
 -                                                      /* pass */
 -                                              }
 -                                              else {
 -                                                      normalize_v3(normal);
 -                                                      axis_dominant_v3_to_m3(axismtx, normal);
 -                                                      invert_m3(axismtx);
 +                                                      if (createSpaceNormalTangent(axismtx, normal, plane)) {
 +                                                              /* pass */
 +                                                      }
 +                                                      else {
 +                                                              normalize_v3(normal);
 +                                                              axis_dominant_v3_to_m3(axismtx, normal);
 +                                                              invert_m3(axismtx);
 +                                                      }
                                                }
 -                                      }
  
 -                                      /* Elements that will be transform (not always a match to selection). */
 -                                      const int bezt_tx = bezt_select_to_transform_triple_flag(bezt, hide_handles);
 +                                              /* Elements that will be transform (not always a match to selection). */
 +                                              const int bezt_tx = bezt_select_to_transform_triple_flag(bezt, hide_handles);
 +
 +                                              if (is_prop_edit || bezt_tx & SEL_F1) {
 +                                                      copy_v3_v3(td->iloc, bezt->vec[0]);
 +                                                      td->loc = bezt->vec[0];
 +                                                      copy_v3_v3(td->center, bezt->vec[(hide_handles ||
 +                                                                                        (t->around == V3D_AROUND_LOCAL_ORIGINS) ||
 +                                                                                        (bezt->f2 & SELECT)) ? 1 : 0]);
 +                                                      if (hide_handles) {
 +                                                              if (bezt->f2 & SELECT) td->flag = TD_SELECTED;
 +                                                              else td->flag = 0;
 +                                                      }
 +                                                      else {
 +                                                              if (bezt->f1 & SELECT) td->flag = TD_SELECTED;
 +                                                              else td->flag = 0;
 +                                                      }
 +                                                      td->ext = NULL;
 +                                                      td->val = NULL;
  
 -                                      if (is_prop_edit || bezt_tx & SEL_F1) {
 -                                              copy_v3_v3(td->iloc, bezt->vec[0]);
 -                                              td->loc = bezt->vec[0];
 -                                              copy_v3_v3(td->center, bezt->vec[(hide_handles ||
 -                                                                                (t->around == V3D_AROUND_LOCAL_ORIGINS) ||
 -                                                                                (bezt->f2 & SELECT)) ? 1 : 0]);
 -                                              if (hide_handles) {
 -                                                      if (bezt->f2 & SELECT) td->flag = TD_SELECTED;
 -                                                      else td->flag = 0;
 -                                              }
 -                                              else {
 -                                                      if (bezt->f1 & SELECT) td->flag = TD_SELECTED;
 -                                                      else td->flag = 0;
 -                                              }
 -                                              td->ext = NULL;
 -                                              td->val = NULL;
 +                                                      hdata = initTransDataCurveHandles(td, bezt);
  
 -                                              hdata = initTransDataCurveHandles(td, bezt);
 +                                                      copy_m3_m3(td->smtx, smtx);
 +                                                      copy_m3_m3(td->mtx, mtx);
 +                                                      if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
 +                                                              copy_m3_m3(td->axismtx, axismtx);
 +                                                      }
  
 -                                              copy_m3_m3(td->smtx, smtx);
 -                                              copy_m3_m3(td->mtx, mtx);
 -                                              if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
 -                                                      copy_m3_m3(td->axismtx, axismtx);
 +                                                      td++;
 +                                                      count++;
 +                                                      tail++;
                                                }
  
 -                                              td++;
 -                                              count++;
 -                                              tail++;
 -                                      }
 +                                              /* This is the Curve Point, the other two are handles */
 +                                              if (is_prop_edit || bezt_tx & SEL_F2) {
 +                                                      copy_v3_v3(td->iloc, bezt->vec[1]);
 +                                                      td->loc = bezt->vec[1];
 +                                                      copy_v3_v3(td->center, td->loc);
 +                                                      if (bezt->f2 & SELECT) td->flag = TD_SELECTED;
 +                                                      else td->flag = 0;
 +                                                      td->ext = NULL;
  
 -                                      /* This is the Curve Point, the other two are handles */
 -                                      if (is_prop_edit || bezt_tx & SEL_F2) {
 -                                              copy_v3_v3(td->iloc, bezt->vec[1]);
 -                                              td->loc = bezt->vec[1];
 -                                              copy_v3_v3(td->center, td->loc);
 -                                              if (bezt->f2 & SELECT) td->flag = TD_SELECTED;
 -                                              else td->flag = 0;
 -                                              td->ext = NULL;
 +                                                      if (t->mode == TFM_CURVE_SHRINKFATTEN) { /* || t->mode==TFM_RESIZE) {*/ /* TODO - make points scale */
 +                                                              td->val = &(bezt->radius);
 +                                                              td->ival = bezt->radius;
 +                                                      }
 +                                                      else if (t->mode == TFM_TILT) {
 +                                                              td->val = &(bezt->alfa);
 +                                                              td->ival = bezt->alfa;
 +                                                      }
 +                                                      else {
 +                                                              td->val = NULL;
 +                                                      }
  
 -                                              if (t->mode == TFM_CURVE_SHRINKFATTEN) { /* || t->mode==TFM_RESIZE) {*/ /* TODO - make points scale */
 -                                                      td->val = &(bezt->radius);
 -                                                      td->ival = bezt->radius;
 -                                              }
 -                                              else if (t->mode == TFM_TILT) {
 -                                                      td->val = &(bezt->alfa);
 -                                                      td->ival = bezt->alfa;
 -                                              }
 -                                              else {
 -                                                      td->val = NULL;
 -                                              }
 +                                                      copy_m3_m3(td->smtx, smtx);
 +                                                      copy_m3_m3(td->mtx, mtx);
 +                                                      if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
 +                                                              copy_m3_m3(td->axismtx, axismtx);
 +                                                      }
  
 -                                              copy_m3_m3(td->smtx, smtx);
 -                                              copy_m3_m3(td->mtx, mtx);
 -                                              if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
 -                                                      copy_m3_m3(td->axismtx, axismtx);
 +                                                      if ((bezt_tx & SEL_F1) == 0 && (bezt_tx & SEL_F3) == 0)
 +                                                              /* If the middle is selected but the sides arnt, this is needed */
 +                                                              if (hdata == NULL) { /* if the handle was not saved by the previous handle */
 +                                                                      hdata = initTransDataCurveHandles(td, bezt);
 +                                                              }
 +
 +                                                      td++;
 +                                                      count++;
 +                                                      tail++;
                                                }
 +                                              if (is_prop_edit || bezt_tx & SEL_F3) {
 +                                                      copy_v3_v3(td->iloc, bezt->vec[2]);
 +                                                      td->loc = bezt->vec[2];
 +                                                      copy_v3_v3(td->center, bezt->vec[(hide_handles ||
 +                                                                                        (t->around == V3D_AROUND_LOCAL_ORIGINS) ||
 +                                                                                        (bezt->f2 & SELECT)) ? 1 : 2]);
 +                                                      if (hide_handles) {
 +                                                              if (bezt->f2 & SELECT) td->flag = TD_SELECTED;
 +                                                              else td->flag = 0;
 +                                                      }
 +                                                      else {
 +                                                              if (bezt->f3 & SELECT) td->flag = TD_SELECTED;
 +                                                              else td->flag = 0;
 +                                                      }
 +                                                      td->ext = NULL;
 +                                                      td->val = NULL;
  
 -                                              if ((bezt_tx & SEL_F1) == 0 && (bezt_tx & SEL_F3) == 0)
 -                                                      /* If the middle is selected but the sides arnt, this is needed */
                                                        if (hdata == NULL) { /* if the handle was not saved by the previous handle */
                                                                hdata = initTransDataCurveHandles(td, bezt);
                                                        }
  
 -                                              td++;
 -                                              count++;
 -                                              tail++;
 -                                      }
 -                                      if (is_prop_edit || bezt_tx & SEL_F3) {
 -                                              copy_v3_v3(td->iloc, bezt->vec[2]);
 -                                              td->loc = bezt->vec[2];
 -                                              copy_v3_v3(td->center, bezt->vec[(hide_handles ||
 -                                                                                (t->around == V3D_AROUND_LOCAL_ORIGINS) ||
 -                                                                                (bezt->f2 & SELECT)) ? 1 : 2]);
 -                                              if (hide_handles) {
 -                                                      if (bezt->f2 & SELECT) td->flag = TD_SELECTED;
 -                                                      else td->flag = 0;
 -                                              }
 -                                              else {
 -                                                      if (bezt->f3 & SELECT) td->flag = TD_SELECTED;
 -                                                      else td->flag = 0;
 -                                              }
 -                                              td->ext = NULL;
 -                                              td->val = NULL;
 -
 -                                              if (hdata == NULL) { /* if the handle was not saved by the previous handle */
 -                                                      hdata = initTransDataCurveHandles(td, bezt);
 -                                              }
 +                                                      copy_m3_m3(td->smtx, smtx);
 +                                                      copy_m3_m3(td->mtx, mtx);
 +                                                      if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
 +                                                              copy_m3_m3(td->axismtx, axismtx);
 +                                                      }
  
 -                                              copy_m3_m3(td->smtx, smtx);
 -                                              copy_m3_m3(td->mtx, mtx);
 -                                              if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
 -                                                      copy_m3_m3(td->axismtx, axismtx);
 +                                                      td++;
 +                                                      count++;
 +                                                      tail++;
                                                }
  
 -                                              td++;
 -                                              count++;
 -                                              tail++;
 +                                              (void)hdata;  /* quiet warning */
 +                                      }
 +                                      else if (is_prop_edit && head != tail) {
 +                                              calc_distanceCurveVerts(head, tail - 1);
 +                                              head = tail;
                                        }
 -
 -                                      (void)hdata;  /* quiet warning */
                                }
 -                              else if (is_prop_edit && head != tail) {
 +                              if (is_prop_edit && head != tail)
                                        calc_distanceCurveVerts(head, tail - 1);
 -                                      head = tail;
 -                              }
 -                      }
 -                      if (is_prop_edit && head != tail)
 -                              calc_distanceCurveVerts(head, tail - 1);
  
 -                      /* TODO - in the case of tilt and radius we can also avoid allocating the initTransDataCurveHandles
 -                       * but for now just don't change handle types */
 -                      if (ELEM(t->mode, TFM_CURVE_SHRINKFATTEN, TFM_TILT, TFM_DUMMY) == 0) {
 -                              /* sets the handles based on their selection, do this after the data is copied to the TransData */
 -                              BKE_nurb_handles_test(nu, !hide_handles);
 +                              /* TODO - in the case of tilt and radius we can also avoid allocating the initTransDataCurveHandles
 +                               * but for now just don't change handle types */
 +                              if (ELEM(t->mode, TFM_CURVE_SHRINKFATTEN, TFM_TILT, TFM_DUMMY) == 0) {
 +                                      /* sets the handles based on their selection, do this after the data is copied to the TransData */
 +                                      BKE_nurb_handles_test(nu, !hide_handles);
 +                              }
                        }
 -              }
 -              else {
 -                      TransData *head, *tail;
 -                      head = tail = td;
 -                      for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a > 0; a--, bp++) {
 -                              if (bp->hide == 0) {
 -                                      if (is_prop_edit || (bp->f1 & SELECT)) {
 -                                              float axismtx[3][3];
 -
 -                                              if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
 -                                                      if (nu->pntsv == 1) {
 -                                                              float normal[3], plane[3];
 -
 -                                                              BKE_nurb_bpoint_calc_normal(nu, bp, normal);
 -                                                              BKE_nurb_bpoint_calc_plane(nu, bp, plane);
 -
 -                                                              if (createSpaceNormalTangent(axismtx, normal, plane)) {
 -                                                                      /* pass */
 -                                                              }
 -                                                              else {
 -                                                                      normalize_v3(normal);
 -                                                                      axis_dominant_v3_to_m3(axismtx, normal);
 -                                                                      invert_m3(axismtx);
 +                      else {
 +                              TransData *head, *tail;
 +                              head = tail = td;
 +                              for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a > 0; a--, bp++) {
 +                                      if (bp->hide == 0) {
 +                                              if (is_prop_edit || (bp->f1 & SELECT)) {
 +                                                      float axismtx[3][3];
 +
 +                                                      if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
 +                                                              if (nu->pntsv == 1) {
 +                                                                      float normal[3], plane[3];
 +
 +                                                                      BKE_nurb_bpoint_calc_normal(nu, bp, normal);
 +                                                                      BKE_nurb_bpoint_calc_plane(nu, bp, plane);
 +
 +                                                                      if (createSpaceNormalTangent(axismtx, normal, plane)) {
 +                                                                              /* pass */
 +                                                                      }
 +                                                                      else {
 +                                                                              normalize_v3(normal);
 +                                                                              axis_dominant_v3_to_m3(axismtx, normal);
 +                                                                              invert_m3(axismtx);
 +                                                                      }
                                                                }
                                                        }
 -                                              }
  
 -                                              copy_v3_v3(td->iloc, bp->vec);
 -                                              td->loc = bp->vec;
 -                                              copy_v3_v3(td->center, td->loc);
 -                                              if (bp->f1 & SELECT) td->flag = TD_SELECTED;
 -                                              else td->flag = 0;
 -                                              td->ext = NULL;
 +                                                      copy_v3_v3(td->iloc, bp->vec);
 +                                                      td->loc = bp->vec;
 +                                                      copy_v3_v3(td->center, td->loc);
 +                                                      if (bp->f1 & SELECT) td->flag = TD_SELECTED;
 +                                                      else td->flag = 0;
 +                                                      td->ext = NULL;
  
 -                                              if (t->mode == TFM_CURVE_SHRINKFATTEN || t->mode == TFM_RESIZE) {
 -                                                      td->val = &(bp->radius);
 -                                                      td->ival = bp->radius;
 -                                              }
 -                                              else {
 -                                                      td->val = &(bp->alfa);
 -                                                      td->ival = bp->alfa;
 -                                              }
 +                                                      if (t->mode == TFM_CURVE_SHRINKFATTEN || t->mode == TFM_RESIZE) {
 +                                                              td->val = &(bp->radius);
 +                                                              td->ival = bp->radius;
 +                                                      }
 +                                                      else {
 +                                                              td->val = &(bp->alfa);
 +                                                              td->ival = bp->alfa;
 +                                                      }
  
 -                                              copy_m3_m3(td->smtx, smtx);
 -                                              copy_m3_m3(td->mtx, mtx);
 -                                              if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
 -                                                      if (nu->pntsv == 1) {
 -                                                              copy_m3_m3(td->axismtx, axismtx);
 +                                                      copy_m3_m3(td->smtx, smtx);
 +                                                      copy_m3_m3(td->mtx, mtx);
 +                                                      if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
 +                                                              if (nu->pntsv == 1) {
 +                                                                      copy_m3_m3(td->axismtx, axismtx);
 +                                                              }
                                                        }
 -                                              }
  
 -                                              td++;
 -                                              count++;
 -                                              tail++;
 +                                                      td++;
 +                                                      count++;
 +                                                      tail++;
 +                                              }
 +                                      }
 +                                      else if (is_prop_edit && head != tail) {
 +                                              calc_distanceCurveVerts(head, tail - 1);
 +                                              head = tail;
                                        }
                                }
 -                              else if (is_prop_edit && head != tail) {
 +                              if (is_prop_edit && head != tail)
                                        calc_distanceCurveVerts(head, tail - 1);
 -                                      head = tail;
 -                              }
                        }
 -                      if (is_prop_edit && head != tail)
 -                              calc_distanceCurveVerts(head, tail - 1);
                }
        }
 -
  #undef SEL_F1
  #undef SEL_F2
  #undef SEL_F3
  
  static void createTransLatticeVerts(TransInfo *t)
  {
 -      Lattice *latt = ((Lattice *)t->obedit->data)->editlatt->latt;
 -      TransData *td = NULL;
 -      BPoint *bp;
 -      float mtx[3][3], smtx[3][3];
 -      int a;
 -      int count = 0, countsel = 0;
 -      const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
 +      FOREACH_TRANS_DATA_CONTAINER (t, tc) {
  
 -      bp = latt->def;
 -      a  = latt->pntsu * latt->pntsv * latt->pntsw;
 -      while (a--) {
 -              if (bp->hide == 0) {
 -                      if (bp->f1 & SELECT) countsel++;
 -                      if (is_prop_edit) count++;
 +              Lattice *latt = ((Lattice *)tc->obedit->data)->editlatt->latt;
 +              TransData *td = NULL;
 +              BPoint *bp;
 +              float mtx[3][3], smtx[3][3];
 +              int a;
 +              int count = 0, countsel = 0;
 +              const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
 +
 +              bp = latt->def;
 +              a  = latt->pntsu * latt->pntsv * latt->pntsw;
 +              while (a--) {
 +                      if (bp->hide == 0) {
 +                              if (bp->f1 & SELECT) countsel++;
 +                              if (is_prop_edit) count++;
 +                      }
 +                      bp++;
                }
 -              bp++;
 -      }
  
 -      /* note: in prop mode we need at least 1 selected */
 -      if (countsel == 0) return;
 +              /* note: in prop mode we need at least 1 selected */
 +              if (countsel == 0) return;
  
 -      if (is_prop_edit) t->total = count;
 -      else t->total = countsel;
 -      t->data = MEM_callocN(t->total * sizeof(TransData), "TransObData(Lattice EditMode)");
 +              if (is_prop_edit) tc->data_len = count;
 +              else tc->data_len = countsel;
 +              tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransObData(Lattice EditMode)");
  
 -      copy_m3_m4(mtx, t->obedit->obmat);
 -      pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
 +              copy_m3_m4(mtx, tc->obedit->obmat);
 +              pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
  
 -      td = t->data;
 -      bp = latt->def;
 -      a  = latt->pntsu * latt->pntsv * latt->pntsw;
 -      while (a--) {
 -              if (is_prop_edit || (bp->f1 & SELECT)) {
 -                      if (bp->hide == 0) {
 -                              copy_v3_v3(td->iloc, bp->vec);
 -                              td->loc = bp->vec;
 -                              copy_v3_v3(td->center, td->loc);
 -                              if (bp->f1 & SELECT) {
 -                                      td->flag = TD_SELECTED;
 -                              }
 -                              else {
 -                                      td->flag = 0;
 -                              }
 -                              copy_m3_m3(td->smtx, smtx);
 -                              copy_m3_m3(td->mtx, mtx);
 +              td = tc->data;
 +              bp = latt->def;
 +              a  = latt->pntsu * latt->pntsv * latt->pntsw;
 +              while (a--) {
 +                      if (is_prop_edit || (bp->f1 & SELECT)) {
 +                              if (bp->hide == 0) {
 +                                      copy_v3_v3(td->iloc, bp->vec);
 +                                      td->loc = bp->vec;
 +                                      copy_v3_v3(td->center, td->loc);
 +                                      if (bp->f1 & SELECT) {
 +                                              td->flag = TD_SELECTED;
 +                                      }
 +                                      else {
 +                                              td->flag = 0;
 +                                      }
 +                                      copy_m3_m3(td->smtx, smtx);
 +                                      copy_m3_m3(td->mtx, mtx);
  
 -                              td->ext = NULL;
 -                              td->val = NULL;
 +                                      td->ext = NULL;
 +                                      td->val = NULL;
  
 -                              td++;
 -                              count++;
 +                                      td++;
 +                                      count++;
 +                              }
                        }
 +                      bp++;
                }
 -              bp++;
        }
  }
  
  /* ******************* particle edit **************** */
  static void createTransParticleVerts(bContext *C, TransInfo *t)
  {
 -      TransData *td = NULL;
 -      TransDataExtension *tx;
 -      Object *ob = CTX_data_active_object(C);
 -      ParticleEditSettings *pset = PE_settings(t->scene);
 -      PTCacheEdit *edit = PE_get_current(t->scene, ob);
 -      ParticleSystem *psys = NULL;
 -      ParticleSystemModifierData *psmd = NULL;
 -      PTCacheEditPoint *point;
 -      PTCacheEditKey *key;
 -      float mat[4][4];
 -      int i, k, transformparticle;
 -      int count = 0, hasselected = 0;
 -      const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
 -
 -      if (edit == NULL || t->settings->particle.selectmode == SCE_SELECT_PATH) return;
 -
 -      psys = edit->psys;
 -
 -      if (psys)
 -              psmd = psys_get_modifier(ob, psys);
 -
 -      for (i = 0, point = edit->points; i < edit->totpoint; i++, point++) {
 -              point->flag &= ~PEP_TRANSFORM;
 -              transformparticle = 0;
 -
 -              if ((point->flag & PEP_HIDE) == 0) {
 -                      for (k = 0, key = point->keys; k < point->totkey; k++, key++) {
 -                              if ((key->flag & PEK_HIDE) == 0) {
 -                                      if (key->flag & PEK_SELECT) {
 -                                              hasselected = 1;
 -                                              transformparticle = 1;
 +      FOREACH_TRANS_DATA_CONTAINER (t, tc) {
 +
 +              TransData *td = NULL;
 +              TransDataExtension *tx;
 +              Object *ob = CTX_data_active_object(C);
 +              ParticleEditSettings *pset = PE_settings(t->scene);
 +              PTCacheEdit *edit = PE_get_current(t->scene, ob);
 +              ParticleSystem *psys = NULL;
 +              ParticleSystemModifierData *psmd = NULL;
 +              PTCacheEditPoint *point;
 +              PTCacheEditKey *key;
 +              float mat[4][4];
 +              int i, k, transformparticle;
 +              int count = 0, hasselected = 0;
 +              const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
 +
 +              if (edit == NULL || t->settings->particle.selectmode == SCE_SELECT_PATH) return;
 +
 +              psys = edit->psys;
 +
 +              if (psys)
 +                      psmd = psys_get_modifier(ob, psys);
 +
 +              for (i = 0, point = edit->points; i < edit->totpoint; i++, point++) {
 +                      point->flag &= ~PEP_TRANSFORM;
 +                      transformparticle = 0;
 +
 +                      if ((point->flag & PEP_HIDE) == 0) {
 +                              for (k = 0, key = point->keys; k < point->totkey; k++, key++) {
 +                                      if ((key->flag & PEK_HIDE) == 0) {
 +                                              if (key->flag & PEK_SELECT) {
 +                                                      hasselected = 1;
 +                                                      transformparticle = 1;
 +                                              }
 +                                              else if (is_prop_edit)
 +                                                      transformparticle = 1;
                                        }
 -                                      else if (is_prop_edit)
 -                                              transformparticle = 1;
                                }
                        }
 -              }
  
 -              if (transformparticle) {
 -                      count += point->totkey;
 -                      point->flag |= PEP_TRANSFORM;
 +                      if (transformparticle) {
 +                              count += point->totkey;
 +                              point->flag |= PEP_TRANSFORM;
 +                      }
                }
 -      }
  
 -      /* note: in prop mode we need at least 1 selected */
 -      if (hasselected == 0) return;
 +              /* note: in prop mode we need at least 1 selected */
 +              if (hasselected == 0) return;
  
 -      t->total = count;
 -      td = t->data = MEM_callocN(t->total * sizeof(TransData), "TransObData(Particle Mode)");
 +              tc->data_len = count;
 +              td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransObData(Particle Mode)");
  
 -      if (t->mode == TFM_BAKE_TIME)
 -              tx = t->ext = MEM_callocN(t->total * sizeof(TransDataExtension), "Particle_TransExtension");
 -      else
 -              tx = t->ext = NULL;
 +              if (t->mode == TFM_BAKE_TIME)
 +                      tx = tc->data_ext = MEM_callocN(tc->data_len * sizeof(TransDataExtension), "Particle_TransExtension");
 +              else
 +                      tx = tc->data_ext = NULL;
  
 -      unit_m4(mat);
 +              unit_m4(mat);
  
 -      invert_m4_m4(ob->imat, ob->obmat);
 +              invert_m4_m4(ob->imat, ob->obmat);
  
 -      for (i = 0, point = edit->points; i < edit->totpoint; i++, point++) {
 -              TransData *head, *tail;
 -              head = tail = td;
 +              for (i = 0, point = edit->points; i < edit->totpoint; i++, point++) {
 +                      TransData *head, *tail;
 +                      head = tail = td;
  
 -              if (!(point->flag & PEP_TRANSFORM)) continue;
 +                      if (!(point->flag & PEP_TRANSFORM)) continue;
  
 -              if (psys && !(psys->flag & PSYS_GLOBAL_HAIR))
 -                      psys_mat_hair_to_global(ob, psmd->dm_final, psys->part->from, psys->particles + i, mat);
 +                      if (psys && !(psys->flag & PSYS_GLOBAL_HAIR))
 +                              psys_mat_hair_to_global(ob, psmd->mesh_final, psys->part->from, psys->particles + i, mat);
  
 -              for (k = 0, key = point->keys; k < point->totkey; k++, key++) {
 -                      if (key->flag & PEK_USE_WCO) {
 -                              copy_v3_v3(key->world_co, key->co);
 -                              mul_m4_v3(mat, key->world_co);
 -                              td->loc = key->world_co;
 -                      }
 -                      else
 -                              td->loc = key->co;
 +                      for (k = 0, key = point->keys; k < point->totkey; k++, key++) {
 +                              if (key->flag & PEK_USE_WCO) {
 +                                      copy_v3_v3(key->world_co, key->co);
 +                                      mul_m4_v3(mat, key->world_co);
 +                                      td->loc = key->world_co;
 +                              }
 +                              else
 +                                      td->loc = key->co;
  
 -                      copy_v3_v3(td->iloc, td->loc);
 -                      copy_v3_v3(td->center, td->loc);
 +                              copy_v3_v3(td->iloc, td->loc);
 +                              copy_v3_v3(td->center, td->loc);
  
 -                      if (key->flag & PEK_SELECT)
 -                              td->flag |= TD_SELECTED;
 -                      else if (!is_prop_edit)
 -                              td->flag |= TD_SKIP;
 +                              if (key->flag & PEK_SELECT)
 +                                      td->flag |= TD_SELECTED;
 +                              else if (!is_prop_edit)
 +                                      td->flag |= TD_SKIP;
  
 -                      unit_m3(td->mtx);
 -                      unit_m3(td->smtx);
 +                              unit_m3(td->mtx);
 +                              unit_m3(td->smtx);
  
 -                      /* don't allow moving roots */
 -                      if (k == 0 && pset->flag & PE_LOCK_FIRST && (!psys || !(psys->flag & PSYS_GLOBAL_HAIR)))
 -                              td->protectflag |= OB_LOCK_LOC;
 +                              /* don't allow moving roots */
 +                              if (k == 0 && pset->flag & PE_LOCK_FIRST && (!psys || !(psys->flag & PSYS_GLOBAL_HAIR)))
 +                                      td->protectflag |= OB_LOCK_LOC;
  
 -                      td->ob = ob;
 -                      td->ext = tx;
 -                      if (t->mode == TFM_BAKE_TIME) {
 -                              td->val = key->time;
 -                              td->ival = *(key->time);
 -                              /* abuse size and quat for min/max values */
 -                              td->flag |= TD_NO_EXT;
 -                              if (k == 0) tx->size = NULL;
 -                              else tx->size = (key - 1)->time;
 +                              td->ob = ob;
 +                              td->ext = tx;
 +                              if (t->mode == TFM_BAKE_TIME) {
 +                                      td->val = key->time;
 +                                      td->ival = *(key->time);
 +                                      /* abuse size and quat for min/max values */
 +                                      td->flag |= TD_NO_EXT;
 +                                      if (k == 0) tx->size = NULL;
 +                                      else tx->size = (key - 1)->time;
  
 -                              if (k == point->totkey - 1) tx->quat = NULL;
 -                              else tx->quat = (key + 1)->time;
 -                      }
 +                                      if (k == point->totkey - 1) tx->quat = NULL;
 +                                      else tx->quat = (key + 1)->time;
 +                              }
  
 -                      td++;
 -                      if (tx)
 -                              tx++;
 -                      tail++;
 +                              td++;
 +                              if (tx)
 +                                      tx++;
 +                              tail++;
 +                      }
 +                      if (is_prop_edit && head != tail)
 +                              calc_distanceCurveVerts(head, tail - 1);
                }
 -              if (is_prop_edit && head != tail)
 -                      calc_distanceCurveVerts(head, tail - 1);
        }
  }
  
  void flushTransParticles(TransInfo *t)
  {
 -      Scene *scene = t->scene;
 -      Object *ob = OBACT;
 -      PTCacheEdit *edit = PE_get_current(scene, ob);
 -      ParticleSystem *psys = edit->psys;
 -      ParticleSystemModifierData *psmd = NULL;
 -      PTCacheEditPoint *point;
 -      PTCacheEditKey *key;
 -      TransData *td;
 -      float mat[4][4], imat[4][4], co[3];
 -      int i, k;
 -      const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
 -
 -      if (psys)
 -              psmd = psys_get_modifier(ob, psys);
 -
 -      /* we do transform in world space, so flush world space position
 -       * back to particle local space (only for hair particles) */
 -      td = t->data;
 -      for (i = 0, point = edit->points; i < edit->totpoint; i++, point++, td++) {
 -              if (!(point->flag & PEP_TRANSFORM)) continue;
 -
 -              if (psys && !(psys->flag & PSYS_GLOBAL_HAIR)) {
 -                      psys_mat_hair_to_global(ob, psmd->dm_final, psys->part->from, psys->particles + i, mat);
 -                      invert_m4_m4(imat, mat);
 +      FOREACH_TRANS_DATA_CONTAINER (t, tc) {
  
 -                      for (k = 0, key = point->keys; k < point->totkey; k++, key++) {
 -                              copy_v3_v3(co, key->world_co);
 -                              mul_m4_v3(imat, co);
 -
 -
 -                              /* optimization for proportional edit */
 -                              if (!is_prop_edit || !compare_v3v3(key->co, co, 0.0001f)) {
 -                                      copy_v3_v3(key->co, co);
 -                                      point->flag |= PEP_EDIT_RECALC;
 +              Scene *scene = t->scene;
 +              ViewLayer *view_layer = t->view_layer;
 +              Object *ob = OBACT(view_layer);
 +              PTCacheEdit *edit = PE_get_current(scene, ob);
 +              ParticleSystem *psys = edit->psys;
 +              ParticleSystemModifierData *psmd = NULL;
 +              PTCacheEditPoint *point;
 +              PTCacheEditKey *key;
 +              TransData *td;
 +              float mat[4][4], imat[4][4], co[3];
 +              int i, k;
 +              const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
 +
 +              if (psys)
 +                      psmd = psys_get_modifier(ob, psys);
 +
 +              /* we do transform in world space, so flush world space position
 +               * back to particle local space (only for hair particles) */
 +              td = tc->data;
 +              for (i = 0, point = edit->points; i < edit->totpoint; i++, point++, td++) {
 +                      if (!(point->flag & PEP_TRANSFORM)) continue;
 +
 +                      if (psys && !(psys->flag & PSYS_GLOBAL_HAIR)) {
 +                              psys_mat_hair_to_global(ob, psmd->mesh_final, psys->part->from, psys->particles + i, mat);
 +                              invert_m4_m4(imat, mat);
 +
 +                              for (k = 0, key = point->keys; k < point->totkey; k++, key++) {
 +                                      copy_v3_v3(co, key->world_co);
 +                                      mul_m4_v3(imat, co);
 +
 +
 +                                      /* optimization for proportional edit */
 +                                      if (!is_prop_edit || !compare_v3v3(key->co, co, 0.0001f)) {
 +                                              copy_v3_v3(key->co, co);
 +                                              point->flag |= PEP_EDIT_RECALC;
 +                                      }
                                }
                        }
 +                      else
 +                              point->flag |= PEP_EDIT_RECALC;
                }
 -              else
 -                      point->flag |= PEP_EDIT_RECALC;
 -      }
  
 -      PE_update_object(scene, OBACT, 1);
 +              PE_update_object(t->depsgraph, scene, OBACT(view_layer), 1);
 +      }
  }
  
  /* ********************* mesh ****************** */
@@@ -2574,248 -2475,243 +2574,248 @@@ static void VertsToTransData(TransInfo 
  
  static void createTransEditVerts(TransInfo *t)
  {
 -      TransData *tob = NULL;
 -      TransDataExtension *tx = NULL;
 -      BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
 -      Mesh *me = t->obedit->data;
 -      BMesh *bm = em->bm;
 -      BMVert *eve;
 -      BMIter iter;
 -      float (*mappedcos)[3] = NULL, (*quats)[4] = NULL;
 -      float mtx[3][3], smtx[3][3], (*defmats)[3][3] = NULL, (*defcos)[3] = NULL;
 -      float *dists = NULL;
 -      int a;
 -      const int prop_mode = (t->flag & T_PROP_EDIT) ? (t->flag & T_PROP_EDIT_ALL) : 0;
 -      int mirror = 0;
 -      int cd_vert_bweight_offset = -1;
 -      bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
 +      FOREACH_TRANS_DATA_CONTAINER (t, tc) {
  
 -      struct TransIslandData *island_info = NULL;
 -      int island_info_tot;
 -      int *island_vert_map = NULL;
 +              TransData *tob = NULL;
 +              TransDataExtension *tx = NULL;
 +              BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
 +              Mesh *me = tc->obedit->data;
 +              BMesh *bm = em->bm;
 +              BMVert *eve;
 +              BMIter iter;
 +              float (*mappedcos)[3] = NULL, (*quats)[4] = NULL;
 +              float mtx[3][3], smtx[3][3], (*defmats)[3][3] = NULL, (*defcos)[3] = NULL;
 +              float *dists = NULL;
 +              int a;
 +              const int prop_mode = (t->flag & T_PROP_EDIT) ? (t->flag & T_PROP_EDIT_ALL) : 0;
 +              int mirror = 0;
 +              int cd_vert_bweight_offset = -1;
 +              bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
  
 -      /* Even for translation this is needed because of island-orientation, see: T51651. */
 -      const bool is_island_center = (t->around == V3D_AROUND_LOCAL_ORIGINS);
 -      /* Original index of our connected vertex when connected distances are calculated.
 -       * Optional, allocate if needed. */
 -      int *dists_index = NULL;
 +              struct TransIslandData *island_info = NULL;
 +              int island_info_tot;
 +              int *island_vert_map = NULL;
  
 -      if (t->flag & T_MIRROR) {
 -              EDBM_verts_mirror_cache_begin(em, 0, false, (t->flag & T_PROP_EDIT) == 0, use_topology);
 -              mirror = 1;
 -      }
 +              /* Even for translation this is needed because of island-orientation, see: T51651. */
 +              const bool is_island_center = (t->around == V3D_AROUND_LOCAL_ORIGINS);
 +              /* Original index of our connected vertex when connected distances are calculated.
 +               * Optional, allocate if needed. */
 +              int *dists_index = NULL;
  
 -      /**
 -       * Quick check if we can transform.
 -       *
 -       * \note ignore modes here, even in edge/face modes, transform data is created by selected vertices.
 -       * \note in prop mode we need at least 1 selected.
 -       */
 -      if (bm->totvertsel == 0) {
 -              goto cleanup;
 -      }
 +              if (t->flag & T_MIRROR) {
 +                      /* TODO(campbell): xform: We need support for many mirror objects at once! */
 +                      if (tc->is_active) {
 +                              EDBM_verts_mirror_cache_begin(em, 0, false, (t->flag & T_PROP_EDIT) == 0, use_topology);
 +                              mirror = 1;
 +                      }
 +              }
  
 -      if (t->mode == TFM_BWEIGHT) {
 -              BM_mesh_cd_flag_ensure(bm, BKE_mesh_from_object(t->obedit), ME_CDFLAG_VERT_BWEIGHT);
 -              cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT);
 -      }
 +              /**
 +               * Quick check if we can transform.
 +               *
 +               * \note ignore modes here, even in edge/face modes, transform data is created by selected vertices.
 +               * \note in prop mode we need at least 1 selected.
 +               */
 +              if (bm->totvertsel == 0) {
 +                      goto cleanup;
 +              }
  
 -      if (prop_mode) {
 -              unsigned int count = 0;
 -              BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
 -                      if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
 -                              count++;
 -                      }
 +              if (t->mode == TFM_BWEIGHT) {
 +                      BM_mesh_cd_flag_ensure(bm, BKE_mesh_from_object(tc->obedit), ME_CDFLAG_VERT_BWEIGHT);
 +                      cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT);
                }
  
 -              t->total = count;
 +              if (prop_mode) {
 +                      unsigned int count = 0;
 +                      BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
 +                              if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
 +                                      count++;
 +                              }
 +                      }
  
 -              /* allocating scratch arrays */
 -              if (prop_mode & T_PROP_CONNECTED) {
 -                      dists = MEM_mallocN(em->bm->totvert * sizeof(float), __func__);
 -                      if (is_island_center) {
 -                              dists_index =  MEM_mallocN(em->bm->totvert * sizeof(int), __func__);
 +                      tc->data_len = count;
 +
 +                      /* allocating scratch arrays */
 +                      if (prop_mode & T_PROP_CONNECTED) {
 +                              dists = MEM_mallocN(em->bm->totvert * sizeof(float), __func__);
 +                              if (is_island_center) {
 +                                      dists_index =  MEM_mallocN(em->bm->totvert * sizeof(int), __func__);
 +                              }
                        }
                }
 -      }
 -      else {
 -              t->total = bm->totvertsel;
 -      }
 -
 -      tob = t->data = MEM_callocN(t->total * sizeof(TransData), "TransObData(Mesh EditMode)");
 -      if (ELEM(t->mode, TFM_SKIN_RESIZE, TFM_SHRINKFATTEN)) {
 -              /* warning, this is overkill, we only need 2 extra floats,
 -               * but this stores loads of extra stuff, for TFM_SHRINKFATTEN its even more overkill
 -               * since we may not use the 'alt' transform mode to maintain shell thickness,
 -               * but with generic transform code its hard to lazy init vars */
 -              tx = t->ext = MEM_callocN(t->total * sizeof(TransDataExtension),
 -                                        "TransObData ext");
 -      }
 +              else {
 +                      tc->data_len = bm->totvertsel;
 +              }
  
 -      copy_m3_m4(mtx, t->obedit->obmat);
 -      /* we use a pseudoinverse so that when one of the axes is scaled to 0,
 -       * matrix inversion still works and we can still moving along the other */
 -      pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
 +              tob = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransObData(Mesh EditMode)");
 +              if (ELEM(t->mode, TFM_SKIN_RESIZE, TFM_SHRINKFATTEN)) {
 +                      /* warning, this is overkill, we only need 2 extra floats,
 +                       * but this stores loads of extra stuff, for TFM_SHRINKFATTEN its even more overkill
 +                       * since we may not use the 'alt' transform mode to maintain shell thickness,
 +                       * but with generic transform code its hard to lazy init vars */
 +                      tx = tc->data_ext = MEM_callocN(tc->data_len * sizeof(TransDataExtension), "TransObData ext");
 +              }
  
 -      if (prop_mode & T_PROP_CONNECTED) {
 -              editmesh_set_connectivity_distance(em->bm, mtx, dists, dists_index);
 -      }
 +              copy_m3_m4(mtx, tc->obedit->obmat);
 +              /* we use a pseudoinverse so that when one of the axes is scaled to 0,
 +               * matrix inversion still works and we can still moving along the other */
 +              pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
  
 -      if (is_island_center) {
 -              /* In this specific case, near-by vertices will need to know the island of the nearest connected vertex. */
 -              const bool calc_single_islands = (
 -                      (prop_mode & T_PROP_CONNECTED) &&
 -                      (t->around == V3D_AROUND_LOCAL_ORIGINS) &&
 -                      (em->selectmode & SCE_SELECT_VERTEX));
 +              if (prop_mode & T_PROP_CONNECTED) {
 +                      editmesh_set_connectivity_distance(em->bm, mtx, dists, dists_index);
 +              }
  
 -              island_info = editmesh_islands_info_calc(em, &island_info_tot, &island_vert_map, calc_single_islands);
 -      }
 +              if (is_island_center) {
 +                      /* In this specific case, near-by vertices will need to know the island of the nearest connected vertex. */
 +                      const bool calc_single_islands = (
 +                              (prop_mode & T_PROP_CONNECTED) &&
 +                              (t->around == V3D_AROUND_LOCAL_ORIGINS) &&
 +                              (em->selectmode & SCE_SELECT_VERTEX));
  
 -      /* detect CrazySpace [tm] */
 -      if (modifiers_getCageIndex(t->scene, t->obedit, NULL, 1) != -1) {
 -              int totleft = -1;
 -              if (modifiers_isCorrectableDeformed(t->scene, t->obedit)) {
 -                      /* check if we can use deform matrices for modifier from the
 -                       * start up to stack, they are more accurate than quats */
 -                      totleft = BKE_crazyspace_get_first_deform_matrices_editbmesh(t->scene, t->obedit, em, &defmats, &defcos);
 +                      island_info = editmesh_islands_info_calc(em, &island_info_tot, &island_vert_map, calc_single_islands);
                }
  
 -              /* if we still have more modifiers, also do crazyspace
 -               * correction with quats, relative to the coordinates after
 -               * the modifiers that support deform matrices (defcos) */
 +              /* detect CrazySpace [tm] */
 +              if (modifiers_getCageIndex(t->scene, tc->obedit, NULL, 1) != -1) {
 +                      int totleft = -1;
 +                      if (modifiers_isCorrectableDeformed(t->scene, tc->obedit)) {
 +                              /* check if we can use deform matrices for modifier from the
 +                               * start up to stack, they are more accurate than quats */
 +                              totleft = BKE_crazyspace_get_first_deform_matrices_editbmesh(t->depsgraph, t->scene, tc->obedit, em, &defmats, &defcos);
 +                      }
 +
 +                      /* if we still have more modifiers, also do crazyspace
 +                       * correction with quats, relative to the coordinates after
 +                       * the modifiers that support deform matrices (defcos) */
  
  #if 0 /* TODO, fix crazyspace+extrude so it can be enabled for general use - campbell */
 -              if ((totleft > 0) || (totleft == -1))
 +                      if ((totleft > 0) || (totleft == -1))
  #else
 -              if (totleft > 0)
 +                      if (totleft > 0)
  #endif
 -              {
 -                      mappedcos = BKE_crazyspace_get_mapped_editverts(t->scene, t->obedit);
 -                      quats = MEM_mallocN(em->bm->totvert * sizeof(*quats), "crazy quats");
 -                      BKE_crazyspace_set_quats_editmesh(em, defcos, mappedcos, quats, !prop_mode);
 -                      if (mappedcos)
 -                              MEM_freeN(mappedcos);
 -              }
 +                      {
 +                              mappedcos = BKE_crazyspace_get_mapped_editverts(t->depsgraph, t->scene, tc->obedit);
 +                              quats = MEM_mallocN(em->bm->totvert * sizeof(*quats), "crazy quats");
 +                              BKE_crazyspace_set_quats_editmesh(em, defcos, mappedcos, quats, !prop_mode);
 +                              if (mappedcos)
 +                                      MEM_freeN(mappedcos);
 +                      }
  
 -              if (defcos) {
 -                      MEM_freeN(defcos);
 +                      if (defcos) {
 +                              MEM_freeN(defcos);
 +                      }
                }
 -      }
  
 -      /* find out which half we do */
 -      if (mirror) {
 -              BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
 -                      if (BM_elem_flag_test(eve, BM_ELEM_SELECT) && eve->co[0] != 0.0f) {
 -                              if (eve->co[0] < 0.0f) {
 -                                      t->mirror = -1;
 -                                      mirror = -1;
 +              /* find out which half we do */
 +              if (mirror) {
 +                      BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
 +                              if (BM_elem_flag_test(eve, BM_ELEM_SELECT) && eve->co[0] != 0.0f) {
 +                                      if (eve->co[0] < 0.0f) {
 +                                              t->mirror = -1;
 +                                              mirror = -1;
 +                                      }
 +                                      break;
                                }
 -                              break;
                        }
                }
 -      }
 -
 -      BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, a) {
 -              if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
 -                      if (prop_mode || BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
 -                              struct TransIslandData *v_island = NULL;
 -                              float *bweight = (cd_vert_bweight_offset != -1) ? BM_ELEM_CD_GET_VOID_P(eve, cd_vert_bweight_offset) : NULL;
  
 -                              if (island_info) {
 -                                      const int connected_index = (dists_index && dists_index[a] != -1) ? dists_index[a] : a;
 -                                      v_island = (island_vert_map[connected_index] != -1) ?
 -                                                 &island_info[island_vert_map[connected_index]] : NULL;
 -                              }
 +              BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, a) {
 +                      if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
 +                              if (prop_mode || BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
 +                                      struct TransIslandData *v_island = NULL;
 +                                      float *bweight = (cd_vert_bweight_offset != -1) ? BM_ELEM_CD_GET_VOID_P(eve, cd_vert_bweight_offset) : NULL;
 +
 +                                      if (island_info) {
 +                                              const int connected_index = (dists_index && dists_index[a] != -1) ? dists_index[a] : a;
 +                                              v_island = (island_vert_map[connected_index] != -1) ?
 +                                                         &island_info[island_vert_map[connected_index]] : NULL;
 +                                      }
  
  
 -                              VertsToTransData(t, tob, tx, em, eve, bweight, v_island);
 -                              if (tx)
 -                                      tx++;
 +                                      VertsToTransData(t, tob, tx, em, eve, bweight, v_island);
 +                                      if (tx)
 +                                              tx++;
  
 -                              /* selected */
 -                              if (BM_elem_flag_test(eve, BM_ELEM_SELECT))
 -                                      tob->flag |= TD_SELECTED;
 +                                      /* selected */
 +                                      if (BM_elem_flag_test(eve, BM_ELEM_SELECT))
 +                                              tob->flag |= TD_SELECTED;
  
 -                              if (prop_mode) {
 -                                      if (prop_mode & T_PROP_CONNECTED) {
 -                                              tob->dist = dists[a];
 -                                      }
 -                                      else {
 -                                              tob->flag |= TD_NOTCONNECTED;
 -                                              tob->dist = FLT_MAX;
 +                                      if (prop_mode) {
 +                                              if (prop_mode & T_PROP_CONNECTED) {
 +                                                      tob->dist = dists[a];
 +                                              }
 +                                              else {
 +                                                      tob->flag |= TD_NOTCONNECTED;
 +                                                      tob->dist = FLT_MAX;
 +                                              }
                                        }
 -                              }
  
 -                              /* CrazySpace */
 -                              if (defmats || (quats && BM_elem_flag_test(eve, BM_ELEM_TAG))) {
 -                                      float mat[3][3], qmat[3][3], imat[3][3];
 +                                      /* CrazySpace */
 +                                      if (defmats || (quats && BM_elem_flag_test(eve, BM_ELEM_TAG))) {
 +                                              float mat[3][3], qmat[3][3], imat[3][3];
  
 -                                      /* use both or either quat and defmat correction */
 -                                      if (quats && BM_elem_flag_test(eve, BM_ELEM_TAG)) {
 -                                              quat_to_mat3(qmat, quats[BM_elem_index_get(eve)]);
 +                                              /* use both or either quat and defmat correction */
 +                                              if (quats && BM_elem_flag_test(eve, BM_ELEM_TAG)) {
 +                                                      quat_to_mat3(qmat, quats[BM_elem_index_get(eve)]);
  
 -                                              if (defmats)
 -                                                      mul_m3_series(mat, defmats[a], qmat, mtx);
 +                                                      if (defmats)
 +                                                              mul_m3_series(mat, defmats[a], qmat, mtx);
 +                                                      else
 +                                                              mul_m3_m3m3(mat, mtx, qmat);
 +                                              }
                                                else
 -                                                      mul_m3_m3m3(mat, mtx, qmat);
 -                                      }
 -                                      else
 -                                              mul_m3_m3m3(mat, mtx, defmats[a]);
 +                                                      mul_m3_m3m3(mat, mtx, defmats[a]);
  
 -                                      invert_m3_m3(imat, mat);
 +                                              invert_m3_m3(imat, mat);
  
 -                                      copy_m3_m3(tob->smtx, imat);
 -                                      copy_m3_m3(tob->mtx, mat);
 -                              }
 -                              else {
 -                                      copy_m3_m3(tob->smtx, smtx);
 -                                      copy_m3_m3(tob->mtx, mtx);
 -                              }
 +                                              copy_m3_m3(tob->smtx, imat);
 +                                              copy_m3_m3(tob->mtx, mat);
 +                                      }
 +                                      else {
 +                                              copy_m3_m3(tob->smtx, smtx);
 +                                              copy_m3_m3(tob->mtx, mtx);
 +                                      }
  
 -                              /* Mirror? */
 -                              if ((mirror > 0 && tob->iloc[0] > 0.0f) || (mirror < 0 && tob->iloc[0] < 0.0f)) {
 -                                      BMVert *vmir = EDBM_verts_mirror_get(em, eve); //t->obedit, em, eve, tob->iloc, a);
 -                                      if (vmir && vmir != eve) {
 -                                              tob->extra = vmir;
 +                                      /* Mirror? */
 +                                      if ((mirror > 0 && tob->iloc[0] > 0.0f) || (mirror < 0 && tob->iloc[0] < 0.0f)) {
 +                                              BMVert *vmir = EDBM_verts_mirror_get(em, eve); //t->obedit, em, eve, tob->iloc, a);
 +                                              if (vmir && vmir != eve) {
 +                                                      tob->extra = vmir;
 +                                              }
                                        }
 +                                      tob++;
                                }
 -                              tob++;
                        }
                }
 -      }
  
 -      if (island_info) {
 -              MEM_freeN(island_info);
 -              MEM_freeN(island_vert_map);
 -      }
 +              if (island_info) {
 +                      MEM_freeN(island_info);
 +                      MEM_freeN(island_vert_map);
 +              }
  
 -      if (mirror != 0) {
 -              tob = t->data;
 -              for (a = 0; a < t->total; a++, tob++) {
 -                      if (ABS(tob->loc[0]) <= 0.00001f) {
 -                              tob->flag |= TD_MIRROR_EDGE;
 +              if (mirror != 0) {
 +                      tob = tc->data;
 +                      for (a = 0; a < tc->data_len; a++, tob++) {
 +                              if (ABS(tob->loc[0]) <= 0.00001f) {
 +                                      tob->flag |= TD_MIRROR_EDGE;
 +                              }
                        }
                }
 -      }
  
  cleanup:
 -      /* crazy space free */
 -      if (quats)
 -              MEM_freeN(quats);
 -      if (defmats)
 -              MEM_freeN(defmats);
 -      if (dists)
 -              MEM_freeN(dists);
 -      if (dists_index)
 -              MEM_freeN(dists_index);
 -
 -      if (t->flag & T_MIRROR) {
 -              EDBM_verts_mirror_cache_end(em);
 +              /* crazy space free */
 +              if (quats)
 +                      MEM_freeN(quats);
 +              if (defmats)
 +                      MEM_freeN(defmats);
 +              if (dists)
 +                      MEM_freeN(dists);
 +              if (dists_index)
 +                      MEM_freeN(dists_index);
 +
 +              if (t->flag & T_MIRROR) {
 +                      EDBM_verts_mirror_cache_end(em);
 +              }
        }
  }
  
  void flushTransNodes(TransInfo *t)
  {
        const float dpi_fac = UI_DPI_FAC;
 -      int a;
 -      TransData *td;
 -      TransData2D *td2d;
  
 -      applyGridAbsolute(t);
 +      FOREACH_TRANS_DATA_CONTAINER (t, tc) {
 +              int a;
 +              TransData *td;
 +              TransData2D *td2d;
  
 -      /* flush to 2d vector from internally used 3d vector */
 -      for (a = 0, td = t->data, td2d = t->data2d; a < t->total; a++, td++, td2d++) {
 -              bNode *node = td->extra;
 -              float locx, locy;
 +              applyGridAbsolute(t);
 +
 +              /* flush to 2d vector from internally used 3d vector */
 +              for (a = 0, td = tc->data, td2d = tc->data_2d; a < tc->data_len; a++, td++, td2d++) {
 +                      bNode *node = td->extra;
 +                      float locx, locy;
  
 -              /* weirdo - but the node system is a mix of free 2d elements and dpi sensitive UI */
 +                      /* weirdo - but the node system is a mix of free 2d elements and dpi sensitive UI */
  #ifdef USE_NODE_CENTER
 -              locx = (td2d->loc[0] - (BLI_rctf_size_x(&node->totr)) * +0.5f) / dpi_fac;
 -              locy = (td2d->loc[1] - (BLI_rctf_size_y(&node->totr)) * -0.5f) / dpi_fac;
 +                      locx = (td2d->loc[0] - (BLI_rctf_size_x(&node->totr)) * +0.5f) / dpi_fac;
 +                      locy = (td2d->loc[1] - (BLI_rctf_size_y(&node->totr)) * -0.5f) / dpi_fac;
  #else
 -              locx = td2d->loc[0] / dpi_fac;
 -              locy = td2d->loc[1] / dpi_fac;
 +                      locx = td2d->loc[0] / dpi_fac;
 +                      locy = td2d->loc[1] / dpi_fac;
  #endif
  
 -              /* account for parents (nested nodes) */
 -              if (node->parent) {
 -                      nodeFromView(node->parent, locx, locy, &node->locx, &node->locy);
 -              }
 -              else {
 -                      node->locx = locx;
 -                      node->locy = locy;
 +                      /* account for parents (nested nodes) */
 +                      if (node->parent) {
 +                              nodeFromView(node->parent, locx, locy, &node->locx, &node->locy);
 +                      }
 +                      else {
 +                              node->locx = locx;
 +                              node->locy = locy;
 +                      }
                }
 -      }
  
 -      /* handle intersection with noodles */
 -      if (t->total == 1) {
 -              ED_node_link_intersect_test(t->sa, 1);
 +              /* handle intersection with noodles */
 +              if (tc->data_len == 1) {
 +                      ED_node_link_intersect_test(t->sa, 1);
 +              }
        }
  }
  
@@@ -2888,14 -2781,13 +2888,14 @@@ BLI_INLINE void trans_update_seq(Scene 
  void flushTransSeq(TransInfo *t)
  {
        ListBase *seqbasep = BKE_sequencer_editing_get(t->scene, false)->seqbasep; /* Editing null check already done */
 +
        int a, new_frame;
        TransData *td = NULL;
        TransData2D *td2d = NULL;
        TransDataSeq *tdsq = NULL;
        Sequence *seq;
  
 -
 +      TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
  
        /* prevent updating the same seq twice
         * if the transdata order is changed this will mess up
        int old_start_prev = 0, sel_flag_prev = 0;
  
        /* flush to 2d vector from internally used 3d vector */
 -      for (a = 0, td = t->data, td2d = t->data2d; a < t->total; a++, td++, td2d++) {
 +      for (a = 0, td = tc->data, td2d = tc->data_2d; a < tc->data_len; a++, td++, td2d++) {
                int old_start;
                tdsq = (TransDataSeq *)td->extra;
                seq = tdsq->seq;
                }
  
                /* update effects inside meta's */
 -              for (a = 0, seq_prev = NULL, td = t->data, td2d = t->data2d;
 -                   a < t->total;
 +              for (a = 0, seq_prev = NULL, td = tc->data, td2d = tc->data_2d;
 +                   a < tc->data_len;
                     a++, td++, td2d++, seq_prev = seq)
                {
                        tdsq = (TransDataSeq *)td->extra;
        /* need to do the overlap check in a new loop otherwise adjacent strips
         * will not be updated and we'll get false positives */
        seq_prev = NULL;
 -      for (a = 0, td = t->data, td2d = t->data2d; a < t->total; a++, td++, td2d++) {
 +      for (a = 0, td = tc->data, td2d = tc->data_2d; a < tc->data_len; a++, td++, td2d++) {
  
                tdsq = (TransDataSeq *)td->extra;
                seq = tdsq->seq;
@@@ -3055,167 -2947,159 +3055,167 @@@ static void createTransUVs(bContext *C
        Image *ima = CTX_data_edit_image(C);
        Scene *scene = t->scene;
        ToolSettings *ts = CTX_data_tool_settings(C);
 -      TransData *td = NULL;
 -      TransData2D *td2d = NULL;
 -      BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
 -      BMFace *efa;
 -      BMIter iter, liter;
 -      UvElementMap *elementmap = NULL;
 -      BLI_bitmap *island_enabled = NULL;
 -      struct { float co[2]; int co_num; } *island_center = NULL;
 -      int count = 0, countsel = 0, count_rejected = 0;
 +
        const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
        const bool is_prop_connected = (t->flag & T_PROP_CONNECTED) != 0;
        const bool is_island_center = (t->around == V3D_AROUND_LOCAL_ORIGINS);
 -      const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
 -      const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY);
  
 -      if (!ED_space_image_show_uvedit(sima, t->obedit))
 -              return;
 +      FOREACH_TRANS_DATA_CONTAINER (t, tc) {
  
 -      /* count */
 -      if (is_prop_connected || is_island_center) {
 -              /* create element map with island information */
 -              const bool use_facesel = (ts->uv_flag & UV_SYNC_SELECTION) == 0;
 -              elementmap = BM_uv_element_map_create(em->bm, use_facesel, false, true);
 -              if (elementmap == NULL) {
 -                      return;
 -              }
 +              TransData *td = NULL;
 +              TransData2D *td2d = NULL;
 +              BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
 +              BMFace *efa;
 +              BMIter iter, liter;
 +              UvElementMap *elementmap = NULL;
 +              BLI_bitmap *island_enabled = NULL;
 +              struct { float co[2]; int co_num; } *island_center = NULL;
 +              int count = 0, countsel = 0, count_rejected = 0;
 +              const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
  
 -              if (is_prop_connected) {
 -                      island_enabled = BLI_BITMAP_NEW(elementmap->totalIslands, "TransIslandData(UV Editing)");
 +              if (!ED_space_image_show_uvedit(sima, tc->obedit)) {
 +                      continue;
                }
  
 -              if (is_island_center) {
 -                      island_center = MEM_callocN(sizeof(*island_center) * elementmap->totalIslands, __func__);
 -              }
 -      }
 +              /* count */
 +              if (is_prop_connected || is_island_center) {
 +                      /* create element map with island information */
 +                      const bool use_facesel = (ts->uv_flag & UV_SYNC_SELECTION) == 0;
 +                      elementmap = BM_uv_element_map_create(em->bm, use_facesel, false, true);
 +                      if (elementmap == NULL) {
 +                              return;
 +                      }
  
 -      BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
 -              MTexPoly *tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
 -              BMLoop *l;
 +                      if (is_prop_connected) {
 +                              island_enabled = BLI_BITMAP_NEW(elementmap->totalIslands, "TransIslandData(UV Editing)");
 +                      }
  
 -              if (!uvedit_face_visible_test(scene, ima, efa, tf)) {
 -                      BM_elem_flag_disable(efa, BM_ELEM_TAG);
 -                      continue;
 +                      if (is_island_center) {
 +                              island_center = MEM_callocN(sizeof(*island_center) * elementmap->totalIslands, __func__);
 +                      }
                }
  
 -              BM_elem_flag_enable(efa, BM_ELEM_TAG);
 -              BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
 -                      if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
 -                              countsel++;
 +              BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
 +                      BMLoop *l;
  
 -                              if (is_prop_connected || island_center) {
 -                                      UvElement *element = BM_uv_element_get(elementmap, efa, l);
 +                      if (!uvedit_face_visible_test(scene, tc->obedit, ima, efa)) {
 +                              BM_elem_flag_disable(efa, BM_ELEM_TAG);
 +                              continue;
 +                      }
 +
 +                      BM_elem_flag_enable(efa, BM_ELEM_TAG);
 +                      BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
 +                              if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
 +                                      countsel++;
 +
 +                                      if (is_prop_connected || island_center) {
 +                                              UvElement *element = BM_uv_element_get(elementmap, efa, l);
  
 -                                      if (is_prop_connected) {
 -                                              BLI_BITMAP_ENABLE(island_enabled, element->island);
 -                                      }
 +                                              if (is_prop_connected) {
 +                                                      BLI_BITMAP_ENABLE(island_enabled, element->island);
 +                                              }
  
 -                                      if (is_island_center) {
 -                                              if (element->flag == false) {
 -                                                      MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
 -                                                      add_v2_v2(island_center[element->island].co, luv->uv);
 -                                                      island_center[element->island].co_num++;
 -                                                      element->flag = true;
 +                                              if (is_island_center) {
 +                                                      if (element->flag == false) {
 +                                                              MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
 +                                                              add_v2_v2(island_center[element->island].co, luv->uv);
 +                                                              island_center[element->island].co_num++;
 +                                                              element->flag = true;
 +                                                      }
                                                }
                                        }
                                }
 -                      }
  
 -                      if (is_prop_edit) {
 -                              count++;
 +                              if (is_prop_edit) {
 +                                      count++;
 +                              }
                        }
                }
 -      }
  
 -      /* note: in prop mode we need at least 1 selected */
 -      if (countsel == 0) {
 -              goto finally;
 -      }
 +              /* note: in prop mode we need at least 1 selected */
 +              if (countsel == 0) {
 +                      goto finally;
 +              }
  
 -      if (is_island_center) {
 -              int i;
 +              if (is_island_center) {
 +                      int i;
  
 -              for (i = 0; i < elementmap->totalIslands; i++) {
 -                      mul_v2_fl(island_center[i].co, 1.0f / island_center[i].co_num);
 -                      mul_v2_v2(island_center[i].co, t->aspect);
 +                      for (i = 0; i < elementmap->totalIslands; i++) {
 +                              mul_v2_fl(island_center[i].co, 1.0f / island_center[i].co_num);
 +                              mul_v2_v2(island_center[i].co, t->aspect);
 +                      }
                }
 -      }
  
 -      t->total = (is_prop_edit) ? count : countsel;
 -      t->data = MEM_callocN(t->total * sizeof(TransData), "TransObData(UV Editing)");
 -      /* for each 2d uv coord a 3d vector is allocated, so that they can be
 -       * treated just as if they were 3d verts */
 -      t->data2d = MEM_callocN(t->total * sizeof(TransData2D), "TransObData2D(UV Editing)");
 +              tc->data_len = (is_prop_edit) ? count : countsel;
 +              tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransObData(UV Editing)");
 +              /* for each 2d uv coord a 3d vector is allocated, so that they can be
 +               * treated just as if they were 3d verts */
 +              tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D), "TransObData2D(UV Editing)");
  
 -      if (sima->flag & SI_CLIP_UV)
 -              t->flag |= T_CLIP_UV;
 +              if (sima->flag & SI_CLIP_UV)
 +                      t->flag |= T_CLIP_UV;
  
 -      td = t->data;
 -      td2d = t->data2d;
 +              td = tc->data;
 +              td2d = tc->data_2d;
  
 -      BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
 -              BMLoop *l;
 +              BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
 +                      BMLoop *l;
  
 -              if (!BM_elem_flag_test(efa, BM_ELEM_TAG))
 -                      continue;
 +                      if (!BM_elem_flag_test(efa, BM_ELEM_TAG))
 +                              continue;
  
 -              BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
 -                      const bool selected = uvedit_uv_select_test(scene, l, cd_loop_uv_offset);
 -                      MLoopUV *luv;
 -                      const float *center = NULL;
 +                      BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
 +                              const bool selected = uvedit_uv_select_test(scene, l, cd_loop_uv_offset);
 +                              MLoopUV *luv;
 +                              const float *center = NULL;
  
 -                      if (!is_prop_edit && !selected)
 -                              continue;
 +                              if (!is_prop_edit && !selected)
 +                                      continue;
  
 -                      if (is_prop_connected || is_island_center) {
 -                              UvElement *element = BM_uv_element_get(elementmap, efa, l);
 +                              if (is_prop_connected || is_island_center) {
 +                                      UvElement *element = BM_uv_element_get(elementmap, efa, l);
  
 -                              if (is_prop_connected) {
 -                                      if (!BLI_BITMAP_TEST(island_enabled, element->island)) {
 -                                              count_rejected++;
 -                                              continue;
 +                                      if (is_prop_connected) {
 +                                              if (!BLI_BITMAP_TEST(island_enabled, element->island)) {
 +                                                      count_rejected++;
 +                                                      continue;
 +                                              }
                                        }
 -                              }
  
 -                              if (is_island_center) {
 -                                      center = island_center[element->island].co;
 +                                      if (is_island_center) {
 +                                              center = island_center[element->island].co;
 +                                      }
                                }
 -                      }
  
 -                      BM_elem_flag_enable(l, BM_ELEM_TAG);
 -                      luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
 -                      UVsToTransData(t->aspect, td++, td2d++, luv->uv, center, selected);
 +                              BM_elem_flag_enable(l, BM_ELEM_TAG);
 +                              luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
 +                              UVsToTransData(t->aspect, td++, td2d++, luv->uv, center, selected);
 +                      }
                }
 -      }
  
 -      if (is_prop_connected) {
 -              t->total -= count_rejected;
 -      }
 -
 -      if (sima->flag & SI_LIVE_UNWRAP)
 -              ED_uvedit_live_unwrap_begin(t->scene, t->obedit);
 +              if (is_prop_connected) {
 +                      tc->data_len -= count_rejected;
 +              }
  
 +              if (sima->flag & SI_LIVE_UNWRAP) {
 +                      /* TODO(campbell): xform: Only active object currently!
 +                       * it uses a static variable. */
 +                      if (tc->is_active) {
 +                              ED_uvedit_live_unwrap_begin(t->scene, tc->obedit);
 +                      }
 +              }
  
  finally:
 -      if (is_prop_connected || is_island_center) {
 -              BM_uv_element_map_free(elementmap);
 +              if (is_prop_connected || is_island_center) {
 +                      BM_uv_element_map_free(elementmap);
  
 -              if (is_prop_connected) {
 -                      MEM_freeN(island_enabled);
 -              }
 +                      if (is_prop_connected) {
 +                              MEM_freeN(island_enabled);
 +                      }
  
 -              if (island_center) {
 -                      MEM_freeN(island_center);
 +                      if (island_center) {
 +                              MEM_freeN(island_center);
 +                      }
                }
        }
  }
  void flushTransUVs(TransInfo *t)
  {
        SpaceImage *sima = t->sa->spacedata.first;
 -      TransData2D *td;
 -      int a;
 -      float aspect_inv[2], size[2];
        const bool use_pixel_snap = ((sima->flag & SI_PIXELSNAP) && (t->state != TRANS_CANCEL));
  
 -      aspect_inv[0] = 1.0f / t->aspect[0];
 -      aspect_inv[1] = 1.0f / t->aspect[1];
 -
 -      if (use_pixel_snap) {
 -              int size_i[2];
 -              ED_space_image_get_size(sima, &size_i[0], &size_i[1]);
 -              size[0] = size_i[0];
 -              size[1] = size_i[1];
 -      }
 +      FOREACH_TRANS_DATA_CONTAINER (t, tc) {
 +              TransData2D *td;
 +              int a;
 +              float aspect_inv[2], size[2];
  
 -      /* flush to 2d vector from internally used 3d vector */
 -      for (a = 0, td = t->data2d; a < t->total; a++, td++) {
 -              td->loc2d[0] = td->loc[0] * aspect_inv[0];
 -              td->loc2d[1] = td->loc[1] * aspect_inv[1];
 +              aspect_inv[0] = 1.0f / t->aspect[0];
 +              aspect_inv[1] = 1.0f / t->aspect[1];
  
                if (use_pixel_snap) {
 -                      td->loc2d[0] = roundf(td->loc2d[0] * size[0]) / size[0];
 -                      td->loc2d[1] = roundf(td->loc2d[1] * size[1]) / size[1];
 +                      int size_i[2];
 +                      ED_space_image_get_size(sima, &size_i[0], &size_i[1]);
 +                      size[0] = size_i[0];
 +                      size[1] = size_i[1];
 +              }
 +
 +              /* flush to 2d vector from internally used 3d vector */
 +              for (a = 0, td = tc->data_2d; a < tc->data_len; a++, td++) {
 +                      td->loc2d[0] = td->loc[0] * aspect_inv[0];
 +                      td->loc2d[1] = td->loc[1] * aspect_inv[1];
 +
 +                      if (use_pixel_snap) {
 +                              td->loc2d[0] = roundf(td->loc2d[0] * size[0]) / size[0];
 +                              td->loc2d[1] = roundf(td->loc2d[1] * size[1]) / size[1];
 +                      }
                }
        }
  }
  
  bool clipUVTransform(TransInfo *t, float vec[2], const bool resize)
  {
 -      TransData *td;
 -      int a;
        bool clipx = true, clipy = true;
        float min[2], max[2];
  
        max[0] = t->aspect[0];
        max[1] = t->aspect[1];
  
 -      for (a = 0, td = t->data; a < t->total; a++, td++) {
 -              minmax_v2v2_v2(min, max, td->loc);
 -      }
 +      FOREACH_TRANS_DATA_CONTAINER (t, tc) {
  
 -      if (resize) {
 -              if (min[0] < 0.0f && t->center[0] > 0.0f && t->center[0] < t->aspect[0] * 0.5f)
 -                      vec[0] *= t->center[0] / (t->center[0] - min[0]);
 -              else if (max[0] > t->aspect[0] && t->center[0] < t->aspect[0])
 -                      vec[0] *= (t->center[0] - t->aspect[0]) / (t->center[0] - max[0]);
 -              else
 -                      clipx = 0;
 +              TransData *td;
 +              int a;
  
 -              if (min[1] < 0.0f && t->center[1] > 0.0f && t->center[1] < t->aspect[1] * 0.5f)
 -                      vec[1] *= t->center[1] / (t->center[1] - min[1]);
 -              else if (max[1] > t->aspect[1] && t->center[1] < t->aspect[1])
 -                      vec[1] *= (t->center[1] - t->aspect[1]) / (t->center[1] - max[1]);
 -              else
 -                      clipy = 0;
 -      }
 -      else {
 -              if (min[0] < 0.0f)
 -                      vec[0] -= min[0];
 -              else if (max[0] > t->aspect[0])
 -                      vec[0] -= max[0] - t->aspect[0];
 -              else
 -                      clipx = 0;
 +              for (a = 0, td = tc->data; a < tc->data_len; a++, td++) {
 +                      minmax_v2v2_v2(min, max, td->loc);
 +              }
  
 -              if (min[1] < 0.0f)
 -                      vec[1] -= min[1];
 -              else if (max[1] > t->aspect[1])
 -                      vec[1] -= max[1] - t->aspect[1];
 -              else
 -                      clipy = 0;
 +              if (resize) {
 +                      if (min[0] < 0.0f && t->center_global[0] > 0.0f && t->center_global[0] < t->aspect[0] * 0.5f)
 +                              vec[0] *= t->center_global[0] / (t->center_global[0] - min[0]);
 +                      else if (max[0] > t->aspect[0] && t->center_global[0] < t->aspect[0])
 +                              vec[0] *= (t->center_global[0] - t->aspect[0]) / (t->center_global[0] - max[0]);
 +                      else
 +                              clipx = 0;
 +
 +                      if (min[1] < 0.0f && t->center_global[1] > 0.0f && t->center_global[1] < t->aspect[1] * 0.5f)
 +                              vec[1] *= t->center_global[1] / (t->center_global[1] - min[1]);
 +                      else if (max[1] > t->aspect[1] && t->center_global[1] < t->aspect[1])
 +                              vec[1] *= (t->center_global[1] - t->aspect[1]) / (t->center_global[1] - max[1]);
 +                      else
 +                              clipy = 0;
 +              }
 +              else {
 +                      if (min[0] < 0.0f)
 +                              vec[0] -= min[0];
 +                      else if (max[0] > t->aspect[0])
 +                              vec[0] -= max[0] - t->aspect[0];
 +                      else
 +                              clipx = 0;
 +
 +                      if (min[1] < 0.0f)
 +                              vec[1] -= min[1];
 +                      else if (max[1] > t->aspect[1])
 +                              vec[1] -= max[1] - t->aspect[1];
 +                      else
 +                              clipy = 0;
 +              }
        }
  
        return (clipx || clipy);
  
  void clipUVData(TransInfo *t)
  {
 -      TransData *td = NULL;
 -      int a;
 -
 -      for (a = 0, td = t->data; a < t->total; a++, td++) {
 -              if (td->flag & TD_NOACTION)
 -                      break;
 +      FOREACH_TRANS_DATA_CONTAINER (t, tc) {
 +              TransData *td = tc->data;
 +              for (int a = 0; a < tc->data_len; a++, td++) {
 +                      if (td->flag & TD_NOACTION)
 +                              break;
  
 -              if ((td->flag & TD_SKIP) || (!td->loc))
 -                      continue;
 +                      if ((td->flag & TD_SKIP) || (!td->loc))
 +                              continue;
  
 -              td->loc[0] = min_ff(max_ff(0.0f, td->loc[0]), t->aspect[0]);
 -              td->loc[1] = min_ff(max_ff(0.0f, td->loc[1]), t->aspect[1]);
 +                      td->loc[0] = min_ff(max_ff(0.0f, td->loc[0]), t->aspect[0]);
 +                      td->loc[1] = min_ff(max_ff(0.0f, td->loc[1]), t->aspect[1]);
 +              }
        }
  }
  
@@@ -3354,8 -3231,6 +3354,8 @@@ static void createTransNlaData(bContex
  
        int count = 0;
  
 +      TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
 +
        /* determine what type of data we are operating on */
        if (ANIM_animdata_get_context(C, &ac) == 0)
                return;
        }
  
        /* allocate memory for data */
 -      t->total = count;
 +      tc->data_len = count;
  
 -      t->data = MEM_callocN(t->total * sizeof(TransData), "TransData(NLA Editor)");
 -      td = t->data;
 -      t->custom.type.data = tdn = MEM_callocN(t->total * sizeof(TransDataNla), "TransDataNla (NLA Editor)");
 -      t->custom.type.use_free = true;
 +      tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransData(NLA Editor)");
 +      td = tc->data;
 +      tc->custom.type.data = tdn = MEM_callocN(tc->data_len * sizeof(TransDataNla), "TransDataNla (NLA Editor)");
 +      tc->custom.type.use_free = true;
  
        /* loop 2: build transdata array */
        for (ale = anim_data.first; ale; ale = ale->next) {
@@@ -3950,11 -3825,11 +3950,11 @@@ typedef struct tGPFtransdata 
  /* This function helps flush transdata written to tempdata into the gp-frames  */
  void flushTransIntFrameActionData(TransInfo *t)
  {
 -      tGPFtransdata *tfd = t->custom.type.data;
 -      int i;
 +      TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
 +      tGPFtransdata *tfd = tc->custom.type.data;
  
        /* flush data! */
 -      for (i = 0; i < t->total; i++, tfd++) {
 +      for (int i = 0; i < tc->data_len; i++, tfd++) {
                *(tfd->sdata) = round_fl_to_int(tfd->val);
        }
  }
@@@ -4111,19 -3986,17 +4111,19 @@@ static void createTransActionData(bCont
                return;
        }
  
 +      TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
 +
        /* allocate memory for data */
 -      t->total = count;
 +      tc->data_len = count;
  
 -      t->data = MEM_callocN(t->total * sizeof(TransData), "TransData(Action Editor)");
 -      t->data2d = MEM_callocN(t->total * sizeof(TransData2D), "transdata2d");
 -      td = t->data;
 -      td2d = t->data2d;
 +      tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransData(Action Editor)");
 +      tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D), "transdata2d");
 +      td = tc->data;
 +      td2d = tc->data_2d;
  
        if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
 -              t->custom.type.data = tfd = MEM_callocN(sizeof(tGPFtransdata) * count, "tGPFtransdata");
 -              t->custom.type.use_free = true;
 +              tc->custom.type.data = tfd = MEM_callocN(sizeof(tGPFtransdata) * count, "tGPFtransdata");
 +              tc->custom.type.use_free = true;
        }
  
        /* loop 2: build transdata array */
  
        /* calculate distances for proportional editing */
        if (is_prop_edit) {
 -              td = t->data;
 +              td = tc->data;
  
                for (ale = anim_data.first; ale; ale = ale->next) {
                        AnimData *adt;
@@@ -4511,20 -4384,18 +4511,20 @@@ static void createTransGraphEditData(bC
                return;
        }
  
 +      TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
 +
        /* allocate&n