FIRE-35686: Add icon to each bone for BVH export state
Also: - correct an issue where Manip changes would not reset base rot, required for BVH - always 'lock' mPelvis for BVH export - Copy L/R and loads can now 'undo' - removed two check-boxes for BVH: now tick-and gomaster
parent
adb9ce2a5c
commit
3bd58efda2
|
|
@ -8100,17 +8100,6 @@
|
|||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>FSPoserResetBaseRotationOnEdit</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Whether to reset the base-rotation of a joint to zero when a user edits it.</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>FSPoserOnSaveConfirmOverwrite</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
|
|
|
|||
|
|
@ -60,7 +60,6 @@ constexpr char XML_JOINT_DELTAROT_STRING_PREFIX[] = "joint_delta_ro
|
|||
constexpr char BVH_JOINT_TRANSFORM_STRING_PREFIX[] = "bvh_joint_transform_";
|
||||
constexpr std::string_view POSER_TRACKPAD_SENSITIVITY_SAVE_KEY = "FSPoserTrackpadSensitivity";
|
||||
constexpr std::string_view POSER_STOPPOSINGWHENCLOSED_SAVE_KEY = "FSPoserStopPosingWhenClosed";
|
||||
constexpr std::string_view POSER_RESETBASEROTONEDIT_SAVE_KEY = "FSPoserResetBaseRotationOnEdit";
|
||||
constexpr std::string_view POSER_SAVEEXTERNALFORMAT_SAVE_KEY = "FSPoserSaveExternalFileAlso";
|
||||
constexpr std::string_view POSER_SAVECONFIRMREQUIRED_SAVE_KEY = "FSPoserOnSaveConfirmOverwrite";
|
||||
constexpr char ICON_SAVE_OK[] = "icon_rotation_is_own_work";
|
||||
|
|
@ -212,8 +211,7 @@ bool FSFloaterPoser::postBuild()
|
|||
mCollisionVolumesPnl = getChild<LLPanel>("collision_volumes_panel");
|
||||
|
||||
mAlsoSaveBvhCbx = getChild<LLCheckBoxCtrl>("also_save_bvh_checkbox");
|
||||
mResetBaseRotCbx = getChild<LLCheckBoxCtrl>("reset_base_rotation_on_edit_checkbox");
|
||||
mResetBaseRotCbx->setCommitCallback([this](LLUICtrl*, const LLSD&) { onClickSetBaseRotZero(); });
|
||||
mAlsoSaveBvhCbx->setCommitCallback([this](LLUICtrl*, const LLSD&) { onClickSavingToBvh(); });
|
||||
|
||||
mTrackpadSensitivitySpnr = getChild<LLUICtrl>("trackpad_sensitivity_spinner");
|
||||
mYawSpnr = getChild<LLUICtrl>("limb_yaw_spinner");
|
||||
|
|
@ -366,10 +364,10 @@ void FSFloaterPoser::onPoseFileSelect()
|
|||
mPoseSaveNameEditor->setText(name);
|
||||
|
||||
bool isDeltaSave = !poseFileStartsFromTeePose(name);
|
||||
if (isDeltaSave && hasString("LoadDiffLabel"))
|
||||
mLoadPosesBtn->setLabel(getString("LoadDiffLabel"));
|
||||
else if (hasString("LoadPoseLabel"))
|
||||
mLoadPosesBtn->setLabel(getString("LoadPoseLabel"));
|
||||
if (isDeltaSave)
|
||||
mLoadPosesBtn->setLabel(tryGetString("LoadDiffLabel"));
|
||||
else
|
||||
mLoadPosesBtn->setLabel(tryGetString("LoadPoseLabel"));
|
||||
}
|
||||
|
||||
void FSFloaterPoser::doPoseSave(LLVOAvatar* avatar, const std::string& filename)
|
||||
|
|
@ -386,24 +384,21 @@ void FSFloaterPoser::doPoseSave(LLVOAvatar* avatar, const std::string& filename)
|
|||
if (getSavingToBvh())
|
||||
savePoseToBvh(avatar, filename);
|
||||
|
||||
if (hasString(ICON_SAVE_OK))
|
||||
mSavePosesBtn->setImageOverlay(getString(ICON_SAVE_OK), mSavePosesBtn->getImageOverlayHAlign());
|
||||
|
||||
mSavePosesBtn->setImageOverlay(tryGetString(ICON_SAVE_OK), mSavePosesBtn->getImageOverlayHAlign());
|
||||
setSavePosesButtonText(!mPoserAnimator.allBaseRotationsAreZero(avatar));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (hasString(ICON_SAVE_FAILED))
|
||||
mSavePosesBtn->setImageOverlay(getString(ICON_SAVE_FAILED), mSavePosesBtn->getImageOverlayHAlign());
|
||||
}
|
||||
mSavePosesBtn->setImageOverlay(tryGetString(ICON_SAVE_FAILED), mSavePosesBtn->getImageOverlayHAlign());
|
||||
}
|
||||
}
|
||||
|
||||
void FSFloaterPoser::onClickPoseSave()
|
||||
{
|
||||
std::string filename = mPoseSaveNameEditor->getValue().asString();
|
||||
if (filename.empty() && hasString(ICON_SAVE_FAILED))
|
||||
if (filename.empty())
|
||||
{
|
||||
mSavePosesBtn->setImageOverlay(getString(ICON_SAVE_FAILED), mSavePosesBtn->getImageOverlayHAlign());
|
||||
mSavePosesBtn->setImageOverlay(tryGetString(ICON_SAVE_FAILED), mSavePosesBtn->getImageOverlayHAlign());
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -444,8 +439,7 @@ void FSFloaterPoser::onClickPoseSave()
|
|||
|
||||
void FSFloaterPoser::onMouseLeaveSavePoseBtn()
|
||||
{
|
||||
if (hasString("icon_save_button"))
|
||||
mSavePosesBtn->setImageOverlay(getString("icon_save_button"), mSavePosesBtn->getImageOverlayHAlign());
|
||||
mSavePosesBtn->setImageOverlay(tryGetString("icon_save_button"), mSavePosesBtn->getImageOverlayHAlign());
|
||||
|
||||
LLVOAvatar* avatar = getUiSelectedAvatar();
|
||||
if (!avatar)
|
||||
|
|
@ -691,7 +685,8 @@ void FSFloaterPoser::updatePosedBones(const std::string& jointName)
|
|||
if (!poserJoint)
|
||||
return;
|
||||
|
||||
mPoserAnimator.recaptureJointAsDelta(avatar, poserJoint, getUiSelectedBoneDeflectionStyle());
|
||||
bool savingToExternal = getSavingToBvh();
|
||||
mPoserAnimator.recaptureJointAsDelta(avatar, poserJoint, savingToExternal, getUiSelectedBoneDeflectionStyle());
|
||||
|
||||
refreshRotationSlidersAndSpinners();
|
||||
refreshPositionSlidersAndSpinners();
|
||||
|
|
@ -723,6 +718,9 @@ void FSFloaterPoser::onClickSymmetrize(const S32 ID)
|
|||
refreshRotationSlidersAndSpinners();
|
||||
enableOrDisableRedoAndUndoButton();
|
||||
refreshTrackpadCursor();
|
||||
|
||||
if (getSavingToBvh())
|
||||
refreshTextHighlightingOnJointScrollLists();
|
||||
}
|
||||
|
||||
void FSFloaterPoser::onCommitSpinner(const LLUICtrl* spinner, const S32 id)
|
||||
|
|
@ -964,6 +962,8 @@ void FSFloaterPoser::onClickLoadHandPose(bool isRightHand)
|
|||
mPoserAnimator.loadJointRotation(avatar, poserJoint, true, vec3);
|
||||
}
|
||||
}
|
||||
|
||||
addBoldToScrollList(mHandJointsScrollList, avatar);
|
||||
}
|
||||
catch ( const std::exception& e )
|
||||
{
|
||||
|
|
@ -1310,8 +1310,8 @@ LLSD FSFloaterPoser::createRowForJoint(const std::string& jointName, bool isHead
|
|||
return NULL;
|
||||
|
||||
std::string headerValue = "";
|
||||
if (isHeaderRow && hasString("icon_category"))
|
||||
headerValue = getString("icon_category");
|
||||
if (isHeaderRow)
|
||||
headerValue = tryGetString("icon_category");
|
||||
|
||||
std::string jointValue = jointName;
|
||||
std::string parameterName = (isHeaderRow ? XML_LIST_HEADER_STRING_PREFIX : XML_LIST_TITLE_STRING_PREFIX) + jointName;
|
||||
|
|
@ -1404,6 +1404,8 @@ void FSFloaterPoser::onUndoLastChange()
|
|||
refreshPositionSlidersAndSpinners();
|
||||
refreshScaleSlidersAndSpinners();
|
||||
refreshTrackpadCursor();
|
||||
if (getSavingToBvh())
|
||||
refreshTextHighlightingOnJointScrollLists();
|
||||
}
|
||||
|
||||
void FSFloaterPoser::onSetAvatarToTpose()
|
||||
|
|
@ -1447,6 +1449,8 @@ void FSFloaterPoser::onResetJoint(const LLSD data)
|
|||
refreshScaleSlidersAndSpinners();
|
||||
refreshTrackpadCursor();
|
||||
enableOrDisableRedoAndUndoButton();
|
||||
if (getSavingToBvh())
|
||||
refreshTextHighlightingOnJointScrollLists();
|
||||
}
|
||||
|
||||
void FSFloaterPoser::onRedoLastChange()
|
||||
|
|
@ -1474,6 +1478,8 @@ void FSFloaterPoser::onRedoLastChange()
|
|||
refreshTrackpadCursor();
|
||||
refreshScaleSlidersAndSpinners();
|
||||
refreshPositionSlidersAndSpinners();
|
||||
if (getSavingToBvh())
|
||||
refreshTextHighlightingOnJointScrollLists();
|
||||
}
|
||||
|
||||
void FSFloaterPoser::enableOrDisableRedoAndUndoButton()
|
||||
|
|
@ -1967,7 +1973,7 @@ void FSFloaterPoser::setSelectedJointsRotation(const LLVector3& absoluteRot, con
|
|||
return;
|
||||
|
||||
auto selectedJoints = getUiSelectedPoserJoints();
|
||||
bool savingToExternal = getWhetherToResetBaseRotationOnEdit();
|
||||
bool savingToExternal = getSavingToBvh();
|
||||
E_BoneDeflectionStyles defl = getUiSelectedBoneDeflectionStyle();
|
||||
|
||||
for (auto item : selectedJoints)
|
||||
|
|
@ -2081,7 +2087,6 @@ void FSFloaterPoser::onJointTabSelect()
|
|||
refreshTrackpadCursor();
|
||||
enableOrDisableRedoAndUndoButton();
|
||||
refreshScaleSlidersAndSpinners();
|
||||
onClickSetBaseRotZero();
|
||||
}
|
||||
|
||||
E_BoneAxisTranslation FSFloaterPoser::getJointTranslation(const std::string& jointName) const
|
||||
|
|
@ -2348,8 +2353,7 @@ void FSFloaterPoser::refreshTextHighlightingOnJointScrollLists()
|
|||
|
||||
void FSFloaterPoser::setSavePosesButtonText(bool setAsSaveDiff)
|
||||
{
|
||||
if (hasString("SavePoseLabel") && hasString("SaveDiffLabel"))
|
||||
setAsSaveDiff ? mSavePosesBtn->setLabel(getString("SaveDiffLabel")) : mSavePosesBtn->setLabel(getString("SavePoseLabel"));
|
||||
setAsSaveDiff ? mSavePosesBtn->setLabel(tryGetString("SaveDiffLabel")) : mSavePosesBtn->setLabel(tryGetString("SavePoseLabel"));
|
||||
}
|
||||
|
||||
void FSFloaterPoser::addBoldToScrollList(LLScrollListCtrl* list, LLVOAvatar* avatar)
|
||||
|
|
@ -2361,32 +2365,56 @@ void FSFloaterPoser::addBoldToScrollList(LLScrollListCtrl* list, LLVOAvatar* ava
|
|||
return;
|
||||
|
||||
std::string iconValue = "";
|
||||
bool considerExternalFormatSaving = getWhetherToResetBaseRotationOnEdit();
|
||||
|
||||
if (considerExternalFormatSaving && hasString("icon_rotation_is_own_work"))
|
||||
iconValue = getString("icon_rotation_is_own_work");
|
||||
bool considerExternalFormatSaving = getSavingToBvh();
|
||||
|
||||
for (auto listItem : list->getAllData())
|
||||
{
|
||||
FSPoserAnimator::FSPoserJoint *userData = static_cast<FSPoserAnimator::FSPoserJoint *>(listItem->getUserdata());
|
||||
if (!userData)
|
||||
FSPoserAnimator::FSPoserJoint *poserJoint = static_cast<FSPoserAnimator::FSPoserJoint *>(listItem->getUserdata());
|
||||
if (!poserJoint)
|
||||
continue;
|
||||
|
||||
if (considerExternalFormatSaving)
|
||||
{
|
||||
if (mPoserAnimator.baseRotationIsZero(avatar, *userData))
|
||||
((LLScrollListText*) listItem->getColumn(COL_ICON))->setValue(iconValue);
|
||||
else
|
||||
((LLScrollListText*) listItem->getColumn(COL_ICON))->setValue("");
|
||||
}
|
||||
((LLScrollListText*)listItem->getColumn(COL_ICON))->setValue(getScrollListIconForJoint(avatar, *poserJoint));
|
||||
else
|
||||
((LLScrollListText*)listItem->getColumn(COL_ICON))->setValue("");
|
||||
|
||||
if (mPoserAnimator.isPosingAvatarJoint(avatar, *userData))
|
||||
if (mPoserAnimator.isPosingAvatarJoint(avatar, *poserJoint))
|
||||
((LLScrollListText *) listItem->getColumn(COL_NAME))->setFontStyle(LLFontGL::BOLD);
|
||||
else
|
||||
((LLScrollListText *) listItem->getColumn(COL_NAME))->setFontStyle(LLFontGL::NORMAL);
|
||||
}
|
||||
}
|
||||
|
||||
std::string FSFloaterPoser::getScrollListIconForJoint(LLVOAvatar* avatar, FSPoserAnimator::FSPoserJoint joint)
|
||||
{
|
||||
if (!avatar)
|
||||
return "";
|
||||
|
||||
if (mPoserAnimator.getRotationIsWorldLocked(avatar, joint))
|
||||
return tryGetString("icon_rotation_is_world_locked");
|
||||
|
||||
if (joint.boneType() == COL_VOLUMES)
|
||||
return tryGetString("icon_rotation_does_not_export");
|
||||
|
||||
if (mPoserAnimator.userSetBaseRotationToZero(avatar, joint))
|
||||
{
|
||||
if (mPoserAnimator.exportRotationWillLockJoint(avatar, joint))
|
||||
return tryGetString("icon_rotation_bvh_locked_edited");
|
||||
else
|
||||
return tryGetString("icon_rotation_bvh_locked_unedited");
|
||||
}
|
||||
else
|
||||
return tryGetString("icon_rotation_bvh_unlocked");
|
||||
}
|
||||
|
||||
std::string FSFloaterPoser::tryGetString(std::string name)
|
||||
{
|
||||
if (name.empty())
|
||||
return "";
|
||||
|
||||
return hasString(name) ? getString(name) : "";
|
||||
}
|
||||
|
||||
bool FSFloaterPoser::savePoseToBvh(LLVOAvatar* avatar, const std::string& poseFileName)
|
||||
{
|
||||
if (poseFileName.empty())
|
||||
|
|
@ -2552,7 +2580,7 @@ void FSFloaterPoser::writeBvhMotion(llofstream* fileStream, LLVOAvatar* avatar,
|
|||
if (!joint)
|
||||
return;
|
||||
|
||||
auto rotation = mPoserAnimator.getJointRotation(avatar, *joint, SWAP_NOTHING, NEGATE_NOTHING);
|
||||
auto rotation = mPoserAnimator.getJointExportRotation(avatar, *joint);
|
||||
auto position = mPoserAnimator.getJointPosition(avatar, *joint);
|
||||
|
||||
switch (joint->boneType())
|
||||
|
|
@ -2644,12 +2672,9 @@ S32 FSFloaterPoser::getBvhJointNegation(const std::string& jointName) const
|
|||
return result;
|
||||
}
|
||||
|
||||
bool FSFloaterPoser::getWhetherToResetBaseRotationOnEdit() { return gSavedSettings.getBOOL(POSER_RESETBASEROTONEDIT_SAVE_KEY); }
|
||||
|
||||
void FSFloaterPoser::onClickSetBaseRotZero() { mAlsoSaveBvhCbx->setEnabled(getWhetherToResetBaseRotationOnEdit()); }
|
||||
|
||||
bool FSFloaterPoser::getSavingToBvh()
|
||||
{
|
||||
return getWhetherToResetBaseRotationOnEdit() && gSavedSettings.getBOOL(POSER_RESETBASEROTONEDIT_SAVE_KEY);
|
||||
return gSavedSettings.getBOOL(POSER_SAVEEXTERNALFORMAT_SAVE_KEY);
|
||||
}
|
||||
|
||||
void FSFloaterPoser::onClickSavingToBvh() { refreshTextHighlightingOnJointScrollLists(); }
|
||||
|
|
|
|||
|
|
@ -264,7 +264,7 @@ public:
|
|||
void onClickLoadLeftHandPose();
|
||||
void onClickLoadRightHandPose();
|
||||
void onClickLoadHandPose(bool isRightHand);
|
||||
void onClickSetBaseRotZero();
|
||||
void onClickSavingToBvh();
|
||||
void onCommitSpinner(const LLUICtrl* spinner, const S32 ID);
|
||||
void onCommitSlider(const LLUICtrl* slider, const S32 id);
|
||||
void onClickSymmetrize(const S32 ID);
|
||||
|
|
@ -351,12 +351,19 @@ public:
|
|||
void addBoldToScrollList(LLScrollListCtrl* list, LLVOAvatar* avatar);
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether the user wishes to reset the base-rotation to zero when they start editing a joint.
|
||||
/// Gets a string for a joint on a scroll-list.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If a joint has a base-rotation of zero, the rotation then appears to be the user's work and qualifies to save to a re-importable format.
|
||||
/// </remarks>
|
||||
bool getWhetherToResetBaseRotationOnEdit();
|
||||
/// <param name="avatar">The avatar owning the supplied joint.</param>
|
||||
/// <param name="joint">The joint to query.</param>
|
||||
/// <returns>A string naming an icon to present with the joint.</returns>
|
||||
std::string getScrollListIconForJoint(LLVOAvatar* avatar, FSPoserAnimator::FSPoserJoint joint);
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get the named string from the XUI.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the string.</param>
|
||||
/// <returns>The named string, if it exists, otherwise an empty string.</returns>
|
||||
std::string tryGetString(std::string name);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of an item from the supplied object ID.
|
||||
|
|
@ -503,7 +510,6 @@ public:
|
|||
LLPanel* mCollisionVolumesPnl{ nullptr };
|
||||
LLPanel* mPosesLoadSavePnl{ nullptr };
|
||||
|
||||
LLCheckBoxCtrl* mResetBaseRotCbx{ nullptr };
|
||||
LLCheckBoxCtrl* mAlsoSaveBvhCbx{ nullptr };
|
||||
|
||||
LLUICtrl* mTrackpadSensitivitySpnr{ nullptr };
|
||||
|
|
|
|||
|
|
@ -57,9 +57,13 @@ void FSJointPose::setPublicPosition(const LLVector3& pos)
|
|||
mCurrentState.mPosition.set(pos);
|
||||
}
|
||||
|
||||
void FSJointPose::setPublicRotation(const LLQuaternion& rot)
|
||||
void FSJointPose::setPublicRotation(bool zeroBase, const LLQuaternion& rot)
|
||||
{
|
||||
addStateToUndo(FSJointState(mCurrentState));
|
||||
|
||||
if (zeroBase)
|
||||
zeroBaseRotation();
|
||||
|
||||
mCurrentState.mRotation.set(rot);
|
||||
}
|
||||
|
||||
|
|
@ -79,6 +83,12 @@ void FSJointPose::redoLastChange()
|
|||
mCurrentState = redoLastStateChange(FSJointState(mCurrentState));
|
||||
}
|
||||
|
||||
void FSJointPose::resetJoint()
|
||||
{
|
||||
addStateToUndo(FSJointState(mCurrentState));
|
||||
mCurrentState.resetJoint();
|
||||
}
|
||||
|
||||
void FSJointPose::addStateToUndo(FSJointState stateToAddToUndo)
|
||||
{
|
||||
auto timeIntervalSinceLastChange = std::chrono::system_clock::now() - mTimeLastUpdatedCurrentState;
|
||||
|
|
@ -125,7 +135,7 @@ FSJointPose::FSJointState FSJointPose::redoLastStateChange(FSJointState thingToS
|
|||
|
||||
mUndoneJointStatesIndex -= 1;
|
||||
mUndoneJointStatesIndex = llclamp(mUndoneJointStatesIndex, 0, mLastSetJointStates.size() - 1);
|
||||
auto result = mLastSetJointStates.at(mUndoneJointStatesIndex);
|
||||
FSJointState result = mLastSetJointStates.at(mUndoneJointStatesIndex);
|
||||
if (mUndoneJointStatesIndex == 0)
|
||||
mLastSetJointStates.pop_front();
|
||||
|
||||
|
|
@ -145,14 +155,14 @@ void FSJointPose::recaptureJoint()
|
|||
mCurrentState = FSJointState(joint);
|
||||
}
|
||||
|
||||
void FSJointPose::recaptureJointAsDelta()
|
||||
void FSJointPose::recaptureJointAsDelta(bool zeroBase)
|
||||
{
|
||||
LLJoint* joint = mJointState->getJoint();
|
||||
if (!joint)
|
||||
return;
|
||||
|
||||
addStateToUndo(FSJointState(mCurrentState));
|
||||
mCurrentState.updateFromJoint(joint);
|
||||
mCurrentState.updateFromJoint(joint, zeroBase);
|
||||
}
|
||||
|
||||
void FSJointPose::swapRotationWith(FSJointPose* oppositeJoint)
|
||||
|
|
@ -203,9 +213,6 @@ void FSJointPose::zeroBaseRotation()
|
|||
if (mIsCollisionVolume)
|
||||
return;
|
||||
|
||||
if (!isBaseRotationZero())
|
||||
purgeUndoQueue();
|
||||
|
||||
mCurrentState.zeroBaseRotation();
|
||||
}
|
||||
|
||||
|
|
@ -219,10 +226,21 @@ bool FSJointPose::isBaseRotationZero() const
|
|||
|
||||
void FSJointPose::purgeUndoQueue()
|
||||
{
|
||||
if (mIsCollisionVolume)
|
||||
return;
|
||||
|
||||
mUndoneJointStatesIndex = 0;
|
||||
mLastSetJointStates.clear();
|
||||
}
|
||||
|
||||
bool FSJointPose::userHaseSetBaseRotationToZero() const
|
||||
{
|
||||
if (mIsCollisionVolume)
|
||||
return false;
|
||||
|
||||
return mCurrentState.userSetBaseRotationToZero();
|
||||
}
|
||||
|
||||
bool FSJointPose::canPerformUndo() const
|
||||
{
|
||||
switch (mLastSetJointStates.size())
|
||||
|
|
|
|||
|
|
@ -77,6 +77,11 @@ class FSJointPose
|
|||
/// </summary>
|
||||
void redoLastChange();
|
||||
|
||||
/// <summary>
|
||||
/// Resets the joint to its conditions when posing started.
|
||||
/// </summary>
|
||||
void resetJoint();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the 'public' rotation of the joint.
|
||||
/// </summary>
|
||||
|
|
@ -85,12 +90,14 @@ class FSJointPose
|
|||
/// <summary>
|
||||
/// Sets the 'public' rotation of the joint.
|
||||
/// </summary>
|
||||
/// <param name="zeroBase">Whether to zero the base rotation on setting the supplied rotation.</param>
|
||||
/// <param name="rot">The change in rotation to apply.</param>
|
||||
/// <remarks>
|
||||
/// 'Public rotation' is the amount of rotation the user has added to the initial state.
|
||||
/// Public rotation is what a user may save to an external format (such as BVH).
|
||||
/// This distinguishes 'private' rotation, which is the state inherited from something like a pose in-world.
|
||||
/// </remarks>
|
||||
void setPublicRotation(const LLQuaternion& rot);
|
||||
void setPublicRotation(bool zeroBase, const LLQuaternion& rot);
|
||||
|
||||
/// <summary>
|
||||
/// Reflects the base and delta rotation of the represented joint left-right.
|
||||
|
|
@ -153,13 +160,20 @@ class FSJointPose
|
|||
/// <summary>
|
||||
/// Recalculates the delta reltive to the base for a new rotation.
|
||||
/// </summary>
|
||||
void recaptureJointAsDelta();
|
||||
/// <param name="zeroBase">Whether to zero the base rotation on setting the supplied rotation.</param>
|
||||
void recaptureJointAsDelta(bool zeroBase);
|
||||
|
||||
/// <summary>
|
||||
/// Clears the undo/redo deque.
|
||||
/// </summary>
|
||||
void purgeUndoQueue();
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether the user has specified the base rotation of a joint to be zero.
|
||||
/// </summary>
|
||||
/// <returns>True if the user performed some action to specify zero rotation as the base, otherwise false.</returns>
|
||||
bool userHaseSetBaseRotationToZero() const;
|
||||
|
||||
/// <summary>
|
||||
/// Reverts the position/rotation/scale to their values when the animation begun.
|
||||
/// This treatment is required for certain joints, particularly Collision Volumes and those bones not commonly animated by an AO.
|
||||
|
|
@ -180,6 +194,7 @@ class FSJointPose
|
|||
public:
|
||||
FSJointState(LLJoint* joint)
|
||||
{
|
||||
mStartingRotation.set(joint->getRotation());
|
||||
mBaseRotation.set(joint->getRotation());
|
||||
mBasePosition.set(joint->getPosition());
|
||||
mBaseScale.set(joint->getScale());
|
||||
|
|
@ -209,11 +224,27 @@ class FSJointPose
|
|||
{
|
||||
mBaseRotation.set(otherState.mBaseRotation);
|
||||
mRotation.set(otherState.mRotation);
|
||||
mUserSpecifiedBaseZero = otherState.userSetBaseRotationToZero();
|
||||
}
|
||||
|
||||
bool userSetBaseRotationToZero() const { return mUserSpecifiedBaseZero; }
|
||||
|
||||
bool baseRotationIsZero() const { return mBaseRotation == LLQuaternion::DEFAULT; }
|
||||
|
||||
void zeroBaseRotation() { mBaseRotation = LLQuaternion::DEFAULT; }
|
||||
void resetJoint()
|
||||
{
|
||||
mUserSpecifiedBaseZero = false;
|
||||
mBaseRotation.set(mStartingRotation);
|
||||
mRotation.set(LLQuaternion::DEFAULT);
|
||||
mPosition.setZero();
|
||||
mScale.setZero();
|
||||
}
|
||||
|
||||
void zeroBaseRotation()
|
||||
{
|
||||
mBaseRotation = LLQuaternion::DEFAULT;
|
||||
mUserSpecifiedBaseZero = true;
|
||||
}
|
||||
|
||||
void revertJointToBase(LLJoint* joint) const
|
||||
{
|
||||
|
|
@ -225,7 +256,7 @@ class FSJointPose
|
|||
joint->setScale(mBaseScale);
|
||||
}
|
||||
|
||||
void updateFromJoint(LLJoint* joint)
|
||||
void updateFromJoint(LLJoint* joint, bool zeroBase)
|
||||
{
|
||||
if (!joint)
|
||||
return;
|
||||
|
|
@ -233,6 +264,10 @@ class FSJointPose
|
|||
LLQuaternion invRot = mBaseRotation;
|
||||
invRot.conjugate();
|
||||
mRotation = joint->getRotation() * invRot;
|
||||
|
||||
if (zeroBase)
|
||||
zeroBaseRotation();
|
||||
|
||||
mPosition.set(joint->getPosition() - mBasePosition);
|
||||
mScale.set(joint->getScale() - mBaseScale);
|
||||
}
|
||||
|
|
@ -240,6 +275,7 @@ class FSJointPose
|
|||
private:
|
||||
FSJointState(FSJointState* state)
|
||||
{
|
||||
mStartingRotation.set(state->mStartingRotation);
|
||||
mBaseRotation.set(state->mBaseRotation);
|
||||
mBasePosition.set(state->mBasePosition);
|
||||
mBaseScale.set(state->mBaseScale);
|
||||
|
|
@ -247,6 +283,7 @@ class FSJointPose
|
|||
mRotation.set(state->mRotation);
|
||||
mPosition.set(state->mPosition);
|
||||
mScale.set(state->mScale);
|
||||
mUserSpecifiedBaseZero = state->userSetBaseRotationToZero();
|
||||
}
|
||||
|
||||
public:
|
||||
|
|
@ -255,9 +292,11 @@ class FSJointPose
|
|||
LLVector3 mScale;
|
||||
|
||||
private:
|
||||
LLQuaternion mStartingRotation;
|
||||
LLQuaternion mBaseRotation;
|
||||
LLVector3 mBasePosition;
|
||||
LLVector3 mBaseScale;
|
||||
bool mUserSpecifiedBaseZero = false;
|
||||
};
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -122,9 +122,7 @@ void FSPoserAnimator::resetJoint(LLVOAvatar* avatar, const FSPoserJoint& joint,
|
|||
if (!jointPose)
|
||||
return;
|
||||
|
||||
jointPose->setPublicRotation(LLQuaternion());
|
||||
jointPose->setPublicPosition(LLVector3());
|
||||
jointPose->setPublicScale(LLVector3());
|
||||
jointPose->resetJoint();
|
||||
|
||||
if (style == NONE || style == DELTAMODE)
|
||||
return;
|
||||
|
|
@ -133,9 +131,7 @@ void FSPoserAnimator::resetJoint(LLVOAvatar* avatar, const FSPoserJoint& joint,
|
|||
if (!oppositeJointPose)
|
||||
return;
|
||||
|
||||
oppositeJointPose->setPublicRotation(LLQuaternion());
|
||||
oppositeJointPose->setPublicPosition(LLVector3());
|
||||
oppositeJointPose->setPublicScale(LLVector3());
|
||||
oppositeJointPose->resetJoint();
|
||||
}
|
||||
|
||||
bool FSPoserAnimator::canRedoOrUndoJointChange(LLVOAvatar* avatar, const FSPoserJoint& joint, bool canUndo)
|
||||
|
|
@ -265,7 +261,7 @@ void FSPoserAnimator::setJointPosition(LLVOAvatar* avatar, const FSPoserJoint* j
|
|||
}
|
||||
}
|
||||
|
||||
bool FSPoserAnimator::baseRotationIsZero(LLVOAvatar* avatar, const FSPoserJoint& joint) const
|
||||
bool FSPoserAnimator::getRotationIsWorldLocked(LLVOAvatar* avatar, const FSPoserJoint& joint) const
|
||||
{
|
||||
if (!isAvatarSafeToUse(avatar))
|
||||
return false;
|
||||
|
|
@ -278,7 +274,53 @@ bool FSPoserAnimator::baseRotationIsZero(LLVOAvatar* avatar, const FSPoserJoint&
|
|||
if (!jointPose)
|
||||
return false;
|
||||
|
||||
return jointPose->isBaseRotationZero();
|
||||
// TODO: FIRE-35769
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FSPoserAnimator::exportRotationWillLockJoint(LLVOAvatar* avatar, const FSPoserJoint& joint) const
|
||||
{
|
||||
const F32 ROTATION_KEYFRAME_THRESHOLD = 0.01f; // this is a guestimate: see BVH loader
|
||||
|
||||
if (!isAvatarSafeToUse(avatar))
|
||||
return false;
|
||||
|
||||
FSPosingMotion* posingMotion = getPosingMotion(avatar);
|
||||
if (!posingMotion)
|
||||
return false;
|
||||
|
||||
FSJointPose* jointPose = posingMotion->getJointPoseByJointName(joint.jointName());
|
||||
if (!jointPose)
|
||||
return false;
|
||||
|
||||
if (!jointPose->userHaseSetBaseRotationToZero())
|
||||
return false;
|
||||
|
||||
F32 rot_threshold = ROTATION_KEYFRAME_THRESHOLD / llmax((F32)getChildJointDepth(&joint, 0) * 0.33f, 1.f);
|
||||
LLQuaternion rotToExport = jointPose->getPublicRotation();
|
||||
|
||||
F32 x_delta = dist_vec(LLVector3::x_axis * LLQuaternion::DEFAULT, LLVector3::x_axis * rotToExport); // when exporting multiple frames this will need to compare frames.
|
||||
F32 y_delta = dist_vec(LLVector3::y_axis * LLQuaternion::DEFAULT, LLVector3::y_axis * rotToExport);
|
||||
F32 rot_test = x_delta + y_delta;
|
||||
|
||||
return rot_test > rot_threshold;
|
||||
}
|
||||
|
||||
bool FSPoserAnimator::userSetBaseRotationToZero(LLVOAvatar* avatar, const FSPoserJoint& joint) const
|
||||
{
|
||||
if (!isAvatarSafeToUse(avatar))
|
||||
return false;
|
||||
|
||||
FSPosingMotion* posingMotion = getPosingMotion(avatar);
|
||||
if (!posingMotion)
|
||||
return false;
|
||||
|
||||
FSJointPose* jointPose = posingMotion->getJointPoseByJointName(joint.jointName());
|
||||
if (!jointPose)
|
||||
return false;
|
||||
|
||||
return jointPose->userHaseSetBaseRotationToZero();
|
||||
}
|
||||
|
||||
bool FSPoserAnimator::allBaseRotationsAreZero(LLVOAvatar* avatar) const
|
||||
|
|
@ -326,7 +368,8 @@ void FSPoserAnimator::recaptureJoint(LLVOAvatar* avatar, const FSPoserJoint& joi
|
|||
setPosingAvatarJoint(avatar, joint, true);
|
||||
}
|
||||
|
||||
void FSPoserAnimator::recaptureJointAsDelta(LLVOAvatar* avatar, const FSPoserJoint* joint, E_BoneDeflectionStyles style)
|
||||
void FSPoserAnimator::recaptureJointAsDelta(LLVOAvatar* avatar, const FSPoserJoint* joint, bool resetBaseRotationToZero,
|
||||
E_BoneDeflectionStyles style)
|
||||
{
|
||||
if (!isAvatarSafeToUse(avatar))
|
||||
return;
|
||||
|
|
@ -339,7 +382,7 @@ void FSPoserAnimator::recaptureJointAsDelta(LLVOAvatar* avatar, const FSPoserJoi
|
|||
if (!jointPose)
|
||||
return;
|
||||
|
||||
jointPose->recaptureJointAsDelta();
|
||||
jointPose->recaptureJointAsDelta(resetBaseRotationToZero);
|
||||
|
||||
if (style == NONE || style == DELTAMODE)
|
||||
return;
|
||||
|
|
@ -365,6 +408,35 @@ void FSPoserAnimator::recaptureJointAsDelta(LLVOAvatar* avatar, const FSPoserJoi
|
|||
}
|
||||
}
|
||||
|
||||
LLVector3 FSPoserAnimator::getJointExportRotation(LLVOAvatar* avatar, const FSPoserJoint& joint) const
|
||||
{
|
||||
auto rotation = getJointRotation(avatar, joint, SWAP_NOTHING, NEGATE_NOTHING);
|
||||
if (exportRotationWillLockJoint(avatar, joint))
|
||||
return rotation;
|
||||
|
||||
LLVector3 vec3;
|
||||
if (!isAvatarSafeToUse(avatar))
|
||||
return vec3;
|
||||
|
||||
FSPosingMotion* posingMotion = getPosingMotion(avatar);
|
||||
if (!posingMotion)
|
||||
return vec3;
|
||||
|
||||
FSJointPose* jointPose = posingMotion->getJointPoseByJointName(joint.jointName());
|
||||
if (!jointPose)
|
||||
return vec3;
|
||||
|
||||
if (!jointPose->userHaseSetBaseRotationToZero())
|
||||
return vec3;
|
||||
|
||||
if (joint.boneType() == WHOLEAVATAR)
|
||||
return LLVector3(DEG_TO_RAD * 0.295f, 0.f, 0.f);
|
||||
|
||||
F32 minimumRotation = DEG_TO_RAD * 0.65f / llmax((F32)getChildJointDepth(&joint, 0) * 0.33f, 1.f);
|
||||
|
||||
return LLVector3(minimumRotation, 0.f, 0.f);
|
||||
}
|
||||
|
||||
LLVector3 FSPoserAnimator::getJointRotation(LLVOAvatar* avatar, const FSPoserJoint& joint, E_BoneAxisTranslation translation, S32 negation) const
|
||||
{
|
||||
LLVector3 vec3;
|
||||
|
|
@ -399,9 +471,6 @@ void FSPoserAnimator::setJointRotation(LLVOAvatar* avatar, const FSPoserJoint* j
|
|||
if (!jointPose)
|
||||
return;
|
||||
|
||||
if (resetBaseRotationToZero)
|
||||
jointPose->zeroBaseRotation();
|
||||
|
||||
LLQuaternion absRot = translateRotationToQuaternion(translation, negation, absRotation);
|
||||
LLQuaternion deltaRot = translateRotationToQuaternion(translation, negation, deltaRotation);
|
||||
switch (deflectionStyle)
|
||||
|
|
@ -409,27 +478,27 @@ void FSPoserAnimator::setJointRotation(LLVOAvatar* avatar, const FSPoserJoint* j
|
|||
case SYMPATHETIC:
|
||||
case MIRROR:
|
||||
if (rotationStyle == DELTAIC_ROT)
|
||||
jointPose->setPublicRotation(deltaRot * jointPose->getPublicRotation());
|
||||
jointPose->setPublicRotation(resetBaseRotationToZero, deltaRot * jointPose->getPublicRotation());
|
||||
else
|
||||
jointPose->setPublicRotation(absRot);
|
||||
jointPose->setPublicRotation(resetBaseRotationToZero, absRot);
|
||||
|
||||
break;
|
||||
|
||||
case SYMPATHETIC_DELTA:
|
||||
case MIRROR_DELTA:
|
||||
jointPose->setPublicRotation(deltaRot * jointPose->getPublicRotation());
|
||||
jointPose->setPublicRotation(resetBaseRotationToZero, deltaRot * jointPose->getPublicRotation());
|
||||
break;
|
||||
|
||||
case DELTAMODE:
|
||||
jointPose->setPublicRotation(deltaRot * jointPose->getPublicRotation());
|
||||
jointPose->setPublicRotation(resetBaseRotationToZero, deltaRot * jointPose->getPublicRotation());
|
||||
return;
|
||||
|
||||
case NONE:
|
||||
default:
|
||||
if (rotationStyle == DELTAIC_ROT)
|
||||
jointPose->setPublicRotation(deltaRot * jointPose->getPublicRotation());
|
||||
jointPose->setPublicRotation(resetBaseRotationToZero, deltaRot * jointPose->getPublicRotation());
|
||||
else
|
||||
jointPose->setPublicRotation(absRot);
|
||||
jointPose->setPublicRotation(resetBaseRotationToZero, absRot);
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
@ -446,7 +515,7 @@ void FSPoserAnimator::setJointRotation(LLVOAvatar* avatar, const FSPoserJoint* j
|
|||
break;
|
||||
|
||||
case SYMPATHETIC_DELTA:
|
||||
oppositeJointPose->setPublicRotation(deltaRot * oppositeJointPose->getPublicRotation());
|
||||
oppositeJointPose->setPublicRotation(resetBaseRotationToZero, deltaRot * oppositeJointPose->getPublicRotation());
|
||||
break;
|
||||
|
||||
case MIRROR:
|
||||
|
|
@ -455,7 +524,7 @@ void FSPoserAnimator::setJointRotation(LLVOAvatar* avatar, const FSPoserJoint* j
|
|||
|
||||
case MIRROR_DELTA:
|
||||
inv_quat = LLQuaternion(-deltaRot.mQ[VX], deltaRot.mQ[VY], -deltaRot.mQ[VZ], deltaRot.mQ[VW]);
|
||||
oppositeJointPose->setPublicRotation(inv_quat * oppositeJointPose->getPublicRotation());
|
||||
oppositeJointPose->setPublicRotation(resetBaseRotationToZero, inv_quat * oppositeJointPose->getPublicRotation());
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
@ -757,11 +826,10 @@ void FSPoserAnimator::loadJointRotation(LLVOAvatar* avatar, const FSPoserJoint*
|
|||
if (!jointPose)
|
||||
return;
|
||||
|
||||
if (setBaseToZero)
|
||||
jointPose->zeroBaseRotation();
|
||||
jointPose->purgeUndoQueue();
|
||||
|
||||
LLQuaternion rot = translateRotationToQuaternion(SWAP_NOTHING, NEGATE_NOTHING, rotation);
|
||||
jointPose->setPublicRotation(rot);
|
||||
jointPose->setPublicRotation(setBaseToZero, rot);
|
||||
}
|
||||
|
||||
void FSPoserAnimator::loadJointPosition(LLVOAvatar* avatar, const FSPoserJoint* joint, bool loadPositionAsDelta, LLVector3 position)
|
||||
|
|
@ -802,7 +870,7 @@ void FSPoserAnimator::loadJointScale(LLVOAvatar* avatar, const FSPoserJoint* joi
|
|||
jointPose->setPublicScale(scale);
|
||||
}
|
||||
|
||||
const FSPoserAnimator::FSPoserJoint* FSPoserAnimator::getPoserJointByName(const std::string& jointName)
|
||||
const FSPoserAnimator::FSPoserJoint* FSPoserAnimator::getPoserJointByName(const std::string& jointName) const
|
||||
{
|
||||
for (size_t index = 0; index != PoserJoints.size(); ++index)
|
||||
{
|
||||
|
|
@ -899,3 +967,23 @@ bool FSPoserAnimator::isAvatarSafeToUse(LLVOAvatar* avatar) const
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
int FSPoserAnimator::getChildJointDepth(const FSPoserJoint* joint, int depth) const
|
||||
{
|
||||
size_t numberOfBvhChildNodes = joint->bvhChildren().size();
|
||||
if (numberOfBvhChildNodes < 1)
|
||||
return depth;
|
||||
|
||||
depth++;
|
||||
|
||||
for (size_t index = 0; index != numberOfBvhChildNodes; ++index)
|
||||
{
|
||||
auto nextJoint = getPoserJointByName(joint->bvhChildren()[index]);
|
||||
if (!nextJoint)
|
||||
continue;
|
||||
|
||||
depth = llmax(depth, getChildJointDepth(nextJoint, depth));
|
||||
}
|
||||
|
||||
return depth;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -392,7 +392,7 @@ public:
|
|||
/// </summary>
|
||||
/// <param name="jointName">The name of the joint to match.</param>
|
||||
/// <returns>The matching joint if found, otherwise nullptr</returns>
|
||||
const FSPoserJoint* getPoserJointByName(const std::string& jointName);
|
||||
const FSPoserJoint* getPoserJointByName(const std::string& jointName) const;
|
||||
|
||||
/// <summary>
|
||||
/// Tries to start posing the supplied avatar.
|
||||
|
|
@ -492,6 +492,18 @@ public:
|
|||
/// <returns>The rotation of the requested joint, if determinable, otherwise a default vector.</returns>
|
||||
LLVector3 getJointRotation(LLVOAvatar* avatar, const FSPoserJoint& joint, E_BoneAxisTranslation translation, S32 negation) const;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the rotation of a joint for the supplied avatar for export.
|
||||
/// </summary>
|
||||
/// <param name="avatar">The avatar whose joint is being queried.</param>
|
||||
/// <param name="joint">The joint to determine the rotation for.</param>
|
||||
/// <returns>The rotation of the requested joint for export.</returns>
|
||||
/// <remarks>
|
||||
/// The BVH export format requires some minimal amount of rotation so it animates the joint on upload.
|
||||
/// The WHOLEAVATAR joint (mPelvis) never exports as 'free'.
|
||||
/// </remarks>
|
||||
LLVector3 getJointExportRotation(LLVOAvatar* avatar, const FSPoserJoint& joint) const;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the rotation of a joint for the supplied avatar.
|
||||
/// </summary>
|
||||
|
|
@ -559,8 +571,9 @@ public:
|
|||
/// </summary>
|
||||
/// <param name="avatar">The avatar whose joint is to be recaptured.</param>
|
||||
/// <param name="joint">The joint to recapture.</param>
|
||||
/// <param name="resetBaseRotationToZero">Whether to set the base rotation to zero on setting the rotation.</param>
|
||||
/// <param name="style">Any ancilliary action to be taken with the change to be made.</param>
|
||||
void recaptureJointAsDelta(LLVOAvatar* avatar, const FSPoserJoint* joint, E_BoneDeflectionStyles style);
|
||||
void recaptureJointAsDelta(LLVOAvatar* avatar, const FSPoserJoint* joint, bool resetBaseRotationToZero, E_BoneDeflectionStyles style);
|
||||
|
||||
/// <summary>
|
||||
/// Sets all of the joint rotations of the supplied avatar to zero.
|
||||
|
|
@ -574,7 +587,26 @@ public:
|
|||
/// <param name="avatar">The avatar owning the supplied joint.</param>
|
||||
/// <param name="joint">The joint to query.</param>
|
||||
/// <returns>True if the supplied joint has a 'base' rotation of zero (thus user-supplied change only), otherwise false.</returns>
|
||||
bool baseRotationIsZero(LLVOAvatar* avatar, const FSPoserJoint& joint) const;
|
||||
bool userSetBaseRotationToZero(LLVOAvatar* avatar, const FSPoserJoint& joint) const;
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether the supplied joints position will be set in an export.
|
||||
/// </summary>
|
||||
/// <param name="avatar">The avatar owning the supplied joint.</param>
|
||||
/// <param name="joint">The joint to query.</param>
|
||||
/// <returns>True if the export will 'lock' the joint, otherwise false.</returns>
|
||||
/// <remarks>
|
||||
/// BVH import leaves a joint 'free' if its rotation is less than something arbitrary.
|
||||
/// </remarks>
|
||||
bool exportRotationWillLockJoint(LLVOAvatar* avatar, const FSPoserJoint& joint) const;
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether the supplied joint for the supplied avatar is rotationally locked to the world.
|
||||
/// </summary>
|
||||
/// <param name="avatar">The avatar owning the supplied joint.</param>
|
||||
/// <param name="joint">The joint to query.</param>
|
||||
/// <returns>True if the joint is maintaining a fixed-rotation in world, otherwise false.</returns>
|
||||
bool getRotationIsWorldLocked(LLVOAvatar* avatar, const FSPoserJoint& joint) const;
|
||||
|
||||
/// <summary>
|
||||
/// Determines if the kind of save to perform should be a 'delta' save, or a complete save.
|
||||
|
|
@ -692,6 +724,14 @@ public:
|
|||
/// <returns>True if the avatar is safe to manipulate, otherwise false.</returns>
|
||||
bool isAvatarSafeToUse(LLVOAvatar* avatar) const;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the depth of descendant joints for the supplied joint.
|
||||
/// </summary>
|
||||
/// <param name="joint">The joint to determine the depth for.</param>
|
||||
/// <param name="depth">The depth of the supplied joint.</param>
|
||||
/// <returns>The number of generations of descendents the joint has, if none, then zero.</returns>
|
||||
int getChildJointDepth(const FSPoserJoint* joint, int depth) const;
|
||||
|
||||
/// <summary>
|
||||
/// Maps the avatar's ID to the animation registered to them.
|
||||
/// Thus we start/stop the same animation, and get/set the same rotations etc.
|
||||
|
|
|
|||
|
|
@ -259,8 +259,8 @@ void FSPosingMotion::setAllRotationsToZeroAndClearUndo()
|
|||
{
|
||||
for (auto poserJoint_iter = mJointPoses.begin(); poserJoint_iter != mJointPoses.end(); ++poserJoint_iter)
|
||||
{
|
||||
poserJoint_iter->zeroBaseRotation();
|
||||
poserJoint_iter->setPublicRotation(LLQuaternion::DEFAULT);
|
||||
poserJoint_iter->purgeUndoQueue();
|
||||
poserJoint_iter->setPublicRotation(true, LLQuaternion::DEFAULT);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,11 @@ width="430">
|
|||
<string name="icon_category" translate="false">Inv_BodyShape</string>
|
||||
<string name="icon_bone" translate="false"></string>
|
||||
<string name="icon_object" translate="false">Inv_Object</string>
|
||||
<string name="icon_rotation_bvh_locked_edited" translate="false">Script_Running</string>
|
||||
<string name="icon_rotation_bvh_locked_unedited" translate="false">Script_NotRunning</string>
|
||||
<string name="icon_rotation_bvh_unlocked" translate="false">Script_Error</string>
|
||||
<string name="icon_rotation_is_world_locked" translate="false">Locked_Icon</string>
|
||||
<string name="icon_rotation_does_not_export" translate="false">Conv_toolbar_close</string>
|
||||
<string name="icon_rotation_is_own_work" translate="false">Check_Mark</string>
|
||||
<string name="icon_save_button" translate="false">Icon_Dock_Foreground</string>
|
||||
<string name="icon_save_failed_button" translate="false">Parcel_Exp_Color</string>
|
||||
|
|
@ -965,25 +970,14 @@ width="430">
|
|||
tool_tip="Not stopping your pose can be helpful if you do a lot of work, and don't want to accidentally lose it."
|
||||
top_pad="10"
|
||||
width="134" />
|
||||
<check_box
|
||||
control_name="FSPoserResetBaseRotationOnEdit"
|
||||
name="reset_base_rotation_on_edit_checkbox"
|
||||
height="16"
|
||||
label="Reset base-rotation on edit"
|
||||
follows="left|top"
|
||||
left="5"
|
||||
tool_tip="When you first edit a rotation, reset it to zero. This means your work can save a pose (and not a diff see load/save). A green tick appears next each joint you have zero-ed export."
|
||||
top_pad="5"
|
||||
width="134" />
|
||||
<check_box
|
||||
control_name="FSPoserSaveExternalFileAlso"
|
||||
name="also_save_bvh_checkbox"
|
||||
height="16"
|
||||
enabled="false"
|
||||
label="Write BVH when saving**"
|
||||
follows="left|top"
|
||||
left="15"
|
||||
tool_tip="When you save your pose, also write a BVH file, which can be uploaded via the 'Build > Upload > Animation' to pose yourself or others in-world. This needs joints to reset their 'base' to zero, because BVH requires original work."
|
||||
left="5"
|
||||
tool_tip="When you save your pose, also write a BVH file. BVH can be uploaded via the 'Build > Upload > Animation' to pose yourself or others in-world. This needs joints to reset their 'base' to zero, because BVH requires original work."
|
||||
top_pad="2"
|
||||
width="134" />
|
||||
<check_box
|
||||
|
|
|
|||
Loading…
Reference in New Issue