diff options
author | Andrey Lihatskiy <alihatskiy@productengine.com> | 2024-05-22 20:51:58 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-05-22 20:51:58 +0300 |
commit | 6cc7dd09d5e69cf57e6de7fb568a0ad2693f9c9a (patch) | |
tree | fab23811a5cedc1ebf01479c852ee92ff62b636c /indra/newview/lljoystickbutton.cpp | |
parent | ef8f4819822288e044ea719feb6af7a1f4df4c4e (diff) | |
parent | 7bb5afc11ee5a6af78302a8d76a9a619e2baaab2 (diff) |
Merge pull request #1545 from Ansariel/DRTVWR-600-maint-A
Merge main into DRTVWR-600-maint-a
Diffstat (limited to 'indra/newview/lljoystickbutton.cpp')
-rw-r--r-- | indra/newview/lljoystickbutton.cpp | 1888 |
1 files changed, 944 insertions, 944 deletions
diff --git a/indra/newview/lljoystickbutton.cpp b/indra/newview/lljoystickbutton.cpp index 7aea9c36bc..18180b9923 100644 --- a/indra/newview/lljoystickbutton.cpp +++ b/indra/newview/lljoystickbutton.cpp @@ -1,944 +1,944 @@ -/** - * @file lljoystickbutton.cpp - * @brief LLJoystick class implementation - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, 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$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "lljoystickbutton.h" - -// Library includes -#include "llcoord.h" -#include "indra_constants.h" -#include "llrender.h" - -// Project includes -#include "llui.h" -#include "llagent.h" -#include "llagentcamera.h" -#include "llviewercamera.h" -#include "llviewertexture.h" -#include "llviewertexturelist.h" -#include "llviewerwindow.h" -#include "llmoveview.h" - -#include "llglheaders.h" - -static LLDefaultChildRegistry::Register<LLJoystickAgentSlide> r1("joystick_slide"); -static LLDefaultChildRegistry::Register<LLJoystickAgentTurn> r2("joystick_turn"); -static LLDefaultChildRegistry::Register<LLJoystickCameraRotate> r3("joystick_rotate"); -static LLDefaultChildRegistry::Register<LLJoystickCameraTrack> r5("joystick_track"); -static LLDefaultChildRegistry::Register<LLJoystickQuaternion> r6("joystick_quat"); - - -const F32 NUDGE_TIME = 0.25f; // in seconds -const F32 ORBIT_NUDGE_RATE = 0.05f; // fraction of normal speed - -const S32 CENTER_DOT_RADIUS = 7; - -// -// Public Methods -// -void QuadrantNames::declareValues() -{ - declare("origin", JQ_ORIGIN); - declare("up", JQ_UP); - declare("down", JQ_DOWN); - declare("left", JQ_LEFT); - declare("right", JQ_RIGHT); -} - - -LLJoystick::LLJoystick(const LLJoystick::Params& p) -: LLButton(p), - mInitialOffset(0, 0), - mLastMouse(0, 0), - mFirstMouse(0, 0), - mVertSlopNear(0), - mVertSlopFar(0), - mHorizSlopNear(0), - mHorizSlopFar(0), - mHeldDown(false), - mHeldDownTimer(), - mInitialQuadrant(p.quadrant) -{ - setHeldDownCallback(&LLJoystick::onBtnHeldDown, this); -} - - -void LLJoystick::updateSlop() -{ - mVertSlopNear = getRect().getHeight(); - mVertSlopFar = getRect().getHeight() * 2; - - mHorizSlopNear = getRect().getWidth(); - mHorizSlopFar = getRect().getWidth() * 2; - - // Compute initial mouse offset based on initial quadrant. - // Place the mouse evenly between the near and far zones. - switch (mInitialQuadrant) - { - case JQ_ORIGIN: - mInitialOffset.set(0, 0); - break; - - case JQ_UP: - mInitialOffset.mX = 0; - mInitialOffset.mY = (mVertSlopNear + mVertSlopFar) / 2; - break; - - case JQ_DOWN: - mInitialOffset.mX = 0; - mInitialOffset.mY = - (mVertSlopNear + mVertSlopFar) / 2; - break; - - case JQ_LEFT: - mInitialOffset.mX = - (mHorizSlopNear + mHorizSlopFar) / 2; - mInitialOffset.mY = 0; - break; - - case JQ_RIGHT: - mInitialOffset.mX = (mHorizSlopNear + mHorizSlopFar) / 2; - mInitialOffset.mY = 0; - break; - - default: - LL_ERRS() << "LLJoystick::LLJoystick() - bad switch case" << LL_ENDL; - break; - } - - return; -} - -bool LLJoystick::pointInCircle(S32 x, S32 y) const -{ - if(this->getLocalRect().getHeight() != this->getLocalRect().getWidth()) - { - LL_WARNS() << "Joystick shape is not square"<<LL_ENDL; - return true; - } - //center is x and y coordinates of center of joystick circle, and also its radius - int center = this->getLocalRect().getHeight()/2; - bool in_circle = (x - center) * (x - center) + (y - center) * (y - center) <= center * center; - - return in_circle; -} - -bool LLJoystick::pointInCenterDot(S32 x, S32 y, S32 radius) const -{ - if (this->getLocalRect().getHeight() != this->getLocalRect().getWidth()) - { - LL_WARNS() << "Joystick shape is not square" << LL_ENDL; - return true; - } - - S32 center = this->getLocalRect().getHeight() / 2; - - bool in_center_circle = (x - center) * (x - center) + (y - center) * (y - center) <= radius * radius; - - return in_center_circle; -} - -bool LLJoystick::handleMouseDown(S32 x, S32 y, MASK mask) -{ - //LL_INFOS() << "joystick mouse down " << x << ", " << y << LL_ENDL; - bool handles = false; - - if(pointInCircle(x, y)) - { - mLastMouse.set(x, y); - mFirstMouse.set(x, y); - mMouseDownTimer.reset(); - handles = LLButton::handleMouseDown(x, y, mask); - } - - return handles; -} - - -bool LLJoystick::handleMouseUp(S32 x, S32 y, MASK mask) -{ - // LL_INFOS() << "joystick mouse up " << x << ", " << y << LL_ENDL; - - if( hasMouseCapture() ) - { - mLastMouse.set(x, y); - mHeldDown = false; - onMouseUp(); - } - - return LLButton::handleMouseUp(x, y, mask); -} - - -bool LLJoystick::handleHover(S32 x, S32 y, MASK mask) -{ - if( hasMouseCapture() ) - { - mLastMouse.set(x, y); - } - - return LLButton::handleHover(x, y, mask); -} - -F32 LLJoystick::getElapsedHeldDownTime() -{ - if( mHeldDown ) - { - return getHeldDownTime(); - } - else - { - return 0.f; - } -} - -// static -void LLJoystick::onBtnHeldDown(void *userdata) -{ - LLJoystick *self = (LLJoystick *)userdata; - if (self) - { - self->mHeldDown = true; - self->onHeldDown(); - } -} - -EJoystickQuadrant LLJoystick::selectQuadrant(LLXMLNodePtr node) -{ - - EJoystickQuadrant quadrant = JQ_RIGHT; - - if (node->hasAttribute("quadrant")) - { - std::string quadrant_name; - node->getAttributeString("quadrant", quadrant_name); - - quadrant = quadrantFromName(quadrant_name); - } - return quadrant; -} - - -std::string LLJoystick::nameFromQuadrant(EJoystickQuadrant quadrant) -{ - if (quadrant == JQ_ORIGIN) return std::string("origin"); - else if (quadrant == JQ_UP) return std::string("up"); - else if (quadrant == JQ_DOWN) return std::string("down"); - else if (quadrant == JQ_LEFT) return std::string("left"); - else if (quadrant == JQ_RIGHT) return std::string("right"); - else return std::string(); -} - - -EJoystickQuadrant LLJoystick::quadrantFromName(const std::string& sQuadrant) -{ - EJoystickQuadrant quadrant = JQ_RIGHT; - - if (sQuadrant == "origin") - { - quadrant = JQ_ORIGIN; - } - else if (sQuadrant == "up") - { - quadrant = JQ_UP; - } - else if (sQuadrant == "down") - { - quadrant = JQ_DOWN; - } - else if (sQuadrant == "left") - { - quadrant = JQ_LEFT; - } - else if (sQuadrant == "right") - { - quadrant = JQ_RIGHT; - } - - return quadrant; -} - - -//------------------------------------------------------------------------------- -// LLJoystickAgentTurn -//------------------------------------------------------------------------------- - -void LLJoystickAgentTurn::onHeldDown() -{ - F32 time = getElapsedHeldDownTime(); - updateSlop(); - - //LL_INFOS() << "move forward/backward (and/or turn)" << LL_ENDL; - - S32 dx = mLastMouse.mX - mFirstMouse.mX + mInitialOffset.mX; - S32 dy = mLastMouse.mY - mFirstMouse.mY + mInitialOffset.mY; - - float m = (float) (dx)/abs(dy); - - if (m > 1) { - m = 1; - } - else if (m < -1) { - m = -1; - } - gAgent.moveYaw(-LLFloaterMove::getYawRate(time)*m); - - - // handle forward/back movement - if (dy > mVertSlopFar) - { - // ...if mouse is forward of run region run forward - gAgent.moveAt(1); - } - else if (dy > mVertSlopNear) - { - if( time < NUDGE_TIME ) - { - gAgent.moveAtNudge(1); - } - else - { - // ...else if mouse is forward of walk region walk forward - // JC 9/5/2002 - Always run / move quickly. - gAgent.moveAt(1); - } - } - else if (dy < -mVertSlopFar) - { - // ...else if mouse is behind run region run backward - gAgent.moveAt(-1); - } - else if (dy < -mVertSlopNear) - { - if( time < NUDGE_TIME ) - { - gAgent.moveAtNudge(-1); - } - else - { - // ...else if mouse is behind walk region walk backward - // JC 9/5/2002 - Always run / move quickly. - gAgent.moveAt(-1); - } - } -} - -//------------------------------------------------------------------------------- -// LLJoystickAgentSlide -//------------------------------------------------------------------------------- - -void LLJoystickAgentSlide::onMouseUp() -{ - F32 time = getElapsedHeldDownTime(); - if( time < NUDGE_TIME ) - { - switch (mInitialQuadrant) - { - case JQ_LEFT: - gAgent.moveLeftNudge(1); - break; - - case JQ_RIGHT: - gAgent.moveLeftNudge(-1); - break; - - default: - break; - } - } -} - -void LLJoystickAgentSlide::onHeldDown() -{ - //LL_INFOS() << "slide left/right (and/or move forward/backward)" << LL_ENDL; - - updateSlop(); - - S32 dx = mLastMouse.mX - mFirstMouse.mX + mInitialOffset.mX; - S32 dy = mLastMouse.mY - mFirstMouse.mY + mInitialOffset.mY; - - // handle left-right sliding - if (dx > mHorizSlopNear) - { - gAgent.moveLeft(-1); - } - else if (dx < -mHorizSlopNear) - { - gAgent.moveLeft(1); - } - - // handle forward/back movement - if (dy > mVertSlopFar) - { - // ...if mouse is forward of run region run forward - gAgent.moveAt(1); - } - else if (dy > mVertSlopNear) - { - // ...else if mouse is forward of walk region walk forward - gAgent.moveAtNudge(1); - } - else if (dy < -mVertSlopFar) - { - // ...else if mouse is behind run region run backward - gAgent.moveAt(-1); - } - else if (dy < -mVertSlopNear) - { - // ...else if mouse is behind walk region walk backward - gAgent.moveAtNudge(-1); - } -} - - -//------------------------------------------------------------------------------- -// LLJoystickCameraRotate -//------------------------------------------------------------------------------- - -LLJoystickCameraRotate::LLJoystickCameraRotate(const LLJoystickCameraRotate::Params& p) -: LLJoystick(p), - mInLeft( false ), - mInTop( false ), - mInRight( false ), - mInBottom( false ), - mInCenter( false ) -{ - mCenterImageName = "Cam_Rotate_Center"; -} - - -void LLJoystickCameraRotate::updateSlop() -{ - // do the initial offset calculation based on mousedown location - - // small fixed slop region - mVertSlopNear = 16; - mVertSlopFar = 32; - - mHorizSlopNear = 16; - mHorizSlopFar = 32; - - return; -} - - -bool LLJoystickCameraRotate::handleMouseDown(S32 x, S32 y, MASK mask) -{ - gAgent.setMovementLocked(true); - updateSlop(); - - // Set initial offset based on initial click location - S32 horiz_center = getRect().getWidth() / 2; - S32 vert_center = getRect().getHeight() / 2; - - S32 dx = x - horiz_center; - S32 dy = y - vert_center; - - if (pointInCenterDot(x, y, CENTER_DOT_RADIUS)) - { - mInitialOffset.mX = 0; - mInitialOffset.mY = 0; - mInitialQuadrant = JQ_ORIGIN; - mInCenter = true; - - resetJoystickCamera(); - } - else if (dy > dx && dy > -dx) - { - // top - mInitialOffset.mX = 0; - mInitialOffset.mY = (mVertSlopNear + mVertSlopFar) / 2; - mInitialQuadrant = JQ_UP; - } - else if (dy > dx && dy <= -dx) - { - // left - mInitialOffset.mX = - (mHorizSlopNear + mHorizSlopFar) / 2; - mInitialOffset.mY = 0; - mInitialQuadrant = JQ_LEFT; - } - else if (dy <= dx && dy <= -dx) - { - // bottom - mInitialOffset.mX = 0; - mInitialOffset.mY = - (mVertSlopNear + mVertSlopFar) / 2; - mInitialQuadrant = JQ_DOWN; - } - else - { - // right - mInitialOffset.mX = (mHorizSlopNear + mHorizSlopFar) / 2; - mInitialOffset.mY = 0; - mInitialQuadrant = JQ_RIGHT; - } - - return LLJoystick::handleMouseDown(x, y, mask); -} - -bool LLJoystickCameraRotate::handleMouseUp(S32 x, S32 y, MASK mask) -{ - gAgent.setMovementLocked(false); - mInCenter = false; - return LLJoystick::handleMouseUp(x, y, mask); -} - -bool LLJoystickCameraRotate::handleHover(S32 x, S32 y, MASK mask) -{ - if (!pointInCenterDot(x, y, CENTER_DOT_RADIUS)) - { - mInCenter = false; - } - - return LLJoystick::handleHover(x, y, mask); -} - -void LLJoystickCameraRotate::onHeldDown() -{ - updateSlop(); - - S32 dx = mLastMouse.mX - mFirstMouse.mX + mInitialOffset.mX; - S32 dy = mLastMouse.mY - mFirstMouse.mY + mInitialOffset.mY; - - // left-right rotation - if (dx > mHorizSlopNear) - { - gAgentCamera.unlockView(); - gAgentCamera.setOrbitLeftKey(getOrbitRate()); - } - else if (dx < -mHorizSlopNear) - { - gAgentCamera.unlockView(); - gAgentCamera.setOrbitRightKey(getOrbitRate()); - } - - // over/under rotation - if (dy > mVertSlopNear) - { - gAgentCamera.unlockView(); - gAgentCamera.setOrbitUpKey(getOrbitRate()); - } - else if (dy < -mVertSlopNear) - { - gAgentCamera.unlockView(); - gAgentCamera.setOrbitDownKey(getOrbitRate()); - } -} - -void LLJoystickCameraRotate::resetJoystickCamera() -{ - gAgentCamera.resetCameraOrbit(); -} - -F32 LLJoystickCameraRotate::getOrbitRate() -{ - F32 time = getElapsedHeldDownTime(); - if( time < NUDGE_TIME ) - { - F32 rate = ORBIT_NUDGE_RATE + time * (1 - ORBIT_NUDGE_RATE)/ NUDGE_TIME; - //LL_INFOS() << rate << LL_ENDL; - return rate; - } - else - { - return 1; - } -} - - -// Only used for drawing -void LLJoystickCameraRotate::setToggleState( bool left, bool top, bool right, bool bottom ) -{ - mInLeft = left; - mInTop = top; - mInRight = right; - mInBottom = bottom; -} - -void LLJoystickCameraRotate::draw() -{ - LLGLSUIDefault gls_ui; - - getImageUnselected()->draw( 0, 0 ); - LLPointer<LLUIImage> image = getImageSelected(); - - if (mInCenter) - { - drawRotatedImage(LLUI::getUIImage(mCenterImageName), 0); - } - else - { - if (mInTop) - { - drawRotatedImage(getImageSelected(), 0); - } - - if (mInRight) - { - drawRotatedImage(getImageSelected(), 1); - } - - if (mInBottom) - { - drawRotatedImage(getImageSelected(), 2); - } - - if (mInLeft) - { - drawRotatedImage(getImageSelected(), 3); - } - } -} - -// Draws image rotated by multiples of 90 degrees -void LLJoystickCameraRotate::drawRotatedImage( LLPointer<LLUIImage> image, S32 rotations ) -{ - S32 width = image->getWidth(); - S32 height = image->getHeight(); - LLTexture* texture = image->getImage(); - - /* - * Scale texture coordinate system - * to handle the different between image size and size of texture. - * If we will use default matrix, - * it may break texture mapping after rotation. - * see EXT-2023 Camera floater: arrows became shifted when pressed. - */ - F32 uv[][2] = - { - { (F32)width/texture->getWidth(), (F32)height/texture->getHeight() }, - { 0.f, (F32)height/texture->getHeight() }, - { 0.f, 0.f }, - { (F32)width/texture->getWidth(), 0.f } - }; - - gGL.getTexUnit(0)->bind(texture); - - gGL.color4fv(UI_VERTEX_COLOR.mV); - - gGL.begin(LLRender::QUADS); - { - gGL.texCoord2fv( uv[ (rotations + 0) % 4]); - gGL.vertex2i(width, height ); - - gGL.texCoord2fv( uv[ (rotations + 1) % 4]); - gGL.vertex2i(0, height ); - - gGL.texCoord2fv( uv[ (rotations + 2) % 4]); - gGL.vertex2i(0, 0); - - gGL.texCoord2fv( uv[ (rotations + 3) % 4]); - gGL.vertex2i(width, 0); - } - gGL.end(); -} - - - -//------------------------------------------------------------------------------- -// LLJoystickCameraTrack -//------------------------------------------------------------------------------- - -LLJoystickCameraTrack::Params::Params() -{ - held_down_delay.seconds(0.0); -} - -LLJoystickCameraTrack::LLJoystickCameraTrack(const LLJoystickCameraTrack::Params& p) -: LLJoystickCameraRotate(p) -{ - mCenterImageName = "Cam_Tracking_Center"; -} - - -void LLJoystickCameraTrack::onHeldDown() -{ - updateSlop(); - - S32 dx = mLastMouse.mX - mFirstMouse.mX + mInitialOffset.mX; - S32 dy = mLastMouse.mY - mFirstMouse.mY + mInitialOffset.mY; - - if (dx > mVertSlopNear) - { - gAgentCamera.unlockView(); - gAgentCamera.setPanRightKey(getOrbitRate()); - } - else if (dx < -mVertSlopNear) - { - gAgentCamera.unlockView(); - gAgentCamera.setPanLeftKey(getOrbitRate()); - } - - // over/under rotation - if (dy > mVertSlopNear) - { - gAgentCamera.unlockView(); - gAgentCamera.setPanUpKey(getOrbitRate()); - } - else if (dy < -mVertSlopNear) - { - gAgentCamera.unlockView(); - gAgentCamera.setPanDownKey(getOrbitRate()); - } -} - -void LLJoystickCameraTrack::resetJoystickCamera() -{ - gAgentCamera.resetCameraPan(); -} - -//------------------------------------------------------------------------------- -// LLJoystickQuaternion -//------------------------------------------------------------------------------- - -LLJoystickQuaternion::Params::Params() -{ -} - -LLJoystickQuaternion::LLJoystickQuaternion(const LLJoystickQuaternion::Params &p): - LLJoystick(p), - mInLeft(false), - mInTop(false), - mInRight(false), - mInBottom(false), - mVectorZero(0.0f, 0.0f, 1.0f), - mRotation(), - mUpDnAxis(1.0f, 0.0f, 0.0f), - mLfRtAxis(0.0f, 0.0f, 1.0f), - mXAxisIndex(2), // left & right across the control - mYAxisIndex(0), // up & down across the control - mZAxisIndex(1) // tested for above and below -{ - for (int i = 0; i < 3; ++i) - { - mLfRtAxis.mV[i] = (mXAxisIndex == i) ? 1.0 : 0.0; - mUpDnAxis.mV[i] = (mYAxisIndex == i) ? 1.0 : 0.0; - } -} - -void LLJoystickQuaternion::setToggleState(bool left, bool top, bool right, bool bottom) -{ - mInLeft = left; - mInTop = top; - mInRight = right; - mInBottom = bottom; -} - -bool LLJoystickQuaternion::handleMouseDown(S32 x, S32 y, MASK mask) -{ - updateSlop(); - - // Set initial offset based on initial click location - S32 horiz_center = getRect().getWidth() / 2; - S32 vert_center = getRect().getHeight() / 2; - - S32 dx = x - horiz_center; - S32 dy = y - vert_center; - - if (dy > dx && dy > -dx) - { - // top - mInitialOffset.mX = 0; - mInitialOffset.mY = (mVertSlopNear + mVertSlopFar) / 2; - mInitialQuadrant = JQ_UP; - } - else if (dy > dx && dy <= -dx) - { - // left - mInitialOffset.mX = -(mHorizSlopNear + mHorizSlopFar) / 2; - mInitialOffset.mY = 0; - mInitialQuadrant = JQ_LEFT; - } - else if (dy <= dx && dy <= -dx) - { - // bottom - mInitialOffset.mX = 0; - mInitialOffset.mY = -(mVertSlopNear + mVertSlopFar) / 2; - mInitialQuadrant = JQ_DOWN; - } - else - { - // right - mInitialOffset.mX = (mHorizSlopNear + mHorizSlopFar) / 2; - mInitialOffset.mY = 0; - mInitialQuadrant = JQ_RIGHT; - } - - return LLJoystick::handleMouseDown(x, y, mask); -} - -bool LLJoystickQuaternion::handleMouseUp(S32 x, S32 y, MASK mask) -{ - return LLJoystick::handleMouseUp(x, y, mask); -} - -void LLJoystickQuaternion::onHeldDown() -{ - LLVector3 axis; - updateSlop(); - - S32 dx = mLastMouse.mX - mFirstMouse.mX + mInitialOffset.mX; - S32 dy = mLastMouse.mY - mFirstMouse.mY + mInitialOffset.mY; - - // left-right rotation - if (dx > mHorizSlopNear) - { - axis += mUpDnAxis; - } - else if (dx < -mHorizSlopNear) - { - axis -= mUpDnAxis; - } - - // over/under rotation - if (dy > mVertSlopNear) - { - axis += mLfRtAxis; - } - else if (dy < -mVertSlopNear) - { - axis -= mLfRtAxis; - } - - if (axis.isNull()) - return; - - axis.normalize(); - - LLQuaternion delta; - delta.setAngleAxis(0.0523599f, axis); // about 3deg - - mRotation *= delta; - setValue(mRotation.getValue()); - onCommit(); -} - -void LLJoystickQuaternion::draw() -{ - LLGLSUIDefault gls_ui; - - getImageUnselected()->draw(0, 0); - LLPointer<LLUIImage> image = getImageSelected(); - - if (mInTop) - { - drawRotatedImage(getImageSelected(), 0); - } - - if (mInRight) - { - drawRotatedImage(getImageSelected(), 1); - } - - if (mInBottom) - { - drawRotatedImage(getImageSelected(), 2); - } - - if (mInLeft) - { - drawRotatedImage(getImageSelected(), 3); - } - - LLVector3 draw_point = mVectorZero * mRotation; - S32 halfwidth = getRect().getWidth() / 2; - S32 halfheight = getRect().getHeight() / 2; - draw_point.mV[mXAxisIndex] = (draw_point.mV[mXAxisIndex] + 1.0) * halfwidth; - draw_point.mV[mYAxisIndex] = (draw_point.mV[mYAxisIndex] + 1.0) * halfheight; - - gl_circle_2d(draw_point.mV[mXAxisIndex], draw_point.mV[mYAxisIndex], 4, 8, - draw_point.mV[mZAxisIndex] >= 0.f); - -} - -F32 LLJoystickQuaternion::getOrbitRate() -{ - return 1; -} - -void LLJoystickQuaternion::updateSlop() -{ - // small fixed slop region - mVertSlopNear = 16; - mVertSlopFar = 32; - - mHorizSlopNear = 16; - mHorizSlopFar = 32; -} - -void LLJoystickQuaternion::drawRotatedImage(LLPointer<LLUIImage> image, S32 rotations) -{ - S32 width = image->getWidth(); - S32 height = image->getHeight(); - LLTexture* texture = image->getImage(); - - /* - * Scale texture coordinate system - * to handle the different between image size and size of texture. - */ - F32 uv[][2] = - { - { (F32)width / texture->getWidth(), (F32)height / texture->getHeight() }, - { 0.f, (F32)height / texture->getHeight() }, - { 0.f, 0.f }, - { (F32)width / texture->getWidth(), 0.f } - }; - - gGL.getTexUnit(0)->bind(texture); - - gGL.color4fv(UI_VERTEX_COLOR.mV); - - gGL.begin(LLRender::QUADS); - { - gGL.texCoord2fv(uv[(rotations + 0) % 4]); - gGL.vertex2i(width, height); - - gGL.texCoord2fv(uv[(rotations + 1) % 4]); - gGL.vertex2i(0, height); - - gGL.texCoord2fv(uv[(rotations + 2) % 4]); - gGL.vertex2i(0, 0); - - gGL.texCoord2fv(uv[(rotations + 3) % 4]); - gGL.vertex2i(width, 0); - } - gGL.end(); -} - -void LLJoystickQuaternion::setRotation(const LLQuaternion &value) -{ - if (value != mRotation) - { - mRotation = value; - mRotation.normalize(); - LLJoystick::setValue(mRotation.getValue()); - } -} - -LLQuaternion LLJoystickQuaternion::getRotation() const -{ - return mRotation; -} - - +/**
+ * @file lljoystickbutton.cpp
+ * @brief LLJoystick class implementation
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, 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$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "lljoystickbutton.h"
+
+// Library includes
+#include "llcoord.h"
+#include "indra_constants.h"
+#include "llrender.h"
+
+// Project includes
+#include "llui.h"
+#include "llagent.h"
+#include "llagentcamera.h"
+#include "llviewercamera.h"
+#include "llviewertexture.h"
+#include "llviewertexturelist.h"
+#include "llviewerwindow.h"
+#include "llmoveview.h"
+
+#include "llglheaders.h"
+
+static LLDefaultChildRegistry::Register<LLJoystickAgentSlide> r1("joystick_slide");
+static LLDefaultChildRegistry::Register<LLJoystickAgentTurn> r2("joystick_turn");
+static LLDefaultChildRegistry::Register<LLJoystickCameraRotate> r3("joystick_rotate");
+static LLDefaultChildRegistry::Register<LLJoystickCameraTrack> r5("joystick_track");
+static LLDefaultChildRegistry::Register<LLJoystickQuaternion> r6("joystick_quat");
+
+
+const F32 NUDGE_TIME = 0.25f; // in seconds
+const F32 ORBIT_NUDGE_RATE = 0.05f; // fraction of normal speed
+
+const S32 CENTER_DOT_RADIUS = 7;
+
+//
+// Public Methods
+//
+void QuadrantNames::declareValues()
+{
+ declare("origin", JQ_ORIGIN);
+ declare("up", JQ_UP);
+ declare("down", JQ_DOWN);
+ declare("left", JQ_LEFT);
+ declare("right", JQ_RIGHT);
+}
+
+
+LLJoystick::LLJoystick(const LLJoystick::Params& p)
+: LLButton(p),
+ mInitialOffset(0, 0),
+ mLastMouse(0, 0),
+ mFirstMouse(0, 0),
+ mVertSlopNear(0),
+ mVertSlopFar(0),
+ mHorizSlopNear(0),
+ mHorizSlopFar(0),
+ mHeldDown(false),
+ mHeldDownTimer(),
+ mInitialQuadrant(p.quadrant)
+{
+ setHeldDownCallback(&LLJoystick::onBtnHeldDown, this);
+}
+
+
+void LLJoystick::updateSlop()
+{
+ mVertSlopNear = getRect().getHeight();
+ mVertSlopFar = getRect().getHeight() * 2;
+
+ mHorizSlopNear = getRect().getWidth();
+ mHorizSlopFar = getRect().getWidth() * 2;
+
+ // Compute initial mouse offset based on initial quadrant.
+ // Place the mouse evenly between the near and far zones.
+ switch (mInitialQuadrant)
+ {
+ case JQ_ORIGIN:
+ mInitialOffset.set(0, 0);
+ break;
+
+ case JQ_UP:
+ mInitialOffset.mX = 0;
+ mInitialOffset.mY = (mVertSlopNear + mVertSlopFar) / 2;
+ break;
+
+ case JQ_DOWN:
+ mInitialOffset.mX = 0;
+ mInitialOffset.mY = - (mVertSlopNear + mVertSlopFar) / 2;
+ break;
+
+ case JQ_LEFT:
+ mInitialOffset.mX = - (mHorizSlopNear + mHorizSlopFar) / 2;
+ mInitialOffset.mY = 0;
+ break;
+
+ case JQ_RIGHT:
+ mInitialOffset.mX = (mHorizSlopNear + mHorizSlopFar) / 2;
+ mInitialOffset.mY = 0;
+ break;
+
+ default:
+ LL_ERRS() << "LLJoystick::LLJoystick() - bad switch case" << LL_ENDL;
+ break;
+ }
+
+ return;
+}
+
+bool LLJoystick::pointInCircle(S32 x, S32 y) const
+{
+ if(this->getLocalRect().getHeight() != this->getLocalRect().getWidth())
+ {
+ LL_WARNS() << "Joystick shape is not square"<<LL_ENDL;
+ return true;
+ }
+ //center is x and y coordinates of center of joystick circle, and also its radius
+ int center = this->getLocalRect().getHeight()/2;
+ bool in_circle = (x - center) * (x - center) + (y - center) * (y - center) <= center * center;
+
+ return in_circle;
+}
+
+bool LLJoystick::pointInCenterDot(S32 x, S32 y, S32 radius) const
+{
+ if (this->getLocalRect().getHeight() != this->getLocalRect().getWidth())
+ {
+ LL_WARNS() << "Joystick shape is not square" << LL_ENDL;
+ return true;
+ }
+
+ S32 center = this->getLocalRect().getHeight() / 2;
+
+ bool in_center_circle = (x - center) * (x - center) + (y - center) * (y - center) <= radius * radius;
+
+ return in_center_circle;
+}
+
+bool LLJoystick::handleMouseDown(S32 x, S32 y, MASK mask)
+{
+ //LL_INFOS() << "joystick mouse down " << x << ", " << y << LL_ENDL;
+ bool handles = false;
+
+ if(pointInCircle(x, y))
+ {
+ mLastMouse.set(x, y);
+ mFirstMouse.set(x, y);
+ mMouseDownTimer.reset();
+ handles = LLButton::handleMouseDown(x, y, mask);
+ }
+
+ return handles;
+}
+
+
+bool LLJoystick::handleMouseUp(S32 x, S32 y, MASK mask)
+{
+ // LL_INFOS() << "joystick mouse up " << x << ", " << y << LL_ENDL;
+
+ if( hasMouseCapture() )
+ {
+ mLastMouse.set(x, y);
+ mHeldDown = false;
+ onMouseUp();
+ }
+
+ return LLButton::handleMouseUp(x, y, mask);
+}
+
+
+bool LLJoystick::handleHover(S32 x, S32 y, MASK mask)
+{
+ if( hasMouseCapture() )
+ {
+ mLastMouse.set(x, y);
+ }
+
+ return LLButton::handleHover(x, y, mask);
+}
+
+F32 LLJoystick::getElapsedHeldDownTime()
+{
+ if( mHeldDown )
+ {
+ return getHeldDownTime();
+ }
+ else
+ {
+ return 0.f;
+ }
+}
+
+// static
+void LLJoystick::onBtnHeldDown(void *userdata)
+{
+ LLJoystick *self = (LLJoystick *)userdata;
+ if (self)
+ {
+ self->mHeldDown = true;
+ self->onHeldDown();
+ }
+}
+
+EJoystickQuadrant LLJoystick::selectQuadrant(LLXMLNodePtr node)
+{
+
+ EJoystickQuadrant quadrant = JQ_RIGHT;
+
+ if (node->hasAttribute("quadrant"))
+ {
+ std::string quadrant_name;
+ node->getAttributeString("quadrant", quadrant_name);
+
+ quadrant = quadrantFromName(quadrant_name);
+ }
+ return quadrant;
+}
+
+
+std::string LLJoystick::nameFromQuadrant(EJoystickQuadrant quadrant)
+{
+ if (quadrant == JQ_ORIGIN) return std::string("origin");
+ else if (quadrant == JQ_UP) return std::string("up");
+ else if (quadrant == JQ_DOWN) return std::string("down");
+ else if (quadrant == JQ_LEFT) return std::string("left");
+ else if (quadrant == JQ_RIGHT) return std::string("right");
+ else return std::string();
+}
+
+
+EJoystickQuadrant LLJoystick::quadrantFromName(const std::string& sQuadrant)
+{
+ EJoystickQuadrant quadrant = JQ_RIGHT;
+
+ if (sQuadrant == "origin")
+ {
+ quadrant = JQ_ORIGIN;
+ }
+ else if (sQuadrant == "up")
+ {
+ quadrant = JQ_UP;
+ }
+ else if (sQuadrant == "down")
+ {
+ quadrant = JQ_DOWN;
+ }
+ else if (sQuadrant == "left")
+ {
+ quadrant = JQ_LEFT;
+ }
+ else if (sQuadrant == "right")
+ {
+ quadrant = JQ_RIGHT;
+ }
+
+ return quadrant;
+}
+
+
+//-------------------------------------------------------------------------------
+// LLJoystickAgentTurn
+//-------------------------------------------------------------------------------
+
+void LLJoystickAgentTurn::onHeldDown()
+{
+ F32 time = getElapsedHeldDownTime();
+ updateSlop();
+
+ //LL_INFOS() << "move forward/backward (and/or turn)" << LL_ENDL;
+
+ S32 dx = mLastMouse.mX - mFirstMouse.mX + mInitialOffset.mX;
+ S32 dy = mLastMouse.mY - mFirstMouse.mY + mInitialOffset.mY;
+
+ float m = (float) (dx)/abs(dy);
+
+ if (m > 1) {
+ m = 1;
+ }
+ else if (m < -1) {
+ m = -1;
+ }
+ gAgent.moveYaw(-LLFloaterMove::getYawRate(time)*m);
+
+
+ // handle forward/back movement
+ if (dy > mVertSlopFar)
+ {
+ // ...if mouse is forward of run region run forward
+ gAgent.moveAt(1);
+ }
+ else if (dy > mVertSlopNear)
+ {
+ if( time < NUDGE_TIME )
+ {
+ gAgent.moveAtNudge(1);
+ }
+ else
+ {
+ // ...else if mouse is forward of walk region walk forward
+ // JC 9/5/2002 - Always run / move quickly.
+ gAgent.moveAt(1);
+ }
+ }
+ else if (dy < -mVertSlopFar)
+ {
+ // ...else if mouse is behind run region run backward
+ gAgent.moveAt(-1);
+ }
+ else if (dy < -mVertSlopNear)
+ {
+ if( time < NUDGE_TIME )
+ {
+ gAgent.moveAtNudge(-1);
+ }
+ else
+ {
+ // ...else if mouse is behind walk region walk backward
+ // JC 9/5/2002 - Always run / move quickly.
+ gAgent.moveAt(-1);
+ }
+ }
+}
+
+//-------------------------------------------------------------------------------
+// LLJoystickAgentSlide
+//-------------------------------------------------------------------------------
+
+void LLJoystickAgentSlide::onMouseUp()
+{
+ F32 time = getElapsedHeldDownTime();
+ if( time < NUDGE_TIME )
+ {
+ switch (mInitialQuadrant)
+ {
+ case JQ_LEFT:
+ gAgent.moveLeftNudge(1);
+ break;
+
+ case JQ_RIGHT:
+ gAgent.moveLeftNudge(-1);
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+void LLJoystickAgentSlide::onHeldDown()
+{
+ //LL_INFOS() << "slide left/right (and/or move forward/backward)" << LL_ENDL;
+
+ updateSlop();
+
+ S32 dx = mLastMouse.mX - mFirstMouse.mX + mInitialOffset.mX;
+ S32 dy = mLastMouse.mY - mFirstMouse.mY + mInitialOffset.mY;
+
+ // handle left-right sliding
+ if (dx > mHorizSlopNear)
+ {
+ gAgent.moveLeft(-1);
+ }
+ else if (dx < -mHorizSlopNear)
+ {
+ gAgent.moveLeft(1);
+ }
+
+ // handle forward/back movement
+ if (dy > mVertSlopFar)
+ {
+ // ...if mouse is forward of run region run forward
+ gAgent.moveAt(1);
+ }
+ else if (dy > mVertSlopNear)
+ {
+ // ...else if mouse is forward of walk region walk forward
+ gAgent.moveAtNudge(1);
+ }
+ else if (dy < -mVertSlopFar)
+ {
+ // ...else if mouse is behind run region run backward
+ gAgent.moveAt(-1);
+ }
+ else if (dy < -mVertSlopNear)
+ {
+ // ...else if mouse is behind walk region walk backward
+ gAgent.moveAtNudge(-1);
+ }
+}
+
+
+//-------------------------------------------------------------------------------
+// LLJoystickCameraRotate
+//-------------------------------------------------------------------------------
+
+LLJoystickCameraRotate::LLJoystickCameraRotate(const LLJoystickCameraRotate::Params& p)
+: LLJoystick(p),
+ mInLeft( false ),
+ mInTop( false ),
+ mInRight( false ),
+ mInBottom( false ),
+ mInCenter( false )
+{
+ mCenterImageName = "Cam_Rotate_Center";
+}
+
+
+void LLJoystickCameraRotate::updateSlop()
+{
+ // do the initial offset calculation based on mousedown location
+
+ // small fixed slop region
+ mVertSlopNear = 16;
+ mVertSlopFar = 32;
+
+ mHorizSlopNear = 16;
+ mHorizSlopFar = 32;
+
+ return;
+}
+
+
+bool LLJoystickCameraRotate::handleMouseDown(S32 x, S32 y, MASK mask)
+{
+ gAgent.setMovementLocked(true);
+ updateSlop();
+
+ // Set initial offset based on initial click location
+ S32 horiz_center = getRect().getWidth() / 2;
+ S32 vert_center = getRect().getHeight() / 2;
+
+ S32 dx = x - horiz_center;
+ S32 dy = y - vert_center;
+
+ if (pointInCenterDot(x, y, CENTER_DOT_RADIUS))
+ {
+ mInitialOffset.mX = 0;
+ mInitialOffset.mY = 0;
+ mInitialQuadrant = JQ_ORIGIN;
+ mInCenter = true;
+
+ resetJoystickCamera();
+ }
+ else if (dy > dx && dy > -dx)
+ {
+ // top
+ mInitialOffset.mX = 0;
+ mInitialOffset.mY = (mVertSlopNear + mVertSlopFar) / 2;
+ mInitialQuadrant = JQ_UP;
+ }
+ else if (dy > dx && dy <= -dx)
+ {
+ // left
+ mInitialOffset.mX = - (mHorizSlopNear + mHorizSlopFar) / 2;
+ mInitialOffset.mY = 0;
+ mInitialQuadrant = JQ_LEFT;
+ }
+ else if (dy <= dx && dy <= -dx)
+ {
+ // bottom
+ mInitialOffset.mX = 0;
+ mInitialOffset.mY = - (mVertSlopNear + mVertSlopFar) / 2;
+ mInitialQuadrant = JQ_DOWN;
+ }
+ else
+ {
+ // right
+ mInitialOffset.mX = (mHorizSlopNear + mHorizSlopFar) / 2;
+ mInitialOffset.mY = 0;
+ mInitialQuadrant = JQ_RIGHT;
+ }
+
+ return LLJoystick::handleMouseDown(x, y, mask);
+}
+
+bool LLJoystickCameraRotate::handleMouseUp(S32 x, S32 y, MASK mask)
+{
+ gAgent.setMovementLocked(false);
+ mInCenter = false;
+ return LLJoystick::handleMouseUp(x, y, mask);
+}
+
+bool LLJoystickCameraRotate::handleHover(S32 x, S32 y, MASK mask)
+{
+ if (!pointInCenterDot(x, y, CENTER_DOT_RADIUS))
+ {
+ mInCenter = false;
+ }
+
+ return LLJoystick::handleHover(x, y, mask);
+}
+
+void LLJoystickCameraRotate::onHeldDown()
+{
+ updateSlop();
+
+ S32 dx = mLastMouse.mX - mFirstMouse.mX + mInitialOffset.mX;
+ S32 dy = mLastMouse.mY - mFirstMouse.mY + mInitialOffset.mY;
+
+ // left-right rotation
+ if (dx > mHorizSlopNear)
+ {
+ gAgentCamera.unlockView();
+ gAgentCamera.setOrbitLeftKey(getOrbitRate());
+ }
+ else if (dx < -mHorizSlopNear)
+ {
+ gAgentCamera.unlockView();
+ gAgentCamera.setOrbitRightKey(getOrbitRate());
+ }
+
+ // over/under rotation
+ if (dy > mVertSlopNear)
+ {
+ gAgentCamera.unlockView();
+ gAgentCamera.setOrbitUpKey(getOrbitRate());
+ }
+ else if (dy < -mVertSlopNear)
+ {
+ gAgentCamera.unlockView();
+ gAgentCamera.setOrbitDownKey(getOrbitRate());
+ }
+}
+
+void LLJoystickCameraRotate::resetJoystickCamera()
+{
+ gAgentCamera.resetCameraOrbit();
+}
+
+F32 LLJoystickCameraRotate::getOrbitRate()
+{
+ F32 time = getElapsedHeldDownTime();
+ if( time < NUDGE_TIME )
+ {
+ F32 rate = ORBIT_NUDGE_RATE + time * (1 - ORBIT_NUDGE_RATE)/ NUDGE_TIME;
+ //LL_INFOS() << rate << LL_ENDL;
+ return rate;
+ }
+ else
+ {
+ return 1;
+ }
+}
+
+
+// Only used for drawing
+void LLJoystickCameraRotate::setToggleState( bool left, bool top, bool right, bool bottom )
+{
+ mInLeft = left;
+ mInTop = top;
+ mInRight = right;
+ mInBottom = bottom;
+}
+
+void LLJoystickCameraRotate::draw()
+{
+ LLGLSUIDefault gls_ui;
+
+ getImageUnselected()->draw( 0, 0 );
+ LLPointer<LLUIImage> image = getImageSelected();
+
+ if (mInCenter)
+ {
+ drawRotatedImage(LLUI::getUIImage(mCenterImageName), 0);
+ }
+ else
+ {
+ if (mInTop)
+ {
+ drawRotatedImage(getImageSelected(), 0);
+ }
+
+ if (mInRight)
+ {
+ drawRotatedImage(getImageSelected(), 1);
+ }
+
+ if (mInBottom)
+ {
+ drawRotatedImage(getImageSelected(), 2);
+ }
+
+ if (mInLeft)
+ {
+ drawRotatedImage(getImageSelected(), 3);
+ }
+ }
+}
+
+// Draws image rotated by multiples of 90 degrees
+void LLJoystickCameraRotate::drawRotatedImage( LLPointer<LLUIImage> image, S32 rotations )
+{
+ S32 width = image->getWidth();
+ S32 height = image->getHeight();
+ LLTexture* texture = image->getImage();
+
+ /*
+ * Scale texture coordinate system
+ * to handle the different between image size and size of texture.
+ * If we will use default matrix,
+ * it may break texture mapping after rotation.
+ * see EXT-2023 Camera floater: arrows became shifted when pressed.
+ */
+ F32 uv[][2] =
+ {
+ { (F32)width/texture->getWidth(), (F32)height/texture->getHeight() },
+ { 0.f, (F32)height/texture->getHeight() },
+ { 0.f, 0.f },
+ { (F32)width/texture->getWidth(), 0.f }
+ };
+
+ gGL.getTexUnit(0)->bind(texture);
+
+ gGL.color4fv(UI_VERTEX_COLOR.mV);
+
+ gGL.begin(LLRender::QUADS);
+ {
+ gGL.texCoord2fv( uv[ (rotations + 0) % 4]);
+ gGL.vertex2i(width, height );
+
+ gGL.texCoord2fv( uv[ (rotations + 1) % 4]);
+ gGL.vertex2i(0, height );
+
+ gGL.texCoord2fv( uv[ (rotations + 2) % 4]);
+ gGL.vertex2i(0, 0);
+
+ gGL.texCoord2fv( uv[ (rotations + 3) % 4]);
+ gGL.vertex2i(width, 0);
+ }
+ gGL.end();
+}
+
+
+
+//-------------------------------------------------------------------------------
+// LLJoystickCameraTrack
+//-------------------------------------------------------------------------------
+
+LLJoystickCameraTrack::Params::Params()
+{
+ held_down_delay.seconds(0.0);
+}
+
+LLJoystickCameraTrack::LLJoystickCameraTrack(const LLJoystickCameraTrack::Params& p)
+: LLJoystickCameraRotate(p)
+{
+ mCenterImageName = "Cam_Tracking_Center";
+}
+
+
+void LLJoystickCameraTrack::onHeldDown()
+{
+ updateSlop();
+
+ S32 dx = mLastMouse.mX - mFirstMouse.mX + mInitialOffset.mX;
+ S32 dy = mLastMouse.mY - mFirstMouse.mY + mInitialOffset.mY;
+
+ if (dx > mVertSlopNear)
+ {
+ gAgentCamera.unlockView();
+ gAgentCamera.setPanRightKey(getOrbitRate());
+ }
+ else if (dx < -mVertSlopNear)
+ {
+ gAgentCamera.unlockView();
+ gAgentCamera.setPanLeftKey(getOrbitRate());
+ }
+
+ // over/under rotation
+ if (dy > mVertSlopNear)
+ {
+ gAgentCamera.unlockView();
+ gAgentCamera.setPanUpKey(getOrbitRate());
+ }
+ else if (dy < -mVertSlopNear)
+ {
+ gAgentCamera.unlockView();
+ gAgentCamera.setPanDownKey(getOrbitRate());
+ }
+}
+
+void LLJoystickCameraTrack::resetJoystickCamera()
+{
+ gAgentCamera.resetCameraPan();
+}
+
+//-------------------------------------------------------------------------------
+// LLJoystickQuaternion
+//-------------------------------------------------------------------------------
+
+LLJoystickQuaternion::Params::Params()
+{
+}
+
+LLJoystickQuaternion::LLJoystickQuaternion(const LLJoystickQuaternion::Params &p):
+ LLJoystick(p),
+ mInLeft(false),
+ mInTop(false),
+ mInRight(false),
+ mInBottom(false),
+ mVectorZero(0.0f, 0.0f, 1.0f),
+ mRotation(),
+ mUpDnAxis(1.0f, 0.0f, 0.0f),
+ mLfRtAxis(0.0f, 0.0f, 1.0f),
+ mXAxisIndex(2), // left & right across the control
+ mYAxisIndex(0), // up & down across the control
+ mZAxisIndex(1) // tested for above and below
+{
+ for (int i = 0; i < 3; ++i)
+ {
+ mLfRtAxis.mV[i] = (mXAxisIndex == i) ? 1.0 : 0.0;
+ mUpDnAxis.mV[i] = (mYAxisIndex == i) ? 1.0 : 0.0;
+ }
+}
+
+void LLJoystickQuaternion::setToggleState(bool left, bool top, bool right, bool bottom)
+{
+ mInLeft = left;
+ mInTop = top;
+ mInRight = right;
+ mInBottom = bottom;
+}
+
+bool LLJoystickQuaternion::handleMouseDown(S32 x, S32 y, MASK mask)
+{
+ updateSlop();
+
+ // Set initial offset based on initial click location
+ S32 horiz_center = getRect().getWidth() / 2;
+ S32 vert_center = getRect().getHeight() / 2;
+
+ S32 dx = x - horiz_center;
+ S32 dy = y - vert_center;
+
+ if (dy > dx && dy > -dx)
+ {
+ // top
+ mInitialOffset.mX = 0;
+ mInitialOffset.mY = (mVertSlopNear + mVertSlopFar) / 2;
+ mInitialQuadrant = JQ_UP;
+ }
+ else if (dy > dx && dy <= -dx)
+ {
+ // left
+ mInitialOffset.mX = -(mHorizSlopNear + mHorizSlopFar) / 2;
+ mInitialOffset.mY = 0;
+ mInitialQuadrant = JQ_LEFT;
+ }
+ else if (dy <= dx && dy <= -dx)
+ {
+ // bottom
+ mInitialOffset.mX = 0;
+ mInitialOffset.mY = -(mVertSlopNear + mVertSlopFar) / 2;
+ mInitialQuadrant = JQ_DOWN;
+ }
+ else
+ {
+ // right
+ mInitialOffset.mX = (mHorizSlopNear + mHorizSlopFar) / 2;
+ mInitialOffset.mY = 0;
+ mInitialQuadrant = JQ_RIGHT;
+ }
+
+ return LLJoystick::handleMouseDown(x, y, mask);
+}
+
+bool LLJoystickQuaternion::handleMouseUp(S32 x, S32 y, MASK mask)
+{
+ return LLJoystick::handleMouseUp(x, y, mask);
+}
+
+void LLJoystickQuaternion::onHeldDown()
+{
+ LLVector3 axis;
+ updateSlop();
+
+ S32 dx = mLastMouse.mX - mFirstMouse.mX + mInitialOffset.mX;
+ S32 dy = mLastMouse.mY - mFirstMouse.mY + mInitialOffset.mY;
+
+ // left-right rotation
+ if (dx > mHorizSlopNear)
+ {
+ axis += mUpDnAxis;
+ }
+ else if (dx < -mHorizSlopNear)
+ {
+ axis -= mUpDnAxis;
+ }
+
+ // over/under rotation
+ if (dy > mVertSlopNear)
+ {
+ axis += mLfRtAxis;
+ }
+ else if (dy < -mVertSlopNear)
+ {
+ axis -= mLfRtAxis;
+ }
+
+ if (axis.isNull())
+ return;
+
+ axis.normalize();
+
+ LLQuaternion delta;
+ delta.setAngleAxis(0.0523599f, axis); // about 3deg
+
+ mRotation *= delta;
+ setValue(mRotation.getValue());
+ onCommit();
+}
+
+void LLJoystickQuaternion::draw()
+{
+ LLGLSUIDefault gls_ui;
+
+ getImageUnselected()->draw(0, 0);
+ LLPointer<LLUIImage> image = getImageSelected();
+
+ if (mInTop)
+ {
+ drawRotatedImage(getImageSelected(), 0);
+ }
+
+ if (mInRight)
+ {
+ drawRotatedImage(getImageSelected(), 1);
+ }
+
+ if (mInBottom)
+ {
+ drawRotatedImage(getImageSelected(), 2);
+ }
+
+ if (mInLeft)
+ {
+ drawRotatedImage(getImageSelected(), 3);
+ }
+
+ LLVector3 draw_point = mVectorZero * mRotation;
+ S32 halfwidth = getRect().getWidth() / 2;
+ S32 halfheight = getRect().getHeight() / 2;
+ draw_point.mV[mXAxisIndex] = (draw_point.mV[mXAxisIndex] + 1.0) * halfwidth;
+ draw_point.mV[mYAxisIndex] = (draw_point.mV[mYAxisIndex] + 1.0) * halfheight;
+
+ gl_circle_2d(draw_point.mV[mXAxisIndex], draw_point.mV[mYAxisIndex], 4, 8,
+ draw_point.mV[mZAxisIndex] >= 0.f);
+
+}
+
+F32 LLJoystickQuaternion::getOrbitRate()
+{
+ return 1;
+}
+
+void LLJoystickQuaternion::updateSlop()
+{
+ // small fixed slop region
+ mVertSlopNear = 16;
+ mVertSlopFar = 32;
+
+ mHorizSlopNear = 16;
+ mHorizSlopFar = 32;
+}
+
+void LLJoystickQuaternion::drawRotatedImage(LLPointer<LLUIImage> image, S32 rotations)
+{
+ S32 width = image->getWidth();
+ S32 height = image->getHeight();
+ LLTexture* texture = image->getImage();
+
+ /*
+ * Scale texture coordinate system
+ * to handle the different between image size and size of texture.
+ */
+ F32 uv[][2] =
+ {
+ { (F32)width / texture->getWidth(), (F32)height / texture->getHeight() },
+ { 0.f, (F32)height / texture->getHeight() },
+ { 0.f, 0.f },
+ { (F32)width / texture->getWidth(), 0.f }
+ };
+
+ gGL.getTexUnit(0)->bind(texture);
+
+ gGL.color4fv(UI_VERTEX_COLOR.mV);
+
+ gGL.begin(LLRender::QUADS);
+ {
+ gGL.texCoord2fv(uv[(rotations + 0) % 4]);
+ gGL.vertex2i(width, height);
+
+ gGL.texCoord2fv(uv[(rotations + 1) % 4]);
+ gGL.vertex2i(0, height);
+
+ gGL.texCoord2fv(uv[(rotations + 2) % 4]);
+ gGL.vertex2i(0, 0);
+
+ gGL.texCoord2fv(uv[(rotations + 3) % 4]);
+ gGL.vertex2i(width, 0);
+ }
+ gGL.end();
+}
+
+void LLJoystickQuaternion::setRotation(const LLQuaternion &value)
+{
+ if (value != mRotation)
+ {
+ mRotation = value;
+ mRotation.normalize();
+ LLJoystick::setValue(mRotation.getValue());
+ }
+}
+
+LLQuaternion LLJoystickQuaternion::getRotation() const
+{
+ return mRotation;
+}
+
+
|