PageRenderTime 119ms CodeModel.GetById 18ms app.highlight 89ms RepoModel.GetById 1ms app.codeStats 1ms

/indra/newview/llagentcamera.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 1985 lines | 1411 code | 298 blank | 276 comment | 291 complexity | 2f86ba108ab5e2059d20104bd762e219 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1/** 
   2 * @file llagentcamera.cpp
   3 * @brief LLAgent 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
  27#include "llviewerprecompiledheaders.h"
  28#include "llagentcamera.h" 
  29
  30#include "pipeline.h"
  31
  32#include "llagent.h"
  33#include "llanimationstates.h"
  34#include "llfloatercamera.h"
  35#include "llfloaterreg.h"
  36#include "llhudmanager.h"
  37#include "lljoystickbutton.h"
  38#include "llselectmgr.h"
  39#include "llsmoothstep.h"
  40#include "lltoolmgr.h"
  41#include "llviewercamera.h"
  42#include "llviewercontrol.h"
  43#include "llviewerjoystick.h"
  44#include "llviewermenu.h"
  45#include "llviewerobjectlist.h"
  46#include "llviewerregion.h"
  47#include "llviewerwindow.h"
  48#include "llvoavatarself.h"
  49#include "llwindow.h"
  50#include "llworld.h"
  51
  52using namespace LLVOAvatarDefines;
  53
  54extern LLMenuBarGL* gMenuBarView;
  55
  56// Mousewheel camera zoom
  57const F32 MIN_ZOOM_FRACTION = 0.25f;
  58const F32 INITIAL_ZOOM_FRACTION = 1.f;
  59const F32 MAX_ZOOM_FRACTION = 8.f;
  60
  61const F32 CAMERA_ZOOM_HALF_LIFE = 0.07f;	// seconds
  62const F32 FOV_ZOOM_HALF_LIFE = 0.07f;	// seconds
  63
  64const F32 CAMERA_FOCUS_HALF_LIFE = 0.f;//0.02f;
  65const F32 CAMERA_LAG_HALF_LIFE = 0.25f;
  66const F32 MIN_CAMERA_LAG = 0.5f;
  67const F32 MAX_CAMERA_LAG = 5.f;
  68
  69const F32 CAMERA_COLLIDE_EPSILON = 0.1f;
  70const F32 MIN_CAMERA_DISTANCE = 0.1f;
  71
  72const F32 AVATAR_ZOOM_MIN_X_FACTOR = 0.55f;
  73const F32 AVATAR_ZOOM_MIN_Y_FACTOR = 0.7f;
  74const F32 AVATAR_ZOOM_MIN_Z_FACTOR = 1.15f;
  75
  76const F32 MAX_CAMERA_DISTANCE_FROM_AGENT = 50.f;
  77
  78const F32 MAX_CAMERA_SMOOTH_DISTANCE = 50.0f;
  79
  80const F32 HEAD_BUFFER_SIZE = 0.3f;
  81
  82const F32 CUSTOMIZE_AVATAR_CAMERA_ANIM_SLOP = 0.1f;
  83
  84const F32 LAND_MIN_ZOOM = 0.15f;
  85
  86const F32 AVATAR_MIN_ZOOM = 0.5f;
  87const F32 OBJECT_MIN_ZOOM = 0.02f;
  88
  89const F32 APPEARANCE_MIN_ZOOM = 0.39f;
  90const F32 APPEARANCE_MAX_ZOOM = 8.f;
  91
  92const F32 CUSTOMIZE_AVATAR_CAMERA_DEFAULT_DIST = 3.5f;
  93
  94const F32 GROUND_TO_AIR_CAMERA_TRANSITION_TIME = 0.5f;
  95const F32 GROUND_TO_AIR_CAMERA_TRANSITION_START_TIME = 0.5f;
  96
  97const F32 OBJECT_EXTENTS_PADDING = 0.5f;
  98
  99// The agent instance.
 100LLAgentCamera gAgentCamera;
 101
 102//-----------------------------------------------------------------------------
 103// LLAgentCamera()
 104//-----------------------------------------------------------------------------
 105LLAgentCamera::LLAgentCamera() :
 106	mInitialized(false),
 107
 108	mDrawDistance( DEFAULT_FAR_PLANE ),
 109
 110	mLookAt(NULL),
 111	mPointAt(NULL),
 112
 113	mHUDTargetZoom(1.f),
 114	mHUDCurZoom(1.f),
 115
 116	mForceMouselook(FALSE),
 117
 118	mCameraMode( CAMERA_MODE_THIRD_PERSON ),
 119	mLastCameraMode( CAMERA_MODE_THIRD_PERSON ),
 120
 121	mCameraPreset(CAMERA_PRESET_REAR_VIEW),
 122
 123	mCameraAnimating( FALSE ),
 124	mAnimationCameraStartGlobal(),
 125	mAnimationFocusStartGlobal(),
 126	mAnimationTimer(),
 127	mAnimationDuration(0.33f),
 128	
 129	mCameraFOVZoomFactor(0.f),
 130	mCameraCurrentFOVZoomFactor(0.f),
 131	mCameraFocusOffset(),
 132	mCameraFOVDefault(DEFAULT_FIELD_OF_VIEW),
 133
 134	mCameraCollidePlane(),
 135
 136	mCurrentCameraDistance(2.f),		// meters, set in init()
 137	mTargetCameraDistance(2.f),
 138	mCameraZoomFraction(1.f),			// deprecated
 139	mThirdPersonHeadOffset(0.f, 0.f, 1.f),
 140	mSitCameraEnabled(FALSE),
 141	mCameraSmoothingLastPositionGlobal(),
 142	mCameraSmoothingLastPositionAgent(),
 143	mCameraSmoothingStop(false),
 144
 145	mCameraUpVector(LLVector3::z_axis), // default is straight up
 146
 147	mFocusOnAvatar(TRUE),
 148	mFocusGlobal(),
 149	mFocusTargetGlobal(),
 150	mFocusObject(NULL),
 151	mFocusObjectDist(0.f),
 152	mFocusObjectOffset(),
 153	mFocusDotRadius( 0.1f ),			// meters
 154	mTrackFocusObject(TRUE),
 155
 156	mAtKey(0), // Either 1, 0, or -1... indicates that movement-key is pressed
 157	mWalkKey(0), // like AtKey, but causes less forward thrust
 158	mLeftKey(0),
 159	mUpKey(0),
 160	mYawKey(0.f),
 161	mPitchKey(0.f),
 162
 163	mOrbitLeftKey(0.f),
 164	mOrbitRightKey(0.f),
 165	mOrbitUpKey(0.f),
 166	mOrbitDownKey(0.f),
 167	mOrbitInKey(0.f),
 168	mOrbitOutKey(0.f),
 169
 170	mPanUpKey(0.f),
 171	mPanDownKey(0.f),
 172	mPanLeftKey(0.f),
 173	mPanRightKey(0.f),
 174	mPanInKey(0.f),
 175	mPanOutKey(0.f)
 176{
 177	mFollowCam.setMaxCameraDistantFromSubject( MAX_CAMERA_DISTANCE_FROM_AGENT );
 178
 179	clearGeneralKeys();
 180	clearOrbitKeys();
 181	clearPanKeys();
 182}
 183
 184// Requires gSavedSettings to be initialized.
 185//-----------------------------------------------------------------------------
 186// init()
 187//-----------------------------------------------------------------------------
 188void LLAgentCamera::init()
 189{
 190	// *Note: this is where LLViewerCamera::getInstance() used to be constructed.
 191
 192	mDrawDistance = gSavedSettings.getF32("RenderFarClip");
 193
 194	LLViewerCamera::getInstance()->setView(DEFAULT_FIELD_OF_VIEW);
 195	// Leave at 0.1 meters until we have real near clip management
 196	LLViewerCamera::getInstance()->setNear(0.1f);
 197	LLViewerCamera::getInstance()->setFar(mDrawDistance);			// if you want to change camera settings, do so in camera.h
 198	LLViewerCamera::getInstance()->setAspect( gViewerWindow->getWorldViewAspectRatio() );		// default, overridden in LLViewerWindow::reshape
 199	LLViewerCamera::getInstance()->setViewHeightInPixels(768);			// default, overridden in LLViewerWindow::reshape
 200
 201	mCameraFocusOffsetTarget = LLVector4(gSavedSettings.getVector3("CameraOffsetBuild"));
 202	
 203	mCameraPreset = (ECameraPreset) gSavedSettings.getU32("CameraPreset");
 204
 205	mCameraOffsetInitial[CAMERA_PRESET_REAR_VIEW] = gSavedSettings.getControl("CameraOffsetRearView");
 206	mCameraOffsetInitial[CAMERA_PRESET_FRONT_VIEW] = gSavedSettings.getControl("CameraOffsetFrontView");
 207	mCameraOffsetInitial[CAMERA_PRESET_GROUP_VIEW] = gSavedSettings.getControl("CameraOffsetGroupView");
 208
 209	mFocusOffsetInitial[CAMERA_PRESET_REAR_VIEW] = gSavedSettings.getControl("FocusOffsetRearView");
 210	mFocusOffsetInitial[CAMERA_PRESET_FRONT_VIEW] = gSavedSettings.getControl("FocusOffsetFrontView");
 211	mFocusOffsetInitial[CAMERA_PRESET_GROUP_VIEW] = gSavedSettings.getControl("FocusOffsetGroupView");
 212
 213	mCameraCollidePlane.clearVec();
 214	mCurrentCameraDistance = getCameraOffsetInitial().magVec() * gSavedSettings.getF32("CameraOffsetScale");
 215	mTargetCameraDistance = mCurrentCameraDistance;
 216	mCameraZoomFraction = 1.f;
 217	mTrackFocusObject = gSavedSettings.getBOOL("TrackFocusObject");
 218
 219	mInitialized = true;
 220}
 221
 222//-----------------------------------------------------------------------------
 223// cleanup()
 224//-----------------------------------------------------------------------------
 225void LLAgentCamera::cleanup()
 226{
 227	setSitCamera(LLUUID::null);
 228
 229	if(mLookAt)
 230	{
 231		mLookAt->markDead() ;
 232		mLookAt = NULL;
 233	}
 234	if(mPointAt)
 235	{
 236		mPointAt->markDead() ;
 237		mPointAt = NULL;
 238	}
 239	setFocusObject(NULL);
 240}
 241
 242void LLAgentCamera::setAvatarObject(LLVOAvatarSelf* avatar)
 243{
 244	if (!mLookAt)
 245	{
 246		mLookAt = (LLHUDEffectLookAt *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_LOOKAT);
 247	}
 248	if (!mPointAt)
 249	{
 250		mPointAt = (LLHUDEffectPointAt *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINTAT);
 251	}
 252	
 253	if (!mLookAt.isNull())
 254	{
 255		mLookAt->setSourceObject(avatar);
 256	}
 257	if (!mPointAt.isNull())
 258	{
 259		mPointAt->setSourceObject(avatar);
 260	}	
 261}
 262
 263//-----------------------------------------------------------------------------
 264// LLAgent()
 265//-----------------------------------------------------------------------------
 266LLAgentCamera::~LLAgentCamera()
 267{
 268	cleanup();
 269
 270	// *Note: this is where LLViewerCamera::getInstance() used to be deleted.
 271}
 272
 273// Change camera back to third person, stop the autopilot,
 274// deselect stuff, etc.
 275//-----------------------------------------------------------------------------
 276// resetView()
 277//-----------------------------------------------------------------------------
 278void LLAgentCamera::resetView(BOOL reset_camera, BOOL change_camera)
 279{
 280	if (gAgent.getAutoPilot())
 281	{
 282		gAgent.stopAutoPilot(TRUE);
 283	}
 284
 285	LLSelectMgr::getInstance()->unhighlightAll();
 286
 287	// By popular request, keep land selection while walking around. JC
 288	// LLViewerParcelMgr::getInstance()->deselectLand();
 289
 290	// force deselect when walking and attachment is selected
 291	// this is so people don't wig out when their avatar moves without animating
 292	if (LLSelectMgr::getInstance()->getSelection()->isAttachment())
 293	{
 294		LLSelectMgr::getInstance()->deselectAll();
 295	}
 296
 297	if (gMenuHolder != NULL)
 298	{
 299		// Hide all popup menus
 300		gMenuHolder->hideMenus();
 301	}
 302
 303	if (change_camera && !gSavedSettings.getBOOL("FreezeTime"))
 304	{
 305		changeCameraToDefault();
 306		
 307		if (LLViewerJoystick::getInstance()->getOverrideCamera())
 308		{
 309			handle_toggle_flycam();
 310		}
 311
 312		// reset avatar mode from eventual residual motion
 313		if (LLToolMgr::getInstance()->inBuildMode())
 314		{
 315			LLViewerJoystick::getInstance()->moveAvatar(true);
 316		}
 317
 318		//Camera Tool is needed for Free Camera Control Mode
 319		if (!LLFloaterCamera::inFreeCameraMode())
 320		{
 321			LLFloaterReg::hideInstance("build");
 322
 323			// Switch back to basic toolset
 324			LLToolMgr::getInstance()->setCurrentToolset(gBasicToolset);
 325		}
 326		
 327		gViewerWindow->showCursor();
 328	}
 329
 330
 331	if (reset_camera && !gSavedSettings.getBOOL("FreezeTime"))
 332	{
 333		if (!gViewerWindow->getLeftMouseDown() && cameraThirdPerson())
 334		{
 335			// leaving mouse-steer mode
 336			LLVector3 agent_at_axis = gAgent.getAtAxis();
 337			agent_at_axis -= projected_vec(agent_at_axis, gAgent.getReferenceUpVector());
 338			agent_at_axis.normalize();
 339			gAgent.resetAxes(lerp(gAgent.getAtAxis(), agent_at_axis, LLCriticalDamp::getInterpolant(0.3f)));
 340		}
 341
 342		setFocusOnAvatar(TRUE, ANIMATE);
 343
 344		mCameraFOVZoomFactor = 0.f;
 345	}
 346
 347	mHUDTargetZoom = 1.f;
 348}
 349
 350// Allow camera to be moved somewhere other than behind avatar.
 351//-----------------------------------------------------------------------------
 352// unlockView()
 353//-----------------------------------------------------------------------------
 354void LLAgentCamera::unlockView()
 355{
 356	if (getFocusOnAvatar())
 357	{
 358		if (isAgentAvatarValid())
 359		{
 360			setFocusGlobal(LLVector3d::zero, gAgentAvatarp->mID);
 361		}
 362		setFocusOnAvatar(FALSE, FALSE);	// no animation
 363	}
 364}
 365
 366//-----------------------------------------------------------------------------
 367// slamLookAt()
 368//-----------------------------------------------------------------------------
 369void LLAgentCamera::slamLookAt(const LLVector3 &look_at)
 370{
 371	LLVector3 look_at_norm = look_at;
 372	look_at_norm.mV[VZ] = 0.f;
 373	look_at_norm.normalize();
 374	gAgent.resetAxes(look_at_norm);
 375}
 376
 377//-----------------------------------------------------------------------------
 378// calcFocusOffset()
 379//-----------------------------------------------------------------------------
 380LLVector3 LLAgentCamera::calcFocusOffset(LLViewerObject *object, LLVector3 original_focus_point, S32 x, S32 y)
 381{
 382	LLMatrix4 obj_matrix = object->getRenderMatrix();
 383	LLQuaternion obj_rot = object->getRenderRotation();
 384	LLVector3 obj_pos = object->getRenderPosition();
 385
 386	BOOL is_avatar = object->isAvatar();
 387	// if is avatar - don't do any funk heuristics to position the focal point
 388	// see DEV-30589
 389	if (is_avatar)
 390	{
 391		return original_focus_point - obj_pos;
 392	}
 393	
 394	LLQuaternion inv_obj_rot = ~obj_rot; // get inverse of rotation
 395	LLVector3 object_extents = object->getScale();	
 396	
 397	// make sure they object extents are non-zero
 398	object_extents.clamp(0.001f, F32_MAX);
 399
 400	// obj_to_cam_ray is unit vector pointing from object center to camera, in the coordinate frame of the object
 401	LLVector3 obj_to_cam_ray = obj_pos - LLViewerCamera::getInstance()->getOrigin();
 402	obj_to_cam_ray.rotVec(inv_obj_rot);
 403	obj_to_cam_ray.normalize();
 404
 405	// obj_to_cam_ray_proportions are the (positive) ratios of 
 406	// the obj_to_cam_ray x,y,z components with the x,y,z object dimensions.
 407	LLVector3 obj_to_cam_ray_proportions;
 408	obj_to_cam_ray_proportions.mV[VX] = llabs(obj_to_cam_ray.mV[VX] / object_extents.mV[VX]);
 409	obj_to_cam_ray_proportions.mV[VY] = llabs(obj_to_cam_ray.mV[VY] / object_extents.mV[VY]);
 410	obj_to_cam_ray_proportions.mV[VZ] = llabs(obj_to_cam_ray.mV[VZ] / object_extents.mV[VZ]);
 411
 412	// find the largest ratio stored in obj_to_cam_ray_proportions
 413	// this corresponds to the object's local axial plane (XY, YZ, XZ) that is *most* facing the camera
 414	LLVector3 longest_object_axis;
 415	// is x-axis longest?
 416	if (obj_to_cam_ray_proportions.mV[VX] > obj_to_cam_ray_proportions.mV[VY] 
 417		&& obj_to_cam_ray_proportions.mV[VX] > obj_to_cam_ray_proportions.mV[VZ])
 418	{
 419		// then grab it
 420		longest_object_axis.setVec(obj_matrix.getFwdRow4());
 421	}
 422	// is y-axis longest?
 423	else if (obj_to_cam_ray_proportions.mV[VY] > obj_to_cam_ray_proportions.mV[VZ])
 424	{
 425		// then grab it
 426		longest_object_axis.setVec(obj_matrix.getLeftRow4());
 427	}
 428	// otherwise, use z axis
 429	else
 430	{
 431		longest_object_axis.setVec(obj_matrix.getUpRow4());
 432	}
 433
 434	// Use this axis as the normal to project mouse click on to plane with that normal, at the object center.
 435	// This generates a point behind the mouse cursor that is approximately in the middle of the object in
 436	// terms of depth.  
 437	// We do this to allow the camera rotation tool to "tumble" the object by rotating the camera.
 438	// If the focus point were the object surface under the mouse, camera rotation would introduce an undesirable
 439	// eccentricity to the object orientation
 440	LLVector3 focus_plane_normal(longest_object_axis);
 441	focus_plane_normal.normalize();
 442
 443	LLVector3d focus_pt_global;
 444	gViewerWindow->mousePointOnPlaneGlobal(focus_pt_global, x, y, gAgent.getPosGlobalFromAgent(obj_pos), focus_plane_normal);
 445	LLVector3 focus_pt = gAgent.getPosAgentFromGlobal(focus_pt_global);
 446
 447	// find vector from camera to focus point in object space
 448	LLVector3 camera_to_focus_vec = focus_pt - LLViewerCamera::getInstance()->getOrigin();
 449	camera_to_focus_vec.rotVec(inv_obj_rot);
 450
 451	// find vector from object origin to focus point in object coordinates
 452	LLVector3 focus_offset_from_object_center = focus_pt - obj_pos;
 453	// convert to object-local space
 454	focus_offset_from_object_center.rotVec(inv_obj_rot);
 455
 456	// We need to project the focus point back into the bounding box of the focused object.
 457	// Do this by calculating the XYZ scale factors needed to get focus offset back in bounds along the camera_focus axis
 458	LLVector3 clip_fraction;
 459
 460	// for each axis...
 461	for (U32 axis = VX; axis <= VZ; axis++)
 462	{
 463		//...calculate distance that focus offset sits outside of bounding box along that axis...
 464		//NOTE: dist_out_of_bounds keeps the sign of focus_offset_from_object_center 
 465		F32 dist_out_of_bounds;
 466		if (focus_offset_from_object_center.mV[axis] > 0.f)
 467		{
 468			dist_out_of_bounds = llmax(0.f, focus_offset_from_object_center.mV[axis] - (object_extents.mV[axis] * 0.5f));
 469		}
 470		else
 471		{
 472			dist_out_of_bounds = llmin(0.f, focus_offset_from_object_center.mV[axis] + (object_extents.mV[axis] * 0.5f));
 473		}
 474
 475		//...then calculate the scale factor needed to push camera_to_focus_vec back in bounds along current axis
 476		if (llabs(camera_to_focus_vec.mV[axis]) < 0.0001f)
 477		{
 478			// don't divide by very small number
 479			clip_fraction.mV[axis] = 0.f;
 480		}
 481		else
 482		{
 483			clip_fraction.mV[axis] = dist_out_of_bounds / camera_to_focus_vec.mV[axis];
 484		}
 485	}
 486
 487	LLVector3 abs_clip_fraction = clip_fraction;
 488	abs_clip_fraction.abs();
 489
 490	// find axis of focus offset that is *most* outside the bounding box and use that to
 491	// rescale focus offset to inside object extents
 492	if (abs_clip_fraction.mV[VX] > abs_clip_fraction.mV[VY]
 493		&& abs_clip_fraction.mV[VX] > abs_clip_fraction.mV[VZ])
 494	{
 495		focus_offset_from_object_center -= clip_fraction.mV[VX] * camera_to_focus_vec;
 496	}
 497	else if (abs_clip_fraction.mV[VY] > abs_clip_fraction.mV[VZ])
 498	{
 499		focus_offset_from_object_center -= clip_fraction.mV[VY] * camera_to_focus_vec;
 500	}
 501	else
 502	{
 503		focus_offset_from_object_center -= clip_fraction.mV[VZ] * camera_to_focus_vec;
 504	}
 505
 506	// convert back to world space
 507	focus_offset_from_object_center.rotVec(obj_rot);
 508	
 509	// now, based on distance of camera from object relative to object size
 510	// push the focus point towards the near surface of the object when (relatively) close to the objcet
 511	// or keep the focus point in the object middle when (relatively) far
 512	// NOTE: leave focus point in middle of avatars, since the behavior you want when alt-zooming on avatars
 513	// is almost always "tumble about middle" and not "spin around surface point"
 514	if (!is_avatar) 
 515	{
 516		LLVector3 obj_rel = original_focus_point - object->getRenderPosition();
 517		
 518		//now that we have the object relative position, we should bias toward the center of the object 
 519		//based on the distance of the camera to the focus point vs. the distance of the camera to the focus
 520
 521		F32 relDist = llabs(obj_rel * LLViewerCamera::getInstance()->getAtAxis());
 522		F32 viewDist = dist_vec(obj_pos + obj_rel, LLViewerCamera::getInstance()->getOrigin());
 523
 524
 525		LLBBox obj_bbox = object->getBoundingBoxAgent();
 526		F32 bias = 0.f;
 527
 528		// virtual_camera_pos is the camera position we are simulating by backing the camera off
 529		// and adjusting the FOV
 530		LLVector3 virtual_camera_pos = gAgent.getPosAgentFromGlobal(mFocusTargetGlobal + (getCameraPositionGlobal() - mFocusTargetGlobal) / (1.f + mCameraFOVZoomFactor));
 531
 532		// if the camera is inside the object (large, hollow objects, for example)
 533		// leave focus point all the way to destination depth, away from object center
 534		if(!obj_bbox.containsPointAgent(virtual_camera_pos))
 535		{
 536			// perform magic number biasing of focus point towards surface vs. planar center
 537			bias = clamp_rescale(relDist/viewDist, 0.1f, 0.7f, 0.0f, 1.0f);
 538			obj_rel = lerp(focus_offset_from_object_center, obj_rel, bias);
 539		}
 540			
 541		focus_offset_from_object_center = obj_rel;
 542	}
 543
 544	return focus_offset_from_object_center;
 545}
 546
 547//-----------------------------------------------------------------------------
 548// calcCameraMinDistance()
 549//-----------------------------------------------------------------------------
 550BOOL LLAgentCamera::calcCameraMinDistance(F32 &obj_min_distance)
 551{
 552	BOOL soft_limit = FALSE; // is the bounding box to be treated literally (volumes) or as an approximation (avatars)
 553
 554	if (!mFocusObject || mFocusObject->isDead() || 
 555		mFocusObject->isMesh() ||
 556		gSavedSettings.getBOOL("DisableCameraConstraints"))
 557	{
 558		obj_min_distance = 0.f;
 559		return TRUE;
 560	}
 561
 562	if (mFocusObject->mDrawable.isNull())
 563	{
 564#ifdef LL_RELEASE_FOR_DOWNLOAD
 565		llwarns << "Focus object with no drawable!" << llendl;
 566#else
 567		mFocusObject->dump();
 568		llerrs << "Focus object with no drawable!" << llendl;
 569#endif
 570		obj_min_distance = 0.f;
 571		return TRUE;
 572	}
 573	
 574	LLQuaternion inv_object_rot = ~mFocusObject->getRenderRotation();
 575	LLVector3 target_offset_origin = mFocusObjectOffset;
 576	LLVector3 camera_offset_target(getCameraPositionAgent() - gAgent.getPosAgentFromGlobal(mFocusTargetGlobal));
 577
 578	// convert offsets into object local space
 579	camera_offset_target.rotVec(inv_object_rot);
 580	target_offset_origin.rotVec(inv_object_rot);
 581
 582	// push around object extents based on target offset
 583	LLVector3 object_extents = mFocusObject->getScale();
 584	if (mFocusObject->isAvatar())
 585	{
 586		// fudge factors that lets you zoom in on avatars a bit more (which don't do FOV zoom)
 587		object_extents.mV[VX] *= AVATAR_ZOOM_MIN_X_FACTOR;
 588		object_extents.mV[VY] *= AVATAR_ZOOM_MIN_Y_FACTOR;
 589		object_extents.mV[VZ] *= AVATAR_ZOOM_MIN_Z_FACTOR;
 590		soft_limit = TRUE;
 591	}
 592	LLVector3 abs_target_offset = target_offset_origin;
 593	abs_target_offset.abs();
 594
 595	LLVector3 target_offset_dir = target_offset_origin;
 596	F32 object_radius = mFocusObject->getVObjRadius();
 597
 598	BOOL target_outside_object_extents = FALSE;
 599
 600	for (U32 i = VX; i <= VZ; i++)
 601	{
 602		if (abs_target_offset.mV[i] * 2.f > object_extents.mV[i] + OBJECT_EXTENTS_PADDING)
 603		{
 604			target_outside_object_extents = TRUE;
 605		}
 606		if (camera_offset_target.mV[i] > 0.f)
 607		{
 608			object_extents.mV[i] -= target_offset_origin.mV[i] * 2.f;
 609		}
 610		else
 611		{
 612			object_extents.mV[i] += target_offset_origin.mV[i] * 2.f;
 613		}
 614	}
 615
 616	// don't shrink the object extents so far that the object inverts
 617	object_extents.clamp(0.001f, F32_MAX);
 618
 619	// move into first octant
 620	LLVector3 camera_offset_target_abs_norm = camera_offset_target;
 621	camera_offset_target_abs_norm.abs();
 622	// make sure offset is non-zero
 623	camera_offset_target_abs_norm.clamp(0.001f, F32_MAX);
 624	camera_offset_target_abs_norm.normalize();
 625
 626	// find camera position relative to normalized object extents
 627	LLVector3 camera_offset_target_scaled = camera_offset_target_abs_norm;
 628	camera_offset_target_scaled.mV[VX] /= object_extents.mV[VX];
 629	camera_offset_target_scaled.mV[VY] /= object_extents.mV[VY];
 630	camera_offset_target_scaled.mV[VZ] /= object_extents.mV[VZ];
 631
 632	if (camera_offset_target_scaled.mV[VX] > camera_offset_target_scaled.mV[VY] && 
 633		camera_offset_target_scaled.mV[VX] > camera_offset_target_scaled.mV[VZ])
 634	{
 635		if (camera_offset_target_abs_norm.mV[VX] < 0.001f)
 636		{
 637			obj_min_distance = object_extents.mV[VX] * 0.5f;
 638		}
 639		else
 640		{
 641			obj_min_distance = object_extents.mV[VX] * 0.5f / camera_offset_target_abs_norm.mV[VX];
 642		}
 643	}
 644	else if (camera_offset_target_scaled.mV[VY] > camera_offset_target_scaled.mV[VZ])
 645	{
 646		if (camera_offset_target_abs_norm.mV[VY] < 0.001f)
 647		{
 648			obj_min_distance = object_extents.mV[VY] * 0.5f;
 649		}
 650		else
 651		{
 652			obj_min_distance = object_extents.mV[VY] * 0.5f / camera_offset_target_abs_norm.mV[VY];
 653		}
 654	}
 655	else
 656	{
 657		if (camera_offset_target_abs_norm.mV[VZ] < 0.001f)
 658		{
 659			obj_min_distance = object_extents.mV[VZ] * 0.5f;
 660		}
 661		else
 662		{
 663			obj_min_distance = object_extents.mV[VZ] * 0.5f / camera_offset_target_abs_norm.mV[VZ];
 664		}
 665	}
 666
 667	LLVector3 object_split_axis;
 668	LLVector3 target_offset_scaled = target_offset_origin;
 669	target_offset_scaled.abs();
 670	target_offset_scaled.normalize();
 671	target_offset_scaled.mV[VX] /= object_extents.mV[VX];
 672	target_offset_scaled.mV[VY] /= object_extents.mV[VY];
 673	target_offset_scaled.mV[VZ] /= object_extents.mV[VZ];
 674
 675	if (target_offset_scaled.mV[VX] > target_offset_scaled.mV[VY] && 
 676		target_offset_scaled.mV[VX] > target_offset_scaled.mV[VZ])
 677	{
 678		object_split_axis = LLVector3::x_axis;
 679	}
 680	else if (target_offset_scaled.mV[VY] > target_offset_scaled.mV[VZ])
 681	{
 682		object_split_axis = LLVector3::y_axis;
 683	}
 684	else
 685	{
 686		object_split_axis = LLVector3::z_axis;
 687	}
 688
 689	LLVector3 camera_offset_object(getCameraPositionAgent() - mFocusObject->getPositionAgent());
 690
 691	// length projected orthogonal to target offset
 692	F32 camera_offset_dist = (camera_offset_object - target_offset_dir * (camera_offset_object * target_offset_dir)).magVec();
 693
 694	// calculate whether the target point would be "visible" if it were outside the bounding box
 695	// on the opposite of the splitting plane defined by object_split_axis;
 696	BOOL exterior_target_visible = FALSE;
 697	if (camera_offset_dist > object_radius)
 698	{
 699		// target is visible from camera, so turn off fov zoom
 700		exterior_target_visible = TRUE;
 701	}
 702
 703	F32 camera_offset_clip = camera_offset_object * object_split_axis;
 704	F32 target_offset_clip = target_offset_dir * object_split_axis;
 705
 706	// target has moved outside of object extents
 707	// check to see if camera and target are on same side 
 708	if (target_outside_object_extents)
 709	{
 710		if (camera_offset_clip > 0.f && target_offset_clip > 0.f)
 711		{
 712			return FALSE;
 713		}
 714		else if (camera_offset_clip < 0.f && target_offset_clip < 0.f)
 715		{
 716			return FALSE;
 717		}
 718	}
 719
 720	// clamp obj distance to diagonal of 10 by 10 cube
 721	obj_min_distance = llmin(obj_min_distance, 10.f * F_SQRT3);
 722
 723	obj_min_distance += LLViewerCamera::getInstance()->getNear() + (soft_limit ? 0.1f : 0.2f);
 724	
 725	return TRUE;
 726}
 727
 728F32 LLAgentCamera::getCameraZoomFraction()
 729{
 730	// 0.f -> camera zoomed all the way out
 731	// 1.f -> camera zoomed all the way in
 732	LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection();
 733	if (selection->getObjectCount() && selection->getSelectType() == SELECT_TYPE_HUD)
 734	{
 735		// already [0,1]
 736		return mHUDTargetZoom;
 737	}
 738	else if (mFocusOnAvatar && cameraThirdPerson())
 739	{
 740		return clamp_rescale(mCameraZoomFraction, MIN_ZOOM_FRACTION, MAX_ZOOM_FRACTION, 1.f, 0.f);
 741	}
 742	else if (cameraCustomizeAvatar())
 743	{
 744		F32 distance = (F32)mCameraFocusOffsetTarget.magVec();
 745		return clamp_rescale(distance, APPEARANCE_MIN_ZOOM, APPEARANCE_MAX_ZOOM, 1.f, 0.f );
 746	}
 747	else
 748	{
 749		F32 min_zoom;
 750		const F32 DIST_FUDGE = 16.f; // meters
 751		F32 max_zoom = llmin(mDrawDistance - DIST_FUDGE, 
 752								LLWorld::getInstance()->getRegionWidthInMeters() - DIST_FUDGE,
 753								MAX_CAMERA_DISTANCE_FROM_AGENT);
 754
 755		F32 distance = (F32)mCameraFocusOffsetTarget.magVec();
 756		if (mFocusObject.notNull())
 757		{
 758			if (mFocusObject->isAvatar())
 759			{
 760				min_zoom = AVATAR_MIN_ZOOM;
 761			}
 762			else
 763			{
 764				min_zoom = OBJECT_MIN_ZOOM;
 765			}
 766		}
 767		else
 768		{
 769			min_zoom = LAND_MIN_ZOOM;
 770		}
 771
 772		return clamp_rescale(distance, min_zoom, max_zoom, 1.f, 0.f);
 773	}
 774}
 775
 776void LLAgentCamera::setCameraZoomFraction(F32 fraction)
 777{
 778	// 0.f -> camera zoomed all the way out
 779	// 1.f -> camera zoomed all the way in
 780	LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection();
 781
 782	if (selection->getObjectCount() && selection->getSelectType() == SELECT_TYPE_HUD)
 783	{
 784		mHUDTargetZoom = fraction;
 785	}
 786	else if (mFocusOnAvatar && cameraThirdPerson())
 787	{
 788		mCameraZoomFraction = rescale(fraction, 0.f, 1.f, MAX_ZOOM_FRACTION, MIN_ZOOM_FRACTION);
 789	}
 790	else if (cameraCustomizeAvatar())
 791	{
 792		LLVector3d camera_offset_dir = mCameraFocusOffsetTarget;
 793		camera_offset_dir.normalize();
 794		mCameraFocusOffsetTarget = camera_offset_dir * rescale(fraction, 0.f, 1.f, APPEARANCE_MAX_ZOOM, APPEARANCE_MIN_ZOOM);
 795	}
 796	else
 797	{
 798		F32 min_zoom = LAND_MIN_ZOOM;
 799		const F32 DIST_FUDGE = 16.f; // meters
 800		F32 max_zoom = llmin(mDrawDistance - DIST_FUDGE, 
 801								LLWorld::getInstance()->getRegionWidthInMeters() - DIST_FUDGE,
 802								MAX_CAMERA_DISTANCE_FROM_AGENT);
 803
 804		if (mFocusObject.notNull())
 805		{
 806			if (mFocusObject.notNull())
 807			{
 808				if (mFocusObject->isAvatar())
 809				{
 810					min_zoom = AVATAR_MIN_ZOOM;
 811				}
 812				else
 813				{
 814					min_zoom = OBJECT_MIN_ZOOM;
 815				}
 816			}
 817		}
 818
 819		LLVector3d camera_offset_dir = mCameraFocusOffsetTarget;
 820		camera_offset_dir.normalize();
 821		mCameraFocusOffsetTarget = camera_offset_dir * rescale(fraction, 0.f, 1.f, max_zoom, min_zoom);
 822	}
 823	startCameraAnimation();
 824}
 825
 826
 827//-----------------------------------------------------------------------------
 828// cameraOrbitAround()
 829//-----------------------------------------------------------------------------
 830void LLAgentCamera::cameraOrbitAround(const F32 radians)
 831{
 832	LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection();
 833	if (selection->getObjectCount() && selection->getSelectType() == SELECT_TYPE_HUD)
 834	{
 835		// do nothing for hud selection
 836	}
 837	else if (mFocusOnAvatar && (mCameraMode == CAMERA_MODE_THIRD_PERSON || mCameraMode == CAMERA_MODE_FOLLOW))
 838	{
 839		gAgent.yaw(radians);
 840	}
 841	else
 842	{
 843		mCameraFocusOffsetTarget.rotVec(radians, 0.f, 0.f, 1.f);
 844		
 845		cameraZoomIn(1.f);
 846	}
 847}
 848
 849
 850//-----------------------------------------------------------------------------
 851// cameraOrbitOver()
 852//-----------------------------------------------------------------------------
 853void LLAgentCamera::cameraOrbitOver(const F32 angle)
 854{
 855	LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection();
 856	if (selection->getObjectCount() && selection->getSelectType() == SELECT_TYPE_HUD)
 857	{
 858		// do nothing for hud selection
 859	}
 860	else if (mFocusOnAvatar && mCameraMode == CAMERA_MODE_THIRD_PERSON)
 861	{
 862		gAgent.pitch(angle);
 863	}
 864	else
 865	{
 866		LLVector3 camera_offset_unit(mCameraFocusOffsetTarget);
 867		camera_offset_unit.normalize();
 868
 869		F32 angle_from_up = acos( camera_offset_unit * gAgent.getReferenceUpVector() );
 870
 871		LLVector3d left_axis;
 872		left_axis.setVec(LLViewerCamera::getInstance()->getLeftAxis());
 873		F32 new_angle = llclamp(angle_from_up - angle, 1.f * DEG_TO_RAD, 179.f * DEG_TO_RAD);
 874		mCameraFocusOffsetTarget.rotVec(angle_from_up - new_angle, left_axis);
 875
 876		cameraZoomIn(1.f);
 877	}
 878}
 879
 880//-----------------------------------------------------------------------------
 881// cameraZoomIn()
 882//-----------------------------------------------------------------------------
 883void LLAgentCamera::cameraZoomIn(const F32 fraction)
 884{
 885	if (gDisconnected)
 886	{
 887		return;
 888	}
 889
 890	LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection();
 891	if (selection->getObjectCount() && selection->getSelectType() == SELECT_TYPE_HUD)
 892	{
 893		// just update hud zoom level
 894		mHUDTargetZoom /= fraction;
 895		return;
 896	}
 897
 898
 899	LLVector3d	camera_offset(mCameraFocusOffsetTarget);
 900	LLVector3d	camera_offset_unit(mCameraFocusOffsetTarget);
 901	F32 min_zoom = LAND_MIN_ZOOM;
 902	F32 current_distance = (F32)camera_offset_unit.normalize();
 903	F32 new_distance = current_distance * fraction;
 904
 905	// Don't move through focus point
 906	if (mFocusObject)
 907	{
 908		LLVector3 camera_offset_dir((F32)camera_offset_unit.mdV[VX], (F32)camera_offset_unit.mdV[VY], (F32)camera_offset_unit.mdV[VZ]);
 909
 910		if (mFocusObject->isAvatar())
 911		{
 912			calcCameraMinDistance(min_zoom);
 913		}
 914		else
 915		{
 916			min_zoom = OBJECT_MIN_ZOOM;
 917		}
 918	}
 919
 920	new_distance = llmax(new_distance, min_zoom); 
 921
 922	// Don't zoom too far back
 923	const F32 DIST_FUDGE = 16.f; // meters
 924	F32 max_distance = llmin(mDrawDistance - DIST_FUDGE, 
 925							 LLWorld::getInstance()->getRegionWidthInMeters() - DIST_FUDGE );
 926
 927	if (new_distance > max_distance)
 928	{
 929		new_distance = max_distance;
 930
 931		/*
 932		// Unless camera is unlocked
 933		if (!LLViewerCamera::sDisableCameraConstraints)
 934		{
 935			return;
 936		}
 937		*/
 938	}
 939
 940	if(cameraCustomizeAvatar())
 941	{
 942		new_distance = llclamp( new_distance, APPEARANCE_MIN_ZOOM, APPEARANCE_MAX_ZOOM );
 943	}
 944
 945	mCameraFocusOffsetTarget = new_distance * camera_offset_unit;
 946}
 947
 948//-----------------------------------------------------------------------------
 949// cameraOrbitIn()
 950//-----------------------------------------------------------------------------
 951void LLAgentCamera::cameraOrbitIn(const F32 meters)
 952{
 953	if (mFocusOnAvatar && mCameraMode == CAMERA_MODE_THIRD_PERSON)
 954	{
 955		F32 camera_offset_dist = llmax(0.001f, getCameraOffsetInitial().magVec() * gSavedSettings.getF32("CameraOffsetScale"));
 956		
 957		mCameraZoomFraction = (mTargetCameraDistance - meters) / camera_offset_dist;
 958
 959		if (!gSavedSettings.getBOOL("FreezeTime") && mCameraZoomFraction < MIN_ZOOM_FRACTION && meters > 0.f)
 960		{
 961			// No need to animate, camera is already there.
 962			changeCameraToMouselook(FALSE);
 963		}
 964
 965		mCameraZoomFraction = llclamp(mCameraZoomFraction, MIN_ZOOM_FRACTION, MAX_ZOOM_FRACTION);
 966	}
 967	else
 968	{
 969		LLVector3d	camera_offset(mCameraFocusOffsetTarget);
 970		LLVector3d	camera_offset_unit(mCameraFocusOffsetTarget);
 971		F32 current_distance = (F32)camera_offset_unit.normalize();
 972		F32 new_distance = current_distance - meters;
 973		F32 min_zoom = LAND_MIN_ZOOM;
 974		
 975		// Don't move through focus point
 976		if (mFocusObject.notNull())
 977		{
 978			if (mFocusObject->isAvatar())
 979			{
 980				min_zoom = AVATAR_MIN_ZOOM;
 981			}
 982			else
 983			{
 984				min_zoom = OBJECT_MIN_ZOOM;
 985			}
 986		}
 987
 988		new_distance = llmax(new_distance, min_zoom);
 989
 990		// Don't zoom too far back
 991		const F32 DIST_FUDGE = 16.f; // meters
 992		F32 max_distance = llmin(mDrawDistance - DIST_FUDGE, 
 993								 LLWorld::getInstance()->getRegionWidthInMeters() - DIST_FUDGE );
 994
 995		if (new_distance > max_distance)
 996		{
 997			// Unless camera is unlocked
 998			if (!gSavedSettings.getBOOL("DisableCameraConstraints"))
 999			{
1000				return;
1001			}
1002		}
1003
1004		if( CAMERA_MODE_CUSTOMIZE_AVATAR == getCameraMode() )
1005		{
1006			new_distance = llclamp( new_distance, APPEARANCE_MIN_ZOOM, APPEARANCE_MAX_ZOOM );
1007		}
1008
1009		// Compute new camera offset
1010		mCameraFocusOffsetTarget = new_distance * camera_offset_unit;
1011		cameraZoomIn(1.f);
1012	}
1013}
1014
1015
1016//-----------------------------------------------------------------------------
1017// cameraPanIn()
1018//-----------------------------------------------------------------------------
1019void LLAgentCamera::cameraPanIn(F32 meters)
1020{
1021	LLVector3d at_axis;
1022	at_axis.setVec(LLViewerCamera::getInstance()->getAtAxis());
1023
1024	mFocusTargetGlobal += meters * at_axis;
1025	mFocusGlobal = mFocusTargetGlobal;
1026	// don't enforce zoom constraints as this is the only way for users to get past them easily
1027	updateFocusOffset();
1028	// NOTE: panning movements expect the camera to move exactly with the focus target, not animated behind -Nyx
1029	mCameraSmoothingLastPositionGlobal = calcCameraPositionTargetGlobal();
1030}
1031
1032//-----------------------------------------------------------------------------
1033// cameraPanLeft()
1034//-----------------------------------------------------------------------------
1035void LLAgentCamera::cameraPanLeft(F32 meters)
1036{
1037	LLVector3d left_axis;
1038	left_axis.setVec(LLViewerCamera::getInstance()->getLeftAxis());
1039
1040	mFocusTargetGlobal += meters * left_axis;
1041	mFocusGlobal = mFocusTargetGlobal;
1042
1043	// disable smoothing for camera pan, which causes some residents unhappiness
1044	mCameraSmoothingStop = true;
1045	
1046	cameraZoomIn(1.f);
1047	updateFocusOffset();
1048	// NOTE: panning movements expect the camera to move exactly with the focus target, not animated behind - Nyx
1049	mCameraSmoothingLastPositionGlobal = calcCameraPositionTargetGlobal();
1050}
1051
1052//-----------------------------------------------------------------------------
1053// cameraPanUp()
1054//-----------------------------------------------------------------------------
1055void LLAgentCamera::cameraPanUp(F32 meters)
1056{
1057	LLVector3d up_axis;
1058	up_axis.setVec(LLViewerCamera::getInstance()->getUpAxis());
1059
1060	mFocusTargetGlobal += meters * up_axis;
1061	mFocusGlobal = mFocusTargetGlobal;
1062
1063	// disable smoothing for camera pan, which causes some residents unhappiness
1064	mCameraSmoothingStop = true;
1065
1066	cameraZoomIn(1.f);
1067	updateFocusOffset();
1068	// NOTE: panning movements expect the camera to move exactly with the focus target, not animated behind -Nyx
1069	mCameraSmoothingLastPositionGlobal = calcCameraPositionTargetGlobal();
1070}
1071
1072//-----------------------------------------------------------------------------
1073// updateLookAt()
1074//-----------------------------------------------------------------------------
1075void LLAgentCamera::updateLookAt(const S32 mouse_x, const S32 mouse_y)
1076{
1077	static LLVector3 last_at_axis;
1078
1079	if (!isAgentAvatarValid()) return;
1080
1081	LLQuaternion av_inv_rot = ~gAgentAvatarp->mRoot.getWorldRotation();
1082	LLVector3 root_at = LLVector3::x_axis * gAgentAvatarp->mRoot.getWorldRotation();
1083
1084	if 	((gViewerWindow->getMouseVelocityStat()->getCurrent() < 0.01f) &&
1085		 (root_at * last_at_axis > 0.95f))
1086	{
1087		LLVector3 vel = gAgentAvatarp->getVelocity();
1088		if (vel.magVecSquared() > 4.f)
1089		{
1090			setLookAt(LOOKAT_TARGET_IDLE, gAgentAvatarp, vel * av_inv_rot);
1091		}
1092		else
1093		{
1094			// *FIX: rotate mframeagent by sit object's rotation?
1095			LLQuaternion look_rotation = gAgentAvatarp->isSitting() ? gAgentAvatarp->getRenderRotation() : gAgent.getFrameAgent().getQuaternion(); // use camera's current rotation
1096			LLVector3 look_offset = LLVector3(2.f, 0.f, 0.f) * look_rotation * av_inv_rot;
1097			setLookAt(LOOKAT_TARGET_IDLE, gAgentAvatarp, look_offset);
1098		}
1099		last_at_axis = root_at;
1100		return;
1101	}
1102
1103	last_at_axis = root_at;
1104	
1105	if (CAMERA_MODE_CUSTOMIZE_AVATAR == getCameraMode())
1106	{
1107		setLookAt(LOOKAT_TARGET_NONE, gAgentAvatarp, LLVector3(-2.f, 0.f, 0.f));	
1108	}
1109	else
1110	{
1111		// Move head based on cursor position
1112		ELookAtType lookAtType = LOOKAT_TARGET_NONE;
1113		LLVector3 headLookAxis;
1114		LLCoordFrame frameCamera = *((LLCoordFrame*)LLViewerCamera::getInstance());
1115
1116		if (cameraMouselook())
1117		{
1118			lookAtType = LOOKAT_TARGET_MOUSELOOK;
1119		}
1120		else if (cameraThirdPerson())
1121		{
1122			// range from -.5 to .5
1123			F32 x_from_center = 
1124				((F32) mouse_x / (F32) gViewerWindow->getWorldViewWidthScaled() ) - 0.5f;
1125			F32 y_from_center = 
1126				((F32) mouse_y / (F32) gViewerWindow->getWorldViewHeightScaled() ) - 0.5f;
1127
1128			frameCamera.yaw( - x_from_center * gSavedSettings.getF32("YawFromMousePosition") * DEG_TO_RAD);
1129			frameCamera.pitch( - y_from_center * gSavedSettings.getF32("PitchFromMousePosition") * DEG_TO_RAD);
1130			lookAtType = LOOKAT_TARGET_FREELOOK;
1131		}
1132
1133		headLookAxis = frameCamera.getAtAxis();
1134		// RN: we use world-space offset for mouselook and freelook
1135		//headLookAxis = headLookAxis * av_inv_rot;
1136		setLookAt(lookAtType, gAgentAvatarp, headLookAxis);
1137	}
1138}
1139
1140//-----------------------------------------------------------------------------
1141// updateCamera()
1142//-----------------------------------------------------------------------------
1143void LLAgentCamera::updateCamera()
1144{
1145	static LLFastTimer::DeclareTimer ftm("Camera");
1146	LLFastTimer t(ftm);
1147
1148	// - changed camera_skyward to the new global "mCameraUpVector"
1149	mCameraUpVector = LLVector3::z_axis;
1150	//LLVector3	camera_skyward(0.f, 0.f, 1.f);
1151
1152	U32 camera_mode = mCameraAnimating ? mLastCameraMode : mCameraMode;
1153
1154	validateFocusObject();
1155
1156	if (isAgentAvatarValid() && 
1157		gAgentAvatarp->isSitting() &&
1158		camera_mode == CAMERA_MODE_MOUSELOOK)
1159	{
1160		//changed camera_skyward to the new global "mCameraUpVector"
1161		mCameraUpVector = mCameraUpVector * gAgentAvatarp->getRenderRotation();
1162	}
1163
1164	if (cameraThirdPerson() && mFocusOnAvatar && LLFollowCamMgr::getActiveFollowCamParams())
1165	{
1166		changeCameraToFollow();
1167	}
1168
1169	//NOTE - this needs to be integrated into a general upVector system here within llAgent. 
1170	if ( camera_mode == CAMERA_MODE_FOLLOW && mFocusOnAvatar )
1171	{
1172		mCameraUpVector = mFollowCam.getUpVector();
1173	}
1174
1175	if (mSitCameraEnabled)
1176	{
1177		if (mSitCameraReferenceObject->isDead())
1178		{
1179			setSitCamera(LLUUID::null);
1180		}
1181	}
1182
1183	// Update UI with our camera inputs
1184	LLFloaterCamera* camera_floater = LLFloaterReg::findTypedInstance<LLFloaterCamera>("camera");
1185	if (camera_floater)
1186	{
1187		camera_floater->mRotate->setToggleState(gAgentCamera.getOrbitRightKey() > 0.f,	// left
1188												gAgentCamera.getOrbitUpKey() > 0.f,		// top
1189												gAgentCamera.getOrbitLeftKey() > 0.f,	// right
1190												gAgentCamera.getOrbitDownKey() > 0.f);	// bottom
1191		
1192		camera_floater->mTrack->setToggleState(gAgentCamera.getPanLeftKey() > 0.f,		// left
1193											   gAgentCamera.getPanUpKey() > 0.f,			// top
1194											   gAgentCamera.getPanRightKey() > 0.f,		// right
1195											   gAgentCamera.getPanDownKey() > 0.f);		// bottom
1196	}
1197
1198	// Handle camera movement based on keyboard.
1199	const F32 ORBIT_OVER_RATE = 90.f * DEG_TO_RAD;			// radians per second
1200	const F32 ORBIT_AROUND_RATE = 90.f * DEG_TO_RAD;		// radians per second
1201	const F32 PAN_RATE = 5.f;								// meters per second
1202
1203	if (gAgentCamera.getOrbitUpKey() || gAgentCamera.getOrbitDownKey())
1204	{
1205		F32 input_rate = gAgentCamera.getOrbitUpKey() - gAgentCamera.getOrbitDownKey();
1206		cameraOrbitOver( input_rate * ORBIT_OVER_RATE / gFPSClamped );
1207	}
1208
1209	if (gAgentCamera.getOrbitLeftKey() || gAgentCamera.getOrbitRightKey())
1210	{
1211		F32 input_rate = gAgentCamera.getOrbitLeftKey() - gAgentCamera.getOrbitRightKey();
1212		cameraOrbitAround(input_rate * ORBIT_AROUND_RATE / gFPSClamped);
1213	}
1214
1215	if (gAgentCamera.getOrbitInKey() || gAgentCamera.getOrbitOutKey())
1216	{
1217		F32 input_rate = gAgentCamera.getOrbitInKey() - gAgentCamera.getOrbitOutKey();
1218		
1219		LLVector3d to_focus = gAgent.getPosGlobalFromAgent(LLViewerCamera::getInstance()->getOrigin()) - calcFocusPositionTargetGlobal();
1220		F32 distance_to_focus = (F32)to_focus.magVec();
1221		// Move at distance (in meters) meters per second
1222		cameraOrbitIn( input_rate * distance_to_focus / gFPSClamped );
1223	}
1224
1225	if (gAgentCamera.getPanInKey() || gAgentCamera.getPanOutKey())
1226	{
1227		F32 input_rate = gAgentCamera.getPanInKey() - gAgentCamera.getPanOutKey();
1228		cameraPanIn(input_rate * PAN_RATE / gFPSClamped);
1229	}
1230
1231	if (gAgentCamera.getPanRightKey() || gAgentCamera.getPanLeftKey())
1232	{
1233		F32 input_rate = gAgentCamera.getPanRightKey() - gAgentCamera.getPanLeftKey();
1234		cameraPanLeft(input_rate * -PAN_RATE / gFPSClamped );
1235	}
1236
1237	if (gAgentCamera.getPanUpKey() || gAgentCamera.getPanDownKey())
1238	{
1239		F32 input_rate = gAgentCamera.getPanUpKey() - gAgentCamera.getPanDownKey();
1240		cameraPanUp(input_rate * PAN_RATE / gFPSClamped );
1241	}
1242
1243	// Clear camera keyboard keys.
1244	gAgentCamera.clearOrbitKeys();
1245	gAgentCamera.clearPanKeys();
1246
1247	// lerp camera focus offset
1248	mCameraFocusOffset = lerp(mCameraFocusOffset, mCameraFocusOffsetTarget, LLCriticalDamp::getInterpolant(CAMERA_FOCUS_HALF_LIFE));
1249
1250	if ( mCameraMode == CAMERA_MODE_FOLLOW )
1251	{
1252		if (isAgentAvatarValid())
1253		{
1254			//--------------------------------------------------------------------------------
1255			// this is where the avatar's position and rotation are given to followCam, and 
1256			// where it is updated. All three of its attributes are updated: (1) position, 
1257			// (2) focus, and (3) upvector. They can then be queried elsewhere in llAgent.
1258			//--------------------------------------------------------------------------------
1259			// *TODO: use combined rotation of frameagent and sit object
1260			LLQuaternion avatarRotationForFollowCam = gAgentAvatarp->isSitting() ? gAgentAvatarp->getRenderRotation() : gAgent.getFrameAgent().getQuaternion();
1261
1262			LLFollowCamParams* current_cam = LLFollowCamMgr::getActiveFollowCamParams();
1263			if (current_cam)
1264			{
1265				mFollowCam.copyParams(*current_cam);
1266				mFollowCam.setSubjectPositionAndRotation( gAgentAvatarp->getRenderPosition(), avatarRotationForFollowCam );
1267				mFollowCam.update();
1268				LLViewerJoystick::getInstance()->setCameraNeedsUpdate(true);
1269			}
1270			else
1271			{
1272				changeCameraToThirdPerson(TRUE);
1273			}
1274		}
1275	}
1276
1277	BOOL hit_limit;
1278	LLVector3d camera_pos_global;
1279	LLVector3d camera_target_global = calcCameraPositionTargetGlobal(&hit_limit);
1280	mCameraVirtualPositionAgent = gAgent.getPosAgentFromGlobal(camera_target_global);
1281	LLVector3d focus_target_global = calcFocusPositionTargetGlobal();
1282
1283	// perform field of view correction
1284	mCameraFOVZoomFactor = calcCameraFOVZoomFactor();
1285	camera_target_global = focus_target_global + (camera_target_global - focus_target_global) * (1.f + mCameraFOVZoomFactor);
1286
1287	gAgent.setShowAvatar(TRUE); // can see avatar by default
1288
1289	// Adjust position for animation
1290	if (mCameraAnimating)
1291	{
1292		F32 time = mAnimationTimer.getElapsedTimeF32();
1293
1294		// yet another instance of critically damped motion, hooray!
1295		// F32 fraction_of_animation = 1.f - pow(2.f, -time / CAMERA_ZOOM_HALF_LIFE);
1296
1297		// linear interpolation
1298		F32 fraction_of_animation = time / mAnimationDuration;
1299
1300		BOOL isfirstPerson = mCameraMode == CAMERA_MODE_MOUSELOOK;
1301		BOOL wasfirstPerson = mLastCameraMode == CAMERA_MODE_MOUSELOOK;
1302		F32 fraction_animation_to_skip;
1303
1304		if (mAnimationCameraStartGlobal == camera_target_global)
1305		{
1306			fraction_animation_to_skip = 0.f;
1307		}
1308		else
1309		{
1310			LLVector3d cam_delta = mAnimationCameraStartGlobal - camera_target_global;
1311			fraction_animation_to_skip = HEAD_BUFFER_SIZE / (F32)cam_delta.magVec();
1312		}
1313		F32 animation_start_fraction = (wasfirstPerson) ? fraction_animation_to_skip : 0.f;
1314		F32 animation_finish_fraction =  (isfirstPerson) ? (1.f - fraction_animation_to_skip) : 1.f;
1315	
1316		if (fraction_of_animation < animation_finish_fraction)
1317		{
1318			if (fraction_of_animation < animation_start_fraction || fraction_of_animation > animation_finish_fraction )
1319			{
1320				gAgent.setShowAvatar(FALSE);
1321			}
1322
1323			// ...adjust position for animation
1324			F32 smooth_fraction_of_animation = llsmoothstep(0.0f, 1.0f, fraction_of_animation);
1325			camera_pos_global = lerp(mAnimationCameraStartGlobal, camera_target_global, smooth_fraction_of_animation);
1326			mFocusGlobal = lerp(mAnimationFocusStartGlobal, focus_target_global, smooth_fraction_of_animation);
1327		}
1328		else
1329		{
1330			// ...animation complete
1331			mCameraAnimating = FALSE;
1332
1333			camera_pos_global = camera_target_global;
1334			mFocusGlobal = focus_target_global;
1335
1336			gAgent.endAnimationUpdateUI();
1337			gAgent.setShowAvatar(TRUE);
1338		}
1339
1340		if (isAgentAvatarValid() && (mCameraMode != CAMERA_MODE_MOUSELOOK))
1341		{
1342			gAgentAvatarp->updateAttachmentVisibility(mCameraMode);
1343		}
1344	}
1345	else 
1346	{
1347		camera_pos_global = camera_target_global;
1348		mFocusGlobal = focus_target_global;
1349		gAgent.setShowAvatar(TRUE);
1350	}
1351
1352	// smoothing
1353	if (TRUE)
1354	{
1355		LLVector3d agent_pos = gAgent.getPositionGlobal();
1356		LLVector3d camera_pos_agent = camera_pos_global - agent_pos;
1357		// Sitting on what you're manipulating can cause camera jitter with smoothing. 
1358		// This turns off smoothing while editing. -MG
1359		bool in_build_mode = LLToolMgr::getInstance()->inBuildMode();
1360		mCameraSmoothingStop = mCameraSmoothingStop || in_build_mode;
1361		
1362		if (cameraThirdPerson() && !mCameraSmoothingStop)
1363		{
1364			const F32 SMOOTHING_HALF_LIFE = 0.02f;
1365			
1366			F32 smoothing = LLCriticalDamp::getInterpolant(gSavedSettings.getF32("CameraPositionSmoothing") * SMOOTHING_HALF_LIFE, FALSE);
1367					
1368			if (!mFocusObject)  // we differentiate on avatar mode 
1369			{
1370				// for avatar-relative focus, we smooth in avatar space -
1371				// the avatar moves too jerkily w/r/t global space to smooth there.
1372
1373				LLVector3d delta = camera_pos_agent - mCameraSmoothingLastPositionAgent;
1374				if (delta.magVec() < MAX_CAMERA_SMOOTH_DISTANCE)  // only smooth over short distances please
1375				{
1376					camera_pos_agent = lerp(mCameraSmoothingLastPositionAgent, camera_pos_agent, smoothing);
1377					camera_pos_global = camera_pos_agent + agent_pos;
1378				}
1379			}
1380			else
1381			{
1382				LLVector3d delta = camera_pos_global - mCameraSmoothingLastPositionGlobal;
1383				if (delta.magVec() < MAX_CAMERA_SMOOTH_DISTANCE) // only smooth over short distances please
1384				{
1385					camera_pos_global = lerp(mCameraSmoothingLastPositionGlobal, camera_pos_global, smoothing);
1386				}
1387			}
1388		}
1389								 
1390		mCameraSmoothingLastPositionGlobal = camera_pos_global;
1391		mCameraSmoothingLastPositionAgent = camera_pos_agent;
1392		mCameraSmoothingStop = false;
1393	}
1394
1395	
1396	mCameraCurrentFOVZoomFactor = lerp(mCameraCurrentFOVZoomFactor, mCameraFOVZoomFactor, LLCriticalDamp::getInterpolant(FOV_ZOOM_HALF_LIFE));
1397
1398//	llinfos << "Current FOV Zoom: " << mCameraCurrentFOVZoomFactor << " Target FOV Zoom: " << mCameraFOVZoomFactor << " Object penetration: " << mFocusObjectDist << llendl;
1399
1400	LLVector3 focus_agent = gAgent.getPosAgentFromGlobal(mFocusGlobal);
1401	
1402	mCameraPositionAgent = gAgent.getPosAgentFromGlobal(camera_pos_global);
1403
1404	// Move the camera
1405
1406	LLViewerCamera::getInstance()->updateCameraLocation(mCameraPositionAgent, mCameraUpVector, focus_agent);
1407	//LLViewerCamera::getInstance()->updateCameraLocation(mCameraPositionAgent, camera_skyward, focus_agent);
1408	
1409	// Change FOV
1410	LLViewerCamera::getInstance()->setView(LLViewerCamera::getInstance()->getDefaultFOV() / (1.f + mCameraCurrentFOVZoomFactor));
1411
1412	// follow camera when in customize mode
1413	if (cameraCustomizeAvatar())	
1414	{
1415		setLookAt(LOOKAT_TARGET_FOCUS, NULL, mCameraPositionAgent);
1416	}
1417
1418	// update the travel distance stat
1419	// this isn't directly related to the camera
1420	// but this seemed like the best place to do this
1421	LLVector3d global_pos = gAgent.getPositionGlobal(); 
1422	if (!gAgent.getLastPositionGlobal().isExactlyZero())
1423	{
1424		LLVector3d delta = global_pos - gAgent.getLastPositionGlobal();
1425		gAgent.setDistanceTraveled(gAgent.getDistanceTraveled() + delta.magVec());
1426	}
1427	gAgent.setLastPositionGlobal(global_pos);
1428	
1429	if (LLVOAvatar::sVisibleInFirstPerson && isAgentAvatarValid() && !gAgentAvatarp->isSitting() && cameraMouselook())
1430	{
1431		LLVector3 head_pos = gAgentAvatarp->mHeadp->getWorldPosition() + 
1432			LLVector3(0.08f, 0.f, 0.05f) * gAgentAvatarp->mHeadp->getWorldRotation() + 
1433			LLVector3(0.1f, 0.f, 0.f) * gAgentAvatarp->mPelvisp->getWorldRotation();
1434		LLVector3 diff = mCameraPositionAgent - head_pos;
1435		diff = diff * ~gAgentAvatarp->mRoot.getWorldRotation();
1436
1437		LLJoint* torso_joint = gAgentAvatarp->mTorsop;
1438		LLJoint* chest_joint = gAgentAvatarp->mChestp;
1439		LLVector3 torso_scale = torso_joint->getScale();
1440		LLVector3 chest_scale = chest_joint->getScale();
1441
1442		// shorten avatar skeleton to avoid foot interpenetration
1443		if (!gAgentAvatarp->mInAir)
1444		{
1445			LLVector3 chest_offset = LLVector3(0.f, 0.f, chest_joint->getPosition().mV[VZ]) * torso_joint->getWorldRotation();
1446			F32 z_compensate = llclamp(-diff.mV[VZ], -0.2f, 1.f);
1447			F32 scale_factor = llclamp(1.f - ((z_compensate * 0.5f) / chest_offset.mV[VZ]), 0.5f, 1.2f);
1448			torso_joint->setScale(LLVector3(1.f, 1.f, scale_factor));
1449
1450			LLJoint* neck_joint = gAgentAvatarp->mNeckp;
1451			LLVector3 neck_offset = LLVector3(0.f, 0.f, neck_joint->getPosition().mV[VZ]) * chest_joint->getWorldRotation();
1452			scale_factor = llclamp(1.f - ((z_compensate * 0.5f) / neck_offset.mV[VZ]), 0.5f, 1.2f);
1453			chest_joint->setScale(LLVector3(1.f, 1.f, scale_factor));
1454			diff.mV[VZ] = 0.f;
1455		}
1456
1457		gAgentAvatarp->mPelvisp->setPosition(gAgentAvatarp->mPelvisp->getPosition() + diff);
1458
1459		gAgentAvatarp->mRoot.updateWorldMatrixChildren();
1460
1461		for (LLVOAvatar::attachment_map_t::iterator iter = gAgentAvatarp->mAttachmentPoints.begin(); 
1462			 iter != gAgentAvatarp->mAttachmentPoints.end(); )
1463		{
1464			LLVOAvatar::attachment_map_t::iterator curiter = iter++;
1465			LLViewerJointAttachment* attachment = curiter->second;
1466			for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
1467				 attachment_iter != attachment->mAttachedObjects.end();
1468				 ++attachment_iter)
1469			{
1470				LLViewerObject *attached_object = (*attachment_iter);
1471				if (attached_object && !attached_object->isDead() && attached_object->mDrawable.notNull())
1472				{
1473					// clear any existing "early" movements of attachment
1474					attached_object->mDrawable->clearState(LLDrawable::EARLY_MOVE);
1475					gPipeline.updateMoveNormalAsync(attached_object->mDrawable);
1476					attached_object->updateText();
1477				}
1478			}
1479		}
1480
1481		torso_joint->setScale(torso_scale);
1482		chest_joint->setScale(chest_scale);
1483	}
1484}
1485
1486void LLAgentCamera::updateLastCamera()
1487{
1488	mLastCameraMode = mCameraMode;
1489}
1490
1491void LLAgentCamera::updateFocusOffset()
1492{
1493	validateFocusObject();
1494	if (mFocusObject.notNull())
1495	{
1496		LLVector3d obj_pos = gAgent.getPosGlobalFromAgent(mFocusObject->getRenderPosition());
1497		mFocusObjectOffset.setVec(mFocusTargetGlobal - obj_pos);
1498	}
1499}
1500
1501void LLAgentCamera::validateFocusObject()
1502{
1503	if (mFocusObject.notNull() && 
1504		mFocusObject->isDead())
1505	{
1506		mFocusObjectOffset.clearVec();
1507		clearFocusObject();
1508		mCamer

Large files files are truncated, but you can click here to view the full file