/indra/newview/llmaniptranslate.cpp
C++ | 2007 lines | 1604 code | 278 blank | 125 comment | 239 complexity | e78d1541749553c330ad50f9c1a0bab2 MD5 | raw file
Possible License(s): LGPL-2.1
Large files files are truncated, but you can click here to view the full file
1/** 2 * @file llmaniptranslate.cpp 3 * @brief LLManipTranslate 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 27/** 28 * Positioning tool 29 */ 30 31#include "llviewerprecompiledheaders.h" 32 33#include "llmaniptranslate.h" 34 35#include "llgl.h" 36#include "llrender.h" 37 38#include "llagent.h" 39#include "llagentcamera.h" 40#include "llbbox.h" 41#include "llbox.h" 42#include "llviewercontrol.h" 43#include "llcriticaldamp.h" 44#include "llcylinder.h" 45#include "lldrawable.h" 46#include "llfloatertools.h" 47#include "llfontgl.h" 48#include "llglheaders.h" 49#include "llhudrender.h" 50#include "llresmgr.h" 51#include "llselectmgr.h" 52#include "llrendersphere.h" 53#include "llstatusbar.h" 54#include "lltoolmgr.h" 55#include "llviewercamera.h" 56#include "llviewerjoint.h" 57#include "llviewerobject.h" 58#include "llviewerwindow.h" 59#include "llvoavatarself.h" 60#include "llworld.h" 61#include "llui.h" 62#include "pipeline.h" 63 64const S32 NUM_AXES = 3; 65const S32 MOUSE_DRAG_SLOP = 2; // pixels 66const F32 HANDLE_HIDE_ANGLE = 0.15f; // radians 67const F32 SELECTED_ARROW_SCALE = 1.3f; 68const F32 MANIPULATOR_HOTSPOT_START = 0.2f; 69const F32 MANIPULATOR_HOTSPOT_END = 1.2f; 70const F32 SNAP_GUIDE_SCREEN_SIZE = 0.7f; 71const F32 MIN_PLANE_MANIP_DOT_PRODUCT = 0.25f; 72const F32 PLANE_TICK_SIZE = 0.4f; 73const F32 MANIPULATOR_SCALE_HALF_LIFE = 0.07f; 74const F32 SNAP_ARROW_SCALE = 0.7f; 75 76static LLPointer<LLViewerTexture> sGridTex = NULL ; 77 78const LLManip::EManipPart MANIPULATOR_IDS[9] = 79{ 80 LLManip::LL_X_ARROW, 81 LLManip::LL_Y_ARROW, 82 LLManip::LL_Z_ARROW, 83 LLManip::LL_X_ARROW, 84 LLManip::LL_Y_ARROW, 85 LLManip::LL_Z_ARROW, 86 LLManip::LL_YZ_PLANE, 87 LLManip::LL_XZ_PLANE, 88 LLManip::LL_XY_PLANE 89}; 90 91const U32 ARROW_TO_AXIS[4] = 92{ 93 VX, 94 VX, 95 VY, 96 VZ 97}; 98 99// Sort manipulator handles by their screen-space projection 100struct ClosestToCamera 101{ 102 bool operator()(const LLManipTranslate::ManipulatorHandle& a, 103 const LLManipTranslate::ManipulatorHandle& b) const 104 { 105 return a.mEndPosition.mV[VZ] < b.mEndPosition.mV[VZ]; 106 } 107}; 108 109LLManipTranslate::LLManipTranslate( LLToolComposite* composite ) 110: LLManip( std::string("Move"), composite ), 111 mLastHoverMouseX(-1), 112 mLastHoverMouseY(-1), 113 mSendUpdateOnMouseUp(FALSE), 114 mMouseOutsideSlop(FALSE), 115 mCopyMadeThisDrag(FALSE), 116 mMouseDownX(-1), 117 mMouseDownY(-1), 118 mAxisArrowLength(50), 119 mConeSize(0), 120 mArrowLengthMeters(0.f), 121 mGridSizeMeters(1.f), 122 mPlaneManipOffsetMeters(0.f), 123 mUpdateTimer(), 124 mSnapOffsetMeters(0.f), 125 mSubdivisions(10.f), 126 mInSnapRegime(FALSE), 127 mSnapped(FALSE), 128 mArrowScales(1.f, 1.f, 1.f), 129 mPlaneScales(1.f, 1.f, 1.f), 130 mPlaneManipPositions(1.f, 1.f, 1.f, 1.f) 131{ 132 if (sGridTex.isNull()) 133 { 134 restoreGL(); 135 } 136} 137 138//static 139U32 LLManipTranslate::getGridTexName() 140{ 141 if(sGridTex.isNull()) 142 { 143 restoreGL() ; 144 } 145 146 return sGridTex.isNull() ? 0 : sGridTex->getTexName() ; 147} 148 149//static 150void LLManipTranslate::destroyGL() 151{ 152 if (sGridTex) 153 { 154 sGridTex = NULL ; 155 } 156} 157 158//static 159void LLManipTranslate::restoreGL() 160{ 161 //generate grid texture 162 U32 rez = 512; 163 U32 mip = 0; 164 165 destroyGL() ; 166 sGridTex = LLViewerTextureManager::getLocalTexture() ; 167 if(!sGridTex->createGLTexture()) 168 { 169 sGridTex = NULL ; 170 return ; 171 } 172 173 GLuint* d = new GLuint[rez*rez]; 174 175 gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, sGridTex->getTexName(), true); 176 gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_TRILINEAR); 177 178 while (rez >= 1) 179 { 180 for (U32 i = 0; i < rez*rez; i++) 181 { 182 d[i] = 0x00FFFFFF; 183 } 184 185 U32 subcol = 0xFFFFFFFF; 186 if (rez >= 4) 187 { //large grain grid 188 for (U32 i = 0; i < rez; i++) 189 { 190 if (rez <= 16) 191 { 192 if (rez == 16) 193 { 194 subcol = 0xA0FFFFFF; 195 } 196 else if (rez == 8) 197 { 198 subcol = 0x80FFFFFF; 199 } 200 else 201 { 202 subcol = 0x40FFFFFF; 203 } 204 } 205 else 206 { 207 subcol = 0xFFFFFFFF; 208 } 209 d[i *rez+ 0 ] = subcol; 210 d[0 *rez+ i ] = subcol; 211 if (rez >= 32) 212 { 213 d[i *rez+ (rez-1)] = subcol; 214 d[(rez-1) *rez+ i ] = subcol; 215 } 216 217 if (rez >= 64) 218 { 219 subcol = 0xFFFFFFFF; 220 221 if (i > 0 && i < (rez-1)) 222 { 223 d[i *rez+ 1 ] = subcol; 224 d[i *rez+ (rez-2)] = subcol; 225 d[1 *rez+ i ] = subcol; 226 d[(rez-2) *rez+ i ] = subcol; 227 } 228 } 229 } 230 } 231 232 subcol = 0x50A0A0A0; 233 if (rez >= 128) 234 { //small grain grid 235 for (U32 i = 8; i < rez; i+=8) 236 { 237 for (U32 j = 2; j < rez-2; j++) 238 { 239 d[i *rez+ j] = subcol; 240 d[j *rez+ i] = subcol; 241 } 242 } 243 } 244 if (rez >= 64) 245 { //medium grain grid 246 if (rez == 64) 247 { 248 subcol = 0x50A0A0A0; 249 } 250 else 251 { 252 subcol = 0xA0D0D0D0; 253 } 254 255 for (U32 i = 32; i < rez; i+=32) 256 { 257 U32 pi = i-1; 258 for (U32 j = 2; j < rez-2; j++) 259 { 260 d[i *rez+ j] = subcol; 261 d[j *rez+ i] = subcol; 262 263 if (rez > 128) 264 { 265 d[pi *rez+ j] = subcol; 266 d[j *rez+ pi] = subcol; 267 } 268 } 269 } 270 } 271#ifdef LL_WINDOWS 272 LLImageGL::setManualImage(GL_TEXTURE_2D, mip, GL_RGBA, rez, rez, GL_RGBA, GL_UNSIGNED_BYTE, d); 273#else 274 LLImageGL::setManualImage(GL_TEXTURE_2D, mip, GL_RGBA, rez, rez, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, d); 275#endif 276 rez = rez >> 1; 277 mip++; 278 } 279 delete [] d; 280} 281 282 283LLManipTranslate::~LLManipTranslate() 284{ 285} 286 287 288void LLManipTranslate::handleSelect() 289{ 290 LLSelectMgr::getInstance()->saveSelectedObjectTransform(SELECT_ACTION_TYPE_PICK); 291 gFloaterTools->setStatusText("move"); 292 LLManip::handleSelect(); 293} 294 295BOOL LLManipTranslate::handleMouseDown(S32 x, S32 y, MASK mask) 296{ 297 BOOL handled = FALSE; 298 299 // didn't click in any UI object, so must have clicked in the world 300 if( (mHighlightedPart == LL_X_ARROW || 301 mHighlightedPart == LL_Y_ARROW || 302 mHighlightedPart == LL_Z_ARROW || 303 mHighlightedPart == LL_YZ_PLANE || 304 mHighlightedPart == LL_XZ_PLANE || 305 mHighlightedPart == LL_XY_PLANE ) ) 306 { 307 handled = handleMouseDownOnPart( x, y, mask ); 308 } 309 310 return handled; 311} 312 313// Assumes that one of the arrows on an object was hit. 314BOOL LLManipTranslate::handleMouseDownOnPart( S32 x, S32 y, MASK mask ) 315{ 316 BOOL can_move = canAffectSelection(); 317 if (!can_move) 318 { 319 return FALSE; 320 } 321 322 highlightManipulators(x, y); 323 S32 hit_part = mHighlightedPart; 324 325 if( (hit_part != LL_X_ARROW) && 326 (hit_part != LL_Y_ARROW) && 327 (hit_part != LL_Z_ARROW) && 328 (hit_part != LL_YZ_PLANE) && 329 (hit_part != LL_XZ_PLANE) && 330 (hit_part != LL_XY_PLANE) ) 331 { 332 return TRUE; 333 } 334 335 mHelpTextTimer.reset(); 336 sNumTimesHelpTextShown++; 337 338 LLSelectMgr::getInstance()->getGrid(mGridOrigin, mGridRotation, mGridScale); 339 340 LLSelectMgr::getInstance()->enableSilhouette(FALSE); 341 342 // we just started a drag, so save initial object positions 343 LLSelectMgr::getInstance()->saveSelectedObjectTransform(SELECT_ACTION_TYPE_MOVE); 344 345 mManipPart = (EManipPart)hit_part; 346 mMouseDownX = x; 347 mMouseDownY = y; 348 mMouseOutsideSlop = FALSE; 349 350 LLVector3 axis; 351 352 LLSelectNode *selectNode = mObjectSelection->getFirstMoveableNode(TRUE); 353 354 if (!selectNode) 355 { 356 // didn't find the object in our selection...oh well 357 llwarns << "Trying to translate an unselected object" << llendl; 358 return TRUE; 359 } 360 361 LLViewerObject *selected_object = selectNode->getObject(); 362 if (!selected_object) 363 { 364 // somehow we lost the object! 365 llwarns << "Translate manip lost the object, no selected object" << llendl; 366 gViewerWindow->setCursor(UI_CURSOR_TOOLTRANSLATE); 367 return TRUE; 368 } 369 370 // Compute unit vectors for arrow hit and a plane through that vector 371 BOOL axis_exists = getManipAxis(selected_object, mManipPart, axis); 372 getManipNormal(selected_object, mManipPart, mManipNormal); 373 374 //LLVector3 select_center_agent = gAgent.getPosAgentFromGlobal(LLSelectMgr::getInstance()->getSelectionCenterGlobal()); 375 // TomY: The above should (?) be identical to the below 376 LLVector3 select_center_agent = getPivotPoint(); 377 mSubdivisions = llclamp(getSubdivisionLevel(select_center_agent, axis_exists ? axis : LLVector3::z_axis, getMinGridScale()), sGridMinSubdivisionLevel, sGridMaxSubdivisionLevel); 378 379 // if we clicked on a planar manipulator, recenter mouse cursor 380 if (mManipPart >= LL_YZ_PLANE && mManipPart <= LL_XY_PLANE) 381 { 382 LLCoordGL mouse_pos; 383 if (!LLViewerCamera::getInstance()->projectPosAgentToScreen(select_center_agent, mouse_pos)) 384 { 385 // mouse_pos may be nonsense 386 llwarns << "Failed to project object center to screen" << llendl; 387 } 388 else if (gSavedSettings.getBOOL("SnapToMouseCursor")) 389 { 390 LLUI::setMousePositionScreen(mouse_pos.mX, mouse_pos.mY); 391 x = mouse_pos.mX; 392 y = mouse_pos.mY; 393 } 394 } 395 396 LLSelectMgr::getInstance()->updateSelectionCenter(); 397 LLVector3d object_start_global = gAgent.getPosGlobalFromAgent(getPivotPoint()); 398 getMousePointOnPlaneGlobal(mDragCursorStartGlobal, x, y, object_start_global, mManipNormal); 399 mDragSelectionStartGlobal = object_start_global; 400 mCopyMadeThisDrag = FALSE; 401 402 // Route future Mouse messages here preemptively. (Release on mouse up.) 403 setMouseCapture( TRUE ); 404 405 return TRUE; 406} 407 408BOOL LLManipTranslate::handleHover(S32 x, S32 y, MASK mask) 409{ 410 // Translation tool only works if mouse button is down. 411 // Bail out if mouse not down. 412 if( !hasMouseCapture() ) 413 { 414 lldebugst(LLERR_USER_INPUT) << "hover handled by LLManipTranslate (inactive)" << llendl; 415 // Always show cursor 416 // gViewerWindow->setCursor(UI_CURSOR_ARROW); 417 gViewerWindow->setCursor(UI_CURSOR_TOOLTRANSLATE); 418 419 highlightManipulators(x, y); 420 return TRUE; 421 } 422 423 // Handle auto-rotation if necessary. 424 LLRect world_rect = gViewerWindow->getWorldViewRectScaled(); 425 const F32 ROTATE_ANGLE_PER_SECOND = 30.f * DEG_TO_RAD; 426 const S32 ROTATE_H_MARGIN = world_rect.getWidth() / 20; 427 const F32 rotate_angle = ROTATE_ANGLE_PER_SECOND / gFPSClamped; 428 BOOL rotated = FALSE; 429 430 // ...build mode moves camera about focus point 431 if (mObjectSelection->getSelectType() != SELECT_TYPE_HUD) 432 { 433 if (x < ROTATE_H_MARGIN) 434 { 435 gAgentCamera.cameraOrbitAround(rotate_angle); 436 rotated = TRUE; 437 } 438 else if (x > world_rect.getWidth() - ROTATE_H_MARGIN) 439 { 440 gAgentCamera.cameraOrbitAround(-rotate_angle); 441 rotated = TRUE; 442 } 443 } 444 445 // Suppress processing if mouse hasn't actually moved. 446 // This may cause problems if the camera moves outside of the 447 // rotation above. 448 if( x == mLastHoverMouseX && y == mLastHoverMouseY && !rotated) 449 { 450 lldebugst(LLERR_USER_INPUT) << "hover handled by LLManipTranslate (mouse unmoved)" << llendl; 451 gViewerWindow->setCursor(UI_CURSOR_TOOLTRANSLATE); 452 return TRUE; 453 } 454 mLastHoverMouseX = x; 455 mLastHoverMouseY = y; 456 457 // Suppress if mouse hasn't moved past the initial slop region 458 // Reset once we start moving 459 if( !mMouseOutsideSlop ) 460 { 461 if (abs(mMouseDownX - x) < MOUSE_DRAG_SLOP && abs(mMouseDownY - y) < MOUSE_DRAG_SLOP ) 462 { 463 lldebugst(LLERR_USER_INPUT) << "hover handled by LLManipTranslate (mouse inside slop)" << llendl; 464 gViewerWindow->setCursor(UI_CURSOR_TOOLTRANSLATE); 465 return TRUE; 466 } 467 else 468 { 469 // ...just went outside the slop region 470 mMouseOutsideSlop = TRUE; 471 // If holding down shift, leave behind a copy. 472 if (mask == MASK_COPY) 473 { 474 // ...we're trying to make a copy 475 LLSelectMgr::getInstance()->selectDuplicate(LLVector3::zero, FALSE); 476 mCopyMadeThisDrag = TRUE; 477 478 // When we make the copy, we don't want to do any other processing. 479 // If so, the object will also be moved, and the copy will be offset. 480 lldebugst(LLERR_USER_INPUT) << "hover handled by LLManipTranslate (made copy)" << llendl; 481 gViewerWindow->setCursor(UI_CURSOR_TOOLTRANSLATE); 482 } 483 } 484 } 485 486 // Throttle updates to 10 per second. 487 BOOL send_update = FALSE; 488 489 LLVector3 axis_f; 490 LLVector3d axis_d; 491 492 // pick the first object to constrain to grid w/ common origin 493 // this is so we don't screw up groups 494 LLSelectNode* selectNode = mObjectSelection->getFirstMoveableNode(TRUE); 495 if (!selectNode) 496 { 497 // somehow we lost the object! 498 llwarns << "Translate manip lost the object, no selectNode" << llendl; 499 gViewerWindow->setCursor(UI_CURSOR_TOOLTRANSLATE); 500 return TRUE; 501 } 502 503 LLViewerObject* object = selectNode->getObject(); 504 if (!object) 505 { 506 // somehow we lost the object! 507 llwarns << "Translate manip lost the object, no object in selectNode" << llendl; 508 gViewerWindow->setCursor(UI_CURSOR_TOOLTRANSLATE); 509 return TRUE; 510 } 511 512 // Compute unit vectors for arrow hit and a plane through that vector 513 BOOL axis_exists = getManipAxis(object, mManipPart, axis_f); // TODO: move this 514 515 axis_d.setVec(axis_f); 516 517 LLSelectMgr::getInstance()->updateSelectionCenter(); 518 LLVector3d current_pos_global = gAgent.getPosGlobalFromAgent(getPivotPoint()); 519 520 mSubdivisions = llclamp(getSubdivisionLevel(getPivotPoint(), axis_f, getMinGridScale()), sGridMinSubdivisionLevel, sGridMaxSubdivisionLevel); 521 522 // Project the cursor onto that plane 523 LLVector3d relative_move; 524 getMousePointOnPlaneGlobal(relative_move, x, y, current_pos_global, mManipNormal);\ 525 relative_move -= mDragCursorStartGlobal; 526 527 // You can't move more than some distance from your original mousedown point. 528 if (gSavedSettings.getBOOL("LimitDragDistance")) 529 { 530 F32 max_drag_distance = gSavedSettings.getF32("MaxDragDistance"); 531 532 if (relative_move.magVecSquared() > max_drag_distance * max_drag_distance) 533 { 534 lldebugst(LLERR_USER_INPUT) << "hover handled by LLManipTranslate (too far)" << llendl; 535 gViewerWindow->setCursor(UI_CURSOR_NOLOCKED); 536 return TRUE; 537 } 538 } 539 540 F64 axis_magnitude = relative_move * axis_d; // dot product 541 LLVector3d cursor_point_snap_line; 542 543 F64 off_axis_magnitude; 544 545 getMousePointOnPlaneGlobal(cursor_point_snap_line, x, y, current_pos_global, mSnapOffsetAxis % axis_f); 546 off_axis_magnitude = axis_exists ? llabs((cursor_point_snap_line - current_pos_global) * LLVector3d(mSnapOffsetAxis)) : 0.f; 547 548 if (gSavedSettings.getBOOL("SnapEnabled")) 549 { 550 if (off_axis_magnitude > mSnapOffsetMeters) 551 { 552 mInSnapRegime = TRUE; 553 LLVector3 mouse_down_offset(mDragCursorStartGlobal - mDragSelectionStartGlobal); 554 LLVector3 cursor_snap_agent = gAgent.getPosAgentFromGlobal(cursor_point_snap_line); 555 if (!gSavedSettings.getBOOL("SnapToMouseCursor")) 556 { 557 cursor_snap_agent -= mouse_down_offset; 558 } 559 560 F32 cursor_grid_dist = (cursor_snap_agent - mGridOrigin) * axis_f; 561 562 F32 snap_dist = getMinGridScale() / (2.f * mSubdivisions); 563 F32 relative_snap_dist = fmodf(llabs(cursor_grid_dist) + snap_dist, getMinGridScale() / mSubdivisions); 564 if (relative_snap_dist < snap_dist * 2.f) 565 { 566 if (cursor_grid_dist > 0.f) 567 { 568 cursor_grid_dist -= relative_snap_dist - snap_dist; 569 } 570 else 571 { 572 cursor_grid_dist += relative_snap_dist - snap_dist; 573 } 574 } 575 576 F32 object_start_on_axis = (gAgent.getPosAgentFromGlobal(mDragSelectionStartGlobal) - mGridOrigin) * axis_f; 577 axis_magnitude = cursor_grid_dist - object_start_on_axis; 578 } 579 else if (mManipPart >= LL_YZ_PLANE && mManipPart <= LL_XY_PLANE) 580 { 581 // subtract offset from object center 582 LLVector3d cursor_point_global; 583 getMousePointOnPlaneGlobal( cursor_point_global, x, y, current_pos_global, mManipNormal ); 584 cursor_point_global -= (mDragCursorStartGlobal - mDragSelectionStartGlobal); 585 586 // snap to planar grid 587 LLVector3 cursor_point_agent = gAgent.getPosAgentFromGlobal(cursor_point_global); 588 LLVector3 camera_plane_projection = LLViewerCamera::getInstance()->getAtAxis(); 589 camera_plane_projection -= projected_vec(camera_plane_projection, mManipNormal); 590 camera_plane_projection.normVec(); 591 LLVector3 camera_projected_dir = camera_plane_projection; 592 camera_plane_projection.rotVec(~mGridRotation); 593 camera_plane_projection.scaleVec(mGridScale); 594 camera_plane_projection.abs(); 595 F32 max_grid_scale; 596 if (camera_plane_projection.mV[VX] > camera_plane_projection.mV[VY] && 597 camera_plane_projection.mV[VX] > camera_plane_projection.mV[VZ]) 598 { 599 max_grid_scale = mGridScale.mV[VX]; 600 } 601 else if (camera_plane_projection.mV[VY] > camera_plane_projection.mV[VZ]) 602 { 603 max_grid_scale = mGridScale.mV[VY]; 604 } 605 else 606 { 607 max_grid_scale = mGridScale.mV[VZ]; 608 } 609 610 F32 num_subdivisions = llclamp(getSubdivisionLevel(getPivotPoint(), camera_projected_dir, max_grid_scale), sGridMinSubdivisionLevel, sGridMaxSubdivisionLevel); 611 612 F32 grid_scale_a; 613 F32 grid_scale_b; 614 LLVector3 cursor_point_grid = (cursor_point_agent - mGridOrigin) * ~mGridRotation; 615 616 switch (mManipPart) 617 { 618 case LL_YZ_PLANE: 619 grid_scale_a = mGridScale.mV[VY] / num_subdivisions; 620 grid_scale_b = mGridScale.mV[VZ] / num_subdivisions; 621 cursor_point_grid.mV[VY] -= fmod(cursor_point_grid.mV[VY] + grid_scale_a * 0.5f, grid_scale_a) - grid_scale_a * 0.5f; 622 cursor_point_grid.mV[VZ] -= fmod(cursor_point_grid.mV[VZ] + grid_scale_b * 0.5f, grid_scale_b) - grid_scale_b * 0.5f; 623 break; 624 case LL_XZ_PLANE: 625 grid_scale_a = mGridScale.mV[VX] / num_subdivisions; 626 grid_scale_b = mGridScale.mV[VZ] / num_subdivisions; 627 cursor_point_grid.mV[VX] -= fmod(cursor_point_grid.mV[VX] + grid_scale_a * 0.5f, grid_scale_a) - grid_scale_a * 0.5f; 628 cursor_point_grid.mV[VZ] -= fmod(cursor_point_grid.mV[VZ] + grid_scale_b * 0.5f, grid_scale_b) - grid_scale_b * 0.5f; 629 break; 630 case LL_XY_PLANE: 631 grid_scale_a = mGridScale.mV[VX] / num_subdivisions; 632 grid_scale_b = mGridScale.mV[VY] / num_subdivisions; 633 cursor_point_grid.mV[VX] -= fmod(cursor_point_grid.mV[VX] + grid_scale_a * 0.5f, grid_scale_a) - grid_scale_a * 0.5f; 634 cursor_point_grid.mV[VY] -= fmod(cursor_point_grid.mV[VY] + grid_scale_b * 0.5f, grid_scale_b) - grid_scale_b * 0.5f; 635 break; 636 default: 637 break; 638 } 639 cursor_point_agent = (cursor_point_grid * mGridRotation) + mGridOrigin; 640 relative_move.setVec(cursor_point_agent - gAgent.getPosAgentFromGlobal(mDragSelectionStartGlobal)); 641 mInSnapRegime = TRUE; 642 } 643 else 644 { 645 mInSnapRegime = FALSE; 646 } 647 } 648 else 649 { 650 mInSnapRegime = FALSE; 651 } 652 653 // Clamp to arrow direction 654 // *FIX: does this apply anymore? 655 if (!axis_exists) 656 { 657 axis_magnitude = relative_move.normVec(); 658 axis_d.setVec(relative_move); 659 axis_d.normVec(); 660 axis_f.setVec(axis_d); 661 } 662 663 LLVector3d clamped_relative_move = axis_magnitude * axis_d; // scalar multiply 664 LLVector3 clamped_relative_move_f = (F32)axis_magnitude * axis_f; // scalar multiply 665 666 for (LLObjectSelection::iterator iter = mObjectSelection->begin(); 667 iter != mObjectSelection->end(); iter++) 668 { 669 LLSelectNode* selectNode = *iter; 670 LLViewerObject* object = selectNode->getObject(); 671 672 // Only apply motion to root objects and objects selected 673 // as "individual". 674 if (!object->isRootEdit() && !selectNode->mIndividualSelection) 675 { 676 continue; 677 } 678 679 if (!object->isRootEdit()) 680 { 681 // child objects should not update if parent is selected 682 LLViewerObject* editable_root = (LLViewerObject*)object->getParent(); 683 if (editable_root->isSelected()) 684 { 685 // we will be moved properly by our parent, so skip 686 continue; 687 } 688 } 689 690 if (object->permMove()) 691 { 692 // handle attachments in local space 693 if (object->isAttachment() && object->mDrawable.notNull()) 694 { 695 // calculate local version of relative move 696 LLQuaternion objWorldRotation = object->mDrawable->mXform.getParent()->getWorldRotation(); 697 objWorldRotation.transQuat(); 698 699 LLVector3 old_position_local = object->getPosition(); 700 LLVector3 new_position_local = selectNode->mSavedPositionLocal + (clamped_relative_move_f * objWorldRotation); 701 702 // move and clamp root object first, before adjusting children 703 if (new_position_local != old_position_local) 704 { 705 send_update = TRUE; 706 } 707 //RN: I forget, but we need to do this because of snapping which doesn't often result 708 // in position changes even when the mouse moves 709 object->setPosition(new_position_local); 710 rebuild(object); 711 gAgentAvatarp->clampAttachmentPositions(); 712 new_position_local = object->getPosition(); 713 714 if (selectNode->mIndividualSelection) 715 { 716 send_update = FALSE; 717 718 // counter-translate child objects if we are moving the root as an individual 719 object->resetChildrenPosition(old_position_local - new_position_local, TRUE) ; 720 } 721 } 722 else 723 { 724 // compute new position to send to simulators, but don't set it yet. 725 // We need the old position to know which simulator to send the move message to. 726 LLVector3d new_position_global = selectNode->mSavedPositionGlobal + clamped_relative_move; 727 728 // Don't let object centers go too far underground 729 F64 min_height = LLWorld::getInstance()->getMinAllowedZ(object, object->getPositionGlobal()); 730 if (new_position_global.mdV[VZ] < min_height) 731 { 732 new_position_global.mdV[VZ] = min_height; 733 } 734 735 // For safety, cap heights where objects can be dragged 736 if (new_position_global.mdV[VZ] > MAX_OBJECT_Z) 737 { 738 new_position_global.mdV[VZ] = MAX_OBJECT_Z; 739 } 740 741 // Grass is always drawn on the ground, so clamp its position to the ground 742 if (object->getPCode() == LL_PCODE_LEGACY_GRASS) 743 { 744 new_position_global.mdV[VZ] = LLWorld::getInstance()->resolveLandHeightGlobal(new_position_global) + 1.f; 745 } 746 747 if (object->isRootEdit()) 748 { 749 new_position_global = LLWorld::getInstance()->clipToVisibleRegions(object->getPositionGlobal(), new_position_global); 750 } 751 752 // PR: Only update if changed 753 LLVector3d old_position_global = object->getPositionGlobal(); 754 LLVector3 old_position_agent = object->getPositionAgent(); 755 LLVector3 new_position_agent = gAgent.getPosAgentFromGlobal(new_position_global); 756 if (object->isRootEdit()) 757 { 758 // finally, move parent object after children have calculated new offsets 759 object->setPositionAgent(new_position_agent); 760 rebuild(object); 761 } 762 else 763 { 764 LLViewerObject* root_object = object->getRootEdit(); 765 new_position_agent -= root_object->getPositionAgent(); 766 new_position_agent = new_position_agent * ~root_object->getRotation(); 767 object->setPositionParent(new_position_agent, FALSE); 768 rebuild(object); 769 } 770 771 if (selectNode->mIndividualSelection) 772 { 773 // counter-translate child objects if we are moving the root as an individual 774 object->resetChildrenPosition(old_position_agent - new_position_agent, TRUE) ; 775 send_update = FALSE; 776 } 777 else if (old_position_global != new_position_global) 778 { 779 send_update = TRUE; 780 } 781 } 782 selectNode->mLastPositionLocal = object->getPosition(); 783 } 784 } 785 786 LLSelectMgr::getInstance()->updateSelectionCenter(); 787 gAgentCamera.clearFocusObject(); 788 dialog_refresh_all(); // ??? is this necessary? 789 790 lldebugst(LLERR_USER_INPUT) << "hover handled by LLManipTranslate (active)" << llendl; 791 gViewerWindow->setCursor(UI_CURSOR_TOOLTRANSLATE); 792 return TRUE; 793} 794 795void LLManipTranslate::highlightManipulators(S32 x, S32 y) 796{ 797 mHighlightedPart = LL_NO_PART; 798 799 if (!mObjectSelection->getObjectCount()) 800 { 801 return; 802 } 803 804 //LLBBox bbox = LLSelectMgr::getInstance()->getBBoxOfSelection(); 805 LLMatrix4 projMatrix = LLViewerCamera::getInstance()->getProjection(); 806 LLMatrix4 modelView = LLViewerCamera::getInstance()->getModelview(); 807 808 LLVector3 object_position = getPivotPoint(); 809 810 LLVector3 grid_origin; 811 LLVector3 grid_scale; 812 LLQuaternion grid_rotation; 813 814 LLSelectMgr::getInstance()->getGrid(grid_origin, grid_rotation, grid_scale); 815 816 LLVector3 relative_camera_dir; 817 818 LLMatrix4 transform; 819 820 if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD) 821 { 822 relative_camera_dir = LLVector3(1.f, 0.f, 0.f) * ~grid_rotation; 823 LLVector4 translation(object_position); 824 transform.initRotTrans(grid_rotation, translation); 825 LLMatrix4 cfr(OGL_TO_CFR_ROTATION); 826 transform *= cfr; 827 LLMatrix4 window_scale; 828 F32 zoom_level = 2.f * gAgentCamera.mHUDCurZoom; 829 window_scale.initAll(LLVector3(zoom_level / LLViewerCamera::getInstance()->getAspect(), zoom_level, 0.f), 830 LLQuaternion::DEFAULT, 831 LLVector3::zero); 832 transform *= window_scale; 833 } 834 else 835 { 836 relative_camera_dir = (object_position - LLViewerCamera::getInstance()->getOrigin()) * ~grid_rotation; 837 relative_camera_dir.normVec(); 838 839 transform.initRotTrans(grid_rotation, LLVector4(object_position)); 840 transform *= modelView; 841 transform *= projMatrix; 842 } 843 844 S32 numManips = 0; 845 846 // edges 847 mManipulatorVertices[numManips++] = LLVector4(mArrowLengthMeters * MANIPULATOR_HOTSPOT_START, 0.f, 0.f, 1.f); 848 mManipulatorVertices[numManips++] = LLVector4(mArrowLengthMeters * MANIPULATOR_HOTSPOT_END, 0.f, 0.f, 1.f); 849 850 mManipulatorVertices[numManips++] = LLVector4(0.f, mArrowLengthMeters * MANIPULATOR_HOTSPOT_START, 0.f, 1.f); 851 mManipulatorVertices[numManips++] = LLVector4(0.f, mArrowLengthMeters * MANIPULATOR_HOTSPOT_END, 0.f, 1.f); 852 853 mManipulatorVertices[numManips++] = LLVector4(0.f, 0.f, mArrowLengthMeters * MANIPULATOR_HOTSPOT_START, 1.f); 854 mManipulatorVertices[numManips++] = LLVector4(0.f, 0.f, mArrowLengthMeters * MANIPULATOR_HOTSPOT_END, 1.f); 855 856 mManipulatorVertices[numManips++] = LLVector4(mArrowLengthMeters * -MANIPULATOR_HOTSPOT_START, 0.f, 0.f, 1.f); 857 mManipulatorVertices[numManips++] = LLVector4(mArrowLengthMeters * -MANIPULATOR_HOTSPOT_END, 0.f, 0.f, 1.f); 858 859 mManipulatorVertices[numManips++] = LLVector4(0.f, mArrowLengthMeters * -MANIPULATOR_HOTSPOT_START, 0.f, 1.f); 860 mManipulatorVertices[numManips++] = LLVector4(0.f, mArrowLengthMeters * -MANIPULATOR_HOTSPOT_END, 0.f, 1.f); 861 862 mManipulatorVertices[numManips++] = LLVector4(0.f, 0.f, mArrowLengthMeters * -MANIPULATOR_HOTSPOT_START, 1.f); 863 mManipulatorVertices[numManips++] = LLVector4(0.f, 0.f, mArrowLengthMeters * -MANIPULATOR_HOTSPOT_END, 1.f); 864 865 S32 num_arrow_manips = numManips; 866 867 // planar manipulators 868 BOOL planar_manip_yz_visible = FALSE; 869 BOOL planar_manip_xz_visible = FALSE; 870 BOOL planar_manip_xy_visible = FALSE; 871 872 mManipulatorVertices[numManips] = LLVector4(0.f, mPlaneManipOffsetMeters * (1.f - PLANE_TICK_SIZE * 0.5f), mPlaneManipOffsetMeters * (1.f - PLANE_TICK_SIZE * 0.5f), 1.f); 873 mManipulatorVertices[numManips++].scaleVec(mPlaneManipPositions); 874 mManipulatorVertices[numManips] = LLVector4(0.f, mPlaneManipOffsetMeters * (1.f + PLANE_TICK_SIZE * 0.5f), mPlaneManipOffsetMeters * (1.f + PLANE_TICK_SIZE * 0.5f), 1.f); 875 mManipulatorVertices[numManips++].scaleVec(mPlaneManipPositions); 876 if (llabs(relative_camera_dir.mV[VX]) > MIN_PLANE_MANIP_DOT_PRODUCT) 877 { 878 planar_manip_yz_visible = TRUE; 879 } 880 881 mManipulatorVertices[numManips] = LLVector4(mPlaneManipOffsetMeters * (1.f - PLANE_TICK_SIZE * 0.5f), 0.f, mPlaneManipOffsetMeters * (1.f - PLANE_TICK_SIZE * 0.5f), 1.f); 882 mManipulatorVertices[numManips++].scaleVec(mPlaneManipPositions); 883 mManipulatorVertices[numManips] = LLVector4(mPlaneManipOffsetMeters * (1.f + PLANE_TICK_SIZE * 0.5f), 0.f, mPlaneManipOffsetMeters * (1.f + PLANE_TICK_SIZE * 0.5f), 1.f); 884 mManipulatorVertices[numManips++].scaleVec(mPlaneManipPositions); 885 if (llabs(relative_camera_dir.mV[VY]) > MIN_PLANE_MANIP_DOT_PRODUCT) 886 { 887 planar_manip_xz_visible = TRUE; 888 } 889 890 mManipulatorVertices[numManips] = LLVector4(mPlaneManipOffsetMeters * (1.f - PLANE_TICK_SIZE * 0.5f), mPlaneManipOffsetMeters * (1.f - PLANE_TICK_SIZE * 0.5f), 0.f, 1.f); 891 mManipulatorVertices[numManips++].scaleVec(mPlaneManipPositions); 892 mManipulatorVertices[numManips] = LLVector4(mPlaneManipOffsetMeters * (1.f + PLANE_TICK_SIZE * 0.5f), mPlaneManipOffsetMeters * (1.f + PLANE_TICK_SIZE * 0.5f), 0.f, 1.f); 893 mManipulatorVertices[numManips++].scaleVec(mPlaneManipPositions); 894 if (llabs(relative_camera_dir.mV[VZ]) > MIN_PLANE_MANIP_DOT_PRODUCT) 895 { 896 planar_manip_xy_visible = TRUE; 897 } 898 899 // Project up to 9 manipulators to screen space 2*X, 2*Y, 2*Z, 3*planes 900 std::vector<ManipulatorHandle> projected_manipulators; 901 projected_manipulators.reserve(9); 902 903 for (S32 i = 0; i < num_arrow_manips; i+= 2) 904 { 905 LLVector4 projected_start = mManipulatorVertices[i] * transform; 906 projected_start = projected_start * (1.f / projected_start.mV[VW]); 907 908 LLVector4 projected_end = mManipulatorVertices[i + 1] * transform; 909 projected_end = projected_end * (1.f / projected_end.mV[VW]); 910 911 ManipulatorHandle projected_manip( 912 LLVector3(projected_start.mV[VX], projected_start.mV[VY], projected_start.mV[VZ]), 913 LLVector3(projected_end.mV[VX], projected_end.mV[VY], projected_end.mV[VZ]), 914 MANIPULATOR_IDS[i / 2], 915 10.f); // 10 pixel hotspot for arrows 916 projected_manipulators.push_back(projected_manip); 917 } 918 919 if (planar_manip_yz_visible) 920 { 921 S32 i = num_arrow_manips; 922 LLVector4 projected_start = mManipulatorVertices[i] * transform; 923 projected_start = projected_start * (1.f / projected_start.mV[VW]); 924 925 LLVector4 projected_end = mManipulatorVertices[i + 1] * transform; 926 projected_end = projected_end * (1.f / projected_end.mV[VW]); 927 928 ManipulatorHandle projected_manip( 929 LLVector3(projected_start.mV[VX], projected_start.mV[VY], projected_start.mV[VZ]), 930 LLVector3(projected_end.mV[VX], projected_end.mV[VY], projected_end.mV[VZ]), 931 MANIPULATOR_IDS[i / 2], 932 20.f); // 20 pixels for planar manipulators 933 projected_manipulators.push_back(projected_manip); 934 } 935 936 if (planar_manip_xz_visible) 937 { 938 S32 i = num_arrow_manips + 2; 939 LLVector4 projected_start = mManipulatorVertices[i] * transform; 940 projected_start = projected_start * (1.f / projected_start.mV[VW]); 941 942 LLVector4 projected_end = mManipulatorVertices[i + 1] * transform; 943 projected_end = projected_end * (1.f / projected_end.mV[VW]); 944 945 ManipulatorHandle projected_manip( 946 LLVector3(projected_start.mV[VX], projected_start.mV[VY], projected_start.mV[VZ]), 947 LLVector3(projected_end.mV[VX], projected_end.mV[VY], projected_end.mV[VZ]), 948 MANIPULATOR_IDS[i / 2], 949 20.f); // 20 pixels for planar manipulators 950 projected_manipulators.push_back(projected_manip); 951 } 952 953 if (planar_manip_xy_visible) 954 { 955 S32 i = num_arrow_manips + 4; 956 LLVector4 projected_start = mManipulatorVertices[i] * transform; 957 projected_start = projected_start * (1.f / projected_start.mV[VW]); 958 959 LLVector4 projected_end = mManipulatorVertices[i + 1] * transform; 960 projected_end = projected_end * (1.f / projected_end.mV[VW]); 961 962 ManipulatorHandle projected_manip( 963 LLVector3(projected_start.mV[VX], projected_start.mV[VY], projected_start.mV[VZ]), 964 LLVector3(projected_end.mV[VX], projected_end.mV[VY], projected_end.mV[VZ]), 965 MANIPULATOR_IDS[i / 2], 966 20.f); // 20 pixels for planar manipulators 967 projected_manipulators.push_back(projected_manip); 968 } 969 970 LLVector2 manip_start_2d; 971 LLVector2 manip_end_2d; 972 LLVector2 manip_dir; 973 LLRect world_view_rect = gViewerWindow->getWorldViewRectScaled(); 974 F32 half_width = (F32)world_view_rect.getWidth() / 2.f; 975 F32 half_height = (F32)world_view_rect.getHeight() / 2.f; 976 LLVector2 mousePos((F32)x - half_width, (F32)y - half_height); 977 LLVector2 mouse_delta; 978 979 // Keep order consistent with insertion via stable_sort 980 std::stable_sort( projected_manipulators.begin(), 981 projected_manipulators.end(), 982 ClosestToCamera() ); 983 984 std::vector<ManipulatorHandle>::iterator it = projected_manipulators.begin(); 985 for ( ; it != projected_manipulators.end(); ++it) 986 { 987 ManipulatorHandle& manipulator = *it; 988 { 989 manip_start_2d.setVec(manipulator.mStartPosition.mV[VX] * half_width, manipulator.mStartPosition.mV[VY] * half_height); 990 manip_end_2d.setVec(manipulator.mEndPosition.mV[VX] * half_width, manipulator.mEndPosition.mV[VY] * half_height); 991 manip_dir = manip_end_2d - manip_start_2d; 992 993 mouse_delta = mousePos - manip_start_2d; 994 995 F32 manip_length = manip_dir.normVec(); 996 997 F32 mouse_pos_manip = mouse_delta * manip_dir; 998 F32 mouse_dist_manip_squared = mouse_delta.magVecSquared() - (mouse_pos_manip * mouse_pos_manip); 999 1000 if (mouse_pos_manip > 0.f && 1001 mouse_pos_manip < manip_length && 1002 mouse_dist_manip_squared < manipulator.mHotSpotRadius * manipulator.mHotSpotRadius) 1003 { 1004 mHighlightedPart = manipulator.mManipID; 1005 break; 1006 } 1007 } 1008 } 1009} 1010 1011F32 LLManipTranslate::getMinGridScale() 1012{ 1013 F32 scale; 1014 switch (mManipPart) 1015 { 1016 case LL_NO_PART: 1017 default: 1018 scale = 1.f; 1019 break; 1020 case LL_X_ARROW: 1021 scale = mGridScale.mV[VX]; 1022 break; 1023 case LL_Y_ARROW: 1024 scale = mGridScale.mV[VY]; 1025 break; 1026 case LL_Z_ARROW: 1027 scale = mGridScale.mV[VZ]; 1028 break; 1029 case LL_YZ_PLANE: 1030 scale = llmin(mGridScale.mV[VY], mGridScale.mV[VZ]); 1031 break; 1032 case LL_XZ_PLANE: 1033 scale = llmin(mGridScale.mV[VX], mGridScale.mV[VZ]); 1034 break; 1035 case LL_XY_PLANE: 1036 scale = llmin(mGridScale.mV[VX], mGridScale.mV[VY]); 1037 break; 1038 } 1039 1040 return scale; 1041} 1042 1043 1044BOOL LLManipTranslate::handleMouseUp(S32 x, S32 y, MASK mask) 1045{ 1046 // first, perform normal processing in case this was a quick-click 1047 handleHover(x, y, mask); 1048 1049 if(hasMouseCapture()) 1050 { 1051 // make sure arrow colors go back to normal 1052 mManipPart = LL_NO_PART; 1053 LLSelectMgr::getInstance()->enableSilhouette(TRUE); 1054 1055 // Might have missed last update due to UPDATE_DELAY timing. 1056 LLSelectMgr::getInstance()->sendMultipleUpdate( UPD_POSITION ); 1057 1058 mInSnapRegime = FALSE; 1059 LLSelectMgr::getInstance()->saveSelectedObjectTransform(SELECT_ACTION_TYPE_PICK); 1060 //gAgent.setObjectTracking(gSavedSettings.getBOOL("TrackFocusObject")); 1061 } 1062 1063 return LLManip::handleMouseUp(x, y, mask); 1064} 1065 1066 1067void LLManipTranslate::render() 1068{ 1069 gGL.matrixMode(LLRender::MM_MODELVIEW); 1070 gGL.pushMatrix(); 1071 if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD) 1072 { 1073 F32 zoom = gAgentCamera.mHUDCurZoom; 1074 gGL.scalef(zoom, zoom, zoom); 1075 } 1076 { 1077 LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE); 1078 renderGuidelines(); 1079 } 1080 { 1081 renderTranslationHandles(); 1082 renderSnapGuides(); 1083 } 1084 gGL.popMatrix(); 1085 1086 renderText(); 1087} 1088 1089void LLManipTranslate::renderSnapGuides() 1090{ 1091 if (!gSavedSettings.getBOOL("SnapEnabled")) 1092 { 1093 return; 1094 } 1095 1096 F32 max_subdivisions = sGridMaxSubdivisionLevel;//(F32)gSavedSettings.getS32("GridSubdivision"); 1097 F32 line_alpha = gSavedSettings.getF32("GridOpacity"); 1098 1099 gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); 1100 LLGLDepthTest gls_depth(GL_TRUE); 1101 LLGLDisable gls_cull(GL_CULL_FACE); 1102 LLVector3 translate_axis; 1103 1104 if (mManipPart == LL_NO_PART) 1105 { 1106 return; 1107 } 1108 1109 LLSelectNode *first_node = mObjectSelection->getFirstMoveableNode(TRUE); 1110 if (!first_node) 1111 { 1112 return; 1113 } 1114 1115 updateGridSettings(); 1116 1117 F32 smallest_grid_unit_scale = getMinGridScale() / max_subdivisions; 1118 LLVector3 grid_origin; 1119 LLVector3 grid_scale; 1120 LLQuaternion grid_rotation; 1121 1122 LLSelectMgr::getInstance()->getGrid(grid_origin, grid_rotation, grid_scale); 1123 LLVector3 saved_selection_center = getSavedPivotPoint(); //LLSelectMgr::getInstance()->getSavedBBoxOfSelection().getCenterAgent(); 1124 LLVector3 selection_center = getPivotPoint(); 1125 1126 LLViewerObject *first_object = first_node->getObject(); 1127 1128 //pick appropriate projection plane for snap rulers according to relative camera position 1129 if (mManipPart >= LL_X_ARROW && mManipPart <= LL_Z_ARROW) 1130 { 1131 LLVector3 normal; 1132 LLColor4 inner_color; 1133 LLManip::EManipPart temp_manip = mManipPart; 1134 switch (mManipPart) 1135 { 1136 case LL_X_ARROW: 1137 normal.setVec(1,0,0); 1138 inner_color.setVec(0,1,1,line_alpha); 1139 mManipPart = LL_YZ_PLANE; 1140 break; 1141 case LL_Y_ARROW: 1142 normal.setVec(0,1,0); 1143 inner_color.setVec(1,0,1,line_alpha); 1144 mManipPart = LL_XZ_PLANE; 1145 break; 1146 case LL_Z_ARROW: 1147 normal.setVec(0,0,1); 1148 inner_color.setVec(1,1,0,line_alpha); 1149 mManipPart = LL_XY_PLANE; 1150 break; 1151 default: 1152 break; 1153 } 1154 1155 highlightIntersection(normal, selection_center, grid_rotation, inner_color); 1156 mManipPart = temp_manip; 1157 getManipAxis(first_object, mManipPart, translate_axis); 1158 1159 LLVector3 at_axis_abs; 1160 if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD) 1161 { 1162 at_axis_abs = LLVector3::x_axis * ~grid_rotation; 1163 } 1164 else 1165 { 1166 at_axis_abs = saved_selection_center - LLViewerCamera::getInstance()->getOrigin(); 1167 at_axis_abs.normVec(); 1168 1169 at_axis_abs = at_axis_abs * ~grid_rotation; 1170 } 1171 at_axis_abs.abs(); 1172 1173 if (at_axis_abs.mV[VX] > at_axis_abs.mV[VY] && at_axis_abs.mV[VX] > at_axis_abs.mV[VZ]) 1174 { 1175 if (mManipPart == LL_Y_ARROW) 1176 { 1177 mSnapOffsetAxis = LLVector3::z_axis; 1178 } 1179 else if (mManipPart == LL_Z_ARROW) 1180 { 1181 mSnapOffsetAxis = LLVector3::y_axis; 1182 } 1183 else if (at_axis_abs.mV[VY] > at_axis_abs.mV[VZ]) 1184 { 1185 mSnapOffsetAxis = LLVector3::z_axis; 1186 } 1187 else 1188 { 1189 mSnapOffsetAxis = LLVector3::y_axis; 1190 } 1191 } 1192 else if (at_axis_abs.mV[VY] > at_axis_abs.mV[VZ]) 1193 { 1194 if (mManipPart == LL_X_ARROW) 1195 { 1196 mSnapOffsetAxis = LLVector3::z_axis; 1197 } 1198 else if (mManipPart == LL_Z_ARROW) 1199 { 1200 mSnapOffsetAxis = LLVector3::x_axis; 1201 } 1202 else if (at_axis_abs.mV[VX] > at_axis_abs.mV[VZ]) 1203 { 1204 mSnapOffsetAxis = LLVector3::z_axis; 1205 } 1206 else 1207 { 1208 mSnapOffsetAxis = LLVector3::x_axis; 1209 } 1210 } 1211 else 1212 { 1213 if (mManipPart == LL_X_ARROW) 1214 { 1215 mSnapOffsetAxis = LLVector3::y_axis; 1216 } 1217 else if (mManipPart == LL_Y_ARROW) 1218 { 1219 mSnapOffsetAxis = LLVector3::x_axis; 1220 } 1221 else if (at_axis_abs.mV[VX] > at_axis_abs.mV[VY]) 1222 { 1223 mSnapOffsetAxis = LLVector3::y_axis; 1224 } 1225 else 1226 { 1227 mSnapOffsetAxis = LLVector3::x_axis; 1228 } 1229 } 1230 1231 mSnapOffsetAxis = mSnapOffsetAxis * grid_rotation; 1232 1233 F32 guide_size_meters; 1234 1235 if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD) 1236 { 1237 guide_size_meters = 1.f / gAgentCamera.mHUDCurZoom; 1238 mSnapOffsetMeters = mArrowLengthMeters * 1.5f; 1239 } 1240 else 1241 { 1242 LLVector3 cam_to_selection = getPivotPoint() - LLViewerCamera::getInstance()->getOrigin(); 1243 F32 current_range = cam_to_selection.normVec(); 1244 guide_size_meters = SNAP_GUIDE_SCREEN_SIZE * gViewerWindow->getWorldViewHeightRaw() * current_range / LLViewerCamera::getInstance()->getPixelMeterRatio(); 1245 1246 F32 fraction_of_fov = mAxisArrowLength / (F32) LLViewerCamera::getInstance()->getViewHeightInPixels(); 1247 F32 apparent_angle = fraction_of_fov * LLViewerCamera::getInstance()->getView(); // radians 1248 F32 offset_at_camera = tan(apparent_angle) * 1.5f; 1249 F32 range = dist_vec(gAgent.getPosAgentFromGlobal(first_node->mSavedPositionGlobal), LLViewerCamera::getInstance()->getOrigin()); 1250 mSnapOffsetMeters = range * offset_at_camera; 1251 } 1252 1253 LLVector3 tick_start; 1254 LLVector3 tick_end; 1255 1256 // how far away from grid origin is the selection along the axis of translation? 1257 F32 dist_grid_axis = (selection_center - mGridOrigin) * translate_axis; 1258 // find distance to nearest smallest grid unit 1259 F32 offset_nearest_grid_unit = fmodf(dist_grid_axis, smallest_grid_unit_scale); 1260 // how many smallest grid units are we away from largest grid scale? 1261 S32 sub_div_offset = llround(fmod(dist_grid_axis - offset_nearest_grid_unit, getMinGridScale() / sGridMinSubdivisionLevel) / smallest_grid_unit_scale); 1262 S32 num_ticks_per_side = llmax(1, llfloor(0.5f * guide_size_meters / smallest_grid_unit_scale)); 1263 1264 LLGLDepthTest gls_depth(GL_FALSE); 1265 1266 for (S32 pass = 0; pass < 3; pass++) 1267 { 1268 LLColor4 line_color = setupSnapGuideRenderPass(pass); 1269 1270 gGL.begin(LLRender::LINES); 1271 { 1272 LLVector3 line_start = selection_center + (mSnapOffsetMeters * mSnapOffsetAxis) + (translate_axis * (guide_size_meters * 0.5f + offset_nearest_grid_unit)); 1273 LLVector3 line_end = selection_center + (mSnapOffsetMeters * mSnapOffsetAxis) - (translate_axis * (guide_size_meters * 0.5f + offset_nearest_grid_unit)); 1274 LLVector3 line_mid = (line_start + line_end) * 0.5f; 1275 1276 gGL.color4f(line_color.mV[VX], line_color.mV[VY], line_color.mV[VZ], line_color.mV[VW] * 0.2f); 1277 gGL.vertex3fv(line_start.mV); 1278 gGL.color4f(line_color.mV[VX], line_color.mV[VY], line_color.mV[VZ], line_color.mV[VW]); 1279 gGL.vertex3fv(line_mid.mV); 1280 gGL.vertex3fv(line_mid.mV); 1281 gGL.color4f(line_color.mV[VX], line_color.mV[VY], line_color.mV[VZ], line_color.mV[VW] * 0.2f); 1282 gGL.vertex3fv(line_end.mV); 1283 1284 line_start.setVec(selection_center + (mSnapOffsetAxis * -mSnapOffsetMeters) + (translate_axis * guide_size_meters * 0.5f)); 1285 line_end.setVec(selection_center + (mSnapOffsetAxis * -mSnapOffsetMeters) - (translate_axis * guide_size_meters * 0.5f)); 1286 line_mid = (line_start + line_end) * 0.5f; 1287 1288 gGL.color4f(line_color.mV[VX], line_color.mV[VY], line_color.mV[VZ], line_color.mV[VW] * 0.2f); 1289 gGL.vertex3fv(line_start.mV); 1290 gGL.color4f(line_color.mV[VX], line_color.mV[VY], line_color.mV[VZ], line_color.mV[VW]); 1291 gGL.vertex3fv(line_mid.mV); 1292 gGL.vertex3fv(line_mid.mV); 1293 gGL.color4f(line_color.mV[VX], line_color.mV[VY], line_color.mV[VZ], line_color.mV[VW] * 0.2f); 1294 gGL.vertex3fv(line_end.mV); 1295 1296 for (S32 i = -num_ticks_per_side; i <= num_ticks_per_side; i++) 1297 { 1298 tick_start = selection_center + (translate_axis * (smallest_grid_unit_scale * (F32)i - offset_nearest_grid_unit)); 1299 1300 F32 cur_subdivisions = llclamp(getSubdivisionLevel(tick_start, translate_axis, getMinGridScale()), sGridMinSubdivisionLevel, sGridMaxSubdivisionLevel); 1301 1302 if (fmodf((F32)(i + sub_div_offset), (max_subdivisions / cur_subdivisions)) != 0.f) 1303 { 1304 continue; 1305 } 1306 1307 // add in off-axis offset 1308 tick_start += (mSnapOffsetAxis * mSnapOffsetMeters); 1309 1310 BOOL is_sub_tick = FALSE; 1311 F32 tick_scale = 1.f; 1312 for (F32 division_level = max_subdivisions; division_level >= sGridMinSubdivisionLevel; division_level /= 2.f) 1313 { 1314 if (fmodf((F32)(i + sub_div_offset), division_level) == 0.f) 1315 { 1316 break; 1317 } 1318 tick_scale *= 0.7f; 1319 is_sub_tick = TRUE; 1320 } 1321 1322// S32 num_ticks_to_fade = is_sub_tick ? num_ticks_per_side / 2 : num_ticks_per_side; 1323// F32 alpha = line_alpha * (1.f - (0.8f * ((F32)llabs(i) / (F32)num_ticks_to_fade))); 1324 1325 tick_end = tick_start + (mSnapOffsetAxis * mSnapOffsetMeters * tick_scale); 1326 1327 gGL.color4f(line_color.mV[VX], line_color.mV[VY], line_color.mV[VZ], line_color.mV[VW]); 1328 gGL.vertex3fv(tick_start.mV); 1329 gGL.vertex3fv(tick_end.mV); 1330 1331 tick_start = selection_center + (mSnapOffsetAxis * -mSnapOffsetMeters) + 1332 (translate_axis * (getMinGridScale() / (F32)(max_subdivisions) * (F32)i - offset_nearest_grid_unit)); 1333 tick_end = tick_start - (mSnapOffsetAxis * mSnapOffsetMeters * tick_scale); 1334 1335 gGL.vertex3fv(tick_start.mV); 1336 gGL.vertex3fv(tick_end.mV); 1337 } 1338 } 1339 gGL.end(); 1340 1341 if (mInSnapRegime) 1342 { 1343 LLVector3 line_start = selection_center - mSnapOffsetAxis * mSnapOffsetMeters; 1344 LLVector3 line_end = selection_center + mSnapOffsetAxis * mSnapOffsetMeters; 1345 1346 gGL.begin(LLRender::LINES); 1347 { 1348 gGL.color4f(line_color.mV[VX], line_color.mV[VY], line_color.mV[VZ], line_color.mV[VW]); 1349 1350 gGL.vertex3fv(line_start.mV); 1351 gGL.vertex3fv(line_end.mV); 1352 } 1353 gGL.end(); 1354 1355 // draw snap guide arrow 1356 gGL.begin(LLRender::TRIANGLES); 1357 { 1358 gGL.color4f(line_color.mV[VX], line_color.mV[VY], line_color.mV[VZ], line_color.mV[VW]); 1359 1360 LLVector3 arrow_dir; 1361 LLVector3 arrow_span = translate_axis; 1362 1363 arrow_dir = -mSnapOffsetAxis; 1364 gGL.vertex3fv((line_start + arrow_dir * mConeSize * SNAP_ARROW_SCALE).mV); 1365 gGL.vertex3fv((line_start + arrow_span * mConeSize * SNAP_ARROW_SCALE).mV); 1366 gGL.vertex3fv((line_start - arrow_span * mConeSize * SNAP_ARROW_SCALE).mV); 1367 1368 arrow_dir = mSnapOffsetAxis; 1369 gGL.vertex3fv((line_end + arrow_dir * mConeSize * SNAP_ARROW_SCALE).mV); 1370 gGL.vertex3fv((line_end + arrow_span * mConeSize * SNAP_ARROW_SCALE).mV); 1371 gGL.vertex3fv((line_end - arrow_span * mConeSize * SNAP_ARROW_SCALE).mV); 1372 } 1373 gGL.end(); 1374 } 1375 } 1376 1377 sub_div_offset = llround(fmod(dist_grid_axis - offset_nearest_grid_unit, getMinGridScale() * 32.f) / smallest_grid_unit_scale); 1378 1379 LLVector2 screen_translate_axis(llabs(translate_axis * LLViewerCamera::getInstance()->getLeftAxis()), llabs(translate_axis * LLViewerCamera::getInstance()->getUpAxis())); 1380 screen_translate_axis.normVec(); 1381 1382 S32 tick_label_spacing = llround(screen_translate_axis * sTickLabelSpacing); 1383 1384 // render tickmark values 1385 for (S32 i = -num_ticks_per_side; i <= num_ticks_per_side; i++) 1386 { 1387 LLVector3 tick_pos = selection_center + (translate_axis * ((smallest_grid_unit_scale * (F32)i) - offset_nearest_grid_unit)); 1388 F32 alpha = line_alpha * (1.f - (0.5f * ((F32)llabs(i) / (F32)num_ticks_per_side))); 1389 1390 F32 tick_scale = 1.f; 1391 for (F32 division_level = max_subdivisions; division_level >= sGridMinSubdivisionLevel; division_level /= 2.f) 1392 { 1393 if (fmodf((F32)(i + sub_div_offset), division_level) == 0.f) 1394 { 1395 break; 1396 } 1397 tick_scale *= 0.7f; 1398 } 1399 1400 if (fmodf((F32)(i + sub_div_offset), (max_subdivisions / llmin(sGridMaxSubdivisionLevel, getSubdivisionLevel(tick_pos, translate_axis, getMinGridScale(), tick_label_spacing)))) == 0.f) 1401 { 1402 F32 snap_offset_meters; 1403 1404 if (mSnapOffsetAxis * LLViewerCamera::getInstance()->getUpAxis() > 0.f) 1405 { 1406 snap_offset_meters = mSnapOffsetMeters; 1407 } 1408 else 1409 { 1410 snap_offset_meters = -mSnapOffsetMeters; 1411 } 1412 LLVector3 text_origin = selection_center + 1413 (translate_axis * ((smallest_grid_unit_scale * (F32)i) - offset_nearest_grid_unit)) + 1414 (mSnapOffsetAxis * snap_offset_meters * (1.f + tick_scale)); 1415 1416 LLVector3 tick_offset = (tick_pos - mGridOrigin) * ~mGridRotation; 1417 F32 offset_val = 0.5f * tick_offset.mV[ARROW_TO_AXIS[mManipPart]] / getMinGridScale(); 1418 EGridMode grid_mode = LLSelectMgr::getInstance()->getGridMode(); 1419 F32 text_highlight = 0.8f; 1420 if(i - llround(offset_nearest_grid_unit / smallest_grid_unit_scale) == 0 && mInSnapRegime) 1421 { 1422 text_highlight = 1.f; 1423 } 1424 1425 if (grid_mode == GRID_MODE_WORLD) 1426 { 1427 // rescale units to meters from multiple of grid scale 1428 offset_val *= 2.f * grid_scale[ARROW_TO_AXIS[mManipPart]]; 1429 renderTickValue(text_origin, offset_val, std::string("m"), LLColor4(text_highlight, text_highlight, text_highlight, alpha)); 1430 } 1431 else 1432 { 1433 renderTickValue(text_origin, offset_val, std::string("x"), LLColor4(text_highlight, text_highlight, text_highlight, alpha)); 1434 } 1435 } 1436 } 1437 if (mObjectSelection->getSelectType() != SELECT_TYPE_HUD) 1438 { 1439 // render helpful text 1440 if (mHelpTextTimer.getElapsedTimeF32() < sHelpTextVisibleTime + sHelpTextFadeTime && sNumTimesHelpTextShown < sMaxTimesShowHelpText) 1441 { 1442 F32 snap_offset_meters_up; 1443 if (mSnapOffsetAxis * LLViewerCamera::getInstance()->getUpAxis() > 0.f) 1444 { 1445 snap_offset_meters_up = mSnapOffsetMeters; 1446 } 1447 else 1448 { 1449 snap_offset_meters_up = -mSnapOffsetMeters; 1450 } 1451 1452 LLVector3 selection_center_start = getSavedPivotPoint();//LLSelectMgr::getInstance()->getSavedBBoxOfSelection().getCenterAgent(); 1453 1454 LLVector3 help_text_pos = selection_center_start + (snap_offset_meters_up * 3.f * mSnapOffsetAxis); 1455 const LLFontGL* big_fontp = LLFontGL::getFontSansSerif(); 1456 1457 std::string help_text = "Move mouse cursor over ruler"; 1458 LLColor4 help_text_color = LLColor4::white; 1459 help_text_color.mV[VALPHA] = clamp_rescale(mHelpTextTimer.getElapsedTimeF32(), sHelpTextVisibleTime, sHelpTextVisibleTime + sHelpTextFadeTime, line_alpha, 0.f); 1460 hud_render_utf8text(help_text, help_text_pos, *big_fontp, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, -0.5f * big_fontp->getWidthF32(help_text), 3.f, help_text_color, mObjectSelection->getSelectType() == SELECT_TYPE_HUD); 1461 help_text = "to snap to grid"; 1462 help_text_pos -= LLViewerCamera::getInstance()->getUpAxis() * mSnapOffsetMeters * 0.2f; 1463 hud_render_utf8text(help_text, help_text_pos, *big_fontp, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, -0.5f * big_fontp->getWidthF32(help_text), 3.f, help_text_color, mObjectSelection->getSelectType() == SELECT_TYPE_HUD); 1464 } 1465 } 1466 } 1467 else 1468 { 1469 // render gridlines for planar snapping 1470 1471 F32 u = 0, v = 0; 1472 LLColor4 inner_color; 1473 LLVector3 normal; 1474 LLVector3 grid_center = selection_center - grid_origin; 1475 F32 usc = 1; 1476 F32 vsc = 1; 1477 1478 grid_center *= ~grid_rotation; 1479 1480 switch (mManipPart) 1481 { 1482 case LL_YZ_PLANE: 1483 u = grid_center.mV[VY]; 1484 v = grid_center.mV[VZ]; 1485 usc = grid_scale.mV[VY]; 1486 vsc = grid_scale.mV[VZ]; 1487 inner_color.setVec(0,1,1,line_alpha); 1488 normal.setVec(1,0,0); 1489 break; 1490 case LL_XZ_PLANE: 1491 u = grid_center.mV[VX]; 1492 v = grid_center.mV[VZ]; 1493 usc = grid_scale.mV[VX]; 1494 vsc = grid_scale.mV[VZ]; 1495 inner_color.setVec(1,0,1,line_alpha); 1496 normal.setVec(0,1,0); 1497 break; 1498 case LL_XY_PLANE: 1499 u = grid_center.mV[VX]; 1500 v = grid_center.mV[VY]; 1501 usc = grid_scale.mV[VX]; 1502 vsc = grid_scale.mV[VY]; 1503 inner_color.setVec(1,1,0,line_alpha); 1504 normal.setVec(0,0,1); 1505 break; 1506 default: 1507 break; 1508 } 1509 1510 gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); 1511 highlightIntersection(normal, selection_center, grid_rotation, inner_color); 1512 1513 gGL.pushMatrix(); 1514 1515 F32 x,y,z,angle_radians; 1516 grid_rotation.getAngleAxis(&angle_radians, &x, &y, &z); 1517 gGL.translatef(selection_center.mV[VX], selection_center.mV[VY], selection_center.mV[VZ]); 1518 gGL.rotatef(angle_radians * RAD_TO_DEG, x, y, z); 1519 1520 F32 sz = mGridSizeMeters; 1521 F32 tiles = sz; 1522 1523 gGL.matrixMode(LLRender::MM_TEXTURE); 1524 gGL.pushMatrix(); 1525 usc = 1.0f/usc; 1526 vsc = 1.0f/vsc; 1527 1528 while (usc > vsc*4.0f) 1529 { 1530 usc *= 0.5f; 1531 } 1532 while (vsc > usc * 4.0f) 1533 { 1534 vsc *= 0.5f; 1535 } 1536 1537 gGL.scalef(usc, vsc, 1.0f); 1538 gGL.translatef(u, v, 0); 1539 1540 float a = line_alpha; 1541 1542 LLColor4 col = LLUIColorTable::instance().getColor("SilhouetteChildColor"); 1543 { 1544 //draw grid behind objects 1545 LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE); 1546 1547 { 1548 LLGLDisable stencil(GL_STENCIL_TEST); 1549 { 1550 LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE, GL_GREATER); 1551 gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, getGridTexName()); 1552 gGL.flush(); 1553 gGL.blendFunc(LLRender::BF_ZERO, LLRender::BF_ONE_MINUS_SOURCE_AL…
Large files files are truncated, but you can click here to view the full file