diff --git a/indra/llui/llstatbar.cpp b/indra/llui/llstatbar.cpp index 7b2be0744a..46b4071675 100644 --- a/indra/llui/llstatbar.cpp +++ b/indra/llui/llstatbar.cpp @@ -687,7 +687,7 @@ void LLStatBar::drawTicks( F32 min, F32 max, F32 value_scale, LLRect &bar_rect ) { // FIRE-33481 - FS hangs on login, progress bar full LL_DEBUGS("STATBAR") << "name: " << this->getName() << "min: " << min << ", max: " << max << ", value_scale: " << value_scale << LL_ENDL; - if ( value_scale == INFINITY ) + if ( value_scale == std::numeric_limits::infinity() ) { return; } diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 3c2da0698a..818e8da7ca 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -140,6 +140,7 @@ set(viewer_SOURCE_FILES fsfloatervramusage.cpp fsfloaterwearablefavorites.cpp fsfloaterwhitelisthelper.cpp + fsjointpose.cpp fskeywords.cpp fslslbridge.cpp fslslbridgerequest.cpp @@ -937,6 +938,7 @@ set(viewer_HEADER_FILES fsfloaternearbychat.h fsfloaterpartialinventory.h fsfloaterplacedetails.h + fsfloaterposer.h fsfloaterposestand.h fsfloaterprotectedfolders.h fsfloaterradar.h @@ -949,6 +951,7 @@ set(viewer_HEADER_FILES fsfloatervramusage.h fsfloaterwearablefavorites.h fsfloaterwhitelisthelper.h + fsjointpose.h fsgridhandler.h fskeywords.h fslslbridge.h @@ -970,6 +973,8 @@ set(viewer_HEADER_FILES fspanelradar.h fsparticipantlist.h fspose.h + fsposeranimator.h + fsposingmotion.h fsradar.h fsradarentry.h fsradarlistctrl.h @@ -979,6 +984,7 @@ set(viewer_HEADER_FILES fsscrolllistctrl.h fsslurl.h fsslurlcommand.h + fsvirtualtrackpad.h fsworldmapmessage.h lggbeamcolormapfloater.h lggbeammapfloater.h diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index dde130a6b7..581018c15a 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -8067,6 +8067,17 @@ Value 0 + FSPoserResetBaseRotationOnEdit + + Comment + Whether to reset the base-rotation of a joint to zero when a user edits it. + Persist + 1 + Type + Boolean + Value + 0 + FSPoserStopPosingWhenClosed Comment diff --git a/indra/newview/fsfloaterposer.cpp b/indra/newview/fsfloaterposer.cpp index 508574d988..23e34adf3b 100644 --- a/indra/newview/fsfloaterposer.cpp +++ b/indra/newview/fsfloaterposer.cpp @@ -54,6 +54,7 @@ constexpr char XML_JOINT_TRANSFORM_STRING_PREFIX[] = "joint_transfor constexpr std::string_view POSER_ADVANCEDWINDOWSTATE_SAVE_KEY = "FSPoserAdvancedWindowState"; 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"; } // namespace /// @@ -61,7 +62,6 @@ constexpr std::string_view POSER_STOPPOSINGWHENCLOSED_SAVE_KEY = "FSPoserStopPos /// The trackpad ordinarily has a range of +1..-1; multiplied by PI, gives PI to -PI, or all 360 degrees of deflection. /// constexpr F32 NormalTrackpadRangeInRads = F_PI; -bool FSFloaterPoser::sDisableRecaptureUntilStopPosing; FSFloaterPoser::FSFloaterPoser(const LLSD& key) : LLFloater(key) { @@ -117,12 +117,11 @@ bool FSFloaterPoser::postBuild() mLimbRollSlider = getChild("limb_roll"); mLimbRollSlider->setCommitCallback([this](LLUICtrl *, const LLSD &) { onLimbYawPitchRollChanged(); }); - // find-and-binds mJointsTabs = getChild("joints_tabs"); mJointsTabs->setCommitCallback( [this](LLUICtrl*, const LLSD&) { - onJointSelect(); + onJointTabSelect(); setRotationChangeButtons(false, false, false); }); @@ -132,23 +131,23 @@ bool FSFloaterPoser::postBuild() mBodyJointsScrollList = getChild("body_joints_scroll"); mBodyJointsScrollList->setCommitOnSelectionChange(true); - mBodyJointsScrollList->setCommitCallback([this](LLUICtrl *, const LLSD &) { onJointSelect(); }); + mBodyJointsScrollList->setCommitCallback([this](LLUICtrl *, const LLSD &) { onJointTabSelect(); }); mFaceJointsScrollList = getChild("face_joints_scroll"); mFaceJointsScrollList->setCommitOnSelectionChange(true); - mFaceJointsScrollList->setCommitCallback([this](LLUICtrl *, const LLSD &) { onJointSelect(); }); + mFaceJointsScrollList->setCommitCallback([this](LLUICtrl *, const LLSD &) { onJointTabSelect(); }); mHandJointsScrollList = getChild("hand_joints_scroll"); mHandJointsScrollList->setCommitOnSelectionChange(true); - mHandJointsScrollList->setCommitCallback([this](LLUICtrl *, const LLSD &) { onJointSelect(); }); + mHandJointsScrollList->setCommitCallback([this](LLUICtrl *, const LLSD &) { onJointTabSelect(); }); mMiscJointsScrollList = getChild("misc_joints_scroll"); mMiscJointsScrollList->setCommitOnSelectionChange(true); - mMiscJointsScrollList->setCommitCallback([this](LLUICtrl *, const LLSD &) { onJointSelect(); }); + mMiscJointsScrollList->setCommitCallback([this](LLUICtrl *, const LLSD &) { onJointTabSelect(); }); mCollisionVolumesScrollList = getChild("collision_volumes_scroll"); mCollisionVolumesScrollList->setCommitOnSelectionChange(true); - mCollisionVolumesScrollList->setCommitCallback([this](LLUICtrl *, const LLSD &) { onJointSelect(); }); + mCollisionVolumesScrollList->setCommitCallback([this](LLUICtrl *, const LLSD &) { onJointTabSelect(); }); mEntireAvJointScroll = getChild("entireAv_joint_scroll"); @@ -197,8 +196,6 @@ bool FSFloaterPoser::postBuild() mToggleDeltaModeBtn = getChild("delta_mode_toggle"); mRedoChangeBtn = getChild("button_redo_change"); mSetToTposeButton = getChild("set_t_pose_button"); - mRecaptureJointsButton = getChild("button_RecaptureParts"); - mRecaptureJointsButton->setEnabled(!sDisableRecaptureUntilStopPosing); mJointsParentPnl = getChild("joints_parent_panel"); mAdvancedParentPnl = getChild("advanced_parent_panel"); @@ -218,7 +215,7 @@ void FSFloaterPoser::onOpen(const LLSD& key) { onAvatarsRefresh(); refreshJointScrollListMembers(); - onJointSelect(); + onJointTabSelect(); onOpenSetAdvancedPanel(); refreshPoseScroll(mHandPresetsScrollList, POSE_PRESETS_HANDS_SUBDIRECTORY); startPosingSelf(); @@ -346,27 +343,34 @@ bool FSFloaterPoser::savePoseToXml(LLVOAvatar* avatar, const std::string& poseFi std::string fullSavePath = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, POSE_SAVE_SUBDIRECTORY, poseFileName + POSE_INTERNAL_FORMAT_FILE_EXT); - bool savingDiff = !mPoserAnimator.posingStartedFromZeroRotations(avatar); + bool savingDiff = !mPoserAnimator.allBaseRotationsAreZero(avatar); LLSD record; - record["version"]["value"] = (S32)4; + record["version"]["value"] = (S32)5; record["startFromTeePose"]["value"] = !savingDiff; LLVector3 rotation, position, scale, zeroVector; + bool baseRotationIsZero; for (const FSPoserAnimator::FSPoserJoint& pj : mPoserAnimator.PoserJoints) { std::string bone_name = pj.jointName(); - if (!mPoserAnimator.tryGetJointSaveVectors(avatar, pj, &rotation, &position, &scale)) + bool posingThisJoint = mPoserAnimator.isPosingAvatarJoint(avatar, pj); + + record[bone_name] = bone_name; + record[bone_name]["enabled"] = posingThisJoint; + if (!posingThisJoint) + continue; + + if (!mPoserAnimator.tryGetJointSaveVectors(avatar, pj, &rotation, &position, &scale, &baseRotationIsZero)) continue; bool jointRotPosScaleAllZero = rotation == zeroVector && position == zeroVector && scale == zeroVector; - bool posingThisJoint = mPoserAnimator.isPosingAvatarJoint(avatar, pj); - if (savingDiff && (!posingThisJoint || jointRotPosScaleAllZero)) + + if (savingDiff && jointRotPosScaleAllZero) continue; - record[bone_name] = bone_name; - record[bone_name]["enabled"] = posingThisJoint; + record[bone_name]["jointBaseRotationIsZero"] = baseRotationIsZero; record[bone_name]["rotation"] = rotation.getValue(); record[bone_name]["position"] = position.getValue(); record[bone_name]["scale"] = scale.getValue(); @@ -413,7 +417,7 @@ void FSFloaterPoser::onClickToggleSelectedBoneEnabled() refreshRotationSliders(); refreshTrackpadCursor(); - refreshTextHighlightingOnAllScrollLists(); + refreshTextHighlightingOnJointScrollLists(); } void FSFloaterPoser::onClickFlipSelectedJoints() @@ -436,7 +440,6 @@ void FSFloaterPoser::onClickFlipSelectedJoints() if (!currentlyPosingJoint) continue; - // need to be posing opposite joint too, or don't flip auto oppositeJoint = mPoserAnimator.getPoserJointByName(item->mirrorJointName()); if (oppositeJoint) { @@ -477,9 +480,6 @@ void FSFloaterPoser::onClickFlipPose() void FSFloaterPoser::onClickRecaptureSelectedBones() { - if (sDisableRecaptureUntilStopPosing) - return; - auto selectedJoints = getUiSelectedPoserJoints(); if (selectedJoints.size() < 1) return; @@ -500,9 +500,10 @@ void FSFloaterPoser::onClickRecaptureSelectedBones() mPoserAnimator.recaptureJoint(avatar, *item, getJointTranslation(item->jointName()), getJointNegation(item->jointName())); } + setSavePosesButtonText(true); refreshRotationSliders(); refreshTrackpadCursor(); - refreshTextHighlightingOnAllScrollLists(); + refreshTextHighlightingOnJointScrollLists(); } void FSFloaterPoser::onClickBrowsePoseCache() @@ -516,10 +517,7 @@ void FSFloaterPoser::onClickBrowsePoseCache() void FSFloaterPoser::onPoseJointsReset() { - // This is a double-click function: it needs to run twice within some amount of time to complete. - auto timeIntervalSinceLastClick = std::chrono::system_clock::now() - mTimeLastClickedJointReset; - mTimeLastClickedJointReset = std::chrono::system_clock::now(); - if (timeIntervalSinceLastClick > mDoubleClickInterval) + if (notDoubleClicked()) return; LLVOAvatar* avatar = getUiSelectedAvatar(); @@ -577,15 +575,22 @@ void FSFloaterPoser::onPoseMenuAction(const LLSD& param) return; loadPoseFromXml(avatar, poseName, loadType); + onJointTabSelect(); refreshJointScrollListMembers(); + setSavePosesButtonText(mPoserAnimator.allBaseRotationsAreZero(avatar)); +} + +bool FSFloaterPoser::notDoubleClicked() +{ + auto timeIntervalSinceLastExecution = std::chrono::system_clock::now() - mTimeLastExecutedDoubleClickMethod; + mTimeLastExecutedDoubleClickMethod = std::chrono::system_clock::now(); + + return timeIntervalSinceLastExecution > mDoubleClickInterval; } void FSFloaterPoser::onClickLoadLeftHandPose() { - // This is a double-click function: it needs to run twice within some amount of time to complete. - auto timeIntervalSinceLastClick = std::chrono::system_clock::now() - mTimeLastClickedJointReset; - mTimeLastClickedJointReset = std::chrono::system_clock::now(); - if (timeIntervalSinceLastClick > mDoubleClickInterval) + if (notDoubleClicked()) return; onClickLoadHandPose(false); @@ -593,10 +598,7 @@ void FSFloaterPoser::onClickLoadLeftHandPose() void FSFloaterPoser::onClickLoadRightHandPose() { - // This is a double-click function: it needs to run twice within some amount of time to complete. - auto timeIntervalSinceLastClick = std::chrono::system_clock::now() - mTimeLastClickedJointReset; - mTimeLastClickedJointReset = std::chrono::system_clock::now(); - if (timeIntervalSinceLastClick > mDoubleClickInterval) + if (notDoubleClicked()) return; onClickLoadHandPose(true); @@ -656,7 +658,7 @@ void FSFloaterPoser::onClickLoadHandPose(bool isRightHand) continue; vec3.setValue(control_map["rotation"]); - mPoserAnimator.setJointRotation(avatar, poserJoint, vec3, NONE, SWAP_NOTHING, NEGATE_NOTHING); + mPoserAnimator.loadJointRotation(avatar, poserJoint, true, vec3); } } } @@ -688,10 +690,7 @@ bool FSFloaterPoser::poseFileStartsFromTeePose(const std::string& poseFileName) S32 lineCount = LLSDSerialize::fromXML(pose, infile); if (lineCount == LLSDParser::PARSE_FAILURE) - { - LL_WARNS("Posing") << "Failed to parse file: " << poseFileName << LL_ENDL; return startFromZeroRot; - } for (LLSD::map_const_iterator itr = pose.beginMap(); itr != pose.endMap(); ++itr) { @@ -738,8 +737,9 @@ void FSFloaterPoser::loadPoseFromXml(LLVOAvatar* avatar, const std::string& pose LLVector3 vec3; LLQuaternion quat; bool enabled; + bool setJointBaseRotationToZero; S32 version = 0; - bool startFromZeroRot = false; + bool startFromZeroRot = true; infile.open(fullPath); if (!infile.is_open()) @@ -770,12 +770,6 @@ void FSFloaterPoser::loadPoseFromXml(LLVOAvatar* avatar, const std::string& pose if (version > 3) loadPositionsAndScalesAsDeltas = true; - if (startFromZeroRot) // legacy saves will always start from T-Pose, for better or worse. - { - disableRecapture(); - mPoserAnimator.setAllAvatarStartingRotationsToZero(avatar); - } - for (LLSD::map_const_iterator itr = pose.beginMap(); itr != pose.endMap(); ++itr) { std::string const& name = itr->first; @@ -785,29 +779,34 @@ void FSFloaterPoser::loadPoseFromXml(LLVOAvatar* avatar, const std::string& pose if (!poserJoint) continue; - if (loadRotations && control_map.has("rotation")) + if (control_map.has("enabled")) { - vec3.setValue(control_map["rotation"]); - mPoserAnimator.loadJointRotation(avatar, poserJoint, vec3); + enabled = control_map["enabled"].asBoolean(); + mPoserAnimator.setPosingAvatarJoint(avatar, *poserJoint, enabled); } + if (control_map.has("jointBaseRotationIsZero")) + setJointBaseRotationToZero = control_map["jointBaseRotationIsZero"].asBoolean(); + else + setJointBaseRotationToZero = startFromZeroRot; + if (loadPositions && control_map.has("position")) { vec3.setValue(control_map["position"]); mPoserAnimator.loadJointPosition(avatar, poserJoint, loadPositionsAndScalesAsDeltas, vec3); } + if (loadRotations && control_map.has("rotation")) + { + vec3.setValue(control_map["rotation"]); + mPoserAnimator.loadJointRotation(avatar, poserJoint, setJointBaseRotationToZero, vec3); + } + if (loadScales && control_map.has("scale")) { vec3.setValue(control_map["scale"]); mPoserAnimator.loadJointScale(avatar, poserJoint, loadPositionsAndScalesAsDeltas, vec3); } - - if (control_map.has("enabled")) - { - enabled = control_map["enabled"].asBoolean(); - mPoserAnimator.setPosingAvatarJoint(avatar, *poserJoint, enabled); - } } } } @@ -815,8 +814,6 @@ void FSFloaterPoser::loadPoseFromXml(LLVOAvatar* avatar, const std::string& pose { LL_WARNS("Posing") << "Everything caught fire trying to load the pose: " << poseFileName << " exception: " << e.what() << LL_ENDL; } - - onJointSelect(); } void FSFloaterPoser::startPosingSelf() @@ -845,7 +842,6 @@ void FSFloaterPoser::stopPosingSelf() mPoserAnimator.stopPosingAvatar(avatar); onAvatarSelect(); - reEnableRecaptureIfAllowed(); } void FSFloaterPoser::onPoseStartStop() @@ -858,7 +854,6 @@ void FSFloaterPoser::onPoseStartStop() if (arePosingSelected) { mPoserAnimator.stopPosingAvatar(avatar); - reEnableRecaptureIfAllowed(); } else { @@ -912,6 +907,7 @@ void FSFloaterPoser::poseControlsEnable(bool enable) void FSFloaterPoser::refreshJointScrollListMembers() { + mEntireAvJointScroll->clearRows(); mBodyJointsScrollList->clearRows(); mFaceJointsScrollList->clearRows(); mHandJointsScrollList->clearRows(); @@ -974,16 +970,10 @@ void FSFloaterPoser::refreshJointScrollListMembers() } if (item) - { item->setUserdata((void*) &*poserJoint_iter); - LLVOAvatar* avatar = getUiSelectedAvatar(); - - if (mPoserAnimator.isPosingAvatarJoint(avatar, *poserJoint_iter)) - ((LLScrollListText *) item->getColumn(COL_NAME))->setFontStyle(LLFontGL::BOLD); - else - ((LLScrollListText *) item->getColumn(COL_NAME))->setFontStyle(LLFontGL::NORMAL); - } } + + refreshTextHighlightingOnJointScrollLists(); } void FSFloaterPoser::addHeaderRowToScrollList(const std::string& jointName, LLScrollListCtrl* bodyJointsScrollList) @@ -1002,8 +992,8 @@ LLSD FSFloaterPoser::createRowForJoint(const std::string& jointName, bool isHead return NULL; std::string headerValue = ""; - if (hasString("icon_category") && hasString("icon_bone")) - headerValue = isHeaderRow ? getString("icon_category") : getString("icon_bone"); + if (isHeaderRow && hasString("icon_category")) + headerValue = getString("icon_category"); std::string jointValue = jointName; std::string parameterName = (isHeaderRow ? XML_LIST_HEADER_STRING_PREFIX : XML_LIST_TITLE_STRING_PREFIX) + jointName; @@ -1151,25 +1141,21 @@ void FSFloaterPoser::onUndoLastScale() void FSFloaterPoser::onSetAvatarToTpose() { - auto timeIntervalSinceLastClick = std::chrono::system_clock::now() - mTimeLastClickedJointReset; - mTimeLastClickedJointReset = std::chrono::system_clock::now(); - if (timeIntervalSinceLastClick > mDoubleClickInterval) + if (notDoubleClicked()) return; LLVOAvatar* avatar = getUiSelectedAvatar(); if (!avatar) return; - disableRecapture(); + setSavePosesButtonText(false); mPoserAnimator.setAllAvatarStartingRotationsToZero(avatar); + refreshTextHighlightingOnJointScrollLists(); } void FSFloaterPoser::onResetPosition() { - // This is a double-click function: it needs to run twice within some amount of time to complete. - auto timeIntervalSinceLastClick = std::chrono::system_clock::now() - mTimeLastClickedJointReset; - mTimeLastClickedJointReset = std::chrono::system_clock::now(); - if (timeIntervalSinceLastClick > mDoubleClickInterval) + if (notDoubleClicked()) return; LLVOAvatar* avatar = getUiSelectedAvatar(); @@ -1196,10 +1182,7 @@ void FSFloaterPoser::onResetPosition() void FSFloaterPoser::onResetScale() { - // This is a double-click function: it needs to run twice within some amount of time to complete. - auto timeIntervalSinceLastClick = std::chrono::system_clock::now() - mTimeLastClickedJointReset; - mTimeLastClickedJointReset = std::chrono::system_clock::now(); - if (timeIntervalSinceLastClick > mDoubleClickInterval) + if (notDoubleClicked()) return; LLVOAvatar* avatar = getUiSelectedAvatar(); @@ -1346,7 +1329,7 @@ void FSFloaterPoser::onToggleAdvancedPanel() return; reshape(poserFloaterWidth, poserFloaterHeight); - onJointSelect(); + onJointTabSelect(); } std::vector FSFloaterPoser::getUiSelectedPoserJoints() const @@ -1415,17 +1398,13 @@ std::vector FSFloaterPoser::getUiSelectedPoserJo E_BoneDeflectionStyles FSFloaterPoser::getUiSelectedBoneDeflectionStyle() const { if (mToggleMirrorRotationBtn->getValue().asBoolean()) - { return MIRROR; - } + if (mToggleSympatheticRotationBtn->getValue().asBoolean()) - { return SYMPATHETIC; - } + if (mToggleDeltaModeBtn->getValue().asBoolean()) - { return DELTAMODE; - } return NONE; } @@ -1554,7 +1533,6 @@ void FSFloaterPoser::onLimbTrackballChanged() yaw *= trackPadSensitivity; pitch *= trackPadSensitivity; - // if the trackpad is in 'infinite scroll' mode, it can produce normalized-values outside the range of the sliders; this wraps them to by the slider full-scale yaw = unWrapScale(yaw) * NormalTrackpadRangeInRads; pitch = unWrapScale(pitch) * NormalTrackpadRangeInRads; roll = unWrapScale(roll) * NormalTrackpadRangeInRads; @@ -1734,18 +1712,33 @@ void FSFloaterPoser::setSelectedJointsRotation(F32 yawInRadians, F32 pitchInRadi if (!mPoserAnimator.isPosingAvatar(avatar)) return; - E_BoneDeflectionStyles defl = getUiSelectedBoneDeflectionStyle(); - LLVector3 vec3 = LLVector3(yawInRadians, pitchInRadians, rollInRadians); + E_BoneDeflectionStyles defl = getUiSelectedBoneDeflectionStyle(); + LLVector3 vec3 = LLVector3(yawInRadians, pitchInRadians, rollInRadians); + auto selectedJoints = getUiSelectedPoserJoints(); + bool savingToExternal = getWhetherToResetBaseRotationOnEdit(); - for (auto item : getUiSelectedPoserJoints()) + for (auto item : selectedJoints) { bool currentlyPosingJoint = mPoserAnimator.isPosingAvatarJoint(avatar, *item); if (!currentlyPosingJoint) continue; + auto oppositeJoint = mPoserAnimator.getPoserJointByName(item->mirrorJointName()); + if (oppositeJoint) + { + bool oppositeJointAlsoSelectedOnUi = + std::find(selectedJoints.begin(), selectedJoints.end(), oppositeJoint) != selectedJoints.end(); + + if (oppositeJointAlsoSelectedOnUi && item->dontFlipOnMirror()) + continue; + } + mPoserAnimator.setJointRotation(avatar, item, vec3, defl, getJointTranslation(item->jointName()), - getJointNegation(item->jointName())); + getJointNegation(item->jointName()), savingToExternal); } + + if (savingToExternal) + refreshTextHighlightingOnJointScrollLists(); } void FSFloaterPoser::setSelectedJointsScale(F32 x, F32 y, F32 z) @@ -1785,7 +1778,7 @@ LLVector3 FSFloaterPoser::getRotationOfFirstSelectedJoint() const return rotation; rotation = mPoserAnimator.getJointRotation(avatar, *selectedJoints.front(), getJointTranslation(selectedJoints.front()->jointName()), - getJointNegation(selectedJoints.front()->jointName()), TARGETROTATION); + getJointNegation(selectedJoints.front()->jointName())); return rotation; } @@ -1826,7 +1819,7 @@ LLVector3 FSFloaterPoser::getScaleOfFirstSelectedJoint() const return scale; } -void FSFloaterPoser::onJointSelect() +void FSFloaterPoser::onJointTabSelect() { refreshAvatarPositionSliders(); refreshRotationSliders(); @@ -1903,8 +1896,9 @@ void FSFloaterPoser::onAvatarSelect() mStartStopPosingBtn->setValue(arePosingSelected); mSetToTposeButton->setEnabled(arePosingSelected); poseControlsEnable(arePosingSelected); - refreshTextHighlightingOnAllScrollLists(); - onJointSelect(); + refreshTextHighlightingOnAvatarScrollList(); + refreshTextHighlightingOnJointScrollLists(); + onJointTabSelect(); setPoseSaveFileTextBoxToUiSelectedAvatarSaveFileName(); } @@ -2038,10 +2032,10 @@ void FSFloaterPoser::onAvatarsRefresh() } mAvatarSelectionScrollList->updateLayout(); - refreshTextHighlightingOnAllScrollLists(); + refreshTextHighlightingOnAvatarScrollList(); } -void FSFloaterPoser::refreshTextHighlightingOnAllScrollLists() +void FSFloaterPoser::refreshTextHighlightingOnAvatarScrollList() { for (auto listItem : mAvatarSelectionScrollList->getAllData()) { @@ -2057,8 +2051,12 @@ void FSFloaterPoser::refreshTextHighlightingOnAllScrollLists() else ((LLScrollListText *) listItem->getColumn(COL_NAME))->setFontStyle(LLFontGL::NORMAL); } - +} + +void FSFloaterPoser::refreshTextHighlightingOnJointScrollLists() +{ LLVOAvatar *avatar = getUiSelectedAvatar(); + addBoldToScrollList(mBodyJointsScrollList, avatar); addBoldToScrollList(mFaceJointsScrollList, avatar); addBoldToScrollList(mHandJointsScrollList, avatar); @@ -2066,21 +2064,9 @@ void FSFloaterPoser::refreshTextHighlightingOnAllScrollLists() addBoldToScrollList(mCollisionVolumesScrollList, avatar); } -void FSFloaterPoser::disableRecapture() +void FSFloaterPoser::setSavePosesButtonText(bool setAsSaveDiff) { - mRecaptureJointsButton->setEnabled(false); - mSavePosesBtn->setLabel("Save Pose"); - sDisableRecaptureUntilStopPosing = true; -} - -void FSFloaterPoser::reEnableRecaptureIfAllowed() -{ - if (posingAnyoneOnScrollList()) - return; - - mRecaptureJointsButton->setEnabled(true); - mSavePosesBtn->setLabel("Save Diff"); - sDisableRecaptureUntilStopPosing = false; + setAsSaveDiff ? mSavePosesBtn->setLabel("Save Diff") : mSavePosesBtn->setLabel("Save Pose"); } bool FSFloaterPoser::posingAnyoneOnScrollList() @@ -2109,15 +2095,31 @@ void FSFloaterPoser::addBoldToScrollList(LLScrollListCtrl* list, LLVOAvatar* ava if (!list) return; + std::string iconValue = ""; + bool considerExternalFormatSaving = getWhetherToResetBaseRotationOnEdit(); + + if (considerExternalFormatSaving && hasString("icon_rotation_is_own_work")) + iconValue = getString("icon_rotation_is_own_work"); + for (auto listItem : list->getAllData()) { FSPoserAnimator::FSPoserJoint *userData = static_cast(listItem->getUserdata()); - if (userData) + if (!userData) + continue; + + if (considerExternalFormatSaving) { - if (mPoserAnimator.isPosingAvatarJoint(avatar, *userData)) - ((LLScrollListText *) listItem->getColumn(COL_NAME))->setFontStyle(LLFontGL::BOLD); + if (mPoserAnimator.baseRotationIsZero(avatar, *userData)) + ((LLScrollListText*) listItem->getColumn(COL_ICON))->setValue(iconValue); else - ((LLScrollListText *) listItem->getColumn(COL_NAME))->setFontStyle(LLFontGL::NORMAL); + ((LLScrollListText*) listItem->getColumn(COL_ICON))->setValue(""); } + + if (mPoserAnimator.isPosingAvatarJoint(avatar, *userData)) + ((LLScrollListText *) listItem->getColumn(COL_NAME))->setFontStyle(LLFontGL::BOLD); + else + ((LLScrollListText *) listItem->getColumn(COL_NAME))->setFontStyle(LLFontGL::NORMAL); } } + +bool FSFloaterPoser::getWhetherToResetBaseRotationOnEdit() { return gSavedSettings.getBOOL(POSER_RESETBASEROTONEDIT_SAVE_KEY); } diff --git a/indra/newview/fsfloaterposer.h b/indra/newview/fsfloaterposer.h index 7f8cfa2a93..ab20071128 100644 --- a/indra/newview/fsfloaterposer.h +++ b/indra/newview/fsfloaterposer.h @@ -81,8 +81,6 @@ class FSFloaterPoser : public LLFloater void onOpen(const LLSD& key) override; void onClose(bool app_quitting) override; - static bool sDisableRecaptureUntilStopPosing; - /// /// Refreshes the supplied pose list from the supplued subdirectory. /// @@ -209,7 +207,7 @@ class FSFloaterPoser : public LLFloater // UI Event Handlers: void onAvatarsRefresh(); void onAvatarSelect(); - void onJointSelect(); + void onJointTabSelect(); void onToggleAdvancedPanel(); void onToggleMirrorChange(); void onToggleSympatheticChange(); @@ -294,19 +292,20 @@ class FSFloaterPoser : public LLFloater S32 getJointNegation(const std::string& jointName) const; /// - /// Refreshes the text on all scroll lists based on their state. + /// Refreshes the text on the avatars scroll list based on their state. /// - void refreshTextHighlightingOnAllScrollLists(); + void refreshTextHighlightingOnAvatarScrollList(); /// - /// Disables recapturing joint traits. + /// Refreshes the text on all joints scroll lists based on their state. /// - void disableRecapture(); + void refreshTextHighlightingOnJointScrollLists(); /// - /// Recapture is be disabled if user is making their own pose (starting from a T-Pose). + /// Sets the text of the save pose button. /// - void reEnableRecaptureIfAllowed(); + /// Whether to indicate a diff will be saved, instead of a pose. + void setSavePosesButtonText(bool setAsSaveDiff); /// /// Gets whether any avatar know by the UI is being posed. @@ -320,14 +319,28 @@ class FSFloaterPoser : public LLFloater /// The avatar to whom the list is relevant. void addBoldToScrollList(LLScrollListCtrl* list, LLVOAvatar* avatar); + /// + /// Determines if the user has run this method twice within mDoubleClickInterval. + /// + /// true if this method has executed since mDoubleClickInterval seconds ago, otherwise false. + bool notDoubleClicked(); + + /// + /// Gets whether the user wishes to reset the base-rotation to zero when they start editing a joint. + /// + /// + /// 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. + /// + bool getWhetherToResetBaseRotationOnEdit(); + /// /// The time when the last click of a button was made. /// Utilized for controls needing a 'double click do' function. /// - std::chrono::system_clock::time_point mTimeLastClickedJointReset = std::chrono::system_clock::now(); + std::chrono::system_clock::time_point mTimeLastExecutedDoubleClickMethod = std::chrono::system_clock::now(); /// - /// The constant time interval, in seconds, a user must click twice within to successfully double-click a button. + /// The constant time interval, in seconds, a user must execute the notDoubleClicked twice to successfully 'double-click' a button. /// std::chrono::duration const mDoubleClickInterval = std::chrono::duration(0.3); @@ -336,6 +349,10 @@ class FSFloaterPoser : public LLFloater /// /// The scale value from the trackball. /// A value appropriate for fitting a slider. + /// + /// If the trackpad is in 'infinite scroll' mode, it can produce normalized-values outside the range of the sliders. + /// This method ensures whatever value the trackpad produces, they work with the sliders. + /// static F32 unWrapScale(F32 scale); FSVirtualTrackpad* mAvatarTrackball{ nullptr }; @@ -382,7 +399,6 @@ class FSFloaterPoser : public LLFloater LLButton* mToggleDeltaModeBtn{ nullptr }; LLButton* mRedoChangeBtn{ nullptr }; LLButton* mSetToTposeButton{ nullptr }; - LLButton* mRecaptureJointsButton{ nullptr }; LLLineEditor* mPoseSaveNameEditor{ nullptr }; diff --git a/indra/newview/fsjointpose.cpp b/indra/newview/fsjointpose.cpp new file mode 100644 index 0000000000..ec3abb0b7f --- /dev/null +++ b/indra/newview/fsjointpose.cpp @@ -0,0 +1,232 @@ +/** + * @file fsjointpose.cpp + * @brief Container for the pose of a joint. + * + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ + * Phoenix Firestorm Viewer Source Code + * Copyright (c) 2024 Angeldark Raymaker @ Second Life + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include +#include +#include "fsposingmotion.h" +#include "llcharacter.h" + +constexpr size_t MaximumUndoQueueLength = 20; + +/// +/// The constant time interval, in seconds, specifying whether an 'undo' value should be added. +/// +constexpr std::chrono::duration UndoUpdateInterval = std::chrono::duration(0.3); + +FSJointPose::FSJointPose(LLJoint* joint, U32 usage, bool isCollisionVolume) +{ + mJointState = new LLJointState; + mJointState->setJoint(joint); + mJointState->setUsage(usage); + + mJointName = joint->getName(); + mIsCollisionVolume = isCollisionVolume; + + mRotation = FSJointRotation(joint->getRotation()); + mBeginningPosition = joint->getPosition(); + mBeginningScale = joint->getScale(); +} + +void FSJointPose::setPositionDelta(const LLVector3& pos) +{ + addToUndo(mPositionDelta, &mUndonePositionIndex, &mLastSetPositionDeltas, &mTimeLastUpdatedPosition); + mPositionDelta.set(pos); +} + +void FSJointPose::setRotationDelta(const LLQuaternion& rot) +{ + addToUndo(mRotation, &mUndoneRotationIndex, &mLastSetRotationDeltas, &mTimeLastUpdatedRotation); + mRotation = FSJointRotation(mRotation.baseRotation, rot); +} + +void FSJointPose::setScaleDelta(const LLVector3& scale) +{ + addToUndo(mScaleDelta, &mUndoneScaleIndex, &mLastSetScaleDeltas, &mTimeLastUpdatedScale); + mScaleDelta.set(scale); +} + +void FSJointPose::undoLastPositionChange() +{ + mPositionDelta.set(undoLastChange(mPositionDelta, &mUndonePositionIndex, &mLastSetPositionDeltas)); +} + +void FSJointPose::undoLastRotationChange() +{ + mRotation.set(undoLastChange(mRotation, &mUndoneRotationIndex, &mLastSetRotationDeltas)); +} + +void FSJointPose::undoLastScaleChange() { mScaleDelta.set(undoLastChange(mScaleDelta, &mUndoneScaleIndex, &mLastSetScaleDeltas)); } + +void FSJointPose::redoLastPositionChange() +{ + mPositionDelta.set(redoLastChange(mPositionDelta, &mUndonePositionIndex, &mLastSetPositionDeltas)); +} + +void FSJointPose::redoLastRotationChange() +{ + mRotation.set(redoLastChange(mRotation, &mUndoneRotationIndex, &mLastSetRotationDeltas)); +} + +void FSJointPose::redoLastScaleChange() { mScaleDelta.set(redoLastChange(mScaleDelta, &mUndoneScaleIndex, &mLastSetScaleDeltas)); } + +template +inline void FSJointPose::addToUndo(T delta, size_t* undoIndex, std::deque* dequeue, + std::chrono::system_clock::time_point* timeLastUpdated) +{ + auto timeIntervalSinceLastChange = std::chrono::system_clock::now() - *timeLastUpdated; + *timeLastUpdated = std::chrono::system_clock::now(); + + if (timeIntervalSinceLastChange < UndoUpdateInterval) + return; + + if (*undoIndex > 0) + { + for (size_t i = 0; i < *undoIndex; i++) + dequeue->pop_front(); + + *undoIndex = 0; + } + + dequeue->push_front(delta); + + while (dequeue->size() > MaximumUndoQueueLength) + dequeue->pop_back(); +} + +template T FSJointPose::undoLastChange(T thingToSet, size_t* undoIndex, std::deque* dequeue) +{ + if (dequeue->empty()) + return thingToSet; + + if (*undoIndex == 0) + dequeue->push_front(thingToSet); + + *undoIndex += 1; + *undoIndex = llclamp(*undoIndex, 0, dequeue->size() - 1); + + return dequeue->at(*undoIndex); +} + +template T FSJointPose::redoLastChange(T thingToSet, size_t* undoIndex, std::deque* dequeue) +{ + if (dequeue->empty()) + return thingToSet; + if (*undoIndex == 0) + return thingToSet; + + *undoIndex -= 1; + *undoIndex = llclamp(*undoIndex, 0, dequeue->size() - 1); + T result = dequeue->at(*undoIndex); + if (*undoIndex == 0) + dequeue->pop_front(); + + return result; +} + +void FSJointPose::recaptureJoint() +{ + if (mIsCollisionVolume) + return; + + LLJoint* joint = mJointState->getJoint(); + if (!joint) + return; + + addToUndo(mRotation, &mUndoneRotationIndex, &mLastSetRotationDeltas, &mTimeLastUpdatedRotation); + mRotation = FSJointRotation(joint->getRotation()); +} + +void FSJointPose::swapRotationWith(FSJointPose* oppositeJoint) +{ + if (!oppositeJoint) + return; + if (mIsCollisionVolume) + return; + + LLJoint* joint = mJointState->getJoint(); + if (!joint) + return; + + auto tempRot = FSJointRotation(mRotation); + mRotation = FSJointRotation(oppositeJoint->mRotation); + oppositeJoint->mRotation = tempRot; +} + +void FSJointPose::revertJointScale() +{ + LLJoint* joint = mJointState->getJoint(); + if (!joint) + return; + + joint->setScale(mBeginningScale); +} + +void FSJointPose::revertJointPosition() +{ + LLJoint* joint = mJointState->getJoint(); + if (!joint) + return; + + joint->setPosition(mBeginningPosition); +} + +void FSJointPose::revertCollisionVolume() +{ + if (!mIsCollisionVolume) + return; + + LLJoint* joint = mJointState->getJoint(); + if (!joint) + return; + + joint->setRotation(mRotation.baseRotation); + joint->setPosition(mBeginningPosition); + joint->setScale(mBeginningScale); +} + +void FSJointPose::reflectRotation() +{ + if (mIsCollisionVolume) + return; + + mRotation.reflectRotation(); +} + +void FSJointPose::zeroBaseRotation() +{ + if (mIsCollisionVolume) + return; + + mRotation.baseRotation = LLQuaternion::DEFAULT; +} + +bool FSJointPose::isBaseRotationZero() const +{ + if (mIsCollisionVolume) + return true; + + return mRotation.baseRotation == LLQuaternion::DEFAULT; +} diff --git a/indra/newview/fsjointpose.h b/indra/newview/fsjointpose.h new file mode 100644 index 0000000000..5249451207 --- /dev/null +++ b/indra/newview/fsjointpose.h @@ -0,0 +1,254 @@ +/** + * @file fsjointpose.h + * @brief Container for the pose of a joint. + * + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ + * Phoenix Firestorm Viewer Source Code + * Copyright (c) 2024 Angeldark Raymaker @ Second Life + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef FS_JOINTPPOSE_H +#define FS_JOINTPPOSE_H + +//----------------------------------------------------------------------------- +// Header files +//----------------------------------------------------------------------------- +#include "llmotion.h" + +//----------------------------------------------------------------------------- +// class FSJointPose +//----------------------------------------------------------------------------- +class FSJointPose +{ + public: + /// + /// A class encapsulating the positions/rotations for a joint. + /// + /// The joint this joint pose represents. + /// The default usage the joint should have in a pose. + /// Whether the supplied joint is a collision volume. + FSJointPose(LLJoint* joint, U32 usage, bool isCollisionVolume = false); + + /// + /// Gets the name of the joint. + /// + std::string jointName() const { return mJointName; } + + /// + /// Gets whether this represents a collision volume. + /// + /// true if the joint is a collision volume, otherwise false. + bool isCollisionVolume() const { return mIsCollisionVolume; } + + /// + /// Gets the position change the animator wishes the joint to have. + /// + LLVector3 getPositionDelta() const { return mPositionDelta; } + + /// + /// Sets the position the animator wishes the joint to be in. + /// + void setPositionDelta(const LLVector3& pos); + + /// + /// Undoes the last position set, if any. + /// + void undoLastPositionChange(); + + /// + /// Undoes the last position set, if any. + /// + void redoLastPositionChange(); + + /// + /// Gets the rotation the animator wishes the joint to be in. + /// + LLQuaternion getRotationDelta() const { return mRotation.deltaRotation; } + + /// + /// Sets the rotation the animator wishes the joint to be in. + /// + void setRotationDelta(const LLQuaternion& rot); + + /// + /// Reflects the base and delta rotation of the represented joint left-right. + /// + void reflectRotation(); + + /// + /// Sets the base rotation of the represented joint to zero. + /// + void zeroBaseRotation(); + + /// + /// Queries whether the represented joint is zero. + /// + /// True if the represented joint is zero, otherwise false. + bool isBaseRotationZero() const; + + /// + /// Undoes the last rotation set, if any. + /// Ordinarily the queue does not contain the current rotation, because we rely on time to add, and not button-up. + /// When we undo, if we are at the top of the queue, we need to add the current rotation so we can redo back to it. + /// Thus when we start undoing, mUndoneRotationIndex points at the current rotation. + /// + void undoLastRotationChange(); + + /// + /// Redoes the last rotation set, if any. + /// + void redoLastRotationChange(); + + /// + /// Gets whether a redo of this joints rotation may be performed. + /// + /// true if the joint can have a redo applied, otherwise false. + bool canRedoRotation() const { return mUndoneRotationIndex > 0; } + + /// + /// Gets the scale the animator wishes the joint to have. + /// + LLVector3 getScaleDelta() const { return mScaleDelta; } + + /// + /// Sets the scale the animator wishes the joint to have. + /// + void setScaleDelta(const LLVector3& scale); + + /// + /// Undoes the last scale set, if any. + /// + void undoLastScaleChange(); + + /// + /// Redoes the last scale set, if any. + /// + void redoLastScaleChange(); + + /// + /// Exchanges the rotations between two joints. + /// + void swapRotationWith(FSJointPose* oppositeJoint); + + /// + /// Resets the beginning properties of the joint this represents. + /// + void recaptureJoint(); + + /// + /// Restores the joint represented by this to the scale it had when this motion started. + /// + void revertJointScale(); + + /// + /// Restores the joint represented by this to the position it had when this motion started. + /// + void revertJointPosition(); + + /// + /// Collision Volumes do not 'reset' their position/rotation when the animation stops. + /// This requires special treatment to revert changes we've made this animation session. + /// + void revertCollisionVolume(); + + LLVector3 getTargetPosition() const { return mPositionDelta + mBeginningPosition; } + LLQuaternion getTargetRotation() const { return mRotation.getTargetRotation(); } + LLVector3 getTargetScale() const { return mScaleDelta + mBeginningScale; } + + /// + /// Gets the pointer to the jointstate for the joint this represents. + /// + LLPointer getJointState() const { return mJointState; } + + /// + /// A class wrapping base and delta rotation, attempting to keep baseRotation as secret as possible. + /// Among other things, facilitates easy undo/redo through the joint-recapture process. + /// + class FSJointRotation + { + public: + FSJointRotation(LLQuaternion base) { baseRotation.set(base); } + + FSJointRotation(LLQuaternion base, LLQuaternion delta) + { + baseRotation.set(base); + deltaRotation.set(delta); + } + + FSJointRotation() = default; + + LLQuaternion baseRotation; + LLQuaternion deltaRotation; + LLQuaternion getTargetRotation() const { return deltaRotation * baseRotation; } + + void reflectRotation() + { + baseRotation.mQ[VX] *= -1; + baseRotation.mQ[VZ] *= -1; + deltaRotation.mQ[VX] *= -1; + deltaRotation.mQ[VZ] *= -1; + } + + void set(const FSJointRotation& jRot) + { + baseRotation.set(jRot.baseRotation); + deltaRotation.set(jRot.deltaRotation); + } + }; + +private: + std::string mJointName = ""; // expected to be a match to LLJoint.getName() for a joint implementation. + LLPointer mJointState{ nullptr }; + + /// + /// Collision Volumes require special treatment when we stop animating an avatar, as they do not revert to their original state + /// natively. + /// + bool mIsCollisionVolume{ false }; + + FSJointRotation mRotation; + std::deque mLastSetRotationDeltas; + size_t mUndoneRotationIndex = 0; + std::chrono::system_clock::time_point mTimeLastUpdatedRotation = std::chrono::system_clock::now(); + + LLVector3 mPositionDelta; + LLVector3 mBeginningPosition; + std::deque mLastSetPositionDeltas; + size_t mUndonePositionIndex = 0; + std::chrono::system_clock::time_point mTimeLastUpdatedPosition = std::chrono::system_clock::now(); + + /// + /// Joint scales require special treatment, as they do not revert when we stop animating an avatar. + /// + LLVector3 mScaleDelta; + LLVector3 mBeginningScale; + std::deque mLastSetScaleDeltas; + size_t mUndoneScaleIndex = 0; + std::chrono::system_clock::time_point mTimeLastUpdatedScale = std::chrono::system_clock::now(); + + template + void addToUndo(T delta, size_t* undoIndex, std::deque* dequeue, std::chrono::system_clock::time_point* timeLastUpdated); + + template T undoLastChange(T thingToSet, size_t* undoIndex, std::deque* dequeue); + + template T redoLastChange(T thingToSet, size_t* undoIndex, std::deque* dequeue); +}; + +#endif // FS_JOINTPPOSE_H diff --git a/indra/newview/fsposeranimator.cpp b/indra/newview/fsposeranimator.cpp index 4f70b19a2f..13ee1990bb 100644 --- a/indra/newview/fsposeranimator.cpp +++ b/indra/newview/fsposeranimator.cpp @@ -45,7 +45,7 @@ bool FSPoserAnimator::isPosingAvatarJoint(LLVOAvatar* avatar, const FSPoserJoint if (posingMotion->isStopped()) return false; - FSPosingMotion::FSJointPose* jointPose = posingMotion->getJointPoseByJointName(joint.jointName()); + FSJointPose* jointPose = posingMotion->getJointPoseByJointName(joint.jointName()); if (!jointPose) return false; @@ -68,7 +68,7 @@ void FSPoserAnimator::setPosingAvatarJoint(LLVOAvatar* avatar, const FSPoserJoin if (posingMotion->isStopped()) return; - FSPosingMotion::FSJointPose* jointPose = posingMotion->getJointPoseByJointName(joint.jointName()); + FSJointPose* jointPose = posingMotion->getJointPoseByJointName(joint.jointName()); if (!jointPose) return; @@ -90,12 +90,12 @@ void FSPoserAnimator::resetAvatarJoint(LLVOAvatar* avatar, const FSPoserJoint& j if (posingMotion->isStopped()) return; - FSPosingMotion::FSJointPose* jointPose = posingMotion->getJointPoseByJointName(joint.jointName()); + FSJointPose* jointPose = posingMotion->getJointPoseByJointName(joint.jointName()); if (!jointPose) return; - jointPose->setTargetPosition(jointPose->getBeginningPosition()); - jointPose->setTargetRotation(jointPose->getBeginningRotation()); + jointPose->setPositionDelta(LLVector3()); + jointPose->setRotationDelta(LLQuaternion()); } void FSPoserAnimator::undoLastJointRotation(LLVOAvatar* avatar, const FSPoserJoint& joint, E_BoneDeflectionStyles style) @@ -110,20 +110,20 @@ void FSPoserAnimator::undoLastJointRotation(LLVOAvatar* avatar, const FSPoserJoi if (posingMotion->isStopped()) return; - FSPosingMotion::FSJointPose* jointPose = posingMotion->getJointPoseByJointName(joint.jointName()); + FSJointPose* jointPose = posingMotion->getJointPoseByJointName(joint.jointName()); if (!jointPose) return; - jointPose->undoLastRotationSet(); + jointPose->undoLastRotationChange(); if (style == NONE) return; - FSPosingMotion::FSJointPose* oppositeJointPose = posingMotion->getJointPoseByJointName(joint.mirrorJointName()); + FSJointPose* oppositeJointPose = posingMotion->getJointPoseByJointName(joint.mirrorJointName()); if (!oppositeJointPose) return; - oppositeJointPose->undoLastRotationSet(); + oppositeJointPose->undoLastRotationChange(); } void FSPoserAnimator::undoLastJointPosition(LLVOAvatar* avatar, const FSPoserJoint& joint, E_BoneDeflectionStyles style) @@ -138,20 +138,20 @@ void FSPoserAnimator::undoLastJointPosition(LLVOAvatar* avatar, const FSPoserJoi if (posingMotion->isStopped()) return; - FSPosingMotion::FSJointPose* jointPose = posingMotion->getJointPoseByJointName(joint.jointName()); + FSJointPose* jointPose = posingMotion->getJointPoseByJointName(joint.jointName()); if (!jointPose) return; - jointPose->undoLastPositionSet(); + jointPose->undoLastPositionChange(); if (style == NONE) return; - FSPosingMotion::FSJointPose* oppositeJointPose = posingMotion->getJointPoseByJointName(joint.mirrorJointName()); + FSJointPose* oppositeJointPose = posingMotion->getJointPoseByJointName(joint.mirrorJointName()); if (!oppositeJointPose) return; - oppositeJointPose->undoLastPositionSet(); + oppositeJointPose->undoLastPositionChange(); } void FSPoserAnimator::undoLastJointScale(LLVOAvatar* avatar, const FSPoserJoint& joint, E_BoneDeflectionStyles style) @@ -166,20 +166,20 @@ void FSPoserAnimator::undoLastJointScale(LLVOAvatar* avatar, const FSPoserJoint& if (posingMotion->isStopped()) return; - FSPosingMotion::FSJointPose* jointPose = posingMotion->getJointPoseByJointName(joint.jointName()); + FSJointPose* jointPose = posingMotion->getJointPoseByJointName(joint.jointName()); if (!jointPose) return; - jointPose->undoLastScaleSet(); + jointPose->undoLastScaleChange(); if (style == NONE) return; - FSPosingMotion::FSJointPose* oppositeJointPose = posingMotion->getJointPoseByJointName(joint.mirrorJointName()); + FSJointPose* oppositeJointPose = posingMotion->getJointPoseByJointName(joint.mirrorJointName()); if (!oppositeJointPose) return; - oppositeJointPose->undoLastScaleSet(); + oppositeJointPose->undoLastScaleChange(); } void FSPoserAnimator::resetJointPosition(LLVOAvatar* avatar, const FSPoserJoint& joint, E_BoneDeflectionStyles style) @@ -194,20 +194,20 @@ void FSPoserAnimator::resetJointPosition(LLVOAvatar* avatar, const FSPoserJoint& if (posingMotion->isStopped()) return; - FSPosingMotion::FSJointPose* jointPose = posingMotion->getJointPoseByJointName(joint.jointName()); + FSJointPose* jointPose = posingMotion->getJointPoseByJointName(joint.jointName()); if (!jointPose) return; - jointPose->setTargetPosition(jointPose->getBeginningPosition()); + jointPose->setPositionDelta(LLVector3()); if (style == NONE) return; - FSPosingMotion::FSJointPose* oppositeJointPose = posingMotion->getJointPoseByJointName(joint.mirrorJointName()); + FSJointPose* oppositeJointPose = posingMotion->getJointPoseByJointName(joint.mirrorJointName()); if (!oppositeJointPose) return; - oppositeJointPose->setTargetPosition(oppositeJointPose->getBeginningPosition()); + oppositeJointPose->setPositionDelta(LLVector3()); } void FSPoserAnimator::resetJointScale(LLVOAvatar* avatar, const FSPoserJoint& joint, E_BoneDeflectionStyles style) @@ -222,20 +222,20 @@ void FSPoserAnimator::resetJointScale(LLVOAvatar* avatar, const FSPoserJoint& jo if (posingMotion->isStopped()) return; - FSPosingMotion::FSJointPose* jointPose = posingMotion->getJointPoseByJointName(joint.jointName()); + FSJointPose* jointPose = posingMotion->getJointPoseByJointName(joint.jointName()); if (!jointPose) return; - jointPose->setTargetScale(jointPose->getBeginningScale()); + jointPose->setScaleDelta(LLVector3()); if (style == NONE) return; - FSPosingMotion::FSJointPose* oppositeJointPose = posingMotion->getJointPoseByJointName(joint.mirrorJointName()); + FSJointPose* oppositeJointPose = posingMotion->getJointPoseByJointName(joint.mirrorJointName()); if (!oppositeJointPose) return; - oppositeJointPose->setTargetScale(oppositeJointPose->getBeginningScale()); + oppositeJointPose->setScaleDelta(LLVector3()); } bool FSPoserAnimator::canRedoJointRotation(LLVOAvatar* avatar, const FSPoserJoint& joint) @@ -250,7 +250,7 @@ bool FSPoserAnimator::canRedoJointRotation(LLVOAvatar* avatar, const FSPoserJoin if (posingMotion->isStopped()) return false; - FSPosingMotion::FSJointPose* jointPose = posingMotion->getJointPoseByJointName(joint.jointName()); + FSJointPose* jointPose = posingMotion->getJointPoseByJointName(joint.jointName()); if (!jointPose) return false; @@ -269,20 +269,20 @@ void FSPoserAnimator::redoLastJointRotation(LLVOAvatar* avatar, const FSPoserJoi if (posingMotion->isStopped()) return; - FSPosingMotion::FSJointPose* jointPose = posingMotion->getJointPoseByJointName(joint.jointName()); + FSJointPose* jointPose = posingMotion->getJointPoseByJointName(joint.jointName()); if (!jointPose) return; - jointPose->redoLastRotationSet(); + jointPose->redoLastRotationChange(); if (style == NONE) return; - FSPosingMotion::FSJointPose* oppositeJointPose = posingMotion->getJointPoseByJointName(joint.mirrorJointName()); + FSJointPose* oppositeJointPose = posingMotion->getJointPoseByJointName(joint.mirrorJointName()); if (!oppositeJointPose) return; - oppositeJointPose->redoLastRotationSet(); + oppositeJointPose->redoLastRotationChange(); } void FSPoserAnimator::redoLastJointPosition(LLVOAvatar* avatar, const FSPoserJoint& joint, E_BoneDeflectionStyles style) @@ -297,20 +297,20 @@ void FSPoserAnimator::redoLastJointPosition(LLVOAvatar* avatar, const FSPoserJoi if (posingMotion->isStopped()) return; - FSPosingMotion::FSJointPose* jointPose = posingMotion->getJointPoseByJointName(joint.jointName()); + FSJointPose* jointPose = posingMotion->getJointPoseByJointName(joint.jointName()); if (!jointPose) return; - jointPose->redoLastPositionSet(); + jointPose->redoLastPositionChange(); if (style == NONE) return; - FSPosingMotion::FSJointPose* oppositeJointPose = posingMotion->getJointPoseByJointName(joint.mirrorJointName()); + FSJointPose* oppositeJointPose = posingMotion->getJointPoseByJointName(joint.mirrorJointName()); if (!oppositeJointPose) return; - oppositeJointPose->redoLastPositionSet(); + oppositeJointPose->redoLastPositionChange(); } void FSPoserAnimator::redoLastJointScale(LLVOAvatar* avatar, const FSPoserJoint& joint, E_BoneDeflectionStyles style) @@ -325,23 +325,23 @@ void FSPoserAnimator::redoLastJointScale(LLVOAvatar* avatar, const FSPoserJoint& if (posingMotion->isStopped()) return; - FSPosingMotion::FSJointPose* jointPose = posingMotion->getJointPoseByJointName(joint.jointName()); + FSJointPose* jointPose = posingMotion->getJointPoseByJointName(joint.jointName()); if (!jointPose) return; - jointPose->redoLastScaleSet(); + jointPose->redoLastScaleChange(); if (style == NONE) return; - FSPosingMotion::FSJointPose* oppositeJointPose = posingMotion->getJointPoseByJointName(joint.mirrorJointName()); + FSJointPose* oppositeJointPose = posingMotion->getJointPoseByJointName(joint.mirrorJointName()); if (!oppositeJointPose) return; - oppositeJointPose->redoLastScaleSet(); + oppositeJointPose->redoLastScaleChange(); } -LLVector3 FSPoserAnimator::getJointPosition(LLVOAvatar* avatar, const FSPoserJoint& joint, bool forRecapture) const +LLVector3 FSPoserAnimator::getJointPosition(LLVOAvatar* avatar, const FSPoserJoint& joint) const { LLVector3 pos; if (!isAvatarSafeToUse(avatar)) @@ -351,16 +351,11 @@ LLVector3 FSPoserAnimator::getJointPosition(LLVOAvatar* avatar, const FSPoserJoi if (!posingMotion) return pos; - FSPosingMotion::FSJointPose* jointPose = posingMotion->getJointPoseByJointName(joint.jointName()); + FSJointPose* jointPose = posingMotion->getJointPoseByJointName(joint.jointName()); if (!jointPose) return pos; - if (forRecapture) - pos = jointPose->getCurrentPosition(); - else - pos = jointPose->getTargetPosition(); - - return pos; + return jointPose->getPositionDelta(); } void FSPoserAnimator::setJointPosition(LLVOAvatar* avatar, const FSPoserJoint* joint, const LLVector3& position, E_BoneDeflectionStyles style) @@ -378,33 +373,33 @@ void FSPoserAnimator::setJointPosition(LLVOAvatar* avatar, const FSPoserJoint* j if (!posingMotion) return; - FSPosingMotion::FSJointPose* jointPose = posingMotion->getJointPoseByJointName(jn); + FSJointPose* jointPose = posingMotion->getJointPoseByJointName(jn); if (!jointPose) return; if (style == NONE) { - jointPose->setTargetPosition(position); + jointPose->setPositionDelta(position); return; } - LLVector3 positionDelta = jointPose->getTargetPosition() - position; + LLVector3 positionDelta = jointPose->getPositionDelta() - position; - FSPosingMotion::FSJointPose* oppositeJointPose = posingMotion->getJointPoseByJointName(joint->mirrorJointName()); + FSJointPose* oppositeJointPose = posingMotion->getJointPoseByJointName(joint->mirrorJointName()); if (!oppositeJointPose) return; - LLVector3 oppositeJointPosition = oppositeJointPose->getTargetPosition(); + LLVector3 oppositeJointPosition = oppositeJointPose->getPositionDelta(); switch (style) { case SYMPATHETIC: - jointPose->setTargetPosition(position); - oppositeJointPose->setTargetPosition(oppositeJointPosition - positionDelta); + jointPose->setPositionDelta(position); + oppositeJointPose->setPositionDelta(oppositeJointPosition - positionDelta); break; case MIRROR: - jointPose->setTargetPosition(position); - oppositeJointPose->setTargetPosition(oppositeJointPosition + positionDelta); + jointPose->setPositionDelta(position); + oppositeJointPose->setPositionDelta(oppositeJointPosition + positionDelta); break; default: @@ -412,7 +407,23 @@ void FSPoserAnimator::setJointPosition(LLVOAvatar* avatar, const FSPoserJoint* j } } -bool FSPoserAnimator::posingStartedFromZeroRotations(LLVOAvatar* avatar) const +bool FSPoserAnimator::baseRotationIsZero(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->isBaseRotationZero(); +} + +bool FSPoserAnimator::allBaseRotationsAreZero(LLVOAvatar* avatar) const { if (!isAvatarSafeToUse(avatar)) return false; @@ -441,40 +452,23 @@ void FSPoserAnimator::setAllAvatarStartingRotationsToZero(LLVOAvatar* avatar) } void FSPoserAnimator::recaptureJoint(LLVOAvatar* avatar, const FSPoserJoint& joint, E_BoneAxisTranslation translation, S32 negation) -{ - LLVector3 newRotation = getJointRotation(avatar, joint, translation, negation, CURRENTROTATION); - LLVector3 newPosition = getJointPosition(avatar, joint, true); - LLVector3 newScale = getJointScale(avatar, joint, true); - - setPosingAvatarJoint(avatar, joint, true); - setStartingJointRotation(avatar, &joint, newRotation, translation, negation); - - // recapture of positions and scale does not reset starting values, since this this could result in unwanted residue deformation after posing stops. - setJointPosition(avatar, &joint, newPosition, NONE); - setJointScale(avatar, &joint, newScale, NONE); -} - -void FSPoserAnimator::setStartingJointRotation(LLVOAvatar* avatar, const FSPoserJoint* joint, const LLVector3& rotation, - E_BoneAxisTranslation translation, S32 negation) { if (!isAvatarSafeToUse(avatar)) return; - if (!joint) - return; FSPosingMotion* posingMotion = getPosingMotion(avatar); if (!posingMotion) return; - FSPosingMotion::FSJointPose* jointPose = posingMotion->getJointPoseByJointName(joint->jointName()); + FSJointPose* jointPose = posingMotion->getJointPoseByJointName(joint.jointName()); if (!jointPose) return; - LLQuaternion rot_quat = translateRotationToQuaternion(translation, negation, rotation); - jointPose->setJointStartRotations(rot_quat); + jointPose->recaptureJoint(); + setPosingAvatarJoint(avatar, joint, true); } -LLVector3 FSPoserAnimator::getJointRotation(LLVOAvatar* avatar, const FSPoserJoint& joint, E_BoneAxisTranslation translation, S32 negation, E_BoneRotationType rotType) const +LLVector3 FSPoserAnimator::getJointRotation(LLVOAvatar* avatar, const FSPoserJoint& joint, E_BoneAxisTranslation translation, S32 negation) const { LLVector3 vec3; if (!isAvatarSafeToUse(avatar)) @@ -484,28 +478,15 @@ LLVector3 FSPoserAnimator::getJointRotation(LLVOAvatar* avatar, const FSPoserJoi if (!posingMotion) return vec3; - FSPosingMotion::FSJointPose* jointPose = posingMotion->getJointPoseByJointName(joint.jointName()); + FSJointPose* jointPose = posingMotion->getJointPoseByJointName(joint.jointName()); if (!jointPose) return vec3; - - LLQuaternion rot; - switch (rotType) - { - case TARGETROTATION: - rot = jointPose->getTargetRotation(); - break; - - case CURRENTROTATION: - default: - rot = jointPose->getCurrentRotation(); - break; - } - return translateRotationFromQuaternion(translation, negation, rot); + 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) +void FSPoserAnimator::setJointRotation(LLVOAvatar* avatar, const FSPoserJoint* joint, const LLVector3& rotation, E_BoneDeflectionStyles style, E_BoneAxisTranslation translation, S32 negation, + bool resetBaseRotationToZero) { if (!isAvatarSafeToUse(avatar)) return; @@ -516,42 +497,52 @@ void FSPoserAnimator::setJointRotation(LLVOAvatar* avatar, const FSPoserJoint* j if (!posingMotion) return; - FSPosingMotion::FSJointPose* jointPose = posingMotion->getJointPoseByJointName(joint->jointName()); + FSJointPose* jointPose = posingMotion->getJointPoseByJointName(joint->jointName()); if (!jointPose) return; + if (resetBaseRotationToZero) + jointPose->zeroBaseRotation(); + LLQuaternion rot_quat = translateRotationToQuaternion(translation, negation, rotation); switch (style) { case SYMPATHETIC: case MIRROR: - jointPose->setTargetRotation(rot_quat); + jointPose->setRotationDelta(rot_quat); break; case DELTAMODE: - jointPose->applyDeltaRotation(rot_quat); - return; - + jointPose->setRotationDelta(rot_quat * jointPose->getRotationDelta()); + break; + case NONE: default: - jointPose->setTargetRotation(rot_quat); + jointPose->setRotationDelta(rot_quat); return; } - FSPosingMotion::FSJointPose* oppositeJointPose = posingMotion->getJointPoseByJointName(joint->mirrorJointName()); + FSJointPose* oppositeJointPose = posingMotion->getJointPoseByJointName(joint->mirrorJointName()); if (!oppositeJointPose) return; + if (resetBaseRotationToZero) + oppositeJointPose->zeroBaseRotation(); + LLQuaternion inv_quat; switch (style) { case SYMPATHETIC: - oppositeJointPose->setTargetRotation(rot_quat); + oppositeJointPose->setRotationDelta(rot_quat); break; case MIRROR: inv_quat = LLQuaternion(-rot_quat.mQ[VX], rot_quat.mQ[VY], -rot_quat.mQ[VZ], rot_quat.mQ[VW]); - oppositeJointPose->setTargetRotation(inv_quat); + oppositeJointPose->setRotationDelta(inv_quat); + break; + + case DELTAMODE: + oppositeJointPose->setRotationDelta(rot_quat * oppositeJointPose->getRotationDelta()); break; default: @@ -571,26 +562,18 @@ void FSPoserAnimator::reflectJoint(LLVOAvatar* avatar, const FSPoserJoint* joint if (!posingMotion) return; - FSPosingMotion::FSJointPose* jointPose = posingMotion->getJointPoseByJointName(joint->jointName()); + FSJointPose* jointPose = posingMotion->getJointPoseByJointName(joint->jointName()); if (!jointPose) return; - FSPosingMotion::FSJointPose* oppositeJointPose = posingMotion->getJointPoseByJointName(joint->mirrorJointName()); - if (!oppositeJointPose) + jointPose->reflectRotation(); + FSJointPose* oppositeJointPose = posingMotion->getJointPoseByJointName(joint->mirrorJointName()); + + if (oppositeJointPose) { - LLQuaternion rot_quat = jointPose->getTargetRotation(); - LLQuaternion inv_quat = LLQuaternion(-rot_quat.mQ[VX], rot_quat.mQ[VY], -rot_quat.mQ[VZ], rot_quat.mQ[VW]); - - jointPose->setTargetRotation(inv_quat); - return; + oppositeJointPose->reflectRotation(); + jointPose->swapRotationWith(oppositeJointPose); } - - LLQuaternion first_quat = jointPose->getTargetRotation(); - LLQuaternion first_inv = LLQuaternion(-first_quat.mQ[VX], first_quat.mQ[VY], -first_quat.mQ[VZ], first_quat.mQ[VW]); - LLQuaternion second_quat = oppositeJointPose->getTargetRotation(); - LLQuaternion second_inv = LLQuaternion(-second_quat.mQ[VX], second_quat.mQ[VY], -second_quat.mQ[VZ], second_quat.mQ[VW]); - jointPose->setTargetRotation(second_inv); - oppositeJointPose->setTargetRotation(first_inv); } void FSPoserAnimator::flipEntirePose(LLVOAvatar* avatar) @@ -725,7 +708,7 @@ LLVector3 FSPoserAnimator::translateRotationFromQuaternion(E_BoneAxisTranslation return vec3; } -LLVector3 FSPoserAnimator::getJointScale(LLVOAvatar* avatar, const FSPoserJoint& joint, bool forRecapture) const +LLVector3 FSPoserAnimator::getJointScale(LLVOAvatar* avatar, const FSPoserJoint& joint) const { LLVector3 scale; if (!isAvatarSafeToUse(avatar)) @@ -735,16 +718,11 @@ LLVector3 FSPoserAnimator::getJointScale(LLVOAvatar* avatar, const FSPoserJoint& if (!posingMotion) return scale; - FSPosingMotion::FSJointPose* jointPose = posingMotion->getJointPoseByJointName(joint.jointName()); + FSJointPose* jointPose = posingMotion->getJointPoseByJointName(joint.jointName()); if (!jointPose) return scale; - if (forRecapture) - scale = jointPose->getCurrentScale(); - else - scale = jointPose->getTargetScale(); - - return scale; + return jointPose->getScaleDelta(); } void FSPoserAnimator::setJointScale(LLVOAvatar* avatar, const FSPoserJoint* joint, const LLVector3& scale, E_BoneDeflectionStyles style) @@ -762,23 +740,24 @@ void FSPoserAnimator::setJointScale(LLVOAvatar* avatar, const FSPoserJoint* join if (!posingMotion) return; - FSPosingMotion::FSJointPose* jointPose = posingMotion->getJointPoseByJointName(jn); + FSJointPose* jointPose = posingMotion->getJointPoseByJointName(jn); if (!jointPose) return; - jointPose->setTargetScale(scale); + jointPose->setScaleDelta(scale); if (style == NONE) return; - FSPosingMotion::FSJointPose* oppositeJointPose = posingMotion->getJointPoseByJointName(joint->mirrorJointName()); + FSJointPose* oppositeJointPose = posingMotion->getJointPoseByJointName(joint->mirrorJointName()); if (!oppositeJointPose) return; - oppositeJointPose->setTargetScale(scale); + oppositeJointPose->setScaleDelta(scale); } -bool FSPoserAnimator::tryGetJointSaveVectors(LLVOAvatar* avatar, const FSPoserJoint& joint, LLVector3* rot, LLVector3* pos, LLVector3* scale) +bool FSPoserAnimator::tryGetJointSaveVectors(LLVOAvatar* avatar, const FSPoserJoint& joint, LLVector3* rot, LLVector3* pos, + LLVector3* scale, bool* baseRotationIsZero) { if (!rot || !pos || !scale) return false; @@ -790,19 +769,20 @@ bool FSPoserAnimator::tryGetJointSaveVectors(LLVOAvatar* avatar, const FSPoserJo if (!posingMotion) return false; - FSPosingMotion::FSJointPose* jointPose = posingMotion->getJointPoseByJointName(joint.jointName()); + FSJointPose* jointPose = posingMotion->getJointPoseByJointName(joint.jointName()); if (!jointPose) return false; - LLQuaternion difference = jointPose->getTargetRotation() * jointPose->getBeginningRotation().conjugate(); // diff * q1 = q2 -> diff = q2 * inverse(q1) + LLQuaternion rotationDelta = jointPose->getRotationDelta(); + rotationDelta.getEulerAngles(&rot->mV[VX], &rot->mV[VY], &rot->mV[VZ]); + pos->set(jointPose->getPositionDelta()); + scale->set(jointPose->getScaleDelta()); + *baseRotationIsZero = jointPose->isBaseRotationZero(); - difference.getEulerAngles(&rot->mV[VX], &rot->mV[VY], &rot->mV[VZ]); - pos->set(jointPose->getTargetPosition() - jointPose->getBeginningPosition()); - scale->set(jointPose->getTargetScale() - jointPose->getBeginningScale()); return true; } -void FSPoserAnimator::loadJointRotation(LLVOAvatar* avatar, const FSPoserJoint* joint, LLVector3 rotation) +void FSPoserAnimator::loadJointRotation(LLVOAvatar* avatar, const FSPoserJoint* joint, bool setBaseToZero, LLVector3 rotation) { if (!isAvatarSafeToUse(avatar) || !joint) return; @@ -811,12 +791,15 @@ void FSPoserAnimator::loadJointRotation(LLVOAvatar* avatar, const FSPoserJoint* if (!posingMotion) return; - FSPosingMotion::FSJointPose* jointPose = posingMotion->getJointPoseByJointName(joint->jointName()); + FSJointPose* jointPose = posingMotion->getJointPoseByJointName(joint->jointName()); if (!jointPose) return; + if (setBaseToZero) + jointPose->zeroBaseRotation(); + LLQuaternion rot = translateRotationToQuaternion(SWAP_NOTHING, NEGATE_NOTHING, rotation); - jointPose->setTargetRotation(rot * jointPose->getBeginningRotation()); + jointPose->setRotationDelta(rot); } void FSPoserAnimator::loadJointPosition(LLVOAvatar* avatar, const FSPoserJoint* joint, bool loadPositionAsDelta, LLVector3 position) @@ -828,14 +811,14 @@ void FSPoserAnimator::loadJointPosition(LLVOAvatar* avatar, const FSPoserJoint* if (!posingMotion) return; - FSPosingMotion::FSJointPose* jointPose = posingMotion->getJointPoseByJointName(joint->jointName()); + FSJointPose* jointPose = posingMotion->getJointPoseByJointName(joint->jointName()); if (!jointPose) return; if (loadPositionAsDelta) - jointPose->setTargetPosition(jointPose->getBeginningPosition() + position); + jointPose->setPositionDelta(position); else - jointPose->setTargetPosition(position); + jointPose->setPositionDelta(position); } void FSPoserAnimator::loadJointScale(LLVOAvatar* avatar, const FSPoserJoint* joint, bool loadScaleAsDelta, LLVector3 scale) @@ -847,14 +830,14 @@ void FSPoserAnimator::loadJointScale(LLVOAvatar* avatar, const FSPoserJoint* joi if (!posingMotion) return; - FSPosingMotion::FSJointPose* jointPose = posingMotion->getJointPoseByJointName(joint->jointName()); + FSJointPose* jointPose = posingMotion->getJointPoseByJointName(joint->jointName()); if (!jointPose) return; if (loadScaleAsDelta) - jointPose->setTargetScale(jointPose->getTargetScale() + scale); + jointPose->setScaleDelta(scale); else - jointPose->setTargetScale(scale); + jointPose->setScaleDelta(scale); } const FSPoserAnimator::FSPoserJoint* FSPoserAnimator::getPoserJointByName(const std::string& jointName) diff --git a/indra/newview/fsposeranimator.h b/indra/newview/fsposeranimator.h index d181c847a8..6821e0aaa9 100644 --- a/indra/newview/fsposeranimator.h +++ b/indra/newview/fsposeranimator.h @@ -56,15 +56,6 @@ typedef enum E_BoneDeflectionStyles DELTAMODE = 3, // each selected joint changes by the same supplied amount relative to their current } E_BoneDeflectionStyles; -/// -/// When getting the rotation of a joint, we can apply different considerations to the rotation. -/// -typedef enum E_BoneRotationType -{ - CURRENTROTATION = 0, // the current rotation the joint has - TARGETROTATION = 1, // the rotation the we want to achieve -} E_BoneRotationType; - /// /// 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. @@ -429,7 +420,7 @@ public: /// The avatar whose joint is being queried. /// The joint to determine the position for. /// The position of the requested joint, if determinable, otherwise a default vector. - LLVector3 getJointPosition(LLVOAvatar* avatar, const FSPoserJoint& joint, bool forRecapture = false) const; + LLVector3 getJointPosition(LLVOAvatar* avatar, const FSPoserJoint& joint) const; /// /// Sets the position of a joint for the supplied avatar. @@ -449,7 +440,7 @@ public: /// The style of negation to dis-apply to the get. /// The type of rotation to get from the supplied joint for the supplied avatar. /// The rotation of the requested joint, if determinable, otherwise a default vector. - LLVector3 getJointRotation(LLVOAvatar* avatar, const FSPoserJoint& joint, E_BoneAxisTranslation translation, S32 negation, E_BoneRotationType rotType) const; + LLVector3 getJointRotation(LLVOAvatar* avatar, const FSPoserJoint& joint, E_BoneAxisTranslation translation, S32 negation) const; /// /// Sets the rotation of a joint for the supplied avatar. @@ -460,8 +451,9 @@ public: /// Any ancilliary action to be taken with the change to be made. /// The axial translation form the supplied joint. /// The style of negation to apply to the set. + /// Whether to set the base rotation to zero on setting the rotation. void setJointRotation(LLVOAvatar* avatar, const FSPoserJoint* joint, const LLVector3& rotation, E_BoneDeflectionStyles style, - E_BoneAxisTranslation translation, S32 negation); + E_BoneAxisTranslation translation, S32 negation, bool resetBaseRotationToZero); /// /// Gets the scale of a joint for the supplied avatar. @@ -469,7 +461,7 @@ public: /// The avatar whose joint is being queried. /// The joint to determine the scale for. /// The scale of the requested joint, if determinable, otherwise a default vector. - LLVector3 getJointScale(LLVOAvatar* avatar, const FSPoserJoint& joint, bool forRecapture = false) const; + LLVector3 getJointScale(LLVOAvatar* avatar, const FSPoserJoint& joint) const; /// /// Sets the scale of a joint for the supplied avatar. @@ -517,7 +509,18 @@ public: /// A save of the rotation 'deltas' facilitates a user saving their changes to an existing animation. /// Thus the save represents 'nothing other than the changes the user made', to some other pose which they may have limited rights to. /// - bool posingStartedFromZeroRotations(LLVOAvatar* avatar) const; + bool baseRotationIsZero(LLVOAvatar* avatar, const FSPoserJoint& joint) const; + + /// + /// Determines if the kind of save to perform should be a 'delta' save, or a complete save. + /// + /// The avatar whose pose-rotations are being considered for saving. + /// True if the save should save only 'deltas' to the rotation, otherwise false. + /// + /// A save of the rotation 'deltas' facilitates a user saving their changes to an existing animation. + /// Thus the save represents 'nothing other than the changes the user made', to some other pose which they may have limited rights to. + /// + bool allBaseRotationsAreZero(LLVOAvatar* avatar) const; /// /// Tries to get the rotation, position and scale changes from initial conditions, to save in some export container. @@ -527,26 +530,28 @@ public: /// The quaternion to store the rotation to save in. /// The vector to store the position to save in. /// The vector to store the scale to save in. + /// The bool to store whether the base rotation is zero. /// True if the joint should be saved, otherwise false. /// /// Our objective is to protect peoples novel work: the poses created with this, and poses from other sources, such as in-world. /// In all scenarios, this yeilds 'deltas' of rotation/position/scale. /// The deltas represent the user's novel work, and may be relative to some initial values (as from a pose), or to 'nothing' (such as all rotations == 0, or, the 'T-Pose'). /// - bool tryGetJointSaveVectors(LLVOAvatar* avatar, const FSPoserJoint& joint, LLVector3* rot, LLVector3* pos, LLVector3* scale); + bool tryGetJointSaveVectors(LLVOAvatar* avatar, const FSPoserJoint& joint, LLVector3* rot, LLVector3* pos, LLVector3* scale, bool* baseRotationIsZero); /// /// Loads a joint rotation for the supplied joint on the supplied avatar. /// /// The avatar to load the rotation for. /// The joint to load the rotation for. + /// Whether to start from a zero base rotation. /// The rotation to load. /// /// All rotations we load are deltas to the current rotation the supplied joint has. /// Whether the joint already has a rotation because some animation is playing, /// or whether its rotation is zero, the result is always the same: just 'add' the supplied rotation to the existing rotation. /// - void loadJointRotation(LLVOAvatar* avatar, const FSPoserJoint* joint, LLVector3 rotation); + void loadJointRotation(LLVOAvatar* avatar, const FSPoserJoint* joint, bool setBaseToZero, LLVector3 rotation); /// /// Loads a joint position for the supplied joint on the supplied avatar. @@ -622,9 +627,6 @@ public: /// True if the avatar is safe to manipulate, otherwise false. bool isAvatarSafeToUse(LLVOAvatar* avatar) const; - void setStartingJointRotation(LLVOAvatar* avatar, const FSPoserJoint* joint, const LLVector3& rotation, - E_BoneAxisTranslation translation, S32 negation); - /// /// 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. diff --git a/indra/newview/fsposingmotion.cpp b/indra/newview/fsposingmotion.cpp index f0f37a1455..d16e9f5374 100644 --- a/indra/newview/fsposingmotion.cpp +++ b/indra/newview/fsposingmotion.cpp @@ -48,7 +48,7 @@ LLMotion::LLMotionInitStatus FSPosingMotion::onInitialize(LLCharacter *character if (!targetJoint) continue; - FSJointPose jointPose = FSJointPose(targetJoint); + FSJointPose jointPose = FSJointPose(targetJoint, POSER_JOINT_STATE); mJointPoses.push_back(jointPose); addJointState(jointPose.getJointState()); @@ -59,7 +59,7 @@ LLMotion::LLMotionInitStatus FSPosingMotion::onInitialize(LLCharacter *character if (!targetJoint) continue; - FSJointPose jointPose = FSJointPose(targetJoint, true); + FSJointPose jointPose = FSJointPose(targetJoint, POSER_JOINT_STATE, true); mJointPoses.push_back(jointPose); addJointState(jointPose.getJointState()); @@ -91,9 +91,9 @@ bool FSPosingMotion::onUpdate(F32 time, U8* joint_mask) currentRotation = joint->getRotation(); currentPosition = joint->getPosition(); currentScale = joint->getScale(); - targetRotation = jointPose.getTargetRotation(); - targetPosition = jointPose.getTargetPosition(); - targetScale = jointPose.getTargetScale(); + targetRotation = jointPose.getTargetRotation(); + targetPosition = jointPose.getTargetPosition(); + targetScale = jointPose.getTargetScale(); if (currentPosition != targetPosition) { @@ -213,7 +213,7 @@ void FSPosingMotion::setJointState(LLJoint* joint, U32 state) addJointState(jointPose->getJointState()); } -FSPosingMotion::FSJointPose* FSPosingMotion::getJointPoseByJointName(const std::string& name) +FSJointPose* FSPosingMotion::getJointPoseByJointName(const std::string& name) { if (mJointPoses.size() < 1) return nullptr; @@ -251,16 +251,12 @@ bool FSPosingMotion::currentlyPosingJoint(LLJoint* joint) bool FSPosingMotion::allStartingRotationsAreZero() const { - LLQuaternion zeroQuat; for (auto poserJoint_iter = mJointPoses.begin(); poserJoint_iter != mJointPoses.end(); ++poserJoint_iter) { - if (poserJoint_iter->jointName() == "mPelvis") - continue; if (poserJoint_iter->isCollisionVolume()) continue; - LLQuaternion quat = poserJoint_iter->getBeginningRotation(); - if (quat != zeroQuat) + if (!poserJoint_iter->isBaseRotationZero()) return false; } @@ -269,14 +265,8 @@ bool FSPosingMotion::allStartingRotationsAreZero() const void FSPosingMotion::setAllRotationsToZero() { - LLQuaternion zeroQuat; for (auto poserJoint_iter = mJointPoses.begin(); poserJoint_iter != mJointPoses.end(); ++poserJoint_iter) - { - if (poserJoint_iter->isCollisionVolume()) - continue; - - poserJoint_iter->setJointStartRotations(zeroQuat); - } + poserJoint_iter->zeroBaseRotation(); } constexpr size_t MaximumUndoQueueLength = 20; @@ -285,251 +275,3 @@ constexpr size_t MaximumUndoQueueLength = 20; /// The constant time interval, in seconds, specifying whether an 'undo' value should be added. /// constexpr std::chrono::duration UndoUpdateInterval = std::chrono::duration(0.3); - - -void FSPosingMotion::FSJointPose::addLastPositionToUndo() -{ - if (mUndonePositionIndex > 0) - { - for (int i = 0; i < mUndonePositionIndex; i++) - mLastSetPositions.pop_front(); - - mUndonePositionIndex = 0; - } - - mLastSetPositions.push_front(mTargetPosition); - - while (mLastSetPositions.size() > MaximumUndoQueueLength) - mLastSetPositions.pop_back(); -} - -void FSPosingMotion::FSJointPose::addLastRotationToUndo() -{ - if (mUndoneRotationIndex > 0) - { - for (int i = 0; i < mUndoneRotationIndex; i++) - mLastSetRotations.pop_front(); - - mUndoneRotationIndex = 0; - } - - mLastSetRotations.push_front(mTargetRotation); - - while (mLastSetRotations.size() > MaximumUndoQueueLength) - mLastSetRotations.pop_back(); -} - -void FSPosingMotion::FSJointPose::addLastScaleToUndo() -{ - if (mUndoneScaleIndex > 0) - { - for (int i = 0; i < mUndoneScaleIndex; i++) - mLastSetScales.pop_front(); - - mUndoneScaleIndex = 0; - } - - mLastSetScales.push_front(mTargetScale); - - while (mLastSetScales.size() > MaximumUndoQueueLength) - mLastSetScales.pop_back(); -} - -LLVector3 FSPosingMotion::FSJointPose::getCurrentPosition() -{ - LLVector3 vec3; - LLJoint* joint = mJointState->getJoint(); - if (!joint) - return vec3; - - vec3 = joint->getPosition(); - return vec3; -} - -void FSPosingMotion::FSJointPose::setTargetPosition(const LLVector3& pos) -{ - auto timeIntervalSinceLastRotationChange = std::chrono::system_clock::now() - mTimeLastUpdatedPosition; - if (timeIntervalSinceLastRotationChange > UndoUpdateInterval) - addLastPositionToUndo(); - - mTimeLastUpdatedPosition = std::chrono::system_clock::now(); - mTargetPosition.set(pos); -} - -LLQuaternion FSPosingMotion::FSJointPose::getCurrentRotation() -{ - LLQuaternion quat; - LLJoint* joint = mJointState->getJoint(); - if (!joint) - return quat; - - quat = joint->getRotation(); - return quat; -} - -void FSPosingMotion::FSJointPose::setTargetRotation(const LLQuaternion& rot) -{ - auto timeIntervalSinceLastRotationChange = std::chrono::system_clock::now() - mTimeLastUpdatedRotation; - if (timeIntervalSinceLastRotationChange > UndoUpdateInterval) - addLastRotationToUndo(); - - mTimeLastUpdatedRotation = std::chrono::system_clock::now(); - mTargetRotation.set(rot); -} - -void FSPosingMotion::FSJointPose::applyDeltaRotation(const LLQuaternion& rot) -{ - auto timeIntervalSinceLastRotationChange = std::chrono::system_clock::now() - mTimeLastUpdatedRotation; - if (timeIntervalSinceLastRotationChange > UndoUpdateInterval) - addLastRotationToUndo(); - - mTimeLastUpdatedRotation = std::chrono::system_clock::now(); - mTargetRotation = mTargetRotation * rot; -} - -LLVector3 FSPosingMotion::FSJointPose::getCurrentScale() -{ - LLVector3 vec3; - LLJoint* joint = mJointState->getJoint(); - if (!joint) - return vec3; - - vec3 = joint->getScale(); - return vec3; -} - -void FSPosingMotion::FSJointPose::setTargetScale(LLVector3 scale) -{ - auto timeIntervalSinceLastScaleChange = std::chrono::system_clock::now() - mTimeLastUpdatedScale; - if (timeIntervalSinceLastScaleChange > UndoUpdateInterval) - addLastScaleToUndo(); - - mTimeLastUpdatedScale = std::chrono::system_clock::now(); - mTargetScale.set(scale); -} - -void FSPosingMotion::FSJointPose::undoLastPositionSet() -{ - if (mLastSetPositions.empty()) - return; - - if (mUndonePositionIndex == 0) // at the top of the queue add the current - addLastPositionToUndo(); - - mUndonePositionIndex++; - mUndonePositionIndex = llclamp(mUndonePositionIndex, 0, mLastSetPositions.size() - 1); - mTargetPosition.set(mLastSetPositions[mUndonePositionIndex]); -} - -void FSPosingMotion::FSJointPose::redoLastPositionSet() -{ - if (mLastSetPositions.empty()) - return; - - mUndonePositionIndex--; - mUndonePositionIndex = llclamp(mUndonePositionIndex, 0, mLastSetPositions.size() - 1); - - mTargetPosition.set(mLastSetPositions[mUndonePositionIndex]); - if (mUndonePositionIndex == 0) - mLastSetPositions.pop_front(); -} - -void FSPosingMotion::FSJointPose::undoLastRotationSet() -{ - if (mLastSetRotations.empty()) - return; - - if (mUndoneRotationIndex == 0) // at the top of the queue add the current - addLastRotationToUndo(); - - mUndoneRotationIndex++; - mUndoneRotationIndex = llclamp(mUndoneRotationIndex, 0, mLastSetRotations.size() - 1); - mTargetRotation.set(mLastSetRotations[mUndoneRotationIndex]); -} - -void FSPosingMotion::FSJointPose::redoLastRotationSet() -{ - if (mLastSetRotations.empty()) - return; - - mUndoneRotationIndex--; - mUndoneRotationIndex = llclamp(mUndoneRotationIndex, 0, mLastSetRotations.size() - 1); - - mTargetRotation.set(mLastSetRotations[mUndoneRotationIndex]); - if (mUndoneRotationIndex == 0) - mLastSetRotations.pop_front(); -} - -void FSPosingMotion::FSJointPose::undoLastScaleSet() -{ - if (mLastSetScales.empty()) - return; - - if (mUndoneScaleIndex == 0) - addLastScaleToUndo(); - - mUndoneScaleIndex++; - mUndoneScaleIndex = llclamp(mUndoneScaleIndex, 0, mLastSetScales.size() - 1); - mTargetScale.set(mLastSetScales[mUndoneScaleIndex]); -} - -void FSPosingMotion::FSJointPose::redoLastScaleSet() -{ - if (mLastSetScales.empty()) - return; - - mUndoneScaleIndex--; - mUndoneScaleIndex = llclamp(mUndoneScaleIndex, 0, mLastSetScales.size() - 1); - - mTargetScale.set(mLastSetScales[mUndoneScaleIndex]); - if (mUndoneScaleIndex == 0) - mLastSetScales.pop_front(); -} - -void FSPosingMotion::FSJointPose::revertJointScale() -{ - LLJoint* joint = mJointState->getJoint(); - if (!joint) - return; - - joint->setScale(mBeginningScale); -} - -void FSPosingMotion::FSJointPose::revertJointPosition() -{ - LLJoint* joint = mJointState->getJoint(); - if (!joint) - return; - - joint->setPosition(mBeginningPosition); -} - -void FSPosingMotion::FSJointPose::revertCollisionVolume() -{ - if (!mIsCollisionVolume) - return; - - LLJoint* joint = mJointState->getJoint(); - if (!joint) - return; - - joint->setRotation(mBeginningRotation); - joint->setPosition(mBeginningPosition); - joint->setScale(mBeginningScale); -} - -void FSPosingMotion::FSJointPose::setJointStartRotations(LLQuaternion quat) { mBeginningRotation = mTargetRotation = quat; } - -FSPosingMotion::FSJointPose::FSJointPose(LLJoint* joint, bool isCollisionVolume) -{ - mJointState = new LLJointState; - mJointState->setJoint(joint); - mJointState->setUsage(POSER_JOINT_STATE); - - mJointName = joint->getName(); - mIsCollisionVolume = isCollisionVolume; - - mBeginningRotation = mTargetRotation = joint->getRotation(); - mBeginningPosition = mTargetPosition = joint->getPosition(); - mBeginningScale = mTargetScale = joint->getScale(); -} diff --git a/indra/newview/fsposingmotion.h b/indra/newview/fsposingmotion.h index c20f3b07c2..438c7603b0 100644 --- a/indra/newview/fsposingmotion.h +++ b/indra/newview/fsposingmotion.h @@ -1,5 +1,5 @@ /** - * @file fsposingmotion.cpp + * @file fsposingmotion.h * @brief Model for posing your (and other) avatar(s). * * $LicenseInfo:firstyear=2024&license=viewerlgpl$ @@ -31,6 +31,7 @@ // Header files //----------------------------------------------------------------------------- #include "llmotion.h" +#include "fsjointpose.h" #define MIN_REQUIRED_PIXEL_AREA_POSING 500.f @@ -47,195 +48,6 @@ public: public: static LLMotion *create(const LLUUID &id) { return new FSPosingMotion(id); } - /// - /// A class encapsulating the positions/rotations for a joint. - /// - class FSJointPose - { - std::string mJointName = ""; // expected to be a match to LLJoint.getName() for a joint implementation. - LLPointer mJointState{ nullptr }; - - /// - /// Collision Volumes require special treatment when we stop animating an avatar, as they do not revert to their original state natively. - /// - bool mIsCollisionVolume{ false }; - - LLQuaternion mTargetRotation; - LLQuaternion mBeginningRotation; - std::deque mLastSetRotations; - size_t mUndoneRotationIndex = 0; - std::chrono::system_clock::time_point mTimeLastUpdatedRotation = std::chrono::system_clock::now(); - - LLVector3 mTargetPosition; - LLVector3 mBeginningPosition; - std::deque mLastSetPositions; - size_t mUndonePositionIndex = 0; - std::chrono::system_clock::time_point mTimeLastUpdatedPosition = std::chrono::system_clock::now(); - - /// - /// Joint scales require special treatment, as they do not revert when we stop animating an avatar. - /// - LLVector3 mTargetScale; - LLVector3 mBeginningScale; - std::deque mLastSetScales; - size_t mUndoneScaleIndex = 0; - std::chrono::system_clock::time_point mTimeLastUpdatedScale = std::chrono::system_clock::now(); - - /// - /// Adds a last position to the deque. - /// - void addLastPositionToUndo(); - - /// - /// Adds a last rotation to the deque. - /// - void addLastRotationToUndo(); - - /// - /// Adds a last rotation to the deque. - /// - void addLastScaleToUndo(); - - public: - /// - /// Gets the name of the joint. - /// - std::string jointName() const { return mJointName; } - - /// - /// Gets whether this represents a collision volume. - /// - /// - bool isCollisionVolume() const { return mIsCollisionVolume; } - - /// - /// Gets whether a redo of this joints rotation may be performed. - /// - /// - bool canRedoRotation() const { return mUndoneRotationIndex > 0; } - - /// - /// Gets the position the joint was in when the animation was initialized. - /// - LLVector3 getBeginningPosition() const { return mBeginningPosition; } - - /// - /// Gets the position the animator wishes the joint to be in. - /// - LLVector3 getTargetPosition() const { return mTargetPosition; } - - /// - /// Gets the position the animator wishes the joint to be in. - /// - LLVector3 getCurrentPosition(); - - /// - /// Sets the position the animator wishes the joint to be in. - /// - void setTargetPosition(const LLVector3& pos); - - /// - /// Gets the rotation the joint was in when the animation was initialized. - /// - LLQuaternion getBeginningRotation() const { return mBeginningRotation; } - - /// - /// Gets the rotation the animator wishes the joint to be in. - /// - LLQuaternion getTargetRotation() const { return mTargetRotation; } - - /// - /// Gets the rotation of the joint. - /// - LLQuaternion getCurrentRotation(); - - /// - /// Sets the rotation the animator wishes the joint to be in. - /// - void setTargetRotation(const LLQuaternion& rot); - - /// - /// Applies a delta to the rotation the joint currently targets. - /// - void applyDeltaRotation(const LLQuaternion& rot); - - /// - /// Gets the scale the animator wishes the joint to have. - /// - LLVector3 getTargetScale() const { return mTargetScale; } - - /// - /// Gets the scale the joint has. - /// - LLVector3 getCurrentScale(); - - /// - /// Gets the scale the joint had when the animation was initialized. - /// - LLVector3 getBeginningScale() const { return mBeginningScale; } - - /// - /// Sets the scale the animator wishes the joint to have. - /// - void setTargetScale(LLVector3 scale); - - /// - /// Undoes the last position set, if any. - /// - void undoLastPositionSet(); - - /// - /// Undoes the last position set, if any. - /// - void redoLastPositionSet(); - - /// - /// Undoes the last rotation set, if any. - /// Ordinarily the queue does not contain the current rotation, because we rely on time to add, and not button-up. - /// When we undo, if we are at the top of the queue, we need to add the current rotation so we can redo back to it. - /// Thus when we start undoing, mUndoneRotationIndex points at the current rotation. - /// - void undoLastRotationSet(); - - /// - /// Undoes the last rotation set, if any. - /// - void redoLastRotationSet(); - - void undoLastScaleSet(); - - void redoLastScaleSet(); - - /// - /// Restores the joint represented by this to the scale it had when this motion started. - /// - void revertJointScale(); - - /// - /// Restores the joint represented by this to the position it had when this motion started. - /// - void revertJointPosition(); - - /// - /// Collision Volumes do not 'reset' their position/rotation when the animation stops. - /// This requires special treatment to revert changes we've made this animation session. - /// - void revertCollisionVolume(); - - /// - /// Sets the beginning and target rotations to the supplied rotation. - /// - void setJointStartRotations(LLQuaternion quat); - - /// - /// Gets the pointer to the jointstate for the joint this represents. - /// - LLPointer getJointState() const { return mJointState; } - - FSJointPose(LLJoint* joint, bool isCollisionVolume = false); - }; - -public: virtual bool getLoop() { return true; } virtual F32 getDuration() { return 0.0; } @@ -323,10 +135,16 @@ private: LLAssetID mMotionID; /// - /// The amount of time, in seconds, we use for transitioning between one animation-state to another; this affects the 'fluidity' - /// of motion between changes to a joint. + /// The time constant, in seconds, we use for transitioning between one animation-state to another; this affects the 'damping' + /// of motion between changes to a joint. 'Constant' in this context is not a reference to the language-idea of 'const' value. + /// Smaller is less damping => faster transition. + /// As implemented, the actual rotation of a joint decays towards the target rotation in something akin to (if not) an exponential. + /// This time constant effects how fast this decay occurs rather than how long it takes to complete (it often never completes). + /// This contributes to the fact that actual rotation != target rotation (in addition to rotation being non-monotonic). /// Use caution making this larger than the subjective amount of time between adjusting a joint and then choosing to use 'undo' it. - /// Undo-function waits a similar amount of time after the last user-incited joint change to add a 'restore point'. + /// Undo-function waits an amount of time after the last user-incited joint change to add a 'restore point'. + /// Important to note is that the actual rotation/position/scale never reaches the target, which seems absurd, however + /// it's the user that closes the feedback loop here: if they want more change, they input more until the result is as they like it. /// const F32 mInterpolationTime = 0.25f; @@ -366,4 +184,3 @@ private: }; #endif // FS_POSINGMOTION_H - diff --git a/indra/newview/llinspecttexture.cpp b/indra/newview/llinspecttexture.cpp index e4a092c5b9..499aaa1a85 100644 --- a/indra/newview/llinspecttexture.cpp +++ b/indra/newview/llinspecttexture.cpp @@ -33,6 +33,8 @@ #include "lltrans.h" #include "llviewertexturelist.h" +#include "rlvactions.h" + // ============================================================================ // Helper functions @@ -42,6 +44,11 @@ LLToolTip* LLInspectTextureUtil::createInventoryToolTip(LLToolTip::Params p) { const LLSD& sdTooltip = p.create_params; + // Texture tooltip RLVa fix + if (!RlvActions::canPreviewTextures()) + return LLUICtrlFactory::create(p); + // + if (sdTooltip.has("thumbnail_id") && sdTooltip["thumbnail_id"].asUUID().notNull()) { // go straight for thumbnail regardless of type diff --git a/indra/newview/skins/default/xui/az/panel_preferences_graphics1.xml b/indra/newview/skins/default/xui/az/panel_preferences_graphics1.xml index b664af7fe6..b298b3bc34 100644 --- a/indra/newview/skins/default/xui/az/panel_preferences_graphics1.xml +++ b/indra/newview/skins/default/xui/az/panel_preferences_graphics1.xml @@ -102,7 +102,7 @@ - + Hamarlaşdırma (yenidən başlatma tövsiyyə olunur): diff --git a/indra/newview/skins/default/xui/de/floater_fs_poser.xml b/indra/newview/skins/default/xui/de/floater_fs_poser.xml index 203c1bc4b4..9ba304d0bc 100644 --- a/indra/newview/skins/default/xui/de/floater_fs_poser.xml +++ b/indra/newview/skins/default/xui/de/floater_fs_poser.xml @@ -222,6 +222,7 @@ + diff --git a/indra/newview/skins/default/xui/de/panel_preferences_graphics1.xml b/indra/newview/skins/default/xui/de/panel_preferences_graphics1.xml index 7011f62114..8f2667d6b7 100644 --- a/indra/newview/skins/default/xui/de/panel_preferences_graphics1.xml +++ b/indra/newview/skins/default/xui/de/panel_preferences_graphics1.xml @@ -143,7 +143,7 @@ S3TC aktivieren: - + Antialiasing (Neustart empfohlen): diff --git a/indra/newview/skins/default/xui/en/floater_fs_poser.xml b/indra/newview/skins/default/xui/en/floater_fs_poser.xml index 3c7b1bc523..a9314c8e1c 100644 --- a/indra/newview/skins/default/xui/en/floater_fs_poser.xml +++ b/indra/newview/skins/default/xui/en/floater_fs_poser.xml @@ -9,6 +9,7 @@ width="403"> Inv_BodyShape Inv_Object + Check_Mark