PageRenderTime 160ms CodeModel.GetById 40ms app.highlight 93ms RepoModel.GetById 17ms app.codeStats 1ms

/indra/newview/llfollowcam.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 901 lines | 578 code | 125 blank | 198 comment | 52 complexity | ea9ba0c768ec279fbee200909c827cbc MD5 | raw file
  1/** 
  2 * @file llfollowcam.cpp
  3 * @author Jeffrey Ventrella
  4 * @brief LLFollowCam class implementation
  5 *
  6 * $LicenseInfo:firstyear=2005&license=viewerlgpl$
  7 * Second Life Viewer Source Code
  8 * Copyright (C) 2010, Linden Research, Inc.
  9 * 
 10 * This library is free software; you can redistribute it and/or
 11 * modify it under the terms of the GNU Lesser General Public
 12 * License as published by the Free Software Foundation;
 13 * version 2.1 of the License only.
 14 * 
 15 * This library is distributed in the hope that it will be useful,
 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 18 * Lesser General Public License for more details.
 19 * 
 20 * You should have received a copy of the GNU Lesser General Public
 21 * License along with this library; if not, write to the Free Software
 22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 23 * 
 24 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 25 * $/LicenseInfo$
 26 */
 27
 28#include "llviewerprecompiledheaders.h"
 29#include "llfollowcam.h"
 30#include "llagent.h"
 31
 32//-------------------------------------------------------
 33// class statics
 34//-------------------------------------------------------
 35std::map<LLUUID, LLFollowCamParams*> LLFollowCamMgr::sParamMap;
 36std::vector<LLFollowCamParams*> LLFollowCamMgr::sParamStack;
 37
 38//-------------------------------------------------------
 39// constants
 40//-------------------------------------------------------
 41const F32 ONE_HALF							= 0.5; 
 42const F32 FOLLOW_CAM_ZOOM_FACTOR			= 0.1f;
 43const F32 FOLLOW_CAM_MIN_ZOOM_AMOUNT		= 0.1f;
 44const F32 DISTANCE_EPSILON					= 0.0001f;
 45const F32 DEFAULT_MAX_DISTANCE_FROM_SUBJECT	= 1000.0;	// this will be correctly set on me by my caller
 46
 47//----------------------------------------------------------------------------------------
 48// This is how slowly the camera position moves to its ideal position 
 49//----------------------------------------------------------------------------------------
 50const F32 FOLLOW_CAM_MIN_POSITION_LAG		= 0.0f;		
 51const F32 FOLLOW_CAM_DEFAULT_POSITION_LAG	= 0.1f;  
 52const F32 FOLLOW_CAM_MAX_POSITION_LAG		= 3.0f;
 53
 54//----------------------------------------------------------------------------------------
 55// This is how slowly the camera focus moves to its subject
 56//----------------------------------------------------------------------------------------
 57const F32 FOLLOW_CAM_MIN_FOCUS_LAG		= 0.0f;
 58const F32 FOLLOW_CAM_DEFAULT_FOCUS_LAG	= 0.1f;
 59const F32 FOLLOW_CAM_MAX_FOCUS_LAG		= 3.0f;
 60
 61//----------------------------------------------------------------------------------------
 62// This is far the position can get from its IDEAL POSITION before it starts getting pulled
 63//----------------------------------------------------------------------------------------
 64const F32 FOLLOW_CAM_MIN_POSITION_THRESHOLD		= 0.0f;
 65const F32 FOLLOW_CAM_DEFAULT_POSITION_THRESHOLD	= 1.0f;
 66const F32 FOLLOW_CAM_MAX_POSITION_THRESHOLD		= 4.0f;
 67
 68//----------------------------------------------------------------------------------------
 69// This is far the focus can get from the subject before it starts getting pulled
 70//----------------------------------------------------------------------------------------
 71const F32 FOLLOW_CAM_MIN_FOCUS_THRESHOLD		= 0.0f;
 72const F32 FOLLOW_CAM_DEFAULT_FOCUS_THRESHOLD	= 1.0f;
 73const F32 FOLLOW_CAM_MAX_FOCUS_THRESHOLD		= 4.0f;
 74
 75//----------------------------------------------------------------------------------------
 76// This is the distance the camera wants to be from the subject
 77//----------------------------------------------------------------------------------------
 78const F32 FOLLOW_CAM_MIN_DISTANCE		= 0.5f;
 79const F32 FOLLOW_CAM_DEFAULT_DISTANCE	= 3.0f;
 80//const F32 FOLLOW_CAM_MAX_DISTANCE		= 10.0f; // from now on I am using mMaxCameraDistantFromSubject
 81
 82//----------------------------------------------------------------------------------------
 83// this is an angluar value
 84// It affects the angle that the camera rises (pitches) in relation 
 85// to the horizontal plane
 86//----------------------------------------------------------------------------------------
 87const F32 FOLLOW_CAM_MIN_PITCH		= -45.0f; 
 88const F32 FOLLOW_CAM_DEFAULT_PITCH	=   0.0f;
 89const F32 FOLLOW_CAM_MAX_PITCH		=  80.0f;	// keep under 90 degrees - avoid gimble lock!
 90
 91
 92//----------------------------------------------------------------------------------------
 93// how high or low the camera considers its ideal focus to be (relative to its subject)
 94//----------------------------------------------------------------------------------------
 95const F32 FOLLOW_CAM_MIN_FOCUS_OFFSET		= -10.0f;
 96const LLVector3 FOLLOW_CAM_DEFAULT_FOCUS_OFFSET	=  LLVector3(1.0f, 0.f, 0.f);
 97const F32 FOLLOW_CAM_MAX_FOCUS_OFFSET		=  10.0f;
 98
 99//----------------------------------------------------------------------------------------
100// This affects the rate at which the camera adjusts to stay behind the subject
101//----------------------------------------------------------------------------------------
102const F32 FOLLOW_CAM_MIN_BEHINDNESS_LAG		= 0.0f;
103const F32 FOLLOW_CAM_DEFAULT_BEHINDNESS_LAG		= 0.f;
104const F32 FOLLOW_CAM_MAX_BEHINDNESS_LAG		= 3.0f;
105
106//---------------------------------------------------------------------------------------------------------------------
107// in  degrees: This is the size of the pie slice behind the subject matter within which the camera is free to move
108//---------------------------------------------------------------------------------------------------------------------
109const F32 FOLLOW_CAM_MIN_BEHINDNESS_ANGLE		= 0.0f;
110const F32 FOLLOW_CAM_DEFAULT_BEHINDNESS_ANGLE	= 10.0f;
111const F32 FOLLOW_CAM_MAX_BEHINDNESS_ANGLE		= 180.0f;
112const F32 FOLLOW_CAM_BEHINDNESS_EPSILON			= 1.0f;
113
114//------------------------------------
115// Constructor
116//------------------------------------
117LLFollowCamParams::LLFollowCamParams()
118{
119	mMaxCameraDistantFromSubject		= DEFAULT_MAX_DISTANCE_FROM_SUBJECT;
120	mPositionLocked						= false;
121	mFocusLocked						= false;
122	mUsePosition						= false;
123	mUseFocus							= false;
124
125	//------------------------------------------------------
126	// setting the attributes to their defaults
127	//------------------------------------------------------
128	setPositionLag		( FOLLOW_CAM_DEFAULT_POSITION_LAG			);
129	setFocusLag			( FOLLOW_CAM_DEFAULT_FOCUS_LAG				);
130	setPositionThreshold( FOLLOW_CAM_DEFAULT_POSITION_THRESHOLD		);
131	setFocusThreshold	( FOLLOW_CAM_DEFAULT_FOCUS_THRESHOLD		);
132	setBehindnessLag	( FOLLOW_CAM_DEFAULT_BEHINDNESS_LAG		);
133	setDistance			( FOLLOW_CAM_DEFAULT_DISTANCE				);
134	setPitch			( FOLLOW_CAM_DEFAULT_PITCH					);
135	setFocusOffset		( FOLLOW_CAM_DEFAULT_FOCUS_OFFSET	);
136	setBehindnessAngle	( FOLLOW_CAM_DEFAULT_BEHINDNESS_ANGLE		);
137	setPositionThreshold( FOLLOW_CAM_DEFAULT_POSITION_THRESHOLD		);
138	setFocusThreshold	( FOLLOW_CAM_DEFAULT_FOCUS_THRESHOLD		);
139
140}
141
142LLFollowCamParams::~LLFollowCamParams() { }
143
144//---------------------------------------------------------
145// buncho set methods
146//---------------------------------------------------------
147
148//---------------------------------------------------------
149void LLFollowCamParams::setPositionLag( F32 p ) 
150{ 
151	mPositionLag = llclamp(p, FOLLOW_CAM_MIN_POSITION_LAG, FOLLOW_CAM_MAX_POSITION_LAG); 
152}
153
154
155//---------------------------------------------------------
156void LLFollowCamParams::setFocusLag( F32 f ) 
157{ 
158	mFocusLag = llclamp(f, FOLLOW_CAM_MIN_FOCUS_LAG, FOLLOW_CAM_MAX_FOCUS_LAG); 
159}
160
161
162//---------------------------------------------------------
163void LLFollowCamParams::setPositionThreshold( F32 p ) 
164{ 
165	mPositionThreshold = llclamp(p, FOLLOW_CAM_MIN_POSITION_THRESHOLD, FOLLOW_CAM_MAX_POSITION_THRESHOLD); 
166}
167
168
169//---------------------------------------------------------
170void LLFollowCamParams::setFocusThreshold( F32 f ) 
171{ 
172	mFocusThreshold = llclamp(f, FOLLOW_CAM_MIN_FOCUS_THRESHOLD, FOLLOW_CAM_MAX_FOCUS_THRESHOLD); 
173}
174
175
176//---------------------------------------------------------
177void LLFollowCamParams::setPitch( F32 p ) 
178{ 
179	mPitch = llclamp(p, FOLLOW_CAM_MIN_PITCH, FOLLOW_CAM_MAX_PITCH); 
180}
181
182
183//---------------------------------------------------------
184void LLFollowCamParams::setBehindnessLag( F32 b ) 
185{ 
186	mBehindnessLag = llclamp(b, FOLLOW_CAM_MIN_BEHINDNESS_LAG, FOLLOW_CAM_MAX_BEHINDNESS_LAG); 
187}
188
189//---------------------------------------------------------
190void LLFollowCamParams::setBehindnessAngle( F32 b ) 
191{ 
192	mBehindnessMaxAngle = llclamp(b, FOLLOW_CAM_MIN_BEHINDNESS_ANGLE, FOLLOW_CAM_MAX_BEHINDNESS_ANGLE); 
193}
194
195//---------------------------------------------------------
196void LLFollowCamParams::setDistance( F32 d ) 
197{ 
198	mDistance = llclamp(d, FOLLOW_CAM_MIN_DISTANCE, mMaxCameraDistantFromSubject); 
199}
200
201//---------------------------------------------------------
202void LLFollowCamParams::setPositionLocked( bool l ) 
203{
204	mPositionLocked = l;
205}
206
207//---------------------------------------------------------
208void LLFollowCamParams::setFocusLocked( bool l ) 
209{
210	mFocusLocked = l;
211
212}
213
214//---------------------------------------------------------
215void LLFollowCamParams::setFocusOffset( const LLVector3& v ) 
216{ 
217	mFocusOffset = v; 
218	mFocusOffset.clamp(FOLLOW_CAM_MIN_FOCUS_OFFSET, FOLLOW_CAM_MAX_FOCUS_OFFSET);
219}
220
221//---------------------------------------------------------
222void LLFollowCamParams::setPosition( const LLVector3& p ) 
223{ 
224	mUsePosition = true;
225	mPosition = p;
226}
227
228//---------------------------------------------------------
229void LLFollowCamParams::setFocus( const LLVector3& f ) 
230{ 
231	mUseFocus = true;
232	mFocus = f;
233}
234
235//---------------------------------------------------------
236// buncho get methods
237//---------------------------------------------------------
238F32			LLFollowCamParams::getPositionLag		() const { return mPositionLag;			}
239F32			LLFollowCamParams::getFocusLag			() const { return mFocusLag;			}
240F32			LLFollowCamParams::getPositionThreshold	() const { return mPositionThreshold;	}
241F32			LLFollowCamParams::getFocusThreshold	() const { return mFocusThreshold;		}
242F32			LLFollowCamParams::getDistance			() const { return mDistance;			}
243F32			LLFollowCamParams::getPitch				() const { return mPitch;				}
244LLVector3	LLFollowCamParams::getFocusOffset		() const { return mFocusOffset;			}
245F32			LLFollowCamParams::getBehindnessAngle	() const { return mBehindnessMaxAngle;	}
246F32			LLFollowCamParams::getBehindnessLag		() const { return mBehindnessLag;		}
247LLVector3	LLFollowCamParams::getPosition			() const { return mPosition;			}
248LLVector3	LLFollowCamParams::getFocus				() const { return mFocus;				}
249bool		LLFollowCamParams::getPositionLocked	() const { return mPositionLocked;		}
250bool		LLFollowCamParams::getFocusLocked		() const { return mFocusLocked;			}
251
252//------------------------------------
253// Constructor
254//------------------------------------
255LLFollowCam::LLFollowCam() : LLFollowCamParams()
256{
257	mUpVector							= LLVector3::z_axis;
258	mSubjectPosition					= LLVector3::zero;
259	mSubjectRotation					= LLQuaternion::DEFAULT;
260
261	mZoomedToMinimumDistance			= false;
262	mPitchCos = mPitchSin = 0.f;
263	mPitchSineAndCosineNeedToBeUpdated	= true; 
264
265	mSimulatedDistance = mDistance;
266}
267
268void LLFollowCam::copyParams(LLFollowCamParams& params)
269{
270	setPositionLag(params.getPositionLag());
271	setFocusLag(params.getFocusLag());
272	setFocusThreshold( params.getFocusThreshold());
273	setPositionThreshold(params.getPositionThreshold());
274	setPitch(params.getPitch());
275	setFocusOffset(params.getFocusOffset());
276	setBehindnessAngle(params.getBehindnessAngle());
277	setBehindnessLag(params.getBehindnessLag());
278
279	setPositionLocked(params.getPositionLocked());
280	setFocusLocked(params.getFocusLocked());
281
282	setDistance(params.getDistance());	
283	if (params.getUsePosition())
284	{
285		setPosition(params.getPosition());
286	}
287	if (params.getUseFocus())
288	{
289		setFocus(params.getFocus());
290	}
291}
292
293//---------------------------------------------------------------------------------------------------------
294void LLFollowCam::update()
295{
296	//####################################################################################
297	// update Focus
298	//####################################################################################
299	LLVector3 offsetSubjectPosition = mSubjectPosition + (mFocusOffset * mSubjectRotation);
300
301	LLVector3 simulated_pos_agent = gAgent.getPosAgentFromGlobal(mSimulatedPositionGlobal);
302	LLVector3 vectorFromCameraToSubject = offsetSubjectPosition - simulated_pos_agent;
303	F32 distanceFromCameraToSubject = vectorFromCameraToSubject.magVec();
304
305	LLVector3 whereFocusWantsToBe = mFocus;
306	LLVector3 focus_pt_agent = gAgent.getPosAgentFromGlobal(mSimulatedFocusGlobal);
307	if ( mFocusLocked ) // if focus is locked, only relative focus needs to be updated
308	{
309		mRelativeFocus = (focus_pt_agent - mSubjectPosition) * ~mSubjectRotation;
310	}
311	else
312	{
313		LLVector3 focusOffset = offsetSubjectPosition - focus_pt_agent;
314		F32 focusOffsetDistance = focusOffset.magVec();
315
316		LLVector3 focusOffsetDirection = focusOffset / focusOffsetDistance;
317		whereFocusWantsToBe = focus_pt_agent + 
318			(focusOffsetDirection * (focusOffsetDistance - mFocusThreshold));
319		if ( focusOffsetDistance > mFocusThreshold )
320		{
321			// this version normalizes focus threshold by distance 
322			// so that the effect is not changed with distance
323			/*
324			F32 focusThresholdNormalizedByDistance = distanceFromCameraToSubject * mFocusThreshold;
325			if ( focusOffsetDistance > focusThresholdNormalizedByDistance )
326			{
327				LLVector3 focusOffsetDirection = focusOffset / focusOffsetDistance;
328				F32 force = focusOffsetDistance - focusThresholdNormalizedByDistance;
329			*/
330
331			F32 focusLagLerp = LLCriticalDamp::getInterpolant( mFocusLag );
332			focus_pt_agent = lerp( focus_pt_agent, whereFocusWantsToBe, focusLagLerp );
333			mSimulatedFocusGlobal = gAgent.getPosGlobalFromAgent(focus_pt_agent);
334		}
335		mRelativeFocus = lerp(mRelativeFocus, (focus_pt_agent - mSubjectPosition) * ~mSubjectRotation, LLCriticalDamp::getInterpolant(0.05f));
336	}// if focus is not locked ---------------------------------------------
337
338
339	LLVector3 whereCameraPositionWantsToBe = gAgent.getPosAgentFromGlobal(mSimulatedPositionGlobal);
340	if (  mPositionLocked )
341	{
342		mRelativePos = (whereCameraPositionWantsToBe - mSubjectPosition) * ~mSubjectRotation;
343	}
344	else
345	{
346		//####################################################################################
347		// update Position
348		//####################################################################################
349		//-------------------------------------------------------------------------
350		// I determine the horizontal vector from the camera to the subject
351		//-------------------------------------------------------------------------
352		LLVector3 horizontalVectorFromCameraToSubject = vectorFromCameraToSubject;
353		horizontalVectorFromCameraToSubject.mV[VZ] = 0.0f;
354
355		//---------------------------------------------------------
356		// Now I determine the horizontal distance
357		//---------------------------------------------------------
358		F32 horizontalDistanceFromCameraToSubject = horizontalVectorFromCameraToSubject.magVec();  
359
360		//---------------------------------------------------------
361		// Then I get the (normalized) horizontal direction...
362		//---------------------------------------------------------
363		LLVector3 horizontalDirectionFromCameraToSubject;	
364		if ( horizontalDistanceFromCameraToSubject < DISTANCE_EPSILON )
365		{
366			// make sure we still have a normalized vector if distance is really small 
367			// (this case is rare and fleeting)
368			horizontalDirectionFromCameraToSubject = LLVector3::z_axis;
369		}
370		else
371		{
372			// I'm not using the "normalize" method, because I can just divide by horizontalDistanceFromCameraToSubject
373			horizontalDirectionFromCameraToSubject = horizontalVectorFromCameraToSubject / horizontalDistanceFromCameraToSubject;
374		}
375
376		//------------------------------------------------------------------------------------------------------------
377		// Here is where I determine an offset relative to subject position in oder to set the ideal position. 
378		//------------------------------------------------------------------------------------------------------------
379		if ( mPitchSineAndCosineNeedToBeUpdated )
380		{
381			calculatePitchSineAndCosine();
382			mPitchSineAndCosineNeedToBeUpdated = false;
383		}
384
385		LLVector3 positionOffsetFromSubject;
386		positionOffsetFromSubject.setVec
387			( 
388				horizontalDirectionFromCameraToSubject.mV[ VX ] * mPitchCos,
389				horizontalDirectionFromCameraToSubject.mV[ VY ] * mPitchCos,
390				-mPitchSin
391			);
392
393		positionOffsetFromSubject *= mSimulatedDistance;
394
395		//----------------------------------------------------------------------
396		// Finally, ideal position is set by taking the subject position and 
397		// extending the positionOffsetFromSubject from that
398		//----------------------------------------------------------------------
399		LLVector3 idealCameraPosition = offsetSubjectPosition - positionOffsetFromSubject;
400
401		//--------------------------------------------------------------------------------
402		// Now I prepare to move the current camera position towards its ideal position...
403		//--------------------------------------------------------------------------------
404		LLVector3 vectorFromPositionToIdealPosition = idealCameraPosition - simulated_pos_agent;
405		F32 distanceFromPositionToIdealPosition = vectorFromPositionToIdealPosition.magVec();
406		
407		//put this inside of the block?		
408		LLVector3 normalFromPositionToIdealPosition = vectorFromPositionToIdealPosition / distanceFromPositionToIdealPosition;
409		
410		whereCameraPositionWantsToBe = simulated_pos_agent + 
411			(normalFromPositionToIdealPosition * (distanceFromPositionToIdealPosition - mPositionThreshold));
412		//-------------------------------------------------------------------------------------------------
413		// The following method takes the target camera position and resets it so that it stays "behind" the subject, 
414		// using behindness angle and behindness force as parameters affecting the exact behavior
415		//-------------------------------------------------------------------------------------------------
416		if ( distanceFromPositionToIdealPosition > mPositionThreshold )
417		{
418			F32 positionPullLerp = LLCriticalDamp::getInterpolant( mPositionLag );
419			simulated_pos_agent = lerp( simulated_pos_agent, whereCameraPositionWantsToBe, positionPullLerp );
420		}
421
422		//--------------------------------------------------------------------
423		// don't let the camera get farther than its official max distance
424		//--------------------------------------------------------------------
425		if ( distanceFromCameraToSubject > mMaxCameraDistantFromSubject )
426		{
427			LLVector3 directionFromCameraToSubject = vectorFromCameraToSubject / distanceFromCameraToSubject;
428			simulated_pos_agent = offsetSubjectPosition - directionFromCameraToSubject * mMaxCameraDistantFromSubject;
429		}
430
431		////-------------------------------------------------------------------------------------------------
432		//// The following method takes mSimulatedPositionGlobal and resets it so that it stays "behind" the subject, 
433		//// using behindness angle and behindness force as parameters affecting the exact behavior
434		////-------------------------------------------------------------------------------------------------
435		updateBehindnessConstraint(gAgent.getPosAgentFromGlobal(mSimulatedFocusGlobal), simulated_pos_agent);
436		mSimulatedPositionGlobal = gAgent.getPosGlobalFromAgent(simulated_pos_agent);
437
438		mRelativePos = lerp(mRelativePos, (simulated_pos_agent - mSubjectPosition) * ~mSubjectRotation, LLCriticalDamp::getInterpolant(0.05f));
439	} // if position is not locked -----------------------------------------------------------
440
441
442	//####################################################################################
443	// update UpVector
444	//####################################################################################
445	// this just points upward for now, but I anticipate future effects requiring 
446	// some rolling ("banking" effects for fun, swoopy vehicles, etc.)
447	mUpVector = LLVector3::z_axis;
448}
449
450
451
452//-------------------------------------------------------------------------------------
453BOOL LLFollowCam::updateBehindnessConstraint(LLVector3 focus, LLVector3& cam_position)
454{
455	BOOL constraint_active = FALSE;
456	// only apply this stuff if the behindness angle is something other than opened up all the way
457	if ( mBehindnessMaxAngle < FOLLOW_CAM_MAX_BEHINDNESS_ANGLE - FOLLOW_CAM_BEHINDNESS_EPSILON )
458	{
459		//--------------------------------------------------------------
460		// horizontalized vector from focus to camera 
461		//--------------------------------------------------------------
462		LLVector3 horizontalVectorFromFocusToCamera;
463		horizontalVectorFromFocusToCamera.setVec(cam_position - focus);
464		horizontalVectorFromFocusToCamera.mV[ VZ ] = 0.0f; 
465		F32 cameraZ = cam_position.mV[ VZ ];
466
467		//--------------------------------------------------------------
468		// distance of horizontalized vector
469		//--------------------------------------------------------------
470		F32 horizontalDistance = horizontalVectorFromFocusToCamera.magVec();
471
472		//--------------------------------------------------------------------------------------------------
473		// calculate horizontalized back vector of the subject and scale by horizontalDistance
474		//--------------------------------------------------------------------------------------------------
475		LLVector3 horizontalSubjectBack( -1.0f, 0.0f, 0.0f );
476		horizontalSubjectBack *= mSubjectRotation;
477		horizontalSubjectBack.mV[ VZ ] = 0.0f; 
478		horizontalSubjectBack.normVec(); // because horizontalizing might make it shorter than 1
479		horizontalSubjectBack *= horizontalDistance;
480
481		//--------------------------------------------------------------------------------------------------
482		// find the angle (in degrees) between these vectors
483		//--------------------------------------------------------------------------------------------------
484		F32 cameraOffsetAngle = 0.f;
485		LLVector3 cameraOffsetRotationAxis;
486		LLQuaternion camera_offset_rotation;
487		camera_offset_rotation.shortestArc(horizontalSubjectBack, horizontalVectorFromFocusToCamera);
488		camera_offset_rotation.getAngleAxis(&cameraOffsetAngle, cameraOffsetRotationAxis);
489		cameraOffsetAngle *= RAD_TO_DEG;
490
491		if ( cameraOffsetAngle > mBehindnessMaxAngle )
492		{
493			F32 fraction = ((cameraOffsetAngle - mBehindnessMaxAngle) / cameraOffsetAngle) * LLCriticalDamp::getInterpolant(mBehindnessLag);
494			cam_position = focus + horizontalSubjectBack * (slerp(fraction, camera_offset_rotation, LLQuaternion::DEFAULT));
495			cam_position.mV[VZ] = cameraZ; // clamp z value back to what it was before we started messing with it
496			constraint_active = TRUE;
497		}
498	}
499	return constraint_active;
500}
501
502
503//---------------------------------------------------------
504void LLFollowCam::calculatePitchSineAndCosine()
505{
506	F32 radian = mPitch * DEG_TO_RAD;
507	mPitchCos = cos( radian );
508	mPitchSin = sin( radian );
509}
510
511//---------------------------------------------------------
512void LLFollowCam::setSubjectPositionAndRotation( const LLVector3 p, const LLQuaternion r )
513{
514	mSubjectPosition = p;
515	mSubjectRotation = r;
516}
517
518
519//---------------------------------------------------------
520void LLFollowCam::zoom( S32 z ) 
521{ 
522	F32 zoomAmount = z * mSimulatedDistance * FOLLOW_CAM_ZOOM_FACTOR;
523
524	if (( zoomAmount <  FOLLOW_CAM_MIN_ZOOM_AMOUNT )
525	&&  ( zoomAmount > -FOLLOW_CAM_MIN_ZOOM_AMOUNT ))
526	{
527		if ( zoomAmount < 0.0f )
528		{
529			zoomAmount = -FOLLOW_CAM_MIN_ZOOM_AMOUNT;
530		}
531		else
532		{
533			zoomAmount = FOLLOW_CAM_MIN_ZOOM_AMOUNT;
534		}
535	}
536
537	mSimulatedDistance += zoomAmount;
538
539	mZoomedToMinimumDistance = false;
540	if ( mSimulatedDistance < FOLLOW_CAM_MIN_DISTANCE ) 
541	{
542		mSimulatedDistance = FOLLOW_CAM_MIN_DISTANCE;
543
544		// if zoomAmount is negative (i.e., getting closer), then
545		// this signifies having hit the minimum:
546		if ( zoomAmount < 0.0f )
547		{
548			mZoomedToMinimumDistance = true;
549		}
550	}
551	else if ( mSimulatedDistance > mMaxCameraDistantFromSubject ) 
552	{
553		mSimulatedDistance = mMaxCameraDistantFromSubject;
554	}
555}
556
557
558//---------------------------------------------------------
559bool LLFollowCam::isZoomedToMinimumDistance()
560{
561	return mZoomedToMinimumDistance;
562}
563
564
565//---------------------------------------------------------
566void LLFollowCam::reset( const LLVector3 p, const LLVector3 f , const LLVector3 u )
567{
568	setPosition(p);
569	setFocus(f);
570	mUpVector	= u;
571}
572
573//---------------------------------------------------------
574void LLFollowCam::setMaxCameraDistantFromSubject( F32 m )
575{
576	mMaxCameraDistantFromSubject = m;
577}
578
579
580void LLFollowCam::setPitch( F32 p ) 
581{ 
582	LLFollowCamParams::setPitch(p);
583	mPitchSineAndCosineNeedToBeUpdated = true; // important
584}
585
586void LLFollowCam::setDistance( F32 d ) 
587{ 
588	if (d != mDistance)
589	{
590		LLFollowCamParams::setDistance(d);
591		mSimulatedDistance = d;
592		mZoomedToMinimumDistance = false; 
593	}
594}
595
596void LLFollowCam::setPosition( const LLVector3& p ) 
597{ 
598	if (p != mPosition)
599	{
600		LLFollowCamParams::setPosition(p);
601		mSimulatedPositionGlobal = gAgent.getPosGlobalFromAgent(mPosition);
602		if (mPositionLocked)
603		{
604			mRelativePos = (mPosition - mSubjectPosition) * ~mSubjectRotation;
605		}
606	}
607}
608
609void LLFollowCam::setFocus( const LLVector3& f ) 
610{ 
611	if (f != mFocus)
612	{
613		LLFollowCamParams::setFocus(f);
614		mSimulatedFocusGlobal = gAgent.getPosGlobalFromAgent(f);
615		if (mFocusLocked)
616		{
617			mRelativeFocus = (mFocus - mSubjectPosition) * ~mSubjectRotation;
618		}
619	}
620}
621
622void LLFollowCam::setPositionLocked( bool locked )
623{
624	LLFollowCamParams::setPositionLocked(locked);
625	if (locked)
626	{
627		// propagate set position to relative position
628		mRelativePos = (gAgent.getPosAgentFromGlobal(mSimulatedPositionGlobal) - mSubjectPosition) * ~mSubjectRotation;
629	}
630}
631
632void LLFollowCam::setFocusLocked( bool locked )
633{
634	LLFollowCamParams::setFocusLocked(locked);
635	if (locked)	
636	{
637		// propagate set position to relative position
638		mRelativeFocus = (gAgent.getPosAgentFromGlobal(mSimulatedFocusGlobal) - mSubjectPosition) * ~mSubjectRotation;
639	}
640}
641
642
643LLVector3	LLFollowCam::getSimulatedPosition() const 
644{ 
645	// return simulated position
646	return mSubjectPosition + (mRelativePos * mSubjectRotation);
647}
648
649LLVector3	LLFollowCam::getSimulatedFocus() const 
650{ 
651	// return simulated focus point
652	return mSubjectPosition + (mRelativeFocus * mSubjectRotation);
653}
654
655LLVector3	LLFollowCam::getUpVector() 
656{ 
657	return mUpVector;			
658}
659
660
661//------------------------------------
662// Destructor
663//------------------------------------
664LLFollowCam::~LLFollowCam()
665{
666}
667
668
669//-------------------------------------------------------
670// LLFollowCamMgr
671//-------------------------------------------------------
672//static
673void LLFollowCamMgr::cleanupClass()
674{
675	for (param_map_t::iterator iter = sParamMap.begin(); iter != sParamMap.end(); ++iter)
676	{
677		LLFollowCamParams* params = iter->second;
678		delete params;
679	}
680	sParamMap.clear();
681}
682
683//static
684void LLFollowCamMgr::setPositionLag( const LLUUID& source, F32 lag)
685{
686	LLFollowCamParams* paramsp = getParamsForID(source);
687	if (paramsp)
688	{
689		paramsp->setPositionLag(lag);
690	}
691}
692
693//static
694void LLFollowCamMgr::setFocusLag( const LLUUID& source, F32 lag)
695{
696	LLFollowCamParams* paramsp = getParamsForID(source);
697	if (paramsp)
698	{
699		paramsp->setFocusLag(lag);
700	}
701}
702
703//static
704void LLFollowCamMgr::setFocusThreshold( const LLUUID& source, F32 threshold)
705{
706	LLFollowCamParams* paramsp = getParamsForID(source);
707	if (paramsp)
708	{
709		paramsp->setFocusThreshold(threshold);
710	}
711
712}
713
714//static
715void LLFollowCamMgr::setPositionThreshold( const LLUUID& source, F32 threshold)
716{
717	LLFollowCamParams* paramsp = getParamsForID(source);
718	if (paramsp)
719	{
720		paramsp->setPositionThreshold(threshold);
721	}
722}
723
724//static
725void LLFollowCamMgr::setDistance( const LLUUID& source, F32 distance)
726{
727	LLFollowCamParams* paramsp = getParamsForID(source);
728	if (paramsp)
729	{
730		paramsp->setDistance(distance);
731	}
732}
733
734//static
735void LLFollowCamMgr::setPitch( const LLUUID& source, F32 pitch)
736{
737	LLFollowCamParams* paramsp = getParamsForID(source);
738	if (paramsp)
739	{
740		paramsp->setPitch(pitch);
741	}
742}
743
744//static
745void LLFollowCamMgr::setFocusOffset( const LLUUID& source, const LLVector3& offset)
746{
747	LLFollowCamParams* paramsp = getParamsForID(source);
748	if (paramsp)
749	{
750		paramsp->setFocusOffset(offset);
751	}
752}
753
754//static
755void LLFollowCamMgr::setBehindnessAngle( const LLUUID& source, F32 angle)
756{
757	LLFollowCamParams* paramsp = getParamsForID(source);
758	if (paramsp)
759	{
760		paramsp->setBehindnessAngle(angle);
761	}
762}
763
764//static
765void LLFollowCamMgr::setBehindnessLag( const LLUUID& source, F32 force)
766{
767	LLFollowCamParams* paramsp = getParamsForID(source);
768	if (paramsp)
769	{
770		paramsp->setBehindnessLag(force);
771	}
772}
773
774//static
775void LLFollowCamMgr::setPosition( const LLUUID& source, const LLVector3 position)
776{
777	LLFollowCamParams* paramsp = getParamsForID(source);
778	if (paramsp)
779	{
780		paramsp->setPosition(position);
781	}
782}
783
784//static
785void LLFollowCamMgr::setFocus( const LLUUID& source, const LLVector3 focus)
786{
787	LLFollowCamParams* paramsp = getParamsForID(source);
788	if (paramsp)
789	{
790		paramsp->setFocus(focus);
791	}
792}
793
794//static
795void LLFollowCamMgr::setPositionLocked( const LLUUID& source, bool locked)
796{
797	LLFollowCamParams* paramsp = getParamsForID(source);
798	if (paramsp)
799	{
800		paramsp->setPositionLocked(locked);
801	}
802}
803
804//static
805void LLFollowCamMgr::setFocusLocked( const LLUUID& source, bool locked )
806{
807	LLFollowCamParams* paramsp = getParamsForID(source);
808	if (paramsp)
809	{
810		paramsp->setFocusLocked(locked);
811	}
812}
813
814//static 
815LLFollowCamParams* LLFollowCamMgr::getParamsForID(const LLUUID& source)
816{
817	LLFollowCamParams* params = NULL;
818
819	param_map_t::iterator found_it = sParamMap.find(source);
820	if (found_it == sParamMap.end()) // didn't find it?
821	{
822		params = new LLFollowCamParams();
823		sParamMap[source] = params;
824	}
825	else
826	{
827		params = found_it->second;
828	}
829
830	return params;
831}
832
833//static
834LLFollowCamParams* LLFollowCamMgr::getActiveFollowCamParams()
835{
836	if (sParamStack.empty())
837	{
838		return NULL;
839	}
840
841	return sParamStack.back();
842}
843
844//static 
845void LLFollowCamMgr::setCameraActive( const LLUUID& source, bool active )
846{
847	LLFollowCamParams* params = getParamsForID(source);
848	param_stack_t::iterator found_it = std::find(sParamStack.begin(), sParamStack.end(), params);
849	if (found_it != sParamStack.end())
850	{
851		sParamStack.erase(found_it);
852	}
853	// put on top of stack
854	if(active)
855	{
856		sParamStack.push_back(params);
857	}
858}
859
860//static
861void LLFollowCamMgr::removeFollowCamParams(const LLUUID& source)
862{
863	setCameraActive(source, FALSE);
864	LLFollowCamParams* params = getParamsForID(source);
865	sParamMap.erase(source);
866	delete params;
867}
868
869//static
870bool LLFollowCamMgr::isScriptedCameraSource(const LLUUID& source)
871{
872	param_map_t::iterator found_it = sParamMap.find(source);
873	return (found_it != sParamMap.end());
874}
875
876//static 
877void LLFollowCamMgr::dump()
878{
879	S32 param_count = 0;
880	llinfos << "Scripted camera active stack" << llendl;
881	for (param_stack_t::iterator param_it = sParamStack.begin();
882		param_it != sParamStack.end();
883		++param_it)
884	{
885		llinfos << param_count++ << 
886			" rot_limit: " << (*param_it)->getBehindnessAngle() << 
887			" rot_lag: " << (*param_it)->getBehindnessLag() << 
888			" distance: " << (*param_it)->getDistance() << 
889			" focus: " << (*param_it)->getFocus() << 
890			" foc_lag: " << (*param_it)->getFocusLag() << 
891			" foc_lock: " << ((*param_it)->getFocusLocked() ? "Y" : "N") << 
892			" foc_offset: " << (*param_it)->getFocusOffset() << 
893			" foc_thresh: " << (*param_it)->getFocusThreshold() << 
894			" pitch: " << (*param_it)->getPitch() << 
895			" pos: " << (*param_it)->getPosition() << 
896			" pos_lag: " << (*param_it)->getPositionLag() << 
897			" pos_lock: " << ((*param_it)->getPositionLocked() ? "Y" : "N") << 
898			" pos_thresh: " << (*param_it)->getPositionThreshold() << llendl;
899	}
900}
901