diff --git a/source/blender/blenlib/BLI_arithb.h b/source/blender/blenlib/BLI_arithb.h index fdccb3854a6..901caaee15f 100644 --- a/source/blender/blenlib/BLI_arithb.h +++ b/source/blender/blenlib/BLI_arithb.h @@ -218,7 +218,7 @@ void Mat4ToEul(float tmat[][4],float *eul); void EulToQuat(float *eul, float *quat); void Mat3ToCompatibleEul(float mat[][3], float *eul, float *oldrot); - +void EulToGimbalAxis(float gmat[][3], float *eul, short order); void compatible_eul(float *eul, float *oldrot); diff --git a/source/blender/blenlib/intern/arithb.c b/source/blender/blenlib/intern/arithb.c index 6c9ae78bac4..0d3304557c3 100644 --- a/source/blender/blenlib/intern/arithb.c +++ b/source/blender/blenlib/intern/arithb.c @@ -3310,6 +3310,69 @@ void Mat3ToCompatibleEul(float mat[][3], float *eul, float *oldrot) VecCopyf(eul, eul1); } +} + +/* the matrix is written to as 3 axis vectors */ +void EulToGimbalAxis(float gmat[][3], float *eul, short order) +{ + RotOrderInfo *R= GET_ROTATIONORDER_INFO(order); + short R_order[3]; + short R_order2[3]; + + float quat[4]; + float teul[3]; + float tvec[3]; + int i, a; + + R_order2[R->i]= 0; + R_order2[R->j]= 1; + R_order2[R->k]= 2; + + R_order[0]= R->i; + R_order[1]= R->j; + R_order[2]= R->k; + + for(i= 0; i<3; i++) { + tvec[0]= tvec[1]= tvec[2]= 0.0f; + tvec[i] = 1.0f; + + VecCopyf(teul, eul); + + for(a= R_order2[i]; a >= 1; a--) + teul[R_order[a-1]]= 0.0f; + + EulOToQuat(teul, order, quat); + NormalQuat(quat); + QuatMulVecf(quat, tvec); + Normalize(tvec); + + VecCopyf(gmat[i], tvec); + } + + +#if 0 + + for(i= 0; i<3; i++) { + tvec[0]= tvec[1]= tvec[2]= 0.0f; + tvec[i] = 1.0f; + + VecCopyf(teul, eul); + + for(a= R_order2[i]; a >= 1; a--) + teul[R_order[a-1]]= 0.0f; + + EulToQuat(teul, quat); + NormalQuat(quat); + QuatMulVecf(quat, tvec); + Normalize(tvec); + + VecCopyf(gmat[i], tvec); + } +#endif + + + + } /* ************ AXIS ANGLE *************** */ diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c index 1143203217b..f80084f7820 100644 --- a/source/blender/editors/transform/transform_constraints.c +++ b/source/blender/editors/transform/transform_constraints.c @@ -575,6 +575,10 @@ void setUserConstraint(TransInfo *t, short orientation, int mode, const char fte sprintf(text, ftext, "view"); setConstraint(t, t->spacemtx, mode, text); break; + case V3D_MANIP_GIMBAL: + sprintf(text, ftext, "gimbal"); + setConstraint(t, t->spacemtx, mode, text); + break; default: /* V3D_MANIP_CUSTOM */ sprintf(text, ftext, t->spacename); setConstraint(t, t->spacemtx, mode, text); diff --git a/source/blender/editors/transform/transform_manipulator.c b/source/blender/editors/transform/transform_manipulator.c index bdf0a91bf89..2247977ef87 100644 --- a/source/blender/editors/transform/transform_manipulator.c +++ b/source/blender/editors/transform/transform_manipulator.c @@ -175,6 +175,61 @@ static void stats_editbone(View3D *v3d, EditBone *ebo) protectflag_to_drawflags(OB_LOCK_LOC|OB_LOCK_ROT|OB_LOCK_SCALE, &v3d->twdrawflag); } + +static int test_rotmode_euler(short rotmode) +{ + return (ELEM(rotmode, ROT_MODE_AXISANGLE, ROT_MODE_QUAT)) ? 0:1; +} + +void gimbalAxis(Object *ob, float gmat[][3]) +{ + if(ob->mode & OB_MODE_POSE) + { + bPoseChannel *pchan= NULL; + + /* use channels to get stats */ + for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) { + if (pchan->bone && pchan->bone->flag & BONE_ACTIVE) { + if(test_rotmode_euler(pchan->rotmode)) { + break; + } + } + } + + if(pchan) { + int i; + + EulToGimbalAxis(gmat, pchan->eul, pchan->rotmode); + + for (i=0; i<3; i++) + Mat3MulVecfl(pchan->bone->bone_mat, gmat[i]); + + if(pchan->parent) { + bPoseChannel *pchan_par= pchan->parent; + + float tmat[3][3]; + Mat3CpyMat4(tmat, pchan_par->pose_mat); + + for (i=0; i<3; i++) + Mat3MulVecfl(tmat, gmat[i]); + } + + /* needed if object trans isnt identity */ + for (i=0; i<3; i++) { + float tmat[3][3]; + Mat3CpyMat4(tmat, ob->obmat); + Mat3MulVecfl(tmat, gmat[i]); + } + } + } + else { + if(test_rotmode_euler(ob->rotmode)) { + EulToGimbalAxis(gmat, ob->rot, ob->rotmode); + } + } +} + + /* centroid, boundbox, of selection */ /* returns total items selected */ int calc_manipulator_stats(const bContext *C) @@ -416,6 +471,14 @@ int calc_manipulator_stats(const bContext *C) case V3D_MANIP_GLOBAL: break; /* nothing to do */ + case V3D_MANIP_GIMBAL: + { + float mat[3][3]; + Mat3One(mat); + gimbalAxis(ob, mat); + Mat4CpyMat3(rv3d->twmat, mat); + break; + } case V3D_MANIP_NORMAL: if(obedit || ob->mode & OB_MODE_POSE) { float mat[3][3]; @@ -1404,9 +1467,10 @@ void BIF_draw_manipulator(const bContext *C) int totsel; if(!(v3d->twflag & V3D_USE_MANIPULATOR)) return; - if(G.moving && (G.moving & G_TRANSFORM_MANIP)==0) return; +// if(G.moving && (G.moving & G_TRANSFORM_MANIP)==0) return; - if(G.moving==0) { +// if(G.moving==0) { + { v3d->twflag &= ~V3D_DRAW_MANIPULATOR; totsel= calc_manipulator_stats(C); @@ -1454,7 +1518,7 @@ void BIF_draw_manipulator(const bContext *C) else draw_manipulator_rotate_cyl(v3d, rv3d, 0, drawflags, v3d->twtype, MAN_RGB); } else - draw_manipulator_rotate(v3d, rv3d, G.moving, drawflags, v3d->twtype); + draw_manipulator_rotate(v3d, rv3d, 0 /* G.moving*/, drawflags, v3d->twtype); glDisable(GL_BLEND); } diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c index c9344b97fb2..e790b38dd67 100644 --- a/source/blender/editors/transform/transform_orientations.c +++ b/source/blender/editors/transform/transform_orientations.c @@ -434,7 +434,7 @@ EnumPropertyItem *BIF_enumTransformOrientation(bContext *C) } char * BIF_menustringTransformOrientation(const bContext *C, char *title) { - char menu[] = "%t|Global%x0|Local%x1|Normal%x2|View%x3"; + char menu[] = "%t|Global%x0|Local%x1|Gimbal%x4|Normal%x2|View%x3"; ListBase *transform_spaces = &CTX_data_scene(C)->transform_spaces; TransformOrientation *ts; int i = V3D_MANIP_CUSTOM; @@ -510,6 +510,7 @@ static int count_bone_select(bArmature *arm, ListBase *lb, int do_it) return total; } +extern void gimbalAxis(Object *ob, float gimbal_vecs[][3]); void initTransformOrientation(bContext *C, TransInfo *t) { View3D *v3d = CTX_wm_view3d(C); @@ -522,7 +523,12 @@ void initTransformOrientation(bContext *C, TransInfo *t) case V3D_MANIP_GLOBAL: strcpy(t->spacename, "global"); break; - + + case V3D_MANIP_GIMBAL: + Mat3One(t->spacemtx); + if(ob) + gimbalAxis(ob, t->spacemtx); + break; case V3D_MANIP_NORMAL: if(obedit || ob->mode & OB_MODE_POSE) { float mat[3][3]; diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h index 564d6749c16..422c56fe4c1 100644 --- a/source/blender/makesdna/DNA_view3d_types.h +++ b/source/blender/makesdna/DNA_view3d_types.h @@ -263,7 +263,8 @@ typedef struct View3D { #define V3D_MANIP_LOCAL 1 #define V3D_MANIP_NORMAL 2 #define V3D_MANIP_VIEW 3 -#define V3D_MANIP_CUSTOM 4 /* anything of value 4 or higher is custom */ +#define V3D_MANIP_GIMBAL 4 +#define V3D_MANIP_CUSTOM 5 /* anything of value 5 or higher is custom */ /* View3d->twflag */ /* USE = user setting, DRAW = based on selection */ diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index e46ba16e3d9..43172f0a1e8 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -77,6 +77,7 @@ static EnumPropertyItem draw_channels_items[] = { static EnumPropertyItem transform_orientation_items[] = { {V3D_MANIP_GLOBAL, "GLOBAL", 0, "Global", "Align the transformation axes to world space"}, {V3D_MANIP_LOCAL, "LOCAL", 0, "Local", "Align the transformation axes to the selected objects' local space"}, + {V3D_MANIP_GIMBAL, "GIMBAL", 0, "Gimbal", "Align each axis to the euler rotation axis as used for input"}, {V3D_MANIP_NORMAL, "NORMAL", 0, "Normal", "Align the transformation axes to average normal of selected elements (bone Y axis for pose mode)"}, {V3D_MANIP_VIEW, "VIEW", 0, "View", "Align the transformation axes to the window"}, {V3D_MANIP_CUSTOM, "CUSTOM", 0, "Custom", "Use a custom transform orientation"}, @@ -169,6 +170,7 @@ EnumPropertyItem *rna_TransformOrientation_itemf(bContext *C, PointerRNA *ptr, i RNA_enum_items_add_value(&item, &totitem, transform_orientation_items, V3D_MANIP_GLOBAL); RNA_enum_items_add_value(&item, &totitem, transform_orientation_items, V3D_MANIP_NORMAL); + RNA_enum_items_add_value(&item, &totitem, transform_orientation_items, V3D_MANIP_GIMBAL); RNA_enum_items_add_value(&item, &totitem, transform_orientation_items, V3D_MANIP_LOCAL); RNA_enum_items_add_value(&item, &totitem, transform_orientation_items, V3D_MANIP_VIEW);