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.cpp882
1 files changed, 882 insertions, 0 deletions
diff --git a/indra/newview/llfollowcam.cpp b/indra/newview/llfollowcam.cpp
new file mode 100644
index 0000000000..6f1addcebb
--- /dev/null
+++ b/indra/newview/llfollowcam.cpp
@@ -0,0 +1,882 @@
+/**
+ * @file llfollowcam.cpp
+ * @author Jeffrey Ventrella
+ * @brief LLFollowCam class implementation
+ *
+ * Copyright (c) 2005-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#include "llviewerprecompiledheaders.h"
+#include "llfollowcam.h"
+#include "llagent.h"
+
+//-------------------------------------------------------
+// class statics
+//-------------------------------------------------------
+std::map<LLUUID, LLFollowCamParams*> LLFollowCamMgr::sParamMap;
+std::vector<LLFollowCamParams*> LLFollowCamMgr::sParamStack;
+
+//-------------------------------------------------------
+// constants
+//-------------------------------------------------------
+const F32 ONE_HALF = 0.5;
+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;
+ 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 = LLCriticalDamp::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, LLCriticalDamp::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 = LLCriticalDamp::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, LLCriticalDamp::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) * LLCriticalDamp::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
+//-------------------------------------------------------
+//static
+void LLFollowCamMgr::cleanupClass()
+{
+ for (param_map_t::iterator iter = sParamMap.begin(); iter != sParamMap.end(); ++iter)
+ {
+ LLFollowCamParams* params = iter->second;
+ delete params;
+ }
+ sParamMap.clear();
+}
+
+//static
+void LLFollowCamMgr::setPositionLag( const LLUUID& source, F32 lag)
+{
+ LLFollowCamParams* paramsp = getParamsForID(source);
+ if (paramsp)
+ {
+ paramsp->setPositionLag(lag);
+ }
+}
+
+//static
+void LLFollowCamMgr::setFocusLag( const LLUUID& source, F32 lag)
+{
+ LLFollowCamParams* paramsp = getParamsForID(source);
+ if (paramsp)
+ {
+ paramsp->setFocusLag(lag);
+ }
+}
+
+//static
+void LLFollowCamMgr::setFocusThreshold( const LLUUID& source, F32 threshold)
+{
+ LLFollowCamParams* paramsp = getParamsForID(source);
+ if (paramsp)
+ {
+ paramsp->setFocusThreshold(threshold);
+ }
+
+}
+
+//static
+void LLFollowCamMgr::setPositionThreshold( const LLUUID& source, F32 threshold)
+{
+ LLFollowCamParams* paramsp = getParamsForID(source);
+ if (paramsp)
+ {
+ paramsp->setPositionThreshold(threshold);
+ }
+}
+
+//static
+void LLFollowCamMgr::setDistance( const LLUUID& source, F32 distance)
+{
+ LLFollowCamParams* paramsp = getParamsForID(source);
+ if (paramsp)
+ {
+ paramsp->setDistance(distance);
+ }
+}
+
+//static
+void LLFollowCamMgr::setPitch( const LLUUID& source, F32 pitch)
+{
+ LLFollowCamParams* paramsp = getParamsForID(source);
+ if (paramsp)
+ {
+ paramsp->setPitch(pitch);
+ }
+}
+
+//static
+void LLFollowCamMgr::setFocusOffset( const LLUUID& source, const LLVector3& offset)
+{
+ LLFollowCamParams* paramsp = getParamsForID(source);
+ if (paramsp)
+ {
+ paramsp->setFocusOffset(offset);
+ }
+}
+
+//static
+void LLFollowCamMgr::setBehindnessAngle( const LLUUID& source, F32 angle)
+{
+ LLFollowCamParams* paramsp = getParamsForID(source);
+ if (paramsp)
+ {
+ paramsp->setBehindnessAngle(angle);
+ }
+}
+
+//static
+void LLFollowCamMgr::setBehindnessLag( const LLUUID& source, F32 force)
+{
+ LLFollowCamParams* paramsp = getParamsForID(source);
+ if (paramsp)
+ {
+ paramsp->setBehindnessLag(force);
+ }
+}
+
+//static
+void LLFollowCamMgr::setPosition( const LLUUID& source, const LLVector3 position)
+{
+ LLFollowCamParams* paramsp = getParamsForID(source);
+ if (paramsp)
+ {
+ paramsp->setPosition(position);
+ }
+}
+
+//static
+void LLFollowCamMgr::setFocus( const LLUUID& source, const LLVector3 focus)
+{
+ LLFollowCamParams* paramsp = getParamsForID(source);
+ if (paramsp)
+ {
+ paramsp->setFocus(focus);
+ }
+}
+
+//static
+void LLFollowCamMgr::setPositionLocked( const LLUUID& source, bool locked)
+{
+ LLFollowCamParams* paramsp = getParamsForID(source);
+ if (paramsp)
+ {
+ paramsp->setPositionLocked(locked);
+ }
+}
+
+//static
+void LLFollowCamMgr::setFocusLocked( const LLUUID& source, bool locked )
+{
+ LLFollowCamParams* paramsp = getParamsForID(source);
+ if (paramsp)
+ {
+ paramsp->setFocusLocked(locked);
+ }
+}
+
+//static
+LLFollowCamParams* LLFollowCamMgr::getParamsForID(const LLUUID& source)
+{
+ LLFollowCamParams* params = NULL;
+
+ param_map_t::iterator found_it = sParamMap.find(source);
+ if (found_it == sParamMap.end()) // didn't find it?
+ {
+ params = new LLFollowCamParams();
+ sParamMap[source] = params;
+ }
+ else
+ {
+ params = found_it->second;
+ }
+
+ return params;
+}
+
+//static
+LLFollowCamParams* LLFollowCamMgr::getActiveFollowCamParams()
+{
+ if (sParamStack.empty())
+ {
+ return NULL;
+ }
+
+ return sParamStack.back();
+}
+
+//static
+void LLFollowCamMgr::setCameraActive( const LLUUID& source, bool active )
+{
+ LLFollowCamParams* params = getParamsForID(source);
+ param_stack_t::iterator found_it = std::find(sParamStack.begin(), sParamStack.end(), params);
+ if (found_it != sParamStack.end())
+ {
+ sParamStack.erase(found_it);
+ }
+ // put on top of stack
+ if(active)
+ {
+ sParamStack.push_back(params);
+ }
+}
+
+//static
+void LLFollowCamMgr::removeFollowCamParams(const LLUUID& source)
+{
+ setCameraActive(source, FALSE);
+ LLFollowCamParams* params = getParamsForID(source);
+ sParamMap.erase(source);
+ delete params;
+}
+
+//static
+bool LLFollowCamMgr::isScriptedCameraSource(const LLUUID& source)
+{
+ param_map_t::iterator found_it = sParamMap.find(source);
+ return (found_it != sParamMap.end());
+}
+
+//static
+void LLFollowCamMgr::dump()
+{
+ S32 param_count = 0;
+ llinfos << "Scripted camera active stack" << llendl;
+ for (param_stack_t::iterator param_it = sParamStack.begin();
+ param_it != sParamStack.end();
+ ++param_it)
+ {
+ llinfos << 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() << llendl;
+ }
+}
+