Merge branch 'master' into blender2.8
[blender.git] / source / blender / editors / transform / transform_snap.c
index 8bc53127b4ce1635c3293a1a7efe8a4601a3a05d..dc922b5c9badc6f5aebaa23c35d4cc3fa5f20d62 100644 (file)
@@ -49,9 +49,9 @@
 #include "BLI_blenlib.h"
 #include "BLI_utildefines.h"
 
-#include "BIF_gl.h"
+#include "GPU_immediate.h"
+#include "GPU_state.h"
 
-#include "BKE_DerivedMesh.h"
 #include "BKE_global.h"
 #include "BKE_object.h"
 #include "BKE_anim.h"  /* for duplis */
@@ -70,6 +70,8 @@
 #include "ED_view3d.h"
 #include "ED_transform_snap_object_context.h"
 
+#include "DEG_depsgraph.h"
+
 #include "UI_resources.h"
 #include "UI_view2d.h"
 
@@ -153,82 +155,58 @@ void drawSnapping(const struct bContext *C, TransInfo *t)
        if (t->spacetype == SPACE_VIEW3D) {
                if (validSnap(t)) {
                        TransSnapPoint *p;
-                       View3D *v3d = CTX_wm_view3d(C);
                        RegionView3D *rv3d = CTX_wm_region_view3d(C);
                        float imat[4][4];
                        float size;
 
-                       glDisable(GL_DEPTH_TEST);
+                       GPU_depth_test(false);
 
                        size = 2.5f * UI_GetThemeValuef(TH_VERTEX_SIZE);
 
                        invert_m4_m4(imat, rv3d->viewmat);
 
+                       uint pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT);
+
+                       immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+
                        for (p = t->tsnap.points.first; p; p = p->next) {
                                if (p == t->tsnap.selectedPoint) {
-                                       glColor4ubv(selectedCol);
+                                       immUniformColor4ubv(selectedCol);
                                }
                                else {
-                                       glColor4ubv(col);
+                                       immUniformColor4ubv(col);
                                }
 
-                               drawcircball(GL_LINE_LOOP, p->co, ED_view3d_pixel_size(rv3d, p->co) * size * 0.75f, imat);
+                               imm_drawcircball(p->co, ED_view3d_pixel_size(rv3d, p->co) * size * 0.75f, imat, pos);
                        }
 
                        if (t->tsnap.status & POINT_INIT) {
-                               glColor4ubv(activeCol);
+                               immUniformColor4ubv(activeCol);
 
-                               drawcircball(GL_LINE_LOOP, t->tsnap.snapPoint, ED_view3d_pixel_size(rv3d, t->tsnap.snapPoint) * size, imat);
+                               imm_drawcircball(t->tsnap.snapPoint, ED_view3d_pixel_size(rv3d, t->tsnap.snapPoint) * size, imat, pos);
                        }
 
                        /* draw normal if needed */
                        if (usingSnappingNormal(t) && validSnappingNormal(t)) {
-                               glColor4ubv(activeCol);
-
-                               glBegin(GL_LINES);
-                               glVertex3f(t->tsnap.snapPoint[0], t->tsnap.snapPoint[1], t->tsnap.snapPoint[2]);
-                               glVertex3f(t->tsnap.snapPoint[0] + t->tsnap.snapNormal[0],
-                                          t->tsnap.snapPoint[1] + t->tsnap.snapNormal[1],
-                                          t->tsnap.snapPoint[2] + t->tsnap.snapNormal[2]);
-                               glEnd();
+                               immUniformColor4ubv(activeCol);
+
+                               immBegin(GWN_PRIM_LINES, 2);
+                               immVertex3f(pos, t->tsnap.snapPoint[0], t->tsnap.snapPoint[1], t->tsnap.snapPoint[2]);
+                               immVertex3f(pos, t->tsnap.snapPoint[0] + t->tsnap.snapNormal[0],
+                                           t->tsnap.snapPoint[1] + t->tsnap.snapNormal[1],
+                                           t->tsnap.snapPoint[2] + t->tsnap.snapNormal[2]);
+                               immEnd();
                        }
 
-                       if (v3d->zbuf)
-                               glEnable(GL_DEPTH_TEST);
+                       immUnbindProgram();
+
+                       GPU_depth_test(true);
                }
        }
        else if (t->spacetype == SPACE_IMAGE) {
                if (validSnap(t)) {
                        /* This will not draw, and Im nor sure why - campbell */
-#if 0
-                       float xuser_asp, yuser_asp;
-                       int wi, hi;
-                       float w, h;
-
-                       calc_image_view(G.sima, 'f');   // float
-                       myortho2(G.v2d->cur.xmin, G.v2d->cur.xmax, G.v2d->cur.ymin, G.v2d->cur.ymax);
-                       glLoadIdentity();
-
-                       ED_space_image_get_aspect(t->sa->spacedata.first, &xuser_aspx, &yuser_asp);
-                       ED_space_image_width(t->sa->spacedata.first, &wi, &hi);
-                       w = (((float)wi) / IMG_SIZE_FALLBACK) * G.sima->zoom * xuser_asp;
-                       h = (((float)hi) / IMG_SIZE_FALLBACK) * G.sima->zoom * yuser_asp;
-
-                       cpack(0xFFFFFF);
-                       glTranslate2fv(t->tsnap.snapPoint);
-
-                       //glRectf(0, 0, 1, 1);
-
-                       setlinestyle(0);
-                       cpack(0x0);
-                       fdrawline(-0.020 / w, 0, -0.1 / w, 0);
-                       fdrawline(0.1 / w, 0, 0.020 / w, 0);
-                       fdrawline(0, -0.020 / h, 0, -0.1 / h);
-                       fdrawline(0, 0.1 / h, 0, 0.020 / h);
-
-                       glTranslatef(-t->tsnap.snapPoint[0], -t->tsnap.snapPoint[1], 0.0f);
-                       setlinestyle(0);
-#endif
+                       /* TODO: see 2.7x for non-working code */
                }
        }
        else if (t->spacetype == SPACE_NODE) {
@@ -239,26 +217,32 @@ void drawSnapping(const struct bContext *C, TransInfo *t)
 
                        size = 2.5f * UI_GetThemeValuef(TH_VERTEX_SIZE);
 
-                       glEnable(GL_BLEND);
+                       GPU_blend(true);
+
+                       uint pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+
+                       immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
 
                        for (p = t->tsnap.points.first; p; p = p->next) {
                                if (p == t->tsnap.selectedPoint) {
-                                       glColor4ubv(selectedCol);
+                                       immUniformColor4ubv(selectedCol);
                                }
                                else {
-                                       glColor4ubv(col);
+                                       immUniformColor4ubv(col);
                                }
 
-                               ED_node_draw_snap(&ar->v2d, p->co, size, 0);
+                               ED_node_draw_snap(&ar->v2d, p->co, size, 0, pos);
                        }
 
                        if (t->tsnap.status & POINT_INIT) {
-                               glColor4ubv(activeCol);
+                               immUniformColor4ubv(activeCol);
 
-                               ED_node_draw_snap(&ar->v2d, t->tsnap.snapPoint, size, t->tsnap.snapNodeBorder);
+                               ED_node_draw_snap(&ar->v2d, t->tsnap.snapPoint, size, t->tsnap.snapNodeBorder, pos);
                        }
 
-                       glDisable(GL_BLEND);
+                       immUnbindProgram();
+
+                       GPU_blend(false);
                }
        }
 }
@@ -284,93 +268,88 @@ eRedrawFlag handleSnapping(TransInfo *t, const wmEvent *event)
 
 void applyProject(TransInfo *t)
 {
-       Main *bmain = CTX_data_main(t->context);
-
        /* XXX FLICKER IN OBJECT MODE */
        if ((t->tsnap.project) && activeSnap(t) && (t->flag & T_NO_PROJECT) == 0) {
-               TransData *td = t->data;
                float tvec[3];
-               float imat[4][4];
                int i;
 
-               if (t->flag & (T_EDIT | T_POSE)) {
-                       Object *ob = t->obedit ? t->obedit : t->poseobj;
-                       invert_m4_m4(imat, ob->obmat);
-               }
+               FOREACH_TRANS_DATA_CONTAINER(t, tc) {
+                       TransData *td = tc->data;
+                       for (i = 0; i < tc->data_len; i++, td++) {
+                               float iloc[3], loc[3], no[3];
+                               float mval_fl[2];
 
-               for (i = 0; i < t->total; i++, td++) {
-                       float iloc[3], loc[3], no[3];
-                       float mval_fl[2];
-                       float dist_px = TRANSFORM_DIST_MAX_PX;
+                               if (td->flag & TD_NOACTION)
+                                       break;
 
-                       if (td->flag & TD_NOACTION)
-                               break;
+                               if (td->flag & TD_SKIP)
+                                       continue;
 
-                       if (td->flag & TD_SKIP)
-                               continue;
+                               if ((t->flag & T_PROP_EDIT) && (td->factor == 0.0f))
+                                       continue;
 
-                       if ((t->flag & T_PROP_EDIT) && (td->factor == 0.0f))
-                               continue;
-
-                       copy_v3_v3(iloc, td->loc);
-                       if (t->flag & (T_EDIT | T_POSE)) {
-                               Object *ob = t->obedit ? t->obedit : t->poseobj;
-                               mul_m4_v3(ob->obmat, iloc);
-                       }
-                       else if (t->flag & T_OBJECT) {
-                               BKE_object_eval_transform_all(bmain->eval_ctx, t->scene, td->ob);
-                               copy_v3_v3(iloc, td->ob->obmat[3]);
-                       }
+                               copy_v3_v3(iloc, td->loc);
+                               if (tc->use_local_mat) {
+                                       mul_m4_v3(tc->mat, iloc);
+                               }
+                               else if (t->flag & T_OBJECT) {
+                                       BKE_object_eval_transform_all(t->depsgraph, t->scene, td->ob);
+                                       copy_v3_v3(iloc, td->ob->obmat[3]);
+                               }
 
-                       if (ED_view3d_project_float_global(t->ar, iloc, mval_fl, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
-                               if (snapObjectsTransform(
-                                       t, mval_fl, &dist_px,
-                                       loc, no))
-                               {
-//                                     if (t->flag & (T_EDIT|T_POSE)) {
-//                                             mul_m4_v3(imat, loc);
-//                                     }
+                               if (ED_view3d_project_float_global(t->ar, iloc, mval_fl, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
+                                       if (ED_transform_snap_object_project_view3d(
+                                               t->tsnap.object_context,
+                                               SCE_SNAP_MODE_FACE,
+                                               &(const struct SnapObjectParams){
+                                                   .snap_select = t->tsnap.modeSelect,
+                                                   .use_object_edit_cage = (t->flag & T_EDIT) != 0,
+                                                   .use_occlusion_test = false,
+                                               },
+                                               mval_fl, 0, loc, no))
+                                       {
+#if 0
+                                               if (tc->use_local_mat) {
+                                                       mul_m4_v3(tc->imat, loc);
+                                               }
+#endif
 
-                                       sub_v3_v3v3(tvec, loc, iloc);
+                                               sub_v3_v3v3(tvec, loc, iloc);
 
-                                       mul_m3_v3(td->smtx, tvec);
+                                               mul_m3_v3(td->smtx, tvec);
 
-                                       add_v3_v3(td->loc, tvec);
+                                               add_v3_v3(td->loc, tvec);
 
-                                       if (t->tsnap.align && (t->flag & T_OBJECT)) {
-                                               /* handle alignment as well */
-                                               const float *original_normal;
-                                               float mat[3][3];
+                                               if (t->tsnap.align && (t->flag & T_OBJECT)) {
+                                                       /* handle alignment as well */
+                                                       const float *original_normal;
+                                                       float mat[3][3];
 
-                                               /* In pose mode, we want to align normals with Y axis of bones... */
-                                               original_normal = td->axismtx[2];
+                                                       /* In pose mode, we want to align normals with Y axis of bones... */
+                                                       original_normal = td->axismtx[2];
 
-                                               rotation_between_vecs_to_mat3(mat, original_normal, no);
+                                                       rotation_between_vecs_to_mat3(mat, original_normal, no);
 
-                                               transform_data_ext_rotate(td, mat, true);
+                                                       transform_data_ext_rotate(td, mat, true);
 
-                                               /* TODO support constraints for rotation too? see ElementRotation */
+                                                       /* TODO support constraints for rotation too? see ElementRotation */
+                                               }
                                        }
                                }
-                       }
 
-                       //XXX constraintTransLim(t, td);
+                               //XXX constraintTransLim(t, td);
+                       }
                }
        }
 }
 
 void applyGridAbsolute(TransInfo *t)
 {
-       Main *bmain = CTX_data_main(t->context);
-
        float grid_size = 0.0f;
        GearsType grid_action;
-       TransData *td;
-       float (*obmat)[4] = NULL;
-       bool use_obmat = false;
        int i;
 
-       if (!(activeSnap(t) && (ELEM(t->tsnap.mode, SCE_SNAP_MODE_INCREMENT, SCE_SNAP_MODE_GRID))))
+       if (!(activeSnap(t) && (t->tsnap.mode & (SCE_SNAP_MODE_INCREMENT | SCE_SNAP_MODE_GRID))))
                return;
 
        grid_action = BIG_GEARS;
@@ -386,57 +365,58 @@ void applyGridAbsolute(TransInfo *t)
        if (grid_size == 0.0f)
                return;
 
-       if (t->flag & (T_EDIT | T_POSE)) {
-               Object *ob = t->obedit ? t->obedit : t->poseobj;
-               obmat = ob->obmat;
-               use_obmat = true;
-       }
+       FOREACH_TRANS_DATA_CONTAINER(t, tc) {
+               TransData *td;
 
-       for (i = 0, td = t->data; i < t->total; i++, td++) {
-               float iloc[3], loc[3], tvec[3];
+               for (i = 0, td = tc->data; i < tc->data_len; i++, td++) {
+                       float iloc[3], loc[3], tvec[3];
 
-               if (td->flag & TD_NOACTION)
-                       break;
+                       if (td->flag & TD_NOACTION)
+                               break;
 
-               if (td->flag & TD_SKIP)
-                       continue;
+                       if (td->flag & TD_SKIP)
+                               continue;
 
-               if ((t->flag & T_PROP_EDIT) && (td->factor == 0.0f))
-                       continue;
+                       if ((t->flag & T_PROP_EDIT) && (td->factor == 0.0f))
+                               continue;
 
-               copy_v3_v3(iloc, td->loc);
-               if (use_obmat) {
-                       mul_m4_v3(obmat, iloc);
-               }
-               else if (t->flag & T_OBJECT) {
-                       BKE_object_eval_transform_all(bmain->eval_ctx, t->scene, td->ob);
-                       copy_v3_v3(iloc, td->ob->obmat[3]);
-               }
+                       copy_v3_v3(iloc, td->loc);
+                       if (tc->use_local_mat) {
+                               mul_m4_v3(tc->mat, iloc);
+                       }
+                       else if (t->flag & T_OBJECT) {
+                               BKE_object_eval_transform_all(t->depsgraph, t->scene, td->ob);
+                               copy_v3_v3(iloc, td->ob->obmat[3]);
+                       }
 
-               mul_v3_v3fl(loc, iloc, 1.0f / grid_size);
-               loc[0] = roundf(loc[0]);
-               loc[1] = roundf(loc[1]);
-               loc[2] = roundf(loc[2]);
-               mul_v3_fl(loc, grid_size);
+                       mul_v3_v3fl(loc, iloc, 1.0f / grid_size);
+                       loc[0] = roundf(loc[0]);
+                       loc[1] = roundf(loc[1]);
+                       loc[2] = roundf(loc[2]);
+                       mul_v3_fl(loc, grid_size);
 
-               sub_v3_v3v3(tvec, loc, iloc);
-               mul_m3_v3(td->smtx, tvec);
-               add_v3_v3(td->loc, tvec);
+                       sub_v3_v3v3(tvec, loc, iloc);
+                       mul_m3_v3(td->smtx, tvec);
+                       add_v3_v3(td->loc, tvec);
+               }
        }
 }
 
 void applySnapping(TransInfo *t, float *vec)
 {
-       /* project is not applied this way */
-       if (t->tsnap.project)
+       if (t->tsnap.project && t->tsnap.mode == SCE_SNAP_MODE_FACE) {
+               /* Each Trans Data already makes the snap to face */
                return;
+       }
 
        if (t->tsnap.status & SNAP_FORCED) {
                t->tsnap.targetSnap(t);
 
                t->tsnap.applySnap(t, vec);
        }
-       else if (!ELEM(t->tsnap.mode, SCE_SNAP_MODE_INCREMENT, SCE_SNAP_MODE_GRID) && activeSnap(t)) {
+       else if (((t->tsnap.mode & ~(SCE_SNAP_MODE_INCREMENT | SCE_SNAP_MODE_GRID)) != 0) &&
+                activeSnap(t))
+       {
                double current = PIL_check_seconds_timer();
 
                // Time base quirky code to go around findnearest slowness
@@ -520,9 +500,10 @@ static void initSnappingMode(TransInfo *t)
 {
        Main *bmain = CTX_data_main(t->context);
        ToolSettings *ts = t->settings;
-       Object *obedit = t->obedit;
-       Scene *scene = t->scene;
-       Base *base_act = scene->basact;
+       /* All obedit types will match. */
+       const int obedit_type = t->data_container->obedit ? t->data_container->obedit->type : -1;
+       ViewLayer *view_layer = t->view_layer;
+       Base *base_act = view_layer->basact;
 
        if (t->spacetype == SPACE_NODE) {
                /* force project off when not supported */
@@ -538,7 +519,7 @@ static void initSnappingMode(TransInfo *t)
        }
        else {
                /* force project off when not supported */
-               if (ts->snap_mode != SCE_SNAP_MODE_FACE)
+               if ((ts->snap_mode & SCE_SNAP_MODE_FACE) == 0)
                        t->tsnap.project = 0;
 
                t->tsnap.mode = ts->snap_mode;
@@ -551,10 +532,10 @@ static void initSnappingMode(TransInfo *t)
 
                /* Edit mode */
                if (t->tsnap.applySnap != NULL && // A snapping function actually exist
-                   (obedit != NULL && ELEM(obedit->type, OB_MESH, OB_ARMATURE, OB_CURVE, OB_LATTICE, OB_MBALL)) ) // Temporary limited to edit mode meshes, armature, curves, mballs
+                   ((obedit_type != -1) && ELEM(obedit_type, OB_MESH, OB_ARMATURE, OB_CURVE, OB_LATTICE, OB_MBALL)) ) // Temporary limited to edit mode meshes, armature, curves, mballs
                {
                        /* Exclude editmesh if using proportional edit */
-                       if ((obedit->type == OB_MESH) && (t->flag & T_PROP_EDIT)) {
+                       if ((obedit_type == OB_MESH) && (t->flag & T_PROP_EDIT)) {
                                t->tsnap.modeSelect = SNAP_NOT_ACTIVE;
                        }
                        else {
@@ -563,17 +544,19 @@ static void initSnappingMode(TransInfo *t)
                }
                /* Particles edit mode*/
                else if (t->tsnap.applySnap != NULL && // A snapping function actually exist
-                        (obedit == NULL && base_act && base_act->object && base_act->object->mode & OB_MODE_PARTICLE_EDIT))
+                        ((obedit_type == -1) && base_act && base_act->object && base_act->object->mode & OB_MODE_PARTICLE_EDIT))
                {
                        t->tsnap.modeSelect = SNAP_ALL;
                }
                /* Object mode */
                else if (t->tsnap.applySnap != NULL && // A snapping function actually exist
-                        (obedit == NULL) ) // Object Mode
+                        (obedit_type == -1) ) // Object Mode
                {
                        /* In "Edit Strokes" mode, Snap tool can perform snap to selected or active objects (see T49632)
                         * TODO: perform self snap in gpencil_strokes */
-                       t->tsnap.modeSelect = ((t->options & CTX_GPENCIL_STROKES) != 0) ? SNAP_ALL : SNAP_NOT_SELECTED;
+                       t->tsnap.modeSelect = (
+                               ((t->options & (CTX_GPENCIL_STROKES | CTX_CURSOR)) != 0) ?
+                               SNAP_ALL : SNAP_NOT_SELECTED);
                }
                else {
                        /* Grid if snap is not possible */
@@ -603,8 +586,7 @@ static void initSnappingMode(TransInfo *t)
        if (t->spacetype == SPACE_VIEW3D) {
                if (t->tsnap.object_context == NULL) {
                        t->tsnap.object_context = ED_transform_snap_object_context_create_view3d(
-                               bmain, t->scene, 0,
-                               t->ar, t->view);
+                               bmain, t->scene, t->depsgraph, 0, t->ar, t->view);
 
                        ED_transform_snap_object_context_set_editmesh_callbacks(
                                t->tsnap.object_context,
@@ -883,7 +865,8 @@ static float TranslationBetween(TransInfo *UNUSED(t), const float p1[3], const f
        return len_squared_v3v3(p1, p2);
 }
 
-static float RotationBetween(TransInfo *t, const float p1[3], const float p2[3])
+static float RotationBetween(
+        TransInfo *t, const float p1[3], const float p2[3])
 {
        float angle, start[3], end[3];
 
@@ -894,7 +877,7 @@ static float RotationBetween(TransInfo *t, const float p1[3], const float p2[3])
        if (t->con.applyRot != NULL && (t->con.mode & CON_APPLY)) {
                float axis[3], tmp[3];
 
-               t->con.applyRot(t, NULL, axis, NULL);
+               t->con.applyRot(t, NULL, NULL, axis, NULL);
 
                project_v3_v3v3(tmp, end, axis);
                sub_v3_v3v3(end, end, tmp);
@@ -974,18 +957,22 @@ static void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec))
                mval[0] = t->mval[0];
                mval[1] = t->mval[1];
 
-               if (t->tsnap.mode == SCE_SNAP_MODE_VOLUME) {
-                       found = peelObjectsTransform(
-                               t, mval,
-                               (t->settings->snap_flag & SCE_SNAP_PEEL_OBJECT) != 0,
-                               loc, no, NULL);
-               }
-               else {
+               if (t->tsnap.mode &
+                   (SCE_SNAP_MODE_VERTEX |
+                    SCE_SNAP_MODE_EDGE   |
+                    SCE_SNAP_MODE_FACE))
+               {
                        zero_v3(no);  /* objects won't set this */
                        found = snapObjectsTransform(
                                t, mval, &dist_px,
                                loc, no);
                }
+               if ((found == false) && (t->tsnap.mode & SCE_SNAP_MODE_VOLUME)) {
+                       found = peelObjectsTransform(
+                               t, mval,
+                               (t->settings->snap_flag & SCE_SNAP_PEEL_OBJECT) != 0,
+                               loc, no, NULL);
+               }
 
                if (found == true) {
                        copy_v3_v3(t->tsnap.snapPoint, loc);
@@ -997,36 +984,39 @@ static void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec))
                        t->tsnap.status &= ~POINT_INIT;
                }
        }
-       else if (t->spacetype == SPACE_IMAGE && t->obedit != NULL && t->obedit->type == OB_MESH) {
-               /* same as above but for UV's */
-               Image *ima = ED_space_image(t->sa->spacedata.first);
-               float co[2];
+       else if (t->spacetype == SPACE_IMAGE && t->obedit_type == OB_MESH) {
+               if (t->tsnap.mode & SCE_SNAP_MODE_VERTEX) {
+                       Image *ima = ED_space_image(t->sa->spacedata.first);
+                       float co[2];
 
-               UI_view2d_region_to_view(&t->ar->v2d, t->mval[0], t->mval[1], &co[0], &co[1]);
+                       UI_view2d_region_to_view(&t->ar->v2d, t->mval[0], t->mval[1], &co[0], &co[1]);
 
-               if (ED_uvedit_nearest_uv(t->scene, t->obedit, ima, co, t->tsnap.snapPoint)) {
-                       t->tsnap.snapPoint[0] *= t->aspect[0];
-                       t->tsnap.snapPoint[1] *= t->aspect[1];
+                       if (ED_uvedit_nearest_uv(t->scene, TRANS_DATA_CONTAINER_FIRST_EVIL(t)->obedit, ima, co, t->tsnap.snapPoint)) {
+                               t->tsnap.snapPoint[0] *= t->aspect[0];
+                               t->tsnap.snapPoint[1] *= t->aspect[1];
 
-                       t->tsnap.status |=  POINT_INIT;
-               }
-               else {
-                       t->tsnap.status &= ~POINT_INIT;
+                               t->tsnap.status |= POINT_INIT;
+                       }
+                       else {
+                               t->tsnap.status &= ~POINT_INIT;
+                       }
                }
        }
        else if (t->spacetype == SPACE_NODE) {
-               float loc[2];
-               float dist_px = SNAP_MIN_DISTANCE; // Use a user defined value here
-               char node_border;
+               if (t->tsnap.mode & (SCE_SNAP_MODE_NODE_X | SCE_SNAP_MODE_NODE_Y)) {
+                       float loc[2];
+                       float dist_px = SNAP_MIN_DISTANCE; // Use a user defined value here
+                       char node_border;
 
-               if (snapNodesTransform(t, t->mval, loc, &dist_px, &node_border)) {
-                       copy_v2_v2(t->tsnap.snapPoint, loc);
-                       t->tsnap.snapNodeBorder = node_border;
+                       if (snapNodesTransform(t, t->mval, loc, &dist_px, &node_border)) {
+                               copy_v2_v2(t->tsnap.snapPoint, loc);
+                               t->tsnap.snapNodeBorder = node_border;
 
-                       t->tsnap.status |=  POINT_INIT;
-               }
-               else {
-                       t->tsnap.status &= ~POINT_INIT;
+                               t->tsnap.status |= POINT_INIT;
+                       }
+                       else {
+                               t->tsnap.status &= ~POINT_INIT;
+                       }
                }
        }
 }
@@ -1079,11 +1069,6 @@ static void TargetSnapActive(TransInfo *t)
        /* Only need to calculate once */
        if ((t->tsnap.status & TARGET_INIT) == 0) {
                if (calculateCenterActive(t, true, t->tsnap.snapTarget)) {
-                       if (t->flag & (T_EDIT | T_POSE)) {
-                               Object *ob = t->obedit ? t->obedit : t->poseobj;
-                               mul_m4_v3(ob->obmat, t->tsnap.snapTarget);
-                       }
-
                        TargetSnapOffset(t, NULL);
 
                        t->tsnap.status |= TARGET_INIT;
@@ -1101,23 +1086,30 @@ static void TargetSnapMedian(TransInfo *t)
 {
        // Only need to calculate once
        if ((t->tsnap.status & TARGET_INIT) == 0) {
-               TransData *td = NULL;
-               int i;
+               int i_accum = 0;
 
                t->tsnap.snapTarget[0] = 0;
                t->tsnap.snapTarget[1] = 0;
                t->tsnap.snapTarget[2] = 0;
 
-               for (td = t->data, i = 0; i < t->total && td->flag & TD_SELECTED; i++, td++) {
-                       add_v3_v3(t->tsnap.snapTarget, td->center);
+               FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+                       TransData *td = tc->data;
+                       int i;
+                       for (i = 0; i < tc->data_len && td->flag & TD_SELECTED; i++, td++) {
+                               /* TODO(campbell): perform the global transformation once per TransDataContainer */
+                               if (tc->use_local_mat) {
+                                       float v[3];
+                                       mul_v3_m4v3(v, tc->mat, td->center);
+                                       add_v3_v3(t->tsnap.snapTarget, v);
+                               }
+                               else {
+                                       add_v3_v3(t->tsnap.snapTarget, td->center);
+                               }
+                       }
+                       i_accum += i;
                }
 
-               mul_v3_fl(t->tsnap.snapTarget, 1.0 / i);
-
-               if (t->flag & (T_EDIT | T_POSE)) {
-                       Object *ob = t->obedit ? t->obedit : t->poseobj;
-                       mul_m4_v3(ob->obmat, t->tsnap.snapTarget);
-               }
+               mul_v3_fl(t->tsnap.snapTarget, 1.0 / i_accum);
 
                TargetSnapOffset(t, NULL);
 
@@ -1130,24 +1122,44 @@ static void TargetSnapClosest(TransInfo *t)
        // Only valid if a snap point has been selected
        if (t->tsnap.status & POINT_INIT) {
                float dist_closest = 0.0f;
-               TransData *closest = NULL, *td = NULL;
+               TransData *closest = NULL;
 
                /* Object mode */
                if (t->flag & T_OBJECT) {
                        int i;
-                       for (td = t->data, i = 0; i < t->total && td->flag & TD_SELECTED; i++, td++) {
-                               struct BoundBox *bb = BKE_object_boundbox_get(td->ob);
-
-                               /* use boundbox if possible */
-                               if (bb) {
-                                       int j;
-
-                                       for (j = 0; j < 8; j++) {
+                       FOREACH_TRANS_DATA_CONTAINER(t, tc) {
+                               TransData *td = tc->data;
+                               for (td = tc->data, i = 0; i < tc->data_len && td->flag & TD_SELECTED; i++, td++) {
+                                       struct BoundBox *bb = BKE_object_boundbox_get(td->ob);
+
+                                       /* use boundbox if possible */
+                                       if (bb) {
+                                               int j;
+
+                                               for (j = 0; j < 8; j++) {
+                                                       float loc[3];
+                                                       float dist;
+
+                                                       copy_v3_v3(loc, bb->vec[j]);
+                                                       mul_m4_v3(td->ext->obmat, loc);
+
+                                                       dist = t->tsnap.distance(t, loc, t->tsnap.snapPoint);
+
+                                                       if ((dist != TRANSFORM_DIST_INVALID) &&
+                                                           (closest == NULL || fabsf(dist) < fabsf(dist_closest)))
+                                                       {
+                                                               copy_v3_v3(t->tsnap.snapTarget, loc);
+                                                               closest = td;
+                                                               dist_closest = dist;
+                                                       }
+                                               }
+                                       }
+                                       /* use element center otherwise */
+                                       else {
                                                float loc[3];
                                                float dist;
 
-                                               copy_v3_v3(loc, bb->vec[j]);
-                                               mul_m4_v3(td->ext->obmat, loc);
+                                               copy_v3_v3(loc, td->center);
 
                                                dist = t->tsnap.distance(t, loc, t->tsnap.snapPoint);
 
@@ -1156,17 +1168,25 @@ static void TargetSnapClosest(TransInfo *t)
                                                {
                                                        copy_v3_v3(t->tsnap.snapTarget, loc);
                                                        closest = td;
-                                                       dist_closest = dist;
                                                }
                                        }
                                }
-                               /* use element center otherwise */
-                               else {
+                       }
+               }
+               else {
+                       FOREACH_TRANS_DATA_CONTAINER(t, tc) {
+                               TransData *td = tc->data;
+                               int i;
+                               for (i = 0; i < tc->data_len && td->flag & TD_SELECTED; i++, td++) {
                                        float loc[3];
                                        float dist;
 
                                        copy_v3_v3(loc, td->center);
 
+                                       if (tc->use_local_mat) {
+                                               mul_m4_v3(tc->mat, loc);
+                                       }
+
                                        dist = t->tsnap.distance(t, loc, t->tsnap.snapPoint);
 
                                        if ((dist != TRANSFORM_DIST_INVALID) &&
@@ -1174,34 +1194,11 @@ static void TargetSnapClosest(TransInfo *t)
                                        {
                                                copy_v3_v3(t->tsnap.snapTarget, loc);
                                                closest = td;
+                                               dist_closest = dist;
                                        }
                                }
                        }
                }
-               else {
-                       int i;
-                       for (td = t->data, i = 0; i < t->total && td->flag & TD_SELECTED; i++, td++) {
-                               float loc[3];
-                               float dist;
-
-                               copy_v3_v3(loc, td->center);
-
-                               if (t->flag & (T_EDIT | T_POSE)) {
-                                       Object *ob = t->obedit ? t->obedit : t->poseobj;
-                                       mul_m4_v3(ob->obmat, loc);
-                               }
-
-                               dist = t->tsnap.distance(t, loc, t->tsnap.snapPoint);
-
-                               if ((dist != TRANSFORM_DIST_INVALID) &&
-                                   (closest == NULL || fabsf(dist) < fabsf(dist_closest)))
-                               {
-                                       copy_v3_v3(t->tsnap.snapTarget, loc);
-                                       closest = td;
-                                       dist_closest = dist;
-                               }
-                       }
-               }
 
                TargetSnapOffset(t, closest);
 
@@ -1214,16 +1211,15 @@ bool snapObjectsTransform(
         float *dist_px,
         float r_loc[3], float r_no[3])
 {
-       return ED_transform_snap_object_project_view3d_ex(
+       return ED_transform_snap_object_project_view3d(
                t->tsnap.object_context,
                t->scene->toolsettings->snap_mode,
                &(const struct SnapObjectParams){
                    .snap_select = t->tsnap.modeSelect,
                    .use_object_edit_cage = (t->flag & T_EDIT) != 0,
+                   .use_occlusion_test = t->scene->toolsettings->snap_mode != SCE_SNAP_MODE_FACE,
                },
-               mval, dist_px, NULL,
-               r_loc, r_no, NULL,
-               NULL, NULL);
+               mval, dist_px, r_loc, r_no);
 }
 
 
@@ -1329,15 +1325,14 @@ static bool snapNodeTest(View2D *v2d, bNode *node, eSnapSelect snap_select)
 
 static NodeBorder snapNodeBorder(int snap_node_mode)
 {
-       switch (snap_node_mode) {
-               case SCE_SNAP_MODE_NODE_X:
-                       return NODE_LEFT | NODE_RIGHT;
-               case SCE_SNAP_MODE_NODE_Y:
-                       return NODE_TOP | NODE_BOTTOM;
-               case SCE_SNAP_MODE_NODE_XY:
-                       return NODE_LEFT | NODE_RIGHT | NODE_TOP | NODE_BOTTOM;
+       NodeBorder flag = 0;
+       if (snap_node_mode & SCE_SNAP_MODE_NODE_X) {
+               flag |= NODE_LEFT | NODE_RIGHT;
        }
-       return 0;
+       if (snap_node_mode & SCE_SNAP_MODE_NODE_Y) {
+               flag |= NODE_TOP | NODE_BOTTOM;
+       }
+       return flag;
 }
 
 static bool snapNode(
@@ -1445,9 +1440,13 @@ void snapGridIncrement(TransInfo *t, float *val)
 {
        GearsType action;
 
-       /* only do something if using absolute or incremental grid snapping */
-       if (!ELEM(t->tsnap.mode, SCE_SNAP_MODE_INCREMENT, SCE_SNAP_MODE_GRID))
+       /* only do something if using absolute or incremental grid snapping
+        * and there is no valid snap point */
+       if (!(t->tsnap.mode & (SCE_SNAP_MODE_INCREMENT | SCE_SNAP_MODE_GRID)) ||
+           validSnap(t))
+       {
                return;
+       }
 
        action = activeSnap(t) ? BIG_GEARS : NO_GEARS;
 
@@ -1487,7 +1486,7 @@ static void applyGridIncrement(TransInfo *t, float *val, int max_index, const fl
        const float *asp = use_aspect ? t->aspect : asp_local;
        int i;
 
-       BLI_assert(ELEM(t->tsnap.mode, SCE_SNAP_MODE_INCREMENT, SCE_SNAP_MODE_GRID));
+       BLI_assert(t->tsnap.mode & (SCE_SNAP_MODE_INCREMENT | SCE_SNAP_MODE_GRID));
        BLI_assert(max_index <= 2);
 
        /* Early bailing out if no need to snap */