diff options
author | Ansariel <ansariel.hiller@phoenixviewer.com> | 2024-05-22 19:04:52 +0200 |
---|---|---|
committer | Ansariel <ansariel.hiller@phoenixviewer.com> | 2024-05-22 19:04:52 +0200 |
commit | 1b67dd855c41f5a0cda7ec2a68d98071986ca703 (patch) | |
tree | ab243607f74f78200787bba5b9b88f07ef1b966f /indra/newview/llmaniprotate.cpp | |
parent | 6d6eabca44d08d5b97bfe3e941d2b9687c2246ea (diff) | |
parent | e1623bb276f83a43ce7a197e388720c05bdefe61 (diff) |
Merge remote-tracking branch 'origin/main' into DRTVWR-600-maint-A
# Conflicts:
# autobuild.xml
# indra/cmake/CMakeLists.txt
# indra/cmake/GoogleMock.cmake
# indra/llaudio/llaudioengine_fmodstudio.cpp
# indra/llaudio/llaudioengine_fmodstudio.h
# indra/llaudio/lllistener_fmodstudio.cpp
# indra/llaudio/lllistener_fmodstudio.h
# indra/llaudio/llstreamingaudio_fmodstudio.cpp
# indra/llaudio/llstreamingaudio_fmodstudio.h
# indra/llcharacter/llmultigesture.cpp
# indra/llcharacter/llmultigesture.h
# indra/llimage/llimage.cpp
# indra/llimage/llimagepng.cpp
# indra/llimage/llimageworker.cpp
# indra/llimage/tests/llimageworker_test.cpp
# indra/llmessage/tests/llmockhttpclient.h
# indra/llprimitive/llgltfmaterial.h
# indra/llrender/llfontfreetype.cpp
# indra/llui/llcombobox.cpp
# indra/llui/llfolderview.cpp
# indra/llui/llfolderviewmodel.h
# indra/llui/lllineeditor.cpp
# indra/llui/lllineeditor.h
# indra/llui/lltextbase.cpp
# indra/llui/lltextbase.h
# indra/llui/lltexteditor.cpp
# indra/llui/lltextvalidate.cpp
# indra/llui/lltextvalidate.h
# indra/llui/lluictrl.h
# indra/llui/llview.cpp
# indra/llwindow/llwindowmacosx.cpp
# indra/newview/app_settings/settings.xml
# indra/newview/llappearancemgr.cpp
# indra/newview/llappearancemgr.h
# indra/newview/llavatarpropertiesprocessor.cpp
# indra/newview/llavatarpropertiesprocessor.h
# indra/newview/llbreadcrumbview.cpp
# indra/newview/llbreadcrumbview.h
# indra/newview/llbreastmotion.cpp
# indra/newview/llbreastmotion.h
# indra/newview/llconversationmodel.h
# indra/newview/lldensityctrl.cpp
# indra/newview/lldensityctrl.h
# indra/newview/llface.inl
# indra/newview/llfloatereditsky.cpp
# indra/newview/llfloatereditwater.cpp
# indra/newview/llfloateremojipicker.h
# indra/newview/llfloaterimsessiontab.cpp
# indra/newview/llfloaterprofiletexture.cpp
# indra/newview/llfloaterprofiletexture.h
# indra/newview/llgesturemgr.cpp
# indra/newview/llgesturemgr.h
# indra/newview/llimpanel.cpp
# indra/newview/llimpanel.h
# indra/newview/llinventorybridge.cpp
# indra/newview/llinventorybridge.h
# indra/newview/llinventoryclipboard.cpp
# indra/newview/llinventoryclipboard.h
# indra/newview/llinventoryfunctions.cpp
# indra/newview/llinventoryfunctions.h
# indra/newview/llinventorygallery.cpp
# indra/newview/lllistbrowser.cpp
# indra/newview/lllistbrowser.h
# indra/newview/llpanelobjectinventory.cpp
# indra/newview/llpanelprofile.cpp
# indra/newview/llpanelprofile.h
# indra/newview/llpreviewgesture.cpp
# indra/newview/llsavedsettingsglue.cpp
# indra/newview/llsavedsettingsglue.h
# indra/newview/lltooldraganddrop.cpp
# indra/newview/llurllineeditorctrl.cpp
# indra/newview/llvectorperfoptions.cpp
# indra/newview/llvectorperfoptions.h
# indra/newview/llviewerparceloverlay.cpp
# indra/newview/llviewertexlayer.cpp
# indra/newview/llviewertexturelist.cpp
# indra/newview/macmain.h
# indra/test/test.cpp
Diffstat (limited to 'indra/newview/llmaniprotate.cpp')
-rw-r--r-- | indra/newview/llmaniprotate.cpp | 3900 |
1 files changed, 1950 insertions, 1950 deletions
diff --git a/indra/newview/llmaniprotate.cpp b/indra/newview/llmaniprotate.cpp index ba8270ff02..73424cf90e 100644 --- a/indra/newview/llmaniprotate.cpp +++ b/indra/newview/llmaniprotate.cpp @@ -1,1950 +1,1950 @@ -/** - * @file llmaniprotate.cpp - * @brief LLManipRotate class implementation - * - * $LicenseInfo:firstyear=2002&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 "llmaniprotate.h" - -// library includes -#include "llmath.h" -#include "llgl.h" -#include "llrender.h" -#include "v4color.h" -#include "llprimitive.h" -#include "llview.h" -#include "llfontgl.h" - -// viewer includes -#include "llagent.h" -#include "llagentcamera.h" -#include "llbox.h" -#include "llbutton.h" -#include "llviewercontrol.h" -#include "llcriticaldamp.h" -#include "lltooltip.h" -#include "llfloatertools.h" -#include "llselectmgr.h" -#include "llstatusbar.h" -#include "llui.h" -#include "llvoavatar.h" -#include "llviewercamera.h" -#include "llviewerobject.h" -#include "llviewerobject.h" -#include "llviewershadermgr.h" -#include "llviewerwindow.h" -#include "llworld.h" -#include "pipeline.h" -#include "lldrawable.h" -#include "llglheaders.h" -#include "lltrans.h" -#include "llvoavatarself.h" -#include "llhudrender.h" - -const F32 RADIUS_PIXELS = 100.f; // size in screen space -const F32 SQ_RADIUS = RADIUS_PIXELS * RADIUS_PIXELS; -const F32 WIDTH_PIXELS = 8; -const S32 CIRCLE_STEPS = 100; -const F32 MAX_MANIP_SELECT_DISTANCE = 100.f; -const F32 SNAP_ANGLE_INCREMENT = 5.625f; -const F32 SNAP_ANGLE_DETENTE = SNAP_ANGLE_INCREMENT; -const F32 SNAP_GUIDE_RADIUS_1 = 2.8f; -const F32 SNAP_GUIDE_RADIUS_2 = 2.4f; -const F32 SNAP_GUIDE_RADIUS_3 = 2.2f; -const F32 SNAP_GUIDE_RADIUS_4 = 2.1f; -const F32 SNAP_GUIDE_RADIUS_5 = 2.05f; -const F32 SNAP_GUIDE_INNER_RADIUS = 2.f; -const F32 AXIS_ONTO_CAM_TOLERANCE = cos( 80.f * DEG_TO_RAD ); -const F32 SELECTED_MANIPULATOR_SCALE = 1.05f; -const F32 MANIPULATOR_SCALE_HALF_LIFE = 0.07f; - -extern void handle_reset_rotation(void*); // in LLViewerWindow - -LLManipRotate::LLManipRotate( LLToolComposite* composite ) -: LLManip( std::string("Rotate"), composite ), - mRotationCenter(), - mCenterScreen(), - mRotation(), - mMouseDown(), - mMouseCur(), - mRadiusMeters(0.f), - mCenterToCam(), - mCenterToCamNorm(), - mCenterToCamMag(0.f), - mCenterToProfilePlane(), - mCenterToProfilePlaneMag(0.f), - mSendUpdateOnMouseUp( false ), - mSmoothRotate( false ), - mCamEdgeOn(false), - mManipulatorScales(1.f, 1.f, 1.f, 1.f) -{ } - -void LLManipRotate::handleSelect() -{ - // *FIX: put this in mouseDown? - LLSelectMgr::getInstance()->saveSelectedObjectTransform(SELECT_ACTION_TYPE_PICK); - if (gFloaterTools) - { - gFloaterTools->setStatusText("rotate"); - } - LLManip::handleSelect(); -} - -void LLManipRotate::render() -{ - LLGLSUIDefault gls_ui; - gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sWhiteImagep); - LLGLDepthTest gls_depth(GL_TRUE); - LLGLEnable gl_blend(GL_BLEND); - - // You can rotate if you can move - LLViewerObject* first_object = mObjectSelection->getFirstMoveableObject(true); - if( !first_object ) - { - return; - } - - if( !updateVisiblity() ) - { - return; - } - - gGL.matrixMode(LLRender::MM_MODELVIEW); - gGL.pushMatrix(); - if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD) - { - F32 zoom = gAgentCamera.mHUDCurZoom; - gGL.scalef(zoom, zoom, zoom); - } - - - LLVector3 center = gAgent.getPosAgentFromGlobal( mRotationCenter ); - - LLColor4 highlight_outside( 1.f, 1.f, 0.f, 1.f ); - LLColor4 highlight_inside( 0.7f, 0.7f, 0.f, 0.5f ); - F32 width_meters = WIDTH_PIXELS * mRadiusMeters / RADIUS_PIXELS; - - gGL.pushMatrix(); - { - - // are we in the middle of a constrained drag? - if (mManipPart >= LL_ROT_X && mManipPart <= LL_ROT_Z) - { - renderSnapGuides(); - } - else - { - gDebugProgram.bind(); - - LLGLEnable cull_face(GL_CULL_FACE); - LLGLDepthTest gls_depth(GL_FALSE); - gGL.pushMatrix(); - { - // Draw "sphere" (intersection of sphere with tangent cone that has apex at camera) - gGL.translatef( mCenterToProfilePlane.mV[VX], mCenterToProfilePlane.mV[VY], mCenterToProfilePlane.mV[VZ] ); - gGL.translatef( center.mV[VX], center.mV[VY], center.mV[VZ] ); - - // Inverse change of basis vectors - LLVector3 forward = mCenterToCamNorm; - LLVector3 left = gAgent.getUpAxis() % forward; - left.normVec(); - LLVector3 up = forward % left; - - LLVector4 a(-forward); - a.mV[3] = 0; - LLVector4 b(up); - b.mV[3] = 0; - LLVector4 c(left); - c.mV[3] = 0; - LLMatrix4 mat; - mat.initRows(a, b, c, LLVector4(0.f, 0.f, 0.f, 1.f)); - - gGL.multMatrix( &mat.mMatrix[0][0] ); - - gGL.rotatef( -90, 0.f, 1.f, 0.f); - LLColor4 color; - if (mManipPart == LL_ROT_ROLL || mHighlightedPart == LL_ROT_ROLL) - { - color.setVec(0.8f, 0.8f, 0.8f, 0.8f); - gGL.scalef(mManipulatorScales.mV[VW], mManipulatorScales.mV[VW], mManipulatorScales.mV[VW]); - } - else - { - color.setVec( 0.7f, 0.7f, 0.7f, 0.6f ); - } - gGL.diffuseColor4fv(color.mV); - gl_washer_2d(mRadiusMeters + width_meters, mRadiusMeters, CIRCLE_STEPS, color, color); - - - if (mManipPart == LL_NO_PART) - { - gGL.color4f( 0.7f, 0.7f, 0.7f, 0.3f ); - gGL.diffuseColor4f(0.7f, 0.7f, 0.7f, 0.3f); - gl_circle_2d( 0, 0, mRadiusMeters, CIRCLE_STEPS, true ); - } - - gGL.flush(); - } - gGL.popMatrix(); - - gUIProgram.bind(); - } - - gGL.translatef( center.mV[VX], center.mV[VY], center.mV[VZ] ); - - LLQuaternion rot; - F32 angle_radians, x, y, z; - - LLVector3 grid_origin; - LLVector3 grid_scale; - LLQuaternion grid_rotation; - - LLSelectMgr::getInstance()->getGrid(grid_origin, grid_rotation, grid_scale); - - grid_rotation.getAngleAxis(&angle_radians, &x, &y, &z); - gGL.rotatef(angle_radians * RAD_TO_DEG, x, y, z); - - - gDebugProgram.bind(); - - if (mManipPart == LL_ROT_Z) - { - mManipulatorScales = lerp(mManipulatorScales, LLVector4(1.f, 1.f, SELECTED_MANIPULATOR_SCALE, 1.f), LLSmoothInterpolation::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE)); - gGL.pushMatrix(); - { - // selected part - gGL.scalef(mManipulatorScales.mV[VZ], mManipulatorScales.mV[VZ], mManipulatorScales.mV[VZ]); - renderActiveRing( mRadiusMeters, width_meters, LLColor4( 0.f, 0.f, 1.f, 1.f) , LLColor4( 0.f, 0.f, 1.f, 0.3f )); - } - gGL.popMatrix(); - } - else if (mManipPart == LL_ROT_Y) - { - mManipulatorScales = lerp(mManipulatorScales, LLVector4(1.f, SELECTED_MANIPULATOR_SCALE, 1.f, 1.f), LLSmoothInterpolation::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE)); - gGL.pushMatrix(); - { - gGL.rotatef( 90.f, 1.f, 0.f, 0.f ); - gGL.scalef(mManipulatorScales.mV[VY], mManipulatorScales.mV[VY], mManipulatorScales.mV[VY]); - renderActiveRing( mRadiusMeters, width_meters, LLColor4( 0.f, 1.f, 0.f, 1.f), LLColor4( 0.f, 1.f, 0.f, 0.3f)); - } - gGL.popMatrix(); - } - else if (mManipPart == LL_ROT_X) - { - mManipulatorScales = lerp(mManipulatorScales, LLVector4(SELECTED_MANIPULATOR_SCALE, 1.f, 1.f, 1.f), LLSmoothInterpolation::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE)); - gGL.pushMatrix(); - { - gGL.rotatef( 90.f, 0.f, 1.f, 0.f ); - gGL.scalef(mManipulatorScales.mV[VX], mManipulatorScales.mV[VX], mManipulatorScales.mV[VX]); - renderActiveRing( mRadiusMeters, width_meters, LLColor4( 1.f, 0.f, 0.f, 1.f), LLColor4( 1.f, 0.f, 0.f, 0.3f)); - } - gGL.popMatrix(); - } - else if (mManipPart == LL_ROT_ROLL) - { - mManipulatorScales = lerp(mManipulatorScales, LLVector4(1.f, 1.f, 1.f, SELECTED_MANIPULATOR_SCALE), LLSmoothInterpolation::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE)); - } - else if (mManipPart == LL_NO_PART) - { - if (mHighlightedPart == LL_NO_PART) - { - mManipulatorScales = lerp(mManipulatorScales, LLVector4(1.f, 1.f, 1.f, 1.f), LLSmoothInterpolation::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE)); - } - - LLGLEnable cull_face(GL_CULL_FACE); - LLGLEnable clip_plane0(GL_CLIP_PLANE0); - LLGLDepthTest gls_depth(GL_FALSE); - //LLGLDisable gls_stencil(GL_STENCIL_TEST); - - // First pass: centers. Second pass: sides. - for( S32 i=0; i<2; i++ ) - { - - gGL.pushMatrix(); - { - if (mHighlightedPart == LL_ROT_Z) - { - mManipulatorScales = lerp(mManipulatorScales, LLVector4(1.f, 1.f, SELECTED_MANIPULATOR_SCALE, 1.f), LLSmoothInterpolation::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE)); - gGL.scalef(mManipulatorScales.mV[VZ], mManipulatorScales.mV[VZ], mManipulatorScales.mV[VZ]); - // hovering over part - gl_ring( mRadiusMeters, width_meters, LLColor4( 0.f, 0.f, 1.f, 1.f ), LLColor4( 0.f, 0.f, 1.f, 0.5f ), CIRCLE_STEPS, i); - } - else - { - // default - gl_ring( mRadiusMeters, width_meters, LLColor4( 0.f, 0.f, 0.8f, 0.8f ), LLColor4( 0.f, 0.f, 0.8f, 0.4f ), CIRCLE_STEPS, i); - } - } - gGL.popMatrix(); - - gGL.pushMatrix(); - { - gGL.rotatef( 90.f, 1.f, 0.f, 0.f ); - if (mHighlightedPart == LL_ROT_Y) - { - mManipulatorScales = lerp(mManipulatorScales, LLVector4(1.f, SELECTED_MANIPULATOR_SCALE, 1.f, 1.f), LLSmoothInterpolation::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE)); - gGL.scalef(mManipulatorScales.mV[VY], mManipulatorScales.mV[VY], mManipulatorScales.mV[VY]); - // hovering over part - gl_ring( mRadiusMeters, width_meters, LLColor4( 0.f, 1.f, 0.f, 1.f ), LLColor4( 0.f, 1.f, 0.f, 0.5f ), CIRCLE_STEPS, i); - } - else - { - // default - gl_ring( mRadiusMeters, width_meters, LLColor4( 0.f, 0.8f, 0.f, 0.8f ), LLColor4( 0.f, 0.8f, 0.f, 0.4f ), CIRCLE_STEPS, i); - } - } - gGL.popMatrix(); - - gGL.pushMatrix(); - { - gGL.rotatef( 90.f, 0.f, 1.f, 0.f ); - if (mHighlightedPart == LL_ROT_X) - { - mManipulatorScales = lerp(mManipulatorScales, LLVector4(SELECTED_MANIPULATOR_SCALE, 1.f, 1.f, 1.f), LLSmoothInterpolation::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE)); - gGL.scalef(mManipulatorScales.mV[VX], mManipulatorScales.mV[VX], mManipulatorScales.mV[VX]); - - // hovering over part - gl_ring( mRadiusMeters, width_meters, LLColor4( 1.f, 0.f, 0.f, 1.f ), LLColor4( 1.f, 0.f, 0.f, 0.5f ), CIRCLE_STEPS, i); - } - else - { - // default - gl_ring( mRadiusMeters, width_meters, LLColor4( 0.8f, 0.f, 0.f, 0.8f ), LLColor4( 0.8f, 0.f, 0.f, 0.4f ), CIRCLE_STEPS, i); - } - } - gGL.popMatrix(); - - if (mHighlightedPart == LL_ROT_ROLL) - { - mManipulatorScales = lerp(mManipulatorScales, LLVector4(1.f, 1.f, 1.f, SELECTED_MANIPULATOR_SCALE), LLSmoothInterpolation::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE)); - } - - } - - } - - gUIProgram.bind(); - } - gGL.popMatrix(); - gGL.popMatrix(); - - - LLVector3 euler_angles; - LLQuaternion object_rot = first_object->getRotationEdit(); - object_rot.getEulerAngles(&(euler_angles.mV[VX]), &(euler_angles.mV[VY]), &(euler_angles.mV[VZ])); - euler_angles *= RAD_TO_DEG; - euler_angles.mV[VX] = ll_round(fmodf(euler_angles.mV[VX] + 360.f, 360.f), 0.05f); - euler_angles.mV[VY] = ll_round(fmodf(euler_angles.mV[VY] + 360.f, 360.f), 0.05f); - euler_angles.mV[VZ] = ll_round(fmodf(euler_angles.mV[VZ] + 360.f, 360.f), 0.05f); - - renderXYZ(euler_angles); -} - -bool LLManipRotate::handleMouseDown(S32 x, S32 y, MASK mask) -{ - bool handled = false; - - LLViewerObject* first_object = mObjectSelection->getFirstMoveableObject(true); - if( first_object ) - { - if( mHighlightedPart != LL_NO_PART ) - { - handled = handleMouseDownOnPart( x, y, mask ); - } - } - - return handled; -} - -// Assumes that one of the parts of the manipulator was hit. -bool LLManipRotate::handleMouseDownOnPart( S32 x, S32 y, MASK mask ) -{ - bool can_rotate = canAffectSelection(); - if (!can_rotate) - { - return false; - } - - highlightManipulators(x, y); - S32 hit_part = mHighlightedPart; - // we just started a drag, so save initial object positions - LLSelectMgr::getInstance()->saveSelectedObjectTransform(SELECT_ACTION_TYPE_ROTATE); - - // save selection center - mRotationCenter = gAgent.getPosGlobalFromAgent( getPivotPoint() ); //LLSelectMgr::getInstance()->getSelectionCenterGlobal(); - - mManipPart = (EManipPart)hit_part; - LLVector3 center = gAgent.getPosAgentFromGlobal( mRotationCenter ); - - if( mManipPart == LL_ROT_GENERAL) - { - mMouseDown = intersectMouseWithSphere( x, y, center, mRadiusMeters); - } - else - { - // Project onto the plane of the ring - LLVector3 axis = getConstraintAxis(); - - F32 axis_onto_cam = llabs( axis * mCenterToCamNorm ); - const F32 AXIS_ONTO_CAM_TOL = cos( 85.f * DEG_TO_RAD ); - if( axis_onto_cam < AXIS_ONTO_CAM_TOL ) - { - LLVector3 up_from_axis = mCenterToCamNorm % axis; - up_from_axis.normVec(); - LLVector3 cur_intersection; - getMousePointOnPlaneAgent(cur_intersection, x, y, center, mCenterToCam); - cur_intersection -= center; - mMouseDown = projected_vec(cur_intersection, up_from_axis); - F32 mouse_depth = SNAP_GUIDE_INNER_RADIUS * mRadiusMeters; - F32 mouse_dist_sqrd = mMouseDown.magVecSquared(); - if (mouse_dist_sqrd > 0.0001f) - { - mouse_depth = sqrtf((SNAP_GUIDE_INNER_RADIUS * mRadiusMeters) * (SNAP_GUIDE_INNER_RADIUS * mRadiusMeters) - - mouse_dist_sqrd); - } - LLVector3 projected_center_to_cam = mCenterToCamNorm - projected_vec(mCenterToCamNorm, axis); - mMouseDown += mouse_depth * projected_center_to_cam; - - } - else - { - mMouseDown = findNearestPointOnRing( x, y, center, axis ) - center; - mMouseDown.normVec(); - } - } - - mMouseCur = mMouseDown; - mAgentSelfAtAxis = gAgent.getAtAxis(); // no point checking if avatar was selected, just save the value - - // Route future Mouse messages here preemptively. (Release on mouse up.) - setMouseCapture( true ); - LLSelectMgr::getInstance()->enableSilhouette(false); - - mHelpTextTimer.reset(); - sNumTimesHelpTextShown++; - return true; -} - - -LLVector3 LLManipRotate::findNearestPointOnRing( S32 x, S32 y, const LLVector3& center, const LLVector3& axis ) -{ - // Project the delta onto the ring and rescale it by the radius so that it's _on_ the ring. - LLVector3 proj_onto_ring; - getMousePointOnPlaneAgent(proj_onto_ring, x, y, center, axis); - proj_onto_ring -= center; - proj_onto_ring.normVec(); - - return center + proj_onto_ring * mRadiusMeters; -} - -bool LLManipRotate::handleMouseUp(S32 x, S32 y, MASK mask) -{ - // first, perform normal processing in case this was a quick-click - handleHover(x, y, mask); - - if( hasMouseCapture() ) - { - for (LLObjectSelection::iterator iter = mObjectSelection->begin(); - iter != mObjectSelection->end(); iter++) - { - LLSelectNode* selectNode = *iter; - LLViewerObject* object = selectNode->getObject(); - LLViewerObject* root_object = (object == NULL) ? NULL : object->getRootEdit(); - - // have permission to move and object is root of selection or individually selected - if (object->permMove() && !object->isPermanentEnforced() && - ((root_object == NULL) || !root_object->isPermanentEnforced()) && - (object->isRootEdit() || selectNode->mIndividualSelection)) - { - object->mUnselectedChildrenPositions.clear() ; - } - } - - mManipPart = LL_NO_PART; - - // Might have missed last update due to timing. - LLSelectMgr::getInstance()->sendMultipleUpdate( UPD_ROTATION | UPD_POSITION ); - LLSelectMgr::getInstance()->enableSilhouette(true); - //gAgent.setObjectTracking(gSavedSettings.getBOOL("TrackFocusObject")); - - LLSelectMgr::getInstance()->updateSelectionCenter(); - LLSelectMgr::getInstance()->saveSelectedObjectTransform(SELECT_ACTION_TYPE_PICK); - } - - return LLManip::handleMouseUp(x, y, mask); -} - - -bool LLManipRotate::handleHover(S32 x, S32 y, MASK mask) -{ - if( hasMouseCapture() ) - { - if( mObjectSelection->isEmpty() ) - { - // Somehow the object got deselected while we were dragging it. - setMouseCapture( false ); - } - else - { - drag(x, y); - } - - LL_DEBUGS("UserInput") << "hover handled by LLManipRotate (active)" << LL_ENDL; - } - else - { - highlightManipulators(x, y); - LL_DEBUGS("UserInput") << "hover handled by LLManipRotate (inactive)" << LL_ENDL; - } - - gViewerWindow->setCursor(UI_CURSOR_TOOLROTATE); - return true; -} - - -LLVector3 LLManipRotate::projectToSphere( F32 x, F32 y, bool* on_sphere ) -{ - F32 z = 0.f; - F32 dist_squared = x*x + y*y; - - *on_sphere = dist_squared <= SQ_RADIUS; - if( *on_sphere ) - { - z = sqrt(SQ_RADIUS - dist_squared); - } - return LLVector3( x, y, z ); -} - -// Freeform rotation -void LLManipRotate::drag( S32 x, S32 y ) -{ - if( !updateVisiblity() ) - { - return; - } - - if( mManipPart == LL_ROT_GENERAL ) - { - mRotation = dragUnconstrained(x, y); - } - else - { - mRotation = dragConstrained(x, y); - } - - bool damped = mSmoothRotate; - mSmoothRotate = false; - - for (LLObjectSelection::iterator iter = mObjectSelection->begin(); - iter != mObjectSelection->end(); iter++) - { - LLSelectNode* selectNode = *iter; - LLViewerObject* object = selectNode->getObject(); - LLViewerObject* root_object = (object == NULL) ? NULL : object->getRootEdit(); - - // have permission to move and object is root of selection or individually selected - if (object->permMove() && !object->isPermanentEnforced() && - ((root_object == NULL) || !root_object->isPermanentEnforced()) && - (object->isRootEdit() || selectNode->mIndividualSelection)) - { - if (!object->isRootEdit()) - { - // child objects should not update if parent is selected - LLViewerObject* editable_root = (LLViewerObject*)object->getParent(); - if (editable_root->isSelected()) - { - // we will be moved properly by our parent, so skip - continue; - } - } - - LLQuaternion new_rot = selectNode->mSavedRotation * mRotation; - std::vector<LLVector3>& child_positions = object->mUnselectedChildrenPositions ; - std::vector<LLQuaternion> child_rotations; - if (object->isRootEdit() && selectNode->mIndividualSelection) - { - object->saveUnselectedChildrenRotation(child_rotations) ; - object->saveUnselectedChildrenPosition(child_positions) ; - } - - if (object->getParent() && object->mDrawable.notNull()) - { - LLQuaternion invParentRotation = object->mDrawable->mXform.getParent()->getWorldRotation(); - invParentRotation.transQuat(); - - object->setRotation(new_rot * invParentRotation, damped); - rebuild(object); - } - else - { - object->setRotation(new_rot, damped); - LLVOAvatar* avatar = object->asAvatar(); - if (avatar && avatar->isSelf() - && LLSelectMgr::getInstance()->mAllowSelectAvatar - && !object->getParent()) - { - // Normal avatars use object's orienttion, but self uses - // separate LLCoordFrame - // See LVOAvatar::updateOrientation() - if (gAgentCamera.getFocusOnAvatar()) - { - //Don't rotate camera with avatar - gAgentCamera.setFocusOnAvatar(false, false, false); - } - - LLVector3 at_axis = mAgentSelfAtAxis; - at_axis *= mRotation; - at_axis.mV[VZ] = 0.f; - at_axis.normalize(); - gAgent.resetAxes(at_axis); - } - rebuild(object); - } - - // for individually selected roots, we need to counterrotate all the children - if (object->isRootEdit() && selectNode->mIndividualSelection) - { - //RN: must do non-damped updates on these objects so relative rotation appears constant - // instead of having two competing slerps making the child objects appear to "wobble" - object->resetChildrenRotationAndPosition(child_rotations, child_positions) ; - } - } - } - - // update positions - for (LLObjectSelection::iterator iter = mObjectSelection->begin(); - iter != mObjectSelection->end(); iter++) - { - LLSelectNode* selectNode = *iter; - LLViewerObject* object = selectNode->getObject(); - LLViewerObject* root_object = (object == NULL) ? NULL : object->getRootEdit(); - - // to avoid cumulative position changes we calculate the objects new position using its saved position - if (object && object->permMove() && !object->isPermanentEnforced() && - ((root_object == NULL) || !root_object->isPermanentEnforced())) - { - LLVector3 center = gAgent.getPosAgentFromGlobal( mRotationCenter ); - - LLVector3 old_position; - LLVector3 new_position; - - if (object->isAttachment() && object->mDrawable.notNull()) - { - // need to work in drawable space to handle selected items from multiple attachments - // (which have no shared frame of reference other than their render positions) - LLXform* parent_xform = object->mDrawable->getXform()->getParent(); - new_position = (selectNode->mSavedPositionLocal * parent_xform->getWorldRotation()) + parent_xform->getWorldPosition(); - old_position = (object->getPosition() * parent_xform->getWorldRotation()) + parent_xform->getWorldPosition();//object->getRenderPosition(); - } - else - { - new_position = gAgent.getPosAgentFromGlobal( selectNode->mSavedPositionGlobal ); - old_position = object->getPositionAgent(); - } - - new_position = (new_position - center) * mRotation; // new relative rotated position - new_position += center; - - if (object->isRootEdit() && !object->isAttachment()) - { - LLVector3d new_pos_global = gAgent.getPosGlobalFromAgent(new_position); - new_pos_global = LLWorld::getInstance()->clipToVisibleRegions(selectNode->mSavedPositionGlobal, new_pos_global); - new_position = gAgent.getPosAgentFromGlobal(new_pos_global); - } - - // for individually selected child objects - if (!object->isRootEdit() && selectNode->mIndividualSelection) - { - LLViewerObject* parentp = (LLViewerObject*)object->getParent(); - if (!parentp->isSelected()) - { - if (object->isAttachment() && object->mDrawable.notNull()) - { - // find position relative to render position of parent - object->setPosition((new_position - parentp->getRenderPosition()) * ~parentp->getRenderRotation()); - rebuild(object); - } - else - { - object->setPositionParent((new_position - parentp->getPositionAgent()) * ~parentp->getRotationRegion()); - rebuild(object); - } - } - } - else if (object->isRootEdit()) - { - if (object->isAttachment() && object->mDrawable.notNull()) - { - LLXform* parent_xform = object->mDrawable->getXform()->getParent(); - object->setPosition((new_position - parent_xform->getWorldPosition()) * ~parent_xform->getWorldRotation()); - rebuild(object); - } - else - { - object->setPositionAgent(new_position); - rebuild(object); - } - } - - // for individually selected roots, we need to counter-translate all unselected children - if (object->isRootEdit() && selectNode->mIndividualSelection) - { - // only offset by parent's translation as we've already countered parent's rotation - rebuild(object); - object->resetChildrenPosition(old_position - new_position) ; - } - } - } - - // store changes to override updates - for (LLObjectSelection::iterator iter = LLSelectMgr::getInstance()->getSelection()->begin(); - iter != LLSelectMgr::getInstance()->getSelection()->end(); iter++) - { - LLSelectNode* selectNode = *iter; - LLViewerObject*cur = selectNode->getObject(); - LLViewerObject *root_object = (cur == NULL) ? NULL : cur->getRootEdit(); - if( cur->permModify() && cur->permMove() && !cur->isPermanentEnforced() && - ((root_object == NULL) || !root_object->isPermanentEnforced()) && - (!cur->isAvatar() || LLSelectMgr::getInstance()->mAllowSelectAvatar)) - { - selectNode->mLastRotation = cur->getRotation(); - selectNode->mLastPositionLocal = cur->getPosition(); - } - } - - LLSelectMgr::getInstance()->updateSelectionCenter(); - - // RN: just clear focus so camera doesn't follow spurious object updates - gAgentCamera.clearFocusObject(); - dialog_refresh_all(); -} - -void LLManipRotate::renderActiveRing( F32 radius, F32 width, const LLColor4& front_color, const LLColor4& back_color) -{ - LLGLEnable cull_face(GL_CULL_FACE); - { - gl_ring(radius, width, back_color, back_color * 0.5f, CIRCLE_STEPS, false); - gl_ring(radius, width, back_color, back_color * 0.5f, CIRCLE_STEPS, true); - } - { - LLGLDepthTest gls_depth(GL_FALSE); - gl_ring(radius, width, front_color, front_color * 0.5f, CIRCLE_STEPS, false); - gl_ring(radius, width, front_color, front_color * 0.5f, CIRCLE_STEPS, true); - } -} - -void LLManipRotate::renderSnapGuides() -{ - static LLCachedControl<bool> snap_enabled(gSavedSettings, "SnapEnabled", true); - if (!snap_enabled) - { - return; - } - - LLVector3 grid_origin; - LLVector3 grid_scale; - LLQuaternion grid_rotation; - - LLSelectMgr::getInstance()->getGrid(grid_origin, grid_rotation, grid_scale, true); - - LLVector3 constraint_axis = getConstraintAxis(); - - LLVector3 center = gAgent.getPosAgentFromGlobal( mRotationCenter ); - LLVector3 cam_at_axis; - if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD) - { - cam_at_axis.setVec(1.f, 0.f, 0.f); - } - else - { - cam_at_axis = center - gAgentCamera.getCameraPositionAgent(); - cam_at_axis.normVec(); - } - - LLVector3 world_snap_axis; - LLVector3 test_axis = constraint_axis; - - bool constrain_to_ref_object = false; - if (mObjectSelection->getSelectType() == SELECT_TYPE_ATTACHMENT && isAgentAvatarValid()) - { - test_axis = test_axis * ~grid_rotation; - } - else if (LLSelectMgr::getInstance()->getGridMode() == GRID_MODE_REF_OBJECT) - { - test_axis = test_axis * ~grid_rotation; - constrain_to_ref_object = true; - } - - test_axis.abs(); - - // find closest global/reference axis to local constraint axis; - if (test_axis.mV[VX] > test_axis.mV[VY] && test_axis.mV[VX] > test_axis.mV[VZ]) - { - world_snap_axis = LLVector3::y_axis; - } - else if (test_axis.mV[VY] > test_axis.mV[VZ]) - { - world_snap_axis = LLVector3::z_axis; - } - else - { - world_snap_axis = LLVector3::x_axis; - } - - LLVector3 projected_snap_axis = world_snap_axis; - if (mObjectSelection->getSelectType() == SELECT_TYPE_ATTACHMENT && isAgentAvatarValid()) - { - projected_snap_axis = projected_snap_axis * grid_rotation; - } - else if (constrain_to_ref_object) - { - projected_snap_axis = projected_snap_axis * grid_rotation; - } - - // project world snap axis onto constraint plane - projected_snap_axis -= projected_vec(projected_snap_axis, constraint_axis); - projected_snap_axis.normVec(); - - S32 num_rings = mCamEdgeOn ? 2 : 1; - for (S32 ring_num = 0; ring_num < num_rings; ring_num++) - { - LLVector3 center = gAgent.getPosAgentFromGlobal( mRotationCenter ); - - if (mCamEdgeOn) - { - // draw two opposing rings - if (ring_num == 0) - { - center += constraint_axis * mRadiusMeters * 0.5f; - } - else - { - center -= constraint_axis * mRadiusMeters * 0.5f; - } - } - - LLGLDepthTest gls_depth(GL_FALSE); - for (S32 pass = 0; pass < 3; pass++) - { - // render snap guide ring - gGL.pushMatrix(); - - LLQuaternion snap_guide_rot; - F32 angle_radians, x, y, z; - snap_guide_rot.shortestArc(LLVector3::z_axis, getConstraintAxis()); - snap_guide_rot.getAngleAxis(&angle_radians, &x, &y, &z); - gGL.translatef(center.mV[VX], center.mV[VY], center.mV[VZ]); - gGL.rotatef(angle_radians * RAD_TO_DEG, x, y, z); - - LLColor4 line_color = setupSnapGuideRenderPass(pass); - - gGL.color4fv(line_color.mV); - - if (mCamEdgeOn) - { - // render an arc - LLVector3 edge_normal = cam_at_axis % constraint_axis; - edge_normal.normVec(); - LLVector3 x_axis_snap = LLVector3::x_axis * snap_guide_rot; - LLVector3 y_axis_snap = LLVector3::y_axis * snap_guide_rot; - - F32 end_angle = atan2(y_axis_snap * edge_normal, x_axis_snap * edge_normal); - //F32 start_angle = angle_between((-1.f * LLVector3::x_axis) * snap_guide_rot, edge_normal); - F32 start_angle = end_angle - F_PI; - gl_arc_2d(0.f, 0.f, mRadiusMeters * SNAP_GUIDE_INNER_RADIUS, CIRCLE_STEPS, false, start_angle, end_angle); - } - else - { - gl_circle_2d(0.f, 0.f, mRadiusMeters * SNAP_GUIDE_INNER_RADIUS, CIRCLE_STEPS, false); - } - gGL.popMatrix(); - - for (S32 i = 0; i < 64; i++) - { - bool render_text = true; - F32 deg = 5.625f * (F32)i; - LLVector3 inner_point; - LLVector3 outer_point; - LLVector3 text_point; - LLQuaternion rot(deg * DEG_TO_RAD, constraint_axis); - gGL.begin(LLRender::LINES); - { - inner_point = (projected_snap_axis * mRadiusMeters * SNAP_GUIDE_INNER_RADIUS * rot) + center; - F32 tick_length = 0.f; - if (i % 16 == 0) - { - tick_length = mRadiusMeters * (SNAP_GUIDE_RADIUS_1 - SNAP_GUIDE_INNER_RADIUS); - } - else if (i % 8 == 0) - { - tick_length = mRadiusMeters * (SNAP_GUIDE_RADIUS_2 - SNAP_GUIDE_INNER_RADIUS); - } - else if (i % 4 == 0) - { - tick_length = mRadiusMeters * (SNAP_GUIDE_RADIUS_3 - SNAP_GUIDE_INNER_RADIUS); - } - else if (i % 2 == 0) - { - tick_length = mRadiusMeters * (SNAP_GUIDE_RADIUS_4 - SNAP_GUIDE_INNER_RADIUS); - } - else - { - tick_length = mRadiusMeters * (SNAP_GUIDE_RADIUS_5 - SNAP_GUIDE_INNER_RADIUS); - } - - if (mCamEdgeOn) - { - // don't draw ticks that are on back side of circle - F32 dot = cam_at_axis * (projected_snap_axis * rot); - if (dot > 0.f) - { - outer_point = inner_point; - render_text = false; - } - else - { - if (ring_num == 0) - { - outer_point = inner_point + (constraint_axis * tick_length) * rot; - } - else - { - outer_point = inner_point - (constraint_axis * tick_length) * rot; - } - } - } - else - { - outer_point = inner_point + (projected_snap_axis * tick_length) * rot; - } - - text_point = outer_point + (projected_snap_axis * mRadiusMeters * 0.1f) * rot; - - gGL.vertex3fv(inner_point.mV); - gGL.vertex3fv(outer_point.mV); - } - gGL.end(); - - //RN: text rendering does own shadow pass, so only render once - if (pass == 1 && render_text && i % 16 == 0) - { - if (world_snap_axis.mV[VX]) - { - if (i == 0) - { - renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Direction_Forward") : LLTrans::getString("Direction_East"), LLColor4::white); - } - else if (i == 16) - { - if (constraint_axis.mV[VZ] > 0.f) - { - renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Direction_Left") : LLTrans::getString("Direction_North"), LLColor4::white); - } - else - { - renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Direction_Right") : LLTrans::getString("Direction_South"), LLColor4::white); - } - } - else if (i == 32) - { - renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Direction_Back") : LLTrans::getString("Direction_West"), LLColor4::white); - } - else - { - if (constraint_axis.mV[VZ] > 0.f) - { - renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Direction_Right") : LLTrans::getString("Direction_South"), LLColor4::white); - } - else - { - renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Direction_Left") : LLTrans::getString("Direction_North"), LLColor4::white); - } - } - } - else if (world_snap_axis.mV[VY]) - { - if (i == 0) - { - renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Direction_Left") : LLTrans::getString("Direction_North"), LLColor4::white); - } - else if (i == 16) - { - if (constraint_axis.mV[VX] > 0.f) - { - renderTickText(text_point, LLTrans::getString("Direction_Up"), LLColor4::white); - } - else - { - renderTickText(text_point, LLTrans::getString("Direction_Down"), LLColor4::white); - } - } - else if (i == 32) - { - renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Direction_Right") : LLTrans::getString("Direction_South"), LLColor4::white); - } - else - { - if (constraint_axis.mV[VX] > 0.f) - { - renderTickText(text_point, LLTrans::getString("Direction_Down"), LLColor4::white); - } - else - { - renderTickText(text_point, LLTrans::getString("Direction_Up"), LLColor4::white); - } - } - } - else if (world_snap_axis.mV[VZ]) - { - if (i == 0) - { - renderTickText(text_point, LLTrans::getString("Direction_Up"), LLColor4::white); - } - else if (i == 16) - { - if (constraint_axis.mV[VY] > 0.f) - { - renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Direction_Forward") : LLTrans::getString("Direction_East"), LLColor4::white); - } - else - { - renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Direction_Back") : LLTrans::getString("Direction_West"), LLColor4::white); - } - } - else if (i == 32) - { - renderTickText(text_point, LLTrans::getString("Direction_Down"), LLColor4::white); - } - else - { - if (constraint_axis.mV[VY] > 0.f) - { - renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Direction_Back") : LLTrans::getString("Direction_West"), LLColor4::white); - } - else - { - renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Direction_Forward") : LLTrans::getString("Direction_East"), LLColor4::white); - } - } - } - } - gGL.color4fv(line_color.mV); - } - - // now render projected object axis - if (mInSnapRegime) - { - LLVector3 object_axis; - getObjectAxisClosestToMouse(object_axis); - - // project onto constraint plane - LLSelectNode* first_node = mObjectSelection->getFirstMoveableNode(true); - object_axis = object_axis * first_node->getObject()->getRenderRotation(); - object_axis = object_axis - (object_axis * getConstraintAxis()) * getConstraintAxis(); - object_axis.normVec(); - object_axis = object_axis * SNAP_GUIDE_INNER_RADIUS * mRadiusMeters + center; - LLVector3 line_start = center; - - gGL.begin(LLRender::LINES); - { - gGL.vertex3fv(line_start.mV); - gGL.vertex3fv(object_axis.mV); - } - gGL.end(); - - // draw snap guide arrow - gGL.begin(LLRender::TRIANGLES); - { - LLVector3 arrow_dir; - LLVector3 arrow_span = (object_axis - line_start) % getConstraintAxis(); - arrow_span.normVec(); - - arrow_dir = mCamEdgeOn ? getConstraintAxis() : object_axis - line_start; - arrow_dir.normVec(); - if (ring_num == 1) - { - arrow_dir *= -1.f; - } - gGL.vertex3fv((object_axis + arrow_dir * mRadiusMeters * 0.1f).mV); - gGL.vertex3fv((object_axis + arrow_span * mRadiusMeters * 0.1f).mV); - gGL.vertex3fv((object_axis - arrow_span * mRadiusMeters * 0.1f).mV); - } - gGL.end(); - - { - LLGLDepthTest gls_depth(GL_TRUE); - gGL.begin(LLRender::LINES); - { - gGL.vertex3fv(line_start.mV); - gGL.vertex3fv(object_axis.mV); - } - gGL.end(); - - // draw snap guide arrow - gGL.begin(LLRender::TRIANGLES); - { - LLVector3 arrow_dir; - LLVector3 arrow_span = (object_axis - line_start) % getConstraintAxis(); - arrow_span.normVec(); - - arrow_dir = mCamEdgeOn ? getConstraintAxis() : object_axis - line_start; - arrow_dir.normVec(); - if (ring_num == 1) - { - arrow_dir *= -1.f; - } - - gGL.vertex3fv((object_axis + arrow_dir * mRadiusMeters * 0.1f).mV); - gGL.vertex3fv((object_axis + arrow_span * mRadiusMeters * 0.1f).mV); - gGL.vertex3fv((object_axis - arrow_span * mRadiusMeters * 0.1f).mV); - } - gGL.end(); - } - } - } - } - - - // render help text - if (mObjectSelection->getSelectType() != SELECT_TYPE_HUD) - { - if (mHelpTextTimer.getElapsedTimeF32() < sHelpTextVisibleTime + sHelpTextFadeTime && sNumTimesHelpTextShown < sMaxTimesShowHelpText) - { - LLVector3 selection_center_start = LLSelectMgr::getInstance()->getSavedBBoxOfSelection().getCenterAgent(); - - LLVector3 offset_dir = LLViewerCamera::getInstance()->getUpAxis(); - - F32 line_alpha = gSavedSettings.getF32("GridOpacity"); - - LLVector3 help_text_pos = selection_center_start + (mRadiusMeters * 3.f * offset_dir); - const LLFontGL* big_fontp = LLFontGL::getFontSansSerif(); - - std::string help_text = LLTrans::getString("manip_hint1"); - LLColor4 help_text_color = LLColor4::white; - help_text_color.mV[VALPHA] = clamp_rescale(mHelpTextTimer.getElapsedTimeF32(), sHelpTextVisibleTime, sHelpTextVisibleTime + sHelpTextFadeTime, line_alpha, 0.f); - hud_render_utf8text(help_text, help_text_pos, *big_fontp, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, -0.5f * big_fontp->getWidthF32(help_text), 3.f, help_text_color, false); - help_text = LLTrans::getString("manip_hint2"); - help_text_pos -= offset_dir * mRadiusMeters * 0.4f; - hud_render_utf8text(help_text, help_text_pos, *big_fontp, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, -0.5f * big_fontp->getWidthF32(help_text), 3.f, help_text_color, false); - } - } -} - -// Returns true if center of sphere is visible. Also sets a bunch of member variables that are used later (e.g. mCenterToCam) -bool LLManipRotate::updateVisiblity() -{ - // Don't want to recalculate the center of the selection during a drag. - // Due to packet delays, sometimes half the objects in the selection have their - // new position and half have their old one. This creates subtle errors in the - // computed center position for that frame. Unfortunately, these errors - // accumulate. The result is objects seem to "fly apart" during rotations. - // JC - 03.26.2002 - if (!hasMouseCapture()) - { - mRotationCenter = gAgent.getPosGlobalFromAgent( getPivotPoint() );//LLSelectMgr::getInstance()->getSelectionCenterGlobal(); - } - - bool visible = false; - - //Assume that UI scale factor is equivalent for X and Y axis - F32 ui_scale_factor = LLUI::getScaleFactor().mV[VX]; - - LLVector3 center = gAgent.getPosAgentFromGlobal( mRotationCenter ); - if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD) - { - mCenterToCam = LLVector3(-1.f / gAgentCamera.mHUDCurZoom, 0.f, 0.f); - mCenterToCamNorm = mCenterToCam; - mCenterToCamMag = mCenterToCamNorm.normVec(); - - mRadiusMeters = RADIUS_PIXELS / (F32) LLViewerCamera::getInstance()->getViewHeightInPixels(); - mRadiusMeters /= gAgentCamera.mHUDCurZoom; - mRadiusMeters *= ui_scale_factor; - - mCenterToProfilePlaneMag = mRadiusMeters * mRadiusMeters / mCenterToCamMag; - mCenterToProfilePlane = -mCenterToProfilePlaneMag * mCenterToCamNorm; - - // x axis range is (-aspect * 0.5f, +aspect * 0.5) - // y axis range is (-0.5, 0.5) - // so use getWorldViewHeightRaw as scale factor when converting to pixel coordinates - mCenterScreen.set((S32)((0.5f - center.mV[VY]) / gAgentCamera.mHUDCurZoom * gViewerWindow->getWorldViewHeightScaled()), - (S32)((center.mV[VZ] + 0.5f) / gAgentCamera.mHUDCurZoom * gViewerWindow->getWorldViewHeightScaled())); - visible = true; - } - else - { - visible = LLViewerCamera::getInstance()->projectPosAgentToScreen(center, mCenterScreen ); - if( visible ) - { - mCenterToCam = gAgentCamera.getCameraPositionAgent() - center; - mCenterToCamNorm = mCenterToCam; - mCenterToCamMag = mCenterToCamNorm.normVec(); - LLVector3 cameraAtAxis = LLViewerCamera::getInstance()->getAtAxis(); - cameraAtAxis.normVec(); - - F32 z_dist = -1.f * (mCenterToCam * cameraAtAxis); - - // Don't drag manip if object too far away - if (gSavedSettings.getBOOL("LimitSelectDistance")) - { - F32 max_select_distance = gSavedSettings.getF32("MaxSelectDistance"); - if (dist_vec_squared(gAgent.getPositionAgent(), center) > (max_select_distance * max_select_distance)) - { - visible = false; - } - } - - if (mCenterToCamMag > 0.001f) - { - F32 fraction_of_fov = RADIUS_PIXELS / (F32) LLViewerCamera::getInstance()->getViewHeightInPixels(); - F32 apparent_angle = fraction_of_fov * LLViewerCamera::getInstance()->getView(); // radians - mRadiusMeters = z_dist * tan(apparent_angle); - mRadiusMeters *= ui_scale_factor; - - mCenterToProfilePlaneMag = mRadiusMeters * mRadiusMeters / mCenterToCamMag; - mCenterToProfilePlane = -mCenterToProfilePlaneMag * mCenterToCamNorm; - } - else - { - visible = false; - } - } - } - - mCamEdgeOn = false; - F32 axis_onto_cam = mManipPart >= LL_ROT_X ? llabs( getConstraintAxis() * mCenterToCamNorm ) : 0.f; - if( axis_onto_cam < AXIS_ONTO_CAM_TOLERANCE ) - { - mCamEdgeOn = true; - } - - return visible; -} - -LLQuaternion LLManipRotate::dragUnconstrained( S32 x, S32 y ) -{ - LLVector3 cam = gAgentCamera.getCameraPositionAgent(); - LLVector3 center = gAgent.getPosAgentFromGlobal( mRotationCenter ); - - mMouseCur = intersectMouseWithSphere( x, y, center, mRadiusMeters); - - F32 delta_x = (F32)(mCenterScreen.mX - x); - F32 delta_y = (F32)(mCenterScreen.mY - y); - - F32 dist_from_sphere_center = sqrt(delta_x * delta_x + delta_y * delta_y); - - LLVector3 axis = mMouseDown % mMouseCur; - F32 angle = atan2(sqrtf(axis * axis), mMouseDown * mMouseCur); - axis.normVec(); - LLQuaternion sphere_rot( angle, axis ); - - if (is_approx_zero(1.f - mMouseDown * mMouseCur)) - { - return LLQuaternion::DEFAULT; - } - else if (dist_from_sphere_center < RADIUS_PIXELS) - { - return sphere_rot; - } - else - { - LLVector3 intersection; - getMousePointOnPlaneAgent( intersection, x, y, center + mCenterToProfilePlane, mCenterToCamNorm ); - - // amount dragging in sphere from center to periphery would rotate object - F32 in_sphere_angle = F_PI_BY_TWO; - F32 dist_to_tangent_point = mRadiusMeters; - if( !is_approx_zero( mCenterToProfilePlaneMag ) ) - { - dist_to_tangent_point = sqrt( mRadiusMeters * mRadiusMeters - mCenterToProfilePlaneMag * mCenterToProfilePlaneMag ); - in_sphere_angle = atan2( dist_to_tangent_point, mCenterToProfilePlaneMag ); - } - - LLVector3 profile_center_to_intersection = intersection - (center + mCenterToProfilePlane); - F32 dist_to_intersection = profile_center_to_intersection.normVec(); - F32 angle = (-1.f + dist_to_intersection / dist_to_tangent_point) * in_sphere_angle; - - LLVector3 axis; - if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD) - { - axis = LLVector3(-1.f, 0.f, 0.f) % profile_center_to_intersection; - } - else - { - axis = (cam - center) % profile_center_to_intersection; - axis.normVec(); - } - return sphere_rot * LLQuaternion( angle, axis ); - } -} - -LLVector3 LLManipRotate::getConstraintAxis() -{ - LLVector3 axis; - if( LL_ROT_ROLL == mManipPart ) - { - axis = mCenterToCamNorm; - } - else - { - S32 axis_dir = mManipPart - LL_ROT_X; - if ((axis_dir >= LL_NO_PART) && (axis_dir < LL_Z_ARROW)) - { - axis.mV[axis_dir] = 1.f; - } - else - { -#ifndef LL_RELEASE_FOR_DOWNLOAD - LL_ERRS() << "Got bogus hit part in LLManipRotate::getConstraintAxis():" << mManipPart << LL_ENDL; -#else - LL_WARNS() << "Got bogus hit part in LLManipRotate::getConstraintAxis():" << mManipPart << LL_ENDL; -#endif - axis.mV[0] = 1.f; - } - - LLVector3 grid_origin; - LLVector3 grid_scale; - LLQuaternion grid_rotation; - - LLSelectMgr::getInstance()->getGrid(grid_origin, grid_rotation, grid_scale); - - LLSelectNode* first_node = mObjectSelection->getFirstMoveableNode(true); - if (first_node) - { - // *FIX: get agent local attachment grid working - // Put rotation into frame of first selected root object - axis = axis * grid_rotation; - } - } - - return axis; -} - -LLQuaternion LLManipRotate::dragConstrained( S32 x, S32 y ) -{ - LLSelectNode* first_object_node = mObjectSelection->getFirstMoveableNode(true); - LLVector3 constraint_axis = getConstraintAxis(); - LLVector3 center = gAgent.getPosAgentFromGlobal( mRotationCenter ); - - F32 angle = 0.f; - - // build snap axes - LLVector3 grid_origin; - LLVector3 grid_scale; - LLQuaternion grid_rotation; - - LLSelectMgr::getInstance()->getGrid(grid_origin, grid_rotation, grid_scale); - - LLVector3 axis1; - LLVector3 axis2; - - LLVector3 test_axis = constraint_axis; - if (mObjectSelection->getSelectType() == SELECT_TYPE_ATTACHMENT && isAgentAvatarValid()) - { - test_axis = test_axis * ~grid_rotation; - } - else if (LLSelectMgr::getInstance()->getGridMode() == GRID_MODE_REF_OBJECT) - { - test_axis = test_axis * ~grid_rotation; - } - test_axis.abs(); - - // find closest global axis to constraint axis; - if (test_axis.mV[VX] > test_axis.mV[VY] && test_axis.mV[VX] > test_axis.mV[VZ]) - { - axis1 = LLVector3::y_axis; - } - else if (test_axis.mV[VY] > test_axis.mV[VZ]) - { - axis1 = LLVector3::z_axis; - } - else - { - axis1 = LLVector3::x_axis; - } - - if (mObjectSelection->getSelectType() == SELECT_TYPE_ATTACHMENT && isAgentAvatarValid()) - { - axis1 = axis1 * grid_rotation; - } - else if (LLSelectMgr::getInstance()->getGridMode() == GRID_MODE_REF_OBJECT) - { - axis1 = axis1 * grid_rotation; - } - - //project axis onto constraint plane - axis1 -= (axis1 * constraint_axis) * constraint_axis; - axis1.normVec(); - - // calculate third and final axis - axis2 = constraint_axis % axis1; - - //F32 axis_onto_cam = llabs( constraint_axis * mCenterToCamNorm ); - if( mCamEdgeOn ) - { - // We're looking at the ring edge-on. - LLVector3 snap_plane_center = (center + (constraint_axis * mRadiusMeters * 0.5f)); - LLVector3 cam_to_snap_plane; - if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD) - { - cam_to_snap_plane.setVec(1.f, 0.f, 0.f); - } - else - { - cam_to_snap_plane = snap_plane_center - gAgentCamera.getCameraPositionAgent(); - cam_to_snap_plane.normVec(); - } - - LLVector3 projected_mouse; - bool hit = getMousePointOnPlaneAgent(projected_mouse, x, y, snap_plane_center, constraint_axis); - projected_mouse -= snap_plane_center; - - if (gSavedSettings.getBOOL("SnapEnabled")) { - S32 snap_plane = 0; - - F32 dot = cam_to_snap_plane * constraint_axis; - if (llabs(dot) < 0.01f) - { - // looking at ring edge on, project onto view plane and check if mouse is past ring - getMousePointOnPlaneAgent(projected_mouse, x, y, snap_plane_center, cam_to_snap_plane); - projected_mouse -= snap_plane_center; - dot = projected_mouse * constraint_axis; - if (projected_mouse * constraint_axis > 0) - { - snap_plane = 1; - } - projected_mouse -= dot * constraint_axis; - } - else if (dot > 0.f) - { - // look for mouse position outside and in front of snap circle - if (hit && projected_mouse.magVec() > SNAP_GUIDE_INNER_RADIUS * mRadiusMeters && projected_mouse * cam_to_snap_plane < 0.f) - { - snap_plane = 1; - } - } - else - { - // look for mouse position inside or in back of snap circle - if (projected_mouse.magVec() < SNAP_GUIDE_INNER_RADIUS * mRadiusMeters || projected_mouse * cam_to_snap_plane > 0.f || !hit) - { - snap_plane = 1; - } - } - - if (snap_plane == 0) - { - // try other plane - snap_plane_center = (center - (constraint_axis * mRadiusMeters * 0.5f)); - if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD) - { - cam_to_snap_plane.setVec(1.f, 0.f, 0.f); - } - else - { - cam_to_snap_plane = snap_plane_center - gAgentCamera.getCameraPositionAgent(); - cam_to_snap_plane.normVec(); - } - - hit = getMousePointOnPlaneAgent(projected_mouse, x, y, snap_plane_center, constraint_axis); - projected_mouse -= snap_plane_center; - - dot = cam_to_snap_plane * constraint_axis; - if (llabs(dot) < 0.01f) - { - // looking at ring edge on, project onto view plane and check if mouse is past ring - getMousePointOnPlaneAgent(projected_mouse, x, y, snap_plane_center, cam_to_snap_plane); - projected_mouse -= snap_plane_center; - dot = projected_mouse * constraint_axis; - if (projected_mouse * constraint_axis < 0) - { - snap_plane = 2; - } - projected_mouse -= dot * constraint_axis; - } - else if (dot < 0.f) - { - // look for mouse position outside and in front of snap circle - if (hit && projected_mouse.magVec() > SNAP_GUIDE_INNER_RADIUS * mRadiusMeters && projected_mouse * cam_to_snap_plane < 0.f) - { - snap_plane = 2; - } - } - else - { - // look for mouse position inside or in back of snap circle - if (projected_mouse.magVec() < SNAP_GUIDE_INNER_RADIUS * mRadiusMeters || projected_mouse * cam_to_snap_plane > 0.f || !hit) - { - snap_plane = 2; - } - } - } - - if (snap_plane > 0) - { - LLVector3 cam_at_axis; - if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD) - { - cam_at_axis.setVec(1.f, 0.f, 0.f); - } - else - { - cam_at_axis = snap_plane_center - gAgentCamera.getCameraPositionAgent(); - cam_at_axis.normVec(); - } - - // first, project mouse onto screen plane at point tangent to rotation radius. - getMousePointOnPlaneAgent(projected_mouse, x, y, snap_plane_center, cam_at_axis); - // project that point onto rotation plane - projected_mouse -= snap_plane_center; - projected_mouse -= projected_vec(projected_mouse, constraint_axis); - - F32 mouse_lateral_dist = llmin(SNAP_GUIDE_INNER_RADIUS * mRadiusMeters, projected_mouse.magVec()); - F32 mouse_depth = SNAP_GUIDE_INNER_RADIUS * mRadiusMeters; - if (llabs(mouse_lateral_dist) > 0.01f) - { - mouse_depth = sqrtf((SNAP_GUIDE_INNER_RADIUS * mRadiusMeters) * (SNAP_GUIDE_INNER_RADIUS * mRadiusMeters) - - (mouse_lateral_dist * mouse_lateral_dist)); - } - LLVector3 projected_camera_at = cam_at_axis - projected_vec(cam_at_axis, constraint_axis); - projected_mouse -= mouse_depth * projected_camera_at; - - if (!mInSnapRegime) - { - mSmoothRotate = true; - } - mInSnapRegime = true; - // 0 to 360 deg - F32 mouse_angle = fmodf(atan2(projected_mouse * axis1, projected_mouse * axis2) * RAD_TO_DEG + 360.f, 360.f); - - F32 relative_mouse_angle = fmodf(mouse_angle + (SNAP_ANGLE_DETENTE / 2), SNAP_ANGLE_INCREMENT); - - LLVector3 object_axis; - getObjectAxisClosestToMouse(object_axis); - if (first_object_node) - { - object_axis = object_axis * first_object_node->mSavedRotation; - } - - // project onto constraint plane - object_axis = object_axis - (object_axis * getConstraintAxis()) * getConstraintAxis(); - object_axis.normVec(); - - if (relative_mouse_angle < SNAP_ANGLE_DETENTE) - { - F32 quantized_mouse_angle = mouse_angle - (relative_mouse_angle - (SNAP_ANGLE_DETENTE * 0.5f)); - angle = (quantized_mouse_angle * DEG_TO_RAD) - atan2(object_axis * axis1, object_axis * axis2); - } - else - { - angle = (mouse_angle * DEG_TO_RAD) - atan2(object_axis * axis1, object_axis * axis2); - } - return LLQuaternion( -angle, constraint_axis ); - } - else - { - if (mInSnapRegime) - { - mSmoothRotate = true; - } - mInSnapRegime = false; - } - } - else { - if (mInSnapRegime) - { - mSmoothRotate = true; - } - mInSnapRegime = false; - } - - if (!mInSnapRegime) - { - LLVector3 up_from_axis = mCenterToCamNorm % constraint_axis; - up_from_axis.normVec(); - LLVector3 cur_intersection; - getMousePointOnPlaneAgent(cur_intersection, x, y, center, mCenterToCam); - cur_intersection -= center; - mMouseCur = projected_vec(cur_intersection, up_from_axis); - F32 mouse_depth = SNAP_GUIDE_INNER_RADIUS * mRadiusMeters; - F32 mouse_dist_sqrd = mMouseCur.magVecSquared(); - if (mouse_dist_sqrd > 0.0001f) - { - mouse_depth = sqrtf((SNAP_GUIDE_INNER_RADIUS * mRadiusMeters) * (SNAP_GUIDE_INNER_RADIUS * mRadiusMeters) - - mouse_dist_sqrd); - } - LLVector3 projected_center_to_cam = mCenterToCamNorm - projected_vec(mCenterToCamNorm, constraint_axis); - mMouseCur += mouse_depth * projected_center_to_cam; - - F32 dist = (cur_intersection * up_from_axis) - (mMouseDown * up_from_axis); - angle = dist / (SNAP_GUIDE_INNER_RADIUS * mRadiusMeters) * -F_PI_BY_TWO; - } - } - else - { - LLVector3 projected_mouse; - getMousePointOnPlaneAgent(projected_mouse, x, y, center, constraint_axis); - projected_mouse -= center; - mMouseCur = projected_mouse; - mMouseCur.normVec(); - - if (!first_object_node) - { - return LLQuaternion::DEFAULT; - } - - if (gSavedSettings.getBOOL("SnapEnabled") && projected_mouse.magVec() > SNAP_GUIDE_INNER_RADIUS * mRadiusMeters) - { - if (!mInSnapRegime) - { - mSmoothRotate = true; - } - mInSnapRegime = true; - // 0 to 360 deg - F32 mouse_angle = fmodf(atan2(projected_mouse * axis1, projected_mouse * axis2) * RAD_TO_DEG + 360.f, 360.f); - - F32 relative_mouse_angle = fmodf(mouse_angle + (SNAP_ANGLE_DETENTE / 2), SNAP_ANGLE_INCREMENT); - - LLVector3 object_axis; - getObjectAxisClosestToMouse(object_axis); - object_axis = object_axis * first_object_node->mSavedRotation; - - // project onto constraint plane - object_axis = object_axis - (object_axis * getConstraintAxis()) * getConstraintAxis(); - object_axis.normVec(); - - if (relative_mouse_angle < SNAP_ANGLE_DETENTE) - { - F32 quantized_mouse_angle = mouse_angle - (relative_mouse_angle - (SNAP_ANGLE_DETENTE * 0.5f)); - angle = (quantized_mouse_angle * DEG_TO_RAD) - atan2(object_axis * axis1, object_axis * axis2); - } - else - { - angle = (mouse_angle * DEG_TO_RAD) - atan2(object_axis * axis1, object_axis * axis2); - } - return LLQuaternion( -angle, constraint_axis ); - } - else - { - if (mInSnapRegime) - { - mSmoothRotate = true; - } - mInSnapRegime = false; - } - - LLVector3 cross_product = mMouseDown % mMouseCur; - angle = atan2(sqrtf(cross_product * cross_product), mMouseCur * mMouseDown); - F32 dir = cross_product * constraint_axis; // cross product - if( dir < 0.f ) - { - angle *= -1.f; - } - } - - F32 rot_step = gSavedSettings.getF32("RotationStep"); - F32 step_size = DEG_TO_RAD * rot_step; - angle -= fmod(angle, step_size); - - return LLQuaternion( angle, constraint_axis ); -} - - - -LLVector3 LLManipRotate::intersectMouseWithSphere( S32 x, S32 y, const LLVector3& sphere_center, F32 sphere_radius) -{ - LLVector3 ray_pt; - LLVector3 ray_dir; - mouseToRay( x, y, &ray_pt, &ray_dir); - return intersectRayWithSphere( ray_pt, ray_dir, sphere_center, sphere_radius ); -} - -LLVector3 LLManipRotate::intersectRayWithSphere( const LLVector3& ray_pt, const LLVector3& ray_dir, const LLVector3& sphere_center, F32 sphere_radius) -{ - LLVector3 ray_pt_to_center = sphere_center - ray_pt; - F32 center_distance = ray_pt_to_center.normVec(); - - F32 dot = ray_dir * ray_pt_to_center; - - if (dot == 0.f) - { - return LLVector3::zero; - } - - // point which ray hits plane centered on sphere origin, facing ray origin - LLVector3 intersection_sphere_plane = ray_pt + (ray_dir * center_distance / dot); - // vector from sphere origin to the point, normalized to sphere radius - LLVector3 sphere_center_to_intersection = (intersection_sphere_plane - sphere_center) / sphere_radius; - - F32 dist_squared = sphere_center_to_intersection.magVecSquared(); - LLVector3 result; - - if (dist_squared > 1.f) - { - result = sphere_center_to_intersection; - result.normVec(); - } - else - { - result = sphere_center_to_intersection - ray_dir * sqrt(1.f - dist_squared); - } - - return result; -} - -// Utility function. Should probably be moved to another class. -// x,y - mouse position in scaled window coordinates (NOT GL viewport coordinates) -//static -void LLManipRotate::mouseToRay( S32 x, S32 y, LLVector3* ray_pt, LLVector3* ray_dir ) -{ - if (LLSelectMgr::getInstance()->getSelection()->getSelectType() == SELECT_TYPE_HUD) - { - F32 mouse_x = (((F32)x / gViewerWindow->getWorldViewRectScaled().getWidth()) - 0.5f) / gAgentCamera.mHUDCurZoom; - F32 mouse_y = ((((F32)y) / gViewerWindow->getWorldViewRectScaled().getHeight()) - 0.5f) / gAgentCamera.mHUDCurZoom; - - *ray_pt = LLVector3(-1.f, -mouse_x, mouse_y); - *ray_dir = LLVector3(1.f, 0.f, 0.f); - } - else - { - *ray_pt = gAgentCamera.getCameraPositionAgent(); - *ray_dir = gViewerWindow->mouseDirectionGlobal(x, y); - } -} - -void LLManipRotate::highlightManipulators( S32 x, S32 y ) -{ - mHighlightedPart = LL_NO_PART; - - //LLBBox bbox = LLSelectMgr::getInstance()->getBBoxOfSelection(); - LLViewerObject *first_object = mObjectSelection->getFirstMoveableObject(true); - - if (!first_object) - { - return; - } - - LLVector3 rotation_center = gAgent.getPosAgentFromGlobal(mRotationCenter); - LLVector3 mouse_dir_x; - LLVector3 mouse_dir_y; - LLVector3 mouse_dir_z; - LLVector3 intersection_roll; - - LLVector3 grid_origin; - LLVector3 grid_scale; - LLQuaternion grid_rotation; - - LLSelectMgr::getInstance()->getGrid(grid_origin, grid_rotation, grid_scale); - - LLVector3 rot_x_axis = LLVector3::x_axis * grid_rotation; - LLVector3 rot_y_axis = LLVector3::y_axis * grid_rotation; - LLVector3 rot_z_axis = LLVector3::z_axis * grid_rotation; - - F32 proj_rot_x_axis = llabs(rot_x_axis * mCenterToCamNorm); - F32 proj_rot_y_axis = llabs(rot_y_axis * mCenterToCamNorm); - F32 proj_rot_z_axis = llabs(rot_z_axis * mCenterToCamNorm); - - F32 min_select_distance = 0.f; - F32 cur_select_distance = 0.f; - - // test x - getMousePointOnPlaneAgent(mouse_dir_x, x, y, rotation_center, rot_x_axis); - mouse_dir_x -= rotation_center; - // push intersection point out when working at obtuse angle to make ring easier to hit - mouse_dir_x *= 1.f + (1.f - llabs(rot_x_axis * mCenterToCamNorm)) * 0.1f; - - // test y - getMousePointOnPlaneAgent(mouse_dir_y, x, y, rotation_center, rot_y_axis); - mouse_dir_y -= rotation_center; - mouse_dir_y *= 1.f + (1.f - llabs(rot_y_axis * mCenterToCamNorm)) * 0.1f; - - // test z - getMousePointOnPlaneAgent(mouse_dir_z, x, y, rotation_center, rot_z_axis); - mouse_dir_z -= rotation_center; - mouse_dir_z *= 1.f + (1.f - llabs(rot_z_axis * mCenterToCamNorm)) * 0.1f; - - // test roll - getMousePointOnPlaneAgent(intersection_roll, x, y, rotation_center, mCenterToCamNorm); - intersection_roll -= rotation_center; - - F32 dist_x = mouse_dir_x.normVec(); - F32 dist_y = mouse_dir_y.normVec(); - F32 dist_z = mouse_dir_z.normVec(); - - F32 distance_threshold = (MAX_MANIP_SELECT_DISTANCE * mRadiusMeters) / gViewerWindow->getWorldViewHeightScaled(); - - if (llabs(dist_x - mRadiusMeters) * llmax(0.05f, proj_rot_x_axis) < distance_threshold) - { - // selected x - cur_select_distance = dist_x * mouse_dir_x * mCenterToCamNorm; - if (cur_select_distance >= -0.05f && (min_select_distance == 0.f || cur_select_distance > min_select_distance)) - { - min_select_distance = cur_select_distance; - mHighlightedPart = LL_ROT_X; - } - } - if (llabs(dist_y - mRadiusMeters) * llmax(0.05f, proj_rot_y_axis) < distance_threshold) - { - // selected y - cur_select_distance = dist_y * mouse_dir_y * mCenterToCamNorm; - if (cur_select_distance >= -0.05f && (min_select_distance == 0.f || cur_select_distance > min_select_distance)) - { - min_select_distance = cur_select_distance; - mHighlightedPart = LL_ROT_Y; - } - } - if (llabs(dist_z - mRadiusMeters) * llmax(0.05f, proj_rot_z_axis) < distance_threshold) - { - // selected z - cur_select_distance = dist_z * mouse_dir_z * mCenterToCamNorm; - if (cur_select_distance >= -0.05f && (min_select_distance == 0.f || cur_select_distance > min_select_distance)) - { - min_select_distance = cur_select_distance; - mHighlightedPart = LL_ROT_Z; - } - } - - // test for edge-on intersections - if (proj_rot_x_axis < 0.05f) - { - if ((proj_rot_y_axis > 0.05f && (dist_y * llabs(mouse_dir_y * rot_x_axis) < distance_threshold) && dist_y < mRadiusMeters) || - (proj_rot_z_axis > 0.05f && (dist_z * llabs(mouse_dir_z * rot_x_axis) < distance_threshold) && dist_z < mRadiusMeters)) - { - mHighlightedPart = LL_ROT_X; - } - } - - if (proj_rot_y_axis < 0.05f) - { - if ((proj_rot_x_axis > 0.05f && (dist_x * llabs(mouse_dir_x * rot_y_axis) < distance_threshold) && dist_x < mRadiusMeters) || - (proj_rot_z_axis > 0.05f && (dist_z * llabs(mouse_dir_z * rot_y_axis) < distance_threshold) && dist_z < mRadiusMeters)) - { - mHighlightedPart = LL_ROT_Y; - } - } - - if (proj_rot_z_axis < 0.05f) - { - if ((proj_rot_x_axis > 0.05f && (dist_x * llabs(mouse_dir_x * rot_z_axis) < distance_threshold) && dist_x < mRadiusMeters) || - (proj_rot_y_axis > 0.05f && (dist_y * llabs(mouse_dir_y * rot_z_axis) < distance_threshold) && dist_y < mRadiusMeters)) - { - mHighlightedPart = LL_ROT_Z; - } - } - - // test for roll - if (mHighlightedPart == LL_NO_PART) - { - F32 roll_distance = intersection_roll.magVec(); - F32 width_meters = WIDTH_PIXELS * mRadiusMeters / RADIUS_PIXELS; - - // use larger distance threshold for roll as it is checked only if something else wasn't highlighted - if (llabs(roll_distance - (mRadiusMeters + (width_meters * 2.f))) < distance_threshold * 2.f) - { - mHighlightedPart = LL_ROT_ROLL; - } - else if (roll_distance < mRadiusMeters) - { - mHighlightedPart = LL_ROT_GENERAL; - } - } -} - -S32 LLManipRotate::getObjectAxisClosestToMouse(LLVector3& object_axis) -{ - LLSelectNode* first_object_node = mObjectSelection->getFirstMoveableNode(true); - - if (!first_object_node) - { - object_axis.clearVec(); - return -1; - } - - LLQuaternion obj_rotation = first_object_node->mSavedRotation; - LLVector3 mouse_down_object = mMouseDown * ~obj_rotation; - LLVector3 mouse_down_abs = mouse_down_object; - mouse_down_abs.abs(); - - S32 axis_index = 0; - if (mouse_down_abs.mV[VX] > mouse_down_abs.mV[VY] && mouse_down_abs.mV[VX] > mouse_down_abs.mV[VZ]) - { - if (mouse_down_object.mV[VX] > 0.f) - { - object_axis = LLVector3::x_axis; - } - else - { - object_axis = LLVector3::x_axis_neg; - } - axis_index = VX; - } - else if (mouse_down_abs.mV[VY] > mouse_down_abs.mV[VZ]) - { - if (mouse_down_object.mV[VY] > 0.f) - { - object_axis = LLVector3::y_axis; - } - else - { - object_axis = LLVector3::y_axis_neg; - } - axis_index = VY; - } - else - { - if (mouse_down_object.mV[VZ] > 0.f) - { - object_axis = LLVector3::z_axis; - } - else - { - object_axis = LLVector3::z_axis_neg; - } - axis_index = VZ; - } - - return axis_index; -} - -//virtual -bool LLManipRotate::canAffectSelection() -{ - bool can_rotate = mObjectSelection->getObjectCount() != 0; - if (can_rotate) - { - struct f : public LLSelectedObjectFunctor - { - virtual bool apply(LLViewerObject* objectp) - { - LLViewerObject *root_object = (objectp == NULL) ? NULL : objectp->getRootEdit(); - return objectp->permMove() && !objectp->isPermanentEnforced() && - ((root_object == NULL) || !root_object->isPermanentEnforced()) && - (objectp->permModify() || !gSavedSettings.getBOOL("EditLinkedParts")); - } - } func; - can_rotate = mObjectSelection->applyToObjects(&func); - } - return can_rotate; -} - +/**
+ * @file llmaniprotate.cpp
+ * @brief LLManipRotate class implementation
+ *
+ * $LicenseInfo:firstyear=2002&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 "llmaniprotate.h"
+
+// library includes
+#include "llmath.h"
+#include "llgl.h"
+#include "llrender.h"
+#include "v4color.h"
+#include "llprimitive.h"
+#include "llview.h"
+#include "llfontgl.h"
+
+// viewer includes
+#include "llagent.h"
+#include "llagentcamera.h"
+#include "llbox.h"
+#include "llbutton.h"
+#include "llviewercontrol.h"
+#include "llcriticaldamp.h"
+#include "lltooltip.h"
+#include "llfloatertools.h"
+#include "llselectmgr.h"
+#include "llstatusbar.h"
+#include "llui.h"
+#include "llvoavatar.h"
+#include "llviewercamera.h"
+#include "llviewerobject.h"
+#include "llviewerobject.h"
+#include "llviewershadermgr.h"
+#include "llviewerwindow.h"
+#include "llworld.h"
+#include "pipeline.h"
+#include "lldrawable.h"
+#include "llglheaders.h"
+#include "lltrans.h"
+#include "llvoavatarself.h"
+#include "llhudrender.h"
+
+const F32 RADIUS_PIXELS = 100.f; // size in screen space
+const F32 SQ_RADIUS = RADIUS_PIXELS * RADIUS_PIXELS;
+const F32 WIDTH_PIXELS = 8;
+const S32 CIRCLE_STEPS = 100;
+const F32 MAX_MANIP_SELECT_DISTANCE = 100.f;
+const F32 SNAP_ANGLE_INCREMENT = 5.625f;
+const F32 SNAP_ANGLE_DETENTE = SNAP_ANGLE_INCREMENT;
+const F32 SNAP_GUIDE_RADIUS_1 = 2.8f;
+const F32 SNAP_GUIDE_RADIUS_2 = 2.4f;
+const F32 SNAP_GUIDE_RADIUS_3 = 2.2f;
+const F32 SNAP_GUIDE_RADIUS_4 = 2.1f;
+const F32 SNAP_GUIDE_RADIUS_5 = 2.05f;
+const F32 SNAP_GUIDE_INNER_RADIUS = 2.f;
+const F32 AXIS_ONTO_CAM_TOLERANCE = cos( 80.f * DEG_TO_RAD );
+const F32 SELECTED_MANIPULATOR_SCALE = 1.05f;
+const F32 MANIPULATOR_SCALE_HALF_LIFE = 0.07f;
+
+extern void handle_reset_rotation(void*); // in LLViewerWindow
+
+LLManipRotate::LLManipRotate( LLToolComposite* composite )
+: LLManip( std::string("Rotate"), composite ),
+ mRotationCenter(),
+ mCenterScreen(),
+ mRotation(),
+ mMouseDown(),
+ mMouseCur(),
+ mRadiusMeters(0.f),
+ mCenterToCam(),
+ mCenterToCamNorm(),
+ mCenterToCamMag(0.f),
+ mCenterToProfilePlane(),
+ mCenterToProfilePlaneMag(0.f),
+ mSendUpdateOnMouseUp( false ),
+ mSmoothRotate( false ),
+ mCamEdgeOn(false),
+ mManipulatorScales(1.f, 1.f, 1.f, 1.f)
+{ }
+
+void LLManipRotate::handleSelect()
+{
+ // *FIX: put this in mouseDown?
+ LLSelectMgr::getInstance()->saveSelectedObjectTransform(SELECT_ACTION_TYPE_PICK);
+ if (gFloaterTools)
+ {
+ gFloaterTools->setStatusText("rotate");
+ }
+ LLManip::handleSelect();
+}
+
+void LLManipRotate::render()
+{
+ LLGLSUIDefault gls_ui;
+ gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sWhiteImagep);
+ LLGLDepthTest gls_depth(GL_TRUE);
+ LLGLEnable gl_blend(GL_BLEND);
+
+ // You can rotate if you can move
+ LLViewerObject* first_object = mObjectSelection->getFirstMoveableObject(true);
+ if( !first_object )
+ {
+ return;
+ }
+
+ if( !updateVisiblity() )
+ {
+ return;
+ }
+
+ gGL.matrixMode(LLRender::MM_MODELVIEW);
+ gGL.pushMatrix();
+ if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD)
+ {
+ F32 zoom = gAgentCamera.mHUDCurZoom;
+ gGL.scalef(zoom, zoom, zoom);
+ }
+
+
+ LLVector3 center = gAgent.getPosAgentFromGlobal( mRotationCenter );
+
+ LLColor4 highlight_outside( 1.f, 1.f, 0.f, 1.f );
+ LLColor4 highlight_inside( 0.7f, 0.7f, 0.f, 0.5f );
+ F32 width_meters = WIDTH_PIXELS * mRadiusMeters / RADIUS_PIXELS;
+
+ gGL.pushMatrix();
+ {
+
+ // are we in the middle of a constrained drag?
+ if (mManipPart >= LL_ROT_X && mManipPart <= LL_ROT_Z)
+ {
+ renderSnapGuides();
+ }
+ else
+ {
+ gDebugProgram.bind();
+
+ LLGLEnable cull_face(GL_CULL_FACE);
+ LLGLDepthTest gls_depth(GL_FALSE);
+ gGL.pushMatrix();
+ {
+ // Draw "sphere" (intersection of sphere with tangent cone that has apex at camera)
+ gGL.translatef( mCenterToProfilePlane.mV[VX], mCenterToProfilePlane.mV[VY], mCenterToProfilePlane.mV[VZ] );
+ gGL.translatef( center.mV[VX], center.mV[VY], center.mV[VZ] );
+
+ // Inverse change of basis vectors
+ LLVector3 forward = mCenterToCamNorm;
+ LLVector3 left = gAgent.getUpAxis() % forward;
+ left.normVec();
+ LLVector3 up = forward % left;
+
+ LLVector4 a(-forward);
+ a.mV[3] = 0;
+ LLVector4 b(up);
+ b.mV[3] = 0;
+ LLVector4 c(left);
+ c.mV[3] = 0;
+ LLMatrix4 mat;
+ mat.initRows(a, b, c, LLVector4(0.f, 0.f, 0.f, 1.f));
+
+ gGL.multMatrix( &mat.mMatrix[0][0] );
+
+ gGL.rotatef( -90, 0.f, 1.f, 0.f);
+ LLColor4 color;
+ if (mManipPart == LL_ROT_ROLL || mHighlightedPart == LL_ROT_ROLL)
+ {
+ color.setVec(0.8f, 0.8f, 0.8f, 0.8f);
+ gGL.scalef(mManipulatorScales.mV[VW], mManipulatorScales.mV[VW], mManipulatorScales.mV[VW]);
+ }
+ else
+ {
+ color.setVec( 0.7f, 0.7f, 0.7f, 0.6f );
+ }
+ gGL.diffuseColor4fv(color.mV);
+ gl_washer_2d(mRadiusMeters + width_meters, mRadiusMeters, CIRCLE_STEPS, color, color);
+
+
+ if (mManipPart == LL_NO_PART)
+ {
+ gGL.color4f( 0.7f, 0.7f, 0.7f, 0.3f );
+ gGL.diffuseColor4f(0.7f, 0.7f, 0.7f, 0.3f);
+ gl_circle_2d( 0, 0, mRadiusMeters, CIRCLE_STEPS, true );
+ }
+
+ gGL.flush();
+ }
+ gGL.popMatrix();
+
+ gUIProgram.bind();
+ }
+
+ gGL.translatef( center.mV[VX], center.mV[VY], center.mV[VZ] );
+
+ LLQuaternion rot;
+ F32 angle_radians, x, y, z;
+
+ LLVector3 grid_origin;
+ LLVector3 grid_scale;
+ LLQuaternion grid_rotation;
+
+ LLSelectMgr::getInstance()->getGrid(grid_origin, grid_rotation, grid_scale);
+
+ grid_rotation.getAngleAxis(&angle_radians, &x, &y, &z);
+ gGL.rotatef(angle_radians * RAD_TO_DEG, x, y, z);
+
+
+ gDebugProgram.bind();
+
+ if (mManipPart == LL_ROT_Z)
+ {
+ mManipulatorScales = lerp(mManipulatorScales, LLVector4(1.f, 1.f, SELECTED_MANIPULATOR_SCALE, 1.f), LLSmoothInterpolation::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE));
+ gGL.pushMatrix();
+ {
+ // selected part
+ gGL.scalef(mManipulatorScales.mV[VZ], mManipulatorScales.mV[VZ], mManipulatorScales.mV[VZ]);
+ renderActiveRing( mRadiusMeters, width_meters, LLColor4( 0.f, 0.f, 1.f, 1.f) , LLColor4( 0.f, 0.f, 1.f, 0.3f ));
+ }
+ gGL.popMatrix();
+ }
+ else if (mManipPart == LL_ROT_Y)
+ {
+ mManipulatorScales = lerp(mManipulatorScales, LLVector4(1.f, SELECTED_MANIPULATOR_SCALE, 1.f, 1.f), LLSmoothInterpolation::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE));
+ gGL.pushMatrix();
+ {
+ gGL.rotatef( 90.f, 1.f, 0.f, 0.f );
+ gGL.scalef(mManipulatorScales.mV[VY], mManipulatorScales.mV[VY], mManipulatorScales.mV[VY]);
+ renderActiveRing( mRadiusMeters, width_meters, LLColor4( 0.f, 1.f, 0.f, 1.f), LLColor4( 0.f, 1.f, 0.f, 0.3f));
+ }
+ gGL.popMatrix();
+ }
+ else if (mManipPart == LL_ROT_X)
+ {
+ mManipulatorScales = lerp(mManipulatorScales, LLVector4(SELECTED_MANIPULATOR_SCALE, 1.f, 1.f, 1.f), LLSmoothInterpolation::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE));
+ gGL.pushMatrix();
+ {
+ gGL.rotatef( 90.f, 0.f, 1.f, 0.f );
+ gGL.scalef(mManipulatorScales.mV[VX], mManipulatorScales.mV[VX], mManipulatorScales.mV[VX]);
+ renderActiveRing( mRadiusMeters, width_meters, LLColor4( 1.f, 0.f, 0.f, 1.f), LLColor4( 1.f, 0.f, 0.f, 0.3f));
+ }
+ gGL.popMatrix();
+ }
+ else if (mManipPart == LL_ROT_ROLL)
+ {
+ mManipulatorScales = lerp(mManipulatorScales, LLVector4(1.f, 1.f, 1.f, SELECTED_MANIPULATOR_SCALE), LLSmoothInterpolation::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE));
+ }
+ else if (mManipPart == LL_NO_PART)
+ {
+ if (mHighlightedPart == LL_NO_PART)
+ {
+ mManipulatorScales = lerp(mManipulatorScales, LLVector4(1.f, 1.f, 1.f, 1.f), LLSmoothInterpolation::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE));
+ }
+
+ LLGLEnable cull_face(GL_CULL_FACE);
+ LLGLEnable clip_plane0(GL_CLIP_PLANE0);
+ LLGLDepthTest gls_depth(GL_FALSE);
+ //LLGLDisable gls_stencil(GL_STENCIL_TEST);
+
+ // First pass: centers. Second pass: sides.
+ for( S32 i=0; i<2; i++ )
+ {
+
+ gGL.pushMatrix();
+ {
+ if (mHighlightedPart == LL_ROT_Z)
+ {
+ mManipulatorScales = lerp(mManipulatorScales, LLVector4(1.f, 1.f, SELECTED_MANIPULATOR_SCALE, 1.f), LLSmoothInterpolation::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE));
+ gGL.scalef(mManipulatorScales.mV[VZ], mManipulatorScales.mV[VZ], mManipulatorScales.mV[VZ]);
+ // hovering over part
+ gl_ring( mRadiusMeters, width_meters, LLColor4( 0.f, 0.f, 1.f, 1.f ), LLColor4( 0.f, 0.f, 1.f, 0.5f ), CIRCLE_STEPS, i);
+ }
+ else
+ {
+ // default
+ gl_ring( mRadiusMeters, width_meters, LLColor4( 0.f, 0.f, 0.8f, 0.8f ), LLColor4( 0.f, 0.f, 0.8f, 0.4f ), CIRCLE_STEPS, i);
+ }
+ }
+ gGL.popMatrix();
+
+ gGL.pushMatrix();
+ {
+ gGL.rotatef( 90.f, 1.f, 0.f, 0.f );
+ if (mHighlightedPart == LL_ROT_Y)
+ {
+ mManipulatorScales = lerp(mManipulatorScales, LLVector4(1.f, SELECTED_MANIPULATOR_SCALE, 1.f, 1.f), LLSmoothInterpolation::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE));
+ gGL.scalef(mManipulatorScales.mV[VY], mManipulatorScales.mV[VY], mManipulatorScales.mV[VY]);
+ // hovering over part
+ gl_ring( mRadiusMeters, width_meters, LLColor4( 0.f, 1.f, 0.f, 1.f ), LLColor4( 0.f, 1.f, 0.f, 0.5f ), CIRCLE_STEPS, i);
+ }
+ else
+ {
+ // default
+ gl_ring( mRadiusMeters, width_meters, LLColor4( 0.f, 0.8f, 0.f, 0.8f ), LLColor4( 0.f, 0.8f, 0.f, 0.4f ), CIRCLE_STEPS, i);
+ }
+ }
+ gGL.popMatrix();
+
+ gGL.pushMatrix();
+ {
+ gGL.rotatef( 90.f, 0.f, 1.f, 0.f );
+ if (mHighlightedPart == LL_ROT_X)
+ {
+ mManipulatorScales = lerp(mManipulatorScales, LLVector4(SELECTED_MANIPULATOR_SCALE, 1.f, 1.f, 1.f), LLSmoothInterpolation::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE));
+ gGL.scalef(mManipulatorScales.mV[VX], mManipulatorScales.mV[VX], mManipulatorScales.mV[VX]);
+
+ // hovering over part
+ gl_ring( mRadiusMeters, width_meters, LLColor4( 1.f, 0.f, 0.f, 1.f ), LLColor4( 1.f, 0.f, 0.f, 0.5f ), CIRCLE_STEPS, i);
+ }
+ else
+ {
+ // default
+ gl_ring( mRadiusMeters, width_meters, LLColor4( 0.8f, 0.f, 0.f, 0.8f ), LLColor4( 0.8f, 0.f, 0.f, 0.4f ), CIRCLE_STEPS, i);
+ }
+ }
+ gGL.popMatrix();
+
+ if (mHighlightedPart == LL_ROT_ROLL)
+ {
+ mManipulatorScales = lerp(mManipulatorScales, LLVector4(1.f, 1.f, 1.f, SELECTED_MANIPULATOR_SCALE), LLSmoothInterpolation::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE));
+ }
+
+ }
+
+ }
+
+ gUIProgram.bind();
+ }
+ gGL.popMatrix();
+ gGL.popMatrix();
+
+
+ LLVector3 euler_angles;
+ LLQuaternion object_rot = first_object->getRotationEdit();
+ object_rot.getEulerAngles(&(euler_angles.mV[VX]), &(euler_angles.mV[VY]), &(euler_angles.mV[VZ]));
+ euler_angles *= RAD_TO_DEG;
+ euler_angles.mV[VX] = ll_round(fmodf(euler_angles.mV[VX] + 360.f, 360.f), 0.05f);
+ euler_angles.mV[VY] = ll_round(fmodf(euler_angles.mV[VY] + 360.f, 360.f), 0.05f);
+ euler_angles.mV[VZ] = ll_round(fmodf(euler_angles.mV[VZ] + 360.f, 360.f), 0.05f);
+
+ renderXYZ(euler_angles);
+}
+
+bool LLManipRotate::handleMouseDown(S32 x, S32 y, MASK mask)
+{
+ bool handled = false;
+
+ LLViewerObject* first_object = mObjectSelection->getFirstMoveableObject(true);
+ if( first_object )
+ {
+ if( mHighlightedPart != LL_NO_PART )
+ {
+ handled = handleMouseDownOnPart( x, y, mask );
+ }
+ }
+
+ return handled;
+}
+
+// Assumes that one of the parts of the manipulator was hit.
+bool LLManipRotate::handleMouseDownOnPart( S32 x, S32 y, MASK mask )
+{
+ bool can_rotate = canAffectSelection();
+ if (!can_rotate)
+ {
+ return false;
+ }
+
+ highlightManipulators(x, y);
+ S32 hit_part = mHighlightedPart;
+ // we just started a drag, so save initial object positions
+ LLSelectMgr::getInstance()->saveSelectedObjectTransform(SELECT_ACTION_TYPE_ROTATE);
+
+ // save selection center
+ mRotationCenter = gAgent.getPosGlobalFromAgent( getPivotPoint() ); //LLSelectMgr::getInstance()->getSelectionCenterGlobal();
+
+ mManipPart = (EManipPart)hit_part;
+ LLVector3 center = gAgent.getPosAgentFromGlobal( mRotationCenter );
+
+ if( mManipPart == LL_ROT_GENERAL)
+ {
+ mMouseDown = intersectMouseWithSphere( x, y, center, mRadiusMeters);
+ }
+ else
+ {
+ // Project onto the plane of the ring
+ LLVector3 axis = getConstraintAxis();
+
+ F32 axis_onto_cam = llabs( axis * mCenterToCamNorm );
+ const F32 AXIS_ONTO_CAM_TOL = cos( 85.f * DEG_TO_RAD );
+ if( axis_onto_cam < AXIS_ONTO_CAM_TOL )
+ {
+ LLVector3 up_from_axis = mCenterToCamNorm % axis;
+ up_from_axis.normVec();
+ LLVector3 cur_intersection;
+ getMousePointOnPlaneAgent(cur_intersection, x, y, center, mCenterToCam);
+ cur_intersection -= center;
+ mMouseDown = projected_vec(cur_intersection, up_from_axis);
+ F32 mouse_depth = SNAP_GUIDE_INNER_RADIUS * mRadiusMeters;
+ F32 mouse_dist_sqrd = mMouseDown.magVecSquared();
+ if (mouse_dist_sqrd > 0.0001f)
+ {
+ mouse_depth = sqrtf((SNAP_GUIDE_INNER_RADIUS * mRadiusMeters) * (SNAP_GUIDE_INNER_RADIUS * mRadiusMeters) -
+ mouse_dist_sqrd);
+ }
+ LLVector3 projected_center_to_cam = mCenterToCamNorm - projected_vec(mCenterToCamNorm, axis);
+ mMouseDown += mouse_depth * projected_center_to_cam;
+
+ }
+ else
+ {
+ mMouseDown = findNearestPointOnRing( x, y, center, axis ) - center;
+ mMouseDown.normVec();
+ }
+ }
+
+ mMouseCur = mMouseDown;
+ mAgentSelfAtAxis = gAgent.getAtAxis(); // no point checking if avatar was selected, just save the value
+
+ // Route future Mouse messages here preemptively. (Release on mouse up.)
+ setMouseCapture( true );
+ LLSelectMgr::getInstance()->enableSilhouette(false);
+
+ mHelpTextTimer.reset();
+ sNumTimesHelpTextShown++;
+ return true;
+}
+
+
+LLVector3 LLManipRotate::findNearestPointOnRing( S32 x, S32 y, const LLVector3& center, const LLVector3& axis )
+{
+ // Project the delta onto the ring and rescale it by the radius so that it's _on_ the ring.
+ LLVector3 proj_onto_ring;
+ getMousePointOnPlaneAgent(proj_onto_ring, x, y, center, axis);
+ proj_onto_ring -= center;
+ proj_onto_ring.normVec();
+
+ return center + proj_onto_ring * mRadiusMeters;
+}
+
+bool LLManipRotate::handleMouseUp(S32 x, S32 y, MASK mask)
+{
+ // first, perform normal processing in case this was a quick-click
+ handleHover(x, y, mask);
+
+ if( hasMouseCapture() )
+ {
+ for (LLObjectSelection::iterator iter = mObjectSelection->begin();
+ iter != mObjectSelection->end(); iter++)
+ {
+ LLSelectNode* selectNode = *iter;
+ LLViewerObject* object = selectNode->getObject();
+ LLViewerObject* root_object = (object == NULL) ? NULL : object->getRootEdit();
+
+ // have permission to move and object is root of selection or individually selected
+ if (object->permMove() && !object->isPermanentEnforced() &&
+ ((root_object == NULL) || !root_object->isPermanentEnforced()) &&
+ (object->isRootEdit() || selectNode->mIndividualSelection))
+ {
+ object->mUnselectedChildrenPositions.clear() ;
+ }
+ }
+
+ mManipPart = LL_NO_PART;
+
+ // Might have missed last update due to timing.
+ LLSelectMgr::getInstance()->sendMultipleUpdate( UPD_ROTATION | UPD_POSITION );
+ LLSelectMgr::getInstance()->enableSilhouette(true);
+ //gAgent.setObjectTracking(gSavedSettings.getBOOL("TrackFocusObject"));
+
+ LLSelectMgr::getInstance()->updateSelectionCenter();
+ LLSelectMgr::getInstance()->saveSelectedObjectTransform(SELECT_ACTION_TYPE_PICK);
+ }
+
+ return LLManip::handleMouseUp(x, y, mask);
+}
+
+
+bool LLManipRotate::handleHover(S32 x, S32 y, MASK mask)
+{
+ if( hasMouseCapture() )
+ {
+ if( mObjectSelection->isEmpty() )
+ {
+ // Somehow the object got deselected while we were dragging it.
+ setMouseCapture( false );
+ }
+ else
+ {
+ drag(x, y);
+ }
+
+ LL_DEBUGS("UserInput") << "hover handled by LLManipRotate (active)" << LL_ENDL;
+ }
+ else
+ {
+ highlightManipulators(x, y);
+ LL_DEBUGS("UserInput") << "hover handled by LLManipRotate (inactive)" << LL_ENDL;
+ }
+
+ gViewerWindow->setCursor(UI_CURSOR_TOOLROTATE);
+ return true;
+}
+
+
+LLVector3 LLManipRotate::projectToSphere( F32 x, F32 y, bool* on_sphere )
+{
+ F32 z = 0.f;
+ F32 dist_squared = x*x + y*y;
+
+ *on_sphere = dist_squared <= SQ_RADIUS;
+ if( *on_sphere )
+ {
+ z = sqrt(SQ_RADIUS - dist_squared);
+ }
+ return LLVector3( x, y, z );
+}
+
+// Freeform rotation
+void LLManipRotate::drag( S32 x, S32 y )
+{
+ if( !updateVisiblity() )
+ {
+ return;
+ }
+
+ if( mManipPart == LL_ROT_GENERAL )
+ {
+ mRotation = dragUnconstrained(x, y);
+ }
+ else
+ {
+ mRotation = dragConstrained(x, y);
+ }
+
+ bool damped = mSmoothRotate;
+ mSmoothRotate = false;
+
+ for (LLObjectSelection::iterator iter = mObjectSelection->begin();
+ iter != mObjectSelection->end(); iter++)
+ {
+ LLSelectNode* selectNode = *iter;
+ LLViewerObject* object = selectNode->getObject();
+ LLViewerObject* root_object = (object == NULL) ? NULL : object->getRootEdit();
+
+ // have permission to move and object is root of selection or individually selected
+ if (object->permMove() && !object->isPermanentEnforced() &&
+ ((root_object == NULL) || !root_object->isPermanentEnforced()) &&
+ (object->isRootEdit() || selectNode->mIndividualSelection))
+ {
+ if (!object->isRootEdit())
+ {
+ // child objects should not update if parent is selected
+ LLViewerObject* editable_root = (LLViewerObject*)object->getParent();
+ if (editable_root->isSelected())
+ {
+ // we will be moved properly by our parent, so skip
+ continue;
+ }
+ }
+
+ LLQuaternion new_rot = selectNode->mSavedRotation * mRotation;
+ std::vector<LLVector3>& child_positions = object->mUnselectedChildrenPositions ;
+ std::vector<LLQuaternion> child_rotations;
+ if (object->isRootEdit() && selectNode->mIndividualSelection)
+ {
+ object->saveUnselectedChildrenRotation(child_rotations) ;
+ object->saveUnselectedChildrenPosition(child_positions) ;
+ }
+
+ if (object->getParent() && object->mDrawable.notNull())
+ {
+ LLQuaternion invParentRotation = object->mDrawable->mXform.getParent()->getWorldRotation();
+ invParentRotation.transQuat();
+
+ object->setRotation(new_rot * invParentRotation, damped);
+ rebuild(object);
+ }
+ else
+ {
+ object->setRotation(new_rot, damped);
+ LLVOAvatar* avatar = object->asAvatar();
+ if (avatar && avatar->isSelf()
+ && LLSelectMgr::getInstance()->mAllowSelectAvatar
+ && !object->getParent())
+ {
+ // Normal avatars use object's orienttion, but self uses
+ // separate LLCoordFrame
+ // See LVOAvatar::updateOrientation()
+ if (gAgentCamera.getFocusOnAvatar())
+ {
+ //Don't rotate camera with avatar
+ gAgentCamera.setFocusOnAvatar(false, false, false);
+ }
+
+ LLVector3 at_axis = mAgentSelfAtAxis;
+ at_axis *= mRotation;
+ at_axis.mV[VZ] = 0.f;
+ at_axis.normalize();
+ gAgent.resetAxes(at_axis);
+ }
+ rebuild(object);
+ }
+
+ // for individually selected roots, we need to counterrotate all the children
+ if (object->isRootEdit() && selectNode->mIndividualSelection)
+ {
+ //RN: must do non-damped updates on these objects so relative rotation appears constant
+ // instead of having two competing slerps making the child objects appear to "wobble"
+ object->resetChildrenRotationAndPosition(child_rotations, child_positions) ;
+ }
+ }
+ }
+
+ // update positions
+ for (LLObjectSelection::iterator iter = mObjectSelection->begin();
+ iter != mObjectSelection->end(); iter++)
+ {
+ LLSelectNode* selectNode = *iter;
+ LLViewerObject* object = selectNode->getObject();
+ LLViewerObject* root_object = (object == NULL) ? NULL : object->getRootEdit();
+
+ // to avoid cumulative position changes we calculate the objects new position using its saved position
+ if (object && object->permMove() && !object->isPermanentEnforced() &&
+ ((root_object == NULL) || !root_object->isPermanentEnforced()))
+ {
+ LLVector3 center = gAgent.getPosAgentFromGlobal( mRotationCenter );
+
+ LLVector3 old_position;
+ LLVector3 new_position;
+
+ if (object->isAttachment() && object->mDrawable.notNull())
+ {
+ // need to work in drawable space to handle selected items from multiple attachments
+ // (which have no shared frame of reference other than their render positions)
+ LLXform* parent_xform = object->mDrawable->getXform()->getParent();
+ new_position = (selectNode->mSavedPositionLocal * parent_xform->getWorldRotation()) + parent_xform->getWorldPosition();
+ old_position = (object->getPosition() * parent_xform->getWorldRotation()) + parent_xform->getWorldPosition();//object->getRenderPosition();
+ }
+ else
+ {
+ new_position = gAgent.getPosAgentFromGlobal( selectNode->mSavedPositionGlobal );
+ old_position = object->getPositionAgent();
+ }
+
+ new_position = (new_position - center) * mRotation; // new relative rotated position
+ new_position += center;
+
+ if (object->isRootEdit() && !object->isAttachment())
+ {
+ LLVector3d new_pos_global = gAgent.getPosGlobalFromAgent(new_position);
+ new_pos_global = LLWorld::getInstance()->clipToVisibleRegions(selectNode->mSavedPositionGlobal, new_pos_global);
+ new_position = gAgent.getPosAgentFromGlobal(new_pos_global);
+ }
+
+ // for individually selected child objects
+ if (!object->isRootEdit() && selectNode->mIndividualSelection)
+ {
+ LLViewerObject* parentp = (LLViewerObject*)object->getParent();
+ if (!parentp->isSelected())
+ {
+ if (object->isAttachment() && object->mDrawable.notNull())
+ {
+ // find position relative to render position of parent
+ object->setPosition((new_position - parentp->getRenderPosition()) * ~parentp->getRenderRotation());
+ rebuild(object);
+ }
+ else
+ {
+ object->setPositionParent((new_position - parentp->getPositionAgent()) * ~parentp->getRotationRegion());
+ rebuild(object);
+ }
+ }
+ }
+ else if (object->isRootEdit())
+ {
+ if (object->isAttachment() && object->mDrawable.notNull())
+ {
+ LLXform* parent_xform = object->mDrawable->getXform()->getParent();
+ object->setPosition((new_position - parent_xform->getWorldPosition()) * ~parent_xform->getWorldRotation());
+ rebuild(object);
+ }
+ else
+ {
+ object->setPositionAgent(new_position);
+ rebuild(object);
+ }
+ }
+
+ // for individually selected roots, we need to counter-translate all unselected children
+ if (object->isRootEdit() && selectNode->mIndividualSelection)
+ {
+ // only offset by parent's translation as we've already countered parent's rotation
+ rebuild(object);
+ object->resetChildrenPosition(old_position - new_position) ;
+ }
+ }
+ }
+
+ // store changes to override updates
+ for (LLObjectSelection::iterator iter = LLSelectMgr::getInstance()->getSelection()->begin();
+ iter != LLSelectMgr::getInstance()->getSelection()->end(); iter++)
+ {
+ LLSelectNode* selectNode = *iter;
+ LLViewerObject*cur = selectNode->getObject();
+ LLViewerObject *root_object = (cur == NULL) ? NULL : cur->getRootEdit();
+ if( cur->permModify() && cur->permMove() && !cur->isPermanentEnforced() &&
+ ((root_object == NULL) || !root_object->isPermanentEnforced()) &&
+ (!cur->isAvatar() || LLSelectMgr::getInstance()->mAllowSelectAvatar))
+ {
+ selectNode->mLastRotation = cur->getRotation();
+ selectNode->mLastPositionLocal = cur->getPosition();
+ }
+ }
+
+ LLSelectMgr::getInstance()->updateSelectionCenter();
+
+ // RN: just clear focus so camera doesn't follow spurious object updates
+ gAgentCamera.clearFocusObject();
+ dialog_refresh_all();
+}
+
+void LLManipRotate::renderActiveRing( F32 radius, F32 width, const LLColor4& front_color, const LLColor4& back_color)
+{
+ LLGLEnable cull_face(GL_CULL_FACE);
+ {
+ gl_ring(radius, width, back_color, back_color * 0.5f, CIRCLE_STEPS, false);
+ gl_ring(radius, width, back_color, back_color * 0.5f, CIRCLE_STEPS, true);
+ }
+ {
+ LLGLDepthTest gls_depth(GL_FALSE);
+ gl_ring(radius, width, front_color, front_color * 0.5f, CIRCLE_STEPS, false);
+ gl_ring(radius, width, front_color, front_color * 0.5f, CIRCLE_STEPS, true);
+ }
+}
+
+void LLManipRotate::renderSnapGuides()
+{
+ static LLCachedControl<bool> snap_enabled(gSavedSettings, "SnapEnabled", true);
+ if (!snap_enabled)
+ {
+ return;
+ }
+
+ LLVector3 grid_origin;
+ LLVector3 grid_scale;
+ LLQuaternion grid_rotation;
+
+ LLSelectMgr::getInstance()->getGrid(grid_origin, grid_rotation, grid_scale, true);
+
+ LLVector3 constraint_axis = getConstraintAxis();
+
+ LLVector3 center = gAgent.getPosAgentFromGlobal( mRotationCenter );
+ LLVector3 cam_at_axis;
+ if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD)
+ {
+ cam_at_axis.setVec(1.f, 0.f, 0.f);
+ }
+ else
+ {
+ cam_at_axis = center - gAgentCamera.getCameraPositionAgent();
+ cam_at_axis.normVec();
+ }
+
+ LLVector3 world_snap_axis;
+ LLVector3 test_axis = constraint_axis;
+
+ bool constrain_to_ref_object = false;
+ if (mObjectSelection->getSelectType() == SELECT_TYPE_ATTACHMENT && isAgentAvatarValid())
+ {
+ test_axis = test_axis * ~grid_rotation;
+ }
+ else if (LLSelectMgr::getInstance()->getGridMode() == GRID_MODE_REF_OBJECT)
+ {
+ test_axis = test_axis * ~grid_rotation;
+ constrain_to_ref_object = true;
+ }
+
+ test_axis.abs();
+
+ // find closest global/reference axis to local constraint axis;
+ if (test_axis.mV[VX] > test_axis.mV[VY] && test_axis.mV[VX] > test_axis.mV[VZ])
+ {
+ world_snap_axis = LLVector3::y_axis;
+ }
+ else if (test_axis.mV[VY] > test_axis.mV[VZ])
+ {
+ world_snap_axis = LLVector3::z_axis;
+ }
+ else
+ {
+ world_snap_axis = LLVector3::x_axis;
+ }
+
+ LLVector3 projected_snap_axis = world_snap_axis;
+ if (mObjectSelection->getSelectType() == SELECT_TYPE_ATTACHMENT && isAgentAvatarValid())
+ {
+ projected_snap_axis = projected_snap_axis * grid_rotation;
+ }
+ else if (constrain_to_ref_object)
+ {
+ projected_snap_axis = projected_snap_axis * grid_rotation;
+ }
+
+ // project world snap axis onto constraint plane
+ projected_snap_axis -= projected_vec(projected_snap_axis, constraint_axis);
+ projected_snap_axis.normVec();
+
+ S32 num_rings = mCamEdgeOn ? 2 : 1;
+ for (S32 ring_num = 0; ring_num < num_rings; ring_num++)
+ {
+ LLVector3 center = gAgent.getPosAgentFromGlobal( mRotationCenter );
+
+ if (mCamEdgeOn)
+ {
+ // draw two opposing rings
+ if (ring_num == 0)
+ {
+ center += constraint_axis * mRadiusMeters * 0.5f;
+ }
+ else
+ {
+ center -= constraint_axis * mRadiusMeters * 0.5f;
+ }
+ }
+
+ LLGLDepthTest gls_depth(GL_FALSE);
+ for (S32 pass = 0; pass < 3; pass++)
+ {
+ // render snap guide ring
+ gGL.pushMatrix();
+
+ LLQuaternion snap_guide_rot;
+ F32 angle_radians, x, y, z;
+ snap_guide_rot.shortestArc(LLVector3::z_axis, getConstraintAxis());
+ snap_guide_rot.getAngleAxis(&angle_radians, &x, &y, &z);
+ gGL.translatef(center.mV[VX], center.mV[VY], center.mV[VZ]);
+ gGL.rotatef(angle_radians * RAD_TO_DEG, x, y, z);
+
+ LLColor4 line_color = setupSnapGuideRenderPass(pass);
+
+ gGL.color4fv(line_color.mV);
+
+ if (mCamEdgeOn)
+ {
+ // render an arc
+ LLVector3 edge_normal = cam_at_axis % constraint_axis;
+ edge_normal.normVec();
+ LLVector3 x_axis_snap = LLVector3::x_axis * snap_guide_rot;
+ LLVector3 y_axis_snap = LLVector3::y_axis * snap_guide_rot;
+
+ F32 end_angle = atan2(y_axis_snap * edge_normal, x_axis_snap * edge_normal);
+ //F32 start_angle = angle_between((-1.f * LLVector3::x_axis) * snap_guide_rot, edge_normal);
+ F32 start_angle = end_angle - F_PI;
+ gl_arc_2d(0.f, 0.f, mRadiusMeters * SNAP_GUIDE_INNER_RADIUS, CIRCLE_STEPS, false, start_angle, end_angle);
+ }
+ else
+ {
+ gl_circle_2d(0.f, 0.f, mRadiusMeters * SNAP_GUIDE_INNER_RADIUS, CIRCLE_STEPS, false);
+ }
+ gGL.popMatrix();
+
+ for (S32 i = 0; i < 64; i++)
+ {
+ bool render_text = true;
+ F32 deg = 5.625f * (F32)i;
+ LLVector3 inner_point;
+ LLVector3 outer_point;
+ LLVector3 text_point;
+ LLQuaternion rot(deg * DEG_TO_RAD, constraint_axis);
+ gGL.begin(LLRender::LINES);
+ {
+ inner_point = (projected_snap_axis * mRadiusMeters * SNAP_GUIDE_INNER_RADIUS * rot) + center;
+ F32 tick_length = 0.f;
+ if (i % 16 == 0)
+ {
+ tick_length = mRadiusMeters * (SNAP_GUIDE_RADIUS_1 - SNAP_GUIDE_INNER_RADIUS);
+ }
+ else if (i % 8 == 0)
+ {
+ tick_length = mRadiusMeters * (SNAP_GUIDE_RADIUS_2 - SNAP_GUIDE_INNER_RADIUS);
+ }
+ else if (i % 4 == 0)
+ {
+ tick_length = mRadiusMeters * (SNAP_GUIDE_RADIUS_3 - SNAP_GUIDE_INNER_RADIUS);
+ }
+ else if (i % 2 == 0)
+ {
+ tick_length = mRadiusMeters * (SNAP_GUIDE_RADIUS_4 - SNAP_GUIDE_INNER_RADIUS);
+ }
+ else
+ {
+ tick_length = mRadiusMeters * (SNAP_GUIDE_RADIUS_5 - SNAP_GUIDE_INNER_RADIUS);
+ }
+
+ if (mCamEdgeOn)
+ {
+ // don't draw ticks that are on back side of circle
+ F32 dot = cam_at_axis * (projected_snap_axis * rot);
+ if (dot > 0.f)
+ {
+ outer_point = inner_point;
+ render_text = false;
+ }
+ else
+ {
+ if (ring_num == 0)
+ {
+ outer_point = inner_point + (constraint_axis * tick_length) * rot;
+ }
+ else
+ {
+ outer_point = inner_point - (constraint_axis * tick_length) * rot;
+ }
+ }
+ }
+ else
+ {
+ outer_point = inner_point + (projected_snap_axis * tick_length) * rot;
+ }
+
+ text_point = outer_point + (projected_snap_axis * mRadiusMeters * 0.1f) * rot;
+
+ gGL.vertex3fv(inner_point.mV);
+ gGL.vertex3fv(outer_point.mV);
+ }
+ gGL.end();
+
+ //RN: text rendering does own shadow pass, so only render once
+ if (pass == 1 && render_text && i % 16 == 0)
+ {
+ if (world_snap_axis.mV[VX])
+ {
+ if (i == 0)
+ {
+ renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Direction_Forward") : LLTrans::getString("Direction_East"), LLColor4::white);
+ }
+ else if (i == 16)
+ {
+ if (constraint_axis.mV[VZ] > 0.f)
+ {
+ renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Direction_Left") : LLTrans::getString("Direction_North"), LLColor4::white);
+ }
+ else
+ {
+ renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Direction_Right") : LLTrans::getString("Direction_South"), LLColor4::white);
+ }
+ }
+ else if (i == 32)
+ {
+ renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Direction_Back") : LLTrans::getString("Direction_West"), LLColor4::white);
+ }
+ else
+ {
+ if (constraint_axis.mV[VZ] > 0.f)
+ {
+ renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Direction_Right") : LLTrans::getString("Direction_South"), LLColor4::white);
+ }
+ else
+ {
+ renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Direction_Left") : LLTrans::getString("Direction_North"), LLColor4::white);
+ }
+ }
+ }
+ else if (world_snap_axis.mV[VY])
+ {
+ if (i == 0)
+ {
+ renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Direction_Left") : LLTrans::getString("Direction_North"), LLColor4::white);
+ }
+ else if (i == 16)
+ {
+ if (constraint_axis.mV[VX] > 0.f)
+ {
+ renderTickText(text_point, LLTrans::getString("Direction_Up"), LLColor4::white);
+ }
+ else
+ {
+ renderTickText(text_point, LLTrans::getString("Direction_Down"), LLColor4::white);
+ }
+ }
+ else if (i == 32)
+ {
+ renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Direction_Right") : LLTrans::getString("Direction_South"), LLColor4::white);
+ }
+ else
+ {
+ if (constraint_axis.mV[VX] > 0.f)
+ {
+ renderTickText(text_point, LLTrans::getString("Direction_Down"), LLColor4::white);
+ }
+ else
+ {
+ renderTickText(text_point, LLTrans::getString("Direction_Up"), LLColor4::white);
+ }
+ }
+ }
+ else if (world_snap_axis.mV[VZ])
+ {
+ if (i == 0)
+ {
+ renderTickText(text_point, LLTrans::getString("Direction_Up"), LLColor4::white);
+ }
+ else if (i == 16)
+ {
+ if (constraint_axis.mV[VY] > 0.f)
+ {
+ renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Direction_Forward") : LLTrans::getString("Direction_East"), LLColor4::white);
+ }
+ else
+ {
+ renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Direction_Back") : LLTrans::getString("Direction_West"), LLColor4::white);
+ }
+ }
+ else if (i == 32)
+ {
+ renderTickText(text_point, LLTrans::getString("Direction_Down"), LLColor4::white);
+ }
+ else
+ {
+ if (constraint_axis.mV[VY] > 0.f)
+ {
+ renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Direction_Back") : LLTrans::getString("Direction_West"), LLColor4::white);
+ }
+ else
+ {
+ renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Direction_Forward") : LLTrans::getString("Direction_East"), LLColor4::white);
+ }
+ }
+ }
+ }
+ gGL.color4fv(line_color.mV);
+ }
+
+ // now render projected object axis
+ if (mInSnapRegime)
+ {
+ LLVector3 object_axis;
+ getObjectAxisClosestToMouse(object_axis);
+
+ // project onto constraint plane
+ LLSelectNode* first_node = mObjectSelection->getFirstMoveableNode(true);
+ object_axis = object_axis * first_node->getObject()->getRenderRotation();
+ object_axis = object_axis - (object_axis * getConstraintAxis()) * getConstraintAxis();
+ object_axis.normVec();
+ object_axis = object_axis * SNAP_GUIDE_INNER_RADIUS * mRadiusMeters + center;
+ LLVector3 line_start = center;
+
+ gGL.begin(LLRender::LINES);
+ {
+ gGL.vertex3fv(line_start.mV);
+ gGL.vertex3fv(object_axis.mV);
+ }
+ gGL.end();
+
+ // draw snap guide arrow
+ gGL.begin(LLRender::TRIANGLES);
+ {
+ LLVector3 arrow_dir;
+ LLVector3 arrow_span = (object_axis - line_start) % getConstraintAxis();
+ arrow_span.normVec();
+
+ arrow_dir = mCamEdgeOn ? getConstraintAxis() : object_axis - line_start;
+ arrow_dir.normVec();
+ if (ring_num == 1)
+ {
+ arrow_dir *= -1.f;
+ }
+ gGL.vertex3fv((object_axis + arrow_dir * mRadiusMeters * 0.1f).mV);
+ gGL.vertex3fv((object_axis + arrow_span * mRadiusMeters * 0.1f).mV);
+ gGL.vertex3fv((object_axis - arrow_span * mRadiusMeters * 0.1f).mV);
+ }
+ gGL.end();
+
+ {
+ LLGLDepthTest gls_depth(GL_TRUE);
+ gGL.begin(LLRender::LINES);
+ {
+ gGL.vertex3fv(line_start.mV);
+ gGL.vertex3fv(object_axis.mV);
+ }
+ gGL.end();
+
+ // draw snap guide arrow
+ gGL.begin(LLRender::TRIANGLES);
+ {
+ LLVector3 arrow_dir;
+ LLVector3 arrow_span = (object_axis - line_start) % getConstraintAxis();
+ arrow_span.normVec();
+
+ arrow_dir = mCamEdgeOn ? getConstraintAxis() : object_axis - line_start;
+ arrow_dir.normVec();
+ if (ring_num == 1)
+ {
+ arrow_dir *= -1.f;
+ }
+
+ gGL.vertex3fv((object_axis + arrow_dir * mRadiusMeters * 0.1f).mV);
+ gGL.vertex3fv((object_axis + arrow_span * mRadiusMeters * 0.1f).mV);
+ gGL.vertex3fv((object_axis - arrow_span * mRadiusMeters * 0.1f).mV);
+ }
+ gGL.end();
+ }
+ }
+ }
+ }
+
+
+ // render help text
+ if (mObjectSelection->getSelectType() != SELECT_TYPE_HUD)
+ {
+ if (mHelpTextTimer.getElapsedTimeF32() < sHelpTextVisibleTime + sHelpTextFadeTime && sNumTimesHelpTextShown < sMaxTimesShowHelpText)
+ {
+ LLVector3 selection_center_start = LLSelectMgr::getInstance()->getSavedBBoxOfSelection().getCenterAgent();
+
+ LLVector3 offset_dir = LLViewerCamera::getInstance()->getUpAxis();
+
+ F32 line_alpha = gSavedSettings.getF32("GridOpacity");
+
+ LLVector3 help_text_pos = selection_center_start + (mRadiusMeters * 3.f * offset_dir);
+ const LLFontGL* big_fontp = LLFontGL::getFontSansSerif();
+
+ std::string help_text = LLTrans::getString("manip_hint1");
+ LLColor4 help_text_color = LLColor4::white;
+ help_text_color.mV[VALPHA] = clamp_rescale(mHelpTextTimer.getElapsedTimeF32(), sHelpTextVisibleTime, sHelpTextVisibleTime + sHelpTextFadeTime, line_alpha, 0.f);
+ hud_render_utf8text(help_text, help_text_pos, *big_fontp, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, -0.5f * big_fontp->getWidthF32(help_text), 3.f, help_text_color, false);
+ help_text = LLTrans::getString("manip_hint2");
+ help_text_pos -= offset_dir * mRadiusMeters * 0.4f;
+ hud_render_utf8text(help_text, help_text_pos, *big_fontp, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, -0.5f * big_fontp->getWidthF32(help_text), 3.f, help_text_color, false);
+ }
+ }
+}
+
+// Returns true if center of sphere is visible. Also sets a bunch of member variables that are used later (e.g. mCenterToCam)
+bool LLManipRotate::updateVisiblity()
+{
+ // Don't want to recalculate the center of the selection during a drag.
+ // Due to packet delays, sometimes half the objects in the selection have their
+ // new position and half have their old one. This creates subtle errors in the
+ // computed center position for that frame. Unfortunately, these errors
+ // accumulate. The result is objects seem to "fly apart" during rotations.
+ // JC - 03.26.2002
+ if (!hasMouseCapture())
+ {
+ mRotationCenter = gAgent.getPosGlobalFromAgent( getPivotPoint() );//LLSelectMgr::getInstance()->getSelectionCenterGlobal();
+ }
+
+ bool visible = false;
+
+ //Assume that UI scale factor is equivalent for X and Y axis
+ F32 ui_scale_factor = LLUI::getScaleFactor().mV[VX];
+
+ LLVector3 center = gAgent.getPosAgentFromGlobal( mRotationCenter );
+ if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD)
+ {
+ mCenterToCam = LLVector3(-1.f / gAgentCamera.mHUDCurZoom, 0.f, 0.f);
+ mCenterToCamNorm = mCenterToCam;
+ mCenterToCamMag = mCenterToCamNorm.normVec();
+
+ mRadiusMeters = RADIUS_PIXELS / (F32) LLViewerCamera::getInstance()->getViewHeightInPixels();
+ mRadiusMeters /= gAgentCamera.mHUDCurZoom;
+ mRadiusMeters *= ui_scale_factor;
+
+ mCenterToProfilePlaneMag = mRadiusMeters * mRadiusMeters / mCenterToCamMag;
+ mCenterToProfilePlane = -mCenterToProfilePlaneMag * mCenterToCamNorm;
+
+ // x axis range is (-aspect * 0.5f, +aspect * 0.5)
+ // y axis range is (-0.5, 0.5)
+ // so use getWorldViewHeightRaw as scale factor when converting to pixel coordinates
+ mCenterScreen.set((S32)((0.5f - center.mV[VY]) / gAgentCamera.mHUDCurZoom * gViewerWindow->getWorldViewHeightScaled()),
+ (S32)((center.mV[VZ] + 0.5f) / gAgentCamera.mHUDCurZoom * gViewerWindow->getWorldViewHeightScaled()));
+ visible = true;
+ }
+ else
+ {
+ visible = LLViewerCamera::getInstance()->projectPosAgentToScreen(center, mCenterScreen );
+ if( visible )
+ {
+ mCenterToCam = gAgentCamera.getCameraPositionAgent() - center;
+ mCenterToCamNorm = mCenterToCam;
+ mCenterToCamMag = mCenterToCamNorm.normVec();
+ LLVector3 cameraAtAxis = LLViewerCamera::getInstance()->getAtAxis();
+ cameraAtAxis.normVec();
+
+ F32 z_dist = -1.f * (mCenterToCam * cameraAtAxis);
+
+ // Don't drag manip if object too far away
+ if (gSavedSettings.getBOOL("LimitSelectDistance"))
+ {
+ F32 max_select_distance = gSavedSettings.getF32("MaxSelectDistance");
+ if (dist_vec_squared(gAgent.getPositionAgent(), center) > (max_select_distance * max_select_distance))
+ {
+ visible = false;
+ }
+ }
+
+ if (mCenterToCamMag > 0.001f)
+ {
+ F32 fraction_of_fov = RADIUS_PIXELS / (F32) LLViewerCamera::getInstance()->getViewHeightInPixels();
+ F32 apparent_angle = fraction_of_fov * LLViewerCamera::getInstance()->getView(); // radians
+ mRadiusMeters = z_dist * tan(apparent_angle);
+ mRadiusMeters *= ui_scale_factor;
+
+ mCenterToProfilePlaneMag = mRadiusMeters * mRadiusMeters / mCenterToCamMag;
+ mCenterToProfilePlane = -mCenterToProfilePlaneMag * mCenterToCamNorm;
+ }
+ else
+ {
+ visible = false;
+ }
+ }
+ }
+
+ mCamEdgeOn = false;
+ F32 axis_onto_cam = mManipPart >= LL_ROT_X ? llabs( getConstraintAxis() * mCenterToCamNorm ) : 0.f;
+ if( axis_onto_cam < AXIS_ONTO_CAM_TOLERANCE )
+ {
+ mCamEdgeOn = true;
+ }
+
+ return visible;
+}
+
+LLQuaternion LLManipRotate::dragUnconstrained( S32 x, S32 y )
+{
+ LLVector3 cam = gAgentCamera.getCameraPositionAgent();
+ LLVector3 center = gAgent.getPosAgentFromGlobal( mRotationCenter );
+
+ mMouseCur = intersectMouseWithSphere( x, y, center, mRadiusMeters);
+
+ F32 delta_x = (F32)(mCenterScreen.mX - x);
+ F32 delta_y = (F32)(mCenterScreen.mY - y);
+
+ F32 dist_from_sphere_center = sqrt(delta_x * delta_x + delta_y * delta_y);
+
+ LLVector3 axis = mMouseDown % mMouseCur;
+ F32 angle = atan2(sqrtf(axis * axis), mMouseDown * mMouseCur);
+ axis.normVec();
+ LLQuaternion sphere_rot( angle, axis );
+
+ if (is_approx_zero(1.f - mMouseDown * mMouseCur))
+ {
+ return LLQuaternion::DEFAULT;
+ }
+ else if (dist_from_sphere_center < RADIUS_PIXELS)
+ {
+ return sphere_rot;
+ }
+ else
+ {
+ LLVector3 intersection;
+ getMousePointOnPlaneAgent( intersection, x, y, center + mCenterToProfilePlane, mCenterToCamNorm );
+
+ // amount dragging in sphere from center to periphery would rotate object
+ F32 in_sphere_angle = F_PI_BY_TWO;
+ F32 dist_to_tangent_point = mRadiusMeters;
+ if( !is_approx_zero( mCenterToProfilePlaneMag ) )
+ {
+ dist_to_tangent_point = sqrt( mRadiusMeters * mRadiusMeters - mCenterToProfilePlaneMag * mCenterToProfilePlaneMag );
+ in_sphere_angle = atan2( dist_to_tangent_point, mCenterToProfilePlaneMag );
+ }
+
+ LLVector3 profile_center_to_intersection = intersection - (center + mCenterToProfilePlane);
+ F32 dist_to_intersection = profile_center_to_intersection.normVec();
+ F32 angle = (-1.f + dist_to_intersection / dist_to_tangent_point) * in_sphere_angle;
+
+ LLVector3 axis;
+ if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD)
+ {
+ axis = LLVector3(-1.f, 0.f, 0.f) % profile_center_to_intersection;
+ }
+ else
+ {
+ axis = (cam - center) % profile_center_to_intersection;
+ axis.normVec();
+ }
+ return sphere_rot * LLQuaternion( angle, axis );
+ }
+}
+
+LLVector3 LLManipRotate::getConstraintAxis()
+{
+ LLVector3 axis;
+ if( LL_ROT_ROLL == mManipPart )
+ {
+ axis = mCenterToCamNorm;
+ }
+ else
+ {
+ S32 axis_dir = mManipPart - LL_ROT_X;
+ if ((axis_dir >= LL_NO_PART) && (axis_dir < LL_Z_ARROW))
+ {
+ axis.mV[axis_dir] = 1.f;
+ }
+ else
+ {
+#ifndef LL_RELEASE_FOR_DOWNLOAD
+ LL_ERRS() << "Got bogus hit part in LLManipRotate::getConstraintAxis():" << mManipPart << LL_ENDL;
+#else
+ LL_WARNS() << "Got bogus hit part in LLManipRotate::getConstraintAxis():" << mManipPart << LL_ENDL;
+#endif
+ axis.mV[0] = 1.f;
+ }
+
+ LLVector3 grid_origin;
+ LLVector3 grid_scale;
+ LLQuaternion grid_rotation;
+
+ LLSelectMgr::getInstance()->getGrid(grid_origin, grid_rotation, grid_scale);
+
+ LLSelectNode* first_node = mObjectSelection->getFirstMoveableNode(true);
+ if (first_node)
+ {
+ // *FIX: get agent local attachment grid working
+ // Put rotation into frame of first selected root object
+ axis = axis * grid_rotation;
+ }
+ }
+
+ return axis;
+}
+
+LLQuaternion LLManipRotate::dragConstrained( S32 x, S32 y )
+{
+ LLSelectNode* first_object_node = mObjectSelection->getFirstMoveableNode(true);
+ LLVector3 constraint_axis = getConstraintAxis();
+ LLVector3 center = gAgent.getPosAgentFromGlobal( mRotationCenter );
+
+ F32 angle = 0.f;
+
+ // build snap axes
+ LLVector3 grid_origin;
+ LLVector3 grid_scale;
+ LLQuaternion grid_rotation;
+
+ LLSelectMgr::getInstance()->getGrid(grid_origin, grid_rotation, grid_scale);
+
+ LLVector3 axis1;
+ LLVector3 axis2;
+
+ LLVector3 test_axis = constraint_axis;
+ if (mObjectSelection->getSelectType() == SELECT_TYPE_ATTACHMENT && isAgentAvatarValid())
+ {
+ test_axis = test_axis * ~grid_rotation;
+ }
+ else if (LLSelectMgr::getInstance()->getGridMode() == GRID_MODE_REF_OBJECT)
+ {
+ test_axis = test_axis * ~grid_rotation;
+ }
+ test_axis.abs();
+
+ // find closest global axis to constraint axis;
+ if (test_axis.mV[VX] > test_axis.mV[VY] && test_axis.mV[VX] > test_axis.mV[VZ])
+ {
+ axis1 = LLVector3::y_axis;
+ }
+ else if (test_axis.mV[VY] > test_axis.mV[VZ])
+ {
+ axis1 = LLVector3::z_axis;
+ }
+ else
+ {
+ axis1 = LLVector3::x_axis;
+ }
+
+ if (mObjectSelection->getSelectType() == SELECT_TYPE_ATTACHMENT && isAgentAvatarValid())
+ {
+ axis1 = axis1 * grid_rotation;
+ }
+ else if (LLSelectMgr::getInstance()->getGridMode() == GRID_MODE_REF_OBJECT)
+ {
+ axis1 = axis1 * grid_rotation;
+ }
+
+ //project axis onto constraint plane
+ axis1 -= (axis1 * constraint_axis) * constraint_axis;
+ axis1.normVec();
+
+ // calculate third and final axis
+ axis2 = constraint_axis % axis1;
+
+ //F32 axis_onto_cam = llabs( constraint_axis * mCenterToCamNorm );
+ if( mCamEdgeOn )
+ {
+ // We're looking at the ring edge-on.
+ LLVector3 snap_plane_center = (center + (constraint_axis * mRadiusMeters * 0.5f));
+ LLVector3 cam_to_snap_plane;
+ if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD)
+ {
+ cam_to_snap_plane.setVec(1.f, 0.f, 0.f);
+ }
+ else
+ {
+ cam_to_snap_plane = snap_plane_center - gAgentCamera.getCameraPositionAgent();
+ cam_to_snap_plane.normVec();
+ }
+
+ LLVector3 projected_mouse;
+ bool hit = getMousePointOnPlaneAgent(projected_mouse, x, y, snap_plane_center, constraint_axis);
+ projected_mouse -= snap_plane_center;
+
+ if (gSavedSettings.getBOOL("SnapEnabled")) {
+ S32 snap_plane = 0;
+
+ F32 dot = cam_to_snap_plane * constraint_axis;
+ if (llabs(dot) < 0.01f)
+ {
+ // looking at ring edge on, project onto view plane and check if mouse is past ring
+ getMousePointOnPlaneAgent(projected_mouse, x, y, snap_plane_center, cam_to_snap_plane);
+ projected_mouse -= snap_plane_center;
+ dot = projected_mouse * constraint_axis;
+ if (projected_mouse * constraint_axis > 0)
+ {
+ snap_plane = 1;
+ }
+ projected_mouse -= dot * constraint_axis;
+ }
+ else if (dot > 0.f)
+ {
+ // look for mouse position outside and in front of snap circle
+ if (hit && projected_mouse.magVec() > SNAP_GUIDE_INNER_RADIUS * mRadiusMeters && projected_mouse * cam_to_snap_plane < 0.f)
+ {
+ snap_plane = 1;
+ }
+ }
+ else
+ {
+ // look for mouse position inside or in back of snap circle
+ if (projected_mouse.magVec() < SNAP_GUIDE_INNER_RADIUS * mRadiusMeters || projected_mouse * cam_to_snap_plane > 0.f || !hit)
+ {
+ snap_plane = 1;
+ }
+ }
+
+ if (snap_plane == 0)
+ {
+ // try other plane
+ snap_plane_center = (center - (constraint_axis * mRadiusMeters * 0.5f));
+ if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD)
+ {
+ cam_to_snap_plane.setVec(1.f, 0.f, 0.f);
+ }
+ else
+ {
+ cam_to_snap_plane = snap_plane_center - gAgentCamera.getCameraPositionAgent();
+ cam_to_snap_plane.normVec();
+ }
+
+ hit = getMousePointOnPlaneAgent(projected_mouse, x, y, snap_plane_center, constraint_axis);
+ projected_mouse -= snap_plane_center;
+
+ dot = cam_to_snap_plane * constraint_axis;
+ if (llabs(dot) < 0.01f)
+ {
+ // looking at ring edge on, project onto view plane and check if mouse is past ring
+ getMousePointOnPlaneAgent(projected_mouse, x, y, snap_plane_center, cam_to_snap_plane);
+ projected_mouse -= snap_plane_center;
+ dot = projected_mouse * constraint_axis;
+ if (projected_mouse * constraint_axis < 0)
+ {
+ snap_plane = 2;
+ }
+ projected_mouse -= dot * constraint_axis;
+ }
+ else if (dot < 0.f)
+ {
+ // look for mouse position outside and in front of snap circle
+ if (hit && projected_mouse.magVec() > SNAP_GUIDE_INNER_RADIUS * mRadiusMeters && projected_mouse * cam_to_snap_plane < 0.f)
+ {
+ snap_plane = 2;
+ }
+ }
+ else
+ {
+ // look for mouse position inside or in back of snap circle
+ if (projected_mouse.magVec() < SNAP_GUIDE_INNER_RADIUS * mRadiusMeters || projected_mouse * cam_to_snap_plane > 0.f || !hit)
+ {
+ snap_plane = 2;
+ }
+ }
+ }
+
+ if (snap_plane > 0)
+ {
+ LLVector3 cam_at_axis;
+ if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD)
+ {
+ cam_at_axis.setVec(1.f, 0.f, 0.f);
+ }
+ else
+ {
+ cam_at_axis = snap_plane_center - gAgentCamera.getCameraPositionAgent();
+ cam_at_axis.normVec();
+ }
+
+ // first, project mouse onto screen plane at point tangent to rotation radius.
+ getMousePointOnPlaneAgent(projected_mouse, x, y, snap_plane_center, cam_at_axis);
+ // project that point onto rotation plane
+ projected_mouse -= snap_plane_center;
+ projected_mouse -= projected_vec(projected_mouse, constraint_axis);
+
+ F32 mouse_lateral_dist = llmin(SNAP_GUIDE_INNER_RADIUS * mRadiusMeters, projected_mouse.magVec());
+ F32 mouse_depth = SNAP_GUIDE_INNER_RADIUS * mRadiusMeters;
+ if (llabs(mouse_lateral_dist) > 0.01f)
+ {
+ mouse_depth = sqrtf((SNAP_GUIDE_INNER_RADIUS * mRadiusMeters) * (SNAP_GUIDE_INNER_RADIUS * mRadiusMeters) -
+ (mouse_lateral_dist * mouse_lateral_dist));
+ }
+ LLVector3 projected_camera_at = cam_at_axis - projected_vec(cam_at_axis, constraint_axis);
+ projected_mouse -= mouse_depth * projected_camera_at;
+
+ if (!mInSnapRegime)
+ {
+ mSmoothRotate = true;
+ }
+ mInSnapRegime = true;
+ // 0 to 360 deg
+ F32 mouse_angle = fmodf(atan2(projected_mouse * axis1, projected_mouse * axis2) * RAD_TO_DEG + 360.f, 360.f);
+
+ F32 relative_mouse_angle = fmodf(mouse_angle + (SNAP_ANGLE_DETENTE / 2), SNAP_ANGLE_INCREMENT);
+
+ LLVector3 object_axis;
+ getObjectAxisClosestToMouse(object_axis);
+ if (first_object_node)
+ {
+ object_axis = object_axis * first_object_node->mSavedRotation;
+ }
+
+ // project onto constraint plane
+ object_axis = object_axis - (object_axis * getConstraintAxis()) * getConstraintAxis();
+ object_axis.normVec();
+
+ if (relative_mouse_angle < SNAP_ANGLE_DETENTE)
+ {
+ F32 quantized_mouse_angle = mouse_angle - (relative_mouse_angle - (SNAP_ANGLE_DETENTE * 0.5f));
+ angle = (quantized_mouse_angle * DEG_TO_RAD) - atan2(object_axis * axis1, object_axis * axis2);
+ }
+ else
+ {
+ angle = (mouse_angle * DEG_TO_RAD) - atan2(object_axis * axis1, object_axis * axis2);
+ }
+ return LLQuaternion( -angle, constraint_axis );
+ }
+ else
+ {
+ if (mInSnapRegime)
+ {
+ mSmoothRotate = true;
+ }
+ mInSnapRegime = false;
+ }
+ }
+ else {
+ if (mInSnapRegime)
+ {
+ mSmoothRotate = true;
+ }
+ mInSnapRegime = false;
+ }
+
+ if (!mInSnapRegime)
+ {
+ LLVector3 up_from_axis = mCenterToCamNorm % constraint_axis;
+ up_from_axis.normVec();
+ LLVector3 cur_intersection;
+ getMousePointOnPlaneAgent(cur_intersection, x, y, center, mCenterToCam);
+ cur_intersection -= center;
+ mMouseCur = projected_vec(cur_intersection, up_from_axis);
+ F32 mouse_depth = SNAP_GUIDE_INNER_RADIUS * mRadiusMeters;
+ F32 mouse_dist_sqrd = mMouseCur.magVecSquared();
+ if (mouse_dist_sqrd > 0.0001f)
+ {
+ mouse_depth = sqrtf((SNAP_GUIDE_INNER_RADIUS * mRadiusMeters) * (SNAP_GUIDE_INNER_RADIUS * mRadiusMeters) -
+ mouse_dist_sqrd);
+ }
+ LLVector3 projected_center_to_cam = mCenterToCamNorm - projected_vec(mCenterToCamNorm, constraint_axis);
+ mMouseCur += mouse_depth * projected_center_to_cam;
+
+ F32 dist = (cur_intersection * up_from_axis) - (mMouseDown * up_from_axis);
+ angle = dist / (SNAP_GUIDE_INNER_RADIUS * mRadiusMeters) * -F_PI_BY_TWO;
+ }
+ }
+ else
+ {
+ LLVector3 projected_mouse;
+ getMousePointOnPlaneAgent(projected_mouse, x, y, center, constraint_axis);
+ projected_mouse -= center;
+ mMouseCur = projected_mouse;
+ mMouseCur.normVec();
+
+ if (!first_object_node)
+ {
+ return LLQuaternion::DEFAULT;
+ }
+
+ if (gSavedSettings.getBOOL("SnapEnabled") && projected_mouse.magVec() > SNAP_GUIDE_INNER_RADIUS * mRadiusMeters)
+ {
+ if (!mInSnapRegime)
+ {
+ mSmoothRotate = true;
+ }
+ mInSnapRegime = true;
+ // 0 to 360 deg
+ F32 mouse_angle = fmodf(atan2(projected_mouse * axis1, projected_mouse * axis2) * RAD_TO_DEG + 360.f, 360.f);
+
+ F32 relative_mouse_angle = fmodf(mouse_angle + (SNAP_ANGLE_DETENTE / 2), SNAP_ANGLE_INCREMENT);
+
+ LLVector3 object_axis;
+ getObjectAxisClosestToMouse(object_axis);
+ object_axis = object_axis * first_object_node->mSavedRotation;
+
+ // project onto constraint plane
+ object_axis = object_axis - (object_axis * getConstraintAxis()) * getConstraintAxis();
+ object_axis.normVec();
+
+ if (relative_mouse_angle < SNAP_ANGLE_DETENTE)
+ {
+ F32 quantized_mouse_angle = mouse_angle - (relative_mouse_angle - (SNAP_ANGLE_DETENTE * 0.5f));
+ angle = (quantized_mouse_angle * DEG_TO_RAD) - atan2(object_axis * axis1, object_axis * axis2);
+ }
+ else
+ {
+ angle = (mouse_angle * DEG_TO_RAD) - atan2(object_axis * axis1, object_axis * axis2);
+ }
+ return LLQuaternion( -angle, constraint_axis );
+ }
+ else
+ {
+ if (mInSnapRegime)
+ {
+ mSmoothRotate = true;
+ }
+ mInSnapRegime = false;
+ }
+
+ LLVector3 cross_product = mMouseDown % mMouseCur;
+ angle = atan2(sqrtf(cross_product * cross_product), mMouseCur * mMouseDown);
+ F32 dir = cross_product * constraint_axis; // cross product
+ if( dir < 0.f )
+ {
+ angle *= -1.f;
+ }
+ }
+
+ F32 rot_step = gSavedSettings.getF32("RotationStep");
+ F32 step_size = DEG_TO_RAD * rot_step;
+ angle -= fmod(angle, step_size);
+
+ return LLQuaternion( angle, constraint_axis );
+}
+
+
+
+LLVector3 LLManipRotate::intersectMouseWithSphere( S32 x, S32 y, const LLVector3& sphere_center, F32 sphere_radius)
+{
+ LLVector3 ray_pt;
+ LLVector3 ray_dir;
+ mouseToRay( x, y, &ray_pt, &ray_dir);
+ return intersectRayWithSphere( ray_pt, ray_dir, sphere_center, sphere_radius );
+}
+
+LLVector3 LLManipRotate::intersectRayWithSphere( const LLVector3& ray_pt, const LLVector3& ray_dir, const LLVector3& sphere_center, F32 sphere_radius)
+{
+ LLVector3 ray_pt_to_center = sphere_center - ray_pt;
+ F32 center_distance = ray_pt_to_center.normVec();
+
+ F32 dot = ray_dir * ray_pt_to_center;
+
+ if (dot == 0.f)
+ {
+ return LLVector3::zero;
+ }
+
+ // point which ray hits plane centered on sphere origin, facing ray origin
+ LLVector3 intersection_sphere_plane = ray_pt + (ray_dir * center_distance / dot);
+ // vector from sphere origin to the point, normalized to sphere radius
+ LLVector3 sphere_center_to_intersection = (intersection_sphere_plane - sphere_center) / sphere_radius;
+
+ F32 dist_squared = sphere_center_to_intersection.magVecSquared();
+ LLVector3 result;
+
+ if (dist_squared > 1.f)
+ {
+ result = sphere_center_to_intersection;
+ result.normVec();
+ }
+ else
+ {
+ result = sphere_center_to_intersection - ray_dir * sqrt(1.f - dist_squared);
+ }
+
+ return result;
+}
+
+// Utility function. Should probably be moved to another class.
+// x,y - mouse position in scaled window coordinates (NOT GL viewport coordinates)
+//static
+void LLManipRotate::mouseToRay( S32 x, S32 y, LLVector3* ray_pt, LLVector3* ray_dir )
+{
+ if (LLSelectMgr::getInstance()->getSelection()->getSelectType() == SELECT_TYPE_HUD)
+ {
+ F32 mouse_x = (((F32)x / gViewerWindow->getWorldViewRectScaled().getWidth()) - 0.5f) / gAgentCamera.mHUDCurZoom;
+ F32 mouse_y = ((((F32)y) / gViewerWindow->getWorldViewRectScaled().getHeight()) - 0.5f) / gAgentCamera.mHUDCurZoom;
+
+ *ray_pt = LLVector3(-1.f, -mouse_x, mouse_y);
+ *ray_dir = LLVector3(1.f, 0.f, 0.f);
+ }
+ else
+ {
+ *ray_pt = gAgentCamera.getCameraPositionAgent();
+ *ray_dir = gViewerWindow->mouseDirectionGlobal(x, y);
+ }
+}
+
+void LLManipRotate::highlightManipulators( S32 x, S32 y )
+{
+ mHighlightedPart = LL_NO_PART;
+
+ //LLBBox bbox = LLSelectMgr::getInstance()->getBBoxOfSelection();
+ LLViewerObject *first_object = mObjectSelection->getFirstMoveableObject(true);
+
+ if (!first_object)
+ {
+ return;
+ }
+
+ LLVector3 rotation_center = gAgent.getPosAgentFromGlobal(mRotationCenter);
+ LLVector3 mouse_dir_x;
+ LLVector3 mouse_dir_y;
+ LLVector3 mouse_dir_z;
+ LLVector3 intersection_roll;
+
+ LLVector3 grid_origin;
+ LLVector3 grid_scale;
+ LLQuaternion grid_rotation;
+
+ LLSelectMgr::getInstance()->getGrid(grid_origin, grid_rotation, grid_scale);
+
+ LLVector3 rot_x_axis = LLVector3::x_axis * grid_rotation;
+ LLVector3 rot_y_axis = LLVector3::y_axis * grid_rotation;
+ LLVector3 rot_z_axis = LLVector3::z_axis * grid_rotation;
+
+ F32 proj_rot_x_axis = llabs(rot_x_axis * mCenterToCamNorm);
+ F32 proj_rot_y_axis = llabs(rot_y_axis * mCenterToCamNorm);
+ F32 proj_rot_z_axis = llabs(rot_z_axis * mCenterToCamNorm);
+
+ F32 min_select_distance = 0.f;
+ F32 cur_select_distance = 0.f;
+
+ // test x
+ getMousePointOnPlaneAgent(mouse_dir_x, x, y, rotation_center, rot_x_axis);
+ mouse_dir_x -= rotation_center;
+ // push intersection point out when working at obtuse angle to make ring easier to hit
+ mouse_dir_x *= 1.f + (1.f - llabs(rot_x_axis * mCenterToCamNorm)) * 0.1f;
+
+ // test y
+ getMousePointOnPlaneAgent(mouse_dir_y, x, y, rotation_center, rot_y_axis);
+ mouse_dir_y -= rotation_center;
+ mouse_dir_y *= 1.f + (1.f - llabs(rot_y_axis * mCenterToCamNorm)) * 0.1f;
+
+ // test z
+ getMousePointOnPlaneAgent(mouse_dir_z, x, y, rotation_center, rot_z_axis);
+ mouse_dir_z -= rotation_center;
+ mouse_dir_z *= 1.f + (1.f - llabs(rot_z_axis * mCenterToCamNorm)) * 0.1f;
+
+ // test roll
+ getMousePointOnPlaneAgent(intersection_roll, x, y, rotation_center, mCenterToCamNorm);
+ intersection_roll -= rotation_center;
+
+ F32 dist_x = mouse_dir_x.normVec();
+ F32 dist_y = mouse_dir_y.normVec();
+ F32 dist_z = mouse_dir_z.normVec();
+
+ F32 distance_threshold = (MAX_MANIP_SELECT_DISTANCE * mRadiusMeters) / gViewerWindow->getWorldViewHeightScaled();
+
+ if (llabs(dist_x - mRadiusMeters) * llmax(0.05f, proj_rot_x_axis) < distance_threshold)
+ {
+ // selected x
+ cur_select_distance = dist_x * mouse_dir_x * mCenterToCamNorm;
+ if (cur_select_distance >= -0.05f && (min_select_distance == 0.f || cur_select_distance > min_select_distance))
+ {
+ min_select_distance = cur_select_distance;
+ mHighlightedPart = LL_ROT_X;
+ }
+ }
+ if (llabs(dist_y - mRadiusMeters) * llmax(0.05f, proj_rot_y_axis) < distance_threshold)
+ {
+ // selected y
+ cur_select_distance = dist_y * mouse_dir_y * mCenterToCamNorm;
+ if (cur_select_distance >= -0.05f && (min_select_distance == 0.f || cur_select_distance > min_select_distance))
+ {
+ min_select_distance = cur_select_distance;
+ mHighlightedPart = LL_ROT_Y;
+ }
+ }
+ if (llabs(dist_z - mRadiusMeters) * llmax(0.05f, proj_rot_z_axis) < distance_threshold)
+ {
+ // selected z
+ cur_select_distance = dist_z * mouse_dir_z * mCenterToCamNorm;
+ if (cur_select_distance >= -0.05f && (min_select_distance == 0.f || cur_select_distance > min_select_distance))
+ {
+ min_select_distance = cur_select_distance;
+ mHighlightedPart = LL_ROT_Z;
+ }
+ }
+
+ // test for edge-on intersections
+ if (proj_rot_x_axis < 0.05f)
+ {
+ if ((proj_rot_y_axis > 0.05f && (dist_y * llabs(mouse_dir_y * rot_x_axis) < distance_threshold) && dist_y < mRadiusMeters) ||
+ (proj_rot_z_axis > 0.05f && (dist_z * llabs(mouse_dir_z * rot_x_axis) < distance_threshold) && dist_z < mRadiusMeters))
+ {
+ mHighlightedPart = LL_ROT_X;
+ }
+ }
+
+ if (proj_rot_y_axis < 0.05f)
+ {
+ if ((proj_rot_x_axis > 0.05f && (dist_x * llabs(mouse_dir_x * rot_y_axis) < distance_threshold) && dist_x < mRadiusMeters) ||
+ (proj_rot_z_axis > 0.05f && (dist_z * llabs(mouse_dir_z * rot_y_axis) < distance_threshold) && dist_z < mRadiusMeters))
+ {
+ mHighlightedPart = LL_ROT_Y;
+ }
+ }
+
+ if (proj_rot_z_axis < 0.05f)
+ {
+ if ((proj_rot_x_axis > 0.05f && (dist_x * llabs(mouse_dir_x * rot_z_axis) < distance_threshold) && dist_x < mRadiusMeters) ||
+ (proj_rot_y_axis > 0.05f && (dist_y * llabs(mouse_dir_y * rot_z_axis) < distance_threshold) && dist_y < mRadiusMeters))
+ {
+ mHighlightedPart = LL_ROT_Z;
+ }
+ }
+
+ // test for roll
+ if (mHighlightedPart == LL_NO_PART)
+ {
+ F32 roll_distance = intersection_roll.magVec();
+ F32 width_meters = WIDTH_PIXELS * mRadiusMeters / RADIUS_PIXELS;
+
+ // use larger distance threshold for roll as it is checked only if something else wasn't highlighted
+ if (llabs(roll_distance - (mRadiusMeters + (width_meters * 2.f))) < distance_threshold * 2.f)
+ {
+ mHighlightedPart = LL_ROT_ROLL;
+ }
+ else if (roll_distance < mRadiusMeters)
+ {
+ mHighlightedPart = LL_ROT_GENERAL;
+ }
+ }
+}
+
+S32 LLManipRotate::getObjectAxisClosestToMouse(LLVector3& object_axis)
+{
+ LLSelectNode* first_object_node = mObjectSelection->getFirstMoveableNode(true);
+
+ if (!first_object_node)
+ {
+ object_axis.clearVec();
+ return -1;
+ }
+
+ LLQuaternion obj_rotation = first_object_node->mSavedRotation;
+ LLVector3 mouse_down_object = mMouseDown * ~obj_rotation;
+ LLVector3 mouse_down_abs = mouse_down_object;
+ mouse_down_abs.abs();
+
+ S32 axis_index = 0;
+ if (mouse_down_abs.mV[VX] > mouse_down_abs.mV[VY] && mouse_down_abs.mV[VX] > mouse_down_abs.mV[VZ])
+ {
+ if (mouse_down_object.mV[VX] > 0.f)
+ {
+ object_axis = LLVector3::x_axis;
+ }
+ else
+ {
+ object_axis = LLVector3::x_axis_neg;
+ }
+ axis_index = VX;
+ }
+ else if (mouse_down_abs.mV[VY] > mouse_down_abs.mV[VZ])
+ {
+ if (mouse_down_object.mV[VY] > 0.f)
+ {
+ object_axis = LLVector3::y_axis;
+ }
+ else
+ {
+ object_axis = LLVector3::y_axis_neg;
+ }
+ axis_index = VY;
+ }
+ else
+ {
+ if (mouse_down_object.mV[VZ] > 0.f)
+ {
+ object_axis = LLVector3::z_axis;
+ }
+ else
+ {
+ object_axis = LLVector3::z_axis_neg;
+ }
+ axis_index = VZ;
+ }
+
+ return axis_index;
+}
+
+//virtual
+bool LLManipRotate::canAffectSelection()
+{
+ bool can_rotate = mObjectSelection->getObjectCount() != 0;
+ if (can_rotate)
+ {
+ struct f : public LLSelectedObjectFunctor
+ {
+ virtual bool apply(LLViewerObject* objectp)
+ {
+ LLViewerObject *root_object = (objectp == NULL) ? NULL : objectp->getRootEdit();
+ return objectp->permMove() && !objectp->isPermanentEnforced() &&
+ ((root_object == NULL) || !root_object->isPermanentEnforced()) &&
+ (objectp->permModify() || !gSavedSettings.getBOOL("EditLinkedParts"));
+ }
+ } func;
+ can_rotate = mObjectSelection->applyToObjects(&func);
+ }
+ return can_rotate;
+}
+
|