886 lines
22 KiB
C++
886 lines
22 KiB
C++
/**
|
|
* @file lltoolgrab.cpp
|
|
* @brief LLToolGrab class implementation
|
|
*
|
|
* Copyright (c) 2001-$CurrentYear$, Linden Research, Inc.
|
|
* $License$
|
|
*/
|
|
|
|
#include "llviewerprecompiledheaders.h"
|
|
|
|
#include "lltoolgrab.h"
|
|
|
|
// library headers
|
|
#include "indra_constants.h" // for agent control flags
|
|
#include "llviewercontrol.h"
|
|
#include "llquaternion.h"
|
|
#include "llbox.h"
|
|
#include "message.h"
|
|
#include "llview.h"
|
|
#include "llfontgl.h"
|
|
#include "llui.h"
|
|
|
|
// newview headers
|
|
#include "llagent.h"
|
|
//#include "llfloateravatarinfo.h"
|
|
#include "lldrawable.h"
|
|
#include "llfloatertools.h"
|
|
#include "llhudeffect.h"
|
|
#include "llhudmanager.h"
|
|
#include "llregionposition.h"
|
|
#include "llselectmgr.h"
|
|
#include "llstatusbar.h"
|
|
#include "lltoolmgr.h"
|
|
#include "lltoolpie.h"
|
|
#include "llviewercamera.h"
|
|
#include "llviewerobject.h"
|
|
#include "llviewerobjectlist.h"
|
|
#include "llviewerregion.h"
|
|
#include "llviewerwindow.h"
|
|
#include "llvoavatar.h"
|
|
#include "llworld.h"
|
|
#include "viewer.h"
|
|
|
|
const S32 SLOP_DIST_SQ = 4;
|
|
|
|
// Override modifier key behavior with these buttons
|
|
BOOL gGrabBtnVertical = FALSE;
|
|
BOOL gGrabBtnSpin = FALSE;
|
|
LLTool* gGrabTransientTool = NULL;
|
|
LLToolGrab *gToolGrab = NULL;
|
|
extern BOOL gDebugClicks;
|
|
|
|
//
|
|
// Methods
|
|
//
|
|
LLToolGrab::LLToolGrab( LLToolComposite* composite )
|
|
: LLTool( "Grab", composite ),
|
|
mMode( GRAB_INACTIVE ),
|
|
mVerticalDragging( FALSE ),
|
|
mHitLand(FALSE),
|
|
mHitObjectID(),
|
|
mGrabObject( NULL ),
|
|
mMouseDownX( -1 ),
|
|
mMouseDownY( -1 ),
|
|
mHasMoved( FALSE ),
|
|
mSpinGrabbing( FALSE ),
|
|
mSpinRotation(),
|
|
mHideBuildHighlight(FALSE)
|
|
{ }
|
|
|
|
LLToolGrab::~LLToolGrab()
|
|
{ }
|
|
|
|
|
|
// virtual
|
|
void LLToolGrab::handleSelect()
|
|
{
|
|
if(gFloaterTools)
|
|
{
|
|
// viewer can crash during startup if we don't check.
|
|
gFloaterTools->setStatusText("Drag to move objects, Ctrl to lift, Ctrl-Shift to spin");
|
|
}
|
|
gGrabBtnVertical = FALSE;
|
|
gGrabBtnSpin = FALSE;
|
|
}
|
|
|
|
void LLToolGrab::handleDeselect()
|
|
{
|
|
if( hasMouseCapture() )
|
|
{
|
|
setMouseCapture( FALSE );
|
|
}
|
|
|
|
gFloaterTools->setStatusText("");
|
|
}
|
|
|
|
BOOL LLToolGrab::handleDoubleClick(S32 x, S32 y, MASK mask)
|
|
{
|
|
if (gDebugClicks)
|
|
{
|
|
llinfos << "LLToolGrab handleDoubleClick (becoming mouseDown)" << llendl;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL LLToolGrab::handleMouseDown(S32 x, S32 y, MASK mask)
|
|
{
|
|
if (gDebugClicks)
|
|
{
|
|
llinfos << "LLToolGrab handleMouseDown" << llendl;
|
|
}
|
|
|
|
mHitLand = FALSE;
|
|
|
|
// call the base class to propogate info to sim
|
|
LLTool::handleMouseDown(x, y, mask);
|
|
|
|
if (!gAgent.leftButtonGrabbed())
|
|
{
|
|
// can grab transparent objects (how touch event propagates, scripters rely on this)
|
|
gViewerWindow->hitObjectOrLandGlobalAsync(x, y, mask, pickCallback, TRUE);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
void LLToolGrab::pickCallback(S32 x, S32 y, MASK mask)
|
|
{
|
|
LLViewerObject *objectp = gObjectList.findObject( gLastHitObjectID );
|
|
|
|
BOOL extend_select = (mask & MASK_SHIFT);
|
|
|
|
if (!extend_select && !gSelectMgr->getSelection()->isEmpty())
|
|
{
|
|
gSelectMgr->deselectAll();
|
|
gToolGrab->mDeselectedThisClick = TRUE;
|
|
}
|
|
else
|
|
{
|
|
gToolGrab->mDeselectedThisClick = FALSE;
|
|
}
|
|
|
|
// if not over object, do nothing
|
|
if (!objectp)
|
|
{
|
|
gToolGrab->setMouseCapture(TRUE);
|
|
gToolGrab->mMode = GRAB_NOOBJECT;
|
|
gToolGrab->mHitObjectID.setNull();
|
|
}
|
|
else
|
|
{
|
|
gToolGrab->handleObjectHit(objectp, x, y, mask);
|
|
}
|
|
}
|
|
|
|
BOOL LLToolGrab::handleObjectHit(LLViewerObject *objectp, S32 x, S32 y, MASK mask)
|
|
{
|
|
mMouseDownX = x;
|
|
mMouseDownY = y;
|
|
mMouseMask = mask;
|
|
|
|
if (gDebugClicks)
|
|
{
|
|
llinfos << "LLToolGrab handleObjectHit " << mMouseDownX << "," << mMouseDownY << llendl;
|
|
}
|
|
|
|
if (NULL == objectp) // unexpected
|
|
{
|
|
llwarns << "objectp was NULL; returning FALSE" << llendl;
|
|
return FALSE;
|
|
}
|
|
|
|
if (objectp->isAvatar())
|
|
{
|
|
if (gGrabTransientTool)
|
|
{
|
|
gBasicToolset->selectTool( gGrabTransientTool );
|
|
gGrabTransientTool = NULL;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
setMouseCapture( TRUE );
|
|
|
|
mHitObjectID = objectp->getID();
|
|
|
|
// Grabs always start from the root
|
|
// objectp = (LLViewerObject *)objectp->getRoot();
|
|
|
|
LLViewerObject* parent = objectp->getRootEdit();
|
|
BOOL script_touch = (objectp->flagHandleTouch()) || (parent && parent->flagHandleTouch());
|
|
|
|
// Clicks on scripted or physical objects are temporary grabs, so
|
|
// not "Build mode"
|
|
mHideBuildHighlight = script_touch || objectp->usePhysics();
|
|
|
|
if (!objectp->usePhysics())
|
|
{
|
|
// In mouselook, we shouldn't be able to grab non-physical,
|
|
// non-touchable objects. If it has a touch handler, we
|
|
// do grab it (so llDetectedGrab works), but movement is
|
|
// blocked on the server side. JC
|
|
if (gAgent.cameraMouselook() && !script_touch)
|
|
{
|
|
mMode = GRAB_LOCKED;
|
|
}
|
|
else
|
|
{
|
|
mMode = GRAB_NONPHYSICAL;
|
|
}
|
|
gViewerWindow->hideCursor();
|
|
gViewerWindow->moveCursorToCenter();
|
|
// Don't bail out here, go on and grab so buttons can get
|
|
// their "touched" event.
|
|
}
|
|
else if( !objectp->permMove() )
|
|
{
|
|
// if mouse is over a physical object without move permission, show feedback if user tries to move it.
|
|
mMode = GRAB_LOCKED;
|
|
|
|
// Don't bail out here, go on and grab so buttons can get
|
|
// their "touched" event.
|
|
}
|
|
else
|
|
{
|
|
// if mouse is over a physical object with move permission,
|
|
// select it and enter "grab" mode (hiding cursor, etc.)
|
|
|
|
mMode = GRAB_ACTIVE_CENTER;
|
|
|
|
gViewerWindow->hideCursor();
|
|
gViewerWindow->moveCursorToCenter();
|
|
}
|
|
|
|
// Always send "touched" message
|
|
|
|
mAccumDeltaX = 0;
|
|
mAccumDeltaY = 0;
|
|
mHasMoved = FALSE;
|
|
mOutsideSlop = FALSE;
|
|
|
|
mGrabObject = objectp;
|
|
|
|
mGrabOffset.clearVec();
|
|
|
|
mVerticalDragging = (mask == MASK_VERTICAL) || gGrabBtnVertical;
|
|
|
|
startGrab(x, y);
|
|
|
|
if ((mask == MASK_SPIN) || gGrabBtnSpin)
|
|
{
|
|
startSpin();
|
|
}
|
|
|
|
gSelectMgr->updateSelectionCenter(); // update selection beam
|
|
|
|
// update point at
|
|
LLViewerObject *edit_object = gObjectList.findObject(mHitObjectID);
|
|
if (edit_object)
|
|
{
|
|
LLVector3 local_edit_point = gAgent.getPosAgentFromGlobal(gLastHitNonFloraPosGlobal);
|
|
local_edit_point -= edit_object->getPositionAgent();
|
|
local_edit_point = local_edit_point * ~edit_object->getRenderRotation();
|
|
gAgent.setPointAt(POINTAT_TARGET_GRAB, edit_object, local_edit_point );
|
|
gAgent.setLookAt(LOOKAT_TARGET_SELECT, edit_object, local_edit_point );
|
|
}
|
|
|
|
// on transient grabs (clicks on world objects), kill the grab immediately
|
|
if (!gViewerWindow->getLeftMouseDown()
|
|
&& gGrabTransientTool
|
|
&& (mMode == GRAB_NONPHYSICAL || mMode == GRAB_LOCKED))
|
|
{
|
|
gBasicToolset->selectTool( gGrabTransientTool );
|
|
gGrabTransientTool = NULL;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
void LLToolGrab::startSpin()
|
|
{
|
|
mSpinGrabbing = TRUE;
|
|
|
|
// Was saveSelectedObjectTransform()
|
|
LLViewerObject *root = (LLViewerObject *)mGrabObject->getRoot();
|
|
mSpinRotation = root->getRotation();
|
|
|
|
LLMessageSystem *msg = gMessageSystem;
|
|
msg->newMessageFast(_PREHASH_ObjectSpinStart);
|
|
msg->nextBlockFast(_PREHASH_AgentData);
|
|
msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
|
|
msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
|
|
msg->nextBlockFast(_PREHASH_ObjectData);
|
|
msg->addUUIDFast(_PREHASH_ObjectID, mGrabObject->getID() );
|
|
msg->sendMessage( mGrabObject->getRegion()->getHost() );
|
|
}
|
|
|
|
|
|
void LLToolGrab::stopSpin()
|
|
{
|
|
mSpinGrabbing = FALSE;
|
|
|
|
LLMessageSystem *msg = gMessageSystem;
|
|
switch(mMode)
|
|
{
|
|
case GRAB_ACTIVE_CENTER:
|
|
case GRAB_NONPHYSICAL:
|
|
case GRAB_LOCKED:
|
|
msg->newMessageFast(_PREHASH_ObjectSpinStop);
|
|
msg->nextBlockFast(_PREHASH_AgentData);
|
|
msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
|
|
msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
|
|
msg->nextBlockFast(_PREHASH_ObjectData);
|
|
msg->addUUIDFast(_PREHASH_ObjectID, mGrabObject->getID() );
|
|
msg->sendMessage( mGrabObject->getRegion()->getHost() );
|
|
break;
|
|
|
|
case GRAB_NOOBJECT:
|
|
case GRAB_INACTIVE:
|
|
default:
|
|
// do nothing
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
void LLToolGrab::startGrab(S32 x, S32 y)
|
|
{
|
|
// Compute grab_offset in the OBJECT's root's coordinate frame
|
|
// (sometimes root == object)
|
|
LLViewerObject *root = (LLViewerObject *)mGrabObject->getRoot();
|
|
|
|
// drag from center
|
|
LLVector3d grab_start_global = root->getPositionGlobal();
|
|
|
|
// Where the grab starts, relative to the center of the root object of the set.
|
|
// JC - This code looks wonky, but I believe it does the right thing.
|
|
// Otherwise, when you grab a linked object set, it "pops" on the start
|
|
// of the drag.
|
|
LLVector3d grab_offsetd = root->getPositionGlobal() - mGrabObject->getPositionGlobal();
|
|
|
|
LLVector3 grab_offset;
|
|
grab_offset.setVec(grab_offsetd);
|
|
|
|
LLQuaternion rotation = root->getRotation();
|
|
rotation.conjQuat();
|
|
grab_offset = grab_offset * rotation;
|
|
|
|
// This planar drag starts at the grab point
|
|
mDragStartPointGlobal = grab_start_global;
|
|
mDragStartFromCamera = grab_start_global - gAgent.getCameraPositionGlobal();
|
|
|
|
LLMessageSystem *msg = gMessageSystem;
|
|
msg->newMessageFast(_PREHASH_ObjectGrab);
|
|
msg->nextBlockFast(_PREHASH_AgentData);
|
|
msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
|
|
msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
|
|
msg->nextBlockFast(_PREHASH_ObjectData);
|
|
msg->addU32Fast(_PREHASH_LocalID, mGrabObject->mLocalID);
|
|
msg->addVector3Fast(_PREHASH_GrabOffset, grab_offset );
|
|
msg->sendMessage( mGrabObject->getRegion()->getHost());
|
|
|
|
mGrabOffsetFromCenterInitial = grab_offset;
|
|
mGrabHiddenOffsetFromCamera = mDragStartFromCamera;
|
|
|
|
mGrabTimer.reset();
|
|
}
|
|
|
|
|
|
BOOL LLToolGrab::handleHover(S32 x, S32 y, MASK mask)
|
|
{
|
|
mLastMouseX = x;
|
|
mLastMouseY = y;
|
|
|
|
if (!gViewerWindow->getLeftMouseDown())
|
|
{
|
|
gViewerWindow->setCursor(UI_CURSOR_TOOLGRAB);
|
|
setMouseCapture(FALSE);
|
|
return TRUE;
|
|
}
|
|
|
|
// Do the right hover based on mode
|
|
switch( mMode )
|
|
{
|
|
case GRAB_ACTIVE_CENTER:
|
|
case GRAB_NONPHYSICAL:
|
|
handleHoverActive( x, y, mask ); // cursor hidden
|
|
break;
|
|
|
|
case GRAB_INACTIVE:
|
|
handleHoverInactive( x, y, mask ); // cursor set here
|
|
break;
|
|
|
|
case GRAB_NOOBJECT:
|
|
case GRAB_LOCKED:
|
|
handleHoverFailed( x, y, mask );
|
|
break;
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
|
|
// Dragging.
|
|
void LLToolGrab::handleHoverActive(S32 x, S32 y, MASK mask)
|
|
{
|
|
llassert( hasMouseCapture() );
|
|
llassert( mGrabObject );
|
|
if (mGrabObject->isDead())
|
|
{
|
|
// Bail out of drag because object has been killed
|
|
setMouseCapture(FALSE);
|
|
return;
|
|
}
|
|
|
|
//--------------------------------------------------
|
|
// Toggle spinning
|
|
//--------------------------------------------------
|
|
if (mSpinGrabbing && !(mask == MASK_SPIN) && !gGrabBtnSpin)
|
|
{
|
|
// user released ALT key, stop spinning
|
|
stopSpin();
|
|
}
|
|
else if (!mSpinGrabbing && (mask == MASK_SPIN) )
|
|
{
|
|
// user pressed ALT key, start spinning
|
|
startSpin();
|
|
}
|
|
|
|
//--------------------------------------------------
|
|
// Toggle vertical dragging
|
|
//--------------------------------------------------
|
|
if (mVerticalDragging && !(mask == MASK_VERTICAL) && !gGrabBtnVertical)
|
|
{
|
|
// ...switch to horizontal dragging
|
|
mVerticalDragging = FALSE;
|
|
|
|
mDragStartPointGlobal = gViewerWindow->clickPointInWorldGlobal(x, y, mGrabObject);
|
|
mDragStartFromCamera = mDragStartPointGlobal - gAgent.getCameraPositionGlobal();
|
|
}
|
|
else if (!mVerticalDragging && (mask == MASK_VERTICAL) )
|
|
{
|
|
// ...switch to vertical dragging
|
|
mVerticalDragging = TRUE;
|
|
|
|
mDragStartPointGlobal = gViewerWindow->clickPointInWorldGlobal(x, y, mGrabObject);
|
|
mDragStartFromCamera = mDragStartPointGlobal - gAgent.getCameraPositionGlobal();
|
|
}
|
|
|
|
const F32 RADIANS_PER_PIXEL_X = 0.01f;
|
|
const F32 RADIANS_PER_PIXEL_Y = 0.01f;
|
|
|
|
const F32 SENSITIVITY_X = 0.0075f;
|
|
const F32 SENSITIVITY_Y = 0.0075f;
|
|
|
|
S32 dx = x - (gViewerWindow->getWindowWidth() / 2);
|
|
S32 dy = y - (gViewerWindow->getWindowHeight() / 2);
|
|
|
|
if (dx != 0 || dy != 0)
|
|
{
|
|
mAccumDeltaX += dx;
|
|
mAccumDeltaY += dy;
|
|
S32 dist_sq = mAccumDeltaX * mAccumDeltaX + mAccumDeltaY * mAccumDeltaY;
|
|
if (dist_sq > SLOP_DIST_SQ)
|
|
{
|
|
mOutsideSlop = TRUE;
|
|
}
|
|
|
|
// mouse has moved outside center
|
|
mHasMoved = TRUE;
|
|
|
|
if (mSpinGrabbing)
|
|
{
|
|
//------------------------------------------------------
|
|
// Handle spinning
|
|
//------------------------------------------------------
|
|
|
|
// x motion maps to rotation around vertical axis
|
|
LLVector3 up(0.f, 0.f, 1.f);
|
|
LLQuaternion rotation_around_vertical( dx*RADIANS_PER_PIXEL_X, up );
|
|
|
|
// y motion maps to rotation around left axis
|
|
const LLVector3 &agent_left = gCamera->getLeftAxis();
|
|
LLQuaternion rotation_around_left( dy*RADIANS_PER_PIXEL_Y, agent_left );
|
|
|
|
// compose with current rotation
|
|
mSpinRotation = mSpinRotation * rotation_around_vertical;
|
|
mSpinRotation = mSpinRotation * rotation_around_left;
|
|
|
|
// TODO: Throttle these
|
|
LLMessageSystem *msg = gMessageSystem;
|
|
msg->newMessageFast(_PREHASH_ObjectSpinUpdate);
|
|
msg->nextBlockFast(_PREHASH_AgentData);
|
|
msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
|
|
msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
|
|
msg->nextBlockFast(_PREHASH_ObjectData);
|
|
msg->addUUIDFast(_PREHASH_ObjectID, mGrabObject->getID() );
|
|
msg->addQuatFast(_PREHASH_Rotation, mSpinRotation );
|
|
msg->sendMessage( mGrabObject->getRegion()->getHost() );
|
|
}
|
|
else
|
|
{
|
|
//------------------------------------------------------
|
|
// Handle grabbing
|
|
//------------------------------------------------------
|
|
|
|
LLVector3d x_part;
|
|
x_part.setVec(gCamera->getLeftAxis());
|
|
x_part.mdV[VZ] = 0.0;
|
|
x_part.normVec();
|
|
|
|
LLVector3d y_part;
|
|
if( mVerticalDragging )
|
|
{
|
|
y_part.setVec(gCamera->getUpAxis());
|
|
// y_part.setVec(0.f, 0.f, 1.f);
|
|
}
|
|
else
|
|
{
|
|
// drag toward camera
|
|
y_part = x_part % LLVector3d::z_axis;
|
|
y_part.mdV[VZ] = 0.0;
|
|
y_part.normVec();
|
|
}
|
|
|
|
mGrabHiddenOffsetFromCamera = mGrabHiddenOffsetFromCamera
|
|
+ (x_part * (-dx * SENSITIVITY_X))
|
|
+ (y_part * ( dy * SENSITIVITY_Y));
|
|
|
|
|
|
// Send the message to the viewer.
|
|
F32 dt = mGrabTimer.getElapsedTimeAndResetF32();
|
|
U32 dt_milliseconds = (U32) (1000.f * dt);
|
|
|
|
// need to return offset from mGrabStartPoint
|
|
LLVector3d grab_point_global;
|
|
|
|
grab_point_global = gAgent.getCameraPositionGlobal() + mGrabHiddenOffsetFromCamera;
|
|
|
|
/* Snap to grid disabled for grab tool - very confusing
|
|
// Handle snapping to grid, but only when the tool is formally selected.
|
|
BOOL snap_on = gSavedSettings.getBOOL("SnapEnabled");
|
|
if (snap_on && !gGrabTransientTool)
|
|
{
|
|
F64 snap_size = gSavedSettings.getF32("GridResolution");
|
|
U8 snap_dimensions = (mVerticalDragging ? 3 : 2);
|
|
|
|
for (U8 i = 0; i < snap_dimensions; i++)
|
|
{
|
|
grab_point_global.mdV[i] += snap_size / 2;
|
|
grab_point_global.mdV[i] -= fmod(grab_point_global.mdV[i], snap_size);
|
|
}
|
|
}
|
|
*/
|
|
|
|
// Don't let object centers go underground.
|
|
F32 land_height = gWorldPointer->resolveLandHeightGlobal(grab_point_global);
|
|
|
|
if (grab_point_global.mdV[VZ] < land_height)
|
|
{
|
|
grab_point_global.mdV[VZ] = land_height;
|
|
}
|
|
|
|
// For safety, cap heights where objects can be dragged
|
|
if (grab_point_global.mdV[VZ] > MAX_OBJECT_Z)
|
|
{
|
|
grab_point_global.mdV[VZ] = MAX_OBJECT_Z;
|
|
}
|
|
|
|
grab_point_global = gWorldp->clipToVisibleRegions(mDragStartPointGlobal, grab_point_global);
|
|
// propagate constrained grab point back to grab offset
|
|
mGrabHiddenOffsetFromCamera = grab_point_global - gAgent.getCameraPositionGlobal();
|
|
|
|
// Handle auto-rotation at screen edge.
|
|
LLVector3 grab_pos_agent = gAgent.getPosAgentFromGlobal( grab_point_global );
|
|
|
|
LLCoordGL grab_center_gl( gViewerWindow->getWindowWidth() / 2, gViewerWindow->getWindowHeight() / 2);
|
|
gCamera->projectPosAgentToScreen(grab_pos_agent, grab_center_gl);
|
|
|
|
const S32 ROTATE_H_MARGIN = gViewerWindow->getWindowWidth() / 20;
|
|
const F32 ROTATE_ANGLE_PER_SECOND = 30.f * DEG_TO_RAD;
|
|
const F32 rotate_angle = ROTATE_ANGLE_PER_SECOND / gFPSClamped;
|
|
// ...build mode moves camera about focus point
|
|
if (grab_center_gl.mX < ROTATE_H_MARGIN)
|
|
{
|
|
if (gAgent.getFocusOnAvatar())
|
|
{
|
|
gAgent.yaw(rotate_angle);
|
|
}
|
|
else
|
|
{
|
|
gAgent.cameraOrbitAround(rotate_angle);
|
|
}
|
|
}
|
|
else if (grab_center_gl.mX > gViewerWindow->getWindowWidth() - ROTATE_H_MARGIN)
|
|
{
|
|
if (gAgent.getFocusOnAvatar())
|
|
{
|
|
gAgent.yaw(-rotate_angle);
|
|
}
|
|
else
|
|
{
|
|
gAgent.cameraOrbitAround(-rotate_angle);
|
|
}
|
|
}
|
|
|
|
// Don't move above top of screen or below bottom
|
|
if ((grab_center_gl.mY < gViewerWindow->getWindowHeight() - 6)
|
|
&& (grab_center_gl.mY > 24))
|
|
{
|
|
// Transmit update to simulator
|
|
LLVector3 grab_pos_region = mGrabObject->getRegion()->getPosRegionFromGlobal( grab_point_global );
|
|
|
|
LLMessageSystem *msg = gMessageSystem;
|
|
msg->newMessageFast(_PREHASH_ObjectGrabUpdate);
|
|
msg->nextBlockFast(_PREHASH_AgentData);
|
|
msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
|
|
msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
|
|
msg->nextBlockFast(_PREHASH_ObjectData);
|
|
msg->addUUIDFast(_PREHASH_ObjectID, mGrabObject->getID() );
|
|
msg->addVector3Fast(_PREHASH_GrabOffsetInitial, mGrabOffsetFromCenterInitial );
|
|
msg->addVector3Fast(_PREHASH_GrabPosition, grab_pos_region );
|
|
msg->addU32Fast(_PREHASH_TimeSinceLast, dt_milliseconds );
|
|
msg->sendMessage( mGrabObject->getRegion()->getHost() );
|
|
}
|
|
}
|
|
|
|
gViewerWindow->moveCursorToCenter();
|
|
|
|
gSelectMgr->updateSelectionCenter();
|
|
|
|
}
|
|
|
|
// once we've initiated a drag, lock the camera down
|
|
if (mHasMoved)
|
|
{
|
|
if (!gAgent.cameraMouselook() &&
|
|
!mGrabObject->isHUDAttachment() &&
|
|
mGrabObject->getRoot() == gAgent.getAvatarObject()->getRoot())
|
|
{
|
|
// force focus to point in space where we were looking previously
|
|
gAgent.setFocusGlobal(gAgent.calcFocusPositionTargetGlobal(), LLUUID::null);
|
|
gAgent.setFocusOnAvatar(FALSE, ANIMATE);
|
|
}
|
|
else
|
|
{
|
|
gAgent.clearFocusObject();
|
|
}
|
|
}
|
|
|
|
// 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.
|
|
gViewerWindow->setCursor(UI_CURSOR_ARROW);
|
|
|
|
lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolGrab (active) [cursor hidden]" << llendl;
|
|
}
|
|
|
|
|
|
// Not dragging. Just showing affordances
|
|
void LLToolGrab::handleHoverInactive(S32 x, S32 y, MASK mask)
|
|
{
|
|
const F32 ROTATE_ANGLE_PER_SECOND = 40.f * DEG_TO_RAD;
|
|
const F32 rotate_angle = ROTATE_ANGLE_PER_SECOND / gFPSClamped;
|
|
|
|
// Look for cursor against the edge of the screen
|
|
// Only works in fullscreen
|
|
if (gSavedSettings.getBOOL("FullScreen"))
|
|
{
|
|
if (gAgent.cameraThirdPerson() )
|
|
{
|
|
if (x == 0)
|
|
{
|
|
gAgent.yaw(rotate_angle);
|
|
//gAgent.setControlFlags(AGENT_CONTROL_YAW_POS);
|
|
}
|
|
else if (x == (gViewerWindow->getWindowWidth() - 1) )
|
|
{
|
|
gAgent.yaw(-rotate_angle);
|
|
//gAgent.setControlFlags(AGENT_CONTROL_YAW_NEG);
|
|
}
|
|
}
|
|
}
|
|
|
|
// JC - TODO - change cursor based on gGrabBtnVertical, gGrabBtnSpin
|
|
lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolGrab (inactive-not over editable object)" << llendl;
|
|
gViewerWindow->setCursor(UI_CURSOR_TOOLGRAB);
|
|
}
|
|
|
|
// User is trying to do something that's not allowed.
|
|
void LLToolGrab::handleHoverFailed(S32 x, S32 y, MASK mask)
|
|
{
|
|
if( GRAB_NOOBJECT == mMode )
|
|
{
|
|
gViewerWindow->setCursor(UI_CURSOR_NO);
|
|
lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolGrab (not on object)" << llendl;
|
|
}
|
|
else
|
|
{
|
|
S32 dist_sq = (x-mMouseDownX) * (x-mMouseDownX) + (y-mMouseDownY) * (y-mMouseDownY);
|
|
if( mOutsideSlop || dist_sq > SLOP_DIST_SQ )
|
|
{
|
|
mOutsideSlop = TRUE;
|
|
|
|
switch( mMode )
|
|
{
|
|
case GRAB_LOCKED:
|
|
gViewerWindow->setCursor(UI_CURSOR_GRABLOCKED);
|
|
lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolGrab (grab failed, no move permission)" << llendl;
|
|
break;
|
|
|
|
// Non physical now handled by handleHoverActive - CRO
|
|
// case GRAB_NONPHYSICAL:
|
|
// gViewerWindow->setCursor(UI_CURSOR_ARROW);
|
|
// lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolGrab (grab failed, nonphysical)" << llendl;
|
|
// break;
|
|
default:
|
|
llassert(0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
gViewerWindow->setCursor(UI_CURSOR_ARROW);
|
|
lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolGrab (grab failed but within slop)" << llendl;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL LLToolGrab::handleMouseUp(S32 x, S32 y, MASK mask)
|
|
{
|
|
// call the base class to propogate info to sim
|
|
LLTool::handleMouseUp(x, y, mask);
|
|
|
|
if( hasMouseCapture() )
|
|
{
|
|
setMouseCapture( FALSE );
|
|
}
|
|
mMode = GRAB_INACTIVE;
|
|
|
|
// HACK: Make some grabs temporary
|
|
if (gGrabTransientTool)
|
|
{
|
|
gBasicToolset->selectTool( gGrabTransientTool );
|
|
gGrabTransientTool = NULL;
|
|
}
|
|
|
|
//gAgent.setObjectTracking(gSavedSettings.getBOOL("TrackFocusObject"));
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void LLToolGrab::stopEditing()
|
|
{
|
|
if( hasMouseCapture() )
|
|
{
|
|
setMouseCapture( FALSE );
|
|
}
|
|
}
|
|
|
|
void LLToolGrab::onMouseCaptureLost()
|
|
{
|
|
// First, fix cursor placement
|
|
if( !gAgent.cameraMouselook()
|
|
&& (GRAB_ACTIVE_CENTER == mMode || GRAB_NONPHYSICAL == mMode))
|
|
{
|
|
llassert( mGrabObject );
|
|
|
|
if (mGrabObject->isHUDAttachment())
|
|
{
|
|
// ...move cursor "naturally", as if it had moved when hidden
|
|
S32 x = mMouseDownX + mAccumDeltaX;
|
|
S32 y = mMouseDownY + mAccumDeltaY;
|
|
LLUI::setCursorPositionScreen(x, y);
|
|
}
|
|
else if (mHasMoved)
|
|
{
|
|
// ...move cursor back to the center of the object
|
|
LLVector3 grab_point_agent = mGrabObject->getRenderPosition();
|
|
|
|
LLCoordGL gl_point;
|
|
gCamera->projectPosAgentToScreen(grab_point_agent, gl_point);
|
|
|
|
LLUI::setCursorPositionScreen(gl_point.mX, gl_point.mY);
|
|
}
|
|
else
|
|
{
|
|
// ...move cursor back to click position
|
|
LLUI::setCursorPositionScreen(mMouseDownX, mMouseDownY);
|
|
}
|
|
|
|
gViewerWindow->showCursor();
|
|
}
|
|
|
|
stopGrab();
|
|
stopSpin();
|
|
mMode = GRAB_INACTIVE;
|
|
|
|
mHideBuildHighlight = FALSE;
|
|
|
|
mGrabObject = NULL;
|
|
|
|
gSelectMgr->updateSelectionCenter();
|
|
gAgent.setPointAt(POINTAT_TARGET_CLEAR);
|
|
gAgent.setLookAt(LOOKAT_TARGET_CLEAR);
|
|
|
|
dialog_refresh_all();
|
|
}
|
|
|
|
|
|
void LLToolGrab::stopGrab()
|
|
{
|
|
// Next, send messages to simulator
|
|
LLMessageSystem *msg = gMessageSystem;
|
|
switch(mMode)
|
|
{
|
|
case GRAB_ACTIVE_CENTER:
|
|
case GRAB_NONPHYSICAL:
|
|
case GRAB_LOCKED:
|
|
msg->newMessageFast(_PREHASH_ObjectDeGrab);
|
|
msg->nextBlockFast(_PREHASH_AgentData);
|
|
msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
|
|
msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
|
|
msg->nextBlockFast(_PREHASH_ObjectData);
|
|
msg->addU32Fast(_PREHASH_LocalID, mGrabObject->mLocalID);
|
|
msg->sendMessage(mGrabObject->getRegion()->getHost());
|
|
|
|
mVerticalDragging = FALSE;
|
|
mGrabOffset.clearVec();
|
|
break;
|
|
|
|
case GRAB_NOOBJECT:
|
|
case GRAB_INACTIVE:
|
|
default:
|
|
// do nothing
|
|
break;
|
|
}
|
|
|
|
mHideBuildHighlight = FALSE;
|
|
}
|
|
|
|
|
|
void LLToolGrab::draw()
|
|
{ }
|
|
|
|
void LLToolGrab::render()
|
|
{ }
|
|
|
|
BOOL LLToolGrab::isEditing()
|
|
{
|
|
// Can't just compare to null directly due to "smart" pointer.
|
|
LLViewerObject *obj = mGrabObject;
|
|
return (obj != NULL);
|
|
}
|
|
|
|
LLViewerObject* LLToolGrab::getEditingObject()
|
|
{
|
|
return mGrabObject;
|
|
}
|
|
|
|
|
|
LLVector3d LLToolGrab::getEditingPointGlobal()
|
|
{
|
|
return getGrabPointGlobal();
|
|
}
|
|
|
|
LLVector3d LLToolGrab::getGrabPointGlobal()
|
|
{
|
|
switch(mMode)
|
|
{
|
|
case GRAB_ACTIVE_CENTER:
|
|
case GRAB_NONPHYSICAL:
|
|
case GRAB_LOCKED:
|
|
return gAgent.getCameraPositionGlobal() + mGrabHiddenOffsetFromCamera;
|
|
|
|
case GRAB_NOOBJECT:
|
|
case GRAB_INACTIVE:
|
|
default:
|
|
return gAgent.getPositionGlobal();
|
|
}
|
|
}
|