PageRenderTime 2602ms CodeModel.GetById 152ms app.highlight 2237ms RepoModel.GetById 194ms app.codeStats 1ms

/indra/newview/llmanipscale.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 1992 lines | 1552 code | 294 blank | 146 comment | 228 complexity | 4a8a49e51625eb90f3fb80d1d0a9a72b MD5 | raw file

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

   1/** 
   2 * @file llmanipscale.cpp
   3 * @brief LLManipScale class implementation
   4 *
   5 * $LicenseInfo:firstyear=2001&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 "llmanipscale.h"
  30
  31// library includes
  32#include "llmath.h"
  33#include "v3math.h"
  34#include "llquaternion.h"
  35#include "llgl.h"
  36#include "llrender.h"
  37#include "v4color.h"
  38#include "llprimitive.h"
  39
  40// viewer includes
  41#include "llagent.h"
  42#include "llagentcamera.h"
  43#include "llbbox.h"
  44#include "llbox.h"
  45#include "llviewercontrol.h"
  46#include "llcriticaldamp.h"
  47#include "lldrawable.h"
  48#include "llfloatertools.h"
  49#include "llglheaders.h"
  50#include "llselectmgr.h"
  51#include "llstatusbar.h"
  52#include "llui.h"
  53#include "llviewercamera.h"
  54#include "llviewerobject.h"
  55#include "llviewerregion.h"
  56#include "llviewerwindow.h"
  57#include "llhudrender.h"
  58#include "llworld.h"
  59#include "v2math.h"
  60#include "llvoavatar.h"
  61#include "llmeshrepository.h"
  62
  63
  64const F32 MAX_MANIP_SELECT_DISTANCE_SQUARED = 11.f * 11.f;
  65const F32 SNAP_GUIDE_SCREEN_OFFSET = 0.05f;
  66const F32 SNAP_GUIDE_SCREEN_LENGTH = 0.7f;
  67const F32 SELECTED_MANIPULATOR_SCALE = 1.2f;
  68const F32 MANIPULATOR_SCALE_HALF_LIFE = 0.07f;
  69const S32 NUM_MANIPULATORS = 14;
  70
  71const LLManip::EManipPart MANIPULATOR_IDS[NUM_MANIPULATORS] = 
  72{
  73	LLManip::LL_CORNER_NNN,
  74	LLManip::LL_CORNER_NNP,
  75	LLManip::LL_CORNER_NPN,
  76	LLManip::LL_CORNER_NPP,
  77	LLManip::LL_CORNER_PNN,
  78	LLManip::LL_CORNER_PNP,
  79	LLManip::LL_CORNER_PPN,
  80	LLManip::LL_CORNER_PPP,
  81	LLManip::LL_FACE_POSZ,
  82	LLManip::LL_FACE_POSX,
  83	LLManip::LL_FACE_POSY,
  84	LLManip::LL_FACE_NEGX,
  85	LLManip::LL_FACE_NEGY,
  86	LLManip::LL_FACE_NEGZ
  87};
  88
  89
  90F32 get_default_max_prim_scale(bool is_flora) 
  91{
  92	// a bit of a hack, but if it's foilage, we don't want to use the
  93	// new larger scale which would result in giant trees and grass
  94	if (gMeshRepo.meshRezEnabled() &&
  95		!is_flora)
  96	{
  97		return DEFAULT_MAX_PRIM_SCALE;
  98	}
  99	else
 100	{	
 101		return DEFAULT_MAX_PRIM_SCALE_NO_MESH;
 102	}
 103}
 104
 105// static
 106void LLManipScale::setUniform(BOOL b)
 107{
 108	gSavedSettings.setBOOL("ScaleUniform", b);
 109}
 110
 111// static
 112void LLManipScale::setShowAxes(BOOL b)
 113{
 114	gSavedSettings.setBOOL("ScaleShowAxes", b);
 115}
 116
 117// static
 118void LLManipScale::setStretchTextures(BOOL b)
 119{
 120	gSavedSettings.setBOOL("ScaleStretchTextures", b);
 121}
 122
 123// static
 124BOOL LLManipScale::getUniform()
 125{
 126	return gSavedSettings.getBOOL("ScaleUniform");
 127}
 128
 129// static
 130BOOL LLManipScale::getShowAxes()
 131{
 132	return gSavedSettings.getBOOL("ScaleShowAxes");
 133}
 134
 135// static
 136BOOL LLManipScale::getStretchTextures()
 137{
 138	return gSavedSettings.getBOOL("ScaleStretchTextures");
 139}
 140
 141inline void LLManipScale::conditionalHighlight( U32 part, const LLColor4* highlight, const LLColor4* normal )
 142{
 143	LLColor4 default_highlight( 1.f, 1.f, 1.f, 1.f );
 144	LLColor4 default_normal( 0.7f, 0.7f, 0.7f, 0.6f );
 145	LLColor4 invisible(0.f, 0.f, 0.f, 0.f);
 146	F32 manipulator_scale = 1.f;
 147
 148	for (S32 i = 0; i < NUM_MANIPULATORS; i++)
 149	{
 150		if((U32)MANIPULATOR_IDS[i] == part)
 151		{
 152			manipulator_scale = mManipulatorScales[i];
 153			break;
 154		}
 155	}
 156
 157	mScaledBoxHandleSize = mBoxHandleSize * manipulator_scale;
 158	if (mManipPart != (S32)LL_NO_PART && mManipPart != (S32)part)
 159	{
 160		gGL.color4fv( invisible.mV );
 161	}
 162	else if( mHighlightedPart == (S32)part )
 163	{
 164		gGL.color4fv( highlight ? highlight->mV : default_highlight.mV );
 165	}
 166	else
 167	{
 168		gGL.color4fv( normal ? normal->mV : default_normal.mV  );
 169	}
 170}
 171
 172void LLManipScale::handleSelect()
 173{
 174	LLBBox bbox = LLSelectMgr::getInstance()->getBBoxOfSelection();
 175	updateSnapGuides(bbox);
 176	LLSelectMgr::getInstance()->saveSelectedObjectTransform(SELECT_ACTION_TYPE_PICK);
 177	gFloaterTools->setStatusText("scale");
 178	LLManip::handleSelect();
 179}
 180
 181LLManipScale::LLManipScale( LLToolComposite* composite )
 182	: 
 183	LLManip( std::string("Scale"), composite ),
 184	mBoxHandleSize( 1.f ),
 185	mScaledBoxHandleSize( 1.f ),
 186	mLastMouseX( -1 ),
 187	mLastMouseY( -1 ),
 188	mSendUpdateOnMouseUp( FALSE ),
 189	mLastUpdateFlags( 0 ),
 190	mScaleSnapUnit1(1.f),
 191	mScaleSnapUnit2(1.f),
 192	mSnapRegimeOffset(0.f),
 193	mSnapGuideLength(0.f),
 194	mInSnapRegime(FALSE),
 195	mScaleSnapValue(0.f)
 196{ 
 197	mManipulatorScales = new F32[NUM_MANIPULATORS];
 198	for (S32 i = 0; i < NUM_MANIPULATORS; i++)
 199	{
 200		mManipulatorScales[i] = 1.f;
 201	}
 202}
 203
 204LLManipScale::~LLManipScale()
 205{
 206	for_each(mProjectedManipulators.begin(), mProjectedManipulators.end(), DeletePointer());
 207	delete[] mManipulatorScales;
 208}
 209
 210void LLManipScale::render()
 211{
 212	LLGLSUIDefault gls_ui;
 213	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 214	LLGLDepthTest gls_depth(GL_TRUE);
 215	LLGLEnable gl_blend(GL_BLEND);
 216	LLGLEnable gls_alpha_test(GL_ALPHA_TEST);
 217	
 218	if( canAffectSelection() )
 219	{
 220		gGL.matrixMode(LLRender::MM_MODELVIEW);
 221		gGL.pushMatrix();
 222		if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD)
 223		{
 224			F32 zoom = gAgentCamera.mHUDCurZoom;
 225			gGL.scalef(zoom, zoom, zoom);
 226		}
 227
 228		////////////////////////////////////////////////////////////////////////
 229		// Calculate size of drag handles 	
 230
 231		const F32 BOX_HANDLE_BASE_SIZE		= 50.0f;   // box size in pixels = BOX_HANDLE_BASE_SIZE * BOX_HANDLE_BASE_FACTOR
 232		const F32 BOX_HANDLE_BASE_FACTOR	= 0.2f;
 233		
 234		LLVector3 center_agent = gAgent.getPosAgentFromGlobal(LLSelectMgr::getInstance()->getSelectionCenterGlobal());
 235
 236		if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD)
 237		{
 238			mBoxHandleSize = BOX_HANDLE_BASE_SIZE * BOX_HANDLE_BASE_FACTOR / (F32) LLViewerCamera::getInstance()->getViewHeightInPixels();
 239			mBoxHandleSize /= gAgentCamera.mHUDCurZoom;
 240		}
 241		else
 242		{
 243			F32 range_squared = dist_vec_squared(gAgentCamera.getCameraPositionAgent(), center_agent);
 244			F32 range_from_agent_squared = dist_vec_squared(gAgent.getPositionAgent(), center_agent);
 245
 246			// Don't draw manip if object too far away
 247			if (gSavedSettings.getBOOL("LimitSelectDistance"))
 248			{
 249				F32 max_select_distance = gSavedSettings.getF32("MaxSelectDistance");
 250				if (range_from_agent_squared > max_select_distance * max_select_distance)
 251				{
 252					return;
 253				}
 254			}
 255
 256			if (range_squared > 0.001f * 0.001f)
 257			{
 258				// range != zero
 259				F32 fraction_of_fov = BOX_HANDLE_BASE_SIZE / (F32) LLViewerCamera::getInstance()->getViewHeightInPixels();
 260				F32 apparent_angle = fraction_of_fov * LLViewerCamera::getInstance()->getView();  // radians
 261				mBoxHandleSize = (F32) sqrtf(range_squared) * tan(apparent_angle) * BOX_HANDLE_BASE_FACTOR;
 262			}
 263			else
 264			{
 265				// range == zero
 266				mBoxHandleSize = BOX_HANDLE_BASE_FACTOR;
 267			}
 268		}
 269
 270		////////////////////////////////////////////////////////////////////////
 271		// Draw bounding box
 272
 273		LLBBox bbox = LLSelectMgr::getInstance()->getBBoxOfSelection();
 274		LLVector3 pos_agent = bbox.getPositionAgent();
 275		LLQuaternion rot = bbox.getRotation();
 276
 277		gGL.matrixMode(LLRender::MM_MODELVIEW);
 278		gGL.pushMatrix();
 279		{
 280			gGL.translatef(pos_agent.mV[VX], pos_agent.mV[VY], pos_agent.mV[VZ]);
 281
 282			F32 angle_radians, x, y, z;
 283			rot.getAngleAxis(&angle_radians, &x, &y, &z);
 284			gGL.rotatef(angle_radians * RAD_TO_DEG, x, y, z);
 285
 286			
 287			{
 288				LLGLEnable poly_offset(GL_POLYGON_OFFSET_FILL);
 289				glPolygonOffset( -2.f, -2.f);
 290
 291				// JC - Band-aid until edge stretch working similar to side stretch
 292				// in non-uniform.
 293				// renderEdges( bbox );
 294
 295				renderCorners( bbox );
 296				renderFaces( bbox );
 297
 298				if (mManipPart != LL_NO_PART)
 299				{
 300					renderGuidelinesPart( bbox );
 301				}
 302
 303				glPolygonOffset( 0.f, 0.f);
 304			}
 305		}
 306		gGL.popMatrix();
 307
 308		if (mManipPart != LL_NO_PART)
 309		{
 310			renderSnapGuides(bbox);
 311		}
 312		gGL.popMatrix();
 313
 314		renderXYZ(bbox.getExtentLocal());
 315	}
 316}
 317
 318BOOL LLManipScale::handleMouseDown(S32 x, S32 y, MASK mask)
 319{
 320	BOOL	handled = FALSE;
 321
 322	if(mHighlightedPart != LL_NO_PART)
 323	{
 324		handled = handleMouseDownOnPart( x, y, mask );
 325	}
 326
 327	return handled;
 328}
 329
 330// Assumes that one of the arrows on an object was hit.
 331BOOL LLManipScale::handleMouseDownOnPart( S32 x, S32 y, MASK mask )
 332{
 333	BOOL can_scale = canAffectSelection();
 334	if (!can_scale)
 335	{
 336		return FALSE;
 337	}
 338
 339	highlightManipulators(x, y);
 340	S32 hit_part = mHighlightedPart;
 341
 342	LLSelectMgr::getInstance()->enableSilhouette(FALSE);
 343	mManipPart = (EManipPart)hit_part;
 344
 345	LLBBox bbox = LLSelectMgr::getInstance()->getBBoxOfSelection();
 346	LLVector3 box_center_agent = bbox.getCenterAgent();
 347	LLVector3 box_corner_agent = bbox.localToAgent( unitVectorToLocalBBoxExtent( partToUnitVector( mManipPart ), bbox ) );
 348	
 349	updateSnapGuides(bbox);
 350
 351	mDragStartPointGlobal = gAgent.getPosGlobalFromAgent(box_corner_agent);
 352	mDragStartCenterGlobal = gAgent.getPosGlobalFromAgent(box_center_agent);
 353	LLVector3 far_corner_agent = bbox.localToAgent( unitVectorToLocalBBoxExtent( -1.f * partToUnitVector( mManipPart ), bbox ) );
 354	mDragFarHitGlobal = gAgent.getPosGlobalFromAgent(far_corner_agent);
 355	mDragPointGlobal = mDragStartPointGlobal;
 356
 357	// we just started a drag, so save initial object positions, orientations, and scales
 358	LLSelectMgr::getInstance()->saveSelectedObjectTransform(SELECT_ACTION_TYPE_SCALE);
 359	// Route future Mouse messages here preemptively.  (Release on mouse up.)
 360	setMouseCapture( TRUE );
 361
 362	mHelpTextTimer.reset();
 363	sNumTimesHelpTextShown++;
 364	return TRUE;
 365}
 366
 367
 368BOOL LLManipScale::handleMouseUp(S32 x, S32 y, MASK mask)
 369{
 370	// first, perform normal processing in case this was a quick-click
 371	handleHover(x, y, mask);
 372
 373	if( hasMouseCapture() )
 374	{
 375		if( (LL_FACE_MIN <= (S32)mManipPart) 
 376			&& ((S32)mManipPart <= LL_FACE_MAX) )
 377		{
 378			sendUpdates(TRUE,TRUE,FALSE);
 379		}
 380		else
 381		if( (LL_CORNER_MIN <= (S32)mManipPart) 
 382			&& ((S32)mManipPart <= LL_CORNER_MAX) )
 383		{
 384			sendUpdates(TRUE,TRUE,TRUE);
 385		}
 386		
 387		//send texture update
 388		LLSelectMgr::getInstance()->adjustTexturesByScale(TRUE, getStretchTextures());
 389		
 390		LLSelectMgr::getInstance()->enableSilhouette(TRUE);
 391		mManipPart = LL_NO_PART;
 392
 393		// Might have missed last update due to UPDATE_DELAY timing
 394		LLSelectMgr::getInstance()->sendMultipleUpdate( mLastUpdateFlags );
 395		
 396		//gAgent.setObjectTracking(gSavedSettings.getBOOL("TrackFocusObject"));
 397		LLSelectMgr::getInstance()->saveSelectedObjectTransform(SELECT_ACTION_TYPE_PICK);
 398	}
 399	return LLManip::handleMouseUp(x, y, mask);
 400}
 401
 402
 403BOOL LLManipScale::handleHover(S32 x, S32 y, MASK mask)
 404{
 405	if( hasMouseCapture() )
 406	{
 407		if( mObjectSelection->isEmpty() )
 408		{
 409			// Somehow the object got deselected while we were dragging it.
 410			setMouseCapture( FALSE );
 411		}
 412		else
 413		{
 414			drag( x, y );
 415		}
 416		lldebugst(LLERR_USER_INPUT) << "hover handled by LLManipScale (active)" << llendl;		
 417	}
 418	else
 419	{
 420		mInSnapRegime = FALSE;
 421		// not dragging...
 422		highlightManipulators(x, y);
 423	}
 424	
 425	// Patch up textures, if possible.
 426	LLSelectMgr::getInstance()->adjustTexturesByScale(FALSE, getStretchTextures());
 427
 428	gViewerWindow->setCursor(UI_CURSOR_TOOLSCALE);
 429	return TRUE;
 430}
 431
 432void LLManipScale::highlightManipulators(S32 x, S32 y)
 433{
 434	mHighlightedPart = LL_NO_PART;
 435
 436	// If we have something selected, try to hit its manipulator handles.
 437	// Don't do this with nothing selected, as it kills the framerate.
 438	LLBBox bbox = LLSelectMgr::getInstance()->getBBoxOfSelection();
 439
 440	if( canAffectSelection() )
 441	{
 442		LLMatrix4 transform;
 443		if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD)
 444		{
 445			LLVector4 translation(bbox.getPositionAgent());
 446			transform.initRotTrans(bbox.getRotation(), translation);
 447			LLMatrix4 cfr(OGL_TO_CFR_ROTATION);
 448			transform *= cfr;
 449			LLMatrix4 window_scale;
 450			F32 zoom_level = 2.f * gAgentCamera.mHUDCurZoom;
 451			window_scale.initAll(LLVector3(zoom_level / LLViewerCamera::getInstance()->getAspect(), zoom_level, 0.f),
 452				LLQuaternion::DEFAULT,
 453				LLVector3::zero);
 454			transform *= window_scale;
 455		}
 456		else
 457		{
 458			LLMatrix4 projMatrix = LLViewerCamera::getInstance()->getProjection();
 459			LLMatrix4 modelView = LLViewerCamera::getInstance()->getModelview();
 460			transform.initAll(LLVector3(1.f, 1.f, 1.f), bbox.getRotation(), bbox.getPositionAgent());
 461			
 462			transform *= modelView;
 463			transform *= projMatrix;
 464		}
 465
 466		LLVector3 min = bbox.getMinLocal();
 467		LLVector3 max = bbox.getMaxLocal();
 468		LLVector3 ctr = bbox.getCenterLocal();
 469
 470		S32 numManips = 0;
 471		// corners
 472		mManipulatorVertices[numManips++] = LLVector4(min.mV[VX], min.mV[VY], min.mV[VZ], 1.f);
 473		mManipulatorVertices[numManips++] = LLVector4(min.mV[VX], min.mV[VY], max.mV[VZ], 1.f);
 474		mManipulatorVertices[numManips++] = LLVector4(min.mV[VX], max.mV[VY], min.mV[VZ], 1.f);
 475		mManipulatorVertices[numManips++] = LLVector4(min.mV[VX], max.mV[VY], max.mV[VZ], 1.f);
 476		mManipulatorVertices[numManips++] = LLVector4(max.mV[VX], min.mV[VY], min.mV[VZ], 1.f);
 477		mManipulatorVertices[numManips++] = LLVector4(max.mV[VX], min.mV[VY], max.mV[VZ], 1.f);
 478		mManipulatorVertices[numManips++] = LLVector4(max.mV[VX], max.mV[VY], min.mV[VZ], 1.f);
 479		mManipulatorVertices[numManips++] = LLVector4(max.mV[VX], max.mV[VY], max.mV[VZ], 1.f);
 480		
 481		// 1-D highlights are applicable iff one object is selected
 482		if( mObjectSelection->getObjectCount() == 1 )
 483		{
 484			// face centers
 485			mManipulatorVertices[numManips++] = LLVector4(ctr.mV[VX], ctr.mV[VY], max.mV[VZ], 1.f);
 486			mManipulatorVertices[numManips++] = LLVector4(max.mV[VX], ctr.mV[VY], ctr.mV[VZ], 1.f);
 487			mManipulatorVertices[numManips++] = LLVector4(ctr.mV[VX], max.mV[VY], ctr.mV[VZ], 1.f);
 488			mManipulatorVertices[numManips++] = LLVector4(min.mV[VX], ctr.mV[VY], ctr.mV[VZ], 1.f);
 489			mManipulatorVertices[numManips++] = LLVector4(ctr.mV[VX], min.mV[VY], ctr.mV[VZ], 1.f);
 490			mManipulatorVertices[numManips++] = LLVector4(ctr.mV[VX], ctr.mV[VY], min.mV[VZ], 1.f);
 491		}
 492
 493		for_each(mProjectedManipulators.begin(), mProjectedManipulators.end(), DeletePointer());
 494		mProjectedManipulators.clear();
 495		
 496		for (S32 i = 0; i < numManips; i++)
 497		{
 498			LLVector4 projectedVertex = mManipulatorVertices[i] * transform;
 499			projectedVertex = projectedVertex * (1.f / projectedVertex.mV[VW]);
 500
 501			ManipulatorHandle* projManipulator = new ManipulatorHandle(LLVector3(projectedVertex.mV[VX], projectedVertex.mV[VY], 
 502				projectedVertex.mV[VZ]), MANIPULATOR_IDS[i], (i < 7) ? SCALE_MANIP_CORNER : SCALE_MANIP_FACE);
 503			mProjectedManipulators.insert(projManipulator);
 504		}
 505
 506		LLRect world_view_rect = gViewerWindow->getWorldViewRectScaled();
 507		F32 half_width = (F32)world_view_rect.getWidth() / 2.f;
 508		F32 half_height = (F32)world_view_rect.getHeight() / 2.f;
 509		LLVector2 manip2d;
 510		LLVector2 mousePos((F32)x - half_width, (F32)y - half_height);
 511		LLVector2 delta;
 512
 513		mHighlightedPart = LL_NO_PART;
 514
 515		for (minpulator_list_t::iterator iter = mProjectedManipulators.begin();
 516			 iter != mProjectedManipulators.end(); ++iter)
 517		{
 518			ManipulatorHandle* manipulator = *iter;
 519			{
 520				manip2d.setVec(manipulator->mPosition.mV[VX] * half_width, manipulator->mPosition.mV[VY] * half_height);
 521				
 522				delta = manip2d - mousePos;
 523				if (delta.magVecSquared() < MAX_MANIP_SELECT_DISTANCE_SQUARED)
 524				{
 525					mHighlightedPart = manipulator->mManipID;
 526
 527					//llinfos << "Tried: " << mHighlightedPart << llendl;
 528					break;
 529				}
 530			}
 531		}
 532	}
 533
 534	for (S32 i = 0; i < NUM_MANIPULATORS; i++)
 535	{
 536		if (mHighlightedPart == MANIPULATOR_IDS[i])
 537		{
 538			mManipulatorScales[i] = lerp(mManipulatorScales[i], SELECTED_MANIPULATOR_SCALE, LLCriticalDamp::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE));
 539		}
 540		else
 541		{
 542			mManipulatorScales[i] = lerp(mManipulatorScales[i], 1.f, LLCriticalDamp::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE));
 543		}
 544	}
 545
 546	lldebugst(LLERR_USER_INPUT) << "hover handled by LLManipScale (inactive)" << llendl;
 547}
 548
 549
 550void LLManipScale::renderFaces( const LLBBox& bbox )
 551{
 552	// Don't bother to render the drag handles for 1-D scaling if 
 553	// more than one object is selected or if it is an attachment
 554	if ( mObjectSelection->getObjectCount() > 1 )
 555	{
 556		return;
 557	}
 558
 559    // This is a flattened representation of the box as render here
 560    //                                       .
 561    //              (+++)        (++-)      /|\t
 562    //                +------------+         | (texture coordinates)
 563    //                |            |         |
 564    //                |     1      |        (*) --->s
 565    //                |    +X      |   
 566	//                |            |
 567    // (+++)     (+-+)|            |(+--)     (++-)        (+++)
 568    //   +------------+------------+------------+------------+
 569    //   |0          3|3          7|7          4|4          0|
 570    //   |     0      |     4      |     5      |     2	     |
 571    //   |    +Z      |    -Y      |    -Z      |    +Y      |
 572    //   |	          |            |            |            |
 573    //   |1          2|2          6|6          5|5          1|
 574    //   +------------+------------+------------+------------+
 575    // (-++)     (--+)|            |(---)     (-+-)        (-++)
 576    //                |     3      |
 577    //                |    -X      |
 578    //                |            |
 579    //                |            |
 580    //                +------------+
 581    //              (-++)        (-+-)
 582
 583	LLColor4 highlight_color( 1.f, 1.f, 1.f, 0.5f);
 584	LLColor4 normal_color(	1.f, 1.f, 1.f, 0.3f);
 585
 586	LLColor4 x_highlight_color( 1.f, 0.2f, 0.2f, 1.0f);
 587	LLColor4 x_normal_color(	0.6f, 0.f, 0.f, 0.4f);
 588
 589	LLColor4 y_highlight_color( 0.2f, 1.f, 0.2f, 1.0f);
 590	LLColor4 y_normal_color(	0.f, 0.6f, 0.f, 0.4f);
 591
 592	LLColor4 z_highlight_color( 0.2f, 0.2f, 1.f, 1.0f);
 593	LLColor4 z_normal_color(	0.f, 0.f, 0.6f, 0.4f);
 594
 595	LLColor4 default_normal_color( 0.7f, 0.7f, 0.7f, 0.15f );
 596
 597	const LLVector3& min = bbox.getMinLocal();
 598	const LLVector3& max = bbox.getMaxLocal();
 599	LLVector3 ctr = bbox.getCenterLocal();
 600
 601	if (mManipPart == LL_NO_PART)
 602	{
 603		gGL.color4fv( default_normal_color.mV );
 604		LLGLDepthTest gls_depth(GL_FALSE);
 605		gGL.begin(LLRender::QUADS); 
 606		{
 607			// Face 0
 608			gGL.vertex3f(min.mV[VX], max.mV[VY], max.mV[VZ]);
 609			gGL.vertex3f(min.mV[VX], min.mV[VY], max.mV[VZ]);
 610			gGL.vertex3f(max.mV[VX], min.mV[VY], max.mV[VZ]);
 611			gGL.vertex3f(max.mV[VX], max.mV[VY], max.mV[VZ]);
 612
 613			// Face 1
 614			gGL.vertex3f(max.mV[VX], min.mV[VY], max.mV[VZ]);
 615			gGL.vertex3f(max.mV[VX], min.mV[VY], min.mV[VZ]);
 616			gGL.vertex3f(max.mV[VX], max.mV[VY], min.mV[VZ]);
 617			gGL.vertex3f(max.mV[VX], max.mV[VY], max.mV[VZ]);
 618
 619			// Face 2
 620			gGL.vertex3f(min.mV[VX], max.mV[VY], min.mV[VZ]);
 621			gGL.vertex3f(min.mV[VX], max.mV[VY], max.mV[VZ]);
 622			gGL.vertex3f(max.mV[VX], max.mV[VY], max.mV[VZ]);
 623			gGL.vertex3f(max.mV[VX], max.mV[VY], min.mV[VZ]);
 624
 625			// Face 3
 626			gGL.vertex3f(min.mV[VX], max.mV[VY], max.mV[VZ]);
 627			gGL.vertex3f(min.mV[VX], max.mV[VY], min.mV[VZ]);
 628			gGL.vertex3f(min.mV[VX], min.mV[VY], min.mV[VZ]);
 629			gGL.vertex3f(min.mV[VX], min.mV[VY], max.mV[VZ]);
 630
 631			// Face 4
 632			gGL.vertex3f(min.mV[VX], min.mV[VY], max.mV[VZ]);
 633			gGL.vertex3f(min.mV[VX], min.mV[VY], min.mV[VZ]);
 634			gGL.vertex3f(max.mV[VX], min.mV[VY], min.mV[VZ]);
 635			gGL.vertex3f(max.mV[VX], min.mV[VY], max.mV[VZ]);
 636
 637			// Face 5
 638			gGL.vertex3f(min.mV[VX], min.mV[VY], min.mV[VZ]);
 639			gGL.vertex3f(min.mV[VX], max.mV[VY], min.mV[VZ]);
 640			gGL.vertex3f(max.mV[VX], max.mV[VY], min.mV[VZ]);
 641			gGL.vertex3f(max.mV[VX], min.mV[VY], min.mV[VZ]);
 642		}
 643		gGL.end();
 644	}
 645
 646	// Find nearest vertex
 647	LLVector3 orientWRTHead = bbox.agentToLocalBasis( bbox.getCenterAgent() - gAgentCamera.getCameraPositionAgent() );
 648	U32 nearest = 
 649		(orientWRTHead.mV[0] < 0.0f ? 1 : 0) + 
 650		(orientWRTHead.mV[1] < 0.0f ? 2 : 0) + 
 651		(orientWRTHead.mV[2] < 0.0f ? 4 : 0);
 652
 653	// opposite faces on Linden cubes:
 654	// 0 & 5
 655	// 1 & 3
 656	// 2 & 4
 657
 658	// Table of order to draw faces, based on nearest vertex
 659	static U32 face_list[8][6] = { 
 660		{ 2,0,1, 4,5,3 }, // v6  F201 F453
 661		{ 2,0,3, 4,5,1 }, // v7  F203 F451
 662		{ 4,0,1, 2,5,3 }, // v5  F401 F253
 663		{ 4,0,3, 2,5,1 }, // v4  F403 F251
 664		{ 2,5,1, 4,0,3 }, // v2  F251 F403
 665		{ 2,5,3, 4,0,1 }, // v3  F253 F401
 666		{ 4,5,1, 2,0,3 }, // v1  F451 F203
 667		{ 4,5,3, 2,0,1 }  // v0  F453 F201
 668	};
 669
 670	{
 671		LLGLDepthTest gls_depth(GL_FALSE);
 672
 673		for (S32 i = 0; i < 6; i++)
 674		{
 675			U32 face = face_list[nearest][i];
 676			switch( face )
 677			{
 678			  case 0:
 679				conditionalHighlight( LL_FACE_POSZ, &z_highlight_color, &z_normal_color );
 680				renderAxisHandle( ctr, LLVector3( ctr.mV[VX], ctr.mV[VY], max.mV[VZ] ) );
 681				break;
 682
 683			  case 1:
 684				conditionalHighlight( LL_FACE_POSX, &x_highlight_color, &x_normal_color );
 685				renderAxisHandle( ctr, LLVector3( max.mV[VX], ctr.mV[VY], ctr.mV[VZ] ) );
 686				break;
 687
 688			  case 2:
 689				conditionalHighlight( LL_FACE_POSY, &y_highlight_color, &y_normal_color );
 690				renderAxisHandle( ctr, LLVector3( ctr.mV[VX], max.mV[VY], ctr.mV[VZ] ) );
 691				break;
 692
 693			  case 3:
 694				conditionalHighlight( LL_FACE_NEGX, &x_highlight_color, &x_normal_color );
 695				renderAxisHandle( ctr, LLVector3( min.mV[VX], ctr.mV[VY], ctr.mV[VZ] ) );
 696				break;
 697
 698			  case 4:
 699				conditionalHighlight( LL_FACE_NEGY, &y_highlight_color, &y_normal_color );
 700				renderAxisHandle( ctr, LLVector3( ctr.mV[VX], min.mV[VY], ctr.mV[VZ] ) );
 701				break;
 702
 703			  case 5:
 704				conditionalHighlight( LL_FACE_NEGZ, &z_highlight_color, &z_normal_color );
 705				renderAxisHandle( ctr, LLVector3( ctr.mV[VX], ctr.mV[VY], min.mV[VZ] ) );
 706				break;
 707			}
 708		}
 709	}
 710}
 711
 712void LLManipScale::renderEdges( const LLBBox& bbox )
 713{
 714	LLVector3 extent = bbox.getExtentLocal();
 715	F32 edge_width = mBoxHandleSize * .6f;
 716
 717	for( U32 part = LL_EDGE_MIN; part <= LL_EDGE_MAX; part++ )
 718	{
 719		LLVector3 direction = edgeToUnitVector( part );
 720		LLVector3 center_to_edge = unitVectorToLocalBBoxExtent( direction, bbox );
 721
 722		gGL.pushMatrix();
 723		{
 724			gGL.translatef( center_to_edge.mV[0], center_to_edge.mV[1], center_to_edge.mV[2] );
 725			conditionalHighlight( part );
 726			gGL.scalef( 
 727				direction.mV[0] ? edge_width : extent.mV[VX],
 728				direction.mV[1] ? edge_width : extent.mV[VY],
 729				direction.mV[2] ? edge_width : extent.mV[VZ] );
 730			gBox.render();
 731		}
 732		gGL.popMatrix();
 733	}
 734}
 735
 736
 737void LLManipScale::renderCorners( const LLBBox& bbox )
 738{
 739	U32 part = LL_CORNER_NNN;
 740
 741	F32 x_offset = bbox.getMinLocal().mV[VX];
 742	for( S32 i=0; i < 2; i++ )
 743	{
 744		F32 y_offset = bbox.getMinLocal().mV[VY];
 745		for( S32 j=0; j < 2; j++ )
 746		{
 747			F32 z_offset = bbox.getMinLocal().mV[VZ];
 748			for( S32 k=0; k < 2; k++ )
 749			{
 750				conditionalHighlight( part );
 751				renderBoxHandle( x_offset, y_offset, z_offset );
 752				part++;
 753
 754				z_offset = bbox.getMaxLocal().mV[VZ];
 755
 756			}
 757			y_offset = bbox.getMaxLocal().mV[VY];
 758		}
 759		x_offset = bbox.getMaxLocal().mV[VX];
 760  }
 761}
 762
 763
 764void LLManipScale::renderBoxHandle( F32 x, F32 y, F32 z )
 765{
 766	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 767	LLGLDepthTest gls_depth(GL_FALSE);
 768
 769	gGL.pushMatrix();
 770	{
 771		gGL.translatef( x, y, z );
 772		gGL.scalef( mScaledBoxHandleSize, mScaledBoxHandleSize, mScaledBoxHandleSize );
 773		gBox.render();
 774	}
 775	gGL.popMatrix();
 776}
 777
 778
 779void LLManipScale::renderAxisHandle( const LLVector3& start, const LLVector3& end )
 780{
 781	if( getShowAxes() )
 782	{
 783		// Draws a single "jacks" style handle: a long, retangular box from start to end.
 784		LLVector3 offset_start = end - start;
 785		offset_start.normVec();
 786		offset_start = start + mBoxHandleSize * offset_start;
 787
 788		LLVector3 delta = end - offset_start;
 789		LLVector3 pos = offset_start + 0.5f * delta;
 790
 791		gGL.pushMatrix();
 792		{
 793			gGL.translatef( pos.mV[VX], pos.mV[VY], pos.mV[VZ] );
 794			gGL.scalef( 
 795				mBoxHandleSize + llabs(delta.mV[VX]),
 796				mBoxHandleSize + llabs(delta.mV[VY]),
 797				mBoxHandleSize + llabs(delta.mV[VZ]));
 798			gBox.render();
 799		}
 800		gGL.popMatrix();
 801	}
 802	else
 803	{
 804		renderBoxHandle( end.mV[VX], end.mV[VY], end.mV[VZ] );
 805	}
 806}
 807
 808
 809void LLManipScale::drag( S32 x, S32 y )
 810{
 811	if( (LL_FACE_MIN <= (S32)mManipPart) 
 812		&& ((S32)mManipPart <= LL_FACE_MAX) )
 813	{
 814		dragFace( x, y );
 815	}
 816	else
 817	if( (LL_CORNER_MIN <= (S32)mManipPart) 
 818		&& ((S32)mManipPart <= LL_CORNER_MAX) )
 819	{
 820		dragCorner( x, y );
 821	}
 822	
 823	// store changes to override updates
 824	for (LLObjectSelection::iterator iter = LLSelectMgr::getInstance()->getSelection()->begin();
 825		 iter != LLSelectMgr::getInstance()->getSelection()->end(); iter++)
 826	{
 827		LLSelectNode* selectNode = *iter;
 828		LLViewerObject*cur = selectNode->getObject();
 829		if( cur->permModify() && cur->permMove() && !cur->isAvatar())
 830		{
 831			selectNode->mLastScale = cur->getScale();
 832			selectNode->mLastPositionLocal = cur->getPosition();
 833		}
 834	}	
 835
 836	LLSelectMgr::getInstance()->updateSelectionCenter();
 837    gAgentCamera.clearFocusObject();
 838}
 839
 840// Scale around the 
 841void LLManipScale::dragCorner( S32 x, S32 y )
 842{
 843	LLBBox bbox	= LLSelectMgr::getInstance()->getBBoxOfSelection();
 844
 845	// Suppress scale if mouse hasn't moved.
 846	if (x == mLastMouseX && y == mLastMouseY)
 847	{
 848	//	sendUpdates(TRUE,TRUE,TRUE);
 849		return;
 850	}
 851
 852	mLastMouseX = x;
 853	mLastMouseY = y;
 854
 855	LLVector3d drag_start_point_global	= mDragStartPointGlobal;
 856	LLVector3d drag_start_center_global = mDragStartCenterGlobal;
 857	LLVector3 drag_start_point_agent = gAgent.getPosAgentFromGlobal(drag_start_point_global);
 858	LLVector3 drag_start_center_agent = gAgent.getPosAgentFromGlobal(drag_start_center_global);
 859
 860	LLVector3d drag_start_dir_d;
 861	drag_start_dir_d.setVec(drag_start_point_global - drag_start_center_global);
 862	LLVector3 drag_start_dir_f;
 863	drag_start_dir_f.setVec(drag_start_dir_d);
 864
 865	F32 s = 0;
 866	F32 t = 0;
 867
 868	nearestPointOnLineFromMouse(x, y, 
 869						drag_start_center_agent,
 870						drag_start_point_agent,
 871						s, t );
 872
 873	F32 drag_start_dist = dist_vec(drag_start_point_agent, drag_start_center_agent);
 874
 875	if( s <= 0 )  // we only care about intersections in front of the camera
 876	{
 877		return;
 878	}
 879
 880	LLVector3d drag_point_global = drag_start_center_global + t * drag_start_dir_d;
 881
 882	F32 scale_factor = t;
 883
 884	BOOL uniform = LLManipScale::getUniform();
 885
 886	if( !uniform )
 887	{
 888		scale_factor = 0.5f + (scale_factor * 0.5f);
 889	}
 890
 891	// check for snapping
 892	LLVector3 drag_center_agent = gAgent.getPosAgentFromGlobal(drag_point_global);
 893	LLVector3 mouse_on_plane1;
 894	getMousePointOnPlaneAgent(mouse_on_plane1, x, y, drag_center_agent, mScalePlaneNormal1);
 895	LLVector3 mouse_on_plane2;
 896	getMousePointOnPlaneAgent(mouse_on_plane2, x, y, drag_center_agent, mScalePlaneNormal2);
 897	LLVector3 mouse_dir_1 = mouse_on_plane1 - mScaleCenter;
 898	LLVector3 mouse_dir_2 = mouse_on_plane2 - mScaleCenter;
 899	LLVector3 mouse_to_scale_line_1 = mouse_dir_1 - projected_vec(mouse_dir_1, mScaleDir);
 900	LLVector3 mouse_to_scale_line_2 = mouse_dir_2 - projected_vec(mouse_dir_2, mScaleDir);
 901	LLVector3 mouse_to_scale_line_dir_1 = mouse_to_scale_line_1;
 902	mouse_to_scale_line_dir_1.normVec();
 903	if (mouse_to_scale_line_dir_1 * mSnapGuideDir1 < 0.f)
 904	{
 905		// need to keep sign of mouse offset wrt to snap guide direction
 906		mouse_to_scale_line_dir_1 *= -1.f;
 907	}
 908	LLVector3 mouse_to_scale_line_dir_2 = mouse_to_scale_line_2;
 909	mouse_to_scale_line_dir_2.normVec();
 910	if (mouse_to_scale_line_dir_2 * mSnapGuideDir2 < 0.f)
 911	{
 912		// need to keep sign of mouse offset wrt to snap guide direction
 913		mouse_to_scale_line_dir_2 *= -1.f;
 914	}
 915
 916	F32 snap_dir_dot_mouse_offset1 = mSnapGuideDir1 * mouse_to_scale_line_dir_1;
 917	F32 snap_dir_dot_mouse_offset2 = mSnapGuideDir2 * mouse_to_scale_line_dir_2;
 918
 919	F32 dist_from_scale_line_1 = mouse_to_scale_line_1 * mouse_to_scale_line_dir_1; 
 920	F32 dist_from_scale_line_2 = mouse_to_scale_line_2 * mouse_to_scale_line_dir_2;
 921
 922	F32 max_scale = partToMaxScale(mManipPart, bbox);
 923	F32 min_scale = partToMinScale(mManipPart, bbox);
 924
 925	BOOL snap_enabled = gSavedSettings.getBOOL("SnapEnabled");
 926	if (snap_enabled && dist_from_scale_line_1 > mSnapRegimeOffset * snap_dir_dot_mouse_offset1)
 927	{
 928		mInSnapRegime = TRUE;
 929		LLVector3 projected_drag_pos = mouse_on_plane1 - (dist_from_scale_line_1 / snap_dir_dot_mouse_offset1) * mSnapGuideDir1;
 930		F32 drag_dist = (projected_drag_pos - mScaleCenter) * mScaleDir;
 931
 932		F32 cur_subdivisions = llclamp(getSubdivisionLevel(projected_drag_pos, mScaleDir, mScaleSnapUnit1), sGridMinSubdivisionLevel, sGridMaxSubdivisionLevel);
 933		F32 snap_dist = mScaleSnapUnit1 / (2.f * cur_subdivisions);
 934		F32 relative_snap_dist = fmodf(drag_dist + snap_dist, mScaleSnapUnit1 / cur_subdivisions);
 935
 936		mScaleSnapValue = llclamp((drag_dist - (relative_snap_dist - snap_dist)), min_scale, max_scale);
 937
 938		scale_factor = mScaleSnapValue / drag_start_dist;
 939		if( !uniform )
 940		{
 941			scale_factor *= 0.5f;
 942		}
 943	}
 944	else if (snap_enabled && dist_from_scale_line_2 > mSnapRegimeOffset * snap_dir_dot_mouse_offset2)
 945	{
 946		mInSnapRegime = TRUE;
 947		LLVector3 projected_drag_pos = mouse_on_plane2 - (dist_from_scale_line_2 / snap_dir_dot_mouse_offset2) * mSnapGuideDir2;
 948		F32 drag_dist = (projected_drag_pos - mScaleCenter) * mScaleDir;
 949
 950		F32 cur_subdivisions = llclamp(getSubdivisionLevel(projected_drag_pos, mScaleDir, mScaleSnapUnit2), sGridMinSubdivisionLevel, sGridMaxSubdivisionLevel);
 951		F32 snap_dist = mScaleSnapUnit2 / (2.f * cur_subdivisions);
 952		F32 relative_snap_dist = fmodf(drag_dist + snap_dist, mScaleSnapUnit2 / cur_subdivisions);
 953
 954		mScaleSnapValue = llclamp((drag_dist - (relative_snap_dist - snap_dist)), min_scale, max_scale);
 955
 956		scale_factor = mScaleSnapValue / drag_start_dist;
 957		if( !uniform )
 958		{
 959			scale_factor *= 0.5f;
 960		}
 961	}
 962	else 
 963	{
 964		mInSnapRegime = FALSE;
 965	}
 966
 967	F32 max_scale_factor = get_default_max_prim_scale() / MIN_PRIM_SCALE;
 968	F32 min_scale_factor = MIN_PRIM_SCALE / get_default_max_prim_scale();
 969
 970	// find max and min scale factors that will make biggest object hit max absolute scale and smallest object hit min absolute scale
 971	for (LLObjectSelection::iterator iter = mObjectSelection->begin();
 972		 iter != mObjectSelection->end(); iter++)
 973	{
 974		LLSelectNode* selectNode = *iter;
 975		LLViewerObject* cur = selectNode->getObject();
 976		if(  cur->permModify() && cur->permMove() && !cur->isAvatar() )
 977		{
 978			const LLVector3& scale = selectNode->mSavedScale;
 979
 980			F32 cur_max_scale_factor = llmin( get_default_max_prim_scale(LLPickInfo::isFlora(cur)) / scale.mV[VX], get_default_max_prim_scale(LLPickInfo::isFlora(cur)) / scale.mV[VY], get_default_max_prim_scale(LLPickInfo::isFlora(cur)) / scale.mV[VZ] );
 981			max_scale_factor = llmin( max_scale_factor, cur_max_scale_factor );
 982
 983			F32 cur_min_scale_factor = llmax( MIN_PRIM_SCALE / scale.mV[VX], MIN_PRIM_SCALE / scale.mV[VY], MIN_PRIM_SCALE / scale.mV[VZ] );
 984			min_scale_factor = llmax( min_scale_factor, cur_min_scale_factor );
 985		}
 986	}
 987
 988	scale_factor = llclamp( scale_factor, min_scale_factor, max_scale_factor );
 989
 990	LLVector3d drag_global = uniform ? mDragStartCenterGlobal : mDragFarHitGlobal;
 991
 992	// do the root objects i.e. (TRUE == cur->isRootEdit())
 993	for (LLObjectSelection::iterator iter = mObjectSelection->begin();
 994		 iter != mObjectSelection->end(); iter++)
 995	{
 996		LLSelectNode* selectNode = *iter;
 997		LLViewerObject* cur = selectNode->getObject();
 998		if( cur->permModify() && cur->permMove() && !cur->isAvatar() && cur->isRootEdit() )
 999		{
1000			const LLVector3& scale = selectNode->mSavedScale;
1001			cur->setScale( scale_factor * scale );
1002			
1003			LLVector3 delta_pos;
1004			LLVector3 original_pos = cur->getPositionEdit();
1005			LLVector3d new_pos_global = drag_global + (selectNode->mSavedPositionGlobal - drag_global) * scale_factor;
1006			if (!cur->isAttachment())
1007			{
1008				new_pos_global = LLWorld::getInstance()->clipToVisibleRegions(selectNode->mSavedPositionGlobal, new_pos_global);
1009			}
1010			cur->setPositionAbsoluteGlobal( new_pos_global );
1011			rebuild(cur);
1012			
1013			delta_pos = cur->getPositionEdit() - original_pos;
1014
1015			if (selectNode->mIndividualSelection)
1016			{
1017				// counter-translate child objects if we are moving the root as an individual
1018				LLViewerObject::const_child_list_t& child_list = cur->getChildren();
1019				for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin();
1020					 iter != child_list.end(); iter++)
1021				{
1022					LLViewerObject* childp = *iter;
1023
1024					if (cur->isAttachment())
1025					{
1026						LLVector3 child_pos = childp->getPosition() - (delta_pos * ~cur->getRotationEdit());
1027						childp->setPosition(child_pos);
1028					}
1029					else
1030					{
1031						LLVector3d child_pos_delta(delta_pos);
1032						// RN: this updates drawable position instantly
1033						childp->setPositionAbsoluteGlobal(childp->getPositionGlobal() - child_pos_delta);
1034					}
1035					rebuild(childp);
1036				}
1037			}
1038		}
1039	}
1040	// do the child objects i.e. (FALSE == cur->isRootEdit())
1041	for (LLObjectSelection::iterator iter = mObjectSelection->begin();
1042		 iter != mObjectSelection->end(); iter++)
1043	{
1044		LLSelectNode* selectNode = *iter;
1045		LLViewerObject*cur = selectNode->getObject();
1046		if( cur->permModify() && cur->permMove() && !cur->isAvatar() && !cur->isRootEdit() )
1047		{
1048			const LLVector3& scale = selectNode->mSavedScale;
1049			cur->setScale( scale_factor * scale, FALSE );
1050							
1051			if (!selectNode->mIndividualSelection)
1052			{
1053				cur->setPosition(selectNode->mSavedPositionLocal * scale_factor);
1054			}
1055
1056			rebuild(cur);
1057		}
1058	}
1059
1060	
1061
1062	mDragPointGlobal = drag_point_global;
1063}
1064
1065	
1066void LLManipScale::dragFace( S32 x, S32 y )
1067{
1068	// Suppress scale if mouse hasn't moved.
1069	if (x == mLastMouseX && y == mLastMouseY)
1070	{
1071	//	sendUpdates(TRUE,TRUE,FALSE);
1072		return;
1073	}
1074
1075	mLastMouseX = x;
1076	mLastMouseY = y;
1077
1078	LLVector3d drag_start_point_global	= mDragStartPointGlobal;
1079	LLVector3d drag_start_center_global = mDragStartCenterGlobal;
1080	LLVector3 drag_start_point_agent = gAgent.getPosAgentFromGlobal(drag_start_point_global);
1081	LLVector3 drag_start_center_agent = gAgent.getPosAgentFromGlobal(drag_start_center_global);
1082
1083	LLVector3d drag_start_dir_d;
1084	drag_start_dir_d.setVec(drag_start_point_global - drag_start_center_global);
1085	LLVector3 drag_start_dir_f;
1086	drag_start_dir_f.setVec(drag_start_dir_d);
1087
1088	LLBBox bbox	= LLSelectMgr::getInstance()->getBBoxOfSelection();
1089
1090	F32 s = 0;
1091	F32 t = 0;
1092
1093	nearestPointOnLineFromMouse(x,
1094						y,
1095						drag_start_center_agent,
1096						drag_start_point_agent,
1097						s, t );
1098
1099	if( s <= 0 )  // we only care about intersections in front of the camera
1100	{
1101		return;
1102	}
1103
1104	LLVector3d drag_point_global = drag_start_center_global + t * drag_start_dir_d;
1105	LLVector3 part_dir_local	= partToUnitVector( mManipPart );
1106
1107	// check for snapping
1108	LLVector3 mouse_on_plane;
1109	getMousePointOnPlaneAgent(mouse_on_plane, x, y, mScaleCenter, mScalePlaneNormal1 );
1110
1111	LLVector3 mouse_on_scale_line = mScaleCenter + projected_vec(mouse_on_plane - mScaleCenter, mScaleDir);
1112	LLVector3 drag_delta(mouse_on_scale_line - drag_start_point_agent);
1113	F32 max_drag_dist = partToMaxScale(mManipPart, bbox);
1114	F32 min_drag_dist = partToMinScale(mManipPart, bbox);
1115
1116	BOOL uniform = LLManipScale::getUniform();
1117	if( uniform )
1118	{
1119		drag_delta *= 2.f;
1120	}
1121
1122	LLVector3 scale_center_to_mouse = mouse_on_plane - mScaleCenter;
1123	F32 dist_from_scale_line = dist_vec(scale_center_to_mouse, (mouse_on_scale_line - mScaleCenter));
1124	F32 dist_along_scale_line = scale_center_to_mouse * mScaleDir;
1125
1126	BOOL snap_enabled = gSavedSettings.getBOOL("SnapEnabled");
1127
1128	if (snap_enabled && dist_from_scale_line > mSnapRegimeOffset)
1129	{
1130		mInSnapRegime = TRUE;
1131
1132 		if (dist_along_scale_line > max_drag_dist)
1133		{
1134			mScaleSnapValue = max_drag_dist;
1135
1136			LLVector3 clamp_point = mScaleCenter + max_drag_dist * mScaleDir;
1137			drag_delta.setVec(clamp_point - drag_start_point_agent);
1138		}
1139		else if (dist_along_scale_line < min_drag_dist)
1140		{
1141			mScaleSnapValue = min_drag_dist;
1142
1143			LLVector3 clamp_point = mScaleCenter + min_drag_dist * mScaleDir;
1144			drag_delta.setVec(clamp_point - drag_start_point_agent);
1145		}
1146		else
1147		{
1148			F32 drag_dist = scale_center_to_mouse * mScaleDir;
1149			F32 cur_subdivisions = llclamp(getSubdivisionLevel(mScaleCenter + mScaleDir * drag_dist, mScaleDir, mScaleSnapUnit1), sGridMinSubdivisionLevel, sGridMaxSubdivisionLevel);
1150			F32 snap_dist = mScaleSnapUnit1 / (2.f * cur_subdivisions);
1151			F32 relative_snap_dist = fmodf(drag_dist + snap_dist, mScaleSnapUnit1 / cur_subdivisions);
1152			relative_snap_dist -= snap_dist;
1153
1154			//make sure that values that the scale is "snapped to"
1155			//do not exceed/go under the applicable max/mins
1156			//this causes the box to shift displacements ever so slightly
1157			//although the "snap value" should go down to 0
1158			//see Jira 1027
1159			relative_snap_dist = llclamp(relative_snap_dist,
1160										 drag_dist - max_drag_dist,
1161										 drag_dist - min_drag_dist);
1162
1163			mScaleSnapValue = drag_dist - relative_snap_dist;
1164
1165			if (llabs(relative_snap_dist) < snap_dist)
1166			{
1167				LLVector3 drag_correction = relative_snap_dist * mScaleDir;
1168				if (uniform)
1169				{
1170					drag_correction *= 2.f;
1171				}
1172
1173				drag_delta -= drag_correction;
1174			}
1175		}
1176	}
1177	else 
1178	{
1179		mInSnapRegime = FALSE;
1180	}
1181
1182	BOOL send_scale_update = FALSE;
1183	BOOL send_position_update = FALSE;
1184
1185	LLVector3 dir_agent;
1186	if( part_dir_local.mV[VX] )
1187	{
1188		dir_agent = bbox.localToAgentBasis( LLVector3::x_axis );
1189	}
1190	else if( part_dir_local.mV[VY] )
1191	{
1192		dir_agent = bbox.localToAgentBasis( LLVector3::y_axis );
1193	}
1194	else if( part_dir_local.mV[VZ] )
1195	{
1196		dir_agent = bbox.localToAgentBasis( LLVector3::z_axis );
1197	}
1198	stretchFace( 
1199		projected_vec(drag_start_dir_f, dir_agent) + drag_start_center_agent,
1200		projected_vec(drag_delta, dir_agent));
1201	send_position_update = TRUE;
1202	send_scale_update = TRUE;
1203
1204	mDragPointGlobal = drag_point_global;
1205}
1206
1207void LLManipScale::sendUpdates( BOOL send_position_update, BOOL send_scale_update, BOOL corner )
1208{
1209	// Throttle updates to 10 per second.
1210	static LLTimer	update_timer;
1211	F32 elapsed_time = update_timer.getElapsedTimeF32();
1212	const F32 UPDATE_DELAY = 0.1f;						//  min time between transmitted updates
1213
1214	if( send_scale_update || send_position_update )
1215	{
1216		U32 update_flags = UPD_NONE;
1217		if (send_position_update)	update_flags |= UPD_POSITION;
1218		if (send_scale_update)		update_flags |= UPD_SCALE;
1219		
1220// 		BOOL send_type = SEND_INDIVIDUALS;
1221		if (corner)
1222		{
1223			update_flags |= UPD_UNIFORM;
1224		}
1225		// keep this up to date for sendonmouseup
1226		mLastUpdateFlags = update_flags;
1227
1228		// enforce minimum update delay and don't stream updates on sub-object selections
1229		if( elapsed_time > UPDATE_DELAY && !gSavedSettings.getBOOL("EditLinkedParts") )
1230		{
1231			LLSelectMgr::getInstance()->sendMultipleUpdate( update_flags );
1232			update_timer.reset();
1233			mSendUpdateOnMouseUp = FALSE;
1234		}
1235		else
1236		{
1237			mSendUpdateOnMouseUp = TRUE;
1238		}
1239		dialog_refresh_all();
1240	}
1241}
1242
1243// Rescales in a single dimension.  Either uniform (standard) or one-sided (scale plus translation)
1244// depending on mUniform.  Handles multiple selection and objects that are not aligned to the bounding box.
1245void LLManipScale::stretchFace( const LLVector3& drag_start_agent, const LLVector3& drag_delta_agent )
1246{
1247	LLVector3 drag_start_center_agent = gAgent.getPosAgentFromGlobal(mDragStartCenterGlobal);
1248
1249	for (LLObjectSelection::iterator iter = mObjectSelection->begin();
1250		 iter != mObjectSelection->end(); iter++)
1251	{
1252		LLSelectNode* selectNode = *iter;
1253		LLViewerObject*cur = selectNode->getObject();
1254		if( cur->permModify() && cur->permMove() && !cur->isAvatar() )
1255		{
1256			LLBBox cur_bbox			= cur->getBoundingBoxAgent();
1257			LLVector3 start_local	= cur_bbox.agentToLocal( drag_start_agent );
1258			LLVector3 end_local		= cur_bbox.agentToLocal( drag_start_agent + drag_delta_agent);
1259			LLVector3 start_center_local = cur_bbox.agentToLocal( drag_start_center_agent );
1260			LLVector3 axis			= nearestAxis( start_local - start_center_local );
1261			S32 axis_index			= axis.mV[0] ? 0 : (axis.mV[1] ? 1 : 2 );
1262
1263			LLVector3 delta_local	= end_local - start_local;
1264			F32 delta_local_mag		= delta_local.magVec();
1265			LLVector3 dir_local;
1266			if (delta_local_mag == 0.f)
1267			{
1268				dir_local = axis;
1269			}
1270			else
1271			{
1272				dir_local = delta_local / delta_local_mag; // normalized delta_local
1273			}
1274
1275			F32 denom = axis * dir_local;
1276			F32 desired_delta_size	= is_approx_zero(denom) ? 0.f : (delta_local_mag / denom);  // in meters
1277			F32 desired_scale		= llclamp(selectNode->mSavedScale.mV[axis_index] + desired_delta_size, MIN_PRIM_SCALE, get_default_max_prim_scale(LLPickInfo::isFlora(cur)));
1278			// propagate scale constraint back to position offset
1279			desired_delta_size		= desired_scale - selectNode->mSavedScale.mV[axis_index]; // propagate constraint back to position
1280
1281			LLVector3 scale			= cur->getScale();
1282			scale.mV[axis_index]	= desired_scale;
1283			cur->setScale(scale, FALSE);
1284			rebuild(cur);				
1285			LLVector3 delta_pos;
1286			if( !getUniform() )
1287			{
1288				LLVector3 delta_pos_local = axis * (0.5f * desired_delta_size);
1289				LLVector3d delta_pos_global;
1290				delta_pos_global.setVec(cur_bbox.localToAgent( delta_pos_local ) - cur_bbox.getCenterAgent());
1291				LLVector3 cur_pos = cur->getPositionEdit();
1292
1293				if (cur->isRootEdit() && !cur->isAttachment())
1294				{
1295					LLVector3d new_pos_global = LLWorld::getInstance()->clipToVisibleRegions(selectNode->mSavedPositionGlobal, selectNode->mSavedPositionGlobal + delta_pos_global);
1296					cur->setPositionGlobal( new_pos_global );
1297				}
1298				else
1299				{
1300					LLXform* parent_xform = cur->mDrawable->getXform()->getParent();
1301					LLVector3 new_pos_local;
1302					// this works in attachment point space using world space delta
1303					if (parent_xform)
1304					{
1305						new_pos_local = selectNode->mSavedPositionLocal + (LLVector3(delta_pos_global) * ~parent_xform->getWorldRotation());
1306					}
1307					else
1308					{
1309						new_pos_local = selectNode->mSavedPositionLocal + LLVector3(delta_pos_global);
1310					}
1311					cur->setPosition(new_pos_local);
1312				}
1313				delta_pos = cur->getPositionEdit() - cur_pos;
1314			}
1315			if (cur->isRootEdit() && selectNode->mIndividualSelection)
1316			{
1317				// counter-translate child objects if we are moving the root as an individual
1318				LLViewerObject::const_child_list_t& child_list = cur->getChildren();
1319				for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin();
1320					 iter != child_list.end(); iter++)
1321				{
1322					LLViewerObject* childp = *iter;
1323					if (!getUniform())
1324					{
1325						LLVector3 child_pos = childp->getPosition() - (delta_pos * ~cur->getRotationEdit());
1326						childp->setPosition(child_pos);
1327						rebuild(childp);
1328					}
1329				}
1330			}
1331		}
1332	}
1333}
1334
1335
1336void LLManipScale::renderGuidelinesPart( const LLBBox& bbox )
1337{
1338	LLVector3 guideline_start = bbox.getCenterLocal();
1339	
1340	LLVector3 guideline_end = unitVectorToLocalBBoxExtent( partToUnitVector( mManipPart ), bbox );
1341
1342	if (!getUniform())
1343	{
1344		guideline_start = unitVectorToLocalBBoxExtent( -partToUnitVector( mManipPart ), bbox );
1345	}
1346
1347	guideline_end -= guideline_start;
1348	guideline_end.normVec();
1349	guideline_end *= LLWorld::getInstance()->getRegionWidthInMeters();
1350	guideline_end += guideline_start;
1351
1352	{
1353		LLGLDepthTest gls_depth(GL_TRUE);
1354		gl_stippled_line_3d( guideline_start, guideline_end, LLColor4(1.f, 1.f, 1.f, 0.5f) );
1355	}
1356	{
1357		LLGLDepthTest gls_depth(GL_FALSE);
1358		gl_stippled_line_3d( guideline_start, guideline_end, LLColor4(1.f, 1.f, 1.f, 0.25f) );
1359	}
1360}
1361
1362void LLManipScale::updateSnapGuides(const LLBBox& bbox)
1363{
1364	LLVector3 grid_origin;
1365	LLVector3 grid_scale;
1366	LLQuaternion grid_rotation;
1367	LLSelectMgr::getInstance()->getGrid(grid_origin, grid_rotation, grid_scale);
1368
1369	LLVector3 box_corner_agent = bbox.localToAgent(unitVectorToLocalBBoxExtent( partToUnitVector( mManipPart ), bbox ));
1370	mScaleCenter = getUniform() ? bbox.getCenterAgent() : bbox.localToAgent(unitVectorToLocalBBoxExtent( -1.f * partToUnitVector( mManipPart ), bbox ));
1371	mScaleDir = box_corner_agent - mScaleCenter;
1372	mScaleDir.normVec();
1373
1374	if(mObjectSelection->getSelectType() == SELECT_TYPE_HUD)
1375	{
1376		mSnapRegimeOffset = SNAP_GUIDE_SCREEN_OFFSET / gAgentCamera.mHUDCurZoom;
1377
1378	}
1379	else
1380	{
1381		F32 object_distance = dist_vec(mScaleCenter, LLViewerCamera::getInstance()->getOrigin());
1382		mSnapRegimeOffset = (SNAP_GUIDE_SCREEN_OFFSET * gViewerWindow->getWorldViewWidthRaw() * object_distance) / LLViewerCamera::getInstance()->getPixelMeterRatio();
1383	}
1384	LLVector3 cam_at_axis;
1385	F32 snap_guide_length;
1386	if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD)
1387	{
1388		cam_at_axis.setVec(1.f, 0.f, 0.f);
1389		snap_guide_length = SNAP_GUIDE_SCREEN_LENGTH / gAgentCamera.mHUDCurZoom;
1390	}
1391	else
1392	{
1393		cam_at_axis = LLViewerCamera::getInstance()->getAtAxis();
1394		F32 manipulator_distance = dist_vec(box_corner_agent, LLViewerCamera::getInstance()->getOrigin());
1395		snap_guide_length = (SNAP_GUIDE_SCREEN_LENGTH * gViewerWindow->getWorldViewWidthRaw() * manipulator_distance) / LLViewerCamera::getInstance()->getPixelMeterRatio();
1396	}
1397	
1398	mSnapGuideLength = snap_guide_length / llmax(0.1f, (llmin(mSnapGuideDir1 * cam_at_axis, mSnapGuideDir2 * cam_at_axis)));
1399
1400	LLVector3 off_axis_dir = mScaleDir % cam_at_axis;
1401	off_axis_dir.normVec();
1402
1403	if( (LL_FACE_MIN <= (S32)mManipPart) && ((S32)mManipPart <= LL_FACE_MAX) )
1404	{
1405		LLVector3 object_scale = bbox.getMaxLocal();
1406		object_scale.scaleVec(off_axis_dir * ~bbox.getRotation());
1407		object_scale.abs();
1408		if (object_scale.mV[VX] > object_scale.mV[VY] && object_scale.mV[VX] > object_scale.mV[VZ])
1409		{
1410			mSnapGuideDir1 = LLVector3::x_axis * bbox.getRotation();
1411		}
1412		else if (object_scale.mV[VY] > object_scale.mV[VZ])
1413		{
1414			mSnapGuideDir1 = LLVector3::y_axis * bbox.getRotation();
1415		}
1416		else
1417		{
1418			mSnapGuideDir1 = LLVector3::z_axis * bbox.getRotation();
1419		}
1420
1421		LLVector3 scale_snap = grid_scale;
1422		mScaleSnapUnit1 = scale_snap.scaleVec(partToUnitVector( mManipPart )).magVec();
1423		mScaleSnapUnit2 = mScaleSnapUnit1;
1424		mSnapGuideDir1 *= mSnapGuideDir1 * LLViewerCamera::getInstance()->getUpAxis() > 0.f ? 1.f : -1.f;
1425		mSnapGuideDir2 = mSnapGuideDir1 * -1.f;
1426		mSnapDir1 = mScaleDir;
1427		mSnapDir2 = mScaleDir;
1428	}
1429	else if( (LL_CORNER_MIN <= (S32)mManipPart) && ((S32)mManipPart <= LL_CORNER_MAX) )
1430	{
1431		LLVector3 local_scale_dir = partToUnitVector( mManipPart );
1432		LLVector3 local_camera_dir;
1433		if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD)
1434		{
1435			local_camera_dir = LLVector3(-1.f, 0.f, 0.f) * ~bbox.getRotation();
1436		}
1437		else
1438		{
1439			local_camera_dir = (LLViewerCamera::getInstance()->getOrigin() - bbox.getCenterAgent()) * ~bbox.getRotation();
1440			local_camera_dir.normVec();
1441		}
1442		local_scale_dir -= projected_vec(local_scale_dir, local_camera_dir);
1443		local_scale_dir.normVec();
1444		LLVector3 x_axis_proj_camera = LLVector3::x_axis - projected_vec(LLVector3::x_axis, local_camera_dir);
1445		x_axis_proj_camera.normVec();
1446		LLVector3 y_axis_proj_camera = LLVector3::y_axis - projected_vec(LLVector3::y_axis, local_camera_dir);
1447		y_axis_proj_camera.normVec();
1448		LLVector3 z_axis_proj_camera = LLVector3::z_axis - projected_vec(LLVector3::z_axis, local_camera_dir);
1449		z_axis_proj_camera.normVec();
1450		F32 x_axis_proj = llabs(local_scale_dir * x_axis_proj_camera);
1451		F32 y_axis_proj = llabs(local_scale_dir * y_axis_proj_camera);
1452		F32 z_axis_proj = llabs(local_scale_dir * z_axis_proj_camera);
1453
1454		if (x_axis_proj > y_axis_proj && x_axis_proj > z_axis_proj)
1455		{
1456			mSnapGuideDir1 = LLVector3::y_axis;
1457			mScaleSnapUnit2 = grid_scale.mV[VY];
1458			mSnapGuideDir2 = LLVector3::z_axis;
1459			mScaleSnapUnit1 = grid_scale.mV[VZ];
1460		}
1461		else if (y_axis_proj > z_axis_proj)
1462		{
1463			mSnapGuideDir1 = LLVector3::x_axis;
1464			mScaleSnapUnit2 = grid_scale.mV[VX];
1465			mSnapGuideDir2 = LLVector3::z_axis;
1466			mScaleSnapUnit1 = grid_scale.mV[VZ];
1467		}
1468		else
1469		{
1470			mSnapGuideDir1 = LLVector3::x_axis;
1471			mScaleSnapUnit2 = grid_scale.mV[VX];
1472			mSnapGuideDir2 = LLVector3::y_axis;
1473			mScaleSnapUnit1 = grid_scale.mV[VY];
1474		}
1475
1476		LLVector3 snap_guide_flip(1.f, 1.f, 1.f);
1477		switch (mManipPart)
1478		{
1479		case LL_CORNER_NNN:
1480			break;
1481		case LL_CORNER_NNP:
1482			snap_guide_flip.setVec(1.f, 1.f, -1.f);
1483			break;
1484		case LL_CORNER_NPN:
1485			snap_guide_flip.setVec(1.f, -1.f, 1.f);
1486			break;
1487		case LL_CORNER_NPP:
1488			snap_guide_flip.setVec(1.f, -1.f, -1.f);
1489			break;
1490		case LL_CORNER_PNN:
1491			snap_guide_flip.setVec(-1.f, 1.f, 1.f);
1492			break;
1493		case LL_CORNER_PNP:
1494			snap_guide_flip.setVec(-1.f, 1.f, -1.f);
1495			break;
1496		case LL_CORNER_PPN:
1497			snap_guide_flip.setVec(-1.f, -1.f, 1.f);
1498			break;
1499		case LL_CORNER_PPP:
1500			snap_guide_flip.setVec(-1.f, -1.f, -1.f);
1501			break;
1502		default:
1503			break;
1504		}
1505		mSnapGuideDir1.scaleVec(snap_guide_flip);
1506		mSnapGuideDir2.scaleVec(snap_guide_flip);
1507		mSnapGuideDir1.rotVec(bbox.getRotation());
1508		mSnapGuideDir2.rotVec(bbox.getRotation());
1509		mSnapDir1 = -1.f * mSnapGuideDir2;
1510		mSnapDir2 = -1.f * mSnapGuideDir1;
1511	}
1512
1513	mScalePlaneNormal1 = mSnapGuideDir1 % mScaleDir;
1514	mScalePlaneNormal1.normVec();
1515
1516	mScalePlaneNormal2 = mSnapGuideDir2 % mScaleDir;
1517	mScalePlaneNormal2.normVec();	
1518
1519	mScaleSnapUnit1 = mScaleSnapUnit1 / (mSnapDir1 * mScaleDir);
1520	mScaleSnapUnit2 = mScaleSnapUnit2 / (mSnapDir2 * mScaleDir);
1521}
1522
1523void LLManipScale::renderSnapGuides(const LLBBox& bbox)
1524{
1525	if (!gSavedSettings.getBOOL("SnapEnabled"))
1526	{
1527		return;
1528	}
1529
1530	F32 max_subdivisions = sGridMaxSubdivisionLevel;
1531	F32 grid_alpha = gSavedSettings.getF32("GridOpacity");
1532
1533	F32 max_point_on_scale_line = partToMaxScale(mManipPart, bbox);
1534	LLVector3 drag_point = gAgent.getPosAgentFromGlobal(mDragPointGlobal);
1535
1536	updateGridSettings();
1537
1538	S32 pass;
1539	for (pass = 0; pass < 3; pass++)
1540	{
1541		LLColor4 tick_color = setupSnapGuideRenderPass(pass);
1542
1543		gGL.begin(LLRender::LINES);
1544		LLVector3 line_mid = mScaleCenter + (mScaleSnapValue * mScaleDir) + (mSnapGuideDir1 * mSnapRegimeOffset);
1545		LLVector3 line_start = line_mid - (mScaleDir * (llmin(mScaleSnapValue, mSnapGuideLength * 0.5f)));
1546		LLVector3 line_end = line_mid + (mScaleDir * llmin(max_point_on_scale_line - mScaleSnapValue, mSnapGuideLength * 0.5f));
1547		
1548		gGL.color4f(tick_color.mV[VRED], tick_color.mV[VGREEN], tick_color.mV[VBLUE], tick_color.mV[VALPHA] * 0.1f);
1549		gGL.vertex3fv(line_start.mV);
1550		gGL.color4fv(tick_color.mV);
1551		gGL.vertex3fv(line_mid.mV);
1552		gGL.vertex3fv(line_mid.mV);
1553		gGL.color4f(tick_color.mV[VRED], tick_color.mV[VGREEN], tick_color.mV[VBLUE], tick_color.mV[VALPHA] * 0.1f);
1554		gGL.vertex3fv(line_end.mV);
1555
1556		line_mid = mScaleCenter + (mScaleSnapValue * mScaleDir) + (mSnapGuideDir2 * mSnapRegimeOffset);
1557		line_start = line_mid - (mScaleDir * (llmin(mScaleSnapValue, mSnapGuideLength * 0.5f)));
1558		line_end = line_mid + (mScaleDir * llmin(max_point_on_scale_line - mScaleSnapValue, 

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