llmanipscale.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:65k
源码类别:

游戏引擎

开发平台:

C++ Builder

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