=== Transform Snap ===
authorMartin Poirier <theeth@yahoo.com>
Sun, 20 Jan 2008 22:43:48 +0000 (22:43 +0000)
committerMartin Poirier <theeth@yahoo.com>
Sun, 20 Jan 2008 22:43:48 +0000 (22:43 +0000)
Snapping Mode: Active

With this mode, the active element (at this time, object or vertice) is used as snapping target. If there is no active element in the selection, it reverts back to median mode.

Edit Mode snapping, other meshes no longer have to be selected to act as snapping point.

Fix a potential bug with snapping point from other meshes.

source/blender/include/transform.h
source/blender/makesdna/DNA_scene_types.h
source/blender/src/header_view3d.c
source/blender/src/transform_conversions.c
source/blender/src/transform_snap.c

index e9e82612721365d2a26db90b3277467c3682f48f..30b9bbf3f51ba945af7240fe6b84010febdad38e 100644 (file)
@@ -265,18 +265,19 @@ typedef struct TransInfo {
 
 /* transdata->flag */
 #define TD_SELECTED                    1
-#define        TD_NOACTION                     2
-#define        TD_USEQUAT                      4
-#define TD_NOTCONNECTED                8
-#define TD_SINGLESIZE          16      /* used for scaling of MetaElem->rad */
+#define TD_ACTIVE                      (1 << 1)
+#define        TD_NOACTION                     (1 << 2)
+#define        TD_USEQUAT                      (1 << 3)
+#define TD_NOTCONNECTED                (1 << 4)
+#define TD_SINGLESIZE          (1 << 5)        /* used for scaling of MetaElem->rad */
 #ifdef WITH_VERSE
-       #define TD_VERSE_OBJECT         32
-       #define TD_VERSE_VERT           64
+       #define TD_VERSE_OBJECT         (1 << 6)
+       #define TD_VERSE_VERT           (1 << 7)
 #endif
-#define TD_TIMEONLY                    128
-#define TD_NOCENTER                    256
-#define TD_NO_EXT                      512     /* ext abused for particle key timing */
-#define TD_SKIP                                1024 /* don't transform this data */
+#define TD_TIMEONLY                    (1 << 8)
+#define TD_NOCENTER                    (1 << 9)
+#define TD_NO_EXT                      (1 << 10)       /* ext abused for particle key timing */
+#define TD_SKIP                                (1 << 11)       /* don't transform this data */
 
 /* transsnap->status */
 #define SNAP_ON                        1
@@ -291,6 +292,7 @@ typedef struct TransInfo {
 #define SNAP_CLOSEST           0
 #define SNAP_CENTER                    1
 #define SNAP_MEDIAN                    2
+#define SNAP_ACTIVE                    3
 
 void checkFirstTime(void);
 
index 200e904bc88673a368010538df83741063ac45b8..b342bc5afe849410958d2e7f68aee8ea46d09c9d 100644 (file)
@@ -663,6 +663,7 @@ typedef struct Scene {
 #define SCE_SNAP_TARGET_CLOSEST        0
 #define SCE_SNAP_TARGET_CENTER 1
 #define SCE_SNAP_TARGET_MEDIAN 2
+#define SCE_SNAP_TARGET_ACTIVE 3
 
 /* sce->selectmode */
 #define SCE_SELECT_VERTEX      1 /* for mesh */
index b476bb6c9447ee4a3a011201e52f9ef4ca5009c1..1c39d286989eb326619e05540ec6dde370e38378 100644 (file)
@@ -1768,6 +1768,9 @@ static void do_view3d_transformmenu(void *arg, int event)
        case 19:
                G.scene->snap_target = SCE_SNAP_TARGET_MEDIAN;
                break;
+       case 20:
+               G.scene->snap_target = SCE_SNAP_TARGET_ACTIVE;
+               break;
        }
        allqueue(REDRAWVIEW3D, 0);
 }
@@ -1839,19 +1842,28 @@ static uiBlock *view3d_transformmenu(void *arg_unused)
                switch(G.scene->snap_target)
                {
                        case SCE_SNAP_TARGET_CLOSEST:
-                               uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Snap Closest",                     0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 17, "");
+                               uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Snap Closest",                             0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 17, "");
                                uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Snap Center",                    0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 18, "");
                                uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Snap Median",                    0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 19, "");
+                               uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Snap Active",                    0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 20, "");
                                break;
                        case SCE_SNAP_TARGET_CENTER:
                                uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Snap Closest",                   0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 17, "");
-                               uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Snap Center",                      0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 18, "");
+                               uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Snap Center",                              0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 18, "");
                                uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Snap Median",                    0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 19, "");
+                               uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Snap Active",                    0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 20, "");
                                break;
                        case SCE_SNAP_TARGET_MEDIAN:
                                uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Snap Closest",                   0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 17, "");
                                uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Snap Center",                    0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 18, "");
-                               uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Snap Median",                      0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 19, "");
+                               uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Snap Median",                              0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 19, "");
+                               uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Snap Active",                    0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 20, "");
+                               break;
+                       case SCE_SNAP_TARGET_ACTIVE:
+                               uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Snap Closest",                   0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 17, "");
+                               uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Snap Center",                    0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 18, "");
+                               uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Snap Median",                    0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 19, "");
+                               uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Snap Active",                              0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 20, "");
                                break;
                }
        }
@@ -5484,7 +5496,7 @@ void view3d_buttons(void)
                        if (G.scene->snap_flag & SCE_SNAP) {
                                uiDefIconButBitS(block, TOG, SCE_SNAP, B_REDR, ICON_SNAP_GEO,xco,0,XIC,YIC, &G.scene->snap_flag, 0, 0, 0, 0, "Use Snap or Grid (Shift Tab)");   
                                xco+= XIC;
-                               uiDefButS(block, MENU, B_NOP, "Mode%t|Closest%x0|Center%x1|Median%x2",xco,0,70,YIC, &G.scene->snap_target, 0, 0, 0, 0, "Snap Target Mode");
+                               uiDefButS(block, MENU, B_NOP, "Mode%t|Closest%x0|Center%x1|Median%x2|Active%x3",xco,0,70,YIC, &G.scene->snap_target, 0, 0, 0, 0, "Snap Target Mode");
                                xco+= 70;
                        } else {
                                uiDefIconButBitS(block, TOG, SCE_SNAP, B_REDR, ICON_SNAP_GEAR,xco,0,XIC,YIC, &G.scene->snap_flag, 0, 0, 0, 0, "Snap while Ctrl is held during transform (Shift Tab)");  
index 3f69316e373c4417edd73c03a7b5425efb4eb1a3..de3e9988f8d335317a75dfdfa54f51a2ebc0615d 100644 (file)
@@ -1952,6 +1952,7 @@ static void createTransEditVerts(TransInfo *t)
        EditMesh *em = G.editMesh;
        EditVert *eve;
        EditVert **nears = NULL;
+       EditVert *eve_act = NULL;
        float *vectors = NULL, *mappedcos = NULL, *quats= NULL;
        float mtx[3][3], smtx[3][3], (*defmats)[3][3] = NULL, (*defcos)[3] = NULL;
        int count=0, countsel=0, a, totleft;
@@ -2002,6 +2003,15 @@ static void createTransEditVerts(TransInfo *t)
        /* note: in prop mode we need at least 1 selected */
        if (countsel==0) return;
        
+       /* check active */
+       if (G.editMesh->selected.last) {
+               EditSelection *ese = G.editMesh->selected.last;
+               if ( ese->type == EDITVERT ) {
+                       eve_act = (EditVert *)ese->data;
+               }
+       }
+
+       
        if(propmode) {
                t->total = count; 
        
@@ -2057,8 +2067,13 @@ static void createTransEditVerts(TransInfo *t)
                if(eve->h==0) {
                        if(propmode || eve->f1) {
                                VertsToTransData(tob, eve);
-
+                               
+                               /* selected */
                                if(eve->f1) tob->flag |= TD_SELECTED;
+                               
+                               /* active */
+                               if(eve == eve_act) tob->flag |= TD_ACTIVE;
+                               
                                if(propmode) {
                                        if (eve->f2) {
                                                float vec[3];
@@ -2883,6 +2898,13 @@ static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob)
                Mat3One(td->smtx);
                Mat3One(td->mtx);
        }
+       
+       /* set active flag */
+       if (BASACT && BASACT->object == ob)
+       {
+               td->flag |= TD_ACTIVE;
+       }
+       
 #ifdef WITH_VERSE
        if(ob->vnode) {
                td->verse = (void*)ob;
index 3279e6e6f09be86bbda831aa4bf6be466d5e6f3c..c0f634a3f670781a95cc96ce21a46f227df177f8 100644 (file)
@@ -85,12 +85,15 @@ void CalcSnapGeometry(TransInfo *t, float *vec);
 void TargetSnapMedian(TransInfo *t);
 void TargetSnapCenter(TransInfo *t);
 void TargetSnapClosest(TransInfo *t);
+void TargetSnapActive(TransInfo *t);
 
 float RotationBetween(TransInfo *t, float p1[3], float p2[3]);
 float TranslationBetween(TransInfo *t, float p1[3], float p2[3]);
 
-// Trickery
-int findNearestVertFromObjects(int *dist, float *loc, int selected);
+/* Modes */
+#define NOT_SELECTED 0
+#define NOT_ACTIVE 1
+int findNearestVertFromObjects(int *dist, float *loc, int mode);
 
 /****************** IMPLEMENTATIONS *********************/
 
@@ -277,6 +280,11 @@ void setSnappingCallback(TransInfo *t)
                        t->tsnap.modeTarget = SNAP_MEDIAN;
                        t->tsnap.targetSnap = TargetSnapMedian;
                        break;
+               case SCE_SNAP_TARGET_ACTIVE:
+                       t->tsnap.modeTarget = SNAP_ACTIVE;
+                       t->tsnap.targetSnap = TargetSnapActive;
+                       break;
+
        }
 
        switch (t->mode)
@@ -391,6 +399,7 @@ void CalcSnapGrid(TransInfo *t, float *vec)
 
 void CalcSnapGeometry(TransInfo *t, float *vec)
 {
+       /* Object mode */
        if (G.obedit == NULL)
        {
                if (t->spacetype == SPACE_VIEW3D)
@@ -399,7 +408,7 @@ void CalcSnapGeometry(TransInfo *t, float *vec)
                        int found = 0;
                        int dist = 40; // Use a user defined value here
                        
-                       found = findNearestVertFromObjects(&dist, vec, 0);
+                       found = findNearestVertFromObjects(&dist, vec, NOT_SELECTED);
                        if (found == 1)
                        {
                                VECCOPY(t->tsnap.snapPoint, vec);
@@ -412,6 +421,7 @@ void CalcSnapGeometry(TransInfo *t, float *vec)
                        }
                }
        }
+       /* Mesh edit mode */
        else if (G.obedit != NULL && G.obedit->type==OB_MESH)
        {
                /*if (G.scene->selectmode & B_SEL_VERT)*/
@@ -426,7 +436,7 @@ void CalcSnapGeometry(TransInfo *t, float *vec)
                        // use findnearestverts in vert mode, others in other modes
                        nearest = findnearestvert(&dist, SELECT, 1);
                        
-                       found = findNearestVertFromObjects(&dist, vec, SELECT);
+                       found = findNearestVertFromObjects(&dist, vec, NOT_ACTIVE);
                        if (found == 1)
                        {
                                VECCOPY(t->tsnap.snapPoint, vec);
@@ -513,6 +523,45 @@ void TargetSnapCenter(TransInfo *t)
        }
 }
 
+void TargetSnapActive(TransInfo *t)
+{
+       // Only need to calculate once
+       if ((t->tsnap.status & TARGET_INIT) == 0)
+       {
+               TransData *td = NULL;
+               TransData *active_td = NULL;
+               int i;
+
+               for(td = t->data, i = 0 ; i < t->total && td->flag & TD_SELECTED ; i++, td++)
+               {
+                       if (td->flag & TD_ACTIVE)
+                       {
+                               active_td = td;
+                               break;
+                       }
+               }
+
+               if (active_td)
+               {       
+                       VECCOPY(t->tsnap.snapTarget, active_td->center);
+                               
+                       if(t->flag & (T_EDIT|T_POSE)) {
+                               Object *ob= G.obedit?G.obedit:t->poseobj;
+                               Mat4MulVecfl(ob->obmat, t->tsnap.snapTarget);
+                       }
+                       
+                       t->tsnap.status |= TARGET_INIT;
+               }
+               /* No active, default to median */
+               else
+               {
+                       t->tsnap.modeTarget = SNAP_MEDIAN;
+                       t->tsnap.targetSnap = TargetSnapMedian;
+                       TargetSnapMedian(t);
+               }               
+       }
+}
+
 void TargetSnapMedian(TransInfo *t)
 {
        // Only need to calculate once
@@ -628,7 +677,7 @@ void TargetSnapClosest(TransInfo *t)
 }
 /*================================================================*/
 
-int findNearestVertFromObjects(int *dist, float *loc, int selected) {
+int findNearestVertFromObjects(int *dist, float *loc, int mode) {
        Base *base;
        int retval = 0;
        short mval[2];
@@ -637,7 +686,7 @@ int findNearestVertFromObjects(int *dist, float *loc, int selected) {
        
        base= FIRSTBASE;
        for ( base = FIRSTBASE; base != NULL; base = base->next ) {
-               if ( base != BASACT && BASE_SELECTABLE(base) && (base->flag & SELECT) == selected ) {
+               if ( BASE_SELECTABLE(base) && ((mode == NOT_SELECTED && (base->flag & SELECT) == 0) || (mode == NOT_ACTIVE && base != BASACT)) ) {
                        Object *ob = base->object;
                        
                        if (ob->type == OB_MESH) {