PageRenderTime 132ms CodeModel.GetById 9ms app.highlight 110ms RepoModel.GetById 2ms app.codeStats 0ms

/indra/newview/llmaniprotate.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 1881 lines | 1516 code | 233 blank | 132 comment | 316 complexity | fbbcd148de8d9fcfb28fdbe36e30a7c8 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1/** 
   2 * @file llmaniprotate.cpp
   3 * @brief LLManipRotate class implementation
   4 *
   5 * $LicenseInfo:firstyear=2002&license=viewerlgpl$
   6 * Second Life Viewer Source Code
   7 * Copyright (C) 2010, Linden Research, Inc.
   8 * 
   9 * This library is free software; you can redistribute it and/or
  10 * modify it under the terms of the GNU Lesser General Public
  11 * License as published by the Free Software Foundation;
  12 * version 2.1 of the License only.
  13 * 
  14 * This library is distributed in the hope that it will be useful,
  15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  17 * Lesser General Public License for more details.
  18 * 
  19 * You should have received a copy of the GNU Lesser General Public
  20 * License along with this library; if not, write to the Free Software
  21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  22 * 
  23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  24 * $/LicenseInfo$
  25 */
  26
  27#include "llviewerprecompiledheaders.h"
  28
  29#include "llmaniprotate.h"
  30
  31// library includes
  32#include "llmath.h"
  33#include "llgl.h"
  34#include "llrender.h"
  35#include "v4color.h"
  36#include "llprimitive.h"
  37#include "llview.h"
  38#include "llfontgl.h"
  39
  40// viewer includes
  41#include "llagent.h"
  42#include "llagentcamera.h"
  43#include "llbox.h"
  44#include "llbutton.h"
  45#include "llviewercontrol.h"
  46#include "llcriticaldamp.h"
  47#include "lltooltip.h"
  48#include "llfloatertools.h"
  49#include "llselectmgr.h"
  50#include "llstatusbar.h"
  51#include "llui.h"
  52#include "llvoavatar.h"
  53#include "llviewercamera.h"
  54#include "llviewerobject.h"
  55#include "llviewerobject.h"
  56#include "llviewershadermgr.h"
  57#include "llviewerwindow.h"
  58#include "llworld.h"
  59#include "pipeline.h"
  60#include "lldrawable.h"
  61#include "llglheaders.h"
  62#include "lltrans.h"
  63#include "llvoavatarself.h"
  64
  65const F32 RADIUS_PIXELS = 100.f;		// size in screen space
  66const F32 SQ_RADIUS = RADIUS_PIXELS * RADIUS_PIXELS;
  67const F32 WIDTH_PIXELS = 8;
  68const S32 CIRCLE_STEPS = 100;
  69const F32 DELTA = F_TWO_PI / CIRCLE_STEPS;
  70const F32 SIN_DELTA = sin( DELTA );
  71const F32 COS_DELTA = cos( DELTA );
  72const F32 MAX_MANIP_SELECT_DISTANCE = 100.f;
  73const F32 SNAP_ANGLE_INCREMENT = 5.625f;
  74const F32 SNAP_ANGLE_DETENTE = SNAP_ANGLE_INCREMENT;
  75const F32 SNAP_GUIDE_RADIUS_1 = 2.8f;
  76const F32 SNAP_GUIDE_RADIUS_2 = 2.4f;
  77const F32 SNAP_GUIDE_RADIUS_3 = 2.2f;
  78const F32 SNAP_GUIDE_RADIUS_4 = 2.1f;
  79const F32 SNAP_GUIDE_RADIUS_5 = 2.05f;
  80const F32 SNAP_GUIDE_INNER_RADIUS = 2.f;
  81const F32 AXIS_ONTO_CAM_TOLERANCE = cos( 80.f * DEG_TO_RAD );
  82const F32 SELECTED_MANIPULATOR_SCALE = 1.05f;
  83const F32 MANIPULATOR_SCALE_HALF_LIFE = 0.07f;
  84
  85extern void handle_reset_rotation(void*);  // in LLViewerWindow
  86
  87LLManipRotate::LLManipRotate( LLToolComposite* composite )
  88: 	LLManip( std::string("Rotate"), composite ),
  89	mRotationCenter(),
  90	mCenterScreen(),
  91	mRotation(),
  92	mMouseDown(),
  93	mMouseCur(),
  94	mRadiusMeters(0.f),
  95	mCenterToCam(),
  96	mCenterToCamNorm(),
  97	mCenterToCamMag(0.f),
  98	mCenterToProfilePlane(),
  99	mCenterToProfilePlaneMag(0.f),
 100	mSendUpdateOnMouseUp( FALSE ),
 101	mSmoothRotate( FALSE ),
 102	mCamEdgeOn(FALSE),
 103	mManipulatorScales(1.f, 1.f, 1.f, 1.f)
 104{ }
 105
 106void LLManipRotate::handleSelect()
 107{
 108	// *FIX: put this in mouseDown?
 109	LLSelectMgr::getInstance()->saveSelectedObjectTransform(SELECT_ACTION_TYPE_PICK);
 110	gFloaterTools->setStatusText("rotate");
 111	LLManip::handleSelect();
 112}
 113
 114void LLManipRotate::render()
 115{
 116	LLGLSUIDefault gls_ui;
 117	gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sWhiteImagep);
 118	LLGLDepthTest gls_depth(GL_TRUE);
 119	LLGLEnable gl_blend(GL_BLEND);
 120	LLGLEnable gls_alpha_test(GL_ALPHA_TEST);
 121	
 122	// You can rotate if you can move
 123	LLViewerObject* first_object = mObjectSelection->getFirstMoveableObject(TRUE);
 124	if( !first_object )
 125	{
 126		return;
 127	}
 128
 129	if( !updateVisiblity() )
 130	{
 131		return;
 132	}
 133
 134	gGL.matrixMode(LLRender::MM_MODELVIEW);
 135	gGL.pushMatrix();
 136	if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD)
 137	{
 138		F32 zoom = gAgentCamera.mHUDCurZoom;
 139		gGL.scalef(zoom, zoom, zoom);
 140	}
 141
 142
 143	LLVector3 center = gAgent.getPosAgentFromGlobal( mRotationCenter );
 144
 145	LLColor4 highlight_outside( 1.f, 1.f, 0.f, 1.f );
 146	LLColor4 highlight_inside( 0.7f, 0.7f, 0.f, 0.5f );
 147	F32 width_meters = WIDTH_PIXELS * mRadiusMeters / RADIUS_PIXELS;
 148
 149	gGL.pushMatrix();
 150	{
 151		
 152		// are we in the middle of a constrained drag?
 153		if (mManipPart >= LL_ROT_X && mManipPart <= LL_ROT_Z)
 154		{
 155			renderSnapGuides();
 156		}
 157		else
 158		{
 159			if (LLGLSLShader::sNoFixedFunction)
 160			{
 161				gDebugProgram.bind();
 162			}
 163
 164			LLGLEnable cull_face(GL_CULL_FACE);
 165			LLGLDepthTest gls_depth(GL_FALSE);
 166			gGL.pushMatrix();
 167			{
 168				// Draw "sphere" (intersection of sphere with tangent cone that has apex at camera)
 169				gGL.translatef( mCenterToProfilePlane.mV[VX], mCenterToProfilePlane.mV[VY], mCenterToProfilePlane.mV[VZ] );
 170				gGL.translatef( center.mV[VX], center.mV[VY], center.mV[VZ] );
 171
 172				// Inverse change of basis vectors
 173				LLVector3 forward = mCenterToCamNorm;
 174				LLVector3 left = gAgent.getUpAxis() % forward;
 175				left.normVec();
 176				LLVector3 up = forward % left;
 177
 178				LLVector4 a(-forward);
 179				a.mV[3] = 0;
 180				LLVector4 b(up);
 181				b.mV[3] = 0;
 182				LLVector4 c(left);
 183				c.mV[3] = 0;
 184				LLMatrix4 mat;
 185				mat.initRows(a, b, c, LLVector4(0.f, 0.f, 0.f, 1.f));
 186
 187				gGL.multMatrix( &mat.mMatrix[0][0] );
 188
 189				gGL.rotatef( -90, 0.f, 1.f, 0.f);
 190				LLColor4 color;
 191				if (mManipPart == LL_ROT_ROLL || mHighlightedPart == LL_ROT_ROLL)
 192				{
 193					color.setVec(0.8f, 0.8f, 0.8f, 0.8f);
 194					gGL.scalef(mManipulatorScales.mV[VW], mManipulatorScales.mV[VW], mManipulatorScales.mV[VW]);
 195				}
 196				else
 197				{
 198					color.setVec( 0.7f, 0.7f, 0.7f, 0.6f );
 199				}
 200				gGL.diffuseColor4fv(color.mV);
 201				gl_washer_2d(mRadiusMeters + width_meters, mRadiusMeters, CIRCLE_STEPS, color, color);
 202
 203
 204				if (mManipPart == LL_NO_PART)
 205				{
 206					gGL.color4f( 0.7f, 0.7f, 0.7f, 0.3f );
 207					gGL.diffuseColor4f(0.7f, 0.7f, 0.7f, 0.3f);
 208					gl_circle_2d( 0, 0,  mRadiusMeters, CIRCLE_STEPS, TRUE );
 209				}
 210				
 211				gGL.flush();
 212			}
 213			gGL.popMatrix();
 214
 215			if (LLGLSLShader::sNoFixedFunction)
 216			{
 217				gUIProgram.bind();
 218			}
 219		}
 220		
 221		gGL.translatef( center.mV[VX], center.mV[VY], center.mV[VZ] );
 222
 223		LLQuaternion rot;
 224		F32 angle_radians, x, y, z;
 225
 226		LLVector3 grid_origin;
 227		LLVector3 grid_scale;
 228		LLQuaternion grid_rotation;
 229
 230		LLSelectMgr::getInstance()->getGrid(grid_origin, grid_rotation, grid_scale);
 231
 232		grid_rotation.getAngleAxis(&angle_radians, &x, &y, &z);
 233		gGL.rotatef(angle_radians * RAD_TO_DEG, x, y, z);
 234
 235
 236		if (LLGLSLShader::sNoFixedFunction)
 237		{
 238			gDebugProgram.bind();
 239		}
 240
 241		if (mManipPart == LL_ROT_Z)
 242		{
 243			mManipulatorScales = lerp(mManipulatorScales, LLVector4(1.f, 1.f, SELECTED_MANIPULATOR_SCALE, 1.f), LLCriticalDamp::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE));
 244			gGL.pushMatrix();
 245			{
 246				// selected part
 247				gGL.scalef(mManipulatorScales.mV[VZ], mManipulatorScales.mV[VZ], mManipulatorScales.mV[VZ]);
 248				renderActiveRing( mRadiusMeters, width_meters, LLColor4( 0.f, 0.f, 1.f, 1.f) , LLColor4( 0.f, 0.f, 1.f, 0.3f ));
 249			}
 250			gGL.popMatrix();
 251		}
 252		else if (mManipPart == LL_ROT_Y)
 253		{
 254			mManipulatorScales = lerp(mManipulatorScales, LLVector4(1.f, SELECTED_MANIPULATOR_SCALE, 1.f, 1.f), LLCriticalDamp::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE));
 255			gGL.pushMatrix();
 256			{
 257				gGL.rotatef( 90.f, 1.f, 0.f, 0.f );
 258				gGL.scalef(mManipulatorScales.mV[VY], mManipulatorScales.mV[VY], mManipulatorScales.mV[VY]);
 259				renderActiveRing( mRadiusMeters, width_meters, LLColor4( 0.f, 1.f, 0.f, 1.f), LLColor4( 0.f, 1.f, 0.f, 0.3f));
 260			}
 261			gGL.popMatrix();
 262		}
 263		else if (mManipPart == LL_ROT_X)
 264		{
 265			mManipulatorScales = lerp(mManipulatorScales, LLVector4(SELECTED_MANIPULATOR_SCALE, 1.f, 1.f, 1.f), LLCriticalDamp::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE));
 266			gGL.pushMatrix();
 267			{
 268				gGL.rotatef( 90.f, 0.f, 1.f, 0.f );
 269				gGL.scalef(mManipulatorScales.mV[VX], mManipulatorScales.mV[VX], mManipulatorScales.mV[VX]);
 270				renderActiveRing( mRadiusMeters, width_meters, LLColor4( 1.f, 0.f, 0.f, 1.f), LLColor4( 1.f, 0.f, 0.f, 0.3f));
 271			}
 272			gGL.popMatrix();
 273		}
 274		else if (mManipPart == LL_ROT_ROLL)
 275		{
 276			mManipulatorScales = lerp(mManipulatorScales, LLVector4(1.f, 1.f, 1.f, SELECTED_MANIPULATOR_SCALE), LLCriticalDamp::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE));
 277		}
 278		else if (mManipPart == LL_NO_PART)
 279		{
 280			if (mHighlightedPart == LL_NO_PART)
 281			{
 282				mManipulatorScales = lerp(mManipulatorScales, LLVector4(1.f, 1.f, 1.f, 1.f), LLCriticalDamp::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE));
 283			}
 284
 285			LLGLEnable cull_face(GL_CULL_FACE);
 286			LLGLEnable clip_plane0(GL_CLIP_PLANE0);
 287			LLGLDepthTest gls_depth(GL_FALSE);
 288
 289			// First pass: centers. Second pass: sides.
 290			for( S32 i=0; i<2; i++ )
 291			{
 292				
 293				gGL.pushMatrix();
 294				{
 295					if (mHighlightedPart == LL_ROT_Z)
 296					{
 297						mManipulatorScales = lerp(mManipulatorScales, LLVector4(1.f, 1.f, SELECTED_MANIPULATOR_SCALE, 1.f), LLCriticalDamp::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE));
 298						gGL.scalef(mManipulatorScales.mV[VZ], mManipulatorScales.mV[VZ], mManipulatorScales.mV[VZ]);
 299						// hovering over part
 300						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);
 301					}
 302					else
 303					{
 304						// default
 305						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);
 306					}
 307				}
 308				gGL.popMatrix();
 309				
 310				gGL.pushMatrix();
 311				{
 312					gGL.rotatef( 90.f, 1.f, 0.f, 0.f );
 313					if (mHighlightedPart == LL_ROT_Y)
 314					{
 315						mManipulatorScales = lerp(mManipulatorScales, LLVector4(1.f, SELECTED_MANIPULATOR_SCALE, 1.f, 1.f), LLCriticalDamp::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE));
 316						gGL.scalef(mManipulatorScales.mV[VY], mManipulatorScales.mV[VY], mManipulatorScales.mV[VY]);
 317						// hovering over part
 318						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);
 319					}
 320					else
 321					{
 322						// default
 323						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);
 324					}						
 325				}
 326				gGL.popMatrix();
 327
 328				gGL.pushMatrix();
 329				{
 330					gGL.rotatef( 90.f, 0.f, 1.f, 0.f );
 331					if (mHighlightedPart == LL_ROT_X)
 332					{
 333						mManipulatorScales = lerp(mManipulatorScales, LLVector4(SELECTED_MANIPULATOR_SCALE, 1.f, 1.f, 1.f), LLCriticalDamp::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE));
 334						gGL.scalef(mManipulatorScales.mV[VX], mManipulatorScales.mV[VX], mManipulatorScales.mV[VX]);
 335	
 336						// hovering over part
 337						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);
 338					}
 339					else
 340					{
 341						// default
 342						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);
 343					}
 344				}
 345				gGL.popMatrix();
 346
 347				if (mHighlightedPart == LL_ROT_ROLL)
 348				{
 349					mManipulatorScales = lerp(mManipulatorScales, LLVector4(1.f, 1.f, 1.f, SELECTED_MANIPULATOR_SCALE), LLCriticalDamp::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE));
 350				}
 351				
 352			}
 353			
 354		}
 355
 356		if (LLGLSLShader::sNoFixedFunction)
 357		{
 358			gUIProgram.bind();
 359		}
 360		
 361	}
 362	gGL.popMatrix();
 363	gGL.popMatrix();
 364	
 365
 366	LLVector3 euler_angles;
 367	LLQuaternion object_rot = first_object->getRotationEdit();
 368	object_rot.getEulerAngles(&(euler_angles.mV[VX]), &(euler_angles.mV[VY]), &(euler_angles.mV[VZ]));
 369	euler_angles *= RAD_TO_DEG;
 370	euler_angles.mV[VX] = llround(fmodf(euler_angles.mV[VX] + 360.f, 360.f), 0.05f);
 371	euler_angles.mV[VY] = llround(fmodf(euler_angles.mV[VY] + 360.f, 360.f), 0.05f);
 372	euler_angles.mV[VZ] = llround(fmodf(euler_angles.mV[VZ] + 360.f, 360.f), 0.05f);
 373
 374	renderXYZ(euler_angles);
 375}
 376
 377BOOL LLManipRotate::handleMouseDown(S32 x, S32 y, MASK mask)
 378{
 379	BOOL	handled = FALSE;
 380
 381	LLViewerObject* first_object = mObjectSelection->getFirstMoveableObject(TRUE);
 382	if( first_object )
 383	{
 384		if( mHighlightedPart != LL_NO_PART )
 385		{
 386			handled = handleMouseDownOnPart( x, y, mask );
 387		}
 388	}
 389
 390	return handled;
 391}
 392
 393// Assumes that one of the parts of the manipulator was hit.
 394BOOL LLManipRotate::handleMouseDownOnPart( S32 x, S32 y, MASK mask )
 395{
 396	BOOL can_rotate = canAffectSelection();
 397	if (!can_rotate)
 398	{
 399		return FALSE;
 400	}
 401
 402	highlightManipulators(x, y);
 403	S32 hit_part = mHighlightedPart;
 404	// we just started a drag, so save initial object positions
 405	LLSelectMgr::getInstance()->saveSelectedObjectTransform(SELECT_ACTION_TYPE_ROTATE);
 406
 407	// save selection center
 408	mRotationCenter = gAgent.getPosGlobalFromAgent( getPivotPoint() ); //LLSelectMgr::getInstance()->getSelectionCenterGlobal();
 409
 410	mManipPart = (EManipPart)hit_part;
 411	LLVector3 center = gAgent.getPosAgentFromGlobal( mRotationCenter );
 412
 413	if( mManipPart == LL_ROT_GENERAL)
 414	{
 415		mMouseDown = intersectMouseWithSphere( x, y, center, mRadiusMeters);
 416	}
 417	else
 418	{
 419		// Project onto the plane of the ring
 420		LLVector3 axis = getConstraintAxis();
 421
 422		F32 axis_onto_cam = llabs( axis * mCenterToCamNorm );
 423		const F32 AXIS_ONTO_CAM_TOL = cos( 85.f * DEG_TO_RAD );
 424		if( axis_onto_cam < AXIS_ONTO_CAM_TOL )
 425		{
 426			LLVector3 up_from_axis = mCenterToCamNorm % axis;
 427			up_from_axis.normVec();
 428			LLVector3 cur_intersection;
 429			getMousePointOnPlaneAgent(cur_intersection, x, y, center, mCenterToCam);
 430			cur_intersection -= center;
 431			mMouseDown = projected_vec(cur_intersection, up_from_axis);
 432			F32 mouse_depth = SNAP_GUIDE_INNER_RADIUS * mRadiusMeters;
 433			F32 mouse_dist_sqrd = mMouseDown.magVecSquared();
 434			if (mouse_dist_sqrd > 0.0001f)
 435			{
 436				mouse_depth = sqrtf((SNAP_GUIDE_INNER_RADIUS * mRadiusMeters) * (SNAP_GUIDE_INNER_RADIUS * mRadiusMeters) - 
 437									mouse_dist_sqrd);
 438			}
 439			LLVector3 projected_center_to_cam = mCenterToCamNorm - projected_vec(mCenterToCamNorm, axis);
 440			mMouseDown += mouse_depth * projected_center_to_cam;
 441
 442		}
 443		else
 444		{
 445			mMouseDown = findNearestPointOnRing( x, y, center, axis ) - center;
 446			mMouseDown.normVec();
 447		}
 448	}
 449
 450	mMouseCur = mMouseDown;
 451
 452	// Route future Mouse messages here preemptively.  (Release on mouse up.)
 453	setMouseCapture( TRUE );
 454	LLSelectMgr::getInstance()->enableSilhouette(FALSE);
 455	return TRUE;
 456}
 457
 458
 459LLVector3 LLManipRotate::findNearestPointOnRing( S32 x, S32 y, const LLVector3& center, const LLVector3& axis )
 460{
 461	// Project the delta onto the ring and rescale it by the radius so that it's _on_ the ring.
 462	LLVector3 proj_onto_ring;
 463	getMousePointOnPlaneAgent(proj_onto_ring, x, y, center, axis);
 464	proj_onto_ring -= center;
 465	proj_onto_ring.normVec();
 466
 467	return center + proj_onto_ring * mRadiusMeters;
 468}
 469
 470BOOL LLManipRotate::handleMouseUp(S32 x, S32 y, MASK mask)
 471{
 472	// first, perform normal processing in case this was a quick-click
 473	handleHover(x, y, mask);
 474
 475	if( hasMouseCapture() )
 476	{
 477		for (LLObjectSelection::iterator iter = mObjectSelection->begin();
 478		 iter != mObjectSelection->end(); iter++)
 479		{
 480			LLSelectNode* selectNode = *iter;
 481			LLViewerObject* object = selectNode->getObject();
 482
 483			// have permission to move and object is root of selection or individually selected
 484			if (object->permMove() && (object->isRootEdit() || selectNode->mIndividualSelection))
 485			{
 486				object->mUnselectedChildrenPositions.clear() ;
 487			}
 488		}
 489
 490		mManipPart = LL_NO_PART;
 491
 492		// Might have missed last update due to timing.
 493		LLSelectMgr::getInstance()->sendMultipleUpdate( UPD_ROTATION | UPD_POSITION );
 494		LLSelectMgr::getInstance()->enableSilhouette(TRUE);
 495		//gAgent.setObjectTracking(gSavedSettings.getBOOL("TrackFocusObject"));
 496
 497		LLSelectMgr::getInstance()->updateSelectionCenter();
 498		LLSelectMgr::getInstance()->saveSelectedObjectTransform(SELECT_ACTION_TYPE_PICK);
 499	}
 500
 501	return LLManip::handleMouseUp(x, y, mask);
 502}
 503
 504
 505BOOL LLManipRotate::handleHover(S32 x, S32 y, MASK mask)
 506{
 507	if( hasMouseCapture() )
 508	{
 509		if( mObjectSelection->isEmpty() )
 510		{
 511			// Somehow the object got deselected while we were dragging it.
 512			setMouseCapture( FALSE );
 513		}
 514		else
 515		{
 516			drag(x, y);
 517		}
 518
 519		lldebugst(LLERR_USER_INPUT) << "hover handled by LLManipRotate (active)" << llendl;		
 520	}
 521	else
 522	{
 523		highlightManipulators(x, y);
 524		lldebugst(LLERR_USER_INPUT) << "hover handled by LLManipRotate (inactive)" << llendl;		
 525	}
 526
 527	gViewerWindow->setCursor(UI_CURSOR_TOOLROTATE);
 528	return TRUE;
 529}
 530
 531
 532LLVector3 LLManipRotate::projectToSphere( F32 x, F32 y, BOOL* on_sphere ) 
 533{
 534	F32 z = 0.f;
 535	F32 dist_squared = x*x + y*y;
 536
 537	*on_sphere = dist_squared <= SQ_RADIUS;
 538    if( *on_sphere )
 539	{    
 540        z = sqrt(SQ_RADIUS - dist_squared);
 541    }
 542	return LLVector3( x, y, z );
 543}
 544
 545// Freeform rotation
 546void LLManipRotate::drag( S32 x, S32 y )
 547{
 548	if( !updateVisiblity() )
 549	{
 550		return;
 551	}
 552
 553	if( mManipPart == LL_ROT_GENERAL )
 554	{
 555		mRotation = dragUnconstrained(x, y);
 556	}
 557	else
 558	{
 559		mRotation = dragConstrained(x, y);
 560	}
 561
 562	BOOL damped = mSmoothRotate;
 563	mSmoothRotate = FALSE;
 564
 565	for (LLObjectSelection::iterator iter = mObjectSelection->begin();
 566		 iter != mObjectSelection->end(); iter++)
 567	{
 568		LLSelectNode* selectNode = *iter;
 569		LLViewerObject* object = selectNode->getObject();
 570
 571		// have permission to move and object is root of selection or individually selected
 572		if (object->permMove() && (object->isRootEdit() || selectNode->mIndividualSelection))
 573		{
 574			if (!object->isRootEdit())
 575			{
 576				// child objects should not update if parent is selected
 577				LLViewerObject* editable_root = (LLViewerObject*)object->getParent();
 578				if (editable_root->isSelected())
 579				{
 580					// we will be moved properly by our parent, so skip
 581					continue;
 582				}
 583			}
 584
 585			LLQuaternion new_rot = selectNode->mSavedRotation * mRotation;
 586			std::vector<LLVector3>& child_positions = object->mUnselectedChildrenPositions ;
 587			std::vector<LLQuaternion> child_rotations;
 588			if (object->isRootEdit() && selectNode->mIndividualSelection)
 589			{
 590				object->saveUnselectedChildrenRotation(child_rotations) ;
 591				object->saveUnselectedChildrenPosition(child_positions) ;			
 592			}
 593
 594			if (object->getParent() && object->mDrawable.notNull())
 595			{
 596				LLQuaternion invParentRotation = object->mDrawable->mXform.getParent()->getWorldRotation();
 597				invParentRotation.transQuat();
 598
 599				object->setRotation(new_rot * invParentRotation, damped);
 600				rebuild(object);
 601			}
 602			else
 603			{
 604				object->setRotation(new_rot, damped);
 605				rebuild(object);
 606			}
 607
 608			// for individually selected roots, we need to counterrotate all the children
 609			if (object->isRootEdit() && selectNode->mIndividualSelection)
 610			{
 611				//RN: must do non-damped updates on these objects so relative rotation appears constant
 612				// instead of having two competing slerps making the child objects appear to "wobble"
 613				object->resetChildrenRotationAndPosition(child_rotations, child_positions) ;
 614			}
 615		}
 616	}
 617
 618	// update positions
 619	for (LLObjectSelection::iterator iter = mObjectSelection->begin();
 620		 iter != mObjectSelection->end(); iter++)
 621	{
 622		LLSelectNode* selectNode = *iter;
 623		LLViewerObject* object = selectNode->getObject();
 624
 625		// to avoid cumulative position changes we calculate the objects new position using its saved position
 626		if (object && object->permMove())
 627		{
 628			LLVector3 center   = gAgent.getPosAgentFromGlobal( mRotationCenter );
 629
 630			LLVector3 old_position;
 631			LLVector3 new_position;
 632
 633			if (object->isAttachment() && object->mDrawable.notNull())
 634			{ 
 635				// need to work in drawable space to handle selected items from multiple attachments 
 636				// (which have no shared frame of reference other than their render positions)
 637				LLXform* parent_xform = object->mDrawable->getXform()->getParent();
 638				new_position = (selectNode->mSavedPositionLocal * parent_xform->getWorldRotation()) + parent_xform->getWorldPosition();
 639				old_position = (object->getPosition() * parent_xform->getWorldRotation()) + parent_xform->getWorldPosition();//object->getRenderPosition();
 640			}
 641			else
 642			{
 643				new_position = gAgent.getPosAgentFromGlobal( selectNode->mSavedPositionGlobal );
 644				old_position = object->getPositionAgent();
 645			}
 646
 647			new_position = (new_position - center) * mRotation;		// new relative rotated position
 648			new_position += center;
 649			
 650			if (object->isRootEdit() && !object->isAttachment())
 651			{
 652				LLVector3d new_pos_global = gAgent.getPosGlobalFromAgent(new_position);
 653				new_pos_global = LLWorld::getInstance()->clipToVisibleRegions(selectNode->mSavedPositionGlobal, new_pos_global);
 654				new_position = gAgent.getPosAgentFromGlobal(new_pos_global);
 655			}
 656
 657			// for individually selected child objects
 658			if (!object->isRootEdit() && selectNode->mIndividualSelection)
 659			{
 660				LLViewerObject* parentp = (LLViewerObject*)object->getParent();
 661				if (!parentp->isSelected())
 662				{
 663					if (object->isAttachment() && object->mDrawable.notNull())
 664					{
 665						// find position relative to render position of parent
 666						object->setPosition((new_position - parentp->getRenderPosition()) * ~parentp->getRenderRotation());
 667						rebuild(object);
 668					}
 669					else
 670					{
 671						object->setPositionParent((new_position - parentp->getPositionAgent()) * ~parentp->getRotationRegion());
 672						rebuild(object);
 673					}
 674				}
 675			}
 676			else if (object->isRootEdit())
 677			{
 678				if (object->isAttachment() && object->mDrawable.notNull())
 679				{
 680					LLXform* parent_xform = object->mDrawable->getXform()->getParent();
 681					object->setPosition((new_position - parent_xform->getWorldPosition()) * ~parent_xform->getWorldRotation());
 682					rebuild(object);
 683				}
 684				else
 685				{
 686					object->setPositionAgent(new_position);
 687					rebuild(object);
 688				}
 689			}
 690
 691			// for individually selected roots, we need to counter-translate all unselected children
 692			if (object->isRootEdit() && selectNode->mIndividualSelection)
 693			{
 694				// only offset by parent's translation as we've already countered parent's rotation
 695				rebuild(object);
 696				object->resetChildrenPosition(old_position - new_position) ;				
 697			}
 698		}
 699	}
 700
 701	// store changes to override updates
 702	for (LLObjectSelection::iterator iter = LLSelectMgr::getInstance()->getSelection()->begin();
 703		 iter != LLSelectMgr::getInstance()->getSelection()->end(); iter++)
 704	{
 705		LLSelectNode* selectNode = *iter;
 706		LLViewerObject*cur = selectNode->getObject();
 707		if( cur->permModify() && cur->permMove() && !cur->isAvatar())
 708		{
 709			selectNode->mLastRotation = cur->getRotation();
 710			selectNode->mLastPositionLocal = cur->getPosition();
 711		}
 712	}	
 713
 714	LLSelectMgr::getInstance()->updateSelectionCenter();
 715
 716	// RN: just clear focus so camera doesn't follow spurious object updates
 717	gAgentCamera.clearFocusObject();
 718	dialog_refresh_all();
 719}
 720
 721void LLManipRotate::renderActiveRing( F32 radius, F32 width, const LLColor4& front_color, const LLColor4& back_color)
 722{
 723	LLGLEnable cull_face(GL_CULL_FACE);
 724	{
 725		gl_ring(radius, width, back_color, back_color * 0.5f, CIRCLE_STEPS, FALSE);
 726		gl_ring(radius, width, back_color, back_color * 0.5f, CIRCLE_STEPS, TRUE);
 727	}
 728	{
 729		LLGLDepthTest gls_depth(GL_FALSE);
 730		gl_ring(radius, width, front_color, front_color * 0.5f, CIRCLE_STEPS, FALSE);
 731		gl_ring(radius, width, front_color, front_color * 0.5f, CIRCLE_STEPS, TRUE);
 732	}
 733}
 734
 735void LLManipRotate::renderSnapGuides()
 736{
 737	LLVector3 grid_origin;
 738	LLVector3 grid_scale;
 739	LLQuaternion grid_rotation;
 740	LLVector3 constraint_axis = getConstraintAxis();
 741
 742	LLSelectMgr::getInstance()->getGrid(grid_origin, grid_rotation, grid_scale);
 743
 744	if (!gSavedSettings.getBOOL("SnapEnabled"))
 745	{
 746		return;
 747	}
 748
 749	LLVector3 center = gAgent.getPosAgentFromGlobal( mRotationCenter );
 750	LLVector3 cam_at_axis;
 751	if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD)
 752	{
 753		cam_at_axis.setVec(1.f, 0.f, 0.f);
 754	}
 755	else
 756	{
 757		cam_at_axis = center - gAgentCamera.getCameraPositionAgent();
 758		cam_at_axis.normVec();
 759	}
 760
 761	LLVector3 world_snap_axis;
 762	LLVector3 test_axis = constraint_axis;
 763
 764	BOOL constrain_to_ref_object = FALSE;
 765	if (mObjectSelection->getSelectType() == SELECT_TYPE_ATTACHMENT && isAgentAvatarValid())
 766	{
 767		test_axis = test_axis * ~grid_rotation;
 768	}
 769	else if (LLSelectMgr::getInstance()->getGridMode() == GRID_MODE_REF_OBJECT)
 770	{
 771		test_axis = test_axis * ~grid_rotation;
 772		constrain_to_ref_object = TRUE;
 773	}
 774
 775	test_axis.abs();
 776
 777	// find closest global/reference axis to local constraint axis;
 778	if (test_axis.mV[VX] > test_axis.mV[VY] && test_axis.mV[VX] > test_axis.mV[VZ])
 779	{
 780		world_snap_axis = LLVector3::y_axis;
 781	}
 782	else if (test_axis.mV[VY] > test_axis.mV[VZ])
 783	{
 784		world_snap_axis = LLVector3::z_axis;
 785	}
 786	else
 787	{
 788		world_snap_axis = LLVector3::x_axis;
 789	}
 790
 791	LLVector3 projected_snap_axis = world_snap_axis;
 792	if (mObjectSelection->getSelectType() == SELECT_TYPE_ATTACHMENT && isAgentAvatarValid())
 793	{
 794		projected_snap_axis = projected_snap_axis * grid_rotation;
 795	}
 796	else if (constrain_to_ref_object)
 797	{
 798		projected_snap_axis = projected_snap_axis * grid_rotation;
 799	}
 800
 801	// project world snap axis onto constraint plane
 802	projected_snap_axis -= projected_vec(projected_snap_axis, constraint_axis);
 803	projected_snap_axis.normVec();
 804
 805	S32 num_rings = mCamEdgeOn ? 2 : 1;
 806	for (S32 ring_num = 0; ring_num < num_rings; ring_num++)
 807	{
 808		LLVector3 center = gAgent.getPosAgentFromGlobal( mRotationCenter );
 809
 810		if (mCamEdgeOn)
 811		{
 812			// draw two opposing rings
 813			if (ring_num == 0)
 814			{
 815				center += constraint_axis * mRadiusMeters * 0.5f;
 816			}
 817			else
 818			{
 819				center -= constraint_axis * mRadiusMeters * 0.5f;
 820			}
 821		}
 822
 823		LLGLDepthTest gls_depth(GL_FALSE);
 824		for (S32 pass = 0; pass < 3; pass++)
 825		{
 826			// render snap guide ring
 827			gGL.pushMatrix();
 828			
 829			LLQuaternion snap_guide_rot;
 830			F32 angle_radians, x, y, z;
 831			snap_guide_rot.shortestArc(LLVector3::z_axis, getConstraintAxis());
 832			snap_guide_rot.getAngleAxis(&angle_radians, &x, &y, &z);
 833			gGL.translatef(center.mV[VX], center.mV[VY], center.mV[VZ]);
 834			gGL.rotatef(angle_radians * RAD_TO_DEG, x, y, z);
 835
 836			LLColor4 line_color = setupSnapGuideRenderPass(pass);
 837
 838			gGL.color4fv(line_color.mV);
 839
 840			if (mCamEdgeOn)
 841			{
 842				// render an arc
 843				LLVector3 edge_normal = cam_at_axis % constraint_axis;
 844				edge_normal.normVec();
 845				LLVector3 x_axis_snap = LLVector3::x_axis * snap_guide_rot;
 846				LLVector3 y_axis_snap = LLVector3::y_axis * snap_guide_rot;
 847
 848				F32 end_angle = atan2(y_axis_snap * edge_normal, x_axis_snap * edge_normal);
 849				//F32 start_angle = angle_between((-1.f * LLVector3::x_axis) * snap_guide_rot, edge_normal);
 850				F32 start_angle = end_angle - F_PI;
 851				gl_arc_2d(0.f, 0.f, mRadiusMeters * SNAP_GUIDE_INNER_RADIUS, CIRCLE_STEPS, FALSE, start_angle, end_angle);
 852			}
 853			else
 854			{
 855				gl_circle_2d(0.f, 0.f, mRadiusMeters * SNAP_GUIDE_INNER_RADIUS, CIRCLE_STEPS, FALSE);
 856			}
 857			gGL.popMatrix();
 858
 859			for (S32 i = 0; i < 64; i++)
 860			{
 861				BOOL render_text = TRUE;
 862				F32 deg = 5.625f * (F32)i;
 863				LLVector3 inner_point;
 864				LLVector3 outer_point;
 865				LLVector3 text_point;
 866				LLQuaternion rot(deg * DEG_TO_RAD, constraint_axis);
 867				gGL.begin(LLRender::LINES);
 868				{
 869					inner_point = (projected_snap_axis * mRadiusMeters * SNAP_GUIDE_INNER_RADIUS * rot) + center;
 870					F32 tick_length = 0.f;
 871					if (i % 16 == 0)
 872					{
 873						tick_length = mRadiusMeters * (SNAP_GUIDE_RADIUS_1 - SNAP_GUIDE_INNER_RADIUS);
 874					}
 875					else if (i % 8 == 0)
 876					{
 877						tick_length = mRadiusMeters * (SNAP_GUIDE_RADIUS_2 - SNAP_GUIDE_INNER_RADIUS);
 878					}
 879					else if (i % 4 == 0)
 880					{
 881						tick_length = mRadiusMeters * (SNAP_GUIDE_RADIUS_3 - SNAP_GUIDE_INNER_RADIUS);
 882					}
 883					else if (i % 2 == 0)
 884					{
 885						tick_length = mRadiusMeters * (SNAP_GUIDE_RADIUS_4 - SNAP_GUIDE_INNER_RADIUS);
 886					}
 887					else
 888					{
 889						tick_length = mRadiusMeters * (SNAP_GUIDE_RADIUS_5 - SNAP_GUIDE_INNER_RADIUS);
 890					}
 891					
 892					if (mCamEdgeOn)
 893					{
 894						// don't draw ticks that are on back side of circle
 895						F32 dot = cam_at_axis * (projected_snap_axis * rot);
 896						if (dot > 0.f)
 897						{
 898							outer_point = inner_point;
 899							render_text = FALSE;
 900						}
 901						else
 902						{
 903							if (ring_num == 0)
 904							{
 905								outer_point = inner_point + (constraint_axis * tick_length) * rot;
 906							}
 907							else
 908							{
 909								outer_point = inner_point - (constraint_axis * tick_length) * rot;
 910							}
 911						}
 912					}
 913					else
 914					{
 915						outer_point = inner_point + (projected_snap_axis * tick_length) * rot;
 916					}
 917
 918					text_point = outer_point + (projected_snap_axis * mRadiusMeters * 0.1f) * rot;
 919
 920					gGL.vertex3fv(inner_point.mV);
 921					gGL.vertex3fv(outer_point.mV);
 922				}
 923				gGL.end();
 924
 925				//RN: text rendering does own shadow pass, so only render once
 926				if (pass == 1 && render_text && i % 16 == 0)
 927				{
 928					if (world_snap_axis.mV[VX])
 929					{
 930						if (i == 0)
 931						{
 932							renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Direction_Forward") : LLTrans::getString("Direction_East"), LLColor4::white);
 933						}
 934						else if (i == 16)
 935						{
 936							if (constraint_axis.mV[VZ] > 0.f)
 937							{
 938								renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Direction_Left") : LLTrans::getString("Direction_North"), LLColor4::white);
 939							}
 940							else
 941							{
 942								renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Direction_Right") : LLTrans::getString("Direction_South"), LLColor4::white);
 943							}
 944						}
 945						else if (i == 32)
 946						{
 947							renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Direction_Back") : LLTrans::getString("Direction_West"), LLColor4::white);
 948						}
 949						else
 950						{
 951							if (constraint_axis.mV[VZ] > 0.f)
 952							{
 953								renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Direction_Right") : LLTrans::getString("Direction_South"), LLColor4::white);
 954							}
 955							else
 956							{
 957								renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Direction_Left") : LLTrans::getString("Direction_North"), LLColor4::white);
 958							}
 959						}
 960					}
 961					else if (world_snap_axis.mV[VY])
 962					{
 963						if (i == 0)
 964						{
 965							renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Direction_Left") : LLTrans::getString("Direction_North"), LLColor4::white);
 966						}
 967						else if (i == 16)
 968						{
 969							if (constraint_axis.mV[VX] > 0.f)
 970							{
 971								renderTickText(text_point, LLTrans::getString("Direction_Up"), LLColor4::white);
 972							}
 973							else
 974							{
 975								renderTickText(text_point, LLTrans::getString("Direction_Down"), LLColor4::white);
 976							}
 977						}
 978						else if (i == 32)
 979						{
 980							renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Direction_Right") : LLTrans::getString("Direction_South"), LLColor4::white);
 981						}
 982						else
 983						{
 984							if (constraint_axis.mV[VX] > 0.f)
 985							{
 986								renderTickText(text_point, LLTrans::getString("Direction_Down"), LLColor4::white);
 987							}
 988							else
 989							{
 990								renderTickText(text_point, LLTrans::getString("Direction_Up"), LLColor4::white);
 991							}
 992						}
 993					}
 994					else if (world_snap_axis.mV[VZ])
 995					{
 996						if (i == 0)
 997						{
 998							renderTickText(text_point, LLTrans::getString("Direction_Up"), LLColor4::white);
 999						}
1000						else if (i == 16)
1001						{
1002							if (constraint_axis.mV[VY] > 0.f)
1003							{
1004								renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Direction_Forward") : LLTrans::getString("Direction_East"), LLColor4::white);
1005							}
1006							else
1007							{
1008								renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Direction_Back") : LLTrans::getString("Direction_West"), LLColor4::white);
1009							}
1010						}
1011						else if (i == 32)
1012						{
1013							renderTickText(text_point, LLTrans::getString("Direction_Down"), LLColor4::white);
1014						}
1015						else
1016						{
1017							if (constraint_axis.mV[VY] > 0.f)
1018							{
1019								renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Direction_Back") : LLTrans::getString("Direction_West"), LLColor4::white);
1020							}
1021							else
1022							{
1023								renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Direction_Forward") : LLTrans::getString("Direction_East"), LLColor4::white);
1024							}
1025						}
1026					}
1027				}
1028				gGL.color4fv(line_color.mV);
1029			}
1030
1031			// now render projected object axis
1032			if (mInSnapRegime)
1033			{
1034				LLVector3 object_axis;
1035				getObjectAxisClosestToMouse(object_axis);
1036
1037				// project onto constraint plane
1038				LLSelectNode* first_node = mObjectSelection->getFirstMoveableNode(TRUE);
1039				object_axis = object_axis * first_node->getObject()->getRenderRotation();
1040				object_axis = object_axis - (object_axis * getConstraintAxis()) * getConstraintAxis();
1041				object_axis.normVec();
1042				object_axis = object_axis * SNAP_GUIDE_INNER_RADIUS * mRadiusMeters + center;
1043				LLVector3 line_start = center;
1044
1045				gGL.begin(LLRender::LINES);
1046				{
1047					gGL.vertex3fv(line_start.mV);
1048					gGL.vertex3fv(object_axis.mV);
1049				}
1050				gGL.end();
1051
1052				// draw snap guide arrow
1053				gGL.begin(LLRender::TRIANGLES);
1054				{
1055					LLVector3 arrow_dir;
1056					LLVector3 arrow_span = (object_axis - line_start) % getConstraintAxis();
1057					arrow_span.normVec();
1058
1059					arrow_dir = mCamEdgeOn ? getConstraintAxis() : object_axis - line_start;
1060					arrow_dir.normVec();
1061					if (ring_num == 1)
1062					{
1063						arrow_dir *= -1.f;
1064					}
1065					gGL.vertex3fv((object_axis + arrow_dir * mRadiusMeters * 0.1f).mV);
1066					gGL.vertex3fv((object_axis + arrow_span * mRadiusMeters * 0.1f).mV);
1067					gGL.vertex3fv((object_axis - arrow_span * mRadiusMeters * 0.1f).mV);
1068				}
1069				gGL.end();
1070
1071				{
1072					LLGLDepthTest gls_depth(GL_TRUE);
1073					gGL.begin(LLRender::LINES);
1074					{
1075						gGL.vertex3fv(line_start.mV);
1076						gGL.vertex3fv(object_axis.mV);
1077					}
1078					gGL.end();
1079
1080					// draw snap guide arrow
1081					gGL.begin(LLRender::TRIANGLES);
1082					{
1083						LLVector3 arrow_dir;
1084						LLVector3 arrow_span = (object_axis - line_start) % getConstraintAxis();
1085						arrow_span.normVec();
1086
1087						arrow_dir = mCamEdgeOn ? getConstraintAxis() : object_axis - line_start;
1088						arrow_dir.normVec();
1089						if (ring_num == 1)
1090						{
1091							arrow_dir *= -1.f;
1092						}
1093
1094						gGL.vertex3fv((object_axis + arrow_dir * mRadiusMeters * 0.1f).mV);
1095						gGL.vertex3fv((object_axis + arrow_span * mRadiusMeters * 0.1f).mV);
1096						gGL.vertex3fv((object_axis - arrow_span * mRadiusMeters * 0.1f).mV);
1097					}
1098					gGL.end();
1099				}
1100			}
1101		}
1102	}
1103}
1104
1105// Returns TRUE if center of sphere is visible.  Also sets a bunch of member variables that are used later (e.g. mCenterToCam)
1106BOOL LLManipRotate::updateVisiblity()
1107{
1108	// Don't want to recalculate the center of the selection during a drag.
1109	// Due to packet delays, sometimes half the objects in the selection have their
1110	// new position and half have their old one.  This creates subtle errors in the
1111	// computed center position for that frame.  Unfortunately, these errors
1112	// accumulate.  The result is objects seem to "fly apart" during rotations.
1113	// JC - 03.26.2002
1114	if (!hasMouseCapture())
1115	{
1116		mRotationCenter = gAgent.getPosGlobalFromAgent( getPivotPoint() );//LLSelectMgr::getInstance()->getSelectionCenterGlobal();
1117	}
1118
1119	BOOL visible = FALSE;
1120
1121	LLVector3 center = gAgent.getPosAgentFromGlobal( mRotationCenter );
1122	if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD)
1123	{
1124		mCenterToCam = LLVector3(-1.f / gAgentCamera.mHUDCurZoom, 0.f, 0.f);
1125		mCenterToCamNorm = mCenterToCam;
1126		mCenterToCamMag = mCenterToCamNorm.normVec();
1127
1128		mRadiusMeters = RADIUS_PIXELS / (F32) LLViewerCamera::getInstance()->getViewHeightInPixels();
1129		mRadiusMeters /= gAgentCamera.mHUDCurZoom;
1130
1131		mCenterToProfilePlaneMag = mRadiusMeters * mRadiusMeters / mCenterToCamMag;
1132		mCenterToProfilePlane = -mCenterToProfilePlaneMag * mCenterToCamNorm;
1133
1134		// x axis range is (-aspect * 0.5f, +aspect * 0.5)
1135		// y axis range is (-0.5, 0.5)
1136		// so use getWorldViewHeightRaw as scale factor when converting to pixel coordinates
1137		mCenterScreen.set((S32)((0.5f - center.mV[VY]) / gAgentCamera.mHUDCurZoom * gViewerWindow->getWorldViewHeightScaled()),
1138							(S32)((center.mV[VZ] + 0.5f) / gAgentCamera.mHUDCurZoom * gViewerWindow->getWorldViewHeightScaled()));
1139		visible = TRUE;
1140	}
1141	else
1142	{
1143		visible = LLViewerCamera::getInstance()->projectPosAgentToScreen(center, mCenterScreen );
1144		if( visible )
1145		{
1146			mCenterToCam = gAgentCamera.getCameraPositionAgent() - center;
1147			mCenterToCamNorm = mCenterToCam;
1148			mCenterToCamMag = mCenterToCamNorm.normVec();
1149			LLVector3 cameraAtAxis = LLViewerCamera::getInstance()->getAtAxis();
1150			cameraAtAxis.normVec();
1151
1152			F32 z_dist = -1.f * (mCenterToCam * cameraAtAxis);
1153
1154			// Don't drag manip if object too far away
1155			if (gSavedSettings.getBOOL("LimitSelectDistance"))
1156			{
1157				F32 max_select_distance = gSavedSettings.getF32("MaxSelectDistance");
1158				if (dist_vec_squared(gAgent.getPositionAgent(), center) > (max_select_distance * max_select_distance))
1159				{
1160					visible = FALSE;
1161				}
1162			}
1163			
1164			if (mCenterToCamMag > 0.001f)
1165			{
1166				F32 fraction_of_fov = RADIUS_PIXELS / (F32) LLViewerCamera::getInstance()->getViewHeightInPixels();
1167				F32 apparent_angle = fraction_of_fov * LLViewerCamera::getInstance()->getView();  // radians
1168				mRadiusMeters = z_dist * tan(apparent_angle);
1169
1170				mCenterToProfilePlaneMag = mRadiusMeters * mRadiusMeters / mCenterToCamMag;
1171				mCenterToProfilePlane = -mCenterToProfilePlaneMag * mCenterToCamNorm;
1172			}
1173			else
1174			{
1175				visible = FALSE;
1176			}
1177		}
1178	}
1179
1180	mCamEdgeOn = FALSE;
1181	F32 axis_onto_cam = mManipPart >= LL_ROT_X ? llabs( getConstraintAxis() * mCenterToCamNorm ) : 0.f;
1182	if( axis_onto_cam < AXIS_ONTO_CAM_TOLERANCE )
1183	{
1184		mCamEdgeOn = TRUE;
1185	}
1186
1187	return visible;
1188}
1189
1190LLQuaternion LLManipRotate::dragUnconstrained( S32 x, S32 y )
1191{
1192	LLVector3 cam = gAgentCamera.getCameraPositionAgent();
1193	LLVector3 center =  gAgent.getPosAgentFromGlobal( mRotationCenter );
1194
1195	mMouseCur = intersectMouseWithSphere( x, y, center, mRadiusMeters);
1196
1197	F32 delta_x = (F32)(mCenterScreen.mX - x);
1198	F32 delta_y = (F32)(mCenterScreen.mY - y);
1199
1200	F32 dist_from_sphere_center = sqrt(delta_x * delta_x + delta_y * delta_y);
1201
1202	LLVector3 axis = mMouseDown % mMouseCur;
1203	axis.normVec();
1204	F32 angle = acos(mMouseDown * mMouseCur);
1205	LLQuaternion sphere_rot( angle, axis );
1206
1207	if (is_approx_zero(1.f - mMouseDown * mMouseCur))
1208	{
1209		return LLQuaternion::DEFAULT;
1210	}
1211	else if (dist_from_sphere_center < RADIUS_PIXELS)
1212	{
1213		return sphere_rot;
1214	}
1215	else
1216	{
1217		LLVector3 intersection;
1218		getMousePointOnPlaneAgent( intersection, x, y, center + mCenterToProfilePlane, mCenterToCamNorm );
1219
1220		// amount dragging in sphere from center to periphery would rotate object
1221		F32 in_sphere_angle = F_PI_BY_TWO;
1222		F32 dist_to_tangent_point = mRadiusMeters;
1223		if( !is_approx_zero( mCenterToProfilePlaneMag ) )
1224		{
1225			dist_to_tangent_point = sqrt( mRadiusMeters * mRadiusMeters - mCenterToProfilePlaneMag * mCenterToProfilePlaneMag );
1226			in_sphere_angle = atan2( dist_to_tangent_point, mCenterToProfilePlaneMag );
1227		}
1228
1229		LLVector3 profile_center_to_intersection = intersection - (center + mCenterToProfilePlane);
1230		F32 dist_to_intersection = profile_center_to_intersection.normVec();
1231		F32 angle = (-1.f + dist_to_intersection / dist_to_tangent_point) * in_sphere_angle;
1232
1233		LLVector3 axis;
1234		if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD)
1235		{
1236			axis = LLVector3(-1.f, 0.f, 0.f) % profile_center_to_intersection;
1237		}
1238		else
1239		{
1240			axis = (cam - center) % profile_center_to_intersection;
1241			axis.normVec();
1242		}
1243		return sphere_rot * LLQuaternion( angle, axis );
1244	}
1245}
1246
1247LLVector3 LLManipRotate::getConstraintAxis()
1248{
1249	LLVector3 axis;
1250	if( LL_ROT_ROLL == mManipPart )
1251	{
1252		axis = mCenterToCamNorm;
1253	}
1254	else
1255	{
1256		S32 axis_dir = mManipPart - LL_ROT_X;
1257		if ((axis_dir >= 0) && (axis_dir < 3))
1258		{
1259			axis.mV[axis_dir] = 1.f;
1260		}
1261		else
1262		{
1263#ifndef LL_RELEASE_FOR_DOWNLOAD
1264			llerrs << "Got bogus hit part in LLManipRotate::getConstraintAxis():" << mManipPart << llendl;
1265#else
1266			llwarns << "Got bogus hit part in LLManipRotate::getConstraintAxis():" << mManipPart << llendl;
1267#endif
1268			axis.mV[0] = 1.f;
1269		}
1270
1271		LLVector3 grid_origin;
1272		LLVector3 grid_scale;
1273		LLQuaternion grid_rotation;
1274
1275		LLSelectMgr::getInstance()->getGrid(grid_origin, grid_rotation, grid_scale);
1276
1277		LLSelectNode* first_node = mObjectSelection->getFirstMoveableNode(TRUE);
1278		if (first_node)
1279		{
1280			// *FIX: get agent local attachment grid working
1281			// Put rotation into frame of first selected root object
1282			axis = axis * grid_rotation;
1283		}
1284	}
1285
1286	return axis;
1287}
1288
1289LLQuaternion LLManipRotate::dragConstrained( S32 x, S32 y )
1290{
1291	LLSelectNode* first_object_node = mObjectSelection->getFirstMoveableNode(TRUE);
1292	LLVector3 constraint_axis = getConstraintAxis();
1293	LLVector3 center = gAgent.getPosAgentFromGlobal( mRotationCenter );
1294
1295	F32 angle = 0.f;
1296
1297	// build snap axes
1298	LLVector3 grid_origin;
1299	LLVector3 grid_scale;
1300	LLQuaternion grid_rotation;
1301
1302	LLSelectMgr::getInstance()->getGrid(grid_origin, grid_rotation, grid_scale);
1303
1304	LLVector3 axis1;
1305	LLVector3 axis2;
1306
1307	LLVector3 test_axis = constraint_axis;
1308	if (mObjectSelection->getSelectType() == SELECT_TYPE_ATTACHMENT && isAgentAvatarValid())
1309	{
1310		test_axis = test_axis * ~grid_rotation;
1311	}
1312	else if (LLSelectMgr::getInstance()->getGridMode() == GRID_MODE_REF_OBJECT)
1313	{
1314		test_axis = test_axis * ~grid_rotation;
1315	}
1316	test_axis.abs();
1317
1318	// find closest global axis to constraint axis;
1319	if (test_axis.mV[VX] > test_axis.mV[VY] && test_axis.mV[VX] > test_axis.mV[VZ])
1320	{
1321		axis1 = LLVector3::y_axis;
1322	}
1323	else if (test_axis.mV[VY] > test_axis.mV[VZ])
1324	{
1325		axis1 = LLVector3::z_axis;
1326	}
1327	else
1328	{
1329		axis1 = LLVector3::x_axis;
1330	}
1331
1332	if (mObjectSelection->getSelectType() == SELECT_TYPE_ATTACHMENT && isAgentAvatarValid())
1333	{
1334		axis1 = axis1 * grid_rotation;
1335	}
1336	else if (LLSelectMgr::getInstance()->getGridMode() == GRID_MODE_REF_OBJECT)
1337	{
1338		axis1 = axis1 * grid_rotation;
1339	}
1340
1341	//project axis onto constraint plane
1342	axis1 -= (axis1 * constraint_axis) * constraint_axis;
1343	axis1.normVec();
1344
1345	// calculate third and final axis
1346	axis2 = constraint_axis % axis1;
1347
1348	//F32 axis_onto_cam = llabs( constraint_axis * mCenterToCamNorm );
1349	if( mCamEdgeOn )
1350	{
1351		// We're looking at the ring edge-on.
1352		LLVector3 snap_plane_center = (center + (constraint_axis * mRadiusMeters * 0.5f));
1353		LLVector3 cam_to_snap_plane;
1354		if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD)
1355		{
1356			cam_to_snap_plane.setVec(1.f, 0.f, 0.f);
1357		}
1358		else
1359		{
1360			cam_to_snap_plane = snap_plane_center - gAgentCamera.getCameraPositionAgent();
1361			cam_to_snap_plane.normVec();
1362		}
1363
1364		LLVector3 projected_mouse;
1365		BOOL hit = getMousePointOnPlaneAgent(projected_mouse, x, y, snap_plane_center, constraint_axis);
1366		projected_mouse -= snap_plane_center;
1367
1368		S32 snap_plane = 0;
1369
1370		F32 dot = cam_to_snap_plane * constraint_axis;
1371		if (llabs(dot) < 0.01f)
1372		{
1373			// looking at ring edge on, project onto view plane and check if mouse is past ring
1374			getMousePointOnPlaneAgent(projected_mouse, x, y, snap_plane_center, cam_to_snap_plane);
1375			projected_mouse -= snap_plane_center;
1376			dot = projected_mouse * constraint_axis;
1377			if (projected_mouse * constraint_axis > 0)
1378			{
1379				snap_plane = 1;
1380			}
1381			projected_mouse -= dot * constraint_axis;
1382		}
1383		else if (dot > 0.f)
1384		{
1385			// look for mouse position outside and in front of snap circle
1386			if (hit && projected_mouse.magVec() > SNAP_GUIDE_INNER_RADIUS * mRadiusMeters && projected_mouse * cam_to_snap_plane < 0.f)
1387			{
1388				snap_plane = 1;
1389			}
1390		}
1391		else
1392		{
1393			// look for mouse position inside or in back of snap circle
1394			if (projected_mouse.magVec() < SNAP_GUIDE_INNER_RADIUS * mRadiusMeters || projected_mouse * cam_to_snap_plane > 0.f || !hit)
1395			{
1396				snap_plane = 1;
1397			}
1398		}
1399
1400		if (snap_plane == 0)
1401		{
1402			// try other plane
1403			snap_plane_center = (center - (constraint_axis * mRadiusMeters * 0.5f));
1404			if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD)
1405			{
1406				cam_to_snap_plane.setVec(1.f, 0.f, 0.f);
1407			}
1408			else
1409			{
1410				cam_to_snap_plane = snap_plane_center - gAgentCamera.getCameraPositionAgent();
1411				cam_to_snap_plane.normVec();
1412			}
1413
1414			hit = getMousePointOnPlaneAgent(projected_mouse, x, y, snap_plane_center, constraint_axis);
1415			projected_mouse -= snap_plane_center;
1416
1417			dot = cam_to_snap_plane * constraint_axis;
1418			if (llabs(dot) < 0.01f)
1419			{
1420				// looking at ring edge on, project onto view plane and check if mouse is past ring
1421				getMousePointOnPlaneAgent(projected_mouse, x, y, snap_plane_center, cam_to_snap_plane);
1422				projected_mouse -= snap_plane_center;
1423				dot = projected_mouse * constraint_axis;
1424				if (projected_mouse * constraint_axis < 0)
1425				{
1426					snap_plane = 2;
1427				}
1428				projected_mouse -= dot * constraint_axis;
1429			}
1430			else if (dot < 0.f)
1431			{
1432				// look for mouse position outside and in front of snap circle
1433				if (hit && projected_mouse.magVec() > SNAP_GUIDE_INNER_RADIUS * mRadiusMeters && projected_mouse * cam_to_snap_plane < 0.f)
1434				{
1435					snap_plane = 2;
1436				}
1437			}
1438			else
1439			{
1440				// look for mouse position inside or in back of snap circle
1441				if (projected_mouse.magVec() < SNAP_GUIDE_INNER_RADIUS * mRadiusMeters || projected_mouse * cam_to_snap_plane > 0.f || !hit)
1442				{
1443					snap_plane = 2;
1444				}
1445			}
1446		}
1447
1448		if (snap_plane > 0)
1449		{
1450			LLVector3 cam_at_axis;
1451			if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD)
1452			{
1453				cam_at_axis.setVec(1.f, 0.f, 0.f);
1454			}
1455			else
1456			{
1457				cam_at_axis = snap_plane_center - gAgentCamera.getCameraPositionAgent();
1458				cam_at_axis.normVec();
1459			}
1460
1461			// first, project mouse onto screen plane at point tangent to rotation radius. 
1462			getMousePointOnPlaneAgent(projected_mouse, x, y, snap_plane_center, cam_at_axis);
1463			// project that point onto rotation plane
1464			projected_mouse -= snap_plane_center;
1465			projected_mouse -= projected_vec(projected_mouse, constraint_axis);
1466
1467			F32 mouse_lateral_dist = llmin(SNAP_GUIDE_INNER_RADIUS * mRadiusMeters, projected_mouse.magVec());
1468			F32 mouse_depth = SNAP_GUIDE_INNER_RADIUS * mRadiusMeters;
1469			if (llabs(mouse_lateral_dist) > 0.01f)
1470			{
1471				mouse_depth = sqrtf((SNAP_GUIDE_INNER_RADIUS * mRadiusMeters) * (SNAP_GUIDE_INNER_RADIUS * mRadiusMeters) - 
1472									(mouse_lateral_dist * mouse_lateral_dist));
1473			}
1474			LLVector3 projected_camera_at = cam_at_axis - projected_vec(cam_at_axis, constraint_axis);
1475			projected_mouse -= mouse_depth * projected_camera_at;
1476
1477			if (!mInSnapRegime)
1478			{
1479				mSmoothRotate = TRUE;
1480			}
1481			mInSnapRegime = TRUE;
1482			// 0 to 360 deg
1483			F32 mouse_angle = fmodf(atan2(projected_mouse * axis1, projected_mouse * axis2) * RAD_TO_DEG + 360.f, 360.f);
1484			
1485			F32 relative_mouse_angle = fmodf(mouse_angle + (SNAP_ANGLE_DETENTE / 2), SNAP_ANGLE_INCREMENT);
1486			//fmodf(llround(mouse_angle * RAD_TO_DEG, 7.5f) + 360.f, 360.f);
1487
1488			LLVector3 object_axis;
1489			getObjectAxisClosestToMouse(object_axis);
1490			object_axis = object_axis * first_object_node->mSavedRotation;
1491
1492			// project onto constraint plane
1493			object_axis = object_axis - (object_axis * getConstraintAxis()) * getConstraintAxis();
1494			object_axis.normVec();
1495
1496			if (relative_mouse_angle < SNAP_ANGLE_DETENTE)
1497			{
1498				F32 quantized_mouse_angle = mouse_angle - (relative_mouse_angle - (SNAP_ANGLE_DETENTE * 0.5f));
1499				angle = (quantized_mouse_angle * DEG_TO_RAD) - atan2(object_axis * axis1, object_axis * axis2);
1500			}
1501			else
1502			{
1503				angle = (mouse_angle * DEG_TO_RAD) - atan2(object_axis * axis1, object_axis * axis2);
1504			}
1505			return LLQuaternion( -angle, constraint_axis );
1506		}
1507		else
1508		{
1509			if (mInSnapRegime)
1510			{
1511				mSmoothRotate = TRUE;
1512			}
1513			mInSnapRegime = FALSE;
1514
1515			LLVector3 up_from_axis = mCenterToCamNorm % constraint_axis;
1516			up_from_axis.normVec();
1517			LLVector3 cur_intersection;
1518			getMousePointOnPlaneAgent(cur_intersection, x, y, center, mCenterToCam);
1519			cur_intersection -= center;
1520			mMouseCur = projected_vec(cur_intersection, up_from_axis);
1521			F32 mouse_depth = SNAP_GUIDE_INNER_RADIUS * mRadiusMeters;
1522			F32 mouse_dist_sqrd = mMouseCur.magVecSquared();
1523			if (mouse_dist_sqrd > 0.0001f)
1524			{
1525				mouse_depth = sqrtf((SNAP_GUIDE_INNER_RADIUS * mRadiusMeters) * (SNAP_GUIDE_INNER_RADIUS * mRadiusMeters) - 
1526									mouse_dist_sqrd);
1527			}
1528			LLVector3 projected_center_to_cam = mCenterToCamNorm - projected_vec(mCenterToCamNorm, constraint_axis);
1529			mMouseCur += mouse_depth * projected_center_to_cam;
1530
1531			F32 dist = (cur_intersection * up_from_axis) - (mMouseDown * up_from_axis);
1532			angle = dist / (SNAP_GUIDE_INNER_RADIUS * mRadiusMeters) * -F_PI_BY_TWO;
1533		}
1534	}
1535	else
1536	{
1537		LLVector3 projected_mouse;
1538		getMousePointOnPlaneAgent(projected_mouse, x, y, center, constraint_axis);
1539		projected_mouse -= center;
1540		mMouseCur = projected_mouse;
1541		mMouseCur.normVec();
1542
1543		if (!first_object_node)
1544		{
1545			return LLQuaternion::DEFAULT;
1546		}
1547
1548		if (gSavedSettings.getBOOL("SnapEnabled") && projected_mouse.magVec() > SNAP_GUIDE_INNER_RADIUS * mRadiusMeters)
1549		{
1550			if (!mInSnapRegime)
1551			{
1552				mSmoothRotate = TRUE;
1553			}
1554			mInSnapRegime = TRUE;
1555			// 0 to 360 deg
1556			F32 mouse_angle = fmodf(atan2(projected_mouse * axis1, projected_mouse * axis2) * RAD_TO_DEG + 360.f, 360.f);
1557			
1558			F32 relative_mouse_angle = fmodf(mouse_angle + (SNAP_ANGLE_DETENTE / 2), SNAP_ANGLE_INCREMENT);
1559			//fmodf(llround(mouse_angle * RAD_TO_DEG, 7.5f) + 360.f, 360.f);
1560
1561			LLVector3 object_axis;
1562			getObjectAxisClosestToMouse(object_axis);
1563			object_axis = object_axis * first_object_node->mSavedRotation;
1564
1565			// project onto constraint plane
1566			object_axis = object_axis - (object_axis * getConstraintAxis()) * getConstraintAxis();
1567			object_axis.normVec();
1568
1569			if (relative_mouse_angle < SNAP_ANGLE_DETENTE)
1570			{
1571				F32 quantized_mouse_angle = mouse_angle - (relative_mouse_angle - (SNAP_ANGLE_DETENTE * 0.5f));
1572				angle = (quantized_mouse_angle * DEG_TO_RAD) - atan2(object_axis * axis1, object_axis * axis2);
1573			}
1574			else
1575			{
1576				angle = (mouse_angle * DEG_TO_RAD) - atan2(object_axis * axis1, object_axis * axis2);
1577			}
1578			return LLQuaternion( -angle, constraint_axis );
1579		}
1580		else
1581		{
1582			if (mInSnapRegime)
1583			{
1584				mSmoothRotate = TRUE;
1585			}
1586			mInSnapRegime = FALSE;
1587		}
1588
1589		angle = acos(mMouseCur * mMouseDown);
1590
1591		F32 dir = (mMouseDown % mMouseCur) * constraint_axis;  // cross product
1592		if( dir < 0.f )
1593		{
1594			angle *= -1.f;
1595		}
1596	}
1597
1598	F32 rot_step = gSavedSettings.getF32("RotationStep");
1599	F32 

Large files files are truncated, but you can click here to view the full file