PageRenderTime 37ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 0ms

/indra/newview/lltoolgrab.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 1142 lines | 782 code | 196 blank | 164 comment | 129 complexity | 21898364ba954ed73320744ec1b0c43f MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file lltoolgrab.cpp
  3. * @brief LLToolGrab 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 "lltoolgrab.h"
  28. // library headers
  29. #include "indra_constants.h" // for agent control flags
  30. #include "llviewercontrol.h"
  31. #include "llquaternion.h"
  32. #include "llbox.h"
  33. #include "message.h"
  34. #include "llview.h"
  35. #include "llfontgl.h"
  36. #include "llui.h"
  37. // newview headers
  38. #include "llagent.h"
  39. #include "llagentcamera.h"
  40. #include "lldrawable.h"
  41. #include "llfloatertools.h"
  42. #include "llhudeffect.h"
  43. #include "llhudmanager.h"
  44. #include "llregionposition.h"
  45. #include "llselectmgr.h"
  46. #include "llstatusbar.h"
  47. #include "lltoolmgr.h"
  48. #include "lltoolpie.h"
  49. #include "llviewercamera.h"
  50. #include "llviewerobject.h"
  51. #include "llviewerobjectlist.h"
  52. #include "llviewerregion.h"
  53. #include "llvoavatarself.h"
  54. #include "llworld.h"
  55. const S32 SLOP_DIST_SQ = 4;
  56. // Override modifier key behavior with these buttons
  57. BOOL gGrabBtnVertical = FALSE;
  58. BOOL gGrabBtnSpin = FALSE;
  59. LLTool* gGrabTransientTool = NULL;
  60. extern BOOL gDebugClicks;
  61. //
  62. // Methods
  63. //
  64. LLToolGrab::LLToolGrab( LLToolComposite* composite )
  65. : LLTool( std::string("Grab"), composite ),
  66. mMode( GRAB_INACTIVE ),
  67. mVerticalDragging( FALSE ),
  68. mHitLand(FALSE),
  69. mLastMouseX(0),
  70. mLastMouseY(0),
  71. mAccumDeltaX(0),
  72. mAccumDeltaY(0),
  73. mHasMoved( FALSE ),
  74. mOutsideSlop(FALSE),
  75. mDeselectedThisClick(FALSE),
  76. mLastFace(0),
  77. mSpinGrabbing( FALSE ),
  78. mSpinRotation(),
  79. mHideBuildHighlight(FALSE)
  80. { }
  81. LLToolGrab::~LLToolGrab()
  82. { }
  83. // virtual
  84. void LLToolGrab::handleSelect()
  85. {
  86. if(gFloaterTools)
  87. {
  88. // viewer can crash during startup if we don't check.
  89. gFloaterTools->setStatusText("grab");
  90. }
  91. gGrabBtnVertical = FALSE;
  92. gGrabBtnSpin = FALSE;
  93. }
  94. void LLToolGrab::handleDeselect()
  95. {
  96. if( hasMouseCapture() )
  97. {
  98. setMouseCapture( FALSE );
  99. }
  100. }
  101. BOOL LLToolGrab::handleDoubleClick(S32 x, S32 y, MASK mask)
  102. {
  103. if (gDebugClicks)
  104. {
  105. llinfos << "LLToolGrab handleDoubleClick (becoming mouseDown)" << llendl;
  106. }
  107. return FALSE;
  108. }
  109. BOOL LLToolGrab::handleMouseDown(S32 x, S32 y, MASK mask)
  110. {
  111. if (gDebugClicks)
  112. {
  113. llinfos << "LLToolGrab handleMouseDown" << llendl;
  114. }
  115. // call the base class to propogate info to sim
  116. LLTool::handleMouseDown(x, y, mask);
  117. if (!gAgent.leftButtonGrabbed())
  118. {
  119. // can grab transparent objects (how touch event propagates, scripters rely on this)
  120. gViewerWindow->pickAsync(x, y, mask, pickCallback, TRUE);
  121. }
  122. return TRUE;
  123. }
  124. void LLToolGrab::pickCallback(const LLPickInfo& pick_info)
  125. {
  126. LLToolGrab::getInstance()->mGrabPick = pick_info;
  127. LLViewerObject *objectp = pick_info.getObject();
  128. BOOL extend_select = (pick_info.mKeyMask & MASK_SHIFT);
  129. if (!extend_select && !LLSelectMgr::getInstance()->getSelection()->isEmpty())
  130. {
  131. LLSelectMgr::getInstance()->deselectAll();
  132. LLToolGrab::getInstance()->mDeselectedThisClick = TRUE;
  133. }
  134. else
  135. {
  136. LLToolGrab::getInstance()->mDeselectedThisClick = FALSE;
  137. }
  138. // if not over object, do nothing
  139. if (!objectp)
  140. {
  141. LLToolGrab::getInstance()->setMouseCapture(TRUE);
  142. LLToolGrab::getInstance()->mMode = GRAB_NOOBJECT;
  143. LLToolGrab::getInstance()->mGrabPick.mObjectID.setNull();
  144. }
  145. else
  146. {
  147. LLToolGrab::getInstance()->handleObjectHit(LLToolGrab::getInstance()->mGrabPick);
  148. }
  149. }
  150. BOOL LLToolGrab::handleObjectHit(const LLPickInfo& info)
  151. {
  152. mGrabPick = info;
  153. LLViewerObject* objectp = mGrabPick.getObject();
  154. if (gDebugClicks)
  155. {
  156. llinfos << "LLToolGrab handleObjectHit " << info.mMousePt.mX << "," << info.mMousePt.mY << llendl;
  157. }
  158. if (NULL == objectp) // unexpected
  159. {
  160. llwarns << "objectp was NULL; returning FALSE" << llendl;
  161. return FALSE;
  162. }
  163. if (objectp->isAvatar())
  164. {
  165. if (gGrabTransientTool)
  166. {
  167. gBasicToolset->selectTool( gGrabTransientTool );
  168. gGrabTransientTool = NULL;
  169. }
  170. return TRUE;
  171. }
  172. setMouseCapture( TRUE );
  173. // Grabs always start from the root
  174. // objectp = (LLViewerObject *)objectp->getRoot();
  175. LLViewerObject* parent = objectp->getRootEdit();
  176. BOOL script_touch = (objectp->flagHandleTouch()) || (parent && parent->flagHandleTouch());
  177. // Clicks on scripted or physical objects are temporary grabs, so
  178. // not "Build mode"
  179. mHideBuildHighlight = script_touch || objectp->usePhysics();
  180. if (!objectp->usePhysics())
  181. {
  182. if (script_touch)
  183. {
  184. mMode = GRAB_NONPHYSICAL; // if it has a script, use the non-physical grab
  185. }
  186. else
  187. {
  188. // In mouselook, we shouldn't be able to grab non-physical,
  189. // non-touchable objects. If it has a touch handler, we
  190. // do grab it (so llDetectedGrab works), but movement is
  191. // blocked on the server side. JC
  192. if (gAgentCamera.cameraMouselook())
  193. {
  194. mMode = GRAB_LOCKED;
  195. }
  196. else
  197. {
  198. mMode = GRAB_ACTIVE_CENTER;
  199. }
  200. gViewerWindow->hideCursor();
  201. gViewerWindow->moveCursorToCenter();
  202. }
  203. }
  204. else if( !objectp->permMove() )
  205. {
  206. // if mouse is over a physical object without move permission, show feedback if user tries to move it.
  207. mMode = GRAB_LOCKED;
  208. // Don't bail out here, go on and grab so buttons can get
  209. // their "touched" event.
  210. }
  211. else
  212. {
  213. // if mouse is over a physical object with move permission,
  214. // select it and enter "grab" mode (hiding cursor, etc.)
  215. mMode = GRAB_ACTIVE_CENTER;
  216. gViewerWindow->hideCursor();
  217. gViewerWindow->moveCursorToCenter();
  218. }
  219. // Always send "touched" message
  220. mLastMouseX = gViewerWindow->getCurrentMouseX();
  221. mLastMouseY = gViewerWindow->getCurrentMouseY();
  222. mAccumDeltaX = 0;
  223. mAccumDeltaY = 0;
  224. mHasMoved = FALSE;
  225. mOutsideSlop = FALSE;
  226. mVerticalDragging = (info.mKeyMask == MASK_VERTICAL) || gGrabBtnVertical;
  227. startGrab();
  228. if ((info.mKeyMask == MASK_SPIN) || gGrabBtnSpin)
  229. {
  230. startSpin();
  231. }
  232. LLSelectMgr::getInstance()->updateSelectionCenter(); // update selection beam
  233. // update point at
  234. LLViewerObject *edit_object = info.getObject();
  235. if (edit_object && info.mPickType != LLPickInfo::PICK_FLORA)
  236. {
  237. LLVector3 local_edit_point = gAgent.getPosAgentFromGlobal(info.mPosGlobal);
  238. local_edit_point -= edit_object->getPositionAgent();
  239. local_edit_point = local_edit_point * ~edit_object->getRenderRotation();
  240. gAgentCamera.setPointAt(POINTAT_TARGET_GRAB, edit_object, local_edit_point );
  241. gAgentCamera.setLookAt(LOOKAT_TARGET_SELECT, edit_object, local_edit_point );
  242. }
  243. // on transient grabs (clicks on world objects), kill the grab immediately
  244. if (!gViewerWindow->getLeftMouseDown()
  245. && gGrabTransientTool
  246. && (mMode == GRAB_NONPHYSICAL || mMode == GRAB_LOCKED))
  247. {
  248. gBasicToolset->selectTool( gGrabTransientTool );
  249. gGrabTransientTool = NULL;
  250. }
  251. return TRUE;
  252. }
  253. void LLToolGrab::startSpin()
  254. {
  255. LLViewerObject* objectp = mGrabPick.getObject();
  256. if (!objectp)
  257. {
  258. return;
  259. }
  260. mSpinGrabbing = TRUE;
  261. // Was saveSelectedObjectTransform()
  262. LLViewerObject *root = (LLViewerObject *)objectp->getRoot();
  263. mSpinRotation = root->getRotation();
  264. LLMessageSystem *msg = gMessageSystem;
  265. msg->newMessageFast(_PREHASH_ObjectSpinStart);
  266. msg->nextBlockFast(_PREHASH_AgentData);
  267. msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
  268. msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
  269. msg->nextBlockFast(_PREHASH_ObjectData);
  270. msg->addUUIDFast(_PREHASH_ObjectID, mGrabPick.mObjectID );
  271. msg->sendMessage( objectp->getRegion()->getHost() );
  272. }
  273. void LLToolGrab::stopSpin()
  274. {
  275. mSpinGrabbing = FALSE;
  276. LLViewerObject* objectp = mGrabPick.getObject();
  277. if (!objectp)
  278. {
  279. return;
  280. }
  281. LLMessageSystem *msg = gMessageSystem;
  282. switch(mMode)
  283. {
  284. case GRAB_ACTIVE_CENTER:
  285. case GRAB_NONPHYSICAL:
  286. case GRAB_LOCKED:
  287. msg->newMessageFast(_PREHASH_ObjectSpinStop);
  288. msg->nextBlockFast(_PREHASH_AgentData);
  289. msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
  290. msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
  291. msg->nextBlockFast(_PREHASH_ObjectData);
  292. msg->addUUIDFast(_PREHASH_ObjectID, objectp->getID() );
  293. msg->sendMessage( objectp->getRegion()->getHost() );
  294. break;
  295. case GRAB_NOOBJECT:
  296. case GRAB_INACTIVE:
  297. default:
  298. // do nothing
  299. break;
  300. }
  301. }
  302. void LLToolGrab::startGrab()
  303. {
  304. // Compute grab_offset in the OBJECT's root's coordinate frame
  305. // (sometimes root == object)
  306. LLViewerObject* objectp = mGrabPick.getObject();
  307. if (!objectp)
  308. {
  309. return;
  310. }
  311. LLViewerObject *root = (LLViewerObject *)objectp->getRoot();
  312. // drag from center
  313. LLVector3d grab_start_global = root->getPositionGlobal();
  314. // Where the grab starts, relative to the center of the root object of the set.
  315. // JC - This code looks wonky, but I believe it does the right thing.
  316. // Otherwise, when you grab a linked object set, it "pops" on the start
  317. // of the drag.
  318. LLVector3d grab_offsetd = root->getPositionGlobal() - objectp->getPositionGlobal();
  319. LLVector3 grab_offset;
  320. grab_offset.setVec(grab_offsetd);
  321. LLQuaternion rotation = root->getRotation();
  322. rotation.conjQuat();
  323. grab_offset = grab_offset * rotation;
  324. // This planar drag starts at the grab point
  325. mDragStartPointGlobal = grab_start_global;
  326. mDragStartFromCamera = grab_start_global - gAgentCamera.getCameraPositionGlobal();
  327. send_ObjectGrab_message(objectp, mGrabPick, grab_offset);
  328. mGrabOffsetFromCenterInitial = grab_offset;
  329. mGrabHiddenOffsetFromCamera = mDragStartFromCamera;
  330. mGrabTimer.reset();
  331. mLastUVCoords = mGrabPick.mUVCoords;
  332. mLastSTCoords = mGrabPick.mSTCoords;
  333. mLastFace = mGrabPick.mObjectFace;
  334. mLastIntersection = mGrabPick.mIntersection;
  335. mLastNormal = mGrabPick.mNormal;
  336. mLastBinormal = mGrabPick.mBinormal;
  337. mLastGrabPos = LLVector3(-1.f, -1.f, -1.f);
  338. }
  339. BOOL LLToolGrab::handleHover(S32 x, S32 y, MASK mask)
  340. {
  341. if (!gViewerWindow->getLeftMouseDown())
  342. {
  343. gViewerWindow->setCursor(UI_CURSOR_TOOLGRAB);
  344. setMouseCapture(FALSE);
  345. return TRUE;
  346. }
  347. // Do the right hover based on mode
  348. switch( mMode )
  349. {
  350. case GRAB_ACTIVE_CENTER:
  351. handleHoverActive( x, y, mask ); // cursor hidden
  352. break;
  353. case GRAB_NONPHYSICAL:
  354. handleHoverNonPhysical(x, y, mask);
  355. break;
  356. case GRAB_INACTIVE:
  357. handleHoverInactive( x, y, mask ); // cursor set here
  358. break;
  359. case GRAB_NOOBJECT:
  360. case GRAB_LOCKED:
  361. handleHoverFailed( x, y, mask );
  362. break;
  363. }
  364. mLastMouseX = x;
  365. mLastMouseY = y;
  366. return TRUE;
  367. }
  368. const F32 GRAB_SENSITIVITY_X = 0.0075f;
  369. const F32 GRAB_SENSITIVITY_Y = 0.0075f;
  370. // Dragging.
  371. void LLToolGrab::handleHoverActive(S32 x, S32 y, MASK mask)
  372. {
  373. LLViewerObject* objectp = mGrabPick.getObject();
  374. if (!objectp || !hasMouseCapture() ) return;
  375. if (objectp->isDead())
  376. {
  377. // Bail out of drag because object has been killed
  378. setMouseCapture(FALSE);
  379. return;
  380. }
  381. //--------------------------------------------------
  382. // Toggle spinning
  383. //--------------------------------------------------
  384. if (mSpinGrabbing && !(mask == MASK_SPIN) && !gGrabBtnSpin)
  385. {
  386. // user released ALT key, stop spinning
  387. stopSpin();
  388. }
  389. else if (!mSpinGrabbing && (mask == MASK_SPIN) )
  390. {
  391. // user pressed ALT key, start spinning
  392. startSpin();
  393. }
  394. //--------------------------------------------------
  395. // Toggle vertical dragging
  396. //--------------------------------------------------
  397. if (mVerticalDragging && !(mask == MASK_VERTICAL) && !gGrabBtnVertical)
  398. {
  399. // ...switch to horizontal dragging
  400. mVerticalDragging = FALSE;
  401. mDragStartPointGlobal = gViewerWindow->clickPointInWorldGlobal(x, y, objectp);
  402. mDragStartFromCamera = mDragStartPointGlobal - gAgentCamera.getCameraPositionGlobal();
  403. }
  404. else if (!mVerticalDragging && (mask == MASK_VERTICAL) )
  405. {
  406. // ...switch to vertical dragging
  407. mVerticalDragging = TRUE;
  408. mDragStartPointGlobal = gViewerWindow->clickPointInWorldGlobal(x, y, objectp);
  409. mDragStartFromCamera = mDragStartPointGlobal - gAgentCamera.getCameraPositionGlobal();
  410. }
  411. const F32 RADIANS_PER_PIXEL_X = 0.01f;
  412. const F32 RADIANS_PER_PIXEL_Y = 0.01f;
  413. S32 dx = x - (gViewerWindow->getWorldViewWidthScaled() / 2);
  414. S32 dy = y - (gViewerWindow->getWorldViewHeightScaled() / 2);
  415. if (dx != 0 || dy != 0)
  416. {
  417. mAccumDeltaX += dx;
  418. mAccumDeltaY += dy;
  419. S32 dist_sq = mAccumDeltaX * mAccumDeltaX + mAccumDeltaY * mAccumDeltaY;
  420. if (dist_sq > SLOP_DIST_SQ)
  421. {
  422. mOutsideSlop = TRUE;
  423. }
  424. // mouse has moved outside center
  425. mHasMoved = TRUE;
  426. if (mSpinGrabbing)
  427. {
  428. //------------------------------------------------------
  429. // Handle spinning
  430. //------------------------------------------------------
  431. // x motion maps to rotation around vertical axis
  432. LLVector3 up(0.f, 0.f, 1.f);
  433. LLQuaternion rotation_around_vertical( dx*RADIANS_PER_PIXEL_X, up );
  434. // y motion maps to rotation around left axis
  435. const LLVector3 &agent_left = LLViewerCamera::getInstance()->getLeftAxis();
  436. LLQuaternion rotation_around_left( dy*RADIANS_PER_PIXEL_Y, agent_left );
  437. // compose with current rotation
  438. mSpinRotation = mSpinRotation * rotation_around_vertical;
  439. mSpinRotation = mSpinRotation * rotation_around_left;
  440. // TODO: Throttle these
  441. LLMessageSystem *msg = gMessageSystem;
  442. msg->newMessageFast(_PREHASH_ObjectSpinUpdate);
  443. msg->nextBlockFast(_PREHASH_AgentData);
  444. msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
  445. msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
  446. msg->nextBlockFast(_PREHASH_ObjectData);
  447. msg->addUUIDFast(_PREHASH_ObjectID, objectp->getID() );
  448. msg->addQuatFast(_PREHASH_Rotation, mSpinRotation );
  449. msg->sendMessage( objectp->getRegion()->getHost() );
  450. }
  451. else
  452. {
  453. //------------------------------------------------------
  454. // Handle grabbing
  455. //------------------------------------------------------
  456. LLVector3d x_part;
  457. x_part.setVec(LLViewerCamera::getInstance()->getLeftAxis());
  458. x_part.mdV[VZ] = 0.0;
  459. x_part.normVec();
  460. LLVector3d y_part;
  461. if( mVerticalDragging )
  462. {
  463. y_part.setVec(LLViewerCamera::getInstance()->getUpAxis());
  464. // y_part.setVec(0.f, 0.f, 1.f);
  465. }
  466. else
  467. {
  468. // drag toward camera
  469. y_part = x_part % LLVector3d::z_axis;
  470. y_part.mdV[VZ] = 0.0;
  471. y_part.normVec();
  472. }
  473. mGrabHiddenOffsetFromCamera = mGrabHiddenOffsetFromCamera
  474. + (x_part * (-dx * GRAB_SENSITIVITY_X))
  475. + (y_part * ( dy * GRAB_SENSITIVITY_Y));
  476. // Send the message to the viewer.
  477. F32 dt = mGrabTimer.getElapsedTimeAndResetF32();
  478. U32 dt_milliseconds = (U32) (1000.f * dt);
  479. // need to return offset from mGrabStartPoint
  480. LLVector3d grab_point_global;
  481. grab_point_global = gAgentCamera.getCameraPositionGlobal() + mGrabHiddenOffsetFromCamera;
  482. /* Snap to grid disabled for grab tool - very confusing
  483. // Handle snapping to grid, but only when the tool is formally selected.
  484. BOOL snap_on = gSavedSettings.getBOOL("SnapEnabled");
  485. if (snap_on && !gGrabTransientTool)
  486. {
  487. F64 snap_size = gSavedSettings.getF32("GridResolution");
  488. U8 snap_dimensions = (mVerticalDragging ? 3 : 2);
  489. for (U8 i = 0; i < snap_dimensions; i++)
  490. {
  491. grab_point_global.mdV[i] += snap_size / 2;
  492. grab_point_global.mdV[i] -= fmod(grab_point_global.mdV[i], snap_size);
  493. }
  494. }
  495. */
  496. // Don't let object centers go underground.
  497. F32 land_height = LLWorld::getInstance()->resolveLandHeightGlobal(grab_point_global);
  498. if (grab_point_global.mdV[VZ] < land_height)
  499. {
  500. grab_point_global.mdV[VZ] = land_height;
  501. }
  502. // For safety, cap heights where objects can be dragged
  503. if (grab_point_global.mdV[VZ] > MAX_OBJECT_Z)
  504. {
  505. grab_point_global.mdV[VZ] = MAX_OBJECT_Z;
  506. }
  507. grab_point_global = LLWorld::getInstance()->clipToVisibleRegions(mDragStartPointGlobal, grab_point_global);
  508. // propagate constrained grab point back to grab offset
  509. mGrabHiddenOffsetFromCamera = grab_point_global - gAgentCamera.getCameraPositionGlobal();
  510. // Handle auto-rotation at screen edge.
  511. LLVector3 grab_pos_agent = gAgent.getPosAgentFromGlobal( grab_point_global );
  512. LLCoordGL grab_center_gl( gViewerWindow->getWorldViewWidthScaled() / 2, gViewerWindow->getWorldViewHeightScaled() / 2);
  513. LLViewerCamera::getInstance()->projectPosAgentToScreen(grab_pos_agent, grab_center_gl);
  514. const S32 ROTATE_H_MARGIN = gViewerWindow->getWorldViewWidthScaled() / 20;
  515. const F32 ROTATE_ANGLE_PER_SECOND = 30.f * DEG_TO_RAD;
  516. const F32 rotate_angle = ROTATE_ANGLE_PER_SECOND / gFPSClamped;
  517. // ...build mode moves camera about focus point
  518. if (grab_center_gl.mX < ROTATE_H_MARGIN)
  519. {
  520. if (gAgentCamera.getFocusOnAvatar())
  521. {
  522. gAgent.yaw(rotate_angle);
  523. }
  524. else
  525. {
  526. gAgentCamera.cameraOrbitAround(rotate_angle);
  527. }
  528. }
  529. else if (grab_center_gl.mX > gViewerWindow->getWorldViewWidthScaled() - ROTATE_H_MARGIN)
  530. {
  531. if (gAgentCamera.getFocusOnAvatar())
  532. {
  533. gAgent.yaw(-rotate_angle);
  534. }
  535. else
  536. {
  537. gAgentCamera.cameraOrbitAround(-rotate_angle);
  538. }
  539. }
  540. // Don't move above top of screen or below bottom
  541. if ((grab_center_gl.mY < gViewerWindow->getWorldViewHeightScaled() - 6)
  542. && (grab_center_gl.mY > 24))
  543. {
  544. // Transmit update to simulator
  545. LLVector3 grab_pos_region = objectp->getRegion()->getPosRegionFromGlobal( grab_point_global );
  546. LLMessageSystem *msg = gMessageSystem;
  547. msg->newMessageFast(_PREHASH_ObjectGrabUpdate);
  548. msg->nextBlockFast(_PREHASH_AgentData);
  549. msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
  550. msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
  551. msg->nextBlockFast(_PREHASH_ObjectData);
  552. msg->addUUIDFast(_PREHASH_ObjectID, objectp->getID() );
  553. msg->addVector3Fast(_PREHASH_GrabOffsetInitial, mGrabOffsetFromCenterInitial );
  554. msg->addVector3Fast(_PREHASH_GrabPosition, grab_pos_region );
  555. msg->addU32Fast(_PREHASH_TimeSinceLast, dt_milliseconds );
  556. msg->nextBlock("SurfaceInfo");
  557. msg->addVector3("UVCoord", LLVector3(mGrabPick.mUVCoords));
  558. msg->addVector3("STCoord", LLVector3(mGrabPick.mSTCoords));
  559. msg->addS32Fast(_PREHASH_FaceIndex, mGrabPick.mObjectFace);
  560. msg->addVector3("Position", mGrabPick.mIntersection);
  561. msg->addVector3("Normal", mGrabPick.mNormal);
  562. msg->addVector3("Binormal", mGrabPick.mBinormal);
  563. msg->sendMessage( objectp->getRegion()->getHost() );
  564. }
  565. }
  566. gViewerWindow->moveCursorToCenter();
  567. LLSelectMgr::getInstance()->updateSelectionCenter();
  568. }
  569. // once we've initiated a drag, lock the camera down
  570. if (mHasMoved)
  571. {
  572. if (!gAgentCamera.cameraMouselook() &&
  573. !objectp->isHUDAttachment() &&
  574. objectp->getRoot() == gAgentAvatarp->getRoot())
  575. {
  576. // force focus to point in space where we were looking previously
  577. gAgentCamera.setFocusGlobal(gAgentCamera.calcFocusPositionTargetGlobal(), LLUUID::null);
  578. gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE);
  579. }
  580. else
  581. {
  582. gAgentCamera.clearFocusObject();
  583. }
  584. }
  585. // HACK to avoid assert: error checking system makes sure that the cursor is set during every handleHover. This is actually a no-op since the cursor is hidden.
  586. gViewerWindow->setCursor(UI_CURSOR_ARROW);
  587. lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolGrab (active) [cursor hidden]" << llendl;
  588. }
  589. void LLToolGrab::handleHoverNonPhysical(S32 x, S32 y, MASK mask)
  590. {
  591. LLViewerObject* objectp = mGrabPick.getObject();
  592. if (!objectp || !hasMouseCapture() ) return;
  593. if (objectp->isDead())
  594. {
  595. // Bail out of drag because object has been killed
  596. setMouseCapture(FALSE);
  597. return;
  598. }
  599. LLPickInfo pick = mGrabPick;
  600. pick.mMousePt = LLCoordGL(x, y);
  601. pick.getSurfaceInfo();
  602. // compute elapsed time
  603. F32 dt = mGrabTimer.getElapsedTimeAndResetF32();
  604. U32 dt_milliseconds = (U32) (1000.f * dt);
  605. // i'm not a big fan of the following code - it's been culled from the physical grab case.
  606. // ideally these two would be nicely integrated - but the code in that method is a serious
  607. // mess of spaghetti. so here we go:
  608. LLVector3 grab_pos_region(0,0,0);
  609. const BOOL SUPPORT_LLDETECTED_GRAB = TRUE;
  610. if (SUPPORT_LLDETECTED_GRAB)
  611. {
  612. //--------------------------------------------------
  613. // Toggle vertical dragging
  614. //--------------------------------------------------
  615. if (mVerticalDragging && !(mask == MASK_VERTICAL) && !gGrabBtnVertical)
  616. {
  617. mVerticalDragging = FALSE;
  618. }
  619. else if (!mVerticalDragging && (mask == MASK_VERTICAL) )
  620. {
  621. mVerticalDragging = TRUE;
  622. }
  623. S32 dx = x - mLastMouseX;
  624. S32 dy = y - mLastMouseY;
  625. if (dx != 0 || dy != 0)
  626. {
  627. mAccumDeltaX += dx;
  628. mAccumDeltaY += dy;
  629. S32 dist_sq = mAccumDeltaX * mAccumDeltaX + mAccumDeltaY * mAccumDeltaY;
  630. if (dist_sq > SLOP_DIST_SQ)
  631. {
  632. mOutsideSlop = TRUE;
  633. }
  634. // mouse has moved
  635. mHasMoved = TRUE;
  636. //------------------------------------------------------
  637. // Handle grabbing
  638. //------------------------------------------------------
  639. LLVector3d x_part;
  640. x_part.setVec(LLViewerCamera::getInstance()->getLeftAxis());
  641. x_part.mdV[VZ] = 0.0;
  642. x_part.normVec();
  643. LLVector3d y_part;
  644. if( mVerticalDragging )
  645. {
  646. y_part.setVec(LLViewerCamera::getInstance()->getUpAxis());
  647. // y_part.setVec(0.f, 0.f, 1.f);
  648. }
  649. else
  650. {
  651. // drag toward camera
  652. y_part = x_part % LLVector3d::z_axis;
  653. y_part.mdV[VZ] = 0.0;
  654. y_part.normVec();
  655. }
  656. mGrabHiddenOffsetFromCamera = mGrabHiddenOffsetFromCamera
  657. + (x_part * (-dx * GRAB_SENSITIVITY_X))
  658. + (y_part * ( dy * GRAB_SENSITIVITY_Y));
  659. }
  660. // need to return offset from mGrabStartPoint
  661. LLVector3d grab_point_global = gAgentCamera.getCameraPositionGlobal() + mGrabHiddenOffsetFromCamera;
  662. grab_pos_region = objectp->getRegion()->getPosRegionFromGlobal( grab_point_global );
  663. }
  664. // only send message if something has changed since last message
  665. BOOL changed_since_last_update = FALSE;
  666. // test if touch data needs to be updated
  667. if ((pick.mObjectFace != mLastFace) ||
  668. (pick.mUVCoords != mLastUVCoords) ||
  669. (pick.mSTCoords != mLastSTCoords) ||
  670. (pick.mIntersection != mLastIntersection) ||
  671. (pick.mNormal != mLastNormal) ||
  672. (pick.mBinormal != mLastBinormal) ||
  673. (grab_pos_region != mLastGrabPos))
  674. {
  675. changed_since_last_update = TRUE;
  676. }
  677. if (changed_since_last_update)
  678. {
  679. LLMessageSystem *msg = gMessageSystem;
  680. msg->newMessageFast(_PREHASH_ObjectGrabUpdate);
  681. msg->nextBlockFast(_PREHASH_AgentData);
  682. msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
  683. msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
  684. msg->nextBlockFast(_PREHASH_ObjectData);
  685. msg->addUUIDFast(_PREHASH_ObjectID, objectp->getID() );
  686. msg->addVector3Fast(_PREHASH_GrabOffsetInitial, mGrabOffsetFromCenterInitial );
  687. msg->addVector3Fast(_PREHASH_GrabPosition, grab_pos_region );
  688. msg->addU32Fast(_PREHASH_TimeSinceLast, dt_milliseconds );
  689. msg->nextBlock("SurfaceInfo");
  690. msg->addVector3("UVCoord", LLVector3(pick.mUVCoords));
  691. msg->addVector3("STCoord", LLVector3(pick.mSTCoords));
  692. msg->addS32Fast(_PREHASH_FaceIndex, pick.mObjectFace);
  693. msg->addVector3("Position", pick.mIntersection);
  694. msg->addVector3("Normal", pick.mNormal);
  695. msg->addVector3("Binormal", pick.mBinormal);
  696. msg->sendMessage( objectp->getRegion()->getHost() );
  697. mLastUVCoords = pick.mUVCoords;
  698. mLastSTCoords = pick.mSTCoords;
  699. mLastFace = pick.mObjectFace;
  700. mLastIntersection = pick.mIntersection;
  701. mLastNormal= pick.mNormal;
  702. mLastBinormal= pick.mBinormal;
  703. mLastGrabPos = grab_pos_region;
  704. }
  705. // update point-at / look-at
  706. if (pick.mObjectFace != -1) // if the intersection was on the surface of the obejct
  707. {
  708. LLVector3 local_edit_point = pick.mIntersection;
  709. local_edit_point -= objectp->getPositionAgent();
  710. local_edit_point = local_edit_point * ~objectp->getRenderRotation();
  711. gAgentCamera.setPointAt(POINTAT_TARGET_GRAB, objectp, local_edit_point );
  712. gAgentCamera.setLookAt(LOOKAT_TARGET_SELECT, objectp, local_edit_point );
  713. }
  714. gViewerWindow->setCursor(UI_CURSOR_HAND);
  715. }
  716. // Not dragging. Just showing affordances
  717. void LLToolGrab::handleHoverInactive(S32 x, S32 y, MASK mask)
  718. {
  719. // JC - TODO - change cursor based on gGrabBtnVertical, gGrabBtnSpin
  720. lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolGrab (inactive-not over editable object)" << llendl;
  721. gViewerWindow->setCursor(UI_CURSOR_TOOLGRAB);
  722. }
  723. // User is trying to do something that's not allowed.
  724. void LLToolGrab::handleHoverFailed(S32 x, S32 y, MASK mask)
  725. {
  726. if( GRAB_NOOBJECT == mMode )
  727. {
  728. gViewerWindow->setCursor(UI_CURSOR_NO);
  729. lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolGrab (not on object)" << llendl;
  730. }
  731. else
  732. {
  733. S32 dist_sq = (x-mGrabPick.mMousePt.mX) * (x-mGrabPick.mMousePt.mX) + (y-mGrabPick.mMousePt.mY) * (y-mGrabPick.mMousePt.mY);
  734. if( mOutsideSlop || dist_sq > SLOP_DIST_SQ )
  735. {
  736. mOutsideSlop = TRUE;
  737. switch( mMode )
  738. {
  739. case GRAB_LOCKED:
  740. gViewerWindow->setCursor(UI_CURSOR_GRABLOCKED);
  741. lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolGrab (grab failed, no move permission)" << llendl;
  742. break;
  743. // Non physical now handled by handleHoverActive - CRO
  744. // case GRAB_NONPHYSICAL:
  745. // gViewerWindow->setCursor(UI_CURSOR_ARROW);
  746. // lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolGrab (grab failed, nonphysical)" << llendl;
  747. // break;
  748. default:
  749. llassert(0);
  750. }
  751. }
  752. else
  753. {
  754. gViewerWindow->setCursor(UI_CURSOR_ARROW);
  755. lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolGrab (grab failed but within slop)" << llendl;
  756. }
  757. }
  758. }
  759. BOOL LLToolGrab::handleMouseUp(S32 x, S32 y, MASK mask)
  760. {
  761. // call the base class to propogate info to sim
  762. LLTool::handleMouseUp(x, y, mask);
  763. if( hasMouseCapture() )
  764. {
  765. setMouseCapture( FALSE );
  766. }
  767. mMode = GRAB_INACTIVE;
  768. // HACK: Make some grabs temporary
  769. if (gGrabTransientTool)
  770. {
  771. gBasicToolset->selectTool( gGrabTransientTool );
  772. gGrabTransientTool = NULL;
  773. }
  774. //gAgent.setObjectTracking(gSavedSettings.getBOOL("TrackFocusObject"));
  775. return TRUE;
  776. }
  777. void LLToolGrab::stopEditing()
  778. {
  779. if( hasMouseCapture() )
  780. {
  781. setMouseCapture( FALSE );
  782. }
  783. }
  784. void LLToolGrab::onMouseCaptureLost()
  785. {
  786. LLViewerObject* objectp = mGrabPick.getObject();
  787. if (!objectp)
  788. {
  789. gViewerWindow->showCursor();
  790. return;
  791. }
  792. // First, fix cursor placement
  793. if( !gAgentCamera.cameraMouselook()
  794. && (GRAB_ACTIVE_CENTER == mMode))
  795. {
  796. if (objectp->isHUDAttachment())
  797. {
  798. // ...move cursor "naturally", as if it had moved when hidden
  799. S32 x = mGrabPick.mMousePt.mX + mAccumDeltaX;
  800. S32 y = mGrabPick.mMousePt.mY + mAccumDeltaY;
  801. LLUI::setMousePositionScreen(x, y);
  802. }
  803. else if (mHasMoved)
  804. {
  805. // ...move cursor back to the center of the object
  806. LLVector3 grab_point_agent = objectp->getRenderPosition();
  807. LLCoordGL gl_point;
  808. if (LLViewerCamera::getInstance()->projectPosAgentToScreen(grab_point_agent, gl_point))
  809. {
  810. LLUI::setMousePositionScreen(gl_point.mX, gl_point.mY);
  811. }
  812. }
  813. else
  814. {
  815. // ...move cursor back to click position
  816. LLUI::setMousePositionScreen(mGrabPick.mMousePt.mX, mGrabPick.mMousePt.mY);
  817. }
  818. gViewerWindow->showCursor();
  819. }
  820. stopGrab();
  821. if (mSpinGrabbing)
  822. stopSpin();
  823. mMode = GRAB_INACTIVE;
  824. mHideBuildHighlight = FALSE;
  825. mGrabPick.mObjectID.setNull();
  826. LLSelectMgr::getInstance()->updateSelectionCenter();
  827. gAgentCamera.setPointAt(POINTAT_TARGET_CLEAR);
  828. gAgentCamera.setLookAt(LOOKAT_TARGET_CLEAR);
  829. dialog_refresh_all();
  830. }
  831. void LLToolGrab::stopGrab()
  832. {
  833. LLViewerObject* objectp = mGrabPick.getObject();
  834. if (!objectp)
  835. {
  836. return;
  837. }
  838. LLPickInfo pick = mGrabPick;
  839. if (mMode == GRAB_NONPHYSICAL)
  840. {
  841. // for non-physical (touch) grabs,
  842. // gather surface info for this degrab (mouse-up)
  843. S32 x = gViewerWindow->getCurrentMouseX();
  844. S32 y = gViewerWindow->getCurrentMouseY();
  845. pick.mMousePt = LLCoordGL(x, y);
  846. pick.getSurfaceInfo();
  847. }
  848. // Next, send messages to simulator
  849. switch(mMode)
  850. {
  851. case GRAB_ACTIVE_CENTER:
  852. case GRAB_NONPHYSICAL:
  853. case GRAB_LOCKED:
  854. send_ObjectDeGrab_message(objectp, pick);
  855. mVerticalDragging = FALSE;
  856. break;
  857. case GRAB_NOOBJECT:
  858. case GRAB_INACTIVE:
  859. default:
  860. // do nothing
  861. break;
  862. }
  863. mHideBuildHighlight = FALSE;
  864. }
  865. void LLToolGrab::draw()
  866. { }
  867. void LLToolGrab::render()
  868. { }
  869. BOOL LLToolGrab::isEditing()
  870. {
  871. return (mGrabPick.getObject().notNull());
  872. }
  873. LLViewerObject* LLToolGrab::getEditingObject()
  874. {
  875. return mGrabPick.getObject();
  876. }
  877. LLVector3d LLToolGrab::getEditingPointGlobal()
  878. {
  879. return getGrabPointGlobal();
  880. }
  881. LLVector3d LLToolGrab::getGrabPointGlobal()
  882. {
  883. switch(mMode)
  884. {
  885. case GRAB_ACTIVE_CENTER:
  886. case GRAB_NONPHYSICAL:
  887. case GRAB_LOCKED:
  888. return gAgentCamera.getCameraPositionGlobal() + mGrabHiddenOffsetFromCamera;
  889. case GRAB_NOOBJECT:
  890. case GRAB_INACTIVE:
  891. default:
  892. return gAgent.getPositionGlobal();
  893. }
  894. }
  895. void send_ObjectGrab_message(LLViewerObject* object, const LLPickInfo & pick, const LLVector3 &grab_offset)
  896. {
  897. if (!object) return;
  898. LLMessageSystem *msg = gMessageSystem;
  899. msg->newMessageFast(_PREHASH_ObjectGrab);
  900. msg->nextBlockFast( _PREHASH_AgentData);
  901. msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
  902. msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
  903. msg->nextBlockFast( _PREHASH_ObjectData);
  904. msg->addU32Fast( _PREHASH_LocalID, object->mLocalID);
  905. msg->addVector3Fast(_PREHASH_GrabOffset, grab_offset);
  906. msg->nextBlock("SurfaceInfo");
  907. msg->addVector3("UVCoord", LLVector3(pick.mUVCoords));
  908. msg->addVector3("STCoord", LLVector3(pick.mSTCoords));
  909. msg->addS32Fast(_PREHASH_FaceIndex, pick.mObjectFace);
  910. msg->addVector3("Position", pick.mIntersection);
  911. msg->addVector3("Normal", pick.mNormal);
  912. msg->addVector3("Binormal", pick.mBinormal);
  913. msg->sendMessage( object->getRegion()->getHost());
  914. /* Diagnostic code
  915. llinfos << "mUVCoords: " << pick.mUVCoords
  916. << ", mSTCoords: " << pick.mSTCoords
  917. << ", mObjectFace: " << pick.mObjectFace
  918. << ", mIntersection: " << pick.mIntersection
  919. << ", mNormal: " << pick.mNormal
  920. << ", mBinormal: " << pick.mBinormal
  921. << llendl;
  922. llinfos << "Avatar pos: " << gAgent.getPositionAgent() << llendl;
  923. llinfos << "Object pos: " << object->getPosition() << llendl;
  924. */
  925. }
  926. void send_ObjectDeGrab_message(LLViewerObject* object, const LLPickInfo & pick)
  927. {
  928. if (!object) return;
  929. LLMessageSystem *msg = gMessageSystem;
  930. msg->newMessageFast(_PREHASH_ObjectDeGrab);
  931. msg->nextBlockFast(_PREHASH_AgentData);
  932. msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
  933. msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
  934. msg->nextBlockFast(_PREHASH_ObjectData);
  935. msg->addU32Fast(_PREHASH_LocalID, object->mLocalID);
  936. msg->nextBlock("SurfaceInfo");
  937. msg->addVector3("UVCoord", LLVector3(pick.mUVCoords));
  938. msg->addVector3("STCoord", LLVector3(pick.mSTCoords));
  939. msg->addS32Fast(_PREHASH_FaceIndex, pick.mObjectFace);
  940. msg->addVector3("Position", pick.mIntersection);
  941. msg->addVector3("Normal", pick.mNormal);
  942. msg->addVector3("Binormal", pick.mBinormal);
  943. msg->sendMessage(object->getRegion()->getHost());
  944. }