summaryrefslogtreecommitdiff
path: root/indra/newview/llfollowcam.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llfollowcam.cpp')
-rw-r--r--indra/newview/llfollowcam.cpp1756
1 files changed, 878 insertions, 878 deletions
diff --git a/indra/newview/llfollowcam.cpp b/indra/newview/llfollowcam.cpp
index 8ce6dc6ef4..89f77414a1 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;
+ }
+}
+