diff options
Diffstat (limited to 'indra/newview/llfollowcam.cpp')
| -rw-r--r-- | indra/newview/llfollowcam.cpp | 1756 | 
1 files changed, 878 insertions, 878 deletions
diff --git a/indra/newview/llfollowcam.cpp b/indra/newview/llfollowcam.cpp index 96cd8a05ff..8ce6dc6ef4 100644 --- a/indra/newview/llfollowcam.cpp +++ b/indra/newview/llfollowcam.cpp @@ -1,878 +1,878 @@ -/**  - * @file llfollowcam.cpp - * @author Jeffrey Ventrella - * @brief LLFollowCam class implementation - * - * $LicenseInfo:firstyear=2005&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - *  - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - *  - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - *  - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - *  - * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" -#include "llfollowcam.h" -#include "llagent.h" - -//------------------------------------------------------- -// constants -//------------------------------------------------------- -const F32 FOLLOW_CAM_ZOOM_FACTOR			= 0.1f; -const F32 FOLLOW_CAM_MIN_ZOOM_AMOUNT		= 0.1f; -const F32 DISTANCE_EPSILON					= 0.0001f; -const F32 DEFAULT_MAX_DISTANCE_FROM_SUBJECT	= 1000.0;	// this will be correctly set on me by my caller - -//---------------------------------------------------------------------------------------- -// This is how slowly the camera position moves to its ideal position  -//---------------------------------------------------------------------------------------- -const F32 FOLLOW_CAM_MIN_POSITION_LAG		= 0.0f;		 -const F32 FOLLOW_CAM_DEFAULT_POSITION_LAG	= 0.1f;   -const F32 FOLLOW_CAM_MAX_POSITION_LAG		= 3.0f; - -//---------------------------------------------------------------------------------------- -// This is how slowly the camera focus moves to its subject -//---------------------------------------------------------------------------------------- -const F32 FOLLOW_CAM_MIN_FOCUS_LAG		= 0.0f; -const F32 FOLLOW_CAM_DEFAULT_FOCUS_LAG	= 0.1f; -const F32 FOLLOW_CAM_MAX_FOCUS_LAG		= 3.0f; - -//---------------------------------------------------------------------------------------- -// This is far the position can get from its IDEAL POSITION before it starts getting pulled -//---------------------------------------------------------------------------------------- -const F32 FOLLOW_CAM_MIN_POSITION_THRESHOLD		= 0.0f; -const F32 FOLLOW_CAM_DEFAULT_POSITION_THRESHOLD	= 1.0f; -const F32 FOLLOW_CAM_MAX_POSITION_THRESHOLD		= 4.0f; - -//---------------------------------------------------------------------------------------- -// This is far the focus can get from the subject before it starts getting pulled -//---------------------------------------------------------------------------------------- -const F32 FOLLOW_CAM_MIN_FOCUS_THRESHOLD		= 0.0f; -const F32 FOLLOW_CAM_DEFAULT_FOCUS_THRESHOLD	= 1.0f; -const F32 FOLLOW_CAM_MAX_FOCUS_THRESHOLD		= 4.0f; - -//---------------------------------------------------------------------------------------- -// This is the distance the camera wants to be from the subject -//---------------------------------------------------------------------------------------- -const F32 FOLLOW_CAM_MIN_DISTANCE		= 0.5f; -const F32 FOLLOW_CAM_DEFAULT_DISTANCE	= 3.0f; -//const F32 FOLLOW_CAM_MAX_DISTANCE		= 10.0f; // from now on I am using mMaxCameraDistantFromSubject - -//---------------------------------------------------------------------------------------- -// this is an angluar value -// It affects the angle that the camera rises (pitches) in relation  -// to the horizontal plane -//---------------------------------------------------------------------------------------- -const F32 FOLLOW_CAM_MIN_PITCH		= -45.0f;  -const F32 FOLLOW_CAM_DEFAULT_PITCH	=   0.0f; -const F32 FOLLOW_CAM_MAX_PITCH		=  80.0f;	// keep under 90 degrees - avoid gimble lock! - - -//---------------------------------------------------------------------------------------- -// how high or low the camera considers its ideal focus to be (relative to its subject) -//---------------------------------------------------------------------------------------- -const F32 FOLLOW_CAM_MIN_FOCUS_OFFSET		= -10.0f; -const LLVector3 FOLLOW_CAM_DEFAULT_FOCUS_OFFSET	=  LLVector3(1.0f, 0.f, 0.f); -const F32 FOLLOW_CAM_MAX_FOCUS_OFFSET		=  10.0f; - -//---------------------------------------------------------------------------------------- -// This affects the rate at which the camera adjusts to stay behind the subject -//---------------------------------------------------------------------------------------- -const F32 FOLLOW_CAM_MIN_BEHINDNESS_LAG		= 0.0f; -const F32 FOLLOW_CAM_DEFAULT_BEHINDNESS_LAG		= 0.f; -const F32 FOLLOW_CAM_MAX_BEHINDNESS_LAG		= 3.0f; - -//--------------------------------------------------------------------------------------------------------------------- -// in  degrees: This is the size of the pie slice behind the subject matter within which the camera is free to move -//--------------------------------------------------------------------------------------------------------------------- -const F32 FOLLOW_CAM_MIN_BEHINDNESS_ANGLE		= 0.0f; -const F32 FOLLOW_CAM_DEFAULT_BEHINDNESS_ANGLE	= 10.0f; -const F32 FOLLOW_CAM_MAX_BEHINDNESS_ANGLE		= 180.0f; -const F32 FOLLOW_CAM_BEHINDNESS_EPSILON			= 1.0f; - -//------------------------------------ -// Constructor -//------------------------------------ -LLFollowCamParams::LLFollowCamParams() -{ -	mMaxCameraDistantFromSubject		= DEFAULT_MAX_DISTANCE_FROM_SUBJECT; -	mPositionLocked						= false; -	mFocusLocked						= false; -	mUsePosition						= false; -	mUseFocus							= false; - -	//------------------------------------------------------ -	// setting the attributes to their defaults -	//------------------------------------------------------ -	setPositionLag		( FOLLOW_CAM_DEFAULT_POSITION_LAG			); -	setFocusLag			( FOLLOW_CAM_DEFAULT_FOCUS_LAG				); -	setPositionThreshold( FOLLOW_CAM_DEFAULT_POSITION_THRESHOLD		); -	setFocusThreshold	( FOLLOW_CAM_DEFAULT_FOCUS_THRESHOLD		); -	setBehindnessLag	( FOLLOW_CAM_DEFAULT_BEHINDNESS_LAG		); -	setDistance			( FOLLOW_CAM_DEFAULT_DISTANCE				); -	setPitch			( FOLLOW_CAM_DEFAULT_PITCH					); -	setFocusOffset		( FOLLOW_CAM_DEFAULT_FOCUS_OFFSET	); -	setBehindnessAngle	( FOLLOW_CAM_DEFAULT_BEHINDNESS_ANGLE		); -	setPositionThreshold( FOLLOW_CAM_DEFAULT_POSITION_THRESHOLD		); -	setFocusThreshold	( FOLLOW_CAM_DEFAULT_FOCUS_THRESHOLD		); - -} - -LLFollowCamParams::~LLFollowCamParams() { } - -//--------------------------------------------------------- -// buncho set methods -//--------------------------------------------------------- - -//--------------------------------------------------------- -void LLFollowCamParams::setPositionLag( F32 p )  -{  -	mPositionLag = llclamp(p, FOLLOW_CAM_MIN_POSITION_LAG, FOLLOW_CAM_MAX_POSITION_LAG);  -} - - -//--------------------------------------------------------- -void LLFollowCamParams::setFocusLag( F32 f )  -{  -	mFocusLag = llclamp(f, FOLLOW_CAM_MIN_FOCUS_LAG, FOLLOW_CAM_MAX_FOCUS_LAG);  -} - - -//--------------------------------------------------------- -void LLFollowCamParams::setPositionThreshold( F32 p )  -{  -	mPositionThreshold = llclamp(p, FOLLOW_CAM_MIN_POSITION_THRESHOLD, FOLLOW_CAM_MAX_POSITION_THRESHOLD);  -} - - -//--------------------------------------------------------- -void LLFollowCamParams::setFocusThreshold( F32 f )  -{  -	mFocusThreshold = llclamp(f, FOLLOW_CAM_MIN_FOCUS_THRESHOLD, FOLLOW_CAM_MAX_FOCUS_THRESHOLD);  -} - - -//--------------------------------------------------------- -void LLFollowCamParams::setPitch( F32 p )  -{  -	mPitch = llclamp(p, FOLLOW_CAM_MIN_PITCH, FOLLOW_CAM_MAX_PITCH);  -} - - -//--------------------------------------------------------- -void LLFollowCamParams::setBehindnessLag( F32 b )  -{  -	mBehindnessLag = llclamp(b, FOLLOW_CAM_MIN_BEHINDNESS_LAG, FOLLOW_CAM_MAX_BEHINDNESS_LAG);  -} - -//--------------------------------------------------------- -void LLFollowCamParams::setBehindnessAngle( F32 b )  -{  -	mBehindnessMaxAngle = llclamp(b, FOLLOW_CAM_MIN_BEHINDNESS_ANGLE, FOLLOW_CAM_MAX_BEHINDNESS_ANGLE);  -} - -//--------------------------------------------------------- -void LLFollowCamParams::setDistance( F32 d )  -{  -	mDistance = llclamp(d, FOLLOW_CAM_MIN_DISTANCE, mMaxCameraDistantFromSubject);  -} - -//--------------------------------------------------------- -void LLFollowCamParams::setPositionLocked( bool l )  -{ -	mPositionLocked = l; -} - -//--------------------------------------------------------- -void LLFollowCamParams::setFocusLocked( bool l )  -{ -	mFocusLocked = l; - -} - -//--------------------------------------------------------- -void LLFollowCamParams::setFocusOffset( const LLVector3& v )  -{  -	mFocusOffset = v;  -	mFocusOffset.clamp(FOLLOW_CAM_MIN_FOCUS_OFFSET, FOLLOW_CAM_MAX_FOCUS_OFFSET); -} - -//--------------------------------------------------------- -void LLFollowCamParams::setPosition( const LLVector3& p )  -{  -	mUsePosition = true; -	mPosition = p; -} - -//--------------------------------------------------------- -void LLFollowCamParams::setFocus( const LLVector3& f )  -{  -	mUseFocus = true; -	mFocus = f; -} - -//--------------------------------------------------------- -// buncho get methods -//--------------------------------------------------------- -F32			LLFollowCamParams::getPositionLag		() const { return mPositionLag;			} -F32			LLFollowCamParams::getFocusLag			() const { return mFocusLag;			} -F32			LLFollowCamParams::getPositionThreshold	() const { return mPositionThreshold;	} -F32			LLFollowCamParams::getFocusThreshold	() const { return mFocusThreshold;		} -F32			LLFollowCamParams::getDistance			() const { return mDistance;			} -F32			LLFollowCamParams::getPitch				() const { return mPitch;				} -LLVector3	LLFollowCamParams::getFocusOffset		() const { return mFocusOffset;			} -F32			LLFollowCamParams::getBehindnessAngle	() const { return mBehindnessMaxAngle;	} -F32			LLFollowCamParams::getBehindnessLag		() const { return mBehindnessLag;		} -LLVector3	LLFollowCamParams::getPosition			() const { return mPosition;			} -LLVector3	LLFollowCamParams::getFocus				() const { return mFocus;				} -bool		LLFollowCamParams::getPositionLocked	() const { return mPositionLocked;		} -bool		LLFollowCamParams::getFocusLocked		() const { return mFocusLocked;			} - -//------------------------------------ -// Constructor -//------------------------------------ -LLFollowCam::LLFollowCam() : LLFollowCamParams() -{ -	mUpVector							= LLVector3::z_axis; -	mSubjectPosition					= LLVector3::zero; -	mSubjectRotation					= LLQuaternion::DEFAULT; - -	mZoomedToMinimumDistance			= false; -	mPitchCos = mPitchSin = 0.f; -	mPitchSineAndCosineNeedToBeUpdated	= true;  - -	mSimulatedDistance = mDistance; -} - -void LLFollowCam::copyParams(LLFollowCamParams& params) -{ -	setPositionLag(params.getPositionLag()); -	setFocusLag(params.getFocusLag()); -	setFocusThreshold( params.getFocusThreshold()); -	setPositionThreshold(params.getPositionThreshold()); -	setPitch(params.getPitch()); -	setFocusOffset(params.getFocusOffset()); -	setBehindnessAngle(params.getBehindnessAngle()); -	setBehindnessLag(params.getBehindnessLag()); - -	setPositionLocked(params.getPositionLocked()); -	setFocusLocked(params.getFocusLocked()); - -	setDistance(params.getDistance());	 -	if (params.getUsePosition()) -	{ -		setPosition(params.getPosition()); -	} -	if (params.getUseFocus()) -	{ -		setFocus(params.getFocus()); -	} -} - -//--------------------------------------------------------------------------------------------------------- -void LLFollowCam::update() -{ -	//#################################################################################### -	// update Focus -	//#################################################################################### -	LLVector3 offsetSubjectPosition = mSubjectPosition + (mFocusOffset * mSubjectRotation); - -	LLVector3 simulated_pos_agent = gAgent.getPosAgentFromGlobal(mSimulatedPositionGlobal); -	LLVector3 vectorFromCameraToSubject = offsetSubjectPosition - simulated_pos_agent; -	F32 distanceFromCameraToSubject = vectorFromCameraToSubject.magVec(); - -	LLVector3 whereFocusWantsToBe = mFocus; -	LLVector3 focus_pt_agent = gAgent.getPosAgentFromGlobal(mSimulatedFocusGlobal); -	if ( mFocusLocked ) // if focus is locked, only relative focus needs to be updated -	{ -		mRelativeFocus = (focus_pt_agent - mSubjectPosition) * ~mSubjectRotation; -	} -	else -	{ -		LLVector3 focusOffset = offsetSubjectPosition - focus_pt_agent; -		F32 focusOffsetDistance = focusOffset.magVec(); - -		LLVector3 focusOffsetDirection = focusOffset / focusOffsetDistance; -		whereFocusWantsToBe = focus_pt_agent +  -			(focusOffsetDirection * (focusOffsetDistance - mFocusThreshold)); -		if ( focusOffsetDistance > mFocusThreshold ) -		{ -			// this version normalizes focus threshold by distance  -			// so that the effect is not changed with distance -			/* -			F32 focusThresholdNormalizedByDistance = distanceFromCameraToSubject * mFocusThreshold; -			if ( focusOffsetDistance > focusThresholdNormalizedByDistance ) -			{ -				LLVector3 focusOffsetDirection = focusOffset / focusOffsetDistance; -				F32 force = focusOffsetDistance - focusThresholdNormalizedByDistance; -			*/ - -			F32 focusLagLerp = LLSmoothInterpolation::getInterpolant( mFocusLag ); -			focus_pt_agent = lerp( focus_pt_agent, whereFocusWantsToBe, focusLagLerp ); -			mSimulatedFocusGlobal = gAgent.getPosGlobalFromAgent(focus_pt_agent); -		} -		mRelativeFocus = lerp(mRelativeFocus, (focus_pt_agent - mSubjectPosition) * ~mSubjectRotation, LLSmoothInterpolation::getInterpolant(0.05f)); -	}// if focus is not locked --------------------------------------------- - - -	LLVector3 whereCameraPositionWantsToBe = gAgent.getPosAgentFromGlobal(mSimulatedPositionGlobal); -	if (  mPositionLocked ) -	{ -		mRelativePos = (whereCameraPositionWantsToBe - mSubjectPosition) * ~mSubjectRotation; -	} -	else -	{ -		//#################################################################################### -		// update Position -		//#################################################################################### -		//------------------------------------------------------------------------- -		// I determine the horizontal vector from the camera to the subject -		//------------------------------------------------------------------------- -		LLVector3 horizontalVectorFromCameraToSubject = vectorFromCameraToSubject; -		horizontalVectorFromCameraToSubject.mV[VZ] = 0.0f; - -		//--------------------------------------------------------- -		// Now I determine the horizontal distance -		//--------------------------------------------------------- -		F32 horizontalDistanceFromCameraToSubject = horizontalVectorFromCameraToSubject.magVec();   - -		//--------------------------------------------------------- -		// Then I get the (normalized) horizontal direction... -		//--------------------------------------------------------- -		LLVector3 horizontalDirectionFromCameraToSubject;	 -		if ( horizontalDistanceFromCameraToSubject < DISTANCE_EPSILON ) -		{ -			// make sure we still have a normalized vector if distance is really small  -			// (this case is rare and fleeting) -			horizontalDirectionFromCameraToSubject = LLVector3::z_axis; -		} -		else -		{ -			// I'm not using the "normalize" method, because I can just divide by horizontalDistanceFromCameraToSubject -			horizontalDirectionFromCameraToSubject = horizontalVectorFromCameraToSubject / horizontalDistanceFromCameraToSubject; -		} - -		//------------------------------------------------------------------------------------------------------------ -		// Here is where I determine an offset relative to subject position in oder to set the ideal position.  -		//------------------------------------------------------------------------------------------------------------ -		if ( mPitchSineAndCosineNeedToBeUpdated ) -		{ -			calculatePitchSineAndCosine(); -			mPitchSineAndCosineNeedToBeUpdated = false; -		} - -		LLVector3 positionOffsetFromSubject; -		positionOffsetFromSubject.setVec -			(  -				horizontalDirectionFromCameraToSubject.mV[ VX ] * mPitchCos, -				horizontalDirectionFromCameraToSubject.mV[ VY ] * mPitchCos, -				-mPitchSin -			); - -		positionOffsetFromSubject *= mSimulatedDistance; - -		//---------------------------------------------------------------------- -		// Finally, ideal position is set by taking the subject position and  -		// extending the positionOffsetFromSubject from that -		//---------------------------------------------------------------------- -		LLVector3 idealCameraPosition = offsetSubjectPosition - positionOffsetFromSubject; - -		//-------------------------------------------------------------------------------- -		// Now I prepare to move the current camera position towards its ideal position... -		//-------------------------------------------------------------------------------- -		LLVector3 vectorFromPositionToIdealPosition = idealCameraPosition - simulated_pos_agent; -		F32 distanceFromPositionToIdealPosition = vectorFromPositionToIdealPosition.magVec(); -		 -		//put this inside of the block?		 -		LLVector3 normalFromPositionToIdealPosition = vectorFromPositionToIdealPosition / distanceFromPositionToIdealPosition; -		 -		whereCameraPositionWantsToBe = simulated_pos_agent +  -			(normalFromPositionToIdealPosition * (distanceFromPositionToIdealPosition - mPositionThreshold)); -		//------------------------------------------------------------------------------------------------- -		// The following method takes the target camera position and resets it so that it stays "behind" the subject,  -		// using behindness angle and behindness force as parameters affecting the exact behavior -		//------------------------------------------------------------------------------------------------- -		if ( distanceFromPositionToIdealPosition > mPositionThreshold ) -		{ -			F32 positionPullLerp = LLSmoothInterpolation::getInterpolant( mPositionLag ); -			simulated_pos_agent = lerp( simulated_pos_agent, whereCameraPositionWantsToBe, positionPullLerp ); -		} - -		//-------------------------------------------------------------------- -		// don't let the camera get farther than its official max distance -		//-------------------------------------------------------------------- -		if ( distanceFromCameraToSubject > mMaxCameraDistantFromSubject ) -		{ -			LLVector3 directionFromCameraToSubject = vectorFromCameraToSubject / distanceFromCameraToSubject; -			simulated_pos_agent = offsetSubjectPosition - directionFromCameraToSubject * mMaxCameraDistantFromSubject; -		} - -		////------------------------------------------------------------------------------------------------- -		//// The following method takes mSimulatedPositionGlobal and resets it so that it stays "behind" the subject,  -		//// using behindness angle and behindness force as parameters affecting the exact behavior -		////------------------------------------------------------------------------------------------------- -		updateBehindnessConstraint(gAgent.getPosAgentFromGlobal(mSimulatedFocusGlobal), simulated_pos_agent); -		mSimulatedPositionGlobal = gAgent.getPosGlobalFromAgent(simulated_pos_agent); - -		mRelativePos = lerp(mRelativePos, (simulated_pos_agent - mSubjectPosition) * ~mSubjectRotation, LLSmoothInterpolation::getInterpolant(0.05f)); -	} // if position is not locked ----------------------------------------------------------- - - -	//#################################################################################### -	// update UpVector -	//#################################################################################### -	// this just points upward for now, but I anticipate future effects requiring  -	// some rolling ("banking" effects for fun, swoopy vehicles, etc.) -	mUpVector = LLVector3::z_axis; -} - - - -//------------------------------------------------------------------------------------- -bool LLFollowCam::updateBehindnessConstraint(LLVector3 focus, LLVector3& cam_position) -{ -	bool constraint_active = false; -	// only apply this stuff if the behindness angle is something other than opened up all the way -	if ( mBehindnessMaxAngle < FOLLOW_CAM_MAX_BEHINDNESS_ANGLE - FOLLOW_CAM_BEHINDNESS_EPSILON ) -	{ -		//-------------------------------------------------------------- -		// horizontalized vector from focus to camera  -		//-------------------------------------------------------------- -		LLVector3 horizontalVectorFromFocusToCamera; -		horizontalVectorFromFocusToCamera.setVec(cam_position - focus); -		horizontalVectorFromFocusToCamera.mV[ VZ ] = 0.0f;  -		F32 cameraZ = cam_position.mV[ VZ ]; - -		//-------------------------------------------------------------- -		// distance of horizontalized vector -		//-------------------------------------------------------------- -		F32 horizontalDistance = horizontalVectorFromFocusToCamera.magVec(); - -		//-------------------------------------------------------------------------------------------------- -		// calculate horizontalized back vector of the subject and scale by horizontalDistance -		//-------------------------------------------------------------------------------------------------- -		LLVector3 horizontalSubjectBack( -1.0f, 0.0f, 0.0f ); -		horizontalSubjectBack *= mSubjectRotation; -		horizontalSubjectBack.mV[ VZ ] = 0.0f;  -		horizontalSubjectBack.normVec(); // because horizontalizing might make it shorter than 1 -		horizontalSubjectBack *= horizontalDistance; - -		//-------------------------------------------------------------------------------------------------- -		// find the angle (in degrees) between these vectors -		//-------------------------------------------------------------------------------------------------- -		F32 cameraOffsetAngle = 0.f; -		LLVector3 cameraOffsetRotationAxis; -		LLQuaternion camera_offset_rotation; -		camera_offset_rotation.shortestArc(horizontalSubjectBack, horizontalVectorFromFocusToCamera); -		camera_offset_rotation.getAngleAxis(&cameraOffsetAngle, cameraOffsetRotationAxis); -		cameraOffsetAngle *= RAD_TO_DEG; - -		if ( cameraOffsetAngle > mBehindnessMaxAngle ) -		{ -			F32 fraction = ((cameraOffsetAngle - mBehindnessMaxAngle) / cameraOffsetAngle) * LLSmoothInterpolation::getInterpolant(mBehindnessLag); -			cam_position = focus + horizontalSubjectBack * (slerp(fraction, camera_offset_rotation, LLQuaternion::DEFAULT)); -			cam_position.mV[VZ] = cameraZ; // clamp z value back to what it was before we started messing with it -			constraint_active = true; -		} -	} -	return constraint_active; -} - - -//--------------------------------------------------------- -void LLFollowCam::calculatePitchSineAndCosine() -{ -	F32 radian = mPitch * DEG_TO_RAD; -	mPitchCos = cos( radian ); -	mPitchSin = sin( radian ); -} - -//--------------------------------------------------------- -void LLFollowCam::setSubjectPositionAndRotation( const LLVector3 p, const LLQuaternion r ) -{ -	mSubjectPosition = p; -	mSubjectRotation = r; -} - - -//--------------------------------------------------------- -void LLFollowCam::zoom( S32 z )  -{  -	F32 zoomAmount = z * mSimulatedDistance * FOLLOW_CAM_ZOOM_FACTOR; - -	if (( zoomAmount <  FOLLOW_CAM_MIN_ZOOM_AMOUNT ) -	&&  ( zoomAmount > -FOLLOW_CAM_MIN_ZOOM_AMOUNT )) -	{ -		if ( zoomAmount < 0.0f ) -		{ -			zoomAmount = -FOLLOW_CAM_MIN_ZOOM_AMOUNT; -		} -		else -		{ -			zoomAmount = FOLLOW_CAM_MIN_ZOOM_AMOUNT; -		} -	} - -	mSimulatedDistance += zoomAmount; - -	mZoomedToMinimumDistance = false; -	if ( mSimulatedDistance < FOLLOW_CAM_MIN_DISTANCE )  -	{ -		mSimulatedDistance = FOLLOW_CAM_MIN_DISTANCE; - -		// if zoomAmount is negative (i.e., getting closer), then -		// this signifies having hit the minimum: -		if ( zoomAmount < 0.0f ) -		{ -			mZoomedToMinimumDistance = true; -		} -	} -	else if ( mSimulatedDistance > mMaxCameraDistantFromSubject )  -	{ -		mSimulatedDistance = mMaxCameraDistantFromSubject; -	} -} - - -//--------------------------------------------------------- -bool LLFollowCam::isZoomedToMinimumDistance() -{ -	return mZoomedToMinimumDistance; -} - - -//--------------------------------------------------------- -void LLFollowCam::reset( const LLVector3 p, const LLVector3 f , const LLVector3 u ) -{ -	setPosition(p); -	setFocus(f); -	mUpVector	= u; -} - -//--------------------------------------------------------- -void LLFollowCam::setMaxCameraDistantFromSubject( F32 m ) -{ -	mMaxCameraDistantFromSubject = m; -} - - -void LLFollowCam::setPitch( F32 p )  -{  -	LLFollowCamParams::setPitch(p); -	mPitchSineAndCosineNeedToBeUpdated = true; // important -} - -void LLFollowCam::setDistance( F32 d )  -{  -	if (d != mDistance) -	{ -		LLFollowCamParams::setDistance(d); -		mSimulatedDistance = d; -		mZoomedToMinimumDistance = false;  -	} -} - -void LLFollowCam::setPosition( const LLVector3& p )  -{  -	if (p != mPosition) -	{ -		LLFollowCamParams::setPosition(p); -		mSimulatedPositionGlobal = gAgent.getPosGlobalFromAgent(mPosition); -		if (mPositionLocked) -		{ -			mRelativePos = (mPosition - mSubjectPosition) * ~mSubjectRotation; -		} -	} -} - -void LLFollowCam::setFocus( const LLVector3& f )  -{  -	if (f != mFocus) -	{ -		LLFollowCamParams::setFocus(f); -		mSimulatedFocusGlobal = gAgent.getPosGlobalFromAgent(f); -		if (mFocusLocked) -		{ -			mRelativeFocus = (mFocus - mSubjectPosition) * ~mSubjectRotation; -		} -	} -} - -void LLFollowCam::setPositionLocked( bool locked ) -{ -	LLFollowCamParams::setPositionLocked(locked); -	if (locked) -	{ -		// propagate set position to relative position -		mRelativePos = (gAgent.getPosAgentFromGlobal(mSimulatedPositionGlobal) - mSubjectPosition) * ~mSubjectRotation; -	} -} - -void LLFollowCam::setFocusLocked( bool locked ) -{ -	LLFollowCamParams::setFocusLocked(locked); -	if (locked)	 -	{ -		// propagate set position to relative position -		mRelativeFocus = (gAgent.getPosAgentFromGlobal(mSimulatedFocusGlobal) - mSubjectPosition) * ~mSubjectRotation; -	} -} - - -LLVector3	LLFollowCam::getSimulatedPosition() const  -{  -	// return simulated position -	return mSubjectPosition + (mRelativePos * mSubjectRotation); -} - -LLVector3	LLFollowCam::getSimulatedFocus() const  -{  -	// return simulated focus point -	return mSubjectPosition + (mRelativeFocus * mSubjectRotation); -} - -LLVector3	LLFollowCam::getUpVector()  -{  -	return mUpVector;			 -} - - -//------------------------------------ -// Destructor -//------------------------------------ -LLFollowCam::~LLFollowCam() -{ -} - - -//------------------------------------------------------- -// LLFollowCamMgr -//------------------------------------------------------- -LLFollowCamMgr::LLFollowCamMgr() -{ -} - -LLFollowCamMgr::~LLFollowCamMgr() -{ -    for (param_map_t::iterator iter = mParamMap.begin(); iter != mParamMap.end(); ++iter) -    { -        LLFollowCamParams* params = iter->second; -        delete params; -    } -    mParamMap.clear(); -} - -void LLFollowCamMgr::setPositionLag( const LLUUID& source, F32 lag) -{ -	LLFollowCamParams* paramsp = getParamsForID(source); -	if (paramsp) -	{ -		paramsp->setPositionLag(lag); -	} -} - -void LLFollowCamMgr::setFocusLag( const LLUUID& source, F32 lag) -{ -	LLFollowCamParams* paramsp = getParamsForID(source); -	if (paramsp) -	{ -		paramsp->setFocusLag(lag); -	} -} - -void LLFollowCamMgr::setFocusThreshold( const LLUUID& source, F32 threshold) -{ -	LLFollowCamParams* paramsp = getParamsForID(source); -	if (paramsp) -	{ -		paramsp->setFocusThreshold(threshold); -	} - -} - -void LLFollowCamMgr::setPositionThreshold( const LLUUID& source, F32 threshold) -{ -	LLFollowCamParams* paramsp = getParamsForID(source); -	if (paramsp) -	{ -		paramsp->setPositionThreshold(threshold); -	} -} - -void LLFollowCamMgr::setDistance( const LLUUID& source, F32 distance) -{ -	LLFollowCamParams* paramsp = getParamsForID(source); -	if (paramsp) -	{ -		paramsp->setDistance(distance); -	} -} - -void LLFollowCamMgr::setPitch( const LLUUID& source, F32 pitch) -{ -	LLFollowCamParams* paramsp = getParamsForID(source); -	if (paramsp) -	{ -		paramsp->setPitch(pitch); -	} -} - -void LLFollowCamMgr::setFocusOffset( const LLUUID& source, const LLVector3& offset) -{ -	LLFollowCamParams* paramsp = getParamsForID(source); -	if (paramsp) -	{ -		paramsp->setFocusOffset(offset); -	} -} - -void LLFollowCamMgr::setBehindnessAngle( const LLUUID& source, F32 angle) -{ -	LLFollowCamParams* paramsp = getParamsForID(source); -	if (paramsp) -	{ -		paramsp->setBehindnessAngle(angle); -	} -} - -void LLFollowCamMgr::setBehindnessLag( const LLUUID& source, F32 force) -{ -	LLFollowCamParams* paramsp = getParamsForID(source); -	if (paramsp) -	{ -		paramsp->setBehindnessLag(force); -	} -} - -void LLFollowCamMgr::setPosition( const LLUUID& source, const LLVector3 position) -{ -	LLFollowCamParams* paramsp = getParamsForID(source); -	if (paramsp) -	{ -		paramsp->setPosition(position); -	} -} - -void LLFollowCamMgr::setFocus( const LLUUID& source, const LLVector3 focus) -{ -	LLFollowCamParams* paramsp = getParamsForID(source); -	if (paramsp) -	{ -		paramsp->setFocus(focus); -	} -} - -void LLFollowCamMgr::setPositionLocked( const LLUUID& source, bool locked) -{ -	LLFollowCamParams* paramsp = getParamsForID(source); -	if (paramsp) -	{ -		paramsp->setPositionLocked(locked); -	} -} - -void LLFollowCamMgr::setFocusLocked( const LLUUID& source, bool locked ) -{ -	LLFollowCamParams* paramsp = getParamsForID(source); -	if (paramsp) -	{ -		paramsp->setFocusLocked(locked); -	} -} - -LLFollowCamParams* LLFollowCamMgr::getParamsForID(const LLUUID& source) -{ -	LLFollowCamParams* params = NULL; - -	param_map_t::iterator found_it = mParamMap.find(source); -	if (found_it == mParamMap.end()) // didn't find it? -	{ -		params = new LLFollowCamParams(); -		mParamMap[source] = params; -	} -	else -	{ -		params = found_it->second; -	} - -	return params; -} - -LLFollowCamParams* LLFollowCamMgr::getActiveFollowCamParams() -{ -	if (mParamStack.empty()) -	{ -		return NULL; -	} - -	return mParamStack.back(); -} - -void LLFollowCamMgr::setCameraActive( const LLUUID& source, bool active ) -{ -	LLFollowCamParams* params = getParamsForID(source); -	param_stack_t::iterator found_it = std::find(mParamStack.begin(), mParamStack.end(), params); -	if (found_it != mParamStack.end()) -	{ -		mParamStack.erase(found_it); -	} -	// put on top of stack -	if(active) -	{ -		mParamStack.push_back(params); -	} -} - -void LLFollowCamMgr::removeFollowCamParams(const LLUUID& source) -{ -	setCameraActive(source, false); -	LLFollowCamParams* params = getParamsForID(source); -	mParamMap.erase(source); -	delete params; -} - -bool LLFollowCamMgr::isScriptedCameraSource(const LLUUID& source) -{ -	param_map_t::iterator found_it = mParamMap.find(source); -	return (found_it != mParamMap.end()); -} - -void LLFollowCamMgr::dump() -{ -	S32 param_count = 0; -	LL_INFOS() << "Scripted camera active stack" << LL_ENDL; -	for (param_stack_t::iterator param_it = mParamStack.begin(); -		param_it != mParamStack.end(); -		++param_it) -	{ -		LL_INFOS() << param_count++ <<  -			" rot_limit: " << (*param_it)->getBehindnessAngle() <<  -			" rot_lag: " << (*param_it)->getBehindnessLag() <<  -			" distance: " << (*param_it)->getDistance() <<  -			" focus: " << (*param_it)->getFocus() <<  -			" foc_lag: " << (*param_it)->getFocusLag() <<  -			" foc_lock: " << ((*param_it)->getFocusLocked() ? "Y" : "N") <<  -			" foc_offset: " << (*param_it)->getFocusOffset() <<  -			" foc_thresh: " << (*param_it)->getFocusThreshold() <<  -			" pitch: " << (*param_it)->getPitch() <<  -			" pos: " << (*param_it)->getPosition() <<  -			" pos_lag: " << (*param_it)->getPositionLag() <<  -			" pos_lock: " << ((*param_it)->getPositionLocked() ? "Y" : "N") <<  -			" pos_thresh: " << (*param_it)->getPositionThreshold() << LL_ENDL; -	} -} - +/**
 + * @file llfollowcam.cpp
 + * @author Jeffrey Ventrella
 + * @brief LLFollowCam class implementation
 + *
 + * $LicenseInfo:firstyear=2005&license=viewerlgpl$
 + * Second Life Viewer Source Code
 + * Copyright (C) 2010, Linden Research, Inc.
 + *
 + * This library is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation;
 + * version 2.1 of the License only.
 + *
 + * This library is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
 + * License along with this library; if not, write to the Free Software
 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 + *
 + * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 + * $/LicenseInfo$
 + */
 +
 +#include "llviewerprecompiledheaders.h"
 +#include "llfollowcam.h"
 +#include "llagent.h"
 +
 +//-------------------------------------------------------
 +// constants
 +//-------------------------------------------------------
 +const F32 FOLLOW_CAM_ZOOM_FACTOR            = 0.1f;
 +const F32 FOLLOW_CAM_MIN_ZOOM_AMOUNT        = 0.1f;
 +const F32 DISTANCE_EPSILON                  = 0.0001f;
 +const F32 DEFAULT_MAX_DISTANCE_FROM_SUBJECT = 1000.0;   // this will be correctly set on me by my caller
 +
 +//----------------------------------------------------------------------------------------
 +// This is how slowly the camera position moves to its ideal position
 +//----------------------------------------------------------------------------------------
 +const F32 FOLLOW_CAM_MIN_POSITION_LAG       = 0.0f;
 +const F32 FOLLOW_CAM_DEFAULT_POSITION_LAG   = 0.1f;
 +const F32 FOLLOW_CAM_MAX_POSITION_LAG       = 3.0f;
 +
 +//----------------------------------------------------------------------------------------
 +// This is how slowly the camera focus moves to its subject
 +//----------------------------------------------------------------------------------------
 +const F32 FOLLOW_CAM_MIN_FOCUS_LAG      = 0.0f;
 +const F32 FOLLOW_CAM_DEFAULT_FOCUS_LAG  = 0.1f;
 +const F32 FOLLOW_CAM_MAX_FOCUS_LAG      = 3.0f;
 +
 +//----------------------------------------------------------------------------------------
 +// This is far the position can get from its IDEAL POSITION before it starts getting pulled
 +//----------------------------------------------------------------------------------------
 +const F32 FOLLOW_CAM_MIN_POSITION_THRESHOLD     = 0.0f;
 +const F32 FOLLOW_CAM_DEFAULT_POSITION_THRESHOLD = 1.0f;
 +const F32 FOLLOW_CAM_MAX_POSITION_THRESHOLD     = 4.0f;
 +
 +//----------------------------------------------------------------------------------------
 +// This is far the focus can get from the subject before it starts getting pulled
 +//----------------------------------------------------------------------------------------
 +const F32 FOLLOW_CAM_MIN_FOCUS_THRESHOLD        = 0.0f;
 +const F32 FOLLOW_CAM_DEFAULT_FOCUS_THRESHOLD    = 1.0f;
 +const F32 FOLLOW_CAM_MAX_FOCUS_THRESHOLD        = 4.0f;
 +
 +//----------------------------------------------------------------------------------------
 +// This is the distance the camera wants to be from the subject
 +//----------------------------------------------------------------------------------------
 +const F32 FOLLOW_CAM_MIN_DISTANCE       = 0.5f;
 +const F32 FOLLOW_CAM_DEFAULT_DISTANCE   = 3.0f;
 +//const F32 FOLLOW_CAM_MAX_DISTANCE     = 10.0f; // from now on I am using mMaxCameraDistantFromSubject
 +
 +//----------------------------------------------------------------------------------------
 +// this is an angluar value
 +// It affects the angle that the camera rises (pitches) in relation
 +// to the horizontal plane
 +//----------------------------------------------------------------------------------------
 +const F32 FOLLOW_CAM_MIN_PITCH      = -45.0f;
 +const F32 FOLLOW_CAM_DEFAULT_PITCH  =   0.0f;
 +const F32 FOLLOW_CAM_MAX_PITCH      =  80.0f;   // keep under 90 degrees - avoid gimble lock!
 +
 +
 +//----------------------------------------------------------------------------------------
 +// how high or low the camera considers its ideal focus to be (relative to its subject)
 +//----------------------------------------------------------------------------------------
 +const F32 FOLLOW_CAM_MIN_FOCUS_OFFSET       = -10.0f;
 +const LLVector3 FOLLOW_CAM_DEFAULT_FOCUS_OFFSET =  LLVector3(1.0f, 0.f, 0.f);
 +const F32 FOLLOW_CAM_MAX_FOCUS_OFFSET       =  10.0f;
 +
 +//----------------------------------------------------------------------------------------
 +// This affects the rate at which the camera adjusts to stay behind the subject
 +//----------------------------------------------------------------------------------------
 +const F32 FOLLOW_CAM_MIN_BEHINDNESS_LAG     = 0.0f;
 +const F32 FOLLOW_CAM_DEFAULT_BEHINDNESS_LAG     = 0.f;
 +const F32 FOLLOW_CAM_MAX_BEHINDNESS_LAG     = 3.0f;
 +
 +//---------------------------------------------------------------------------------------------------------------------
 +// in  degrees: This is the size of the pie slice behind the subject matter within which the camera is free to move
 +//---------------------------------------------------------------------------------------------------------------------
 +const F32 FOLLOW_CAM_MIN_BEHINDNESS_ANGLE       = 0.0f;
 +const F32 FOLLOW_CAM_DEFAULT_BEHINDNESS_ANGLE   = 10.0f;
 +const F32 FOLLOW_CAM_MAX_BEHINDNESS_ANGLE       = 180.0f;
 +const F32 FOLLOW_CAM_BEHINDNESS_EPSILON         = 1.0f;
 +
 +//------------------------------------
 +// Constructor
 +//------------------------------------
 +LLFollowCamParams::LLFollowCamParams()
 +{
 +    mMaxCameraDistantFromSubject        = DEFAULT_MAX_DISTANCE_FROM_SUBJECT;
 +    mPositionLocked                     = false;
 +    mFocusLocked                        = false;
 +    mUsePosition                        = false;
 +    mUseFocus                           = false;
 +
 +    //------------------------------------------------------
 +    // setting the attributes to their defaults
 +    //------------------------------------------------------
 +    setPositionLag      ( FOLLOW_CAM_DEFAULT_POSITION_LAG           );
 +    setFocusLag         ( FOLLOW_CAM_DEFAULT_FOCUS_LAG              );
 +    setPositionThreshold( FOLLOW_CAM_DEFAULT_POSITION_THRESHOLD     );
 +    setFocusThreshold   ( FOLLOW_CAM_DEFAULT_FOCUS_THRESHOLD        );
 +    setBehindnessLag    ( FOLLOW_CAM_DEFAULT_BEHINDNESS_LAG     );
 +    setDistance         ( FOLLOW_CAM_DEFAULT_DISTANCE               );
 +    setPitch            ( FOLLOW_CAM_DEFAULT_PITCH                  );
 +    setFocusOffset      ( FOLLOW_CAM_DEFAULT_FOCUS_OFFSET   );
 +    setBehindnessAngle  ( FOLLOW_CAM_DEFAULT_BEHINDNESS_ANGLE       );
 +    setPositionThreshold( FOLLOW_CAM_DEFAULT_POSITION_THRESHOLD     );
 +    setFocusThreshold   ( FOLLOW_CAM_DEFAULT_FOCUS_THRESHOLD        );
 +
 +}
 +
 +LLFollowCamParams::~LLFollowCamParams() { }
 +
 +//---------------------------------------------------------
 +// buncho set methods
 +//---------------------------------------------------------
 +
 +//---------------------------------------------------------
 +void LLFollowCamParams::setPositionLag( F32 p )
 +{
 +    mPositionLag = llclamp(p, FOLLOW_CAM_MIN_POSITION_LAG, FOLLOW_CAM_MAX_POSITION_LAG);
 +}
 +
 +
 +//---------------------------------------------------------
 +void LLFollowCamParams::setFocusLag( F32 f )
 +{
 +    mFocusLag = llclamp(f, FOLLOW_CAM_MIN_FOCUS_LAG, FOLLOW_CAM_MAX_FOCUS_LAG);
 +}
 +
 +
 +//---------------------------------------------------------
 +void LLFollowCamParams::setPositionThreshold( F32 p )
 +{
 +    mPositionThreshold = llclamp(p, FOLLOW_CAM_MIN_POSITION_THRESHOLD, FOLLOW_CAM_MAX_POSITION_THRESHOLD);
 +}
 +
 +
 +//---------------------------------------------------------
 +void LLFollowCamParams::setFocusThreshold( F32 f )
 +{
 +    mFocusThreshold = llclamp(f, FOLLOW_CAM_MIN_FOCUS_THRESHOLD, FOLLOW_CAM_MAX_FOCUS_THRESHOLD);
 +}
 +
 +
 +//---------------------------------------------------------
 +void LLFollowCamParams::setPitch( F32 p )
 +{
 +    mPitch = llclamp(p, FOLLOW_CAM_MIN_PITCH, FOLLOW_CAM_MAX_PITCH);
 +}
 +
 +
 +//---------------------------------------------------------
 +void LLFollowCamParams::setBehindnessLag( F32 b )
 +{
 +    mBehindnessLag = llclamp(b, FOLLOW_CAM_MIN_BEHINDNESS_LAG, FOLLOW_CAM_MAX_BEHINDNESS_LAG);
 +}
 +
 +//---------------------------------------------------------
 +void LLFollowCamParams::setBehindnessAngle( F32 b )
 +{
 +    mBehindnessMaxAngle = llclamp(b, FOLLOW_CAM_MIN_BEHINDNESS_ANGLE, FOLLOW_CAM_MAX_BEHINDNESS_ANGLE);
 +}
 +
 +//---------------------------------------------------------
 +void LLFollowCamParams::setDistance( F32 d )
 +{
 +    mDistance = llclamp(d, FOLLOW_CAM_MIN_DISTANCE, mMaxCameraDistantFromSubject);
 +}
 +
 +//---------------------------------------------------------
 +void LLFollowCamParams::setPositionLocked( bool l )
 +{
 +    mPositionLocked = l;
 +}
 +
 +//---------------------------------------------------------
 +void LLFollowCamParams::setFocusLocked( bool l )
 +{
 +    mFocusLocked = l;
 +
 +}
 +
 +//---------------------------------------------------------
 +void LLFollowCamParams::setFocusOffset( const LLVector3& v )
 +{
 +    mFocusOffset = v;
 +    mFocusOffset.clamp(FOLLOW_CAM_MIN_FOCUS_OFFSET, FOLLOW_CAM_MAX_FOCUS_OFFSET);
 +}
 +
 +//---------------------------------------------------------
 +void LLFollowCamParams::setPosition( const LLVector3& p )
 +{
 +    mUsePosition = true;
 +    mPosition = p;
 +}
 +
 +//---------------------------------------------------------
 +void LLFollowCamParams::setFocus( const LLVector3& f )
 +{
 +    mUseFocus = true;
 +    mFocus = f;
 +}
 +
 +//---------------------------------------------------------
 +// buncho get methods
 +//---------------------------------------------------------
 +F32         LLFollowCamParams::getPositionLag       () const { return mPositionLag;         }
 +F32         LLFollowCamParams::getFocusLag          () const { return mFocusLag;            }
 +F32         LLFollowCamParams::getPositionThreshold () const { return mPositionThreshold;   }
 +F32         LLFollowCamParams::getFocusThreshold    () const { return mFocusThreshold;      }
 +F32         LLFollowCamParams::getDistance          () const { return mDistance;            }
 +F32         LLFollowCamParams::getPitch             () const { return mPitch;               }
 +LLVector3   LLFollowCamParams::getFocusOffset       () const { return mFocusOffset;         }
 +F32         LLFollowCamParams::getBehindnessAngle   () const { return mBehindnessMaxAngle;  }
 +F32         LLFollowCamParams::getBehindnessLag     () const { return mBehindnessLag;       }
 +LLVector3   LLFollowCamParams::getPosition          () const { return mPosition;            }
 +LLVector3   LLFollowCamParams::getFocus             () const { return mFocus;               }
 +bool        LLFollowCamParams::getPositionLocked    () const { return mPositionLocked;      }
 +bool        LLFollowCamParams::getFocusLocked       () const { return mFocusLocked;         }
 +
 +//------------------------------------
 +// Constructor
 +//------------------------------------
 +LLFollowCam::LLFollowCam() : LLFollowCamParams()
 +{
 +    mUpVector                           = LLVector3::z_axis;
 +    mSubjectPosition                    = LLVector3::zero;
 +    mSubjectRotation                    = LLQuaternion::DEFAULT;
 +
 +    mZoomedToMinimumDistance            = false;
 +    mPitchCos = mPitchSin = 0.f;
 +    mPitchSineAndCosineNeedToBeUpdated  = true;
 +
 +    mSimulatedDistance = mDistance;
 +}
 +
 +void LLFollowCam::copyParams(LLFollowCamParams& params)
 +{
 +    setPositionLag(params.getPositionLag());
 +    setFocusLag(params.getFocusLag());
 +    setFocusThreshold( params.getFocusThreshold());
 +    setPositionThreshold(params.getPositionThreshold());
 +    setPitch(params.getPitch());
 +    setFocusOffset(params.getFocusOffset());
 +    setBehindnessAngle(params.getBehindnessAngle());
 +    setBehindnessLag(params.getBehindnessLag());
 +
 +    setPositionLocked(params.getPositionLocked());
 +    setFocusLocked(params.getFocusLocked());
 +
 +    setDistance(params.getDistance());
 +    if (params.getUsePosition())
 +    {
 +        setPosition(params.getPosition());
 +    }
 +    if (params.getUseFocus())
 +    {
 +        setFocus(params.getFocus());
 +    }
 +}
 +
 +//---------------------------------------------------------------------------------------------------------
 +void LLFollowCam::update()
 +{
 +    //####################################################################################
 +    // update Focus
 +    //####################################################################################
 +    LLVector3 offsetSubjectPosition = mSubjectPosition + (mFocusOffset * mSubjectRotation);
 +
 +    LLVector3 simulated_pos_agent = gAgent.getPosAgentFromGlobal(mSimulatedPositionGlobal);
 +    LLVector3 vectorFromCameraToSubject = offsetSubjectPosition - simulated_pos_agent;
 +    F32 distanceFromCameraToSubject = vectorFromCameraToSubject.magVec();
 +
 +    LLVector3 whereFocusWantsToBe = mFocus;
 +    LLVector3 focus_pt_agent = gAgent.getPosAgentFromGlobal(mSimulatedFocusGlobal);
 +    if ( mFocusLocked ) // if focus is locked, only relative focus needs to be updated
 +    {
 +        mRelativeFocus = (focus_pt_agent - mSubjectPosition) * ~mSubjectRotation;
 +    }
 +    else
 +    {
 +        LLVector3 focusOffset = offsetSubjectPosition - focus_pt_agent;
 +        F32 focusOffsetDistance = focusOffset.magVec();
 +
 +        LLVector3 focusOffsetDirection = focusOffset / focusOffsetDistance;
 +        whereFocusWantsToBe = focus_pt_agent +
 +            (focusOffsetDirection * (focusOffsetDistance - mFocusThreshold));
 +        if ( focusOffsetDistance > mFocusThreshold )
 +        {
 +            // this version normalizes focus threshold by distance
 +            // so that the effect is not changed with distance
 +            /*
 +            F32 focusThresholdNormalizedByDistance = distanceFromCameraToSubject * mFocusThreshold;
 +            if ( focusOffsetDistance > focusThresholdNormalizedByDistance )
 +            {
 +                LLVector3 focusOffsetDirection = focusOffset / focusOffsetDistance;
 +                F32 force = focusOffsetDistance - focusThresholdNormalizedByDistance;
 +            */
 +
 +            F32 focusLagLerp = LLSmoothInterpolation::getInterpolant( mFocusLag );
 +            focus_pt_agent = lerp( focus_pt_agent, whereFocusWantsToBe, focusLagLerp );
 +            mSimulatedFocusGlobal = gAgent.getPosGlobalFromAgent(focus_pt_agent);
 +        }
 +        mRelativeFocus = lerp(mRelativeFocus, (focus_pt_agent - mSubjectPosition) * ~mSubjectRotation, LLSmoothInterpolation::getInterpolant(0.05f));
 +    }// if focus is not locked ---------------------------------------------
 +
 +
 +    LLVector3 whereCameraPositionWantsToBe = gAgent.getPosAgentFromGlobal(mSimulatedPositionGlobal);
 +    if (  mPositionLocked )
 +    {
 +        mRelativePos = (whereCameraPositionWantsToBe - mSubjectPosition) * ~mSubjectRotation;
 +    }
 +    else
 +    {
 +        //####################################################################################
 +        // update Position
 +        //####################################################################################
 +        //-------------------------------------------------------------------------
 +        // I determine the horizontal vector from the camera to the subject
 +        //-------------------------------------------------------------------------
 +        LLVector3 horizontalVectorFromCameraToSubject = vectorFromCameraToSubject;
 +        horizontalVectorFromCameraToSubject.mV[VZ] = 0.0f;
 +
 +        //---------------------------------------------------------
 +        // Now I determine the horizontal distance
 +        //---------------------------------------------------------
 +        F32 horizontalDistanceFromCameraToSubject = horizontalVectorFromCameraToSubject.magVec();
 +
 +        //---------------------------------------------------------
 +        // Then I get the (normalized) horizontal direction...
 +        //---------------------------------------------------------
 +        LLVector3 horizontalDirectionFromCameraToSubject;
 +        if ( horizontalDistanceFromCameraToSubject < DISTANCE_EPSILON )
 +        {
 +            // make sure we still have a normalized vector if distance is really small
 +            // (this case is rare and fleeting)
 +            horizontalDirectionFromCameraToSubject = LLVector3::z_axis;
 +        }
 +        else
 +        {
 +            // I'm not using the "normalize" method, because I can just divide by horizontalDistanceFromCameraToSubject
 +            horizontalDirectionFromCameraToSubject = horizontalVectorFromCameraToSubject / horizontalDistanceFromCameraToSubject;
 +        }
 +
 +        //------------------------------------------------------------------------------------------------------------
 +        // Here is where I determine an offset relative to subject position in oder to set the ideal position.
 +        //------------------------------------------------------------------------------------------------------------
 +        if ( mPitchSineAndCosineNeedToBeUpdated )
 +        {
 +            calculatePitchSineAndCosine();
 +            mPitchSineAndCosineNeedToBeUpdated = false;
 +        }
 +
 +        LLVector3 positionOffsetFromSubject;
 +        positionOffsetFromSubject.setVec
 +            (
 +                horizontalDirectionFromCameraToSubject.mV[ VX ] * mPitchCos,
 +                horizontalDirectionFromCameraToSubject.mV[ VY ] * mPitchCos,
 +                -mPitchSin
 +            );
 +
 +        positionOffsetFromSubject *= mSimulatedDistance;
 +
 +        //----------------------------------------------------------------------
 +        // Finally, ideal position is set by taking the subject position and
 +        // extending the positionOffsetFromSubject from that
 +        //----------------------------------------------------------------------
 +        LLVector3 idealCameraPosition = offsetSubjectPosition - positionOffsetFromSubject;
 +
 +        //--------------------------------------------------------------------------------
 +        // Now I prepare to move the current camera position towards its ideal position...
 +        //--------------------------------------------------------------------------------
 +        LLVector3 vectorFromPositionToIdealPosition = idealCameraPosition - simulated_pos_agent;
 +        F32 distanceFromPositionToIdealPosition = vectorFromPositionToIdealPosition.magVec();
 +
 +        //put this inside of the block?
 +        LLVector3 normalFromPositionToIdealPosition = vectorFromPositionToIdealPosition / distanceFromPositionToIdealPosition;
 +
 +        whereCameraPositionWantsToBe = simulated_pos_agent +
 +            (normalFromPositionToIdealPosition * (distanceFromPositionToIdealPosition - mPositionThreshold));
 +        //-------------------------------------------------------------------------------------------------
 +        // The following method takes the target camera position and resets it so that it stays "behind" the subject,
 +        // using behindness angle and behindness force as parameters affecting the exact behavior
 +        //-------------------------------------------------------------------------------------------------
 +        if ( distanceFromPositionToIdealPosition > mPositionThreshold )
 +        {
 +            F32 positionPullLerp = LLSmoothInterpolation::getInterpolant( mPositionLag );
 +            simulated_pos_agent = lerp( simulated_pos_agent, whereCameraPositionWantsToBe, positionPullLerp );
 +        }
 +
 +        //--------------------------------------------------------------------
 +        // don't let the camera get farther than its official max distance
 +        //--------------------------------------------------------------------
 +        if ( distanceFromCameraToSubject > mMaxCameraDistantFromSubject )
 +        {
 +            LLVector3 directionFromCameraToSubject = vectorFromCameraToSubject / distanceFromCameraToSubject;
 +            simulated_pos_agent = offsetSubjectPosition - directionFromCameraToSubject * mMaxCameraDistantFromSubject;
 +        }
 +
 +        ////-------------------------------------------------------------------------------------------------
 +        //// The following method takes mSimulatedPositionGlobal and resets it so that it stays "behind" the subject,
 +        //// using behindness angle and behindness force as parameters affecting the exact behavior
 +        ////-------------------------------------------------------------------------------------------------
 +        updateBehindnessConstraint(gAgent.getPosAgentFromGlobal(mSimulatedFocusGlobal), simulated_pos_agent);
 +        mSimulatedPositionGlobal = gAgent.getPosGlobalFromAgent(simulated_pos_agent);
 +
 +        mRelativePos = lerp(mRelativePos, (simulated_pos_agent - mSubjectPosition) * ~mSubjectRotation, LLSmoothInterpolation::getInterpolant(0.05f));
 +    } // if position is not locked -----------------------------------------------------------
 +
 +
 +    //####################################################################################
 +    // update UpVector
 +    //####################################################################################
 +    // this just points upward for now, but I anticipate future effects requiring
 +    // some rolling ("banking" effects for fun, swoopy vehicles, etc.)
 +    mUpVector = LLVector3::z_axis;
 +}
 +
 +
 +
 +//-------------------------------------------------------------------------------------
 +bool LLFollowCam::updateBehindnessConstraint(LLVector3 focus, LLVector3& cam_position)
 +{
 +    bool constraint_active = false;
 +    // only apply this stuff if the behindness angle is something other than opened up all the way
 +    if ( mBehindnessMaxAngle < FOLLOW_CAM_MAX_BEHINDNESS_ANGLE - FOLLOW_CAM_BEHINDNESS_EPSILON )
 +    {
 +        //--------------------------------------------------------------
 +        // horizontalized vector from focus to camera
 +        //--------------------------------------------------------------
 +        LLVector3 horizontalVectorFromFocusToCamera;
 +        horizontalVectorFromFocusToCamera.setVec(cam_position - focus);
 +        horizontalVectorFromFocusToCamera.mV[ VZ ] = 0.0f;
 +        F32 cameraZ = cam_position.mV[ VZ ];
 +
 +        //--------------------------------------------------------------
 +        // distance of horizontalized vector
 +        //--------------------------------------------------------------
 +        F32 horizontalDistance = horizontalVectorFromFocusToCamera.magVec();
 +
 +        //--------------------------------------------------------------------------------------------------
 +        // calculate horizontalized back vector of the subject and scale by horizontalDistance
 +        //--------------------------------------------------------------------------------------------------
 +        LLVector3 horizontalSubjectBack( -1.0f, 0.0f, 0.0f );
 +        horizontalSubjectBack *= mSubjectRotation;
 +        horizontalSubjectBack.mV[ VZ ] = 0.0f;
 +        horizontalSubjectBack.normVec(); // because horizontalizing might make it shorter than 1
 +        horizontalSubjectBack *= horizontalDistance;
 +
 +        //--------------------------------------------------------------------------------------------------
 +        // find the angle (in degrees) between these vectors
 +        //--------------------------------------------------------------------------------------------------
 +        F32 cameraOffsetAngle = 0.f;
 +        LLVector3 cameraOffsetRotationAxis;
 +        LLQuaternion camera_offset_rotation;
 +        camera_offset_rotation.shortestArc(horizontalSubjectBack, horizontalVectorFromFocusToCamera);
 +        camera_offset_rotation.getAngleAxis(&cameraOffsetAngle, cameraOffsetRotationAxis);
 +        cameraOffsetAngle *= RAD_TO_DEG;
 +
 +        if ( cameraOffsetAngle > mBehindnessMaxAngle )
 +        {
 +            F32 fraction = ((cameraOffsetAngle - mBehindnessMaxAngle) / cameraOffsetAngle) * LLSmoothInterpolation::getInterpolant(mBehindnessLag);
 +            cam_position = focus + horizontalSubjectBack * (slerp(fraction, camera_offset_rotation, LLQuaternion::DEFAULT));
 +            cam_position.mV[VZ] = cameraZ; // clamp z value back to what it was before we started messing with it
 +            constraint_active = true;
 +        }
 +    }
 +    return constraint_active;
 +}
 +
 +
 +//---------------------------------------------------------
 +void LLFollowCam::calculatePitchSineAndCosine()
 +{
 +    F32 radian = mPitch * DEG_TO_RAD;
 +    mPitchCos = cos( radian );
 +    mPitchSin = sin( radian );
 +}
 +
 +//---------------------------------------------------------
 +void LLFollowCam::setSubjectPositionAndRotation( const LLVector3 p, const LLQuaternion r )
 +{
 +    mSubjectPosition = p;
 +    mSubjectRotation = r;
 +}
 +
 +
 +//---------------------------------------------------------
 +void LLFollowCam::zoom( S32 z )
 +{
 +    F32 zoomAmount = z * mSimulatedDistance * FOLLOW_CAM_ZOOM_FACTOR;
 +
 +    if (( zoomAmount <  FOLLOW_CAM_MIN_ZOOM_AMOUNT )
 +    &&  ( zoomAmount > -FOLLOW_CAM_MIN_ZOOM_AMOUNT ))
 +    {
 +        if ( zoomAmount < 0.0f )
 +        {
 +            zoomAmount = -FOLLOW_CAM_MIN_ZOOM_AMOUNT;
 +        }
 +        else
 +        {
 +            zoomAmount = FOLLOW_CAM_MIN_ZOOM_AMOUNT;
 +        }
 +    }
 +
 +    mSimulatedDistance += zoomAmount;
 +
 +    mZoomedToMinimumDistance = false;
 +    if ( mSimulatedDistance < FOLLOW_CAM_MIN_DISTANCE )
 +    {
 +        mSimulatedDistance = FOLLOW_CAM_MIN_DISTANCE;
 +
 +        // if zoomAmount is negative (i.e., getting closer), then
 +        // this signifies having hit the minimum:
 +        if ( zoomAmount < 0.0f )
 +        {
 +            mZoomedToMinimumDistance = true;
 +        }
 +    }
 +    else if ( mSimulatedDistance > mMaxCameraDistantFromSubject )
 +    {
 +        mSimulatedDistance = mMaxCameraDistantFromSubject;
 +    }
 +}
 +
 +
 +//---------------------------------------------------------
 +bool LLFollowCam::isZoomedToMinimumDistance()
 +{
 +    return mZoomedToMinimumDistance;
 +}
 +
 +
 +//---------------------------------------------------------
 +void LLFollowCam::reset( const LLVector3 p, const LLVector3 f , const LLVector3 u )
 +{
 +    setPosition(p);
 +    setFocus(f);
 +    mUpVector   = u;
 +}
 +
 +//---------------------------------------------------------
 +void LLFollowCam::setMaxCameraDistantFromSubject( F32 m )
 +{
 +    mMaxCameraDistantFromSubject = m;
 +}
 +
 +
 +void LLFollowCam::setPitch( F32 p )
 +{
 +    LLFollowCamParams::setPitch(p);
 +    mPitchSineAndCosineNeedToBeUpdated = true; // important
 +}
 +
 +void LLFollowCam::setDistance( F32 d )
 +{
 +    if (d != mDistance)
 +    {
 +        LLFollowCamParams::setDistance(d);
 +        mSimulatedDistance = d;
 +        mZoomedToMinimumDistance = false;
 +    }
 +}
 +
 +void LLFollowCam::setPosition( const LLVector3& p )
 +{
 +    if (p != mPosition)
 +    {
 +        LLFollowCamParams::setPosition(p);
 +        mSimulatedPositionGlobal = gAgent.getPosGlobalFromAgent(mPosition);
 +        if (mPositionLocked)
 +        {
 +            mRelativePos = (mPosition - mSubjectPosition) * ~mSubjectRotation;
 +        }
 +    }
 +}
 +
 +void LLFollowCam::setFocus( const LLVector3& f )
 +{
 +    if (f != mFocus)
 +    {
 +        LLFollowCamParams::setFocus(f);
 +        mSimulatedFocusGlobal = gAgent.getPosGlobalFromAgent(f);
 +        if (mFocusLocked)
 +        {
 +            mRelativeFocus = (mFocus - mSubjectPosition) * ~mSubjectRotation;
 +        }
 +    }
 +}
 +
 +void LLFollowCam::setPositionLocked( bool locked )
 +{
 +    LLFollowCamParams::setPositionLocked(locked);
 +    if (locked)
 +    {
 +        // propagate set position to relative position
 +        mRelativePos = (gAgent.getPosAgentFromGlobal(mSimulatedPositionGlobal) - mSubjectPosition) * ~mSubjectRotation;
 +    }
 +}
 +
 +void LLFollowCam::setFocusLocked( bool locked )
 +{
 +    LLFollowCamParams::setFocusLocked(locked);
 +    if (locked)
 +    {
 +        // propagate set position to relative position
 +        mRelativeFocus = (gAgent.getPosAgentFromGlobal(mSimulatedFocusGlobal) - mSubjectPosition) * ~mSubjectRotation;
 +    }
 +}
 +
 +
 +LLVector3   LLFollowCam::getSimulatedPosition() const
 +{
 +    // return simulated position
 +    return mSubjectPosition + (mRelativePos * mSubjectRotation);
 +}
 +
 +LLVector3   LLFollowCam::getSimulatedFocus() const
 +{
 +    // return simulated focus point
 +    return mSubjectPosition + (mRelativeFocus * mSubjectRotation);
 +}
 +
 +LLVector3   LLFollowCam::getUpVector()
 +{
 +    return mUpVector;
 +}
 +
 +
 +//------------------------------------
 +// Destructor
 +//------------------------------------
 +LLFollowCam::~LLFollowCam()
 +{
 +}
 +
 +
 +//-------------------------------------------------------
 +// LLFollowCamMgr
 +//-------------------------------------------------------
 +LLFollowCamMgr::LLFollowCamMgr()
 +{
 +}
 +
 +LLFollowCamMgr::~LLFollowCamMgr()
 +{
 +    for (param_map_t::iterator iter = mParamMap.begin(); iter != mParamMap.end(); ++iter)
 +    {
 +        LLFollowCamParams* params = iter->second;
 +        delete params;
 +    }
 +    mParamMap.clear();
 +}
 +
 +void LLFollowCamMgr::setPositionLag( const LLUUID& source, F32 lag)
 +{
 +    LLFollowCamParams* paramsp = getParamsForID(source);
 +    if (paramsp)
 +    {
 +        paramsp->setPositionLag(lag);
 +    }
 +}
 +
 +void LLFollowCamMgr::setFocusLag( const LLUUID& source, F32 lag)
 +{
 +    LLFollowCamParams* paramsp = getParamsForID(source);
 +    if (paramsp)
 +    {
 +        paramsp->setFocusLag(lag);
 +    }
 +}
 +
 +void LLFollowCamMgr::setFocusThreshold( const LLUUID& source, F32 threshold)
 +{
 +    LLFollowCamParams* paramsp = getParamsForID(source);
 +    if (paramsp)
 +    {
 +        paramsp->setFocusThreshold(threshold);
 +    }
 +
 +}
 +
 +void LLFollowCamMgr::setPositionThreshold( const LLUUID& source, F32 threshold)
 +{
 +    LLFollowCamParams* paramsp = getParamsForID(source);
 +    if (paramsp)
 +    {
 +        paramsp->setPositionThreshold(threshold);
 +    }
 +}
 +
 +void LLFollowCamMgr::setDistance( const LLUUID& source, F32 distance)
 +{
 +    LLFollowCamParams* paramsp = getParamsForID(source);
 +    if (paramsp)
 +    {
 +        paramsp->setDistance(distance);
 +    }
 +}
 +
 +void LLFollowCamMgr::setPitch( const LLUUID& source, F32 pitch)
 +{
 +    LLFollowCamParams* paramsp = getParamsForID(source);
 +    if (paramsp)
 +    {
 +        paramsp->setPitch(pitch);
 +    }
 +}
 +
 +void LLFollowCamMgr::setFocusOffset( const LLUUID& source, const LLVector3& offset)
 +{
 +    LLFollowCamParams* paramsp = getParamsForID(source);
 +    if (paramsp)
 +    {
 +        paramsp->setFocusOffset(offset);
 +    }
 +}
 +
 +void LLFollowCamMgr::setBehindnessAngle( const LLUUID& source, F32 angle)
 +{
 +    LLFollowCamParams* paramsp = getParamsForID(source);
 +    if (paramsp)
 +    {
 +        paramsp->setBehindnessAngle(angle);
 +    }
 +}
 +
 +void LLFollowCamMgr::setBehindnessLag( const LLUUID& source, F32 force)
 +{
 +    LLFollowCamParams* paramsp = getParamsForID(source);
 +    if (paramsp)
 +    {
 +        paramsp->setBehindnessLag(force);
 +    }
 +}
 +
 +void LLFollowCamMgr::setPosition( const LLUUID& source, const LLVector3 position)
 +{
 +    LLFollowCamParams* paramsp = getParamsForID(source);
 +    if (paramsp)
 +    {
 +        paramsp->setPosition(position);
 +    }
 +}
 +
 +void LLFollowCamMgr::setFocus( const LLUUID& source, const LLVector3 focus)
 +{
 +    LLFollowCamParams* paramsp = getParamsForID(source);
 +    if (paramsp)
 +    {
 +        paramsp->setFocus(focus);
 +    }
 +}
 +
 +void LLFollowCamMgr::setPositionLocked( const LLUUID& source, bool locked)
 +{
 +    LLFollowCamParams* paramsp = getParamsForID(source);
 +    if (paramsp)
 +    {
 +        paramsp->setPositionLocked(locked);
 +    }
 +}
 +
 +void LLFollowCamMgr::setFocusLocked( const LLUUID& source, bool locked )
 +{
 +    LLFollowCamParams* paramsp = getParamsForID(source);
 +    if (paramsp)
 +    {
 +        paramsp->setFocusLocked(locked);
 +    }
 +}
 +
 +LLFollowCamParams* LLFollowCamMgr::getParamsForID(const LLUUID& source)
 +{
 +    LLFollowCamParams* params = NULL;
 +
 +    param_map_t::iterator found_it = mParamMap.find(source);
 +    if (found_it == mParamMap.end()) // didn't find it?
 +    {
 +        params = new LLFollowCamParams();
 +        mParamMap[source] = params;
 +    }
 +    else
 +    {
 +        params = found_it->second;
 +    }
 +
 +    return params;
 +}
 +
 +LLFollowCamParams* LLFollowCamMgr::getActiveFollowCamParams()
 +{
 +    if (mParamStack.empty())
 +    {
 +        return NULL;
 +    }
 +
 +    return mParamStack.back();
 +}
 +
 +void LLFollowCamMgr::setCameraActive( const LLUUID& source, bool active )
 +{
 +    LLFollowCamParams* params = getParamsForID(source);
 +    param_stack_t::iterator found_it = std::find(mParamStack.begin(), mParamStack.end(), params);
 +    if (found_it != mParamStack.end())
 +    {
 +        mParamStack.erase(found_it);
 +    }
 +    // put on top of stack
 +    if(active)
 +    {
 +        mParamStack.push_back(params);
 +    }
 +}
 +
 +void LLFollowCamMgr::removeFollowCamParams(const LLUUID& source)
 +{
 +    setCameraActive(source, false);
 +    LLFollowCamParams* params = getParamsForID(source);
 +    mParamMap.erase(source);
 +    delete params;
 +}
 +
 +bool LLFollowCamMgr::isScriptedCameraSource(const LLUUID& source)
 +{
 +    param_map_t::iterator found_it = mParamMap.find(source);
 +    return (found_it != mParamMap.end());
 +}
 +
 +void LLFollowCamMgr::dump()
 +{
 +    S32 param_count = 0;
 +    LL_INFOS() << "Scripted camera active stack" << LL_ENDL;
 +    for (param_stack_t::iterator param_it = mParamStack.begin();
 +        param_it != mParamStack.end();
 +        ++param_it)
 +    {
 +        LL_INFOS() << param_count++ <<
 +            " rot_limit: " << (*param_it)->getBehindnessAngle() <<
 +            " rot_lag: " << (*param_it)->getBehindnessLag() <<
 +            " distance: " << (*param_it)->getDistance() <<
 +            " focus: " << (*param_it)->getFocus() <<
 +            " foc_lag: " << (*param_it)->getFocusLag() <<
 +            " foc_lock: " << ((*param_it)->getFocusLocked() ? "Y" : "N") <<
 +            " foc_offset: " << (*param_it)->getFocusOffset() <<
 +            " foc_thresh: " << (*param_it)->getFocusThreshold() <<
 +            " pitch: " << (*param_it)->getPitch() <<
 +            " pos: " << (*param_it)->getPosition() <<
 +            " pos_lag: " << (*param_it)->getPositionLag() <<
 +            " pos_lock: " << ((*param_it)->getPositionLocked() ? "Y" : "N") <<
 +            " pos_thresh: " << (*param_it)->getPositionThreshold() << LL_ENDL;
 +    }
 +}
 +
  | 
