fix [#34802] Individual Transformation Confusing in Edit Mode
authorCampbell Barton <ideasman42@gmail.com>
Thu, 4 Apr 2013 09:20:46 +0000 (09:20 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Thu, 4 Apr 2013 09:20:46 +0000 (09:20 +0000)
Individual transformation now works in editmode mesh faces/edge, armature bones and metaballs.

source/blender/bmesh/intern/bmesh_marking.c
source/blender/editors/transform/transform.h
source/blender/editors/transform/transform_constraints.c
source/blender/editors/transform/transform_conversions.c
source/blender/editors/transform/transform_orientations.c
source/blender/editors/transform/transform_snap.c

index 73aee5917ae15e91f4677c92dcb131c3cf8ba061..2cc84671e41ea7cd5d95284e979f8abb4776afc1 100644 (file)
@@ -619,7 +619,7 @@ void BM_editselection_center(BMEditSelection *ese, float r_center[3])
        }
        else if (ese->htype == BM_FACE) {
                BMFace *efa = (BMFace *)ese->ele;
-               BM_face_calc_center_bounds(efa, r_center);
+               BM_face_calc_center_mean(efa, r_center);
        }
 }
 
index a551ef5008ef14678d678b4ddac6d872fe828fe7..1f08bfda6a68d70dc0326c3d12346b8dcf9f6814 100644 (file)
@@ -72,7 +72,7 @@ typedef struct TransSnap {
        short   target;
        short   modePoint;
        short   modeSelect;
-       short   align;
+       bool    align;
        char    project;
        char    snap_self;
        short   peel;
@@ -593,7 +593,7 @@ void flushTransGraphData(TransInfo *t);
 void remake_graph_transdata(TransInfo *t, struct ListBase *anim_data);
 void flushTransUVs(TransInfo *t);
 void flushTransParticles(TransInfo *t);
-int clipUVTransform(TransInfo *t, float *vec, int resize);
+bool clipUVTransform(TransInfo *t, float vec[2], const bool resize);
 void clipUVData(TransInfo *t);
 void flushTransNodes(TransInfo *t);
 void flushTransSeq(TransInfo *t);
@@ -628,8 +628,8 @@ void setUserConstraint(TransInfo *t, short orientation, int mode, const char tex
 
 void constraintNumInput(TransInfo *t, float vec[3]);
 
-int isLockConstraint(TransInfo *t);
-int getConstraintSpaceDimension(TransInfo *t);
+bool isLockConstraint(TransInfo *t);
+int  getConstraintSpaceDimension(TransInfo *t);
 char constraintModeToChar(TransInfo *t);
 
 void startConstraint(TransInfo *t);
@@ -652,21 +652,21 @@ typedef enum {
 void snapGrid(TransInfo *t, float *val);
 void snapGridAction(TransInfo *t, float *val, GearsType action);
 
-int activeSnap(TransInfo *t);
-int validSnap(TransInfo *t);
+bool activeSnap(TransInfo *t);
+bool validSnap(TransInfo *t);
 
 void initSnapping(struct TransInfo *t, struct wmOperator *op);
 void applyProject(TransInfo *t);
 void applySnapping(TransInfo *t, float *vec);
 void resetSnapping(TransInfo *t);
-int  handleSnapping(TransInfo *t, const struct wmEvent *event);
+bool handleSnapping(TransInfo *t, const struct wmEvent *event);
 void drawSnapping(const struct bContext *C, TransInfo *t);
-int usingSnappingNormal(TransInfo *t);
-int validSnappingNormal(TransInfo *t);
+bool usingSnappingNormal(TransInfo *t);
+bool validSnappingNormal(TransInfo *t);
 
 void getSnapPoint(TransInfo *t, float vec[3]);
 void addSnapPoint(TransInfo *t);
-int updateSelectedSnapPoint(TransInfo *t);
+bool updateSelectedSnapPoint(TransInfo *t);
 void removeSnapPoint(TransInfo *t);
 
 /********************** Mouse Input ******************************/
@@ -729,8 +729,8 @@ struct TransformOrientation *createMeshSpace(struct bContext *C, struct ReportLi
 struct TransformOrientation *createBoneSpace(struct bContext *C, struct ReportList *reports, char *name, int overwrite);
 
 /* Those two fill in mat and return non-zero on success */
-int createSpaceNormal(float mat[3][3], float normal[3]);
-int createSpaceNormalTangent(float mat[3][3], float normal[3], float tangent[3]);
+bool createSpaceNormal(float mat[3][3], const float normal[3]);
+bool createSpaceNormalTangent(float mat[3][3], float normal[3], float tangent[3]);
 
 struct TransformOrientation *addMatrixSpace(struct bContext *C, float mat[3][3], char name[], int overwrite);
 void applyTransformOrientation(const struct bContext *C, float mat[3][3], char *name);
index f3026205ea235ec426156fe3154baf6adb0be0c4..7678051fd386815f978007b306d6b32ebafaf819 100644 (file)
@@ -557,13 +557,17 @@ void setConstraint(TransInfo *t, float space[3][3], int mode, const char text[])
 
 void setLocalConstraint(TransInfo *t, int mode, const char text[])
 {
+       /* edit-mode now allows local transforms too */
+#if 0
        if (t->flag & T_EDIT) {
                float obmat[3][3];
                copy_m3_m4(obmat, t->scene->obedit->obmat);
                normalize_m3(obmat);
                setConstraint(t, obmat, mode, text);
        }
-       else {
+       else
+#endif
+       {
                if (t->total == 1) {
                        setConstraint(t, t->data->axismtx, mode, text);
                }
@@ -743,37 +747,42 @@ void drawPropCircle(const struct bContext *C, TransInfo *t)
 
 static void drawObjectConstraint(TransInfo *t)
 {
-       int i;
-       TransData *td = t->data;
-
        /* Draw the first one lighter because that's the one who controls the others.
         * Meaning the transformation is projected on that one and just copied on the others
         * constraint space.
         * In a nutshell, the object with light axis is controlled by the user and the others follow.
         * Without drawing the first light, users have little clue what they are doing.
         */
-       if (t->con.mode & CON_AXIS0) {
-               drawLine(t, td->ob->obmat[3], td->axismtx[0], 'X', DRAWLIGHT);
-       }
-       if (t->con.mode & CON_AXIS1) {
-               drawLine(t, td->ob->obmat[3], td->axismtx[1], 'Y', DRAWLIGHT);
-       }
-       if (t->con.mode & CON_AXIS2) {
-               drawLine(t, td->ob->obmat[3], td->axismtx[2], 'Z', DRAWLIGHT);
-       }
+       short options = DRAWLIGHT;
+       TransData *td = t->data;
+       int i;
 
-       td++;
+       for (i = 0; i < t->total; i++, td++) {
+               float co[3];
+
+               if (t->flag & T_OBJECT) {
+                       copy_v3_v3(co, td->ob->obmat[3]);
+               }
+               else if (t->flag & T_EDIT) {
+                       mul_v3_m4v3(co, t->obedit->obmat, td->center);
+               }
+               else if (t->flag & T_POSE) {
+                       mul_v3_m4v3(co, t->poseobj->obmat, td->center);
+               }
+               else {
+                       copy_v3_v3(co, td->center);
+               }
 
-       for (i = 1; i < t->total; i++, td++) {
                if (t->con.mode & CON_AXIS0) {
-                       drawLine(t, td->ob->obmat[3], td->axismtx[0], 'X', 0);
+                       drawLine(t, td->center, td->axismtx[0], 'X', options);
                }
                if (t->con.mode & CON_AXIS1) {
-                       drawLine(t, td->ob->obmat[3], td->axismtx[1], 'Y', 0);
+                       drawLine(t, td->center, td->axismtx[1], 'Y', options);
                }
                if (t->con.mode & CON_AXIS2) {
-                       drawLine(t, td->ob->obmat[3], td->axismtx[2], 'Z', 0);
+                       drawLine(t, td->center, td->axismtx[2], 'Z', options);
                }
+               options &= ~DRAWLIGHT;
        }
 }
 
@@ -992,20 +1001,20 @@ char constraintModeToChar(TransInfo *t)
 }
 
 
-int isLockConstraint(TransInfo *t)
+bool isLockConstraint(TransInfo *t)
 {
        int mode = t->con.mode;
 
        if ((mode & (CON_AXIS0 | CON_AXIS1)) == (CON_AXIS0 | CON_AXIS1))
-               return 1;
+               return true;
 
        if ((mode & (CON_AXIS1 | CON_AXIS2)) == (CON_AXIS1 | CON_AXIS2))
-               return 1;
+               return true;
 
        if ((mode & (CON_AXIS0 | CON_AXIS2)) == (CON_AXIS0 | CON_AXIS2))
-               return 1;
+               return true;
 
-       return 0;
+       return false;
 }
 
 /*
index f84c967711c8152bcfd38f5fdf91ac74b3bc5226..661d7055036b4e8f56cf745990466451fe8336f5 100644 (file)
 
 
 /* local function prototype - for Object/Bone Constraints */
-static short constraints_list_needinv(TransInfo *t, ListBase *list);
+static bool constraints_list_needinv(TransInfo *t, ListBase *list);
 
 /* ************************** Functions *************************** */
 
@@ -1236,6 +1236,8 @@ static void createTransMBallVerts(TransInfo *t)
                        copy_v3_v3(td->iloc, td->loc);
                        copy_v3_v3(td->center, td->loc);
 
+                       quat_to_mat3(td->axismtx, ml->quat);
+
                        if (ml->flag & SELECT) td->flag = TD_SELECTED | TD_USEQUAT | TD_SINGLESIZE;
                        else td->flag = TD_USEQUAT;
 
@@ -1858,32 +1860,29 @@ static void editmesh_set_connectivity_distance(BMEditMesh *em, float mtx[3][3],
        MEM_freeN(tots);
 }
 
-/* loop-in-a-loop I know, but we need it! (ton) */
-static void get_face_center(float r_cent[3], BMVert *eve)
-
+static BMElem *bm_vert_single_select_face(BMVert *eve)
 {
-       BMFace *efa;
+       BMElem *ele;
        BMIter iter;
 
-       BM_ITER_ELEM (efa, &iter, eve, BM_FACES_OF_VERT) {
-               if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
-                       BM_face_calc_center_mean(efa, r_cent);
-                       break;
+       BM_ITER_ELEM (ele, &iter, eve, BM_FACES_OF_VERT) {
+               if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) {
+                       return ele;
                }
        }
+       return NULL;
 }
-
-static void get_edge_center(float r_cent[3], BMVert *eve)
+static BMElem *bm_vert_single_select_edge(BMVert *eve)
 {
-       BMEdge *eed;
+       BMElem *ele;
        BMIter iter;
 
-       BM_ITER_ELEM (eed, &iter, eve, BM_EDGES_OF_VERT) {
-               if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
-                       mid_v3_v3v3(r_cent, eed->v1->co, eed->v2->co);
-                       break;
+       BM_ITER_ELEM (ele, &iter, eve, BM_EDGES_OF_VERT) {
+               if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) {
+                       return ele;
                }
        }
+       return NULL;
 }
 
 /* way to overwrite what data is edited with transform */
@@ -1895,25 +1894,51 @@ static void VertsToTransData(TransInfo *t, TransData *td, TransDataExtension *tx
        //      td->loc = key->co;
        //else
        td->loc = eve->co;
-
+       copy_v3_v3(td->iloc, td->loc);
        copy_v3_v3(td->center, td->loc);
 
        if (t->around == V3D_LOCAL) {
-               if (em->selectmode & SCE_SELECT_FACE)
-                       get_face_center(td->center, eve);
-               else if (em->selectmode & SCE_SELECT_EDGE)
-                       get_edge_center(td->center, eve);
+               BMElem *ele;
+               bool is_axismat_set = false;
+
+               if (em->selectmode & (SCE_SELECT_FACE | SCE_SELECT_EDGE) &&
+                   (ele = ((em->selectmode & SCE_SELECT_FACE) ?
+                           bm_vert_single_select_face(eve) :
+                           bm_vert_single_select_edge(eve))))
+               {
+                       float normal[3], tangent[3];
+
+                       BMEditSelection ese;
+                       ese.next = ese.prev = NULL;
+                       ese.ele = ele;
+                       ese.htype = ele->head.htype;
+
+                       BM_editselection_center(&ese, td->center);
+                       BM_editselection_normal(&ese, normal);
+                       BM_editselection_plane(&ese, tangent);
+
+                       if (createSpaceNormalTangent(td->axismtx, normal, tangent)) {
+                               is_axismat_set = true;
+                       }
+               }
+
+               /* for verts or fallback when createSpaceNormalTangent fails */
+               if (is_axismat_set == false) {
+                       axis_dominant_v3_to_m3(td->axismtx, eve->no);
+                       invert_m3(td->axismtx);
+               }
+       }
+       else {
+               /* Setting normals */
+               copy_v3_v3(td->axismtx[2], eve->no);
+               td->axismtx[0][0]        =
+                   td->axismtx[0][1]    =
+                   td->axismtx[0][2]    =
+                   td->axismtx[1][0]    =
+                   td->axismtx[1][1]    =
+                   td->axismtx[1][2]    = 0.0f;
        }
-       copy_v3_v3(td->iloc, td->loc);
 
-       // Setting normals
-       copy_v3_v3(td->axismtx[2], eve->no);
-       td->axismtx[0][0]        =
-           td->axismtx[0][1]    =
-           td->axismtx[0][2]    =
-           td->axismtx[1][0]    =
-           td->axismtx[1][1]    =
-           td->axismtx[1][2]    = 0.0f;
 
        td->ext = NULL;
        td->val = NULL;
@@ -2503,7 +2528,7 @@ void flushTransUVs(TransInfo *t)
        }
 }
 
-int clipUVTransform(TransInfo *t, float *vec, int resize)
+bool clipUVTransform(TransInfo *t, float vec[2], const bool resize)
 {
        TransData *td;
        int a, clipx = 1, clipy = 1;
@@ -2574,16 +2599,16 @@ void clipUVData(TransInfo *t)
 /* ********************* ANIMATION EDITORS (GENERAL) ************************* */
 
 /* This function tests if a point is on the "mouse" side of the cursor/frame-marking */
-static short FrameOnMouseSide(char side, float frame, float cframe)
+static bool FrameOnMouseSide(char side, float frame, float cframe)
 {
        /* both sides, so it doesn't matter */
-       if (side == 'B') return 1;
+       if (side == 'B') return true;
 
        /* only on the named side */
        if (side == 'R')
-               return (frame >= cframe) ? 1 : 0;
+               return (frame >= cframe);
        else
-               return (frame <= cframe) ? 1 : 0;
+               return (frame <= cframe);
 }
 
 /* ********************* NLA EDITOR ************************* */
@@ -4523,7 +4548,7 @@ static void createTransSeqData(bContext *C, TransInfo *t)
  * These particular constraints benefit from this, but others don't, hence
  * this semi-hack ;-)    - Aligorith
  */
-static short constraints_list_needinv(TransInfo *t, ListBase *list)
+static bool constraints_list_needinv(TransInfo *t, ListBase *list)
 {
        bConstraint *con;
 
@@ -4536,26 +4561,30 @@ static short constraints_list_needinv(TransInfo *t, ListBase *list)
                        if ((con->flag & CONSTRAINT_DISABLE) == 0 && (con->enforce != 0.0f)) {
                                /* (affirmative) returns for specific constraints here... */
                                /* constraints that require this regardless  */
-                               if (con->type == CONSTRAINT_TYPE_CHILDOF) return 1;
-                               if (con->type == CONSTRAINT_TYPE_FOLLOWPATH) return 1;
-                               if (con->type == CONSTRAINT_TYPE_CLAMPTO) return 1;
-                               if (con->type == CONSTRAINT_TYPE_OBJECTSOLVER) return 1;
-                               if (con->type == CONSTRAINT_TYPE_FOLLOWTRACK) return 1;
-                               
+                               if (ELEM5(con->type,
+                                         CONSTRAINT_TYPE_CHILDOF,
+                                         CONSTRAINT_TYPE_FOLLOWPATH,
+                                         CONSTRAINT_TYPE_CLAMPTO,
+                                         CONSTRAINT_TYPE_OBJECTSOLVER,
+                                         CONSTRAINT_TYPE_FOLLOWTRACK))
+                               {
+                                       return true;
+                               }
+
                                /* constraints that require this only under special conditions */
                                if (con->type == CONSTRAINT_TYPE_ROTLIKE) {
                                        /* CopyRot constraint only does this when rotating, and offset is on */
                                        bRotateLikeConstraint *data = (bRotateLikeConstraint *)con->data;
                                        
                                        if ((data->flag & ROTLIKE_OFFSET) && (t->mode == TFM_ROTATION))
-                                               return 1;
+                                               return true;
                                }
                        }
                }
        }
 
        /* no appropriate candidates found */
-       return 0;
+       return false;
 }
 
 /* transcribe given object into TransData for Transforming */
@@ -4563,8 +4592,8 @@ static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob)
 {
        Scene *scene = t->scene;
        float obmtx[3][3];
-       short constinv;
-       short skip_invert = 0;
+       bool constinv;
+       bool skip_invert = false;
 
        if (t->mode != TFM_DUMMY && ob->rigidbody_object) {
                float rot[3][3], scale[3];
@@ -4602,15 +4631,15 @@ static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob)
 
        /* disable constraints inversion for dummy pass */
        if (t->mode == TFM_DUMMY)
-               skip_invert = 1;
+               skip_invert = true;
 
-       if (skip_invert == 0 && constinv == 0) {
-               if (constinv == 0)
+       if (skip_invert == false && constinv == false) {
+               if (constinv == false)
                        ob->transflag |= OB_NO_CONSTRAINTS;  /* BKE_object_where_is_calc_time checks this */
                
                BKE_object_where_is_calc(t->scene, ob);
                
-               if (constinv == 0)
+               if (constinv == false)
                        ob->transflag &= ~OB_NO_CONSTRAINTS;
        }
        else
@@ -4762,19 +4791,19 @@ static void set_trans_object_base_flags(TransInfo *t)
        }
 }
 
-static int mark_children(Object *ob)
+static bool mark_children(Object *ob)
 {
        if (ob->flag & (SELECT | BA_TRANSFORM_CHILD))
-               return 1;
+               return true;
 
        if (ob->parent) {
                if (mark_children(ob->parent)) {
                        ob->flag |= BA_TRANSFORM_CHILD;
-                       return 1;
+                       return true;
                }
        }
        
-       return 0;
+       return false;
 }
 
 static int count_proportional_objects(TransInfo *t)
index 0c1f169935aef46f0c581e4459795804851499ad..023083a98ffc828ab17763bfb641e8098b3b742a 100644 (file)
@@ -213,13 +213,13 @@ TransformOrientation *createMeshSpace(bContext *C, ReportList *reports, char *na
        return addMatrixSpace(C, mat, name, overwrite);
 }
 
-int createSpaceNormal(float mat[3][3], float normal[3])
+bool createSpaceNormal(float mat[3][3], const float normal[3])
 {
        float tangent[3] = {0.0f, 0.0f, 1.0f};
        
        copy_v3_v3(mat[2], normal);
        if (normalize_v3(mat[2]) == 0.0f) {
-               return 0; /* error return */
+               return false;  /* error return */
        }
 
        cross_v3_v3v3(mat[0], mat[2], tangent);
@@ -233,14 +233,14 @@ int createSpaceNormal(float mat[3][3], float normal[3])
 
        normalize_m3(mat);
        
-       return 1;
+       return true;
 }
 
-int createSpaceNormalTangent(float mat[3][3], float normal[3], float tangent[3])
+bool createSpaceNormalTangent(float mat[3][3], float normal[3], float tangent[3])
 {
        copy_v3_v3(mat[2], normal);
        if (normalize_v3(mat[2]) == 0.0f) {
-               return 0; /* error return */
+               return false;  /* error return */
        }
        
        /* preempt zero length tangent from causing trouble */
@@ -250,14 +250,14 @@ int createSpaceNormalTangent(float mat[3][3], float normal[3], float tangent[3])
 
        cross_v3_v3v3(mat[0], mat[2], tangent);
        if (normalize_v3(mat[0]) == 0.0f) {
-               return 0; /* error return */
+               return false;  /* error return */
        }
        
        cross_v3_v3v3(mat[1], mat[2], mat[0]);
 
        normalize_m3(mat);
        
-       return 1;
+       return true;
 }
 
 TransformOrientation *addMatrixSpace(bContext *C, float mat[3][3], char name[], int overwrite)
index e04ea3f84c3337e25156874faa3785989e52b384..c6ab33124ef1d5b109a1900d24bea7800ccdce55 100644 (file)
@@ -124,13 +124,13 @@ int BIF_snappingSupported(Object *obedit)
 }
 #endif
 
-int validSnap(TransInfo *t)
+bool validSnap(TransInfo *t)
 {
        return (t->tsnap.status & (POINT_INIT | TARGET_INIT)) == (POINT_INIT | TARGET_INIT) ||
               (t->tsnap.status & (MULTI_POINTS | TARGET_INIT)) == (MULTI_POINTS | TARGET_INIT);
 }
 
-int activeSnap(TransInfo *t)
+bool activeSnap(TransInfo *t)
 {
        return (t->modifiers & (MOD_SNAP | MOD_SNAP_INVERT)) == MOD_SNAP || (t->modifiers & (MOD_SNAP | MOD_SNAP_INVERT)) == MOD_SNAP_INVERT;
 }
@@ -264,9 +264,9 @@ void drawSnapping(const struct bContext *C, TransInfo *t)
        }
 }
 
-int  handleSnapping(TransInfo *t, const wmEvent *event)
+bool handleSnapping(TransInfo *t, const wmEvent *event)
 {
-       int status = 0;
+       bool status = false;
 
 #if 0 // XXX need a proper selector for all snap mode
        if (BIF_snappingSupported(t->obedit) && event->type == TABKEY && event->shift) {
@@ -372,7 +372,7 @@ void applySnapping(TransInfo *t, float *vec)
 void resetSnapping(TransInfo *t)
 {
        t->tsnap.status = 0;
-       t->tsnap.align = 0;
+       t->tsnap.align = false;
        t->tsnap.project = 0;
        t->tsnap.mode = 0;
        t->tsnap.modeSelect = 0;
@@ -387,20 +387,20 @@ void resetSnapping(TransInfo *t)
        t->tsnap.snapNodeBorder = 0;
 }
 
-int usingSnappingNormal(TransInfo *t)
+bool usingSnappingNormal(TransInfo *t)
 {
        return t->tsnap.align;
 }
 
-int validSnappingNormal(TransInfo *t)
+bool validSnappingNormal(TransInfo *t)
 {
        if (validSnap(t)) {
                if (dot_v3v3(t->tsnap.snapNormal, t->tsnap.snapNormal) > 0) {
-                       return 1;
+                       return true;
                }
        }
        
-       return 0;
+       return false;
 }
 
 static void initSnappingMode(TransInfo *t)
@@ -603,9 +603,9 @@ void addSnapPoint(TransInfo *t)
        }
 }
 
-int updateSelectedSnapPoint(TransInfo *t)
+bool updateSelectedSnapPoint(TransInfo *t)
 {
-       int status = 0;
+       bool status = false;
        if (t->tsnap.status & MULTI_POINTS) {
                TransSnapPoint *p, *closest_p = NULL;
                float closest_dist = TRANSFORM_SNAP_MAX_PX;
@@ -628,7 +628,7 @@ int updateSelectedSnapPoint(TransInfo *t)
                }
 
                if (closest_p) {
-                       status = t->tsnap.selectedPoint == closest_p ? 0 : 1;
+                       status = (t->tsnap.selectedPoint != closest_p);
                        t->tsnap.selectedPoint = closest_p;
                }
        }