PageRenderTime 61ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/indra/newview/llmaniprotate.cpp

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