diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index ffda9d8039..5a50e75b1f 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -169,6 +169,7 @@ set(viewer_SOURCE_FILES fsscriptlibrary.cpp fsscrolllistctrl.cpp fsslurlcommand.cpp + fsvirtualtrackpad.cpp fsworldmapmessage.cpp lggbeamcolormapfloater.cpp lggbeammapfloater.cpp diff --git a/indra/newview/fsfloaterposer.cpp b/indra/newview/fsfloaterposer.cpp index acb948ad97..fd068a9816 100644 --- a/indra/newview/fsfloaterposer.cpp +++ b/indra/newview/fsfloaterposer.cpp @@ -31,7 +31,7 @@ #include "llavatarnamecache.h" #include "lldiriterator.h" #include "llsdserialize.h" -#include "llvirtualtrackball.h" +#include "fsvirtualtrackpad.h" #include "llfloater.h" #include "llviewercontrol.h" #include "llcontrolavatar.h" @@ -124,10 +124,7 @@ FSFloaterPoser::FSFloaterPoser(const LLSD& key) : LLFloater(key) mCommitCallbackRegistrar.add("Poser.TrackBallMove", boost::bind(&FSFloaterPoser::onLimbTrackballChanged, this)); // so I can debug } -FSFloaterPoser::~FSFloaterPoser() -{ - clearRecentlySetRotations(); -} +FSFloaterPoser::~FSFloaterPoser() {} bool FSFloaterPoser::postBuild() { @@ -741,25 +738,12 @@ void FSFloaterPoser::onToggleSympatheticChange() void FSFloaterPoser::onUndoLastRotation() { - auto size = _lastSetRotations.size(); - if (size < 2) + FSVirtualTrackpad *trackBall = getChild(POSER_AVATAR_TRACKBALL_NAME); + if (!trackBall) return; - _lastSetRotations.pop(); - LLVector3 lastRotation = _lastSetRotations.top(); - - setSelectedJointsRotation(lastRotation.mV[VX], lastRotation.mV[VY], lastRotation.mV[VZ]); -} - -void FSFloaterPoser::clearRecentlySetRotations() -{ - while (!_lastSetRotations.empty()) - _lastSetRotations.pop(); -} - -void FSFloaterPoser::addRotationToRecentlySet(F32 yawInRadians, F32 pitchInRadians, F32 rollInRadians) -{ - _lastSetRotations.push(LLVector3(yawInRadians, pitchInRadians, rollInRadians)); + trackBall->undoLastValue(); + onLimbTrackballChanged(); } void FSFloaterPoser::onToggleAdvancedPanel() @@ -934,44 +918,31 @@ void FSFloaterPoser::onAvatarPositionSet() /// void FSFloaterPoser::onLimbTrackballChanged() { - LLVirtualTrackball *trackBall = getChild(POSER_AVATAR_TRACKBALL_NAME); + FSVirtualTrackpad *trackBall = getChild(POSER_AVATAR_TRACKBALL_NAME); if (!trackBall) return; + LLVector2 trackPadPos; + LLSD position = trackBall->getValue(); + if (position.isArray() && position.size() == 2) + trackPadPos.setValue(position); + else + return; + LLSliderCtrl *pitchSlider = getChild(POSER_AVATAR_SLIDER_PITCH_NAME); // up/down LLSliderCtrl *yawSlider = getChild(POSER_AVATAR_SLIDER_YAW_NAME); // left right LLSliderCtrl *rollSlider = getChild(POSER_AVATAR_SLIDER_ROLL_NAME); if (!yawSlider || !pitchSlider || !rollSlider) return; - LLQuaternion trackBallQuat = trackBall->getRotation(); - - // Convert the quaternion to a cartesian (x,y,z) point on a unit-sphere - LLVector3 cartesionPoint = VectorZero * trackBallQuat; // VX is +up/-down screen; VY is +right/-left screen; VZ is +in/-out; all are ranged 1..-1 - F32 yaw, pitch, roll; - if (cartesionPoint.mV[VZ] >= 0) // the sun is in front of the trackball, easy math - { - yaw = cartesionPoint.mV[VX] * F_PI_BY_TWO; - pitch = cartesionPoint.mV[VY] * F_PI_BY_TWO; - } - else // when the sun is behind the trackball (VZ < 0), we want to keep increasing the angle - { - // this is a first pass, and does not consider sensitivity changes around the edges. - // it could be worth disallowing VZ < 0, or only allowing as an advanced feature. - if (cartesionPoint.mV[VX] >= 0) // sun is in top hemisphere - yaw = F_PI_BY_TWO * (2 - cartesionPoint.mV[VX]); - else - yaw = -1 * F_PI_BY_TWO - F_PI_BY_TWO * (1 + cartesionPoint.mV[VX]); + yaw = trackPadPos.mV[VX]; + pitch = trackPadPos.mV[VY]; - if (cartesionPoint.mV[VY] >= 0) // sun is in screen-right hemisphere - pitch = F_PI_BY_TWO * (2 - cartesionPoint.mV[VY]); - else - pitch = -1 * F_PI_BY_TWO - F_PI_BY_TWO * (1 + cartesionPoint.mV[VY]); - } - - roll = rollSlider->getValue().asReal(); // roll comes from the slider + yaw *= F_PI; + pitch *= F_PI; + roll = rollSlider->getValue().asReal(); // roll comes from its own slider roll *= DEG_TO_RAD; setSelectedJointsRotation(yaw, pitch, roll); @@ -997,22 +968,16 @@ void FSFloaterPoser::onLimbYawPitchRollChanged() yaw *= DEG_TO_RAD; pitch *= DEG_TO_RAD; roll *= DEG_TO_RAD; - + setSelectedJointsRotation(yaw, pitch, roll); - yaw *= F_PI; - pitch *= F_PI; - roll *= F_PI; // roll needs to be recalculated from unit sphere based on ranges of yaw and roll - LLVector3 vec3 = LLVector3(yaw, pitch, roll); - LLQuaternion quat; - quat.unpackFromVector3(vec3); - quat.setAngleAxis(pitch, 0, 1, 0); - - LLVirtualTrackball *trackBall = getChild(POSER_AVATAR_TRACKBALL_NAME); + FSVirtualTrackpad *trackBall = getChild(POSER_AVATAR_TRACKBALL_NAME); if (!trackBall) return; - trackBall->setRotation(quat); + yaw /= F_PI; + pitch /= F_PI; + trackBall->setValue(yaw, pitch); } void FSFloaterPoser::setSelectedJointsPosition(F32 x, F32 y, F32 z) @@ -1040,8 +1005,6 @@ void FSFloaterPoser::setSelectedJointsRotation(F32 yawInRadians, F32 pitchInRadi if (!_poserAnimator.isPosingAvatar(avatar)) return; - addRotationToRecentlySet(yawInRadians, pitchInRadians, rollInRadians); - E_BoneDeflectionStyles defl = getUiSelectedBoneDeflectionStyle(); LLVector3 vec3 = LLVector3(yawInRadians, pitchInRadians, rollInRadians); @@ -1078,26 +1041,10 @@ void FSFloaterPoser::onJointSelect() if (!_poserAnimator.isPosingAvatar(avatar)) return; - clearRecentlySetRotations(); LLVector3 rotation = _poserAnimator.getJointRotation(avatar, *selectedJoints.front()); - F32 yaw = rotation.mV[VX]; - F32 pitch = rotation.mV[VY]; - F32 roll = rotation.mV[VZ]; - - if (is_approx_zero(pitch)) - pitch = F_APPROXIMATELY_ZERO; - - LLQuaternion quat; - quat.setAngleAxis(-pitch, 0, 1, 0); - LLQuaternion az_quat; - az_quat.setAngleAxis(F_TWO_PI - yaw, 0, 0, 1); - quat *= az_quat; - - LLVirtualTrackball *trackBall = getChild(POSER_AVATAR_TRACKBALL_NAME); - if (!trackBall) - return; - - trackBall->setRotation(quat); + F32 yaw = rotation.mV[VX]; + F32 pitch = rotation.mV[VY]; + F32 roll = rotation.mV[VZ]; LLSliderCtrl *yawSlider = getChild(POSER_AVATAR_SLIDER_YAW_NAME); LLSliderCtrl *pitchSlider = getChild(POSER_AVATAR_SLIDER_PITCH_NAME); @@ -1108,6 +1055,10 @@ void FSFloaterPoser::onJointSelect() yawSlider->setValue(yaw *= RAD_TO_DEG); pitchSlider->setValue(pitch *= RAD_TO_DEG); rollSlider->setValue(roll *= RAD_TO_DEG); + + FSVirtualTrackpad *trackBall = getChild(POSER_AVATAR_TRACKBALL_NAME); + if (trackBall) + trackBall->setValue(yaw /= 180, pitch /= 180); } /// diff --git a/indra/newview/fsfloaterposer.h b/indra/newview/fsfloaterposer.h index 68a191b44f..b67381453b 100644 --- a/indra/newview/fsfloaterposer.h +++ b/indra/newview/fsfloaterposer.h @@ -77,8 +77,7 @@ class FSFloaterPoser : public LLFloater std::vector getUiSelectedPoserJoints(); LLVOAvatar *getUiSelectedAvatar(); E_BoneDeflectionStyles getUiSelectedBoneDeflectionStyle(); - void addRotationToRecentlySet(F32 yawInRadians, F32 pitchInRadians, F32 rollInRadians); - void clearRecentlySetRotations(); + void setSelectedJointsRotation(F32 yawInRadians, F32 pitchInRadians, F32 rollInRadians); void setSelectedJointsPosition(F32 x, F32 y, F32 z); void setSelectedJointsScale(F32 x, F32 y, F32 z); @@ -124,7 +123,6 @@ class FSFloaterPoser : public LLFloater private: FSPoserAnimator _poserAnimator; - std::stack _lastSetRotations; }; #endif diff --git a/indra/newview/fsvirtualtrackpad.cpp b/indra/newview/fsvirtualtrackpad.cpp new file mode 100644 index 0000000000..bffca5ed37 --- /dev/null +++ b/indra/newview/fsvirtualtrackpad.cpp @@ -0,0 +1,243 @@ +/** +* @file irtualTrackpad.cpp +* @author Angeldark Raymaker; derived from llVirtualTrackball by Andrey Lihatskiy +* @brief Header file for FSVirtualTrackpad +* +* $LicenseInfo:firstyear=2001&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2018, Linden Research, Inc. +* +* 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$ +*/ + +// A two dimensional slider control with optional pinch-mode. + +#include "fsvirtualtrackpad.h" +#include "llrect.h" +#include "lluictrlfactory.h" + +// Globals +static LLDefaultChildRegistry::Register register_virtual_trackball("fs_virtual_trackpad"); + +FSVirtualTrackpad::Params::Params() + : border("border"), + image_moon_back("image_moon_back"), + image_moon_front("image_moon_front"), + image_sphere("image_sphere"), + image_sun_back("image_sun_back"), + image_sun_front("image_sun_front"), + pinch_mode("pinch_mode") +{ +} + +FSVirtualTrackpad::FSVirtualTrackpad(const FSVirtualTrackpad::Params &p) + : LLUICtrl(p), + mImgMoonBack(p.image_moon_back), + mImgMoonFront(p.image_moon_front), + mImgSunBack(p.image_sun_back), + mImgSunFront(p.image_sun_front), + mImgSphere(p.image_sphere), + mAllowPinchMode(p.pinch_mode) +{ + LLRect border_rect = getLocalRect(); + S32 centerX = border_rect.getCenterX(); + S32 centerY = border_rect.getCenterY(); + + mValue.set(centerX, centerY); + mPinchValue.set(centerX, centerY); + mLastValue.set(centerX, centerY); + mLastPinchValue.set(centerX, centerY); + + LLViewBorder::Params border = p.border; + border.rect(border_rect); + mBorder = LLUICtrlFactory::create(border); + addChild(mBorder); + + LLPanel::Params touch_area; + touch_area.rect = LLRect(border_rect); + mTouchArea = LLUICtrlFactory::create(touch_area); + addChild(mTouchArea); +} + +FSVirtualTrackpad::~FSVirtualTrackpad() {} + +bool FSVirtualTrackpad::postBuild() +{ + return true; +} + +void FSVirtualTrackpad::drawThumb(const LLVector2 vec, bool isPinchThumb) +{ + LLUIImage *thumb = isPinchThumb ? mImgSunFront : mImgMoonFront; + + thumb->draw(LLRect(vec.mV[VX] - thumb->getWidth() / 2, + vec.mV[VY] + thumb->getHeight() / 2, + vec.mV[VX] + thumb->getWidth() / 2, + vec.mV[VY] - thumb->getHeight() / 2)); +} + +bool FSVirtualTrackpad::isPointInTouchArea(S32 x, S32 y) const +{ + if (!mTouchArea) + return false; + + return mTouchArea->getRect().localPointInRect(x, y); +} + +void FSVirtualTrackpad::draw() +{ + mImgSphere->draw(mTouchArea->getRect(), UI_VERTEX_COLOR); + + if (mAllowPinchMode) + drawThumb(mPinchValue, true); + + drawThumb(mValue, false); + + LLView::draw(); +} + +void FSVirtualTrackpad::setValue(const LLSD& value) +{ + if (value.isArray() && value.size() == 2) + mValue.setValue(value); +} + +void FSVirtualTrackpad::setValue(F32 x, F32 y) { mValue = convertNormalizedToPixelPos(x, y); } + +void FSVirtualTrackpad::setPinchValue(F32 x, F32 y) { mPinchValue = convertNormalizedToPixelPos(x, y); } + +void FSVirtualTrackpad::undoLastValue() { setValueAndCommit(mLastValue); } + +void FSVirtualTrackpad::undoLastSetPinchValue() { setPinchValueAndCommit(mLastValue); } + +void FSVirtualTrackpad::setValueAndCommit(const LLVector2 vec) +{ + mValue.set(vec); + onCommit(); +} + +void FSVirtualTrackpad::setPinchValueAndCommit(const LLVector2 vec) +{ + mPinchValue.set(vec); + onCommit(); +} + +LLSD FSVirtualTrackpad::getValue() const { return normalizePixelPosToCenter(mValue).getValue(); } + +LLSD FSVirtualTrackpad::getPinchValue() const { return normalizePixelPosToCenter(mPinchValue).getValue(); } + +bool FSVirtualTrackpad::handleHover(S32 x, S32 y, MASK mask) +{ + if (!hasMouseCapture()) + return true; + + bool slowMode = mask == MASK_CONTROL; + + LLRect rect = mTouchArea->getRect(); + rect.clampPointToRect(x, y); + + if (doingPinchMode) + mPinchValue.set(x, y); + else + mValue.set(x, y); + + onCommit(); + + return true; +} + +LLVector2 FSVirtualTrackpad::normalizePixelPosToCenter(LLVector2 pixelPos) const +{ + LLVector2 result; + if (!mTouchArea) + return result; + + LLRect rect = mTouchArea->getRect(); + S32 centerX = rect.getCenterX(); + S32 centerY = rect.getCenterY(); + S32 width = rect.getWidth(); + S32 height = rect.getHeight(); + + result.mV[VX] = (pixelPos.mV[VX] - centerX) / width * 2; + result.mV[VY] = (pixelPos.mV[VY] - centerY) / height * 2; + + return result; +} + +LLVector2 FSVirtualTrackpad::convertNormalizedToPixelPos(F32 x, F32 y) +{ + LLVector2 result; + if (!mTouchArea) + return result; + + LLRect rect = mTouchArea->getRect(); + S32 centerX = rect.getCenterX(); + S32 centerY = rect.getCenterY(); + S32 width = rect.getWidth(); + S32 height = rect.getHeight(); + + result.mV[VX] = (centerX + x * width / 2); + result.mV[VY] = (centerY + y * height / 2); + + return result; +} + +bool FSVirtualTrackpad::handleMouseUp(S32 x, S32 y, MASK mask) +{ + if (hasMouseCapture()) + { + doingPinchMode = false; + gFocusMgr.setMouseCapture(NULL); + + make_ui_sound("UISndClickRelease"); + } + + return LLView::handleMouseUp(x, y, mask); +} + +bool FSVirtualTrackpad::handleMouseDown(S32 x, S32 y, MASK mask) +{ + if (isPointInTouchArea(x, y)) + { + mLastValue.set(mValue); + gFocusMgr.setMouseCapture(this); + + make_ui_sound("UISndClick"); + } + + return LLView::handleMouseDown(x, y, mask); +} + +// move pinch cursor +bool FSVirtualTrackpad::handleRightMouseDown(S32 x, S32 y, MASK mask) +{ + if (!mAllowPinchMode) + return LLView::handleRightMouseDown(x, y, mask); + + if (isPointInTouchArea(x, y)) + { + mLastPinchValue.set(mPinchValue); + doingPinchMode = true; + gFocusMgr.setMouseCapture(this); + + make_ui_sound("UISndClick"); + } + + return LLView::handleRightMouseDown(x, y, mask); +} + diff --git a/indra/newview/fsvirtualtrackpad.h b/indra/newview/fsvirtualtrackpad.h new file mode 100644 index 0000000000..c12b097936 --- /dev/null +++ b/indra/newview/fsvirtualtrackpad.h @@ -0,0 +1,123 @@ +/** +* @file fsvirtualtrackpad.h +* @author Angeldark Raymaker; derived from llVirtualTrackball by Andrey Lihatskiy +* @brief Header file for FSVirtualTrackpad +* +* $LicenseInfo:firstyear=2001&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2018, Linden Research, Inc. +* +* 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$ +*/ + +// A two dimensional slider control with optional pinch-mode. + +#ifndef LL_FSVIRTUALTRACKPAD_H +#define LL_FSVIRTUALTRACKPAD_H + +#include "lluictrl.h" +#include "llpanel.h" + +class FSVirtualTrackpad + : public LLUICtrl +{ +public: + struct Params + : public LLInitParam::Block + { + Optional border; + Optional image_moon_back, image_moon_front, image_sphere, image_sun_back, image_sun_front; + Optional pinch_mode; + Optional allow_drag_outside; + + Params(); + }; + + + virtual ~FSVirtualTrackpad(); + /*virtual*/ bool postBuild(); + + virtual bool handleHover(S32 x, S32 y, MASK mask); + virtual bool handleMouseUp(S32 x, S32 y, MASK mask); + virtual bool handleMouseDown(S32 x, S32 y, MASK mask); + virtual bool handleRightMouseDown(S32 x, S32 y, MASK mask); + + virtual void draw(); + + virtual void setValue(const LLSD& value); + + /// + /// Sets the position of the cursor. + /// + /// The x-axis (left/right) position to set; expected range -1..1; left= -1 + /// The y-axis (top/bottom) position to set; expected range 1..-1; top = 1 + void setValue(F32 x, F32 y); + + void undoLastValue(); + void undoLastSetPinchValue(); + + /// + /// Sets the position of the second cursor. + /// + /// The normalized x-axis value (ordinarily screen left-right), expected left-to-right range -1..1. + /// The normalized y-axis value (ordinarily screen up-down), expected top-to-bottom range 1..-1 + void setPinchValue(F32 x, F32 y); + + virtual LLSD getValue() const; + virtual LLSD getPinchValue() const; + +protected: + friend class LLUICtrlFactory; + FSVirtualTrackpad(const Params&); + +protected: + LLPanel* mTouchArea; + LLViewBorder* mBorder; + +private: + void setValueAndCommit(const LLVector2 vec); + void setPinchValueAndCommit(const LLVector2 vec); + void drawThumb(LLVector2 vec, bool isPinchThumb); + bool isPointInTouchArea(S32 x, S32 y) const; + LLVector2 normalizePixelPosToCenter(LLVector2 vec) const; + LLVector2 convertNormalizedToPixelPos(F32 x, F32 y); + + LLUIImage* mImgMoonBack; + LLUIImage* mImgMoonFront; + LLUIImage* mImgSunBack; + LLUIImage* mImgSunFront; + LLUIImage* mImgSphere; + + /// + /// Whether we allow the second cursor to appear. + /// + bool mAllowPinchMode = false; + + /// + /// Whether we should be moving the pinch cursor now + /// + bool doingPinchMode = false; + + LLVector2 mValue; + LLVector2 mPinchValue; + LLVector2 mLastValue; + LLVector2 mLastPinchValue; +}; + +#endif + diff --git a/indra/newview/skins/default/xui/en/floater_poser.xml b/indra/newview/skins/default/xui/en/floater_poser.xml index a95a7a7796..add6511759 100644 --- a/indra/newview/skins/default/xui/en/floater_poser.xml +++ b/indra/newview/skins/default/xui/en/floater_poser.xml @@ -510,13 +510,13 @@ width="565"> left="5" top="2" width="105">Rotation: - + + + + + +