Rotation Modes Bugfix:

Animating rotations using different rotation modes should now work more often than before. 

Previously, quaternion and axis-angle values were stored in the same variable in DNA, but that was causing problems with other animation curves overwriting the values and causing the rotations to not work as expected. 

There are still some issues, but I'll track those down later tonight
This commit is contained in:
Joshua Leung 2009-10-08 00:57:00 +00:00
parent fd511eb984
commit 475ab5ceb4
14 changed files with 172 additions and 77 deletions

@ -104,7 +104,7 @@ void armature_loc_pose_to_bone(struct bPoseChannel *pchan, float *inloc, float *
void armature_mat_pose_to_delta(float delta_mat[][4], float pose_mat[][4], float arm_mat[][4]);
/* Rotation Mode Conversions - Used for PoseChannels + Objects... */
void BKE_rotMode_change_values(float quat[4], float eul[3], short oldMode, short newMode);
void BKE_rotMode_change_values(float quat[4], float eul[3], float axis[3], float *angle, short oldMode, short newMode);
/* B-Bone support */
typedef struct Mat4 {

@ -446,7 +446,7 @@ bPoseChannel *verify_pose_channel(bPose* pose, const char* name)
strncpy(chan->name, name, 31);
/* init vars to prevent math errors */
chan->quat[0] = 1.0f;
chan->quat[0] = chan->rotAxis[1]= 1.0f;
chan->size[0] = chan->size[1] = chan->size[2] = 1.0f;
chan->limitmin[0]= chan->limitmin[1]= chan->limitmin[2]= -180.0f;
@ -607,6 +607,8 @@ static void copy_pose_channel_data(bPoseChannel *pchan, const bPoseChannel *chan
VECCOPY(pchan->loc, chan->loc);
VECCOPY(pchan->size, chan->size);
VECCOPY(pchan->eul, chan->eul);
VECCOPY(pchan->rotAxis, chan->rotAxis);
pchan->rotAngle= chan->rotAngle;
QUATCOPY(pchan->quat, chan->quat);
pchan->rotmode= chan->rotmode;
Mat4CpyMat4(pchan->chan_mat, (float(*)[4])chan->chan_mat);
@ -975,14 +977,16 @@ void rest_pose(bPose *pose)
memset(pose->stride_offset, 0, sizeof(pose->stride_offset));
memset(pose->cyclic_offset, 0, sizeof(pose->cyclic_offset));
for (pchan=pose->chanbase.first; pchan; pchan= pchan->next){
for (pchan=pose->chanbase.first; pchan; pchan= pchan->next) {
for (i=0; i<3; i++) {
pchan->loc[i]= 0.0f;
pchan->quat[i+1]= 0.0f;
pchan->eul[i]= 0.0f;
pchan->size[i]= 1.0f;
pchan->rotAxis[i]= 0.0f;
}
pchan->quat[0]= 1.0f;
pchan->quat[0]= pchan->rotAxis[1]= 1.0f;
pchan->rotAngle= 0.0f;
pchan->flag &= ~(POSE_LOC|POSE_ROT|POSE_SIZE);
}

@ -1285,16 +1285,14 @@ void armature_mat_pose_to_delta(float delta_mat[][4], float pose_mat[][4], float
/* Called from RNA when rotation mode changes
* - the result should be that the rotations given in the provided pointers have had conversions
* applied (as appropriate), such that the rotation of the element hasn't 'visually' changed
*
* - as in SDNA data, quat is used to store quaternions AND axis-angle rotations...
*/
void BKE_rotMode_change_values (float quat[4], float eul[3], short oldMode, short newMode)
void BKE_rotMode_change_values (float quat[4], float eul[3], float *axis, float angle[3], short oldMode, short newMode)
{
/* check if any change - if so, need to convert data */
if (newMode > 0) { /* to euler */
if (oldMode == ROT_MODE_AXISANGLE) {
/* axis-angle to euler */
AxisAngleToEulO(&quat[1], quat[0], eul, newMode);
AxisAngleToEulO(axis, *angle, eul, newMode);
}
else if (oldMode == ROT_MODE_QUAT) {
/* quat to euler */
@ -1305,11 +1303,7 @@ void BKE_rotMode_change_values (float quat[4], float eul[3], short oldMode, shor
else if (newMode == ROT_MODE_QUAT) { /* to quat */
if (oldMode == ROT_MODE_AXISANGLE) {
/* axis angle to quat */
float q[4];
/* copy to temp var first, since quats and axis-angle are stored in same place */
QuatCopy(q, quat);
AxisAngleToQuat(q, &quat[1], quat[0]);
AxisAngleToQuat(quat, axis, *angle);
}
else if (oldMode > 0) {
/* euler to quat */
@ -1317,24 +1311,20 @@ void BKE_rotMode_change_values (float quat[4], float eul[3], short oldMode, shor
}
/* else { no conversion needed } */
}
else { /* to axis-angle */
else if (newMode == ROT_MODE_AXISANGLE) { /* to axis-angle */
if (oldMode > 0) {
/* euler to axis angle */
EulOToAxisAngle(eul, oldMode, &quat[1], &quat[0]);
}
else if (oldMode == ROT_MODE_QUAT) {
/* quat to axis angle */
float q[4];
/* copy to temp var first, since quats and axis-angle are stored in same place */
QuatCopy(q, quat);
QuatToAxisAngle(q, &quat[1], &quat[0]);
QuatToAxisAngle(quat, axis, angle);
}
/* when converting to axis-angle, we need a special exception for the case when there is no axis */
if (IS_EQ(quat[1], quat[2]) && IS_EQ(quat[2], quat[3])) {
if (IS_EQ(axis[0], axis[1]) && IS_EQ(axis[1], axis[2])) {
/* for now, rotate around y-axis then (so that it simply becomes the roll) */
quat[2]= 1.0f;
axis[1]= 1.0f;
}
}
}
@ -1651,8 +1641,8 @@ void chan_calc_mat(bPoseChannel *chan)
EulOToMat3(chan->eul, chan->rotmode, rmat);
}
else if (chan->rotmode == ROT_MODE_AXISANGLE) {
/* axis-angle - stored in quaternion data, but not really that great for 3D-changing orientations */
AxisAngleToMat3(&chan->quat[1], chan->quat[0], rmat);
/* axis-angle - not really that great for 3D-changing orientations */
AxisAngleToMat3(chan->rotAxis, chan->rotAngle, rmat);
}
else {
/* quats are normalised before use to eliminate scaling issues */

@ -1041,6 +1041,8 @@ Object *add_object(struct Scene *scene, int type)
* but rotations default to quaternions
*/
ob->rotmode= ROT_MODE_EUL;
/* axis-angle must not have a 0,0,0 axis, so set y-axis as default... */
ob->rotAxis[1]= ob->drotAxis[1]= 1.0f;
base= scene_add_base(scene, ob);
scene_select_base(scene, base);
@ -1602,9 +1604,9 @@ void object_rot_to_mat3(Object *ob, float mat[][3])
EulOToMat3(ob->drot, ob->rotmode, dmat);
}
else if (ob->rotmode == ROT_MODE_AXISANGLE) {
/* axis-angle - stored in quaternion data, but not really that great for 3D-changing orientations */
AxisAngleToMat3(&ob->quat[1], ob->quat[0], rmat);
AxisAngleToMat3(&ob->dquat[1], ob->dquat[0], dmat);
/* axis-angle - not really that great for 3D-changing orientations */
AxisAngleToMat3(ob->rotAxis, ob->rotAngle, rmat);
AxisAngleToMat3(ob->drotAxis, ob->drotAngle, dmat);
}
else {
/* quats are normalised before use to eliminate scaling issues */

@ -581,6 +581,7 @@ short paste_animedit_keys (bAnimContext *ac, ListBase *anim_data)
for (aci= animcopybuf.first; aci; aci= aci->next) {
/* check that paths exist */
if (aci->rna_path && fcu->rna_path) {
// FIXME: this breaks for bone names!
if (strcmp(aci->rna_path, fcu->rna_path) == 0) {
/* should be a match unless there's more than one of these */
if ((no_name) || (aci->array_index == fcu->array_index))

@ -4875,14 +4875,39 @@ static int pose_clear_rot_exec(bContext *C, wmOperator *op)
/* check if convert to eulers for locking... */
if (pchan->protectflag & OB_LOCK_ROT4D) {
/* perform clamping on a component by component basis */
if ((pchan->protectflag & OB_LOCK_ROTW) == 0)
pchan->quat[0]= (pchan->rotmode == ROT_MODE_AXISANGLE) ? 0.0f : 1.0f;
if ((pchan->protectflag & OB_LOCK_ROTX) == 0)
pchan->quat[1]= 0.0f;
if ((pchan->protectflag & OB_LOCK_ROTY) == 0)
pchan->quat[2]= 0.0f;
if ((pchan->protectflag & OB_LOCK_ROTZ) == 0)
pchan->quat[3]= 0.0f;
if (pchan->rotmode == ROT_MODE_AXISANGLE) {
if ((pchan->protectflag & OB_LOCK_ROTW) == 0)
pchan->rotAngle= 0.0f;
if ((pchan->protectflag & OB_LOCK_ROTX) == 0)
pchan->rotAxis[0]= 0.0f;
if ((pchan->protectflag & OB_LOCK_ROTY) == 0)
pchan->rotAxis[1]= 0.0f;
if ((pchan->protectflag & OB_LOCK_ROTZ) == 0)
pchan->rotAxis[2]= 0.0f;
/* check validity of axis - axis should never be 0,0,0 (if so, then we make it rotate about y) */
if (IS_EQ(pchan->rotAxis[0], pchan->rotAxis[1]) && IS_EQ(pchan->rotAxis[1], pchan->rotAxis[2]))
pchan->rotAxis[1] = 1.0f;
}
else if (pchan->rotmode == ROT_MODE_QUAT) {
if ((pchan->protectflag & OB_LOCK_ROTW) == 0)
pchan->quat[0]= 1.0f;
if ((pchan->protectflag & OB_LOCK_ROTX) == 0)
pchan->quat[1]= 0.0f;
if ((pchan->protectflag & OB_LOCK_ROTY) == 0)
pchan->quat[2]= 0.0f;
if ((pchan->protectflag & OB_LOCK_ROTZ) == 0)
pchan->quat[3]= 0.0f;
}
else {
/* the flag may have been set for the other modes, so just ignore the extra flag... */
if ((pchan->protectflag & OB_LOCK_ROTX) == 0)
pchan->eul[0]= 0.0f;
if ((pchan->protectflag & OB_LOCK_ROTY) == 0)
pchan->eul[1]= 0.0f;
if ((pchan->protectflag & OB_LOCK_ROTZ) == 0)
pchan->eul[2]= 0.0f;
}
}
else {
/* perform clamping using euler form (3-components) */
@ -4893,7 +4918,7 @@ static int pose_clear_rot_exec(bContext *C, wmOperator *op)
QuatToEul(pchan->quat, oldeul);
}
else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
AxisAngleToEulO(&pchan->quat[1], pchan->quat[0], oldeul, EULER_ORDER_DEFAULT);
AxisAngleToEulO(pchan->rotAxis, pchan->rotAngle, oldeul, EULER_ORDER_DEFAULT);
}
else {
VECCOPY(oldeul, pchan->eul);
@ -4916,7 +4941,7 @@ static int pose_clear_rot_exec(bContext *C, wmOperator *op)
}
}
else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
AxisAngleToEulO(&pchan->quat[1], pchan->quat[0], oldeul, EULER_ORDER_DEFAULT);
EulOToAxisAngle(eul, EULER_ORDER_DEFAULT, pchan->rotAxis, &pchan->rotAngle);
}
else {
VECCOPY(pchan->eul, eul);
@ -4930,8 +4955,8 @@ static int pose_clear_rot_exec(bContext *C, wmOperator *op)
}
else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
/* by default, make rotation of 0 radians around y-axis (roll) */
pchan->quat[0]=pchan->quat[1]=pchan->quat[3]= 0.0f;
pchan->quat[2]= 1.0f;
pchan->rotAxis[0]=pchan->rotAxis[2]=pchan->rotAngle= 0.0f;
pchan->rotAxis[1]= 1.0f;
}
else {
pchan->eul[0]= pchan->eul[1]= pchan->eul[2]= 0.0f;

@ -819,7 +819,7 @@ void pose_copy_menu(Scene *scene)
/* need to convert to quat first (in temp var)... */
Mat4ToQuat(delta_mat, tmp_quat);
QuatToAxisAngle(tmp_quat, &pchan->quat[1], &pchan->quat[0]);
QuatToAxisAngle(tmp_quat, pchan->rotAxis, &pchan->rotAngle);
}
else if (pchan->rotmode == ROT_MODE_QUAT)
Mat4ToQuat(delta_mat, pchan->quat);
@ -1024,23 +1024,23 @@ static int pose_paste_exec (bContext *C, wmOperator *op)
else if (pchan->rotmode > 0) {
/* quat/axis-angle to euler */
if (chan->rotmode == ROT_MODE_AXISANGLE)
AxisAngleToEulO(&chan->quat[1], chan->quat[0], pchan->eul, pchan->rotmode);
AxisAngleToEulO(chan->rotAxis, chan->rotAngle, pchan->eul, pchan->rotmode);
else
QuatToEulO(chan->quat, pchan->eul, pchan->rotmode);
}
else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
/* quat/euler to axis angle */
if (chan->rotmode > 0)
EulOToAxisAngle(chan->eul, chan->rotmode, &pchan->quat[1], &pchan->quat[0]);
EulOToAxisAngle(chan->eul, chan->rotmode, pchan->rotAxis, &pchan->rotAngle);
else
QuatToAxisAngle(chan->quat, &pchan->quat[1], &pchan->quat[0]);
QuatToAxisAngle(chan->quat, pchan->rotAxis, &pchan->rotAngle);
}
else {
/* euler/axis-angle to quat */
if (chan->rotmode > 0)
EulOToQuat(chan->eul, chan->rotmode, pchan->quat);
else
AxisAngleToQuat(pchan->quat, &chan->quat[1], chan->quat[0]);
AxisAngleToQuat(pchan->quat, chan->rotAxis, pchan->rotAngle);
}
/* paste flipped pose? */
@ -1055,10 +1055,10 @@ static int pose_paste_exec (bContext *C, wmOperator *op)
else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
float eul[3];
AxisAngleToEulO(&pchan->quat[1], pchan->quat[0], eul, EULER_ORDER_DEFAULT);
AxisAngleToEulO(pchan->rotAxis, pchan->rotAngle, eul, EULER_ORDER_DEFAULT);
eul[1]*= -1;
eul[2]*= -1;
EulOToAxisAngle(eul, EULER_ORDER_DEFAULT, &pchan->quat[1], &pchan->quat[0]);
EulOToAxisAngle(eul, EULER_ORDER_DEFAULT, pchan->rotAxis, &pchan->rotAngle);
// experimental method (uncomment to test):
#if 0

@ -117,17 +117,41 @@ static int object_rotation_clear_exec(bContext *C, wmOperator *op)
CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) {
if(!(ob->mode & OB_MODE_WEIGHT_PAINT)) {
if (ob->protectflag & (OB_LOCK_ROTX|OB_LOCK_ROTY|OB_LOCK_ROTZ|OB_LOCK_ROTW)) {
/* check if convert to eulers for locking... */
if (ob->protectflag & OB_LOCK_ROT4D) {
/* perform clamping on a component by component basis */
if ((ob->protectflag & OB_LOCK_ROTW) == 0)
ob->quat[0]= (ob->rotmode == ROT_MODE_AXISANGLE) ? 0.0f : 1.0f;
if ((ob->protectflag & OB_LOCK_ROTX) == 0)
ob->quat[1]= 0.0f;
if ((ob->protectflag & OB_LOCK_ROTY) == 0)
ob->quat[2]= 0.0f;
if ((ob->protectflag & OB_LOCK_ROTZ) == 0)
ob->quat[3]= 0.0f;
if (ob->rotmode == ROT_MODE_AXISANGLE) {
if ((ob->protectflag & OB_LOCK_ROTW) == 0)
ob->rotAngle= 0.0f;
if ((ob->protectflag & OB_LOCK_ROTX) == 0)
ob->rotAxis[0]= 0.0f;
if ((ob->protectflag & OB_LOCK_ROTY) == 0)
ob->rotAxis[1]= 0.0f;
if ((ob->protectflag & OB_LOCK_ROTZ) == 0)
ob->rotAxis[2]= 0.0f;
/* check validity of axis - axis should never be 0,0,0 (if so, then we make it rotate about y) */
if (IS_EQ(ob->rotAxis[0], ob->rotAxis[1]) && IS_EQ(ob->rotAxis[1], ob->rotAxis[2]))
ob->rotAxis[1] = 1.0f;
}
else if (ob->rotmode == ROT_MODE_QUAT) {
if ((ob->protectflag & OB_LOCK_ROTW) == 0)
ob->quat[0]= 1.0f;
if ((ob->protectflag & OB_LOCK_ROTX) == 0)
ob->quat[1]= 0.0f;
if ((ob->protectflag & OB_LOCK_ROTY) == 0)
ob->quat[2]= 0.0f;
if ((ob->protectflag & OB_LOCK_ROTZ) == 0)
ob->quat[3]= 0.0f;
}
else {
/* the flag may have been set for the other modes, so just ignore the extra flag... */
if ((ob->protectflag & OB_LOCK_ROTX) == 0)
ob->rot[0]= 0.0f;
if ((ob->protectflag & OB_LOCK_ROTY) == 0)
ob->rot[1]= 0.0f;
if ((ob->protectflag & OB_LOCK_ROTZ) == 0)
ob->rot[2]= 0.0f;
}
}
else {
/* perform clamping using euler form (3-components) */
@ -138,7 +162,7 @@ static int object_rotation_clear_exec(bContext *C, wmOperator *op)
QuatToEul(ob->quat, oldeul);
}
else if (ob->rotmode == ROT_MODE_AXISANGLE) {
AxisAngleToEulO(&ob->quat[1], ob->quat[0], oldeul, EULER_ORDER_DEFAULT);
AxisAngleToEulO(ob->rotAxis, ob->rotAngle, oldeul, EULER_ORDER_DEFAULT);
}
else {
VECCOPY(oldeul, ob->rot);
@ -161,7 +185,7 @@ static int object_rotation_clear_exec(bContext *C, wmOperator *op)
}
}
else if (ob->rotmode == ROT_MODE_AXISANGLE) {
AxisAngleToEulO(&ob->quat[1], ob->quat[0], oldeul, EULER_ORDER_DEFAULT);
EulOToAxisAngle(eul, EULER_ORDER_DEFAULT, ob->rotAxis, &ob->rotAngle);
}
else {
VECCOPY(ob->rot, eul);
@ -175,8 +199,8 @@ static int object_rotation_clear_exec(bContext *C, wmOperator *op)
}
else if (ob->rotmode == ROT_MODE_AXISANGLE) {
/* by default, make rotation of 0 radians around y-axis (roll) */
ob->quat[0]=ob->quat[1]=ob->quat[3]= 0.0f;
ob->quat[2]= 1.0f;
ob->rotAxis[0]=ob->rotAxis[2]=ob->rotAngle= 0.0f;
ob->rotAxis[1]= 1.0f;
}
else {
ob->rot[0]= ob->rot[1]= ob->rot[2]= 0.0f;

@ -689,6 +689,7 @@ static void do_view3d_region_buttons(bContext *C, void *arg, int event)
case B_OBJECTPANELROT:
if(ob) {
// TODO: need to support roation modes
ob->rot[0]= M_PI*tfp->ob_eul[0]/180.0;
ob->rot[1]= M_PI*tfp->ob_eul[1]/180.0;
ob->rot[2]= M_PI*tfp->ob_eul[2]/180.0;
@ -870,13 +871,12 @@ static void do_view3d_region_buttons(bContext *C, void *arg, int event)
float quat[4];
/* convert to axis-angle, passing through quats */
EulToQuat(eul, quat);
QuatToAxisAngle(quat, &pchan->quat[1], &pchan->quat[0]);
QuatToAxisAngle(quat, pchan->rotAxis, &pchan->rotAngle);
}
else if (pchan->rotmode == ROT_MODE_QUAT)
EulToQuat(eul, pchan->quat);
else
VecCopyf(pchan->eul, eul);
}
/* no break, pass on */
case B_ARMATUREPANEL2:

@ -509,7 +509,7 @@ static short apply_targetless_ik(Object *ob)
if (parchan->rotmode > 0)
Mat3ToEulO(rmat3, parchan->eul, parchan->rotmode);
else if (parchan->rotmode == ROT_MODE_AXISANGLE)
Mat3ToAxisAngle(rmat3, &parchan->quat[1], &parchan->quat[0]);
Mat3ToAxisAngle(rmat3, parchan->rotAxis, &pchan->rotAngle);
else
Mat3ToQuat(rmat3, parchan->quat);
@ -519,7 +519,7 @@ static short apply_targetless_ik(Object *ob)
if (parchan->rotmode > 0)
EulOToMat3(parchan->eul, parchan->rotmode, qrmat);
else if (parchan->rotmode == ROT_MODE_AXISANGLE)
AxisAngleToMat3(&parchan->quat[1], parchan->quat[0], qrmat);
AxisAngleToMat3(parchan->rotAxis, parchan->rotAngle, qrmat);
else
QuatToMat3(parchan->quat, qrmat);

@ -128,12 +128,15 @@ typedef struct bPoseChannel {
void *dual_quat;
void *b_bone_dual_quats;
float loc[3]; /* transforms - written in by actions or transform */
/* transforms - written in by actions or transform */
float loc[3];
float size[3];
float eul[3]; /* rotations - written in by actions or transform (but only euler/quat in use at any one time!) */
float quat[4];
short rotmode; /* for now either quat (0), or xyz-euler (1) */
/* rotations - written in by actions or transform (but only one representation gets used at any time) */
float eul[3]; /* euler rotation */
float quat[4]; /* quaternion rotation */
float rotAxis[3], rotAngle; /* axis-angle rotation */
short rotmode; /* eRotationModes - rotation representation to use */
short pad;
float chan_mat[4][4]; /* matrix result of loc/quat/size , and where we put deform in, see next line */

@ -133,8 +133,10 @@ typedef struct Object {
/* rot en drot have to be together! (transform('r' en 's')) */
float loc[3], dloc[3], orig[3];
float size[3], dsize[3];
float rot[3], drot[3];
float quat[4], dquat[4];
float rot[3], drot[3]; /* euler rotation */
float quat[4], dquat[4]; /* quaternion rotation */
float rotAxis[3], drotAxis[3]; /* axis angle rotation - axis part */
float rotAngle, drotAngle; /* axis angle rotation - angle part */
float obmat[4][4];
float parentinv[4][4]; /* inverse result of parent, so that object doesn't 'stick' to parent */
float constinv[4][4]; /* inverse result of constraints. doesn't include effect of parent or object local transform */

@ -484,12 +484,34 @@ static void rna_Object_rotation_euler_set(PointerRNA *ptr, const float *value)
VECCOPY(ob->rot, value);
}
/* rotation - axis-angle */
static void rna_Object_rotation_axis_angle_get(PointerRNA *ptr, float *value)
{
Object *ob= ptr->data;
/* for now, assume that rotation mode is axis-angle */
value[0]= ob->rotAngle;
VecCopyf(&value[1], ob->rotAxis);
}
/* rotation - axis-angle */
static void rna_Object_rotation_axis_angle_set(PointerRNA *ptr, const float *value)
{
Object *ob= ptr->data;
/* for now, assume that rotation mode is axis-angle */
ob->rotAngle= value[0];
VecCopyf(ob->rotAxis, (float *)&value[1]);
// TODO: validate axis?
}
static void rna_Object_rotation_mode_set(PointerRNA *ptr, int value)
{
Object *ob= ptr->data;
/* use API Method for conversions... */
BKE_rotMode_change_values(ob->quat, ob->rot, ob->rotmode, (short)value);
BKE_rotMode_change_values(ob->quat, ob->rot, ob->rotAxis, &ob->rotAngle, ob->rotmode, (short)value);
/* finally, set the new rotation type */
ob->rotmode= value;
@ -1242,8 +1264,8 @@ static void rna_def_object(BlenderRNA *brna)
* having a single one is better for Keyframing and other property-management situations...
*/
prop= RNA_def_property(srna, "rotation_axis_angle", PROP_FLOAT, PROP_AXISANGLE);
RNA_def_property_float_sdna(prop, NULL, "quat");
// TODO: we may need some validation funcs
RNA_def_property_array(prop, 4); // TODO: maybe we'll need to define the 'default value' getter too...
RNA_def_property_float_funcs(prop, "rna_Object_rotation_axis_angle_get", "rna_Object_rotation_axis_angle_set", NULL);
RNA_def_property_ui_text(prop, "Axis-Angle Rotation", "Angle of Rotation for Axis-Angle rotation representation.");
RNA_def_property_update(prop, NC_OBJECT|ND_TRANSFORM, "rna_Object_update");
@ -1283,7 +1305,7 @@ static void rna_def_object(BlenderRNA *brna)
#if 0 // XXX not supported well yet...
prop= RNA_def_property(srna, "delta_rotation_axis_angle", PROP_FLOAT, PROP_AXISANGLE);
RNA_def_property_float_sdna(prop, NULL, "dquat");
RNA_def_property_float_sdna(prop, NULL, "dquat"); // FIXME: this is not a single field any more! (drotAxis and drotAngle)
RNA_def_property_ui_text(prop, "Delta Rotation (Axis Angle)", "Extra added rotation to the rotation of the object (when using Axis-Angle rotations).");
RNA_def_property_update(prop, NC_OBJECT|ND_TRANSFORM, "rna_Object_update");
#endif

@ -162,7 +162,7 @@ static void rna_PoseChannel_rotation_euler_get(PointerRNA *ptr, float *value)
bPoseChannel *pchan= ptr->data;
if(pchan->rotmode == ROT_MODE_AXISANGLE) /* default XYZ eulers */
AxisAngleToEulO(&pchan->quat[1], pchan->quat[0], value, EULER_ORDER_DEFAULT);
AxisAngleToEulO(pchan->rotAxis, pchan->rotAngle, value, EULER_ORDER_DEFAULT);
else if(pchan->rotmode == ROT_MODE_QUAT) /* default XYZ eulers */
QuatToEul(pchan->quat, value);
else
@ -175,19 +175,41 @@ static void rna_PoseChannel_rotation_euler_set(PointerRNA *ptr, const float *val
bPoseChannel *pchan= ptr->data;
if(pchan->rotmode == ROT_MODE_AXISANGLE) /* default XYZ eulers */
EulOToAxisAngle((float *)value, EULER_ORDER_DEFAULT, &pchan->quat[1], &pchan->quat[0]);
EulOToAxisAngle((float *)value, EULER_ORDER_DEFAULT, pchan->rotAxis, &pchan->rotAngle);
else if(pchan->rotmode == ROT_MODE_QUAT) /* default XYZ eulers */
EulToQuat((float*)value, pchan->quat);
else
VECCOPY(pchan->eul, value);
}
/* rotation - axis-angle */
static void rna_PoseChannel_rotation_axis_angle_get(PointerRNA *ptr, float *value)
{
bPoseChannel *pchan= ptr->data;
/* for now, assume that rotation mode is axis-angle */
value[0]= pchan->rotAngle;
VecCopyf(&value[1], pchan->rotAxis);
}
/* rotation - axis-angle */
static void rna_PoseChannel_rotation_axis_angle_set(PointerRNA *ptr, const float *value)
{
bPoseChannel *pchan= ptr->data;
/* for now, assume that rotation mode is axis-angle */
pchan->rotAngle= value[0];
VecCopyf(pchan->rotAxis, (float *)&value[1]);
// TODO: validate axis?
}
static void rna_PoseChannel_rotation_mode_set(PointerRNA *ptr, int value)
{
bPoseChannel *pchan= ptr->data;
/* use API Method for conversions... */
BKE_rotMode_change_values(pchan->quat, pchan->eul, pchan->rotmode, (short)value);
BKE_rotMode_change_values(pchan->quat, pchan->eul, pchan->rotAxis, &pchan->rotAngle, pchan->rotmode, (short)value);
/* finally, set the new rotation type */
pchan->rotmode= value;
@ -578,8 +600,8 @@ static void rna_def_pose_channel(BlenderRNA *brna)
* having a single one is better for Keyframing and other property-management situations...
*/
prop= RNA_def_property(srna, "rotation_axis_angle", PROP_FLOAT, PROP_AXISANGLE);
RNA_def_property_float_sdna(prop, NULL, "quat");
// TODO: we may need some validation funcs
RNA_def_property_array(prop, 4); // TODO: maybe we'll need to define the 'default value' getter too...
RNA_def_property_float_funcs(prop, "rna_PoseChannel_rotation_axis_angle_get", "rna_PoseChannel_rotation_axis_angle_set", NULL);
RNA_def_property_ui_text(prop, "Axis-Angle Rotation", "Angle of Rotation for Axis-Angle rotation representation.");
RNA_def_property_update(prop, NC_OBJECT|ND_TRANSFORM, "rna_Pose_update");