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