FIRE-34884: Separate delta-mode operation from rotation changes

master
Angeldark Raymaker 2024-12-02 19:40:36 +00:00
parent ffd83207a6
commit 617a8f0644
6 changed files with 114 additions and 78 deletions

View File

@ -1131,7 +1131,7 @@ void FSFloaterPoser::onUndoLastRotation()
{
bool currentlyPosing = mPoserAnimator.isPosingAvatarJoint(avatar, *item);
if (currentlyPosing)
mPoserAnimator.undoLastJointRotation(avatar, *item, getUiSelectedBoneDeflectionStyle(item->jointName()));
mPoserAnimator.undoLastJointRotation(avatar, *item, getUiSelectedBoneDeflectionStyle());
}
enableOrDisableRedoButton();
@ -1156,7 +1156,7 @@ void FSFloaterPoser::onUndoLastPosition()
{
bool currentlyPosing = mPoserAnimator.isPosingAvatarJoint(avatar, *item);
if (currentlyPosing)
mPoserAnimator.undoLastJointPosition(avatar, *item, getUiSelectedBoneDeflectionStyle(item->jointName()));
mPoserAnimator.undoLastJointPosition(avatar, *item, getUiSelectedBoneDeflectionStyle());
}
refreshAdvancedPositionSliders();
@ -1180,7 +1180,7 @@ void FSFloaterPoser::onUndoLastScale()
{
bool currentlyPosing = mPoserAnimator.isPosingAvatarJoint(avatar, *item);
if (currentlyPosing)
mPoserAnimator.undoLastJointScale(avatar, *item, getUiSelectedBoneDeflectionStyle(item->jointName()));
mPoserAnimator.undoLastJointScale(avatar, *item, getUiSelectedBoneDeflectionStyle());
}
refreshAdvancedScaleSliders();
@ -1220,7 +1220,7 @@ void FSFloaterPoser::onResetPosition()
{
bool currentlyPosing = mPoserAnimator.isPosingAvatarJoint(avatar, *item);
if (currentlyPosing)
mPoserAnimator.resetJointPosition(avatar, *item, getUiSelectedBoneDeflectionStyle(item->jointName()));
mPoserAnimator.resetJointPosition(avatar, *item, getUiSelectedBoneDeflectionStyle());
}
refreshAdvancedPositionSliders();
@ -1247,7 +1247,7 @@ void FSFloaterPoser::onResetScale()
{
bool currentlyPosing = mPoserAnimator.isPosingAvatarJoint(avatar, *item);
if (currentlyPosing)
mPoserAnimator.resetJointScale(avatar, *item, getUiSelectedBoneDeflectionStyle(item->jointName()));
mPoserAnimator.resetJointScale(avatar, *item, getUiSelectedBoneDeflectionStyle());
}
refreshAdvancedScaleSliders();
@ -1270,7 +1270,7 @@ void FSFloaterPoser::onRedoLastRotation()
{
bool currentlyPosing = mPoserAnimator.isPosingAvatarJoint(avatar, *item);
if (currentlyPosing)
mPoserAnimator.redoLastJointRotation(avatar, *item, getUiSelectedBoneDeflectionStyle(item->jointName()));
mPoserAnimator.redoLastJointRotation(avatar, *item, getUiSelectedBoneDeflectionStyle());
}
enableOrDisableRedoButton();
@ -1295,7 +1295,7 @@ void FSFloaterPoser::onRedoLastPosition()
{
bool currentlyPosing = mPoserAnimator.isPosingAvatarJoint(avatar, *item);
if (currentlyPosing)
mPoserAnimator.redoLastJointPosition(avatar, *item, getUiSelectedBoneDeflectionStyle(item->jointName()));
mPoserAnimator.redoLastJointPosition(avatar, *item, getUiSelectedBoneDeflectionStyle());
}
refreshAdvancedPositionSliders();
@ -1319,7 +1319,7 @@ void FSFloaterPoser::onRedoLastScale()
{
bool currentlyPosing = mPoserAnimator.isPosingAvatarJoint(avatar, *item);
if (currentlyPosing)
mPoserAnimator.redoLastJointScale(avatar, *item, getUiSelectedBoneDeflectionStyle(item->jointName()));
mPoserAnimator.redoLastJointScale(avatar, *item, getUiSelectedBoneDeflectionStyle());
}
refreshAdvancedScaleSliders();
@ -1443,39 +1443,25 @@ std::vector<FSPoserAnimator::FSPoserJoint*> FSFloaterPoser::getUiSelectedPoserJo
return joints;
}
bool FSFloaterPoser::isAnyDeltaModeRotation(const E_BoneDeflectionStyles deflection)
{
if (mToggleDeltaModeBtn->getValue().asBoolean())
return true;
switch (deflection)
{
case DELTAMODE:
case SYMPATHETIC_DELTA:
case MIRROR_DELTA:
return true;
case NONE:
case SYMPATHETIC:
case MIRROR:
default:
return false;
}
}
E_BoneDeflectionStyles FSFloaterPoser::getUiSelectedBoneDeflectionStyle(const std::string& jointName) const
E_RotationStyle FSFloaterPoser::getUiSelectedBoneRotationStyle(const std::string& jointName) const
{
if (jointName.empty())
return NONE;
return ABSOLUTE_ROT;
bool isDelta = mToggleDeltaModeBtn->getValue().asBoolean();
bool hasRotationStylePreferenceParameter = hasString(XML_JOINT_DELTAROT_STRING_PREFIX + jointName);
if (hasRotationStylePreferenceParameter)
{
std::string paramValue = getString(XML_JOINT_DELTAROT_STRING_PREFIX + jointName);
if (strstr(paramValue.c_str(), "true"))
isDelta = true;
}
if (!hasRotationStylePreferenceParameter)
return ABSOLUTE_ROT;
std::string paramValue = getString(XML_JOINT_DELTAROT_STRING_PREFIX + jointName);
if (strstr(paramValue.c_str(), "true"))
return DELTAIC_ROT;
return ABSOLUTE_ROT;
}
E_BoneDeflectionStyles FSFloaterPoser::getUiSelectedBoneDeflectionStyle() const
{
bool isDelta = mToggleDeltaModeBtn->getValue().asBoolean();
if (mToggleMirrorRotationBtn->getValue().asBoolean())
return isDelta ? MIRROR_DELTA : MIRROR;
@ -1746,6 +1732,7 @@ void FSFloaterPoser::setSelectedJointsPosition(F32 x, F32 y, F32 z)
return;
LLVector3 vec3 = LLVector3(x, y, z);
E_BoneDeflectionStyles defl = getUiSelectedBoneDeflectionStyle();
for (auto item : getUiSelectedPoserJoints())
{
@ -1753,7 +1740,6 @@ void FSFloaterPoser::setSelectedJointsPosition(F32 x, F32 y, F32 z)
if (!currentlyPosingJoint)
continue;
E_BoneDeflectionStyles defl = getUiSelectedBoneDeflectionStyle(item->jointName());
mPoserAnimator.setJointPosition(avatar, item, vec3, defl);
}
}
@ -1767,8 +1753,9 @@ void FSFloaterPoser::setSelectedJointsRotation(LLVector3 absoluteRot, LLVector3
if (!mPoserAnimator.isPosingAvatar(avatar))
return;
auto selectedJoints = getUiSelectedPoserJoints();
bool savingToExternal = getWhetherToResetBaseRotationOnEdit();
auto selectedJoints = getUiSelectedPoserJoints();
bool savingToExternal = getWhetherToResetBaseRotationOnEdit();
E_BoneDeflectionStyles defl = getUiSelectedBoneDeflectionStyle();
for (auto item : selectedJoints)
{
@ -1786,9 +1773,9 @@ void FSFloaterPoser::setSelectedJointsRotation(LLVector3 absoluteRot, LLVector3
continue;
}
E_BoneDeflectionStyles defl = getUiSelectedBoneDeflectionStyle(item->jointName());
mPoserAnimator.setJointRotation(avatar, item, isAnyDeltaModeRotation(defl) ? deltaRot : absoluteRot, defl,
getJointTranslation(item->jointName()), getJointNegation(item->jointName()), savingToExternal);
mPoserAnimator.setJointRotation(avatar, item, absoluteRot, deltaRot, defl,
getJointTranslation(item->jointName()), getJointNegation(item->jointName()), savingToExternal,
getUiSelectedBoneRotationStyle(item->jointName()));
}
if (savingToExternal)
@ -1804,7 +1791,8 @@ void FSFloaterPoser::setSelectedJointsScale(F32 x, F32 y, F32 z)
if (!mPoserAnimator.isPosingAvatar(avatar))
return;
LLVector3 vec3 = LLVector3(x, y, z);
LLVector3 vec3 = LLVector3(x, y, z);
E_BoneDeflectionStyles defl = getUiSelectedBoneDeflectionStyle();
for (auto item : getUiSelectedPoserJoints())
{
@ -1812,7 +1800,6 @@ void FSFloaterPoser::setSelectedJointsScale(F32 x, F32 y, F32 z)
if (!currentlyPosingJoint)
continue;
E_BoneDeflectionStyles defl = getUiSelectedBoneDeflectionStyle(item->jointName());
mPoserAnimator.setJointScale(avatar, item, vec3, defl);
}
}

View File

@ -147,16 +147,16 @@ class FSFloaterPoser : public LLFloater
/// Gets the current bone-deflection style: encapsulates 'anything else you want to do' while you're manipulating a joint.
/// Such as: fiddle the opposite joint too.
/// </summary>
/// <param name="jointName">The well-known joint name of the joint to add the row for, eg: mChest.</param>
/// <returns>A E_BoneDeflectionStyles member.</returns>
E_BoneDeflectionStyles getUiSelectedBoneDeflectionStyle(const std::string& jointName) const;
E_BoneDeflectionStyles getUiSelectedBoneDeflectionStyle() const;
/// <summary>
/// Gets whether the supplied joint name should be rotated using the delta method.
/// Gets the means by which the rotation should be applied to the supplied joint name.
/// Such as: fiddle the opposite joint too.
/// </summary>
/// <param name="deflection">The deflection to consider.</param>
/// <returns>true if the joint should be rotated by delta for any reason, otherwise false.</returns>
bool isAnyDeltaModeRotation(const E_BoneDeflectionStyles deflection);
/// <param name="jointName">The well-known joint name of the joint to add the row for, eg: mChest.</param>
/// <returns>A E_RotationStyle member.</returns>
E_RotationStyle getUiSelectedBoneRotationStyle(const std::string& jointName) const;
/// <summary>
/// Gets the collection of UUIDs for nearby avatars.

View File

@ -169,13 +169,30 @@ void FSJointPose::swapRotationWith(FSJointPose* oppositeJoint)
if (mIsCollisionVolume)
return;
LLJoint* joint = mJointState->getJoint();
if (!joint)
auto tempRot = FSJointRotation(mRotation);
mRotation = FSJointRotation(oppositeJoint->mRotation);
oppositeJoint->mRotation = tempRot;
}
void FSJointPose::cloneRotationFrom(FSJointPose* fromJoint)
{
if (!fromJoint)
return;
auto tempRot = FSJointRotation(mRotation);
mRotation = FSJointRotation(oppositeJoint->mRotation);
oppositeJoint->mRotation = tempRot;
mRotation = FSJointRotation(fromJoint->mRotation);
}
void FSJointPose::mirrorRotationFrom(FSJointPose* fromJoint)
{
if (!fromJoint)
return;
cloneRotationFrom(fromJoint);
mRotation.baseRotation = LLQuaternion(-mRotation.baseRotation.mQ[VX], mRotation.baseRotation.mQ[VY], -mRotation.baseRotation.mQ[VZ],
mRotation.baseRotation.mQ[VW]);
mRotation.deltaRotation = LLQuaternion(-mRotation.deltaRotation.mQ[VX], mRotation.deltaRotation.mQ[VY], -mRotation.deltaRotation.mQ[VZ],
mRotation.deltaRotation.mQ[VW]);
}
void FSJointPose::revertJointScale()

View File

@ -147,6 +147,16 @@ class FSJointPose
/// </summary>
void swapRotationWith(FSJointPose* oppositeJoint);
/// <summary>
/// Clones the rotation to this from the supplied joint.
/// </summary>
void cloneRotationFrom(FSJointPose* fromJoint);
/// <summary>
/// Mirrors the rotation to this from the supplied joint.
/// </summary>
void mirrorRotationFrom(FSJointPose* fromJoint);
/// <summary>
/// Resets the beginning properties of the joint this represents.
/// </summary>

View File

@ -496,8 +496,9 @@ LLVector3 FSPoserAnimator::getJointRotation(LLVOAvatar* avatar, const FSPoserJoi
return translateRotationFromQuaternion(translation, negation, jointPose->getRotationDelta());
}
void FSPoserAnimator::setJointRotation(LLVOAvatar* avatar, const FSPoserJoint* joint, const LLVector3& rotation, E_BoneDeflectionStyles style, E_BoneAxisTranslation translation, S32 negation,
bool resetBaseRotationToZero)
void FSPoserAnimator::setJointRotation(LLVOAvatar* avatar, const FSPoserJoint* joint, const LLVector3& absRotation,
const LLVector3& deltaRotation, E_BoneDeflectionStyles deflectionStyle,
E_BoneAxisTranslation translation, S32 negation, bool resetBaseRotationToZero, E_RotationStyle rotationStyle)
{
if (!isAvatarSafeToUse(avatar))
return;
@ -515,26 +516,35 @@ void FSPoserAnimator::setJointRotation(LLVOAvatar* avatar, const FSPoserJoint* j
if (resetBaseRotationToZero)
jointPose->zeroBaseRotation();
LLQuaternion rot_quat = translateRotationToQuaternion(translation, negation, rotation);
switch (style)
LLQuaternion absRot = translateRotationToQuaternion(translation, negation, absRotation);
LLQuaternion deltaRot = translateRotationToQuaternion(translation, negation, deltaRotation);
switch (deflectionStyle)
{
case SYMPATHETIC:
case MIRROR:
jointPose->setRotationDelta(rot_quat);
if (rotationStyle == DELTAIC_ROT)
jointPose->setRotationDelta(deltaRot * jointPose->getRotationDelta());
else
jointPose->setRotationDelta(absRot);
break;
case SYMPATHETIC_DELTA:
case MIRROR_DELTA:
jointPose->setRotationDelta(rot_quat * jointPose->getRotationDelta());
jointPose->setRotationDelta(deltaRot * jointPose->getRotationDelta());
break;
case DELTAMODE:
jointPose->setRotationDelta(rot_quat * jointPose->getRotationDelta());
jointPose->setRotationDelta(deltaRot * jointPose->getRotationDelta());
return;
case NONE:
default:
jointPose->setRotationDelta(rot_quat);
if (rotationStyle == DELTAIC_ROT)
jointPose->setRotationDelta(deltaRot * jointPose->getRotationDelta());
else
jointPose->setRotationDelta(absRot);
return;
}
@ -542,27 +552,23 @@ void FSPoserAnimator::setJointRotation(LLVOAvatar* avatar, const FSPoserJoint* j
if (!oppositeJointPose)
return;
if (resetBaseRotationToZero)
oppositeJointPose->zeroBaseRotation();
LLQuaternion inv_quat;
switch (style)
switch (deflectionStyle)
{
case SYMPATHETIC:
oppositeJointPose->setRotationDelta(rot_quat);
oppositeJointPose->cloneRotationFrom(jointPose);
break;
case SYMPATHETIC_DELTA:
oppositeJointPose->setRotationDelta(rot_quat * oppositeJointPose->getRotationDelta());
oppositeJointPose->setRotationDelta(deltaRot * oppositeJointPose->getRotationDelta());
break;
case MIRROR:
inv_quat = LLQuaternion(-rot_quat.mQ[VX], rot_quat.mQ[VY], -rot_quat.mQ[VZ], rot_quat.mQ[VW]);
oppositeJointPose->setRotationDelta(inv_quat);
oppositeJointPose->mirrorRotationFrom(jointPose);
break;
case MIRROR_DELTA:
inv_quat = LLQuaternion(-rot_quat.mQ[VX], rot_quat.mQ[VY], -rot_quat.mQ[VZ], rot_quat.mQ[VW]);
inv_quat = LLQuaternion(-deltaRot.mQ[VX], deltaRot.mQ[VY], -deltaRot.mQ[VZ], deltaRot.mQ[VW]);
oppositeJointPose->setRotationDelta(inv_quat * oppositeJointPose->getRotationDelta());
break;

View File

@ -54,10 +54,24 @@ typedef enum E_BoneDeflectionStyles
MIRROR = 1, // change the other joint, like in a mirror, eg: one left one right
SYMPATHETIC = 2, // change the other joint, but opposite to a mirrored way, eg: both go right or both go left
DELTAMODE = 3, // each selected joint changes by the same supplied amount relative to their current
MIRROR_DELTA = 4, // As MIRROR, but applied as negated delta to opposite
SYMPATHETIC_DELTA = 5, // As SYMPATHETIC, but applied as delta
MIRROR_DELTA = 4, // Applies a MIRROR delta, this limb and its opposite change by opposite amount
SYMPATHETIC_DELTA = 5, // Applies a SYMPATHETIC delta, this limb and the opposite change by the same amount
} E_BoneDeflectionStyles;
/// <summary>
/// Joints may have rotations applied by applying an absolute value or a delta value.
/// When applying a rotation as absolutes, feedback via the UI can tend to Gimbal lock control of the quaternion.
/// For certain joints, particularly "down the centreline", absolute rotations provide the best feel.
/// For other joints, such as hips, knees, elbows and wrists, Gimbal lock readily occurs (sitting poses particularly), and
/// applying small angle changes directly to the quaternion (rather than going via the locked absolute) makes for
/// a more sensible user experience.
/// </summary>
typedef enum E_RotationStyle
{
ABSOLUTE_ROT = 0, // The rotation should be applied as an absolute value because while it can Gimbal lock, it doesn't happen often.
DELTAIC_ROT = 1, // The rotation should be applied as a delta value because it is apt to Gimbal lock.
} E_RotationStyle;
/// <summary>
/// When we're going from bone-rotation to the UI sliders, some of the axes need swapping so they make sense in UI-terms.
/// eg: for one bone, the X-axis may mean up and down, but for another bone, the x-axis might be left-right.
@ -457,13 +471,15 @@ public:
/// </summary>
/// <param name="avatar">The avatar whose joint is to be set.</param>
/// <param name="joint">The joint to set.</param>
/// <param name="rotation">The rotation to set the joint to.</param>
/// <param name="absRotation">The absolute rotation to apply to the joint, if appropriate.</param>
/// <param name="deltaRotation">The delta of rotation to apply to the joint, if appropriate.</param>
/// <param name="style">Any ancilliary action to be taken with the change to be made.</param>
/// <param name="translation">The axial translation form the supplied joint.</param>
/// <param name="negation">The style of negation to apply to the set.</param>
/// <param name="resetBaseRotationToZero">Whether to set the base rotation to zero on setting the rotation.</param>
void setJointRotation(LLVOAvatar* avatar, const FSPoserJoint* joint, const LLVector3& rotation, E_BoneDeflectionStyles style,
E_BoneAxisTranslation translation, S32 negation, bool resetBaseRotationToZero);
/// <param name="rotationStyle">Whether to apply the supplied rotation as a delta to the supplied joint.</param>
void setJointRotation(LLVOAvatar* avatar, const FSPoserJoint* joint, const LLVector3& absRotation, const LLVector3& deltaRotation, E_BoneDeflectionStyles style,
E_BoneAxisTranslation translation, S32 negation, bool resetBaseRotationToZero, E_RotationStyle rotationStyle);
/// <summary>
/// Gets the scale of a joint for the supplied avatar.