diff options
| author | Kelly Washington <kelly@lindenlab.com> | 2008-04-03 22:50:22 +0000 | 
|---|---|---|
| committer | Kelly Washington <kelly@lindenlab.com> | 2008-04-03 22:50:22 +0000 | 
| commit | dc48f1c7417f0f49ad1bd32330845ce17a29eece (patch) | |
| tree | 8772aff5f32c1702228b7ca7e324fbd077269854 /indra | |
| parent | b5936a4b1d8780b5b8cd425998eacd2c64ffa693 (diff) | |
svn merge -r83872:83893 linden/branches/Branch_1-20-0-Server to linden/release
HAVOK4 IN TEH HOUSE!!11!!ONE!!
If it is broken blame Joel for not fixing the loginassetdatabaseinventorygroupIM server instead of working on this.
QAR-448
Diffstat (limited to 'indra')
77 files changed, 3130 insertions, 451 deletions
| diff --git a/indra/llcharacter/llstatemachine.h b/indra/llcharacter/llstatemachine.h index c19a926dbb..5ae1668a11 100644 --- a/indra/llcharacter/llstatemachine.h +++ b/indra/llcharacter/llstatemachine.h @@ -54,7 +54,7 @@ class LLFSMTransition : public LLUniqueID  {  public:  	LLFSMTransition() : LLUniqueID(){}; -	virtual std::string getName(){ return "unnamed"; } +	virtual std::string getName()const { return "unnamed"; }  };  class LLFSMState : public LLUniqueID @@ -64,7 +64,7 @@ public:  	virtual void onEntry(void *){};  	virtual void onExit(void *){};  	virtual void execute(void *){}; -	virtual std::string getName(){ return "unnamed"; } +	virtual std::string getName() const { return "unnamed"; }  };  class LLStateDiagram diff --git a/indra/llcommon/indra_constants.h b/indra/llcommon/indra_constants.h index 89b276e3b3..a0b1293639 100644 --- a/indra/llcommon/indra_constants.h +++ b/indra/llcommon/indra_constants.h @@ -38,9 +38,10 @@  // At 45 Hz collisions seem stable and objects seem  // to settle down at a reasonable rate.  // JC 3/18/2003 -const F32 HAVOK_TIMESTEP = 1.f / 45.f; +const F32 PHYSICS_TIMESTEP = 1.f / 45.f;  const F32 COLLISION_TOLERANCE = 0.1f; +const F32 HALF_COLLISION_TOLERANCE = COLLISION_TOLERANCE * 0.5f;  // Time constants  const U32 HOURS_PER_LINDEN_DAY		= 4;	 @@ -53,6 +54,8 @@ const F32 REGION_WIDTH_METERS = 256.f;  const S32 REGION_WIDTH_UNITS = 256;  const U32 REGION_WIDTH_U32 = 256; +const F32 REGION_HEIGHT_METERS = 4096.f; +  // Bits for simulator performance query flags  enum LAND_STAT_FLAGS  { @@ -87,7 +90,7 @@ const 	F32 	MAX_AGENT_HEIGHT		= 2.65f - 2.0f * COLLISION_TOLERANCE;  // For linked sets  const S32 MAX_CHILDREN_PER_TASK = 255; -const S32 MAX_CHILDREN_PER_PHYSICAL_TASK = 31; +const S32 MAX_CHILDREN_PER_PHYSICAL_TASK = 32;  const S32 MAX_JOINTS_PER_OBJECT = 1;	// limiting to 1 until Havok 2.x diff --git a/indra/llcommon/llagentconstants.h b/indra/llcommon/llagentconstants.h index 2989d6d7d4..f630af6530 100644 --- a/indra/llcommon/llagentconstants.h +++ b/indra/llcommon/llagentconstants.h @@ -67,43 +67,43 @@ const U32 CONTROL_ML_LBUTTON_DOWN_INDEX		= 30;  const U32 CONTROL_ML_LBUTTON_UP_INDEX		= 31;  const U32 TOTAL_CONTROLS					= 32; -const U32 AGENT_CONTROL_AT_POS              = 0x1 << CONTROL_AT_POS_INDEX; -const U32 AGENT_CONTROL_AT_NEG              = 0x1 << CONTROL_AT_NEG_INDEX; -const U32 AGENT_CONTROL_LEFT_POS            = 0x1 << CONTROL_LEFT_POS_INDEX; -const U32 AGENT_CONTROL_LEFT_NEG            = 0x1 << CONTROL_LEFT_NEG_INDEX; -const U32 AGENT_CONTROL_UP_POS              = 0x1 << CONTROL_UP_POS_INDEX; -const U32 AGENT_CONTROL_UP_NEG              = 0x1 << CONTROL_UP_NEG_INDEX; -const U32 AGENT_CONTROL_PITCH_POS           = 0x1 << CONTROL_PITCH_POS_INDEX; -const U32 AGENT_CONTROL_PITCH_NEG           = 0x1 << CONTROL_PITCH_NEG_INDEX; -const U32 AGENT_CONTROL_YAW_POS             = 0x1 << CONTROL_YAW_POS_INDEX; -const U32 AGENT_CONTROL_YAW_NEG             = 0x1 << CONTROL_YAW_NEG_INDEX; - -const U32 AGENT_CONTROL_FAST_AT             = 0x1 << CONTROL_FAST_AT_INDEX; -const U32 AGENT_CONTROL_FAST_LEFT           = 0x1 << CONTROL_FAST_LEFT_INDEX; -const U32 AGENT_CONTROL_FAST_UP             = 0x1 << CONTROL_FAST_UP_INDEX; - -const U32 AGENT_CONTROL_FLY					= 0x1 << CONTROL_FLY_INDEX; -const U32 AGENT_CONTROL_STOP				= 0x1 << CONTROL_STOP_INDEX; -const U32 AGENT_CONTROL_FINISH_ANIM			= 0x1 << CONTROL_FINISH_ANIM_INDEX; -const U32 AGENT_CONTROL_STAND_UP			= 0x1 << CONTROL_STAND_UP_INDEX; -const U32 AGENT_CONTROL_SIT_ON_GROUND		= 0x1 << CONTROL_SIT_ON_GROUND_INDEX; -const U32 AGENT_CONTROL_MOUSELOOK			= 0x1 << CONTROL_MOUSELOOK_INDEX; - -const U32 AGENT_CONTROL_NUDGE_AT_POS        = 0x1 << CONTROL_NUDGE_AT_POS_INDEX; -const U32 AGENT_CONTROL_NUDGE_AT_NEG        = 0x1 << CONTROL_NUDGE_AT_NEG_INDEX; -const U32 AGENT_CONTROL_NUDGE_LEFT_POS      = 0x1 << CONTROL_NUDGE_LEFT_POS_INDEX; -const U32 AGENT_CONTROL_NUDGE_LEFT_NEG      = 0x1 << CONTROL_NUDGE_LEFT_NEG_INDEX; -const U32 AGENT_CONTROL_NUDGE_UP_POS        = 0x1 << CONTROL_NUDGE_UP_POS_INDEX; -const U32 AGENT_CONTROL_NUDGE_UP_NEG        = 0x1 << CONTROL_NUDGE_UP_NEG_INDEX; -const U32 AGENT_CONTROL_TURN_LEFT	        = 0x1 << CONTROL_TURN_LEFT_INDEX; -const U32 AGENT_CONTROL_TURN_RIGHT	        = 0x1 << CONTROL_TURN_RIGHT_INDEX; - -const U32 AGENT_CONTROL_AWAY				= 0x1 << CONTROL_AWAY_INDEX; - -const U32 AGENT_CONTROL_LBUTTON_DOWN		= 0x1 << CONTROL_LBUTTON_DOWN_INDEX; -const U32 AGENT_CONTROL_LBUTTON_UP			= 0x1 << CONTROL_LBUTTON_UP_INDEX; -const U32 AGENT_CONTROL_ML_LBUTTON_DOWN		= 0x1 << CONTROL_ML_LBUTTON_DOWN_INDEX; -const U32 AGENT_CONTROL_ML_LBUTTON_UP		= ((U32)0x1) << CONTROL_ML_LBUTTON_UP_INDEX; +const U32 AGENT_CONTROL_AT_POS              = 0x1 << CONTROL_AT_POS_INDEX;			// 0x00000001 +const U32 AGENT_CONTROL_AT_NEG              = 0x1 << CONTROL_AT_NEG_INDEX;			// 0x00000002 +const U32 AGENT_CONTROL_LEFT_POS            = 0x1 << CONTROL_LEFT_POS_INDEX;		// 0x00000004 +const U32 AGENT_CONTROL_LEFT_NEG            = 0x1 << CONTROL_LEFT_NEG_INDEX;		// 0x00000008 +const U32 AGENT_CONTROL_UP_POS              = 0x1 << CONTROL_UP_POS_INDEX;			// 0x00000010 +const U32 AGENT_CONTROL_UP_NEG              = 0x1 << CONTROL_UP_NEG_INDEX;			// 0x00000020 +const U32 AGENT_CONTROL_PITCH_POS           = 0x1 << CONTROL_PITCH_POS_INDEX;		// 0x00000040 +const U32 AGENT_CONTROL_PITCH_NEG           = 0x1 << CONTROL_PITCH_NEG_INDEX;		// 0x00000080 +const U32 AGENT_CONTROL_YAW_POS             = 0x1 << CONTROL_YAW_POS_INDEX;			// 0x00000100 +const U32 AGENT_CONTROL_YAW_NEG             = 0x1 << CONTROL_YAW_NEG_INDEX;			// 0x00000200 + +const U32 AGENT_CONTROL_FAST_AT             = 0x1 << CONTROL_FAST_AT_INDEX;			// 0x00000400 +const U32 AGENT_CONTROL_FAST_LEFT           = 0x1 << CONTROL_FAST_LEFT_INDEX;		// 0x00000800 +const U32 AGENT_CONTROL_FAST_UP             = 0x1 << CONTROL_FAST_UP_INDEX;			// 0x00001000 + +const U32 AGENT_CONTROL_FLY					= 0x1 << CONTROL_FLY_INDEX;				// 0x00002000 +const U32 AGENT_CONTROL_STOP				= 0x1 << CONTROL_STOP_INDEX;			// 0x00004000 +const U32 AGENT_CONTROL_FINISH_ANIM			= 0x1 << CONTROL_FINISH_ANIM_INDEX;		// 0x00008000 +const U32 AGENT_CONTROL_STAND_UP			= 0x1 << CONTROL_STAND_UP_INDEX;		// 0x00010000 +const U32 AGENT_CONTROL_SIT_ON_GROUND		= 0x1 << CONTROL_SIT_ON_GROUND_INDEX;	// 0x00020000 +const U32 AGENT_CONTROL_MOUSELOOK			= 0x1 << CONTROL_MOUSELOOK_INDEX;		// 0x00040000 + +const U32 AGENT_CONTROL_NUDGE_AT_POS        = 0x1 << CONTROL_NUDGE_AT_POS_INDEX;	// 0x00080000 +const U32 AGENT_CONTROL_NUDGE_AT_NEG        = 0x1 << CONTROL_NUDGE_AT_NEG_INDEX;	// 0x00100000 +const U32 AGENT_CONTROL_NUDGE_LEFT_POS      = 0x1 << CONTROL_NUDGE_LEFT_POS_INDEX;	// 0x00200000 +const U32 AGENT_CONTROL_NUDGE_LEFT_NEG      = 0x1 << CONTROL_NUDGE_LEFT_NEG_INDEX;	// 0x00400000 +const U32 AGENT_CONTROL_NUDGE_UP_POS        = 0x1 << CONTROL_NUDGE_UP_POS_INDEX;	// 0x00800000 +const U32 AGENT_CONTROL_NUDGE_UP_NEG        = 0x1 << CONTROL_NUDGE_UP_NEG_INDEX;	// 0x01000000 +const U32 AGENT_CONTROL_TURN_LEFT	        = 0x1 << CONTROL_TURN_LEFT_INDEX;		// 0x02000000 +const U32 AGENT_CONTROL_TURN_RIGHT	        = 0x1 << CONTROL_TURN_RIGHT_INDEX;		// 0x04000000 + +const U32 AGENT_CONTROL_AWAY				= 0x1 << CONTROL_AWAY_INDEX;			// 0x08000000 + +const U32 AGENT_CONTROL_LBUTTON_DOWN		= 0x1 << CONTROL_LBUTTON_DOWN_INDEX;	// 0x10000000 +const U32 AGENT_CONTROL_LBUTTON_UP			= 0x1 << CONTROL_LBUTTON_UP_INDEX;		// 0x20000000 +const U32 AGENT_CONTROL_ML_LBUTTON_DOWN		= 0x1 << CONTROL_ML_LBUTTON_DOWN_INDEX;	// 0x40000000 +const U32 AGENT_CONTROL_ML_LBUTTON_UP		= ((U32)0x1) << CONTROL_ML_LBUTTON_UP_INDEX;	// 0x80000000  const U32 AGENT_CONTROL_AT 		= AGENT_CONTROL_AT_POS   								  | AGENT_CONTROL_AT_NEG  diff --git a/indra/llcommon/llapr.cpp b/indra/llcommon/llapr.cpp index 3512f2fb17..5e6dfd975e 100644 --- a/indra/llcommon/llapr.cpp +++ b/indra/llcommon/llapr.cpp @@ -116,8 +116,10 @@ void LLScopedLock::unlock()  bool ll_apr_warn_status(apr_status_t status)  {  	if(APR_SUCCESS == status) return false; +#ifndef LL_WINDOWS  	char buf[MAX_STRING];	/* Flawfinder: ignore */  	llwarns << "APR: " << apr_strerror(status, buf, MAX_STRING) << llendl; +#endif  	return true;  } diff --git a/indra/llcommon/lldefs.h b/indra/llcommon/lldefs.h index 96b2ab169b..34bde66678 100644 --- a/indra/llcommon/lldefs.h +++ b/indra/llcommon/lldefs.h @@ -218,7 +218,15 @@ inline LLDATATYPE llmin(const LLDATATYPE& d1, const LLDATATYPE& d2, const LLDATA  template <class LLDATATYPE>   inline LLDATATYPE llclamp(const LLDATATYPE& a, const LLDATATYPE& minval, const LLDATATYPE& maxval)  { -	return llmin(llmax(a, minval), maxval); +	if ( a < minval ) +	{ +		return minval; +	} +	else if ( a > maxval ) +	{ +		return maxval; +	} +	return a;  }  template <class LLDATATYPE>  @@ -234,3 +242,4 @@ inline LLDATATYPE llclampb(const LLDATATYPE& a)  }  #endif // LL_LLDEFS_H + diff --git a/indra/llcommon/llframetimer.cpp b/indra/llcommon/llframetimer.cpp index 23d8775824..b74151bc2a 100644 --- a/indra/llcommon/llframetimer.cpp +++ b/indra/llcommon/llframetimer.cpp @@ -140,3 +140,18 @@ F32 LLFrameTimer::getFrameDeltaTimeF32()  {  	return (F32)(U64_to_F64(sFrameDeltaTime) * USEC_TO_SEC_F64);   } + + +//	static  +// Return seconds since the current frame started +F32  LLFrameTimer::getCurrentFrameTime() +{ +	U64 frame_time = totalTime() - sTotalTime; +	return (F32)(U64_to_F64(frame_time) * USEC_TO_SEC_F64);  +} + +// Glue code to avoid full class .h file #includes +F32  getCurrentFrameTime() +{ +	return (F32)(LLFrameTimer::getCurrentFrameTime()); +} diff --git a/indra/llcommon/llframetimer.h b/indra/llcommon/llframetimer.h index 9d55fd1a0b..2998560ab9 100644 --- a/indra/llcommon/llframetimer.h +++ b/indra/llcommon/llframetimer.h @@ -74,6 +74,9 @@ public:  	static F32	getFrameDeltaTimeF32(); +	// Return seconds since the current frame started +	static F32  getCurrentFrameTime(); +  	// MANIPULATORS  	void start();  	void stop(); @@ -144,4 +147,7 @@ protected:  	BOOL mStarted;  }; +// Glue code for Havok (or anything else that doesn't want the full .h files) +extern F32  getCurrentFrameTime(); +  #endif  // LL_LLFRAMETIMER_H diff --git a/indra/llcommon/llpreprocessor.h b/indra/llcommon/llpreprocessor.h index ac06b431c1..454a820ce5 100644 --- a/indra/llcommon/llpreprocessor.h +++ b/indra/llcommon/llpreprocessor.h @@ -79,9 +79,16 @@  #endif +  // Deal with the differeneces on Windows  #if LL_MSVC -#define snprintf safe_snprintf		/* Flawfinder: ignore */ +namespace snprintf_hack +{ +	int snprintf(char *str, size_t size, const char *format, ...); +} + +// #define snprintf safe_snprintf		/* Flawfinder: ignore */ +using snprintf_hack::snprintf;  #endif	// LL_MSVC  // Static linking with apr on windows needs to be declared. diff --git a/indra/llcommon/llptrskiplist.h b/indra/llcommon/llptrskiplist.h index 81c8ca3ef3..b03faf57f1 100644 --- a/indra/llcommon/llptrskiplist.h +++ b/indra/llcommon/llptrskiplist.h @@ -34,6 +34,7 @@  #include "llerror.h"  //#include "vmath.h" +#include "llrand.h"  /////////////////////////////////////////////  // diff --git a/indra/llcommon/llskiplist.h b/indra/llcommon/llskiplist.h index 314043ebac..17e0baddb7 100644 --- a/indra/llcommon/llskiplist.h +++ b/indra/llcommon/llskiplist.h @@ -32,6 +32,7 @@  #define LL_LLSKIPLIST_H  #include "llrand.h" +#include "llrand.h"  // NOTA BENE: Insert first needs to be < NOT <=  // Binary depth must be >= 2 diff --git a/indra/llcommon/llstatenums.h b/indra/llcommon/llstatenums.h index e9876f8061..a82996b852 100644 --- a/indra/llcommon/llstatenums.h +++ b/indra/llcommon/llstatenums.h @@ -57,7 +57,13 @@ enum  	LL_SIM_STAT_VIRTUAL_SIZE_KB,  	LL_SIM_STAT_RESIDENT_SIZE_KB,  	LL_SIM_STAT_PENDING_LOCAL_UPLOADS, -	LL_SIM_STAT_TOTAL_UNACKED_BYTES +	LL_SIM_STAT_TOTAL_UNACKED_BYTES, +	LL_SIM_STAT_PHYSICS_PINNED_TASKS, +	LL_SIM_STAT_PHYSICS_LOD_TASKS, +	LL_SIM_STAT_SIMPHYSICSSTEPMS, +	LL_SIM_STAT_SIMPHYSICSSHAPEMS, +	LL_SIM_STAT_SIMPHYSICSOTHERMS, +	LL_SIM_STAT_SIMPHYSICSMEMORY  };  #endif diff --git a/indra/llcommon/llstl.h b/indra/llcommon/llstl.h index b692daefd8..988e706091 100644 --- a/indra/llcommon/llstl.h +++ b/indra/llcommon/llstl.h @@ -33,6 +33,9 @@  #define LL_LLSTL_H  #include <functional> +#include <algorithm> +#include <map> +#include <vector>  #include <set>  #include <deque> diff --git a/indra/llcommon/llstring.cpp b/indra/llcommon/llstring.cpp index a688bc1c6f..59d71a8e8e 100644 --- a/indra/llcommon/llstring.cpp +++ b/indra/llcommon/llstring.cpp @@ -804,16 +804,19 @@ std::string utf8str_removeCRLF(const std::string& utf8str)  #if LL_WINDOWS  // documentation moved to header. Phoenix 2007-11-27 -int safe_snprintf(char *str, size_t size, const char *format, ...) +namespace snprintf_hack  { -	va_list args; -	va_start(args, format); - -	int num_written = _vsnprintf(str, size, format, args); /* Flawfinder: ignore */ -	va_end(args); -	 -	str[size-1] = '\0'; // always null terminate -	return num_written; +	int snprintf(char *str, size_t size, const char *format, ...) +	{ +		va_list args; +		va_start(args, format); + +		int num_written = _vsnprintf(str, size, format, args); /* Flawfinder: ignore */ +		va_end(args); +		 +		str[size-1] = '\0'; // always null terminate +		return num_written; +	}  }  std::string ll_convert_wide_to_string(const wchar_t* in) diff --git a/indra/llcommon/llversionserver.h b/indra/llcommon/llversionserver.h index b87d054b3b..5da3c01096 100644 --- a/indra/llcommon/llversionserver.h +++ b/indra/llcommon/llversionserver.h @@ -33,9 +33,9 @@  #define LL_LLVERSIONSERVER_H  const S32 LL_VERSION_MAJOR = 1; -const S32 LL_VERSION_MINOR = 19; -const S32 LL_VERSION_PATCH = 2; -const S32 LL_VERSION_BUILD = 83236; +const S32 LL_VERSION_MINOR = 20; +const S32 LL_VERSION_PATCH = 0; +const S32 LL_VERSION_BUILD = 83892;  const char * const LL_CHANNEL = "Second Life Server"; diff --git a/indra/llmath/llline.cpp b/indra/llmath/llline.cpp new file mode 100644 index 0000000000..b62631072b --- /dev/null +++ b/indra/llmath/llline.cpp @@ -0,0 +1,176 @@ +/**  + * @file llline.cpp + * @author Andrew Meadows + * @brief Simple line class that can compute nearest approach between two lines + * + * Copyright (c) 2001-$CurrentYear$, Linden Research, Inc. + * $License$ + */ + +#include "llline.h" +#include "llrand.h" + +const F32 SOME_SMALL_NUMBER = 1.0e-5f; +const F32 SOME_VERY_SMALL_NUMBER = 1.0e-8f; + +LLLine::LLLine() +:	mPoint(0.f, 0.f, 0.f), +	mDirection(1.f, 0.f, 0.f) +{ } + +LLLine::LLLine( const LLVector3& first_point, const LLVector3& second_point ) +{ +	setPoints(first_point, second_point); +} + +void LLLine::setPoints( const LLVector3& first_point, const LLVector3& second_point ) +{ +	mPoint = first_point; +	mDirection = second_point - first_point; +	mDirection.normalize(); +} + +void LLLine::setPointDirection( const LLVector3& first_point, const LLVector3& second_point ) +{ +	setPoints(first_point, first_point + second_point); +} + +bool LLLine::intersects( const LLVector3& point, F32 radius ) const +{ +	LLVector3 other_direction = point - mPoint; +	LLVector3 nearest_point = mPoint + mDirection * (other_direction * mDirection); +	F32 nearest_approach = (nearest_point - point).length(); +	return (nearest_approach <= radius); +} + +// returns the point on this line that is closest to some_point +LLVector3 LLLine::nearestApproach( const LLVector3& some_point ) const +{ +	return (mPoint + mDirection * ((some_point - mPoint) * mDirection)); +} + +// the accuracy of this method sucks when you give it two nearly +// parallel lines, so you should probably check for parallelism +// before you call this +//  +// returns the point on this line that is closest to other_line +LLVector3 LLLine::nearestApproach( const LLLine& other_line ) const +{ +	LLVector3 between_points = other_line.mPoint - mPoint; +	F32 dir_dot_dir = mDirection * other_line.mDirection; +	F32 one_minus_dir_dot_dir = 1.0f - fabs(dir_dot_dir); +	if ( one_minus_dir_dot_dir < SOME_VERY_SMALL_NUMBER ) +	{ +#ifdef LL_DEBUG +		llwarns << "LLLine::nearestApproach() was given two very " +			<< "nearly parallel lines dir1 = " << mDirection  +			<< " dir2 = " << other_line.mDirection << " with 1-dot_product = "  +			<< one_minus_dir_dot_dir << llendl; +#endif +		// the lines are approximately parallel +		// We shouldn't fall in here because this check should have been made +		// BEFORE this function was called.  We dare not continue with the  +		// computations for fear of division by zero, but we have to return  +		// something so we return a bogus point -- caller beware. +		return 0.5f * (mPoint + other_line.mPoint); +	} + +	F32 odir_dot_bp = other_line.mDirection * between_points; + +	F32 numerator = 0; +	F32 denominator = 0; +	for (S32 i=0; i<3; i++) +	{ +		F32 factor = dir_dot_dir * other_line.mDirection.mV[i] - mDirection.mV[i]; +		numerator += ( between_points.mV[i] - odir_dot_bp * other_line.mDirection.mV[i] ) * factor; +		denominator -= factor * factor; +	} + +	F32 length_to_nearest_approach = numerator / denominator; + +	return mPoint + length_to_nearest_approach * mDirection; +} + +std::ostream& operator<<( std::ostream& output_stream, const LLLine& line ) +{ +	output_stream << "{point=" << line.mPoint << "," << "dir=" << line.mDirection << "}"; +	return output_stream; +} + + +F32 ALMOST_PARALLEL = 0.99f; +F32 TOO_SMALL_FOR_DIVISION = 0.0001f; + +// returns 'true' if this line intersects the plane +// on success stores the intersection point in 'result' +bool LLLine::intersectsPlane( LLVector3& result, const LLLine& plane ) const +{ +	// p = P + l * d     equation for a line +	//  +	// N * p = D         equation for a point +	// +	// N * (P + l * d) = D +	// N*P + l * (N*d) = D +	// l * (N*d) = D - N*P +	// l =  ( D - N*P ) / ( N*d ) +	// + +	F32 dot = plane.mDirection * mDirection; +	if (fabs(dot) < TOO_SMALL_FOR_DIVISION) +	{ +		return false; +	} + +	F32 plane_dot = plane.mDirection * plane.mPoint; +	F32 length = ( plane_dot - (plane.mDirection * mPoint) ) / dot; +	result = mPoint + length * mDirection; +	return true; +} + +//static  +// returns 'true' if planes intersect, and stores the result  +// the second and third arguments are treated as planes +// where mPoint is on the plane and mDirection is the normal +// result.mPoint will be the intersection line's closest approach  +// to first_plane.mPoint +bool LLLine::getIntersectionBetweenTwoPlanes( LLLine& result, const LLLine& first_plane, const LLLine& second_plane ) +{ +	// TODO -- if we ever get some generic matrix solving code in our libs +	// then we should just use that, since this problem is really just +	// linear algebra. + +	F32 dot = fabs(first_plane.mDirection * second_plane.mDirection); +	if (dot > ALMOST_PARALLEL) +	{ +		// the planes are nearly parallel +		return false; +	} + +	LLVector3 direction = first_plane.mDirection % second_plane.mDirection; +	direction.normalize(); + +	LLVector3 first_intersection; +	{ +		LLLine intersection_line(first_plane); +		intersection_line.mDirection = direction % first_plane.mDirection; +		intersection_line.mDirection.normalize(); +		intersection_line.intersectsPlane(first_intersection, second_plane); +	} + +	/* +	LLVector3 second_intersection; +	{ +		LLLine intersection_line(second_plane); +		intersection_line.mDirection = direction % second_plane.mDirection; +		intersection_line.mDirection.normalize(); +		intersection_line.intersectsPlane(second_intersection, first_plane); +	} +	*/ + +	result.mPoint = first_intersection; +	result.mDirection = direction; + +	return true; +} + + diff --git a/indra/llmath/llline.h b/indra/llmath/llline.h new file mode 100644 index 0000000000..cdae3fc1fe --- /dev/null +++ b/indra/llmath/llline.h @@ -0,0 +1,62 @@ +// llline.h +/** + * @file llline.cpp + * @author Andrew Meadows + * @brief Simple line for computing nearest approach between two infinite lines + * + * Copyright (c) 2006-$CurrentYear$, Linden Research, Inc. + * $License$ + */ + +#ifndef LL_LINE_H +#define LL_LINE_H + +#include <iostream> +#include "stdtypes.h" +#include "v3math.h" + +const F32 DEFAULT_INTERSECTION_ERROR = 0.000001f; + +class LLLine +{ +public: +	LLLine(); +	LLLine( const LLVector3& first_point, const LLVector3& second_point ); +	virtual ~LLLine() {}; + +	void setPointDirection( const LLVector3& first_point, const LLVector3& second_point ); +	void setPoints( const LLVector3& first_point, const LLVector3& second_point ); + +	bool intersects( const LLVector3& point, F32 radius = DEFAULT_INTERSECTION_ERROR ) const; + +	// returns the point on this line that is closest to some_point +	LLVector3 nearestApproach( const LLVector3& some_point ) const; + +	// returns the point on this line that is closest to other_line +	LLVector3 nearestApproach( const LLLine& other_line ) const; + +	friend std::ostream& operator<<( std::ostream& output_stream, const LLLine& line ); + +	// returns 'true' if this line intersects the plane +	// on success stores the intersection point in 'result' +	bool intersectsPlane( LLVector3& result, const LLLine& plane ) const; + +	// returns 'true' if planes intersect, and stores the result  +	// the second and third arguments are treated as planes +	// where mPoint is on the plane and mDirection is the normal +	// result.mPoint will be the intersection line's closest approach  +	// to first_plane.mPoint +	static bool getIntersectionBetweenTwoPlanes( LLLine& result, const LLLine& first_plane, const LLLine& second_plane ); + +	const LLVector3& getPoint() const { return mPoint; } +	const LLVector3& getDirection() const { return mDirection; } + +protected: +	// these are protected because some code assumes that the normal is  +	// always correct and properly normalized. +	LLVector3 mPoint; +	LLVector3 mDirection; +}; + + +#endif diff --git a/indra/llmath/llmath.h b/indra/llmath/llmath.h index 6df241d3ab..5dfddff4eb 100644 --- a/indra/llmath/llmath.h +++ b/indra/llmath/llmath.h @@ -32,8 +32,14 @@  #ifndef LLMATH_H  #define LLMATH_H +#include <cmath> +//#include <math.h> +//#include <stdlib.h> +#include "lldefs.h" +  // work around for Windows & older gcc non-standard function names.  #if LL_WINDOWS +#include <float.h>  #define llisnan(val)	_isnan(val)  #define llfinite(val)	_finite(val)  #elif (LL_LINUX && __GNUC__ <= 2) @@ -99,6 +105,12 @@ inline BOOL is_approx_equal(F32 x, F32 y)  	return (abs((S32) ((U32&)x - (U32&)y) ) < COMPARE_MANTISSA_UP_TO_BIT);  } +inline BOOL is_approx_equal(F64 x, F64 y) +{ +	const S64 COMPARE_MANTISSA_UP_TO_BIT = 0x02; +	return (abs((S32) ((U64&)x - (U64&)y) ) < COMPARE_MANTISSA_UP_TO_BIT); +} +  inline BOOL is_approx_equal_fraction(F32 x, F32 y, U32 frac_bits)  {  	BOOL ret = TRUE; @@ -120,6 +132,27 @@ inline BOOL is_approx_equal_fraction(F32 x, F32 y, U32 frac_bits)  	return ret;  } +inline BOOL is_approx_equal_fraction(F64 x, F64 y, U32 frac_bits) +{ +	BOOL ret = TRUE; +	F64 diff = (F64) fabs(x - y); + +	S32 diffInt = (S32) diff; +	S32 diffFracTolerance = (S32) ((diff - (F64) diffInt) * (1 << frac_bits)); +	 +	// if integer portion is not equal, not enough bits were used for packing +	// so error out since either the use case is not correct OR there is +	// an issue with pack/unpack. should fail in either case. +	// for decimal portion, make sure that the delta is no more than 1 +	// based on the number of bits used for packing decimal portion. +	if (diffInt != 0 || diffFracTolerance > 1) +	{ +		ret = FALSE; +	} + +	return ret; +} +  inline S32 llabs(const S32 a)  {  	return S32(labs(a)); diff --git a/indra/llmath/llquaternion.cpp b/indra/llmath/llquaternion.cpp index 34c1fd1762..c3e84e366d 100644 --- a/indra/llmath/llquaternion.cpp +++ b/indra/llmath/llquaternion.cpp @@ -51,19 +51,19 @@ const LLQuaternion LLQuaternion::DEFAULT;  LLQuaternion::LLQuaternion(const LLMatrix4 &mat)  {  	*this = mat.quaternion(); -	normQuat(); +	normalize();  }  LLQuaternion::LLQuaternion(const LLMatrix3 &mat)  {  	*this = mat.quaternion(); -	normQuat(); +	normalize();  }  LLQuaternion::LLQuaternion(F32 angle, const LLVector4 &vec)  {  	LLVector3 v(vec.mV[VX], vec.mV[VY], vec.mV[VZ]); -	v.normVec(); +	v.normalize();  	F32 c, s;  	c = cosf(angle*0.5f); @@ -73,13 +73,13 @@ LLQuaternion::LLQuaternion(F32 angle, const LLVector4 &vec)  	mQ[VY] = v.mV[VY] * s;  	mQ[VZ] = v.mV[VZ] * s;  	mQ[VW] = c; -	normQuat(); +	normalize();  }  LLQuaternion::LLQuaternion(F32 angle, const LLVector3 &vec)  {  	LLVector3 v(vec); -	v.normVec(); +	v.normalize();  	F32 c, s;  	c = cosf(angle*0.5f); @@ -89,7 +89,7 @@ LLQuaternion::LLQuaternion(F32 angle, const LLVector3 &vec)  	mQ[VY] = v.mV[VY] * s;  	mQ[VZ] = v.mV[VZ] * s;  	mQ[VW] = c; -	normQuat(); +	normalize();  }  LLQuaternion::LLQuaternion(const LLVector3 &x_axis, @@ -99,7 +99,7 @@ LLQuaternion::LLQuaternion(const LLVector3 &x_axis,  	LLMatrix3 mat;  	mat.setRows(x_axis, y_axis, z_axis);  	*this = mat.quaternion(); -	normQuat(); +	normalize();  }  // Quatizations @@ -138,10 +138,93 @@ void	LLQuaternion::quantize8(F32 lower, F32 upper)  // Set LLQuaternion routines +const LLQuaternion&	LLQuaternion::setAngleAxis(F32 angle, F32 x, F32 y, F32 z) +{ +	LLVector3 vec(x, y, z); +	vec.normalize(); + +	angle *= 0.5f; +	F32 c, s; +	c = cosf(angle); +	s = sinf(angle); + +	mQ[VX] = vec.mV[VX]*s; +	mQ[VY] = vec.mV[VY]*s; +	mQ[VZ] = vec.mV[VZ]*s; +	mQ[VW] = c; + +	normalize(); +	return (*this); +} + +const LLQuaternion&	LLQuaternion::setAngleAxis(F32 angle, const LLVector3 &vec) +{ +	LLVector3 v(vec); +	v.normalize(); + +	angle *= 0.5f; +	F32 c, s; +	c = cosf(angle); +	s = sinf(angle); + +	mQ[VX] = v.mV[VX]*s; +	mQ[VY] = v.mV[VY]*s; +	mQ[VZ] = v.mV[VZ]*s; +	mQ[VW] = c; + +	normalize(); +	return (*this); +} + +const LLQuaternion&	LLQuaternion::setAngleAxis(F32 angle, const LLVector4 &vec) +{ +	LLVector3 v(vec.mV[VX], vec.mV[VY], vec.mV[VZ]); +	v.normalize(); + +	F32 c, s; +	c = cosf(angle*0.5f); +	s = sinf(angle*0.5f); + +	mQ[VX] = v.mV[VX]*s; +	mQ[VY] = v.mV[VY]*s; +	mQ[VZ] = v.mV[VZ]*s; +	mQ[VW] = c; + +	normalize(); +	return (*this); +} + +const LLQuaternion&	LLQuaternion::setEulerAngles(F32 roll, F32 pitch, F32 yaw) +{ +	LLMatrix3 rot_mat(roll, pitch, yaw); +	rot_mat.orthogonalize(); +	*this = rot_mat.quaternion(); +		 +	normalize(); +	return (*this); +} + +// deprecated +const LLQuaternion&	LLQuaternion::set(const LLMatrix3 &mat) +{ +	*this = mat.quaternion(); +	normalize(); +	return (*this); +} + +// deprecated +const LLQuaternion&	LLQuaternion::set(const LLMatrix4 &mat) +{ +	*this = mat.quaternion(); +	normalize(); +	return (*this); +} + +// deprecated  const LLQuaternion&	LLQuaternion::setQuat(F32 angle, F32 x, F32 y, F32 z)  {  	LLVector3 vec(x, y, z); -	vec.normVec(); +	vec.normalize();  	angle *= 0.5f;  	F32 c, s; @@ -153,14 +236,15 @@ const LLQuaternion&	LLQuaternion::setQuat(F32 angle, F32 x, F32 y, F32 z)  	mQ[VZ] = vec.mV[VZ]*s;  	mQ[VW] = c; -	normQuat(); +	normalize();  	return (*this);  } +// deprecated  const LLQuaternion&	LLQuaternion::setQuat(F32 angle, const LLVector3 &vec)  {  	LLVector3 v(vec); -	v.normVec(); +	v.normalize();  	angle *= 0.5f;  	F32 c, s; @@ -172,14 +256,14 @@ const LLQuaternion&	LLQuaternion::setQuat(F32 angle, const LLVector3 &vec)  	mQ[VZ] = v.mV[VZ]*s;  	mQ[VW] = c; -	normQuat(); +	normalize();  	return (*this);  }  const LLQuaternion&	LLQuaternion::setQuat(F32 angle, const LLVector4 &vec)  {  	LLVector3 v(vec.mV[VX], vec.mV[VY], vec.mV[VZ]); -	v.normVec(); +	v.normalize();  	F32 c, s;  	c = cosf(angle*0.5f); @@ -190,7 +274,7 @@ const LLQuaternion&	LLQuaternion::setQuat(F32 angle, const LLVector4 &vec)  	mQ[VZ] = v.mV[VZ]*s;  	mQ[VW] = c; -	normQuat(); +	normalize();  	return (*this);  } @@ -200,7 +284,21 @@ const LLQuaternion&	LLQuaternion::setQuat(F32 roll, F32 pitch, F32 yaw)  	rot_mat.orthogonalize();  	*this = rot_mat.quaternion(); -	normQuat(); +	normalize(); +	return (*this); +} + +const LLQuaternion&	LLQuaternion::setQuat(const LLMatrix3 &mat) +{ +	*this = mat.quaternion(); +	normalize(); +	return (*this); +} + +const LLQuaternion&	LLQuaternion::setQuat(const LLMatrix4 &mat) +{ +	*this = mat.quaternion(); +	normalize();  	return (*this);  //#if 1  //	// NOTE: LLQuaternion's are actually inverted with respect to @@ -337,8 +435,8 @@ void LLQuaternion::shortestArc(const LLVector3 &a, const LLVector3 &b)  	// Make sure neither vector is zero length.  Also normalize  	// the vectors while we are at it. -	F32 vec_a_mag = vec_a.normVec(); -	F32 vec_b_mag = vec_b.normVec(); +	F32 vec_a_mag = vec_a.normalize(); +	F32 vec_b_mag = vec_b.normalize();  	if (vec_a_mag < F_APPROXIMATELY_ZERO ||  		vec_b_mag < F_APPROXIMATELY_ZERO)  	{ @@ -370,7 +468,7 @@ void LLQuaternion::shortestArc(const LLVector3 &a, const LLVector3 &b)  		ortho_axis -= proj;  		// Turn this into an orthonormal axis. -		F32 ortho_length = ortho_axis.normVec(); +		F32 ortho_length = ortho_axis.normalize();  		// If the axis' length is 0, then our guess at an orthogonal axis  		// was wrong (a is parallel to the x-axis).  		if (ortho_length < F_APPROXIMATELY_ZERO) @@ -391,7 +489,7 @@ void LLQuaternion::shortestArc(const LLVector3 &a, const LLVector3 &b)  		// Return the rotation between these vectors.  		F32 theta = (F32)acos(cos_theta); -		setQuat(theta, axis); +		setAngleAxis(theta, axis);  	}  } @@ -516,7 +614,7 @@ LLQuaternion lerp(F32 t, const LLQuaternion &p, const LLQuaternion &q)  {  	LLQuaternion r;  	r = t * (q - p) + p; -	r.normQuat(); +	r.normalize();  	return r;  }  #endif @@ -529,7 +627,7 @@ LLQuaternion lerp(F32 t, const LLQuaternion &q)  	r.mQ[VY] = t * q.mQ[VY];  	r.mQ[VZ] = t * q.mQ[VZ];  	r.mQ[VW] = t * (q.mQ[VZ] - 1.f) + 1.f; -	r.normQuat(); +	r.normalize();  	return r;  } @@ -544,7 +642,7 @@ LLQuaternion lerp(F32 t, const LLQuaternion &p, const LLQuaternion &q)  	r.mQ[VY] = t * q.mQ[VY] + (inv_t * p.mQ[VY]);  	r.mQ[VZ] = t * q.mQ[VZ] + (inv_t * p.mQ[VZ]);  	r.mQ[VW] = t * q.mQ[VW] + (inv_t * p.mQ[VW]); -	r.normQuat(); +	r.normalize();  	return r;  } @@ -640,8 +738,8 @@ LLQuaternion slerp(F32 t, const LLQuaternion &q)          // when c < 0.0 then theta > PI/2           // since quat and -quat are the same rotation we invert one of            // p or q to reduce unecessary spins -        // A equivalent way to do it is to convert acos(c) as if it had been negative, -        // and to negate stp  +        // A equivalent way to do it is to convert acos(c) as if it had  +		// been negative, and to negate stp           angle   = (F32) acos(-c);           stp     = -(F32) sin(angle * (1.f - t));          stq     = (F32) sin(angle * t); @@ -742,20 +840,6 @@ LLQuaternion::Order StringToOrder( const char *str )  	return LLQuaternion::XYZ;  } -const LLQuaternion&	LLQuaternion::setQuat(const LLMatrix3 &mat) -{ -	*this = mat.quaternion(); -	normQuat(); -	return (*this); -} - -const LLQuaternion&	LLQuaternion::setQuat(const LLMatrix4 &mat) -{ -	*this = mat.quaternion(); -	normQuat(); -	return (*this); -} -  void LLQuaternion::getAngleAxis(F32* angle, LLVector3 &vec) const  {  	F32 cos_a = mQ[VW]; @@ -769,10 +853,28 @@ void LLQuaternion::getAngleAxis(F32* angle, LLVector3 &vec) const  	else  		sin_a = 1.f/sin_a; -    *angle = 2.0f * (F32) acos( cos_a ); -    vec.mV[VX] = mQ[VX] * sin_a; -    vec.mV[VY] = mQ[VY] * sin_a; -    vec.mV[VZ] = mQ[VZ] * sin_a; +    F32 temp_angle = 2.0f * (F32) acos( cos_a ); +	if (temp_angle > F_PI) +	{ +		// The (angle,axis) pair should never have angles outside [PI, -PI] +		// since we want the _shortest_ (angle,axis) solution. +		// Since acos is defined for [0, PI], and we multiply by 2.0, we +		// can push the angle outside the acceptible range. +		// When this happens we set the angle to the other portion of a  +		// full 2PI rotation, and negate the axis, which reverses the  +		// direction of the rotation (by the right-hand rule). +		*angle = 2.f * F_PI - temp_angle; +    	vec.mV[VX] = - mQ[VX] * sin_a; +    	vec.mV[VY] = - mQ[VY] * sin_a; +    	vec.mV[VZ] = - mQ[VZ] * sin_a; +	} +	else +	{ +		*angle = temp_angle; +    	vec.mV[VX] = mQ[VX] * sin_a; +    	vec.mV[VY] = mQ[VY] * sin_a; +    	vec.mV[VZ] = mQ[VZ] * sin_a; +	}  } @@ -846,7 +948,7 @@ BOOL LLQuaternion::parseQuat(const char* buf, LLQuaternion* value)  	S32 count = sscanf( buf, "%f %f %f %f", quat.mQ + 0, quat.mQ + 1, quat.mQ + 2, quat.mQ + 3 );  	if( 4 == count )  	{ -		value->setQuat( quat ); +		value->set( quat );  		return TRUE;  	} diff --git a/indra/llmath/llquaternion.h b/indra/llmath/llquaternion.h index 01ddae94cb..a088d70674 100644 --- a/indra/llmath/llquaternion.h +++ b/indra/llmath/llquaternion.h @@ -57,10 +57,10 @@ public:  	LLQuaternion();									// Initializes Quaternion to (0,0,0,1)  	explicit LLQuaternion(const LLMatrix4 &mat);				// Initializes Quaternion from Matrix4  	explicit LLQuaternion(const LLMatrix3 &mat);				// Initializes Quaternion from Matrix3 -	LLQuaternion(F32 x, F32 y, F32 z, F32 w);		// Initializes Quaternion to normQuat(x, y, z, w) +	LLQuaternion(F32 x, F32 y, F32 z, F32 w);		// Initializes Quaternion to normalize(x, y, z, w)  	LLQuaternion(F32 angle, const LLVector4 &vec);	// Initializes Quaternion to axis_angle2quat(angle, vec)  	LLQuaternion(F32 angle, const LLVector3 &vec);	// Initializes Quaternion to axis_angle2quat(angle, vec) -	LLQuaternion(const F32 *q);						// Initializes Quaternion to normQuat(x, y, z, w) +	LLQuaternion(const F32 *q);						// Initializes Quaternion to normalize(x, y, z, w)  	LLQuaternion(const LLVector3 &x_axis,  				 const LLVector3 &y_axis,  				 const LLVector3 &z_axis);			// Initializes Quaternion from Matrix3 = [x_axis ; y_axis ; z_axis] @@ -71,15 +71,27 @@ public:  	void quantize16(F32 lower, F32 upper);					// changes the vector to reflect quatization  	void quantize8(F32 lower, F32 upper);							// changes the vector to reflect quatization  	void loadIdentity();											// Loads the quaternion that represents the identity rotation -	const LLQuaternion&	setQuatInit(F32 x, F32 y, F32 z, F32 w);	// Sets Quaternion to normQuat(x, y, z, w) -	const LLQuaternion&	setQuat(const LLQuaternion &quat);			// Copies Quaternion -	const LLQuaternion&	setQuat(const F32 *q);						// Sets Quaternion to normQuat(quat[VX], quat[VY], quat[VZ], quat[VW]) -	const LLQuaternion&	setQuat(const LLMatrix3 &mat);				// Sets Quaternion to mat2quat(mat) -	const LLQuaternion&	setQuat(const LLMatrix4 &mat);				// Sets Quaternion to mat2quat(mat) -	const LLQuaternion&	setQuat(F32 angle, F32 x, F32 y, F32 z);	// Sets Quaternion to axis_angle2quat(angle, x, y, z) -	const LLQuaternion&	setQuat(F32 angle, const LLVector3 &vec);	// Sets Quaternion to axis_angle2quat(angle, vec) -	const LLQuaternion&	setQuat(F32 angle, const LLVector4 &vec);	// Sets Quaternion to axis_angle2quat(angle, vec) -	const LLQuaternion&	setQuat(F32 roll, F32 pitch, F32 yaw);		// Sets Quaternion to euler2quat(pitch, yaw, roll) + +	const LLQuaternion&	set(F32 x, F32 y, F32 z, F32 w);		// Sets Quaternion to normalize(x, y, z, w) +	const LLQuaternion&	set(const LLQuaternion &quat);			// Copies Quaternion +	const LLQuaternion&	set(const F32 *q);						// Sets Quaternion to normalize(quat[VX], quat[VY], quat[VZ], quat[VW]) +	const LLQuaternion&	set(const LLMatrix3 &mat);				// Sets Quaternion to mat2quat(mat) +	const LLQuaternion&	set(const LLMatrix4 &mat);				// Sets Quaternion to mat2quat(mat) + +	const LLQuaternion&	setAngleAxis(F32 angle, F32 x, F32 y, F32 z);	// Sets Quaternion to axis_angle2quat(angle, x, y, z) +	const LLQuaternion&	setAngleAxis(F32 angle, const LLVector3 &vec);	// Sets Quaternion to axis_angle2quat(angle, vec) +	const LLQuaternion&	setAngleAxis(F32 angle, const LLVector4 &vec);	// Sets Quaternion to axis_angle2quat(angle, vec) +	const LLQuaternion&	setEulerAngles(F32 roll, F32 pitch, F32 yaw);	// Sets Quaternion to euler2quat(pitch, yaw, roll) + +	const LLQuaternion&	setQuatInit(F32 x, F32 y, F32 z, F32 w);	// deprecated +	const LLQuaternion&	setQuat(const LLQuaternion &quat);			// deprecated +	const LLQuaternion&	setQuat(const F32 *q);						// deprecated +	const LLQuaternion&	setQuat(const LLMatrix3 &mat);				// deprecated +	const LLQuaternion&	setQuat(const LLMatrix4 &mat);				// deprecated +	const LLQuaternion&	setQuat(F32 angle, F32 x, F32 y, F32 z);	// deprecated +	const LLQuaternion&	setQuat(F32 angle, const LLVector3 &vec);	// deprecated +	const LLQuaternion&	setQuat(F32 angle, const LLVector4 &vec);	// deprecated +	const LLQuaternion&	setQuat(F32 roll, F32 pitch, F32 yaw);		// deprecated  	LLMatrix4	getMatrix4(void) const;							// Returns the Matrix4 equivalent of Quaternion  	LLMatrix3	getMatrix3(void) const;							// Returns the Matrix3 equivalent of Quaternion @@ -87,11 +99,16 @@ public:  	void		getAngleAxis(F32* angle, LLVector3 &vec) const;  	void		getEulerAngles(F32 *roll, F32* pitch, F32 *yaw) const; -	F32				normQuat();					// Normalizes Quaternion and returns magnitude -	const LLQuaternion&	conjQuat(void);				// Conjugates Quaternion and returns result +	F32	normalize();	// Normalizes Quaternion and returns magnitude +	F32	normQuat();		// deprecated + +	const LLQuaternion&	conjugate(void);	// Conjugates Quaternion and returns result +	const LLQuaternion&	conjQuat(void);		// deprecated  	// Other useful methods -	const LLQuaternion&	transQuat();											// Transpose +	const LLQuaternion&	transpose();		// transpose (same as conjugate) +	const LLQuaternion&	transQuat();		// deprecated +  	void			shortestArc(const LLVector3 &a, const LLVector3 &b);	// shortest rotation from a to b  	const LLQuaternion& constrain(F32 radians);						// constrains rotation to a cone angle specified in radians @@ -189,7 +206,7 @@ inline LLQuaternion::LLQuaternion(F32 x, F32 y, F32 z, F32 w)  	mQ[VS] = w;  	//RN: don't normalize this case as its used mainly for temporaries during calculations -	//normQuat(); +	//normalize();  	/*  	F32 mag = sqrtf(mQ[VX]*mQ[VX] + mQ[VY]*mQ[VY] + mQ[VZ]*mQ[VZ] + mQ[VS]*mQ[VS]);  	mag -= 1.f; @@ -205,7 +222,7 @@ inline LLQuaternion::LLQuaternion(const F32 *q)  	mQ[VZ] = q[VZ];  	mQ[VS] = q[VW]; -	normQuat(); +	normalize();  	/*  	F32 mag = sqrtf(mQ[VX]*mQ[VX] + mQ[VY]*mQ[VY] + mQ[VZ]*mQ[VZ] + mQ[VS]*mQ[VS]);  	mag -= 1.f; @@ -224,33 +241,67 @@ inline void LLQuaternion::loadIdentity()  } +inline const LLQuaternion&	LLQuaternion::set(F32 x, F32 y, F32 z, F32 w) +{ +	mQ[VX] = x; +	mQ[VY] = y; +	mQ[VZ] = z; +	mQ[VS] = w; +	normalize(); +	return (*this); +} + +inline const LLQuaternion&	LLQuaternion::set(const LLQuaternion &quat) +{ +	mQ[VX] = quat.mQ[VX]; +	mQ[VY] = quat.mQ[VY]; +	mQ[VZ] = quat.mQ[VZ]; +	mQ[VW] = quat.mQ[VW]; +	normalize(); +	return (*this); +} + +inline const LLQuaternion&	LLQuaternion::set(const F32 *q) +{ +	mQ[VX] = q[VX]; +	mQ[VY] = q[VY]; +	mQ[VZ] = q[VZ]; +	mQ[VS] = q[VW]; +	normalize(); +	return (*this); +} + + +// deprecated  inline const LLQuaternion&	LLQuaternion::setQuatInit(F32 x, F32 y, F32 z, F32 w)  {  	mQ[VX] = x;  	mQ[VY] = y;  	mQ[VZ] = z;  	mQ[VS] = w; -	normQuat(); +	normalize();  	return (*this);  } +// deprecated  inline const LLQuaternion&	LLQuaternion::setQuat(const LLQuaternion &quat)  {  	mQ[VX] = quat.mQ[VX];  	mQ[VY] = quat.mQ[VY];  	mQ[VZ] = quat.mQ[VZ];  	mQ[VW] = quat.mQ[VW]; -	normQuat(); +	normalize();  	return (*this);  } +// deprecated  inline const LLQuaternion&	LLQuaternion::setQuat(const F32 *q)  {  	mQ[VX] = q[VX];  	mQ[VY] = q[VY];  	mQ[VZ] = q[VZ];  	mQ[VS] = q[VW]; -	normQuat(); +	normalize();  	return (*this);  } @@ -270,10 +321,36 @@ inline void LLQuaternion::getAngleAxis(F32* angle, F32* x, F32* y, F32* z) const  	else  		sin_a = 1.f/sin_a; -    *angle = 2.0f * (F32) acos( cos_a ); -    *x = mQ[VX] * sin_a; -    *y = mQ[VY] * sin_a; -    *z = mQ[VZ] * sin_a; +    F32 temp_angle = 2.0f * (F32) acos( cos_a ); +	if (temp_angle > F_PI) +	{ +		// The (angle,axis) pair should never have angles outside [PI, -PI] +		// since we want the _shortest_ (angle,axis) solution. +		// Since acos is defined for [0, PI], and we multiply by 2.0, we +		// can push the angle outside the acceptible range. +		// When this happens we set the angle to the other portion of a  +		// full 2PI rotation, and negate the axis, which reverses the  +		// direction of the rotation (by the right-hand rule). +		*angle = 2.f * F_PI - temp_angle; +    	*x = - mQ[VX] * sin_a; +    	*y = - mQ[VY] * sin_a; +    	*z = - mQ[VZ] * sin_a; +	} +	else +	{ +		*angle = temp_angle; +    	*x = mQ[VX] * sin_a; +    	*y = mQ[VY] * sin_a; +    	*z = mQ[VZ] * sin_a; +	} +} + +inline const LLQuaternion& LLQuaternion::conjugate() +{ +	mQ[VX] *= -1.f; +	mQ[VY] *= -1.f; +	mQ[VZ] *= -1.f; +	return (*this);  }  inline const LLQuaternion& LLQuaternion::conjQuat() @@ -285,12 +362,21 @@ inline const LLQuaternion& LLQuaternion::conjQuat()  }  // Transpose +inline const LLQuaternion& LLQuaternion::transpose() +{ +	mQ[VX] *= -1.f; +	mQ[VY] *= -1.f; +	mQ[VZ] *= -1.f; +	return (*this); +} + +// deprecated  inline const LLQuaternion& LLQuaternion::transQuat()  { -	mQ[VX] = -mQ[VX]; -	mQ[VY] = -mQ[VY]; -	mQ[VZ] = -mQ[VZ]; -	return *this; +	mQ[VX] *= -1.f; +	mQ[VY] *= -1.f; +	mQ[VZ] *= -1.f; +	return (*this);  } @@ -382,6 +468,30 @@ inline const LLQuaternion&	operator*=(LLQuaternion &a, const LLQuaternion &b)  	return a;  } +inline F32	LLQuaternion::normalize() +{ +	F32 mag = sqrtf(mQ[VX]*mQ[VX] + mQ[VY]*mQ[VY] + mQ[VZ]*mQ[VZ] + mQ[VS]*mQ[VS]); + +	if (mag > FP_MAG_THRESHOLD) +	{ +		F32 oomag = 1.f/mag; +		mQ[VX] *= oomag; +		mQ[VY] *= oomag; +		mQ[VZ] *= oomag; +		mQ[VS] *= oomag; +	} +	else +	{ +		mQ[VX] = 0.f; +		mQ[VY] = 0.f; +		mQ[VZ] = 0.f; +		mQ[VS] = 1.f; +	} + +	return mag; +} + +// deprecated  inline F32	LLQuaternion::normQuat()  {  	F32 mag = sqrtf(mQ[VX]*mQ[VX] + mQ[VY]*mQ[VY] + mQ[VZ]*mQ[VZ] + mQ[VS]*mQ[VS]); diff --git a/indra/llmath/llsphere.cpp b/indra/llmath/llsphere.cpp new file mode 100644 index 0000000000..3428dc1487 --- /dev/null +++ b/indra/llmath/llsphere.cpp @@ -0,0 +1,351 @@ +/**  + * @file llsphere.cpp + * @author Andrew Meadows + * @brief Simple line class that can compute nearest approach between two lines + * + * Copyright (c) 2006-$CurrentYear$, Linden Research, Inc. + * $License$ + */ + +#include "llsphere.h" + +LLSphere::LLSphere() +:	mCenter(0.f, 0.f, 0.f), +	mRadius(0.f) +{ } + +LLSphere::LLSphere( const LLVector3& center, F32 radius) +{ +	set(center, radius); +} + +void LLSphere::set( const LLVector3& center, F32 radius ) +{ +	mCenter = center; +	setRadius(radius); +} + +void LLSphere::setCenter( const LLVector3& center) +{ +	mCenter = center; +} + +void LLSphere::setRadius( F32 radius) +{ +	if (radius < 0.f) +	{ +		radius = -radius; +	} +	mRadius = radius; +} +	 +const LLVector3& LLSphere::getCenter() const +{ +	return mCenter; +} + +F32 LLSphere::getRadius() const +{ +	return mRadius; +} + +// returns 'TRUE' if this sphere completely contains other_sphere +BOOL LLSphere::contains(const LLSphere& other_sphere) const +{ +	F32 separation = (mCenter - other_sphere.mCenter).length(); +	return (mRadius >= separation + other_sphere.mRadius) ? TRUE : FALSE; +} + +// returns 'TRUE' if this sphere completely contains other_sphere +BOOL LLSphere::overlaps(const LLSphere& other_sphere) const +{ +	F32 separation = (mCenter - other_sphere.mCenter).length(); +	return (separation <= mRadius + other_sphere.mRadius) ? TRUE : FALSE; +} + +// returns overlap +// negative overlap is closest approach +F32 LLSphere::getOverlap(const LLSphere& other_sphere) const +{ +	// separation is distance from other_sphere's edge and this center +	return (mCenter - other_sphere.mCenter).length() - mRadius - other_sphere.mRadius; +} + +bool LLSphere::operator==(const LLSphere& rhs) const +{ +	// TODO? -- use approximate equality for centers? +	return (mRadius == rhs.mRadius +			&& mCenter == rhs.mCenter); +} + +std::ostream& operator<<( std::ostream& output_stream, const LLSphere& sphere) +{ +	output_stream << "{center=" << sphere.mCenter << "," << "radius=" << sphere.mRadius << "}"; +	return output_stream; +} + +// static  +// removes any spheres that are contained in others +void LLSphere::collapse(std::vector<LLSphere>& sphere_list) +{ +	std::vector<LLSphere>::iterator first_itr = sphere_list.begin(); +	while (first_itr != sphere_list.end()) +	{ +		bool delete_from_front = false; + +		std::vector<LLSphere>::iterator second_itr = first_itr; +		++second_itr; +		while (second_itr != sphere_list.end()) +		{ +			if (second_itr->contains(*first_itr)) +			{ +				delete_from_front = true; +				break; +			} +			else if (first_itr->contains(*second_itr)) +			{ +				sphere_list.erase(second_itr++); +			} +			else +			{ +				++second_itr; +			} +		} + +		if (delete_from_front) +		{ +			sphere_list.erase(first_itr++); +		} +		else +		{ +			++first_itr; +		} +	} +} + +// static +// returns the bounding sphere that contains both spheres +LLSphere LLSphere::getBoundingSphere(const LLSphere& first_sphere, const LLSphere& second_sphere) +{ +	LLVector3 direction = second_sphere.mCenter - first_sphere.mCenter; + +	// HACK -- it is possible to get enough floating point error in the  +	// other getBoundingSphere() method that we have to add some slop +	// at the end.  Unfortunately, this breaks the link-order invarience +	// for the linkability tests... unless we also apply the same slop +	// here. +	F32 half_milimeter = 0.0005f; + +	F32 distance = direction.length(); +	if (0.f == distance) +	{ +		direction.setVec(1.f, 0.f, 0.f); +	} +	else +	{ +		direction.normVec(); +	} +	// the 'edge' is measured from the first_sphere's center +	F32 max_edge = 0.f; +	F32 min_edge = 0.f; + +	max_edge = llmax(max_edge + first_sphere.getRadius(), max_edge + distance + second_sphere.getRadius() + half_milimeter); +	min_edge = llmin(min_edge - first_sphere.getRadius(), min_edge + distance - second_sphere.getRadius() - half_milimeter); +	F32 radius = 0.5f * (max_edge - min_edge); +	LLVector3 center = first_sphere.mCenter + (0.5f * (max_edge + min_edge)) * direction; +	return LLSphere(center, radius); +} + +// static +// returns the bounding sphere that contains an arbitrary set of spheres +LLSphere LLSphere::getBoundingSphere(const std::vector<LLSphere>& sphere_list) +{ +	// this algorithm can get relatively inaccurate when the sphere  +	// collection is 'small' (contained within a bounding sphere of about  +	// 2 meters or less) +	// TODO -- improve the accuracy for small collections of spheres + +	LLSphere bounding_sphere( LLVector3(0.f, 0.f, 0.f), 0.f ); +	S32 sphere_count = sphere_list.size(); +	if (1 == sphere_count) +	{ +		// trivial case -- single sphere +		std::vector<LLSphere>::const_iterator sphere_itr = sphere_list.begin(); +		bounding_sphere = *sphere_itr; +	} +	else if (2 == sphere_count) +	{ +		// trivial case -- two spheres +		std::vector<LLSphere>::const_iterator first_sphere = sphere_list.begin(); +		std::vector<LLSphere>::const_iterator second_sphere = first_sphere; +		++second_sphere; +		bounding_sphere = LLSphere::getBoundingSphere(*first_sphere, *second_sphere); +	} +	else if (sphere_count > 0) +	{ +		// non-trivial case -- we will approximate the solution +		// +		// NOTE -- there is a fancy/fast way to do this for large  +		// numbers of arbirary N-dimensional spheres -- you can look it +		// up on the net.  We're dealing with 3D spheres at collection +		// sizes of 256 spheres or smaller, so we just use this +		// brute force method. + +		// TODO -- perhaps would be worthwile to test for the solution where +		// the largest spanning radius just happens to work.  That is, where +		// there are really two spheres that determine the bounding sphere, +		// and all others are contained therein. + +		// compute the AABB +		std::vector<LLSphere>::const_iterator first_itr = sphere_list.begin(); +		LLVector3 max_corner = first_itr->getCenter() + first_itr->getRadius() * LLVector3(1.f, 1.f, 1.f); +		LLVector3 min_corner = first_itr->getCenter() - first_itr->getRadius() * LLVector3(1.f, 1.f, 1.f); +		{ +			std::vector<LLSphere>::const_iterator sphere_itr = sphere_list.begin(); +			for (++sphere_itr; sphere_itr != sphere_list.end(); ++sphere_itr) +			{ +				LLVector3 center = sphere_itr->getCenter(); +				F32 radius = sphere_itr->getRadius(); +				for (S32 i=0; i<3; ++i) +				{ +					if (center.mV[i] + radius > max_corner.mV[i]) +					{ +						max_corner.mV[i] = center.mV[i] + radius; +					} +					if (center.mV[i] - radius < min_corner.mV[i]) +					{ +						min_corner.mV[i] = center.mV[i] - radius; +					} +				} +			} +		} + +		// get the starting center and radius from the AABB +		LLVector3 diagonal = max_corner - min_corner; +		F32 bounding_radius = 0.5f * diagonal.length(); +		LLVector3 bounding_center = 0.5f * (max_corner + min_corner); + +		// compute the starting step-size +		F32 minimum_radius = 0.5f * llmin(diagonal.mV[VX], llmin(diagonal.mV[VY], diagonal.mV[VZ])); +		F32 step_length = bounding_radius - minimum_radius; +		S32 step_count = 0; +		S32 max_step_count = 12; +		F32 half_milimeter = 0.0005f; + +		// wander the center around in search of tighter solutions +		S32 last_dx = 2;	// 2 is out of bounds --> no match +		S32 last_dy = 2; +		S32 last_dz = 2; + +		while (step_length > half_milimeter +				&& step_count < max_step_count) +		{ +			// the algorithm for testing the maximum radius could be expensive enough +			// that it makes sense to NOT duplicate testing when possible, so we keep +			// track of where we last tested, and only test the new points + +			S32 best_dx = 0; +			S32 best_dy = 0; +			S32 best_dz = 0; + +			// sample near the center of the box +			bool found_better_center = false; +			for (S32 dx = -1; dx < 2; ++dx) +			{ +				for (S32 dy = -1; dy < 2; ++dy) +				{ +					for (S32 dz = -1; dz < 2; ++dz) +					{ +						if (dx == 0 && dy == 0 && dz == 0) +						{ +							continue; +						} + +						// count the number of indecies that match the last_*'s +						S32 match_count = 0; +						if (last_dx == dx) ++match_count; +						if (last_dy == dy) ++match_count; +						if (last_dz == dz) ++match_count; +						if (match_count == 2) +						{ +							// we've already tested this point +							continue; +						} + +						LLVector3 center = bounding_center; +						center.mV[VX] += (F32) dx * step_length; +						center.mV[VY] += (F32) dy * step_length; +						center.mV[VZ] += (F32) dz * step_length; + +						// compute the radius of the bounding sphere +						F32 max_radius = 0.f; +						std::vector<LLSphere>::const_iterator sphere_itr; +						for (sphere_itr = sphere_list.begin(); sphere_itr != sphere_list.end(); ++sphere_itr) +						{ +							F32 radius = (sphere_itr->getCenter() - center).length() + sphere_itr->getRadius(); +							if (radius > max_radius) +							{ +								max_radius = radius; +							} +						} +						if (max_radius < bounding_radius) +						{ +							best_dx = dx; +							best_dy = dy; +							best_dz = dz; +							bounding_center = center; +							bounding_radius = max_radius; +							found_better_center = true; +						} +					} +				} +			} +			if (found_better_center) +			{ +				// remember where we came from so we can avoid retesting +				last_dx = -best_dx; +				last_dy = -best_dy; +				last_dz = -best_dz; +			} +			else +			{ +				// reduce the step size +				step_length *= 0.5f; +				//++step_count; +				// reset the last_*'s +				last_dx = 2;	// 2 is out of bounds --> no match +				last_dy = 2; +				last_dz = 2; +			} +		} + +		// HACK -- it is possible to get enough floating point error for the +		// bounding sphere to too small on the order of 10e-6, but we only need +		// it to be accurate to within about half a millimeter +		bounding_radius += half_milimeter; + +		// this algorithm can get relatively inaccurate when the sphere  +		// collection is 'small' (contained within a bounding sphere of about  +		// 2 meters or less) +		// TODO -- fix this +		/* debug code +		{ +			std::vector<LLSphere>::const_iterator sphere_itr; +			for (sphere_itr = sphere_list.begin(); sphere_itr != sphere_list.end(); ++sphere_itr) +			{ +				F32 radius = (sphere_itr->getCenter() - bounding_center).length() + sphere_itr->getRadius(); +				if (radius + 0.1f > bounding_radius) +				{ +					std::cout << " rad = " << radius << "  bounding - rad = " << (bounding_radius - radius) << std::endl; +				} +			} +			std::cout << "\n" << std::endl; +		} +		*/  + +		bounding_sphere.set(bounding_center, bounding_radius); +	} +	return bounding_sphere; +} + + diff --git a/indra/llmath/llsphere.h b/indra/llmath/llsphere.h new file mode 100644 index 0000000000..709406eb5e --- /dev/null +++ b/indra/llmath/llsphere.h @@ -0,0 +1,59 @@ +// llsphere.h +/** + * @file llsphere.cpp + * @author Andrew Meadows + * @brief Simple sphere implementation for basic geometric operations + * + * Copyright (c) 2001-$CurrentYear$, Linden Research, Inc. + * $License$ + */ + +#ifndef LL_SPHERE_H +#define LL_SPHERE_H + +#include "stdtypes.h" +#include "v3math.h" +#include <iostream> +#include <vector> + +class LLSphere +{ +public: +	LLSphere(); +	LLSphere( const LLVector3& center, F32 radius ); + +	void set( const LLVector3& center, F32 radius ); +	void setCenter( const LLVector3& center ); +	void setRadius( F32 radius ); + +	const LLVector3& getCenter() const; +	F32 getRadius() const; + +	// returns TRUE if this sphere completely contains other_sphere +	BOOL contains(const LLSphere& other_sphere) const; + +	// returns TRUE if this sphere overlaps other_sphere +	BOOL overlaps(const LLSphere& other_sphere) const; + +	// returns overlap distance +	// negative overlap is closest approach +	F32 getOverlap(const LLSphere& other_sphere) const; + +	// removes any spheres that are contained in others +	static void collapse(std::vector<LLSphere>& sphere_list); + +	// returns minimum sphere bounding sphere for a set of spheres +	static LLSphere getBoundingSphere(const LLSphere& first_sphere, const LLSphere& second_sphere); +	static LLSphere getBoundingSphere(const std::vector<LLSphere>& sphere_list); + +	bool operator==(const LLSphere& rhs) const; + +	friend std::ostream& operator<<( std::ostream& output_stream, const LLSphere& line ); + +protected: +	LLVector3 mCenter; +	F32 mRadius; +}; + + +#endif diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index 0c711cabcd..43b42bf182 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -2510,12 +2510,19 @@ bool LLVolumeParams::validate(U8 prof_curve, F32 prof_begin, F32 prof_end, F32 h  	return true;  } -#define MAX_INDEX 10000  S32 *LLVolume::getTriangleIndices(U32 &num_indices) const  { -	S32 index[MAX_INDEX]; +	S32 expected_num_triangle_indices = getNumTriangleIndices(); +	if (expected_num_triangle_indices > MAX_VOLUME_TRIANGLE_INDICES) +	{ +		// we don't allow LLVolumes with this many vertices +		llwarns << "Couldn't allocate triangle indices" << llendl; +		num_indices = 0; +		return NULL; +	} + +	S32* index = new S32[expected_num_triangle_indices];  	S32 count = 0; -	S32 *indices = NULL;  	// Let's do this totally diffently, as we don't care about faces...  	// Counter-clockwise triangles are forward facing... @@ -2529,6 +2536,9 @@ S32 *LLVolume::getTriangleIndices(U32 &num_indices) const  	size_s_out = getProfile().getTotalOut();  	size_t = getPath().mPath.size(); +	// NOTE -- if the construction of the triangles below ever changes +	// then getNumTriangleIndices() method may also have to be updated. +  	if (open)		/* Flawfinder: ignore */  	{  		if (hollow) @@ -2536,9 +2546,6 @@ S32 *LLVolume::getTriangleIndices(U32 &num_indices) const  			// Open hollow -- much like the closed solid, except we   			// we need to stitch up the gap between s=0 and s=size_s-1 -			if ( (size_t - 1) * (((size_s -1) * 6) + 6) >= MAX_INDEX) -				goto noindices; -  			for (t = 0; t < size_t - 1; t++)  			{  				// The outer face, first cut, and inner face @@ -2652,8 +2659,6 @@ S32 *LLVolume::getTriangleIndices(U32 &num_indices) const  					if (use_tri1a2)  					{ -						if (count + 3 >= MAX_INDEX) -							goto noindices;  						index[count++] = pt1 + i;  						index[count++] = pt1 + 1 + i;  						index[count++] = pt2 + i; @@ -2661,8 +2666,6 @@ S32 *LLVolume::getTriangleIndices(U32 &num_indices) const  					}  					else  					{ -						if (count + 3 >= MAX_INDEX) -							goto noindices;  						index[count++] = pt1 + i;  						index[count++] = pt2 - 1 + i;  						index[count++] = pt2 + i; @@ -2753,8 +2756,6 @@ S32 *LLVolume::getTriangleIndices(U32 &num_indices) const  					if (use_tri1a2)  					{ -						if (count + 3 >= MAX_INDEX) -							goto noindices;  						index[count++] = pt1;  						index[count++] = pt2;  						index[count++] = pt1 + 1; @@ -2762,8 +2763,6 @@ S32 *LLVolume::getTriangleIndices(U32 &num_indices) const  					}  					else  					{ -						if (count + 3 >= MAX_INDEX) -							goto noindices;  						index[count++] = pt1;  						index[count++] = pt2;  						index[count++] = pt2 - 1; @@ -2776,9 +2775,6 @@ S32 *LLVolume::getTriangleIndices(U32 &num_indices) const  		{  			// Open solid -			if ( (size_t - 1) * (((size_s -1) * 6) + 6) >= MAX_INDEX) -				goto noindices; -  			for (t = 0; t < size_t - 1; t++)  			{  				// Outer face + 1 cut face @@ -2808,8 +2804,6 @@ S32 *LLVolume::getTriangleIndices(U32 &num_indices) const  			// Do the top and bottom caps, if necessary  			if (path_open)  			{ -				if ( count + (size_s - 2) * 3 >= MAX_INDEX) -					goto noindices;  				for (s = 0; s < size_s - 2; s++)  				{  					index[count++] = s+1; @@ -2819,8 +2813,6 @@ S32 *LLVolume::getTriangleIndices(U32 &num_indices) const  				// We've got a top cap  				S32 offset = (size_t - 1)*size_s; -				if ( count + (size_s - 2) * 3 >= MAX_INDEX) -					goto noindices;  				for (s = 0; s < size_s - 2; s++)  				{  					// Inverted ordering from bottom cap. @@ -2836,8 +2828,6 @@ S32 *LLVolume::getTriangleIndices(U32 &num_indices) const  		// Closed hollow  		// Outer face -		if ( (size_t - 1) * (size_s_out - 1) * 6 >= MAX_INDEX) -			goto noindices;  		for (t = 0; t < size_t - 1; t++)  		{  			for (s = 0; s < size_s_out - 1; s++) @@ -2856,8 +2846,6 @@ S32 *LLVolume::getTriangleIndices(U32 &num_indices) const  		// Inner face  		// Invert facing from outer face -		if ( count + (size_t - 1) * ((size_s - 1) - size_s_out) * 6 >= MAX_INDEX) -			goto noindices;  		for (t = 0; t < size_t - 1; t++)  		{  			for (s = size_s_out; s < size_s - 1; s++) @@ -2962,8 +2950,6 @@ S32 *LLVolume::getTriangleIndices(U32 &num_indices) const  				if (use_tri1a2)  				{ -					if (count + 3 >= MAX_INDEX) -						goto noindices;  					index[count++] = pt1 + i;  					index[count++] = pt1 + 1 + i;  					index[count++] = pt2 + i; @@ -2971,8 +2957,6 @@ S32 *LLVolume::getTriangleIndices(U32 &num_indices) const  				}  				else  				{ -					if (count + 3 >= MAX_INDEX) -						goto noindices;  					index[count++] = pt1 + i;  					index[count++] = pt2 - 1 + i;  					index[count++] = pt2 + i; @@ -3063,8 +3047,6 @@ S32 *LLVolume::getTriangleIndices(U32 &num_indices) const  				if (use_tri1a2)  				{ -					if (count + 3 >= MAX_INDEX) -						goto noindices;  					index[count++] = pt1;  					index[count++] = pt2;  					index[count++] = pt1 + 1; @@ -3072,8 +3054,6 @@ S32 *LLVolume::getTriangleIndices(U32 &num_indices) const  				}  				else  				{ -					if (count + 3 >= MAX_INDEX) -						goto noindices;  					index[count++] = pt1;  					index[count++] = pt2;  					index[count++] = pt2 - 1; @@ -3085,8 +3065,6 @@ S32 *LLVolume::getTriangleIndices(U32 &num_indices) const  	else  	{  		// Closed solid.  Easy case. -		if ( (size_t - 1) * (size_s - 1) * 6 > MAX_INDEX) -			goto noindices;  		for (t = 0; t < size_t - 1; t++)  		{  			for (s = 0; s < size_s - 1; s++) @@ -3108,8 +3086,6 @@ S32 *LLVolume::getTriangleIndices(U32 &num_indices) const  		if (path_open)  		{  			// bottom cap -			if ( count + (size_s - 2 - 1) * 3 >= MAX_INDEX) -				goto noindices;  			for (s = 1; s < size_s - 2; s++)  			{  				index[count++] = s+1; @@ -3119,8 +3095,6 @@ S32 *LLVolume::getTriangleIndices(U32 &num_indices) const  			// top cap  			S32 offset = (size_t - 1)*size_s; -			if ( count + (size_s - 2 - 1) * 3 >= MAX_INDEX) -				goto noindices;  			for (s = 1; s < size_s - 2; s++)  			{  				// Inverted ordering from bottom cap. @@ -3131,7 +3105,18 @@ S32 *LLVolume::getTriangleIndices(U32 &num_indices) const  		}  	} +#ifdef LL_DEBUG +	// assert that we computed the correct number of indices +	if (count != expected_num_triangle_indices ) +	{ +		llerrs << "bad index count prediciton:" +			<< "  expected=" << expected_num_triangle_indices  +			<< " actual=" << count << llendl; +	} +#endif +  #if 0 +	// verify that each index does not point beyond the size of the mesh  	S32 num_vertices = mMesh.size();  	for (i = 0; i < count; i+=3)  	{ @@ -3142,17 +3127,65 @@ S32 *LLVolume::getTriangleIndices(U32 &num_indices) const  	}  #endif -	indices = new S32[count]; -noindices: -	if (!indices) +	num_indices = count; +	return index; +} + +S32 LLVolume::getNumTriangleIndices() const +{ +	BOOL profile_open = getProfile().isOpen(); +	BOOL hollow = getProfile().isHollow(); +	BOOL path_open = getPath().isOpen(); + +	S32 size_s, size_s_out, size_t; +	size_s = getProfile().getTotal(); +	size_s_out = getProfile().getTotalOut(); +	size_t = getPath().mPath.size(); + +	S32 count = 0; +	if (profile_open)		/* Flawfinder: ignore */  	{ -		llwarns << "Couldn't allocate triangle indices" << llendl; -		num_indices = 0; -		return NULL; +		if (hollow) +		{ +			// Open hollow -- much like the closed solid, except we  +			// we need to stitch up the gap between s=0 and s=size_s-1 +			count = (size_t - 1) * (((size_s -1) * 6) + 6); +		} +		else +		{ +			count = (size_t - 1) * (((size_s -1) * 6) + 6);  +		}  	} -	num_indices = count; -	memcpy(indices, index, count * sizeof(S32));		/* Flawfinder: ignore */ -	return indices; +	else if (hollow) +	{ +		// Closed hollow +		// Outer face +		count = (size_t - 1) * (size_s_out - 1) * 6; + +		// Inner face +		count += (size_t - 1) * ((size_s - 1) - size_s_out) * 6; +	} +	else +	{ +		// Closed solid.  Easy case. +		count = (size_t - 1) * (size_s - 1) * 6; +	} + +	if (path_open) +	{ +		S32 cap_triangle_count = size_s - 3; +		if ( profile_open +			|| hollow ) +		{ +			cap_triangle_count = size_s - 2; +		} +		if ( cap_triangle_count > 0 ) +		{ +			// top and bottom caps +			count += cap_triangle_count * 2 * 3; +		} +	} +	return count;  }  //----------------------------------------------------------------------------- @@ -3483,7 +3516,7 @@ struct lessTriangle  BOOL equalTriangle(const S32 *a, const S32 *b)  { -	if ((*a == *b) && (*(a+1) == *(b+1)) && ((*a+2) == (*b+2))) +	if ((*a == *b) && (*(a+1) == *(b+1)) && (*(a+2) == *(b+2)))  	{  		return TRUE;  	} @@ -3499,6 +3532,21 @@ BOOL LLVolume::cleanupTriangleData( const S32 num_input_vertices,  									S32 &num_output_triangles,  									S32 **output_triangles)  { +	/* Testing: avoid any cleanup +	num_output_vertices = num_input_vertices; +	num_output_triangles = num_input_triangles; + +	*output_vertices = new LLVector3[num_input_vertices]; +	for (S32 i = 0; i < num_input_vertices; i++) +	{ +		(*output_vertices)[i] = input_vertices[i].mPos; +	} + +	*output_triangles = new S32[num_input_triangles*3]; +	memcpy(*output_triangles, input_triangles, 3*num_input_triangles*sizeof(S32));		// Flawfinder: ignore +	return TRUE; +	*/ +  	// Here's how we do this:  	// Create a structure which contains the original vertex index and the  	// LLVector3 data. @@ -3549,7 +3597,7 @@ BOOL LLVolume::cleanupTriangleData( const S32 num_input_vertices,  		}  		else  		{ -			//llinfos << "Removed duplicate vertex " << pairp->mVertex << llendl; +			//llinfos << "Removed duplicate vertex " << pairp->mVertex << ", distance magVecSquared() is " << (pairp->mVertex - prev_pairp->mVertex).magVecSquared() << llendl;  		}  		vertex_mapping[pairp->mIndex] = new_num_vertices - 1;  	} @@ -3561,50 +3609,54 @@ BOOL LLVolume::cleanupTriangleData( const S32 num_input_vertices,  	for (i = 0; i < num_input_triangles; i++)  	{ -		//llinfos << "Checking triangle " << input_triangles[i*3] << ":" << input_triangles[i*3+1] << ":" << input_triangles[i*3+2] << llendl; -		input_triangles[i*3] = vertex_mapping[input_triangles[i*3]]; -		input_triangles[i*3+1] = vertex_mapping[input_triangles[i*3+1]]; -		input_triangles[i*3+2] = vertex_mapping[input_triangles[i*3+2]]; +		S32 v1 = i*3; +		S32 v2 = i*3 + 1; +		S32 v3 = i*3 + 2; + +		//llinfos << "Checking triangle " << input_triangles[v1] << ":" << input_triangles[v2] << ":" << input_triangles[v3] << llendl; +		input_triangles[v1] = vertex_mapping[input_triangles[v1]]; +		input_triangles[v2] = vertex_mapping[input_triangles[v2]]; +		input_triangles[v3] = vertex_mapping[input_triangles[v3]]; -		if ((input_triangles[i*3] == input_triangles[i*3+1]) -			|| (input_triangles[i*3] == input_triangles[i*3+2]) -			|| (input_triangles[i*3+1] == input_triangles[i*3+2])) +		if ((input_triangles[v1] == input_triangles[v2]) +			|| (input_triangles[v1] == input_triangles[v3]) +			|| (input_triangles[v2] == input_triangles[v3]))  		{ -			//llinfos << "Removing degenerate triangle " << input_triangles[i*3] << ":" << input_triangles[i*3+1] << ":" << input_triangles[i*3+2] << llendl; +			//llinfos << "Removing degenerate triangle " << input_triangles[v1] << ":" << input_triangles[v2] << ":" << input_triangles[v3] << llendl;  			// Degenerate triangle, skip  			continue;  		} -		if (input_triangles[i*3] < input_triangles[i*3+1]) +		if (input_triangles[v1] < input_triangles[v2])  		{ -			if (input_triangles[i*3] < input_triangles[i*3+2]) +			if (input_triangles[v1] < input_triangles[v3])  			{  				// (0 < 1) && (0 < 2) -				new_triangles[new_num_triangles*3] = input_triangles[i*3]; -				new_triangles[new_num_triangles*3+1] = input_triangles[i*3+1]; -				new_triangles[new_num_triangles*3+2] = input_triangles[i*3+2]; +				new_triangles[new_num_triangles*3] = input_triangles[v1]; +				new_triangles[new_num_triangles*3+1] = input_triangles[v2]; +				new_triangles[new_num_triangles*3+2] = input_triangles[v3];  			}  			else  			{  				// (0 < 1) && (2 < 0) -				new_triangles[new_num_triangles*3] = input_triangles[i*3+2]; -				new_triangles[new_num_triangles*3+1] = input_triangles[i*3]; -				new_triangles[new_num_triangles*3+2] = input_triangles[i*3+1]; +				new_triangles[new_num_triangles*3] = input_triangles[v3]; +				new_triangles[new_num_triangles*3+1] = input_triangles[v1]; +				new_triangles[new_num_triangles*3+2] = input_triangles[v2];  			}  		} -		else if (input_triangles[i*3+1] < input_triangles[i*3+2]) +		else if (input_triangles[v2] < input_triangles[v3])  		{  			// (1 < 0) && (1 < 2) -			new_triangles[new_num_triangles*3] = input_triangles[i*3+1]; -			new_triangles[new_num_triangles*3+1] = input_triangles[i*3+2]; -			new_triangles[new_num_triangles*3+2] = input_triangles[i*3]; +			new_triangles[new_num_triangles*3] = input_triangles[v2]; +			new_triangles[new_num_triangles*3+1] = input_triangles[v3]; +			new_triangles[new_num_triangles*3+2] = input_triangles[v1];  		}  		else  		{  			// (1 < 0) && (2 < 1) -			new_triangles[new_num_triangles*3] = input_triangles[i*3+2]; -			new_triangles[new_num_triangles*3+1] = input_triangles[i*3]; -			new_triangles[new_num_triangles*3+2] = input_triangles[i*3+1]; +			new_triangles[new_num_triangles*3] = input_triangles[v3]; +			new_triangles[new_num_triangles*3+1] = input_triangles[v1]; +			new_triangles[new_num_triangles*3+2] = input_triangles[v2];  		}  		new_num_triangles++;  	} @@ -3845,23 +3897,44 @@ void LLVolumeParams::reduceT(F32 begin, F32 end)  	mPathParams.setEnd(a + end * (b - a));  } +const F32 MIN_CONCAVE_PROFILE_WEDGE = 0.125f;	// 1/8 unity +const F32 MIN_CONCAVE_PATH_WEDGE = 0.111111f;	// 1/9 unity + +// returns TRUE if the shape can be approximated with a convex shape  +// for collison purposes  BOOL LLVolumeParams::isConvex() const  { -	// The logic for determining convexity is a little convoluted. +	F32 path_length = mPathParams.getEnd() - mPathParams.getBegin(); -	// Do we need to take getTwistBegin into account?  DK 08/12/04 -	if (   mProfileParams.getHollow() != 0.0f  -		|| mPathParams.getTwist() != mPathParams.getTwistBegin() ) +	if ( mPathParams.getTwist() != mPathParams.getTwistBegin() +		&& path_length > MIN_CONCAVE_PATH_WEDGE )  	{ -		// hollow or twist gaurantees concavity +		// twist along a "not too short" path is concave  		return FALSE;  	}  	F32 profile_length = mProfileParams.getEnd() - mProfileParams.getBegin(); -	BOOL concave_profile = (profile_length < 1.0f) && (profile_length > 0.5f); -	if (concave_profile) +	F32 hollow = mProfileParams.getHollow(); +	BOOL same_hole = hollow == 0.f  +					 || (mProfileParams.getCurveType() & LL_PCODE_HOLE_MASK) == LL_PCODE_HOLE_SAME; + +	F32 min_profile_wedge = MIN_CONCAVE_PROFILE_WEDGE; +	U8 profile_type = mProfileParams.getCurveType() & LL_PCODE_PROFILE_MASK; +	if ( LL_PCODE_PROFILE_CIRCLE_HALF == profile_type )  	{ -		// concave profile +		// it is a sphere and spheres get twice the minimum profile wedge +		min_profile_wedge = 2.f * MIN_CONCAVE_PROFILE_WEDGE; +	} + +	BOOL convex_profile = ( ( profile_length == 1.f +						     || profile_length <= 0.5f ) +						   && hollow == 0.f )						// trivially convex +						  || ( profile_length <= min_profile_wedge +							  && same_hole );						// effectvely convex (even when hollow) + +	if (!convex_profile) +	{ +		// profile is concave  		return FALSE;  	} @@ -3872,7 +3945,6 @@ BOOL LLVolumeParams::isConvex() const  		return TRUE;  	} -	F32 path_length = mPathParams.getEnd() - mPathParams.getBegin();  	BOOL concave_path = (path_length < 1.0f) && (path_length > 0.5f);  	if (concave_path)  	{ @@ -3880,17 +3952,43 @@ BOOL LLVolumeParams::isConvex() const  	}  	// we're left with spheres, toroids and tubes -	// only the spheres can be convex -	U8 profile_type = mProfileParams.getCurveType() & LL_PCODE_PROFILE_MASK;  	if ( LL_PCODE_PROFILE_CIRCLE_HALF == profile_type )  	{ +		// at this stage all spheres must be convex  		return TRUE;  	}  	// it's a toroid or tube		 +	if ( path_length <= MIN_CONCAVE_PATH_WEDGE ) +	{ +		// effectively convex +		return TRUE; +	} +  	return FALSE;  } +// debug +void LLVolumeParams::setCube() +{ +	mProfileParams.setCurveType(LL_PCODE_PROFILE_SQUARE); +	mProfileParams.setBegin(0.f); +	mProfileParams.setEnd(1.f); +	mProfileParams.setHollow(0.f); + +	mPathParams.setBegin(0.f); +	mPathParams.setEnd(1.f); +	mPathParams.setScale(1.f, 1.f); +	mPathParams.setShear(0.f, 0.f); +	mPathParams.setCurveType(LL_PCODE_PATH_LINE); +	mPathParams.setTwistBegin(0.f); +	mPathParams.setTwistEnd(0.f); +	mPathParams.setRadiusOffset(0.f); +	mPathParams.setTaper(0.f, 0.f); +	mPathParams.setRevolutions(0.f); +	mPathParams.setSkew(0.f); +} +  LLFaceID LLVolume::generateFaceMask()  {  	LLFaceID new_mask = 0x0000; diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h index 9af02d2629..a1eba9de38 100644 --- a/indra/llmath/llvolume.h +++ b/indra/llmath/llvolume.h @@ -72,6 +72,8 @@ const F32 TAPER_QUANTA  = 0.01f;  const F32 REV_QUANTA    = 0.015f;  const F32 HOLLOW_QUANTA = 0.00002f; +const S32 MAX_VOLUME_TRIANGLE_INDICES = 10000; +  //============================================================================  // useful masks @@ -187,10 +189,10 @@ class LLProfileParams  public:  	LLProfileParams()  	{ -		mBegin     = 0; -		mEnd       = 1; -		mHollow    = 0;  		mCurveType = LL_PCODE_PROFILE_SQUARE; +		mBegin     = 0.f; +		mEnd       = 1.f; +		mHollow    = 0.f;  	}  	LLProfileParams(U8 curve, F32 begin, F32 end, F32 hollow) @@ -307,17 +309,17 @@ class LLPathParams  public:  	LLPathParams()  	{ -		mBegin     = 0; -		mEnd       = 1; -		mScale.setVec(1,1); -		mShear.setVec(0,0); +		mBegin     = 0.f; +		mEnd       = 1.f; +		mScale.setVec(1.f,1.f); +		mShear.setVec(0.f,0.f);  		mCurveType = LL_PCODE_PATH_LINE; -		mTwistBegin		= 0; -		mTwistEnd     	= 0; -		mRadiusOffset	= 0; -		mTaper.setVec(0,0); -		mRevolutions	= 1; -		mSkew			= 0; +		mTwistBegin		= 0.f; +		mTwistEnd     	= 0.f; +		mRadiusOffset	= 0.f; +		mTaper.setVec(0.f,0.f); +		mRevolutions	= 1.f; +		mSkew			= 0.f;  	}  	LLPathParams(U8 curve, F32 begin, F32 end, F32 scx, F32 scy, F32 shx, F32 shy, F32 twistend, F32 twistbegin, F32 radiusoffset, F32 tx, F32 ty, F32 revolutions, F32 skew) @@ -627,6 +629,9 @@ public:  	friend std::ostream& operator<<(std::ostream &s, const LLVolumeParams &volume_params); +	// debug helper functions +	void setCube(); +  protected:  	LLProfileParams mProfileParams;  	LLPathParams	mPathParams; @@ -869,6 +874,10 @@ public:  	S32 getSculptLevel() const                              { return mSculptLevel; }  	S32 *getTriangleIndices(U32 &num_indices) const; + +	// returns number of triangle indeces required for path/profile mesh +	S32 getNumTriangleIndices() const; +  	void generateSilhouetteVertices(std::vector<LLVector3> &vertices, std::vector<LLVector3> &normals, std::vector<S32> &segments, const LLVector3& view_vec,  											  const LLMatrix4& mat,  										  const LLMatrix3& norm_mat); diff --git a/indra/llmath/llvolumemgr.cpp b/indra/llmath/llvolumemgr.cpp index 1a448ed8e0..f3a6b7d157 100644 --- a/indra/llmath/llvolumemgr.cpp +++ b/indra/llmath/llvolumemgr.cpp @@ -36,7 +36,7 @@  //#define DEBUG_VOLUME -LLVolumeMgr* gVolumeMgr = 0; +//LLVolumeMgr* gVolumeMgr = 0;  const F32 BASE_THRESHOLD = 0.03f; @@ -49,37 +49,23 @@ F32 LLVolumeLODGroup::mDetailThresholds[NUM_LODS] = {BASE_THRESHOLD,  //static  F32 LLVolumeLODGroup::mDetailScales[NUM_LODS] = {1.f, 1.5f, 2.5f, 4.f}; -//============================================================================ -//static -void LLVolumeMgr::initClass() -{ -	gVolumeMgr = new LLVolumeMgr(); -} - -//static -BOOL LLVolumeMgr::cleanupClass() -{ -	BOOL res = FALSE; -	if (gVolumeMgr) { -		res = gVolumeMgr->cleanup(); -		delete gVolumeMgr; -		gVolumeMgr = 0; -	} -	return res; -}  //============================================================================  LLVolumeMgr::LLVolumeMgr() +:	mDataMutex(NULL)  { -	mDataMutex = new LLMutex(gAPRPoolp); -//	mNumVolumes = 0; +	// the LLMutex magic interferes with easy unit testing, +	// so you now must manually call useMutex() to use it +	//mDataMutex = new LLMutex(gAPRPoolp);  }  LLVolumeMgr::~LLVolumeMgr()  {  	cleanup(); +  	delete mDataMutex; +	mDataMutex = NULL;  }  BOOL LLVolumeMgr::cleanup() @@ -90,7 +76,10 @@ BOOL LLVolumeMgr::cleanup()  	}  	#endif  	BOOL no_refs = TRUE; -	mDataMutex->lock(); +	if (mDataMutex) +	{ +		mDataMutex->lock(); +	}  	for (volume_lod_group_map_t::iterator iter = mVolumeLODGroups.begin(),  			 end = mVolumeLODGroups.end();  		 iter != end; iter++) @@ -106,29 +95,37 @@ BOOL LLVolumeMgr::cleanup()   		volgroupp->unref();// this );  	}  	mVolumeLODGroups.clear(); -	mDataMutex->unlock(); +	if (mDataMutex) +	{ +		mDataMutex->unlock(); +	}  	return no_refs;  } +// whatever calls getVolume() never owns the LLVolume* and +// cannot keep references for long since it may be deleted +// later.  For best results hold it in an LLPointer<LLVolume>.  LLVolume *LLVolumeMgr::getVolume(const LLVolumeParams &volume_params, const S32 detail)  {  	LLVolumeLODGroup* volgroupp; -	mDataMutex->lock(); +	if (mDataMutex) +	{ +		mDataMutex->lock(); +	}  	volume_lod_group_map_t::iterator iter = mVolumeLODGroups.find(&volume_params);  	if( iter == mVolumeLODGroups.end() )  	{ -		volgroupp = new LLVolumeLODGroup(volume_params); -		const LLVolumeParams* params = &(volgroupp->getParams()); -		mVolumeLODGroups[params] = volgroupp; - 		volgroupp->ref(); // initial reference +		volgroupp = createNewGroup(volume_params);  	}  	else  	{  		volgroupp = iter->second;  	} -	volgroupp->ref();// this ); -	mDataMutex->unlock(); -	//	mNumVolumes++; +	volgroupp->ref(); +	if (mDataMutex) +	{ +		mDataMutex->unlock(); +	}  	#ifdef DEBUG_VOLUME  	{  		lldebugs << "LLVolumeMgr::getVolume() " << (*this) << llendl; @@ -137,6 +134,27 @@ LLVolume *LLVolumeMgr::getVolume(const LLVolumeParams &volume_params, const S32  	return volgroupp->getLOD(detail);  } +// virtual +LLVolumeLODGroup* LLVolumeMgr::getGroup( const LLVolumeParams& volume_params ) const +{ +	LLVolumeLODGroup* volgroupp = NULL; +	if (mDataMutex) +	{ +		mDataMutex->lock(); +	} +	volume_lod_group_map_t::const_iterator iter = mVolumeLODGroups.find(&volume_params); +	if( iter != mVolumeLODGroups.end() ) +	{ +		volgroupp = iter->second; +	} +	if (mDataMutex) +	{ +		mDataMutex->unlock(); +	} +	return volgroupp; +} + +// virtual  void LLVolumeMgr::cleanupVolume(LLVolume *volumep)  {  	if (volumep->isUnique()) @@ -145,12 +163,18 @@ void LLVolumeMgr::cleanupVolume(LLVolume *volumep)  		return;  	}  	LLVolumeParams* params = (LLVolumeParams*) &(volumep->getParams()); -	mDataMutex->lock(); +	if (mDataMutex) +	{ +		mDataMutex->lock(); +	}  	volume_lod_group_map_t::iterator iter = mVolumeLODGroups.find(params);  	if( iter == mVolumeLODGroups.end() )  	{  		llerrs << "Warning! Tried to cleanup unknown volume type! " << *params << llendl; -		mDataMutex->unlock(); +		if (mDataMutex) +		{ +			mDataMutex->unlock(); +		}  		return;  	}  	else @@ -164,9 +188,11 @@ void LLVolumeMgr::cleanupVolume(LLVolume *volumep)  			mVolumeLODGroups.erase(params);  			volgroupp->unref();// this );  		} -		//	mNumVolumes--;  	} -	mDataMutex->unlock(); +	if (mDataMutex) +	{ +		mDataMutex->unlock(); +	}  	#ifdef DEBUG_VOLUME  	{ @@ -175,10 +201,43 @@ void LLVolumeMgr::cleanupVolume(LLVolume *volumep)  	#endif  } +#ifdef DEBUG_VOLUME +S32 LLVolumeMgr::getTotalRefCount() const +{ +	S32 total_ref_count = 0; +	for ( volume_lod_group_map_t::const_iterator iter = mVolumeLODGroups.begin(), +			 end = mVolumeLODGroups.end(); +		 iter != end; iter++) +	{ +		total_ref_count += iter->second->getTotalVolumeRefCount(); +	} +	return total_ref_count; +} + +S32 LLVolumeMgr::getGroupCount() const +{ +	return mVolumeLODGroups.size(); +} +#endif + +// protected +LLVolumeLODGroup* LLVolumeMgr::createNewGroup(const LLVolumeParams& volume_params) +{ +	LLVolumeLODGroup* group = new LLVolumeLODGroup(volume_params); +	const LLVolumeParams* params = &(group->getParams()); +	mVolumeLODGroups[params] = group; + 	group->ref(); // initial reference +	return group; +} + +// virtual  void LLVolumeMgr::dump()  {  	F32 avg = 0.f; -	mDataMutex->lock(); +	if (mDataMutex) +	{ +		mDataMutex->lock(); +	}  	for (volume_lod_group_map_t::iterator iter = mVolumeLODGroups.begin(),  			 end = mVolumeLODGroups.end();  		 iter != end; iter++) @@ -188,16 +247,30 @@ void LLVolumeMgr::dump()  	}  	int count = (int)mVolumeLODGroups.size();  	avg = count ? avg / (F32)count : 0.0f; -	mDataMutex->unlock(); +	if (mDataMutex) +	{ +		mDataMutex->unlock(); +	}  	llinfos << "Average usage of LODs " << avg << llendl;  } +void LLVolumeMgr::useMutex() +{  +	if (!mDataMutex) +	{ +		mDataMutex = new LLMutex(gAPRPoolp); +	} +} +  std::ostream& operator<<(std::ostream& s, const LLVolumeMgr& volume_mgr)  {  	s << "{ numLODgroups=" << volume_mgr.mVolumeLODGroups.size() << ", ";  	S32 total_refs = 0; -	volume_mgr.mDataMutex->lock(); +	if (volume_mgr.mDataMutex) +	{ +		volume_mgr.mDataMutex->lock(); +	}  	LLVolumeMgr::volume_lod_group_map_iter iter = volume_mgr.mVolumeLODGroups.begin();  	LLVolumeMgr::volume_lod_group_map_iter end  = volume_mgr.mVolumeLODGroups.end(); @@ -208,7 +281,10 @@ std::ostream& operator<<(std::ostream& s, const LLVolumeMgr& volume_mgr)  		s << ", " << (*volgroupp);  	} -	volume_mgr.mDataMutex->unlock(); +	if (volume_mgr.mDataMutex) +	{ +		volume_mgr.mDataMutex->unlock(); +	}  	s << ", total_refs=" << total_refs << " }";  	return s; @@ -222,15 +298,39 @@ LLVolumeLODGroup::LLVolumeLODGroup(const LLVolumeParams ¶ms)  	for (i = 0; i < NUM_LODS; i++)  	{  		mLODRefs[i] = 0; -		mVolumeLODs[i] = NULL; +		// no need to initialize mVolumeLODs, they are smart pointers +		//mVolumeLODs[i] = NULL;  		mAccessCount[i] = 0;  	}  } +#ifdef DEBUG_VOLUME +S32 LLVolumeLODGroup::getTotalVolumeRefCount() const +{ +	S32 total_ref_count = 0; +	for (S32 i = 0; i < NUM_LODS; i++) +	{ +		total_ref_count += mLODRefs[i]; +	} +	return total_ref_count; +} +#endif + +// protected  LLVolumeLODGroup::~LLVolumeLODGroup()  { +	destroy();  } +// protected +void LLVolumeLODGroup::destroy() +{ +	for (S32 i = 0; i < NUM_LODS; i++) +	{ +		// remember that mVolumeLODs are smart pointers! +		mVolumeLODs[i] = NULL; +	} +}  LLVolume * LLVolumeLODGroup::getLOD(const S32 detail)  { @@ -242,7 +342,7 @@ LLVolume * LLVolumeLODGroup::getLOD(const S32 detail)  		mVolumeLODs[detail] = new LLVolume(mParams, mDetailScales[detail]);  	}  	mLODRefs[detail]++; -	return mVolumeLODs[detail]; +	return mVolumeLODs[detail].get();  }  BOOL LLVolumeLODGroup::derefLOD(LLVolume *volumep) diff --git a/indra/llmath/llvolumemgr.h b/indra/llmath/llvolumemgr.h index f3d4b5ee6b..c28ffce631 100644 --- a/indra/llmath/llvolumemgr.h +++ b/indra/llmath/llvolumemgr.h @@ -43,9 +43,6 @@ class LLVolumeLODGroup;  class LLVolumeLODGroup : public LLThreadSafeRefCount  { -protected: -	~LLVolumeLODGroup(); -	  public:  	enum  	{ @@ -60,11 +57,19 @@ public:  	static F32 getVolumeScaleFromDetail(const S32 detail);  	LLVolume *getLOD(const S32 detail); -	const LLVolumeParams &getParams() const { return mParams; }; +	const LLVolumeParams& getParams() const { return mParams; };  	F32	dump();  	friend std::ostream& operator<<(std::ostream& s, const LLVolumeLODGroup& volgroup); +#ifdef DEBUG_VOLUME +	S32 getTotalVolumeRefCount() const; +#endif + +protected: +	virtual ~LLVolumeLODGroup(); +	void destroy(); +	  protected:  	LLVolumeParams mParams; @@ -77,30 +82,50 @@ protected:  class LLVolumeMgr  { -public: -	static void initClass(); -	static BOOL cleanupClass(); +//public: +//	static void initClass(); +//	static BOOL cleanupClass();  public:  	LLVolumeMgr(); -	~LLVolumeMgr(); +	virtual ~LLVolumeMgr();  	BOOL cleanup();			// Cleanup all volumes being managed, returns TRUE if no dangling references + +	virtual LLVolumeLODGroup* getGroup( const LLVolumeParams& volume_params ) const; + +	// whatever calls getVolume() never owns the LLVolume* and +	// cannot keep references for long since it may be deleted +	// later.  For best results hold it in an LLPointer<LLVolume>.  	LLVolume *getVolume(const LLVolumeParams &volume_params, const S32 detail); +  	void cleanupVolume(LLVolume *volumep);  	void dump(); + +	// manually call this for mutex magic +	void useMutex(); + +#ifdef DEBUG_VOLUME +	S32 getTotalRefCount() const; +	S32 getGroupCount() const; +#endif  	friend std::ostream& operator<<(std::ostream& s, const LLVolumeMgr& volume_mgr);  protected: +	virtual LLVolumeLODGroup* createNewGroup(const LLVolumeParams& volume_params); + +protected:  	typedef std::map<const LLVolumeParams*, LLVolumeLODGroup*, LLVolumeParams::compare> volume_lod_group_map_t;  	typedef volume_lod_group_map_t::const_iterator volume_lod_group_map_iter;  	volume_lod_group_map_t mVolumeLODGroups;  	LLMutex* mDataMutex; -	 -//	S32 mNumVolumes; + +	// We need to be able to disable threadsafe checks to prevent  +	// some unit_tests from blocking on failure +	bool mThreadSafe;  }; -extern LLVolumeMgr* gVolumeMgr; +//extern LLVolumeMgr* gVolumeMgr;  #endif // LL_LLVOLUMEMGR_H diff --git a/indra/llmath/m3math.cpp b/indra/llmath/m3math.cpp index d4f99cb8c9..184b87c000 100644 --- a/indra/llmath/m3math.cpp +++ b/indra/llmath/m3math.cpp @@ -136,7 +136,7 @@ void LLMatrix3::getEulerAngles(F32 *roll, F32 *pitch, F32 *yaw) const  // Clear and Assignment Functions -const LLMatrix3&	LLMatrix3::identity() +const LLMatrix3&	LLMatrix3::setIdentity()  {  	mMatrix[0][0] = 1.f;  	mMatrix[0][1] = 0.f; @@ -152,7 +152,23 @@ const LLMatrix3&	LLMatrix3::identity()  	return (*this);  } -const LLMatrix3&	LLMatrix3::zero() +const LLMatrix3&	LLMatrix3::clear() +{ +	mMatrix[0][0] = 0.f; +	mMatrix[0][1] = 0.f; +	mMatrix[0][2] = 0.f; + +	mMatrix[1][0] = 0.f; +	mMatrix[1][1] = 0.f; +	mMatrix[1][2] = 0.f; + +	mMatrix[2][0] = 0.f; +	mMatrix[2][1] = 0.f; +	mMatrix[2][2] = 0.f; +	return (*this); +} + +const LLMatrix3&	LLMatrix3::setZero()  {  	mMatrix[0][0] = 0.f;  	mMatrix[0][1] = 0.f; @@ -190,15 +206,26 @@ F32		LLMatrix3::determinant() const  		  	mMatrix[0][2] * (mMatrix[1][0] * mMatrix[2][1] - mMatrix[1][1] * mMatrix[2][0]);   } -// This is identical to the transMat3() method because we assume a rotation matrix -const LLMatrix3&	LLMatrix3::invert() +// inverts this matrix +void LLMatrix3::invert()  { -	// transpose the matrix -	F32 temp; -	temp = mMatrix[VX][VY]; mMatrix[VX][VY] = mMatrix[VY][VX]; mMatrix[VY][VX] = temp; -	temp = mMatrix[VX][VZ]; mMatrix[VX][VZ] = mMatrix[VZ][VX]; mMatrix[VZ][VX] = temp; -	temp = mMatrix[VY][VZ]; mMatrix[VY][VZ] = mMatrix[VZ][VY]; mMatrix[VZ][VY] = temp; -	return *this; +	// fails silently if determinant is zero too small +	F32 det = determinant(); +	const F32 VERY_SMALL_DETERMINANT = 0.000001f; +	if (fabs(det) > VERY_SMALL_DETERMINANT) +	{ +		// invertiable +		LLMatrix3 t(*this); +		mMatrix[VX][VX] = ( t.mMatrix[VY][VY] * t.mMatrix[VZ][VZ] - t.mMatrix[VY][VZ] * t.mMatrix[VZ][VY] ) / det; +		mMatrix[VY][VX] = ( t.mMatrix[VY][VZ] * t.mMatrix[VZ][VX] - t.mMatrix[VY][VX] * t.mMatrix[VZ][VZ] ) / det; +		mMatrix[VZ][VX] = ( t.mMatrix[VY][VX] * t.mMatrix[VZ][VY] - t.mMatrix[VY][VY] * t.mMatrix[VZ][VX] ) / det; +		mMatrix[VX][VY] = ( t.mMatrix[VZ][VY] * t.mMatrix[VX][VZ] - t.mMatrix[VZ][VZ] * t.mMatrix[VX][VY] ) / det; +		mMatrix[VY][VY] = ( t.mMatrix[VZ][VZ] * t.mMatrix[VX][VX] - t.mMatrix[VZ][VX] * t.mMatrix[VX][VZ] ) / det; +		mMatrix[VZ][VY] = ( t.mMatrix[VZ][VX] * t.mMatrix[VX][VY] - t.mMatrix[VZ][VY] * t.mMatrix[VX][VX] ) / det; +		mMatrix[VX][VZ] = ( t.mMatrix[VX][VY] * t.mMatrix[VY][VZ] - t.mMatrix[VX][VZ] * t.mMatrix[VY][VY] ) / det; +		mMatrix[VY][VZ] = ( t.mMatrix[VX][VZ] * t.mMatrix[VY][VX] - t.mMatrix[VX][VX] * t.mMatrix[VY][VZ] ) / det; +		mMatrix[VZ][VZ] = ( t.mMatrix[VX][VX] * t.mMatrix[VY][VY] - t.mMatrix[VX][VY] * t.mMatrix[VY][VX] ) / det; +	}  }  // does not assume a rotation matrix, and does not divide by determinant, assuming results will be renormalized @@ -351,6 +378,27 @@ const LLMatrix3&	LLMatrix3::setRows(const LLVector3 &fwd, const LLVector3 &left,  	return *this;  } +const LLMatrix3& LLMatrix3::setRow( U32 rowIndex, const LLVector3& row ) +{ +	llassert( rowIndex >= 0 && rowIndex < NUM_VALUES_IN_MAT3 ); + +	mMatrix[rowIndex][0] = row[0]; +	mMatrix[rowIndex][1] = row[1]; +	mMatrix[rowIndex][2] = row[2]; + +	return *this; +} + +const LLMatrix3& LLMatrix3::setCol( U32 colIndex, const LLVector3& col ) +{ +	llassert( colIndex >= 0 && colIndex < NUM_VALUES_IN_MAT3 ); + +	mMatrix[0][colIndex] = col[0]; +	mMatrix[1][colIndex] = col[1]; +	mMatrix[2][colIndex] = col[2]; + +	return *this; +}  // Rotate exisitng mMatrix  const LLMatrix3&	LLMatrix3::rotate(const F32 angle, const F32 x, const F32 y, const F32 z) @@ -384,6 +432,16 @@ const LLMatrix3&	LLMatrix3::rotate(const LLQuaternion &q)  	return *this;  } +void LLMatrix3::add(const LLMatrix3& other_matrix) +{ +	for (S32 i = 0; i < 3; ++i) +	{ +		for (S32 j = 0; j < 3; ++j) +		{ +			mMatrix[i][j] += other_matrix.mMatrix[i][j]; +		} +	} +}  LLVector3	LLMatrix3::getFwdRow() const  { @@ -536,6 +594,19 @@ const LLMatrix3& operator*=(LLMatrix3 &a, const LLMatrix3 &b)  	return a;  } +const LLMatrix3& operator*=(LLMatrix3 &a, F32 scalar ) +{ +	for( U32 i = 0; i < NUM_VALUES_IN_MAT3; ++i ) +	{ +		for( U32 j = 0; j < NUM_VALUES_IN_MAT3; ++j ) +		{ +			a.mMatrix[i][j] *= scalar; +		} +	} + +	return a; +} +  std::ostream& operator<<(std::ostream& s, const LLMatrix3 &a)   {  	s << "{ "  diff --git a/indra/llmath/m3math.h b/indra/llmath/m3math.h index d2848aaf5a..5f37456f51 100644 --- a/indra/llmath/m3math.h +++ b/indra/llmath/m3math.h @@ -33,6 +33,7 @@  #define LL_M3MATH_H  #include "llerror.h" +#include "stdtypes.h"  class LLVector4;  class LLVector3; @@ -76,8 +77,9 @@ class LLMatrix3  		//  		// various useful matrix functions -		const LLMatrix3& identity();				// Load identity matrix -		const LLMatrix3& zero();					// Clears Matrix to zero +		const LLMatrix3& setIdentity();				// Load identity matrix +		const LLMatrix3& clear();					// Clears Matrix to zero +		const LLMatrix3& setZero();					// Clears Matrix to zero  		///////////////////////////  		// @@ -91,6 +93,9 @@ class LLMatrix3  		const LLMatrix3& setRot(const LLQuaternion &q);			// Transform matrix by Euler angles and translating by pos  		const LLMatrix3& setRows(const LLVector3 &x_axis, const LLVector3 &y_axis, const LLVector3 &z_axis); +		const LLMatrix3& setRow( U32 rowIndex, const LLVector3& row ); +		const LLMatrix3& setCol( U32 colIndex, const LLVector3& col ); +  		///////////////////////////  		// @@ -103,29 +108,31 @@ class LLMatrix3  		LLVector3 getFwdRow() const;  		LLVector3 getLeftRow() const;  		LLVector3 getUpRow() const; -		F32	 determinant() const;						// Return determinant +		F32	 determinant() const;			// Return determinant  		///////////////////////////  		//  		// Operations on an existing matrix  		// -		const LLMatrix3& transpose();					// Transpose MAT4 -		const LLMatrix3& invert();					// Invert MAT4 -		const LLMatrix3& orthogonalize();						// Orthogonalizes X, then Y, then Z -		const LLMatrix3& adjointTranspose();		// returns transpose of matrix adjoint, for multiplying normals +		const LLMatrix3& transpose();		// Transpose MAT4 +		const LLMatrix3& orthogonalize();	// Orthogonalizes X, then Y, then Z +		void invert();			// Invert MAT4 +		const LLMatrix3& adjointTranspose();// returns transpose of matrix adjoint, for multiplying normals  		// Rotate existing matrix    		// Note: the two lines below are equivalent:  		//	foo.rotate(bar)   		//	foo = foo * bar -		// That is, foo.rotMat3(bar) multiplies foo by bar FROM THE RIGHT +		// That is, foo.rotate(bar) multiplies foo by bar FROM THE RIGHT  		const LLMatrix3& rotate(const F32 angle, const F32 x, const F32 y, const F32 z); 	// Rotate matrix by rotating angle radians about (x, y, z)  		const LLMatrix3& rotate(const F32 angle, const LLVector3 &vec);						// Rotate matrix by rotating angle radians about vec  		const LLMatrix3& rotate(const F32 roll, const F32 pitch, const F32 yaw); 			// Rotate matrix by roll (about x), pitch (about y), and yaw (about z)  		const LLMatrix3& rotate(const LLQuaternion &q);			// Transform matrix by Euler angles and translating by pos +		void add(const LLMatrix3& other_matrix);	// add other_matrix to this one +  // This operator is misleading as to operation direction  //		friend LLVector3 operator*(const LLMatrix3 &a, const LLVector3 &b);			// Apply rotation a to vector b @@ -137,6 +144,7 @@ class LLMatrix3  		friend bool operator!=(const LLMatrix3 &a, const LLMatrix3 &b);				// Return a != b  		friend const LLMatrix3& operator*=(LLMatrix3 &a, const LLMatrix3 &b);				// Return a * b +		friend const LLMatrix3& operator*=(LLMatrix3 &a, F32 scalar );						// Return a * scalar  		friend std::ostream&	 operator<<(std::ostream& s, const LLMatrix3 &a);	// Stream a  }; diff --git a/indra/llmath/m4math.cpp b/indra/llmath/m4math.cpp index 4e7cf847dc..836b3178d5 100644 --- a/indra/llmath/m4math.cpp +++ b/indra/llmath/m4math.cpp @@ -163,7 +163,7 @@ LLMatrix4::~LLMatrix4(void)  // Clear and Assignment Functions -const LLMatrix4& LLMatrix4::zero() +const LLMatrix4& LLMatrix4::setZero()  {  	mMatrix[0][0] = 0.f;  	mMatrix[0][1] = 0.f; diff --git a/indra/llmath/m4math.h b/indra/llmath/m4math.h index 4958777b29..7eacbf6542 100644 --- a/indra/llmath/m4math.h +++ b/indra/llmath/m4math.h @@ -132,8 +132,8 @@ public:  				  const LLVector4 &row3);  	// various useful matrix functions -	const LLMatrix4& identity();					// Load identity matrix -	const LLMatrix4& zero();						// Clears matrix to all zeros. +	const LLMatrix4& setIdentity();					// Load identity matrix +	const LLMatrix4& setZero();						// Clears matrix to all zeros.  	const LLMatrix4& initRotation(const F32 angle, const F32 x, const F32 y, const F32 z);	// Calculate rotation matrix by rotating angle radians about (x, y, z)  	const LLMatrix4& initRotation(const F32 angle, const LLVector4 &axis);	// Calculate rotation matrix for rotating angle radians about vec @@ -243,10 +243,10 @@ public:  inline LLMatrix4::LLMatrix4()  { -	identity(); +	setIdentity();  } -inline const LLMatrix4&	LLMatrix4::identity() +inline const LLMatrix4&	LLMatrix4::setIdentity()  {  	mMatrix[0][0] = 1.f;  	mMatrix[0][1] = 0.f; diff --git a/indra/llmath/v2math.h b/indra/llmath/v2math.h index f2450b1fd3..5f46655a07 100644 --- a/indra/llmath/v2math.h +++ b/indra/llmath/v2math.h @@ -54,18 +54,26 @@ class LLVector2  		LLVector2(const F32 *vec);				// Initializes LLVector2 to (vec[0]. vec[1])  		// Clears LLVector2 to (0, 0).  DEPRECATED - prefer zeroVec. -		void	clearVec(); +		void	clear(); +		void	setZero(); +		void	clearVec();	// deprecated +		void	zeroVec();	// deprecated -		// Zero LLVector2 to (0, 0) -		void	zeroVec(); +		void	set(F32 x, F32 y);	        // Sets LLVector2 to (x, y) +		void	set(const LLVector2 &vec);	// Sets LLVector2 to vec +		void	set(const F32 *vec);			// Sets LLVector2 to vec -		void	setVec(F32 x, F32 y);	        // Sets LLVector2 to (x, y) -		void	setVec(const LLVector2 &vec);	// Sets LLVector2 to vec -		void	setVec(const F32 *vec);			// Sets LLVector2 to vec +		void	setVec(F32 x, F32 y);	        // deprecated +		void	setVec(const LLVector2 &vec);	// deprecated +		void	setVec(const F32 *vec);			// deprecated -		F32		magVec() const;				// Returns magnitude of LLVector2 -		F32		magVecSquared() const;		// Returns magnitude squared of LLVector2 -		F32		normVec();					// Normalizes and returns the magnitude of LLVector2 +		F32		length() const;				// Returns magnitude of LLVector2 +		F32		lengthSquared() const;		// Returns magnitude squared of LLVector2 +		F32		normalize();					// Normalizes and returns the magnitude of LLVector2 + +		F32		magVec() const;				// deprecated +		F32		magVecSquared() const;		// deprecated +		F32		normVec();					// deprecated  		BOOL		abs();						// sets all values to absolute value of original value (first octant), returns TRUE if changed @@ -132,30 +140,66 @@ inline LLVector2::LLVector2(const F32 *vec)  // Clear and Assignment Functions +inline void	LLVector2::clear(void) +{ +	mV[VX] = 0.f; +	mV[VY] = 0.f; +} + +inline void	LLVector2::setZero(void) +{ +	mV[VX] = 0.f; +	mV[VY] = 0.f; +} + +// deprecated  inline void	LLVector2::clearVec(void)  {  	mV[VX] = 0.f;  	mV[VY] = 0.f;  } +// deprecated  inline void	LLVector2::zeroVec(void)  {  	mV[VX] = 0.f;  	mV[VY] = 0.f;  } +inline void	LLVector2::set(F32 x, F32 y) +{ +	mV[VX] = x; +	mV[VY] = y; +} + +inline void	LLVector2::set(const LLVector2 &vec) +{ +	mV[VX] = vec.mV[VX]; +	mV[VY] = vec.mV[VY]; +} + +inline void	LLVector2::set(const F32 *vec) +{ +	mV[VX] = vec[VX]; +	mV[VY] = vec[VY]; +} + + +// deprecated  inline void	LLVector2::setVec(F32 x, F32 y)  {  	mV[VX] = x;  	mV[VY] = y;  } +// deprecated  inline void	LLVector2::setVec(const LLVector2 &vec)  {  	mV[VX] = vec.mV[VX];  	mV[VY] = vec.mV[VY];  } +// deprecated  inline void	LLVector2::setVec(const F32 *vec)  {  	mV[VX] = vec[VX]; @@ -164,16 +208,49 @@ inline void	LLVector2::setVec(const F32 *vec)  // LLVector2 Magnitude and Normalization Functions +inline F32 LLVector2::length(void) const +{ +	return fsqrtf(mV[0]*mV[0] + mV[1]*mV[1]); +} + +inline F32 LLVector2::lengthSquared(void) const +{ +	return mV[0]*mV[0] + mV[1]*mV[1]; +} + +inline F32		LLVector2::normalize(void) +{ +	F32 mag = fsqrtf(mV[0]*mV[0] + mV[1]*mV[1]); +	F32 oomag; + +	if (mag > FP_MAG_THRESHOLD) +	{ +		oomag = 1.f/mag; +		mV[0] *= oomag; +		mV[1] *= oomag; +	} +	else +	{ +		mV[0] = 0.f; +		mV[1] = 0.f; +		mag = 0; +	} +	return (mag); +} + +// deprecated  inline F32		LLVector2::magVec(void) const  {  	return fsqrtf(mV[0]*mV[0] + mV[1]*mV[1]);  } +// deprecated  inline F32		LLVector2::magVecSquared(void) const  {  	return mV[0]*mV[0] + mV[1]*mV[1];  } +// deprecated  inline F32		LLVector2::normVec(void)  {  	F32 mag = fsqrtf(mV[0]*mV[0] + mV[1]*mV[1]); diff --git a/indra/llmath/v3dmath.h b/indra/llmath/v3dmath.h index ac3f06c453..667c335f51 100644 --- a/indra/llmath/v3dmath.h +++ b/indra/llmath/v3dmath.h @@ -83,8 +83,9 @@ class LLVector3d  		BOOL		clamp(const F64 min, const F64 max);		// Clamps all values to (min,max), returns TRUE if data changed  		BOOL		abs();						// sets all values to absolute value of original value (first octant), returns TRUE if changed -		inline const LLVector3d&	clearVec();						// Clears LLVector3d to (0, 0, 0, 1) -		inline const LLVector3d&	zeroVec();						// Zero LLVector3d to (0, 0, 0, 0) +		inline const LLVector3d&	clearVec();		// Clears LLVector3d to (0, 0, 0, 1) +		inline const LLVector3d&	setZero();		// Zero LLVector3d to (0, 0, 0, 0) +		inline const LLVector3d&	zeroVec();		// deprecated  		inline const LLVector3d&	setVec(const F64 x, const F64 y, const F64 z);	// Sets LLVector3d to (x, y, z, 1)  		inline const LLVector3d&	setVec(const LLVector3d &vec);	// Sets LLVector3d to vec  		inline const LLVector3d&	setVec(const F64 *vec);			// Sets LLVector3d to vec @@ -198,6 +199,14 @@ inline const LLVector3d&	LLVector3d::clearVec(void)  	return (*this);  } +inline const LLVector3d&	LLVector3d::setZero(void) +{ +	mdV[0] = 0.f; +	mdV[1] = 0.f; +	mdV[2] = 0.f; +	return (*this); +} +  inline const LLVector3d&	LLVector3d::zeroVec(void)  {  	mdV[0] = 0.f; diff --git a/indra/llmath/v3math.cpp b/indra/llmath/v3math.cpp index 5ffd1dd428..f1fe1a780e 100644 --- a/indra/llmath/v3math.cpp +++ b/indra/llmath/v3math.cpp @@ -172,6 +172,22 @@ LLVector3			LLVector3::scaledVec(const LLVector3& vec) const  	return ret;  } +const LLVector3&	LLVector3::set(const LLVector3d &vec) +{ +	mV[0] = (F32)vec.mdV[0]; +	mV[1] = (F32)vec.mdV[1]; +	mV[2] = (F32)vec.mdV[2]; +	return (*this); +} + +const LLVector3&	LLVector3::set(const LLVector4 &vec) +{ +	mV[0] = vec.mV[0]; +	mV[1] = vec.mV[1]; +	mV[2] = vec.mV[2]; +	return (*this); +} +  const LLVector3&	LLVector3::setVec(const LLVector3d &vec)  {  	mV[0] = (F32)vec.mdV[0]; diff --git a/indra/llmath/v3math.h b/indra/llmath/v3math.h index e18b20ddd0..03c780a1f4 100644 --- a/indra/llmath/v3math.h +++ b/indra/llmath/v3math.h @@ -81,18 +81,33 @@ class LLVector3  		BOOL		abs();						// sets all values to absolute value of original value (first octant), returns TRUE if changed -		inline void	clearVec();						// Clears LLVector3 to (0, 0, 0, 1) -		inline void	zeroVec();						// Zero LLVector3 to (0, 0, 0, 0) -		inline void	setVec(F32 x, F32 y, F32 z);	// Sets LLVector3 to (x, y, z, 1) -		inline void	setVec(const LLVector3 &vec);	// Sets LLVector3 to vec -		inline void	setVec(const F32 *vec);			// Sets LLVector3 to vec +		inline void	clear();						// Clears LLVector3 to (0, 0, 0) +		inline void	setZero();						// Clears LLVector3 to (0, 0, 0) +		inline void	clearVec();						// deprecated +		inline void	zeroVec();						// deprecated -		const LLVector3& setVec(const LLVector4 &vec); -		const LLVector3& setVec(const LLVector3d &vec);	// Sets LLVector3 to vec +		inline void	set(F32 x, F32 y, F32 z);		// Sets LLVector3 to (x, y, z, 1) +		inline void	set(const LLVector3 &vec);		// Sets LLVector3 to vec +		inline void	set(const F32 *vec);			// Sets LLVector3 to vec +		const LLVector3& set(const LLVector4 &vec); +		const LLVector3& set(const LLVector3d &vec);// Sets LLVector3 to vec -		F32		magVec() const;				// Returns magnitude of LLVector3 -		F32		magVecSquared() const;		// Returns magnitude squared of LLVector3 -		inline F32		normVec();					// Normalizes and returns the magnitude of LLVector3 +		inline void	setVec(F32 x, F32 y, F32 z);	// deprecated +		inline void	setVec(const LLVector3 &vec);	// deprecated +		inline void	setVec(const F32 *vec);			// deprecated + +		const LLVector3& setVec(const LLVector4 &vec);  // deprecated +		const LLVector3& setVec(const LLVector3d &vec);	// deprecated + +		F32		length() const;			// Returns magnitude of LLVector3 +		F32		lengthSquared() const;	// Returns magnitude squared of LLVector3 +		F32		magVec() const;			// deprecated +		F32		magVecSquared() const;	// deprecated + +		inline F32		normalize();	// Normalizes and returns the magnitude of LLVector3 +		inline F32		normVec();		// deprecated + +		inline BOOL inRange( F32 min, F32 max ) const; // Returns true if all values of the vector are between min and max  		const LLVector3&	rotVec(F32 angle, const LLVector3 &vec);	// Rotates about vec by angle radians  		const LLVector3&	rotVec(F32 angle, F32 x, F32 y, F32 z);		// Rotates about x,y,z by angle radians @@ -188,6 +203,20 @@ inline BOOL LLVector3::isFinite() const  // Clear and Assignment Functions +inline void	LLVector3::clear(void) +{ +	mV[0] = 0.f; +	mV[1] = 0.f; +	mV[2] = 0.f; +} + +inline void	LLVector3::setZero(void) +{ +	mV[0] = 0.f; +	mV[1] = 0.f; +	mV[2] = 0.f; +} +  inline void	LLVector3::clearVec(void)  {  	mV[0] = 0.f; @@ -202,6 +231,28 @@ inline void	LLVector3::zeroVec(void)  	mV[2] = 0.f;  } +inline void	LLVector3::set(F32 x, F32 y, F32 z) +{ +	mV[VX] = x; +	mV[VY] = y; +	mV[VZ] = z; +} + +inline void	LLVector3::set(const LLVector3 &vec) +{ +	mV[0] = vec.mV[0]; +	mV[1] = vec.mV[1]; +	mV[2] = vec.mV[2]; +} + +inline void	LLVector3::set(const F32 *vec) +{ +	mV[0] = vec[0]; +	mV[1] = vec[1]; +	mV[2] = vec[2]; +} + +// deprecated  inline void	LLVector3::setVec(F32 x, F32 y, F32 z)  {  	mV[VX] = x; @@ -209,6 +260,7 @@ inline void	LLVector3::setVec(F32 x, F32 y, F32 z)  	mV[VZ] = z;  } +// deprecated  inline void	LLVector3::setVec(const LLVector3 &vec)  {  	mV[0] = vec.mV[0]; @@ -216,6 +268,7 @@ inline void	LLVector3::setVec(const LLVector3 &vec)  	mV[2] = vec.mV[2];  } +// deprecated  inline void	LLVector3::setVec(const F32 *vec)  {  	mV[0] = vec[0]; @@ -223,6 +276,29 @@ inline void	LLVector3::setVec(const F32 *vec)  	mV[2] = vec[2];  } +inline F32 LLVector3::normalize(void) +{ +	F32 mag = fsqrtf(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]); +	F32 oomag; + +	if (mag > FP_MAG_THRESHOLD) +	{ +		oomag = 1.f/mag; +		mV[0] *= oomag; +		mV[1] *= oomag; +		mV[2] *= oomag; +	} +	else +	{ +		mV[0] = 0.f; +		mV[1] = 0.f; +		mV[2] = 0.f; +		mag = 0; +	} +	return (mag); +} + +// deprecated  inline F32 LLVector3::normVec(void)  {  	F32 mag = fsqrtf(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]); @@ -247,6 +323,16 @@ inline F32 LLVector3::normVec(void)  // LLVector3 Magnitude and Normalization Functions +inline F32	LLVector3::length(void) const +{ +	return fsqrtf(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]); +} + +inline F32	LLVector3::lengthSquared(void) const +{ +	return mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]; +} +  inline F32	LLVector3::magVec(void) const  {  	return fsqrtf(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]); @@ -257,6 +343,13 @@ inline F32	LLVector3::magVecSquared(void) const  	return mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2];  } +inline BOOL LLVector3::inRange( F32 min, F32 max ) const +{ +	return mV[0] >= min && mV[0] <= max && +		   mV[1] >= min && mV[1] <= max && +		   mV[2] >= min && mV[2] <= max;		 +} +  inline LLVector3 operator+(const LLVector3 &a, const LLVector3 &b)  {  	LLVector3 c(a); @@ -397,7 +490,7 @@ inline F32	dist_vec_squared2D(const LLVector3 &a, const LLVector3 &b)  inline LLVector3 projected_vec(const LLVector3 &a, const LLVector3 &b)  {  	LLVector3 project_axis = b; -	project_axis.normVec(); +	project_axis.normalize();  	return project_axis * (a * project_axis);  } @@ -438,8 +531,8 @@ inline F32 angle_between(const LLVector3& a, const LLVector3& b)  {  	LLVector3 an = a;  	LLVector3 bn = b; -	an.normVec(); -	bn.normVec(); +	an.normalize(); +	bn.normalize();  	F32 cosine = an * bn;  	F32 angle = (cosine >= 1.0f) ? 0.0f :  				(cosine <= -1.0f) ? F_PI : @@ -451,8 +544,8 @@ inline BOOL are_parallel(const LLVector3 &a, const LLVector3 &b, F32 epsilon)  {  	LLVector3 an = a;  	LLVector3 bn = b; -	an.normVec(); -	bn.normVec(); +	an.normalize(); +	bn.normalize();  	F32 dot = an * bn;  	if ( (1.0f - fabs(dot)) < epsilon)  	{ diff --git a/indra/llmath/v4math.cpp b/indra/llmath/v4math.cpp index b753778ba1..9da4b501d6 100644 --- a/indra/llmath/v4math.cpp +++ b/indra/llmath/v4math.cpp @@ -113,8 +113,8 @@ F32 angle_between( const LLVector4& a, const LLVector4& b )  {  	LLVector4 an = a;  	LLVector4 bn = b; -	an.normVec(); -	bn.normVec(); +	an.normalize(); +	bn.normalize();  	F32 cosine = an * bn;  	F32 angle = (cosine >= 1.0f) ? 0.0f :  		(cosine <= -1.0f) ? F_PI : @@ -126,8 +126,8 @@ BOOL are_parallel(const LLVector4 &a, const LLVector4 &b, F32 epsilon)  {  	LLVector4 an = a;  	LLVector4 bn = b; -	an.normVec(); -	bn.normVec(); +	an.normalize(); +	bn.normalize();  	F32 dot = an * bn;  	if ( (1.0f - fabs(dot)) < epsilon)  		return TRUE; diff --git a/indra/llmath/v4math.h b/indra/llmath/v4math.h index 34b5f9e33c..9f71d3452a 100644 --- a/indra/llmath/v4math.h +++ b/indra/llmath/v4math.h @@ -68,17 +68,29 @@ class LLVector4  		inline BOOL isFinite() const;									// checks to see if all values of LLVector3 are finite -		inline void	clearVec();							// Clears LLVector4 to (0, 0, 0, 1) -		inline void	zeroVec();							// zero LLVector4 to (0, 0, 0, 0) -		inline void	setVec(F32 x, F32 y, F32 z);		// Sets LLVector4 to (x, y, z, 1) -		inline void	setVec(F32 x, F32 y, F32 z, F32 w);	// Sets LLVector4 to (x, y, z, w) -		inline void	setVec(const LLVector4 &vec);		// Sets LLVector4 to vec -		inline void	setVec(const LLVector3 &vec, F32 w = 1.f); // Sets LLVector4 to LLVector3 vec -		inline void	setVec(const F32 *vec);				// Sets LLVector4 to vec - -		F32			magVec() const;				// Returns magnitude of LLVector4 -		F32			magVecSquared() const;		// Returns magnitude squared of LLVector4 -		F32			normVec();					// Normalizes and returns the magnitude of LLVector4 +		inline void	clear();		// Clears LLVector4 to (0, 0, 0, 1) +		inline void	clearVec();		// deprecated +		inline void	zeroVec();		// deprecated + +		inline void	set(F32 x, F32 y, F32 z);			// Sets LLVector4 to (x, y, z, 1) +		inline void	set(F32 x, F32 y, F32 z, F32 w);	// Sets LLVector4 to (x, y, z, w) +		inline void	set(const LLVector4 &vec);			// Sets LLVector4 to vec +		inline void	set(const LLVector3 &vec, F32 w = 1.f); // Sets LLVector4 to LLVector3 vec +		inline void	set(const F32 *vec);				// Sets LLVector4 to vec + +		inline void	setVec(F32 x, F32 y, F32 z);		// deprecated +		inline void	setVec(F32 x, F32 y, F32 z, F32 w);	// deprecated +		inline void	setVec(const LLVector4 &vec);		// deprecated +		inline void	setVec(const LLVector3 &vec, F32 w = 1.f); // deprecated +		inline void	setVec(const F32 *vec);				// deprecated + +		F32	length() const;				// Returns magnitude of LLVector4 +		F32	lengthSquared() const;		// Returns magnitude squared of LLVector4 +		F32	normalize();				// Normalizes and returns the magnitude of LLVector4 + +		F32			magVec() const;				// deprecated +		F32			magVecSquared() const;		// deprecated +		F32			normVec();					// deprecated  		// Sets all values to absolute value of their original values  		// Returns TRUE if data changed @@ -192,6 +204,15 @@ inline BOOL LLVector4::isFinite() const  // Clear and Assignment Functions +inline void	LLVector4::clear(void) +{ +	mV[VX] = 0.f; +	mV[VY] = 0.f; +	mV[VZ] = 0.f; +	mV[VW] = 1.f; +} + +// deprecated  inline void	LLVector4::clearVec(void)  {  	mV[VX] = 0.f; @@ -200,6 +221,7 @@ inline void	LLVector4::clearVec(void)  	mV[VW] = 1.f;  } +// deprecated  inline void	LLVector4::zeroVec(void)  {  	mV[VX] = 0.f; @@ -208,6 +230,48 @@ inline void	LLVector4::zeroVec(void)  	mV[VW] = 0.f;  } +inline void	LLVector4::set(F32 x, F32 y, F32 z) +{ +	mV[VX] = x; +	mV[VY] = y; +	mV[VZ] = z; +	mV[VW] = 1.f; +} + +inline void	LLVector4::set(F32 x, F32 y, F32 z, F32 w) +{ +	mV[VX] = x; +	mV[VY] = y; +	mV[VZ] = z; +	mV[VW] = w; +} + +inline void	LLVector4::set(const LLVector4 &vec) +{ +	mV[VX] = vec.mV[VX]; +	mV[VY] = vec.mV[VY]; +	mV[VZ] = vec.mV[VZ]; +	mV[VW] = vec.mV[VW]; +} + +inline void	LLVector4::set(const LLVector3 &vec, F32 w) +{ +	mV[VX] = vec.mV[VX]; +	mV[VY] = vec.mV[VY]; +	mV[VZ] = vec.mV[VZ]; +	mV[VW] = w; +} + +inline void	LLVector4::set(const F32 *vec) +{ +	mV[VX] = vec[VX]; +	mV[VY] = vec[VY]; +	mV[VZ] = vec[VZ]; +	mV[VW] = vec[VW]; +} + + +// deprecated  inline void	LLVector4::setVec(F32 x, F32 y, F32 z)  {  	mV[VX] = x; @@ -216,6 +280,7 @@ inline void	LLVector4::setVec(F32 x, F32 y, F32 z)  	mV[VW] = 1.f;  } +// deprecated  inline void	LLVector4::setVec(F32 x, F32 y, F32 z, F32 w)  {  	mV[VX] = x; @@ -224,6 +289,7 @@ inline void	LLVector4::setVec(F32 x, F32 y, F32 z, F32 w)  	mV[VW] = w;  } +// deprecated  inline void	LLVector4::setVec(const LLVector4 &vec)  {  	mV[VX] = vec.mV[VX]; @@ -232,6 +298,7 @@ inline void	LLVector4::setVec(const LLVector4 &vec)  	mV[VW] = vec.mV[VW];  } +// deprecated  inline void	LLVector4::setVec(const LLVector3 &vec, F32 w)  {  	mV[VX] = vec.mV[VX]; @@ -240,6 +307,7 @@ inline void	LLVector4::setVec(const LLVector3 &vec, F32 w)  	mV[VW] = w;  } +// deprecated  inline void	LLVector4::setVec(const F32 *vec)  {  	mV[VX] = vec[VX]; @@ -250,6 +318,16 @@ inline void	LLVector4::setVec(const F32 *vec)  // LLVector4 Magnitude and Normalization Functions +inline F32		LLVector4::length(void) const +{ +	return fsqrtf(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]); +} + +inline F32		LLVector4::lengthSquared(void) const +{ +	return mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]; +} +  inline F32		LLVector4::magVec(void) const  {  	return fsqrtf(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]); @@ -364,13 +442,13 @@ inline LLVector4 operator-(const LLVector4 &a)  inline F32	dist_vec(const LLVector4 &a, const LLVector4 &b)  {  	LLVector4 vec = a - b; -	return (vec.magVec()); +	return (vec.length());  }  inline F32	dist_vec_squared(const LLVector4 &a, const LLVector4 &b)  {  	LLVector4 vec = a - b; -	return (vec.magVecSquared()); +	return (vec.lengthSquared());  }  inline LLVector4 lerp(const LLVector4 &a, const LLVector4 &b, F32 u) @@ -382,6 +460,29 @@ inline LLVector4 lerp(const LLVector4 &a, const LLVector4 &b, F32 u)  		a.mV[VW] + (b.mV[VW] - a.mV[VW]) * u);  } +inline F32		LLVector4::normalize(void) +{ +	F32 mag = fsqrtf(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]); +	F32 oomag; + +	if (mag > FP_MAG_THRESHOLD) +	{ +		oomag = 1.f/mag; +		mV[VX] *= oomag; +		mV[VY] *= oomag; +		mV[VZ] *= oomag; +	} +	else +	{ +		mV[0] = 0.f; +		mV[1] = 0.f; +		mV[2] = 0.f; +		mag = 0; +	} +	return (mag); +} + +// deprecated  inline F32		LLVector4::normVec(void)  {  	F32 mag = fsqrtf(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]); diff --git a/indra/llmath/xform.h b/indra/llmath/xform.h index 9a5c99140e..feca790820 100644 --- a/indra/llmath/xform.h +++ b/indra/llmath/xform.h @@ -35,10 +35,12 @@  #include "m4math.h"  #include "llquaternion.h" -const F32 MAX_OBJECT_Z 		= 768.f; +const F32 MAX_OBJECT_Z 		= 4096.f; // should match REGION_HEIGHT_METERS, Pre-havok4: 768.f  const F32 MIN_OBJECT_Z 		= -256.f; -const F32 MIN_OBJECT_SCALE 	= 0.01f; -const F32 MAX_OBJECT_SCALE 	= 10.f; +const F32 DEFAULT_MAX_PRIM_SCALE = 10.f; +const F32 MIN_PRIM_SCALE = 0.01f; +const F32 MAX_PRIM_SCALE = 65536.f;	// something very high but not near FLT_MAX +  class LLXform  { @@ -138,7 +140,7 @@ public:  	void init()  	{ -		mWorldMatrix.identity(); +		mWorldMatrix.setIdentity();  		mMin.clearVec();  		mMax.clearVec(); diff --git a/indra/llmessage/llinstantmessage.h b/indra/llmessage/llinstantmessage.h index abb1651faf..9645d4a763 100644 --- a/indra/llmessage/llinstantmessage.h +++ b/indra/llmessage/llinstantmessage.h @@ -177,7 +177,7 @@ enum EGodlikeRequest  	GOD_WANTS_NOTHING,  	// for requesting physics information about an object -	GOD_WANTS_HAVOK_INFO, +	GOD_WANTS_PHYSICS_INFO,  	// two unused requests that can be appropriated for debug   	// purposes (no viewer recompile necessary) diff --git a/indra/llmessage/lliohttpserver.cpp b/indra/llmessage/lliohttpserver.cpp index 625dbb68b9..ec5cb93d69 100644 --- a/indra/llmessage/lliohttpserver.cpp +++ b/indra/llmessage/lliohttpserver.cpp @@ -203,7 +203,9 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl(  		}  		// Log all HTTP transactions. -		llinfos << verb << " " << context[CONTEXT_REQUEST]["path"].asString() +		// TODO: Add a way to log these to their own file instead of indra.log +		// It is just too spammy to be in indra.log. +		lldebugs << verb << " " << context[CONTEXT_REQUEST]["path"].asString()  			<< " " << mStatusCode << " " <<  mStatusMessage << " " << delta  			<< "s" << llendl; @@ -723,8 +725,8 @@ LLIOPipe::EStatus LLHTTPResponder::process_impl(  		const LLHTTPNode* node = mRootNode.traverse(mPath, context);  		if(node)  		{ - 			lldebugs << "LLHTTPResponder::process_impl found node for " -				<< mAbsPathAndQuery << llendl; + 			//llinfos << "LLHTTPResponder::process_impl found node for " +			//	<< mAbsPathAndQuery << llendl;    			// Copy everything after mLast read to the out.  			LLBufferArray::segment_iterator_t seg_iter; diff --git a/indra/llmessage/llregionflags.h b/indra/llmessage/llregionflags.h index 65d76bba28..aa9964d46b 100644 --- a/indra/llmessage/llregionflags.h +++ b/indra/llmessage/llregionflags.h @@ -140,7 +140,7 @@ const U32 ESTATE_MAINLAND = 1;  const U32 ESTATE_ORIENTATION = 2;  const U32 ESTATE_INTERNAL = 3;  const U32 ESTATE_SHOWCASE = 4; -const U32 ESTATE_KIDGRID = 5; +const U32 ESTATE_TEEN = 5;  const U32 ESTATE_LAST_LINDEN = 5; // last linden owned/managed estate  // for EstateOwnerRequest, setaccess message diff --git a/indra/llprimitive/llmaterialtable.cpp b/indra/llprimitive/llmaterialtable.cpp index 40cf97099c..3eea03e0b9 100644 --- a/indra/llprimitive/llmaterialtable.cpp +++ b/indra/llprimitive/llmaterialtable.cpp @@ -36,9 +36,58 @@  #include "material_codes.h"  #include "sound_ids.h"  #include "imageids.h" +#include <llphysics/llphysicsversion.h>  LLMaterialTable LLMaterialTable::basic(1); +/*  +	Old Havok 1 constants + +// these are the approximately correct friction values for various materials +// however Havok1's friction dynamics are not very correct, so the effective +// friction coefficients that result from these numbers are approximately +// 25-50% too low, more incorrect for the lower values. +F32 const LLMaterialTable::FRICTION_MIN 	= 0.2f; 	 +F32 const LLMaterialTable::FRICTION_GLASS 	= 0.2f; 	// borosilicate glass +F32 const LLMaterialTable::FRICTION_LIGHT 	= 0.2f; 	// +F32 const LLMaterialTable::FRICTION_METAL 	= 0.3f; 	// steel +F32 const LLMaterialTable::FRICTION_PLASTIC	= 0.4f; 	// HDPE +F32 const LLMaterialTable::FRICTION_WOOD 	= 0.6f; 	// southern pine +F32 const LLMaterialTable::FRICTION_FLESH 	= 0.60f; 	// saltwater +F32 const LLMaterialTable::FRICTION_LAND 	= 0.78f; 	// dirt +F32 const LLMaterialTable::FRICTION_STONE 	= 0.8f; 	// concrete +F32 const LLMaterialTable::FRICTION_RUBBER 	= 0.9f; 	// +F32 const LLMaterialTable::FRICTION_MAX 	= 0.95f; 	// +*/ + +#if LL_CURRENT_HAVOK_VERSION == LL_HAVOK_VERSION_460 +// Havok4 has more correct friction dynamics, however here we have to use +// the "incorrect" equivalents for the legacy Havok1 behavior +F32 const LLMaterialTable::FRICTION_MIN 	= 0.15f; 	 +F32 const LLMaterialTable::FRICTION_GLASS 	= 0.13f; 	// borosilicate glass +F32 const LLMaterialTable::FRICTION_LIGHT 	= 0.14f; 	// +F32 const LLMaterialTable::FRICTION_METAL 	= 0.22f; 	// steel +F32 const LLMaterialTable::FRICTION_PLASTIC	= 0.3f; 	// HDPE +F32 const LLMaterialTable::FRICTION_WOOD 	= 0.44f; 	// southern pine +F32 const LLMaterialTable::FRICTION_FLESH 	= 0.46f; 	// saltwater +F32 const LLMaterialTable::FRICTION_LAND 	= 0.58f; 	// dirt +F32 const LLMaterialTable::FRICTION_STONE 	= 0.6f; 	// concrete +F32 const LLMaterialTable::FRICTION_RUBBER 	= 0.67f; 	// +F32 const LLMaterialTable::FRICTION_MAX 	= 0.71f; 	// +#endif + +F32 const LLMaterialTable::RESTITUTION_MIN 		= 0.02f; 	 +F32 const LLMaterialTable::RESTITUTION_LAND 	= LLMaterialTable::RESTITUTION_MIN; +F32 const LLMaterialTable::RESTITUTION_FLESH 	= 0.2f; 	// saltwater +F32 const LLMaterialTable::RESTITUTION_STONE 	= 0.4f; 	// concrete +F32 const LLMaterialTable::RESTITUTION_METAL 	= 0.4f; 	// steel +F32 const LLMaterialTable::RESTITUTION_WOOD 	= 0.5f; 	// southern pine +F32 const LLMaterialTable::RESTITUTION_GLASS 	= 0.7f; 	// borosilicate glass +F32 const LLMaterialTable::RESTITUTION_PLASTIC	= 0.7f; 	// HDPE +F32 const LLMaterialTable::RESTITUTION_LIGHT 	= 0.7f; 	// +F32 const LLMaterialTable::RESTITUTION_RUBBER 	= 0.9f; 	// +F32 const LLMaterialTable::RESTITUTION_MAX		= 0.95f; +  F32 const LLMaterialTable::DEFAULT_FRICTION = 0.5f;  F32 const LLMaterialTable::DEFAULT_RESTITUTION = 0.4f; diff --git a/indra/llprimitive/llmaterialtable.h b/indra/llprimitive/llmaterialtable.h index 46b6f070d9..e84e75c677 100644 --- a/indra/llprimitive/llmaterialtable.h +++ b/indra/llprimitive/llmaterialtable.h @@ -33,11 +33,36 @@  #define LL_LLMATERIALTABLE_H  #include "lluuid.h" -#include "linked_lists.h"  #include "llstring.h" +#include <list> +  const U32 LLMATERIAL_INFO_NAME_LENGTH = 256; +// We've moved toward more reasonable mass values for the Havok4 engine. +// The LEGACY_DEFAULT_OBJECT_DENSITY is used to maintain support for +// legacy scripts code (llGetMass()) and script energy consumption. +const F32 DEFAULT_OBJECT_DENSITY = 1000.0f;			// per m^3 +const F32 LEGACY_DEFAULT_OBJECT_DENSITY = 10.0f; + +// Avatars density depends on the collision shape used.  The approximate +// legacy volumes of avatars are: +// Body_Length Body_Width Body_Fat Leg_Length  Volume(m^3) +// ------------------------------------------------------- +//    min     |   min    |  min   |    min    |   0.123   | +//    max     |   max    |  max   |    max    |   0.208   | +// +// Either the avatar shape must be tweaked to match those volumes +// or the DEFAULT_AVATAR_DENSITY must be adjusted to achieve the  +// legacy mass. +// +// The current density appears to be low because the mass and +// inertia are computed as if the avatar were a cylinder which +// has more volume than the actual collision shape of the avatar. +// See the physics engine mass properties code for more info. +const F32 DEFAULT_AVATAR_DENSITY = 445.3f;		// was 444.24f; + +  class LLMaterialInfo  {  public: @@ -84,9 +109,33 @@ public:  class LLMaterialTable  {  public: +	static const F32 FRICTION_MIN; +	static const F32 FRICTION_GLASS; +	static const F32 FRICTION_LIGHT; +	static const F32 FRICTION_METAL; +	static const F32 FRICTION_PLASTIC; +	static const F32 FRICTION_WOOD; +	static const F32 FRICTION_LAND; +	static const F32 FRICTION_STONE; +	static const F32 FRICTION_FLESH; +	static const F32 FRICTION_RUBBER; +	static const F32 FRICTION_MAX; + +	static const F32 RESTITUTION_MIN; +	static const F32 RESTITUTION_LAND; +	static const F32 RESTITUTION_FLESH; +	static const F32 RESTITUTION_STONE; +	static const F32 RESTITUTION_METAL; +	static const F32 RESTITUTION_WOOD; +	static const F32 RESTITUTION_GLASS; +	static const F32 RESTITUTION_PLASTIC; +	static const F32 RESTITUTION_LIGHT; +	static const F32 RESTITUTION_RUBBER; +	static const F32 RESTITUTION_MAX; +  	typedef std::list<LLMaterialInfo*> info_list_t;  	info_list_t mMaterialInfoList; -	 +  	LLUUID *mCollisionSoundMatrix;  	LLUUID *mSlidingSoundMatrix;  	LLUUID *mRollingSoundMatrix; @@ -117,8 +166,8 @@ public:  	char*  getName(U8 mcode);  	F32 getDensity(U8 mcode);						        // kg/m^3, 0 if not found -	F32 getFriction(U8 mcode);						        // havok values -	F32 getRestitution(U8 mcode);						    // havok values +	F32 getFriction(U8 mcode);						        // physics values +	F32 getRestitution(U8 mcode);						    // physics values  	F32 getHPMod(U8 mcode);  	F32 getDamageMod(U8 mcode);  	F32 getEPMod(U8 mcode); diff --git a/indra/llprimitive/llprimitive.cpp b/indra/llprimitive/llprimitive.cpp index 77bca8f803..cc676f73f1 100644 --- a/indra/llprimitive/llprimitive.cpp +++ b/indra/llprimitive/llprimitive.cpp @@ -113,9 +113,38 @@ const BOOL FLEXIBLE_OBJECT_DEFAULT_RENDERING_COLLISION_SPHERE = FALSE;  const char *SCULPT_DEFAULT_TEXTURE = "be293869-d0d9-0a69-5989-ad27f1946fd4"; // old inverted texture: "7595d345-a24c-e7ef-f0bd-78793792133e"; +//static  +// LEGACY: by default we use the LLVolumeMgr::gVolumeMgr global +// TODO -- eliminate this global from the codebase! +LLVolumeMgr* LLPrimitive::sVolumeManager = NULL; + +// static +void LLPrimitive::setVolumeManager( LLVolumeMgr* volume_manager ) +{ +	if ( !volume_manager || sVolumeManager ) +	{ +		llerrs << "Unable to set LLPrimitive::sVolumeManager to NULL" << llendl; +	} +	sVolumeManager = volume_manager; +} + +// static +bool LLPrimitive::cleanupVolumeManager() +{ +	BOOL res = FALSE; +	if (sVolumeManager)  +	{ +		res = sVolumeManager->cleanup(); +		delete sVolumeManager; +		sVolumeManager = NULL; +	} +	return res; +} +  //===============================================================  LLPrimitive::LLPrimitive() +:	mMiscFlags(0)  {  	mPrimitiveCode = 0; @@ -149,7 +178,7 @@ LLPrimitive::~LLPrimitive()  	// Cleanup handled by volume manager  	if (mVolumep)  	{ -		gVolumeMgr->cleanupVolume(mVolumep); +		sVolumeManager->cleanupVolume(mVolumep);  	}  	mVolumep = NULL;  } @@ -162,7 +191,7 @@ LLPrimitive *LLPrimitive::createPrimitive(LLPCode p_code)  	if (retval)  	{ -		retval->init(p_code); +		retval->init_primitive(p_code);  	}  	else  	{ @@ -173,7 +202,7 @@ LLPrimitive *LLPrimitive::createPrimitive(LLPCode p_code)  }  //=============================================================== -void LLPrimitive::init(LLPCode p_code) +void LLPrimitive::init_primitive(LLPCode p_code)  {  	if (mNumTEs)  	{ @@ -533,6 +562,8 @@ S32 LLPrimitive::setTEGlow(const U8 te, const F32 glow)  LLPCode LLPrimitive::legacyToPCode(const U8 legacy)  { +	// TODO: Should this default to something valid? +	// Maybe volume?  	LLPCode pcode = 0;  	switch (legacy) @@ -621,7 +652,7 @@ LLPCode LLPrimitive::legacyToPCode(const U8 legacy)  		pcode = LL_PCODE_TREE_NEW;  		break;  	default: -		llwarns << "Unknown legacy code " << legacy << "!" << llendl; +		llwarns << "Unknown legacy code " << legacy << " [" << (S32)legacy << "]!" << llendl;  	}  	return pcode; @@ -904,10 +935,10 @@ BOOL LLPrimitive::setVolume(const LLVolumeParams &volume_params, const S32 detai  			}  		} -		volumep = gVolumeMgr->getVolume(volume_params, detail); +		volumep = sVolumeManager->getVolume(volume_params, detail);  		if (volumep == mVolumep)  		{ -			gVolumeMgr->cleanupVolume( volumep );  // gVolumeMgr->getVolume() creates a reference, but we don't need a second one. +			sVolumeManager->cleanupVolume( volumep );  // LLVolumeMgr::getVolume() creates a reference, but we don't need a second one.  			return TRUE;  		}  	} @@ -950,7 +981,7 @@ BOOL LLPrimitive::setVolume(const LLVolumeParams &volume_params, const S32 detai  	// build the new object -	gVolumeMgr->cleanupVolume(mVolumep); +	sVolumeManager->cleanupVolume(mVolumep);  	mVolumep = volumep;  	U32 new_face_mask = mVolumep->mFaceMask; diff --git a/indra/llprimitive/llprimitive.h b/indra/llprimitive/llprimitive.h index eef58341e7..2b738f8d29 100644 --- a/indra/llprimitive/llprimitive.h +++ b/indra/llprimitive/llprimitive.h @@ -48,6 +48,7 @@ class LLColor4;  class LLColor3;  class LLTextureEntry;  class LLDataPacker; +class LLVolumeMgr;  enum LLGeomType // NOTE: same vals as GL Ids  { @@ -269,11 +270,32 @@ public:  class LLPrimitive : public LLXform  {  public: + +	// HACK for removing LLPrimitive's dependency on gVolumeMgr global. +	// If a different LLVolumeManager is instantiated and set early enough +	// then the LLPrimitive class will use it instead of gVolumeMgr. +	static LLVolumeMgr* getVolumeManager() { return sVolumeManager; } +	static void setVolumeManager( LLVolumeMgr* volume_manager); +	static bool cleanupVolumeManager(); + +	// these flags influence how the RigidBody representation is built +	static const U32 PRIM_FLAG_PHANTOM 				= 0x1 << 0; +	static const U32 PRIM_FLAG_VOLUME_DETECT 		= 0x1 << 1; +	static const U32 PRIM_FLAG_DYNAMIC 				= 0x1 << 2; +	static const U32 PRIM_FLAG_AVATAR 				= 0x1 << 3; +	static const U32 PRIM_FLAG_SCULPT 				= 0x1 << 4; +	// not used yet, but soon +	static const U32 PRIM_FLAG_COLLISION_CALLBACK 	= 0x1 << 5; +	static const U32 PRIM_FLAG_CONVEX 				= 0x1 << 6; +	static const U32 PRIM_FLAG_DEFAULT_VOLUME		= 0x1 << 7; +	static const U32 PRIM_FLAG_SITTING				= 0x1 << 8; +	static const U32 PRIM_FLAG_SITTING_ON_GROUND	= 0x1 << 9;		// Set along with PRIM_FLAG_SITTING +  	LLPrimitive();  	virtual ~LLPrimitive();  	static LLPrimitive *createPrimitive(LLPCode p_code); -	void init(LLPCode p_code); +	void init_primitive(LLPCode p_code);  	void setPCode(const LLPCode pcode);  	const LLVolume *getVolumeConst() const { return mVolumep; }		// HACK for Windoze confusion about ostream operator in LLVolume @@ -369,8 +391,15 @@ public:  	void setTextureList(LLTextureEntry *listp); -	inline BOOL			isAvatar() const; -	 +	inline BOOL	isAvatar() const; +	inline BOOL	isSittingAvatar() const; +	inline BOOL	isSittingAvatarOnGround() const; + +	void setFlags(U32 flags) { mMiscFlags = flags; } +	void addFlags(U32 flags) { mMiscFlags |= flags; } +	void removeFlags(U32 flags) { mMiscFlags &= ~flags; } +	U32 getFlags() const { return mMiscFlags; } +  	static const char *pCodeToString(const LLPCode pcode);  	static LLPCode legacyToPCode(const U8 legacy);  	static U8 pCodeToLegacy(const LLPCode pcode); @@ -388,11 +417,28 @@ protected:  	LLTextureEntry		*mTextureList;		// list of texture GUIDs, scales, offsets  	U8					mMaterial;			// Material code  	U8					mNumTEs;			// # of faces on the primitve	 +	U32 				mMiscFlags;			// home for misc bools + +	static LLVolumeMgr* sVolumeManager;  };  inline BOOL LLPrimitive::isAvatar() const  { -	return mPrimitiveCode == LL_PCODE_LEGACY_AVATAR; +	return ( LL_PCODE_LEGACY_AVATAR == mPrimitiveCode ) ? TRUE : FALSE; +} + +inline BOOL LLPrimitive::isSittingAvatar() const +{ +	// this is only used server-side +	return ( LL_PCODE_LEGACY_AVATAR == mPrimitiveCode  +			 &&	 ((getFlags() & (PRIM_FLAG_SITTING | PRIM_FLAG_SITTING_ON_GROUND)) != 0) ) ? TRUE : FALSE; +} + +inline BOOL LLPrimitive::isSittingAvatarOnGround() const +{ +	// this is only used server-side +	return ( LL_PCODE_LEGACY_AVATAR == mPrimitiveCode  +			 &&	 ((getFlags() & PRIM_FLAG_SITTING_ON_GROUND) != 0) ) ? TRUE : FALSE;  }  // static diff --git a/indra/llprimitive/llprimlinkinfo.h b/indra/llprimitive/llprimlinkinfo.h new file mode 100644 index 0000000000..139617f969 --- /dev/null +++ b/indra/llprimitive/llprimlinkinfo.h @@ -0,0 +1,375 @@ +/**  + * @file llprimlinkinfo.h + * @author andrew@lindenlab.com + * @brief A template for determining which prims in a set are linkable + * + * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc. + * $License$ + */ + + +#ifndef LL_PRIM_LINK_INFO_H +#define LL_PRIM_LINK_INFO_H + +// system includes +#include <iostream> +#include <map> +#include <list> +#include <vector> + +// common includes +#include "stdtypes.h" +#include "v3math.h" +#include "llquaternion.h" +#include "llsphere.h" + + +const F32 MAX_OBJECT_SPAN = 54.f;		// max distance from outside edge of an object to the farthest edge +const F32 OBJECT_SPAN_BONUS = 2.f;		// infinitesimally small prims can always link up to this distance +const S32 MAX_PRIMS_PER_OBJECT = 255; + + +template < typename DATA_TYPE > +class LLPrimLinkInfo +{ +public: +	LLPrimLinkInfo(); +	LLPrimLinkInfo( DATA_TYPE data, const LLSphere& sphere ); +	~LLPrimLinkInfo(); + +	void set( DATA_TYPE data, const LLSphere& sphere ); +	void append( DATA_TYPE data, const LLSphere& sphere ); +	void getData( std::list< DATA_TYPE >& data_list ) const; +	F32 getDiameter() const; +	LLVector3 getCenter() const; + +	// returns 'true' if this info can link with other_info +	bool canLink( const LLPrimLinkInfo< DATA_TYPE >& other_info ); + +	S32 getPrimCount() const { return mDataMap.size(); } + +	void mergeLinkableSet( typename std::list< LLPrimLinkInfo < DATA_TYPE > >& unlinked ); + +	void transform(const LLVector3& position, const LLQuaternion& rotation); + +private: +	// returns number of merges made +	S32 merge(LLPrimLinkInfo< DATA_TYPE >& other_info); + +	// returns number of collapses made +	static S32 collapse(typename std::list< LLPrimLinkInfo < DATA_TYPE > >& unlinked ); + +	void computeBoundingSphere(); + +	// Internal utility to encapsulate the link rules +	F32 get_max_linkable_span(const LLSphere& first, const LLSphere& second); +	F32 get_span(const LLSphere& first, const LLSphere& second); + +private: +	std::map< DATA_TYPE, LLSphere > mDataMap; +	LLSphere mBoundingSphere; +}; + + + +template < typename DATA_TYPE > +LLPrimLinkInfo< DATA_TYPE >::LLPrimLinkInfo() +:	mBoundingSphere( LLVector3(0.f, 0.f, 0.f), 0.f ) +{ +} + +template < typename DATA_TYPE > +LLPrimLinkInfo< DATA_TYPE >::LLPrimLinkInfo( DATA_TYPE data, const LLSphere& sphere) +:	mBoundingSphere(sphere) +{ +	mDataMap[data] = sphere; +} + +template < typename DATA_TYPE > +LLPrimLinkInfo< DATA_TYPE >::~LLPrimLinkInfo() +{ +	mDataMap.clear(); +} + +template < typename DATA_TYPE > +void LLPrimLinkInfo< DATA_TYPE>::set( DATA_TYPE data, const LLSphere& sphere ) +{ +	if (!mDataMap.empty()) +	{ +		mDataMap.clear(); +	} +	mDataMap[data] = sphere; +	mBoundingSphere = sphere; +} + +template < typename DATA_TYPE > +void LLPrimLinkInfo< DATA_TYPE>::append( DATA_TYPE data, const LLSphere& sphere ) +{ +	mDataMap[data] = sphere; +	if (!mBoundingSphere.contains(sphere)) +	{ +		computeBoundingSphere(); +	} +} + +template < typename DATA_TYPE > +void LLPrimLinkInfo< DATA_TYPE >::getData( std::list< DATA_TYPE >& data_list) const +{ +	typename std::map< DATA_TYPE, LLSphere >::const_iterator map_itr; +	for (map_itr = mDataMap.begin(); map_itr != mDataMap.end(); ++map_itr) +	{ +		data_list.push_back(map_itr->first); +	} +} + +template < typename DATA_TYPE > +F32 LLPrimLinkInfo< DATA_TYPE >::getDiameter() const +{  +	return 2.f * mBoundingSphere.getRadius(); +} + +template < typename DATA_TYPE > +LLVector3 LLPrimLinkInfo< DATA_TYPE >::getCenter() const +{  +	return mBoundingSphere.getCenter();  +} + +template < typename DATA_TYPE > +F32 LLPrimLinkInfo< DATA_TYPE >::get_max_linkable_span(const LLSphere& first, const LLSphere& second) +{ +	F32 max_span = 3.f * (first.getRadius() + second.getRadius()) + OBJECT_SPAN_BONUS; +	if (max_span > MAX_OBJECT_SPAN) +	{ +		max_span = MAX_OBJECT_SPAN; +	} + +	return max_span; +} + +template < typename DATA_TYPE > +F32 LLPrimLinkInfo< DATA_TYPE >::get_span(const LLSphere& first, const LLSphere& second) +{ +	F32 span = (first.getCenter() - second.getCenter()).length() +				+ first.getRadius() + second.getRadius(); +	return span; +} + +// static +// returns 'true' if this info can link with any part of other_info +template < typename DATA_TYPE > +bool LLPrimLinkInfo< DATA_TYPE >::canLink(const LLPrimLinkInfo& other_info) +{ +	F32 max_span = get_max_linkable_span(mBoundingSphere, other_info.mBoundingSphere); + +	F32 span = get_span(mBoundingSphere, other_info.mBoundingSphere); +	 +	if (span <= max_span) +	{ +		// The entire other_info fits inside the max span. +		return TRUE; +	} +	else if (span > max_span + 2.f * other_info.mBoundingSphere.getRadius()) +	{ +		// there is no way any piece of other_info could link with this one +		return FALSE; +	} + +	// there may be a piece of other_info that is linkable +	typename std::map< DATA_TYPE, LLSphere >::const_iterator map_itr; +	for (map_itr = other_info.mDataMap.begin(); map_itr != other_info.mDataMap.end(); ++map_itr) +	{ +		const LLSphere& other_sphere = (*map_itr).second; +		max_span = get_max_linkable_span(mBoundingSphere, other_sphere); + +		span = get_span(mBoundingSphere, other_sphere); + +		if (span <= max_span) +		{ +			// found one piece that is linkable +			return TRUE; +		} +	} +	return FALSE; +} + +// merges elements of 'unlinked'  +// returns number of links made (NOT final prim count, NOR linked prim count) +// and removes any linkable infos from 'unlinked'  +template < typename DATA_TYPE > +void LLPrimLinkInfo< DATA_TYPE >::mergeLinkableSet(std::list< LLPrimLinkInfo< DATA_TYPE > > & unlinked) +{ +	bool linked_something = true; +	while (linked_something) +	{ +		linked_something = false; + +		typename std::list< LLPrimLinkInfo< DATA_TYPE > >::iterator other_itr = unlinked.begin(); +		while ( other_itr != unlinked.end() +			   && getPrimCount() < MAX_PRIMS_PER_OBJECT ) +		{ +			S32 merge_count = merge(*other_itr); +			if (merge_count > 0) +			{ +				linked_something = true; +			} +			if (0 == (*other_itr).getPrimCount()) +			{ +				unlinked.erase(other_itr++); +			} +			else +			{ +				++other_itr; +			} +		} +		if (!linked_something +			&& unlinked.size() > 1) +		{ +			S32 collapse_count = collapse(unlinked); +			if (collapse_count > 0) +			{ +				linked_something = true; +			} +		} +	} +} + +// transforms all of the spheres into a new reference frame +template < typename DATA_TYPE > +void LLPrimLinkInfo< DATA_TYPE >::transform(const LLVector3& position, const LLQuaternion& rotation) +{ +	typename std::map< DATA_TYPE, LLSphere >::iterator map_itr; +	for (map_itr = mDataMap.begin(); map_itr != mDataMap.end(); ++map_itr) +	{ +		(*map_itr).second.setCenter((*map_itr).second.getCenter() * rotation + position); +	} +	mBoundingSphere.setCenter(mBoundingSphere.getCenter() * rotation + position); +} + +// private +// returns number of links made +template < typename DATA_TYPE > +S32 LLPrimLinkInfo< DATA_TYPE >::merge(LLPrimLinkInfo& other_info) +{ +	S32 link_count = 0; + +//	F32 other_radius = other_info.mBoundingSphere.getRadius(); +//	other_info.computeBoundingSphere(); +//	if ( other_radius != other_info.mBoundingSphere.getRadius() ) +//	{ +//		llinfos << "Other bounding sphere changed!!" << llendl; +//	} + +//	F32 this_radius = mBoundingSphere.getRadius(); +//	computeBoundingSphere(); +//	if ( this_radius != mBoundingSphere.getRadius() ) +//	{ +//		llinfos << "This bounding sphere changed!!" << llendl; +//	} + + +	F32 max_span = get_max_linkable_span(mBoundingSphere, other_info.mBoundingSphere); + +	//  F32 center_dist = (mBoundingSphere.getCenter() - other_info.mBoundingSphere.getCenter()).length(); +	//	llinfos << "objects are " << center_dist << "m apart" << llendl; +	F32 span = get_span(mBoundingSphere, other_info.mBoundingSphere); + +	F32 span_limit = max_span + (2.f * other_info.mBoundingSphere.getRadius()); +	if (span > span_limit) +	{ +		// there is no way any piece of other_info could link with this one +		// llinfos << "span too large:  " << span << " vs. " << span_limit << llendl; +		return 0; +	} + +	bool completely_linkable = (span <= max_span) ? true : false; + +	typename std::map< DATA_TYPE, LLSphere >::iterator map_itr = other_info.mDataMap.begin(); +	while (map_itr != other_info.mDataMap.end() +			&& getPrimCount() < MAX_PRIMS_PER_OBJECT ) +	{ +		DATA_TYPE other_data = (*map_itr).first; +		LLSphere& other_sphere = (*map_itr).second; + +		if (!completely_linkable) +		{ +			max_span = get_max_linkable_span(mBoundingSphere, other_sphere); +	 +			F32 span = get_span(mBoundingSphere, other_sphere); + +			if (span > max_span) +			{ +				++map_itr; +				continue; +			} +		} + +		mDataMap[other_data] = other_sphere; +		++link_count; + +		if (!mBoundingSphere.contains(other_sphere) ) +		{ +			computeBoundingSphere(); +		} + +		// remove from the other info +		other_info.mDataMap.erase(map_itr++); +	} + +	if (link_count > 0 && other_info.getPrimCount() > 0) +	{ +		other_info.computeBoundingSphere(); +	} +	return link_count; +} + +// links any linkable elements of unlinked +template < typename DATA_TYPE > +S32 LLPrimLinkInfo< DATA_TYPE >::collapse(std::list< LLPrimLinkInfo< DATA_TYPE > > & unlinked) +{  +	S32 link_count = 0; +	bool linked_something = true; +	while (linked_something) +	{ +		linked_something = false; + +		typename std::list< LLPrimLinkInfo< DATA_TYPE > >::iterator this_itr = unlinked.begin(); +		typename std::list< LLPrimLinkInfo< DATA_TYPE > >::iterator other_itr = this_itr; +		++other_itr; +		while ( other_itr != unlinked.end() ) +			    +		{ +			S32 merge_count = (*this_itr).merge(*other_itr); +			if (merge_count > 0) +			{ +				linked_something = true; +				link_count += merge_count; +			} +			if (0 == (*other_itr).getPrimCount()) +			{ +				unlinked.erase(other_itr++); +			} +			else +			{ +				++other_itr; +			} +		} +	} +	return link_count; +} + + +template < typename DATA_TYPE > +void LLPrimLinkInfo< DATA_TYPE >::computeBoundingSphere() +{  +	std::vector< LLSphere > sphere_list; +	typename std::map< DATA_TYPE, LLSphere >::const_iterator map_itr; +	for (map_itr = mDataMap.begin(); map_itr != mDataMap.end(); ++map_itr) +	{ +		sphere_list.push_back(map_itr->second); +	} +	mBoundingSphere = LLSphere::getBoundingSphere(sphere_list); +} + + +#endif + diff --git a/indra/newview/app_settings/keywords.ini b/indra/newview/app_settings/keywords.ini index 961e86c6cb..9a8b1f7537 100644 --- a/indra/newview/app_settings/keywords.ini +++ b/indra/newview/app_settings/keywords.ini @@ -339,7 +339,7 @@ PRIM_FLEXIBLE		Sets primitive flexibility to TRUE or FALSE  PRIM_POINT_LIGHT	Sets light emission to TRUE or FALSE  PRIM_TEMP_ON_REZ	Sets temporay on rez to TRUE or FALSE  PRIM_PHANTOM		Sets phantom to TRUE or FALSE -PRIM_CAST_SHADOWS	Enables or disables shadow casting for the primitive +PRIM_CAST_SHADOWS	DEPRECATED. Takes 1 parameter, an integer, but has no effect when set and always returns 0 if used in llGetPrimitiveParams.  PRIM_POSITION		Sets primitive position to a vector position  PRIM_SIZE			Sets primitive size to a vector size  PRIM_ROTATION		Sets primitive rotation diff --git a/indra/newview/linux_tools/handle_secondlifeprotocol.sh b/indra/newview/linux_tools/handle_secondlifeprotocol.sh index 7ff86d1b93..7ff86d1b93 100755..100644 --- a/indra/newview/linux_tools/handle_secondlifeprotocol.sh +++ b/indra/newview/linux_tools/handle_secondlifeprotocol.sh diff --git a/indra/newview/linux_tools/register_secondlifeprotocol.sh b/indra/newview/linux_tools/register_secondlifeprotocol.sh index 4ab96f97d6..4ab96f97d6 100755..100644 --- a/indra/newview/linux_tools/register_secondlifeprotocol.sh +++ b/indra/newview/linux_tools/register_secondlifeprotocol.sh diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index d00dfef478..2f5589a966 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -92,7 +92,7 @@  #include "llquantize.h"  #include "llselectmgr.h"  #include "llsky.h" -#include "llsphere.h" +#include "llrendersphere.h"  #include "llstatusbar.h"  #include "llimview.h"  #include "lltool.h" @@ -1907,7 +1907,7 @@ void LLAgent::cameraOrbitIn(const F32 meters)  		if( CAMERA_MODE_CUSTOMIZE_AVATAR == getCameraMode() )  		{ -			llclamp( new_distance, APPEARANCE_MIN_ZOOM, APPEARANCE_MAX_ZOOM ); +			new_distance = llclamp( new_distance, APPEARANCE_MIN_ZOOM, APPEARANCE_MAX_ZOOM );  		}  		// Compute new camera offset @@ -6891,7 +6891,7 @@ void LLAgent::sendAgentSetAppearance()  	msg->addUUIDFast(_PREHASH_AgentID, getID());  	msg->addUUIDFast(_PREHASH_SessionID, getSessionID()); -	// correct for the collisiton tolerance (to make it look like the  +	// correct for the collision tolerance (to make it look like the   	// agent is actually walking on the ground/object)  	// NOTE -- when we start correcting all of the other Havok geometry   	// to compensate for the COLLISION_TOLERANCE ugliness we will have  diff --git a/indra/newview/llagent.h b/indra/newview/llagent.h index 50830a75f0..1a7d239288 100644 --- a/indra/newview/llagent.h +++ b/indra/newview/llagent.h @@ -181,7 +181,7 @@ public:  	void			updateCamera();			// call once per frame to update camera location/orientation  	void			resetCamera();						// slam camera into its default position  	void			setupSitCamera(); -	void			setCameraCollidePlane(LLVector4 &plane) { mCameraCollidePlane = plane; } +	void			setCameraCollidePlane(const LLVector4 &plane) { mCameraCollidePlane = plane; }  	void			changeCameraToDefault();  	void			changeCameraToMouselook(BOOL animate = TRUE); @@ -428,7 +428,7 @@ public:  	U32 			getControlFlags();   	void 			setControlFlags(U32 mask); 			// performs bitwise mControlFlags |= mask -	void 			clearControlFlags(U32 mask); 			// performs bitwise mControlFlags &= mask +	void 			clearControlFlags(U32 mask); 			// performs bitwise mControlFlags &= ~mask  	BOOL			controlFlagsDirty() const;  	void			enableControlFlagReset();  	void 			resetControlFlags(); diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 502160716e..fc092e5cba 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -32,6 +32,7 @@  #include "llviewerprecompiledheaders.h"  #include "llappviewer.h" +#include "llprimitive.h"  #include "llversionviewer.h"  #include "llfeaturemanager.h" @@ -1207,10 +1208,12 @@ bool LLAppViewer::cleanup()  	gLcdScreen = NULL;  #endif -	if (!gVolumeMgr->cleanup()) +	LLVolumeMgr* volume_manager = LLPrimitive::getVolumeManager(); +	if (!volume_manager->cleanup())  	{  		llwarns << "Remaining references in the volume manager!" << llendflush;  	} +	LLPrimitive::cleanupVolumeManager();  	LLViewerParcelMgr::cleanupGlobals(); @@ -1219,7 +1222,8 @@ bool LLAppViewer::cleanup()   	//end_messaging_system();  	LLFollowCamMgr::cleanupClass(); -	LLVolumeMgr::cleanupClass(); +	//LLVolumeMgr::cleanupClass(); +	LLPrimitive::cleanupVolumeManager();  	LLWorldMapView::cleanupClass();  	LLUI::cleanupClass(); @@ -1766,7 +1770,10 @@ bool LLAppViewer::initConfiguration()  	LLSplashScreen::show();  	LLSplashScreen::update(splash_msg.str().c_str()); -	LLVolumeMgr::initClass(); +	//LLVolumeMgr::initClass(); +	LLVolumeMgr* volume_manager = new LLVolumeMgr(); +	volume_manager->useMutex();	// LLApp and LLMutex magic must be manually enabled +	LLPrimitive::setVolumeManager(volume_manager);  	// Note: this is where we used to initialize LLFeatureManager::getInstance()->. diff --git a/indra/newview/llflexibleobject.cpp b/indra/newview/llflexibleobject.cpp index b700faeccc..c18dc069a4 100644 --- a/indra/newview/llflexibleobject.cpp +++ b/indra/newview/llflexibleobject.cpp @@ -36,7 +36,7 @@  #include "llface.h"  #include "llflexibleobject.h"  #include "llglheaders.h" -#include "llsphere.h" +#include "llrendersphere.h"  #include "llviewerobject.h"  #include "llimagegl.h"  #include "llagent.h" diff --git a/indra/newview/llglsandbox.cpp b/indra/newview/llglsandbox.cpp index a29136214c..493b69f99e 100644 --- a/indra/newview/llglsandbox.cpp +++ b/indra/newview/llglsandbox.cpp @@ -53,7 +53,7 @@  #include "lltoolmgr.h"  #include "llselectmgr.h"  #include "llhudmanager.h" -#include "llsphere.h" +#include "llrendersphere.h"  #include "llviewerobjectlist.h"  #include "lltoolselectrect.h"  #include "llviewerwindow.h" diff --git a/indra/newview/llhudeffect.cpp b/indra/newview/llhudeffect.cpp index 1385141bd0..83fdb66fe5 100644 --- a/indra/newview/llhudeffect.cpp +++ b/indra/newview/llhudeffect.cpp @@ -36,7 +36,7 @@  #include "message.h"  #include "llgl.h"  #include "llagent.h" -#include "llsphere.h" +#include "llrendersphere.h"  #include "llimagegl.h"  #include "llviewerobjectlist.h" diff --git a/indra/newview/llhudeffectbeam.cpp b/indra/newview/llhudeffectbeam.cpp index 613a234ba5..9fae0e3387 100644 --- a/indra/newview/llhudeffectbeam.cpp +++ b/indra/newview/llhudeffectbeam.cpp @@ -43,7 +43,7 @@  #include "llglheaders.h"  #include "llhudrender.h"  #include "llimagegl.h" -#include "llsphere.h" +#include "llrendersphere.h"  #include "llviewercamera.h"  #include "llvoavatar.h"  #include "llviewercontrol.h" diff --git a/indra/newview/llhudeffectlookat.cpp b/indra/newview/llhudeffectlookat.cpp index 920a1caaf3..613f310b08 100644 --- a/indra/newview/llhudeffectlookat.cpp +++ b/indra/newview/llhudeffectlookat.cpp @@ -40,7 +40,7 @@  #include "llvoavatar.h"  #include "lldrawable.h"  #include "llviewerobjectlist.h" -#include "llsphere.h" +#include "llrendersphere.h"  #include "llselectmgr.h"  #include "llglheaders.h" diff --git a/indra/newview/llmanipscale.cpp b/indra/newview/llmanipscale.cpp index cd9cd83968..a2d6909b28 100644 --- a/indra/newview/llmanipscale.cpp +++ b/indra/newview/llmanipscale.cpp @@ -962,8 +962,8 @@ void LLManipScale::dragCorner( S32 x, S32 y )  		mInSnapRegime = FALSE;  	} -	F32 max_scale_factor = MAX_OBJECT_SCALE / MIN_OBJECT_SCALE; -	F32 min_scale_factor = MIN_OBJECT_SCALE / MAX_OBJECT_SCALE; +	F32 max_scale_factor = DEFAULT_MAX_PRIM_SCALE / MIN_PRIM_SCALE; +	F32 min_scale_factor = MIN_PRIM_SCALE / DEFAULT_MAX_PRIM_SCALE;  	// find max and min scale factors that will make biggest object hit max absolute scale and smallest object hit min absolute scale  	for (LLObjectSelection::iterator iter = mObjectSelection->begin(); @@ -975,10 +975,10 @@ void LLManipScale::dragCorner( S32 x, S32 y )  		{  			const LLVector3& scale = selectNode->mSavedScale; -			F32 cur_max_scale_factor = llmin( MAX_OBJECT_SCALE / scale.mV[VX], MAX_OBJECT_SCALE / scale.mV[VY], MAX_OBJECT_SCALE / scale.mV[VZ] ); +			F32 cur_max_scale_factor = llmin( DEFAULT_MAX_PRIM_SCALE / scale.mV[VX], DEFAULT_MAX_PRIM_SCALE / scale.mV[VY], DEFAULT_MAX_PRIM_SCALE / scale.mV[VZ] );  			max_scale_factor = llmin( max_scale_factor, cur_max_scale_factor ); -			F32 cur_min_scale_factor = llmax( MIN_OBJECT_SCALE / scale.mV[VX], MIN_OBJECT_SCALE / scale.mV[VY], MIN_OBJECT_SCALE / scale.mV[VZ] ); +			F32 cur_min_scale_factor = llmax( MIN_PRIM_SCALE / scale.mV[VX], MIN_PRIM_SCALE / scale.mV[VY], MIN_PRIM_SCALE / scale.mV[VZ] );  			min_scale_factor = llmax( min_scale_factor, cur_min_scale_factor );  		}  	} @@ -1270,7 +1270,7 @@ void LLManipScale::stretchFace( const LLVector3& drag_start_agent, const LLVecto  			F32 denom = axis * dir_local;  			F32 desired_delta_size	= is_approx_zero(denom) ? 0.f : (delta_local_mag / denom);  // in meters -			F32 desired_scale		= llclamp(selectNode->mSavedScale.mV[axis_index] + desired_delta_size, MIN_OBJECT_SCALE, MAX_OBJECT_SCALE); +			F32 desired_scale		= llclamp(selectNode->mSavedScale.mV[axis_index] + desired_delta_size, MIN_PRIM_SCALE, DEFAULT_MAX_PRIM_SCALE);  			// propagate scale constraint back to position offset  			desired_delta_size		= desired_scale - selectNode->mSavedScale.mV[axis_index]; // propagate constraint back to position @@ -1968,7 +1968,7 @@ F32		LLManipScale::partToMaxScale( S32 part, const LLBBox &bbox ) const  			max_extent = bbox_extents.mV[i];  		}  	} -	max_scale_factor = bbox_extents.magVec() * MAX_OBJECT_SCALE / max_extent; +	max_scale_factor = bbox_extents.magVec() * DEFAULT_MAX_PRIM_SCALE / max_extent;  	if (getUniform())  	{ @@ -1983,7 +1983,7 @@ F32		LLManipScale::partToMinScale( S32 part, const LLBBox &bbox ) const  {  	LLVector3 bbox_extents = unitVectorToLocalBBoxExtent( partToUnitVector( part ), bbox );  	bbox_extents.abs(); -	F32 min_extent = MAX_OBJECT_SCALE; +	F32 min_extent = DEFAULT_MAX_PRIM_SCALE;  	for (U32 i = VX; i <= VZ; i++)  	{  		if (bbox_extents.mV[i] > 0.f && bbox_extents.mV[i] < min_extent) @@ -1991,7 +1991,7 @@ F32		LLManipScale::partToMinScale( S32 part, const LLBBox &bbox ) const  			min_extent = bbox_extents.mV[i];  		}  	} -	F32 min_scale_factor = bbox_extents.magVec() * MIN_OBJECT_SCALE / min_extent; +	F32 min_scale_factor = bbox_extents.magVec() * MIN_PRIM_SCALE / min_extent;  	if (getUniform())  	{ diff --git a/indra/newview/llmaniptranslate.cpp b/indra/newview/llmaniptranslate.cpp index 9856b47830..c55f9f806a 100644 --- a/indra/newview/llmaniptranslate.cpp +++ b/indra/newview/llmaniptranslate.cpp @@ -53,7 +53,7 @@  #include "llhudrender.h"  #include "llresmgr.h"  #include "llselectmgr.h" -#include "llsphere.h" +#include "llrendersphere.h"  #include "llstatusbar.h"  #include "lltoolmgr.h"  #include "llviewercamera.h" diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp index 83f72160e1..d6ac5908dc 100644 --- a/indra/newview/llpanelobject.cpp +++ b/indra/newview/llpanelobject.cpp @@ -1666,15 +1666,8 @@ void LLPanelObject::sendPosition()  				mObject->setPositionEdit(newpos);  			}  			LLSelectMgr::getInstance()->sendMultipleUpdate(UPD_POSITION); -			//mRootObject->sendPositionUpdate();  			LLSelectMgr::getInstance()->updateSelectionCenter(); - -//			llinfos << "position sent" << llendl; -		} -		else -		{ -//			llinfos << "position not changed" << llendl;  		}  	}  	else diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 331d13d85d..fb692d257b 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -3263,6 +3263,41 @@ void init_stat_view()  	stat_barp->mDisplayBar = FALSE;  	stat_barp->mDisplayMean = FALSE; +	LLStatView *phys_details_viewp; +	phys_details_viewp = new LLStatView("phys detail view", "Physics Details", "", rect); +	sim_statviewp->addChildAtEnd(phys_details_viewp); + +	stat_barp = phys_details_viewp->addStat("Pinned Objects", &(LLViewerStats::getInstance()->mPhysicsPinnedTasks)); +	stat_barp->mPrecision = 0; +	stat_barp->mMinBar = 0.f; +	stat_barp->mMaxBar = 500.f; +	stat_barp->mTickSpacing = 10.f; +	stat_barp->mLabelSpacing = 40.f; +	stat_barp->mPerSec = FALSE; +	stat_barp->mDisplayBar = FALSE; +	stat_barp->mDisplayMean = FALSE; + +	stat_barp = phys_details_viewp->addStat("Low LOD Objects", &(LLViewerStats::getInstance()->mPhysicsLODTasks)); +	stat_barp->mPrecision = 0; +	stat_barp->mMinBar = 0.f; +	stat_barp->mMaxBar = 500.f; +	stat_barp->mTickSpacing = 10.f; +	stat_barp->mLabelSpacing = 40.f; +	stat_barp->mPerSec = FALSE; +	stat_barp->mDisplayBar = FALSE; +	stat_barp->mDisplayMean = FALSE; + +	stat_barp = phys_details_viewp->addStat("Memory Allocated", &(LLViewerStats::getInstance()->mPhysicsMemoryAllocated)); +	stat_barp->setUnitLabel(" MB"); +	stat_barp->mPrecision = 0; +	stat_barp->mMinBar = 0.f; +	stat_barp->mMaxBar = 1024.f; +	stat_barp->mTickSpacing = 128.f; +	stat_barp->mLabelSpacing = 256.f; +	stat_barp->mPerSec = FALSE; +	stat_barp->mDisplayBar = FALSE; +	stat_barp->mDisplayMean = FALSE; +  	stat_barp = sim_statviewp->addStat("Agent Updates/Sec", &(LLViewerStats::getInstance()->mSimAgentUPS));  	stat_barp->mPrecision = 1;  	stat_barp->mMinBar = 0.f; @@ -3424,6 +3459,44 @@ void init_stat_view()  	stat_barp->mDisplayBar = FALSE;  	stat_barp->mDisplayMean = FALSE; +	LLStatView *physics_time_viewp; +	physics_time_viewp = new LLStatView("physics perf view", "Physics Details (ms)", "", rect); +	sim_time_viewp->addChildAtEnd(physics_time_viewp); +	{ +		stat_barp = physics_time_viewp->addStat("Physics Step", &(LLViewerStats::getInstance()->mSimSimPhysicsStepMsec)); +		stat_barp->setUnitLabel("ms"); +		stat_barp->mPrecision = 1; +		stat_barp->mMinBar = 0.f; +		stat_barp->mMaxBar = 40.f; +		stat_barp->mTickSpacing = 10.f; +		stat_barp->mLabelSpacing = 20.f; +		stat_barp->mPerSec = FALSE; +		stat_barp->mDisplayBar = FALSE; +		stat_barp->mDisplayMean = FALSE; + +		stat_barp = physics_time_viewp->addStat("Update Shapes", &(LLViewerStats::getInstance()->mSimSimPhysicsShapeUpdateMsec)); +		stat_barp->setUnitLabel("ms"); +		stat_barp->mPrecision = 1; +		stat_barp->mMinBar = 0.f; +		stat_barp->mMaxBar = 40.f; +		stat_barp->mTickSpacing = 10.f; +		stat_barp->mLabelSpacing = 20.f; +		stat_barp->mPerSec = FALSE; +		stat_barp->mDisplayBar = FALSE; +		stat_barp->mDisplayMean = FALSE; + +		stat_barp = physics_time_viewp->addStat("Other", &(LLViewerStats::getInstance()->mSimSimPhysicsOtherMsec)); +		stat_barp->setUnitLabel("ms"); +		stat_barp->mPrecision = 1; +		stat_barp->mMinBar = 0.f; +		stat_barp->mMaxBar = 40.f; +		stat_barp->mTickSpacing = 10.f; +		stat_barp->mLabelSpacing = 20.f; +		stat_barp->mPerSec = FALSE; +		stat_barp->mDisplayBar = FALSE; +		stat_barp->mDisplayMean = FALSE; +	} +  	stat_barp = sim_time_viewp->addStat("Sim Time (Other)", &(LLViewerStats::getInstance()->mSimSimOtherMsec));  	stat_barp->setUnitLabel("ms");  	stat_barp->mPrecision = 1; diff --git a/indra/newview/llviewercamera.cpp b/indra/newview/llviewercamera.cpp index 517a02b4ad..8657f59ccb 100644 --- a/indra/newview/llviewercamera.cpp +++ b/indra/newview/llviewercamera.cpp @@ -168,7 +168,7 @@ void LLViewerCamera::calcProjection(const F32 far_distance) const  	f = 1/tan(fov_y*0.5f); -	mProjectionMatrix.zero(); +	mProjectionMatrix.setZero();  	mProjectionMatrix.mMatrix[0][0] = f/aspect;  	mProjectionMatrix.mMatrix[1][1] = f;  	mProjectionMatrix.mMatrix[2][2] = (z_far + z_near)/(z_near - z_far); diff --git a/indra/newview/llviewerjoint.cpp b/indra/newview/llviewerjoint.cpp index 04de6bed92..b1cad86a61 100644 --- a/indra/newview/llviewerjoint.cpp +++ b/indra/newview/llviewerjoint.cpp @@ -40,7 +40,7 @@  #include "llglimmediate.h"  #include "llmath.h"  #include "llglheaders.h" -#include "llsphere.h" +#include "llrendersphere.h"  #include "llvoavatar.h"  #include "pipeline.h" diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 4d7ef5e2fd..4234d4862c 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -1193,7 +1193,6 @@ void init_debug_ui_menu(LLMenuGL* menu)  	menu->append(new LLMenuItemCallGL( "Dump SelectMgr", &dump_select_mgr));  	menu->append(new LLMenuItemCallGL( "Dump Inventory", &dump_inventory));  	menu->append(new LLMenuItemCallGL( "Dump Focus Holder", &handle_dump_focus, NULL, NULL, 'F', MASK_ALT | MASK_CONTROL)); -	menu->append(new LLMenuItemCallGL( "Dump VolumeMgr",	&dump_volume_mgr, NULL, NULL));  	menu->append(new LLMenuItemCallGL( "Print Selected Object Info",	&print_object_info, NULL, NULL, 'P', MASK_CONTROL|MASK_SHIFT ));  	menu->append(new LLMenuItemCallGL( "Print Agent Info",			&print_agent_nvpairs, NULL, NULL, 'P', MASK_SHIFT ));  	menu->append(new LLMenuItemCallGL( "Texture Memory Stats",  &output_statistics, NULL, NULL, 'M', MASK_SHIFT | MASK_ALT | MASK_CONTROL)); @@ -5219,11 +5218,6 @@ void dump_select_mgr(void*)  	LLSelectMgr::getInstance()->dump();  } -void dump_volume_mgr(void*) -{ -	gVolumeMgr->dump(); -} -  void dump_inventory(void*)  {  	gInventory.dumpInventory(); diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 938034a009..439063e439 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -3490,6 +3490,24 @@ void process_sim_stats(LLMessageSystem *msg, void **user_data)  		case LL_SIM_STAT_TOTAL_UNACKED_BYTES:  			LLViewerStats::getInstance()->mSimTotalUnackedBytes.addValue(stat_value / 1024.f);  			break; +		case LL_SIM_STAT_PHYSICS_PINNED_TASKS: +			LLViewerStats::getInstance()->mPhysicsPinnedTasks.addValue(stat_value); +			break; +		case LL_SIM_STAT_PHYSICS_LOD_TASKS: +			LLViewerStats::getInstance()->mPhysicsLODTasks.addValue(stat_value); +			break; +		case LL_SIM_STAT_SIMPHYSICSSTEPMS: +			LLViewerStats::getInstance()->mSimSimPhysicsStepMsec.addValue(stat_value); +			break; +		case LL_SIM_STAT_SIMPHYSICSSHAPEMS: +			LLViewerStats::getInstance()->mSimSimPhysicsShapeUpdateMsec.addValue(stat_value); +			break; +		case LL_SIM_STAT_SIMPHYSICSOTHERMS: +			LLViewerStats::getInstance()->mSimSimPhysicsOtherMsec.addValue(stat_value); +			break; +		case LL_SIM_STAT_SIMPHYSICSMEMORY: +			LLViewerStats::getInstance()->mPhysicsMemoryAllocated.addValue(stat_value); +			break;  		default:  // 			llwarns << "Unknown stat id" << stat_id << llendl;  		  break; diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index d32eb6414c..30668172f1 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -67,7 +67,7 @@  #include "llfollowcam.h"  #include "llnetmap.h"  #include "llselectmgr.h" -#include "llsphere.h" +#include "llrendersphere.h"  #include "lltooldraganddrop.h"  #include "llviewercamera.h"  #include "llviewerimagelist.h" @@ -202,7 +202,7 @@ LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRe  {  	llassert(mRegionp); -	LLPrimitive::init(pcode); +	LLPrimitive::init_primitive(pcode);  	// CP: added 12/2/2005 - this was being initialised to 0, not the current frame time  	mLastInterpUpdateSecs = LLFrameTimer::getElapsedSeconds(); @@ -723,6 +723,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,  	LLVector3 new_vel;  	LLVector3 new_acc;  	LLVector3 new_angv; +	LLVector3 old_angv = getAngularVelocity();  	LLQuaternion new_rot;  	LLVector3 new_scale = getScale(); @@ -1857,7 +1858,8 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,  		}  	} -	if (new_rot != mLastRot) +	if (new_rot != mLastRot +		|| new_angv != old_angv)  	{  		mLastRot = new_rot;  		setChanged(ROTATED | SILHOUETTE); @@ -1974,7 +1976,7 @@ BOOL LLViewerObject::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)  		F32 dt_raw = (F32)(time - mLastInterpUpdateSecs);  		F32 dt = mTimeDilation * dt_raw; -		if (!mUserSelected && !mJointInfo) +		if (!mJointInfo)  		{  			applyAngularVelocity(dt);  		} @@ -2060,9 +2062,9 @@ BOOL LLViewerObject::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)  		else  		{  			// linear motion -			// HAVOK_TIMESTEP is used below to correct for the fact that the velocity in object +			// PHYSICS_TIMESTEP is used below to correct for the fact that the velocity in object  			// updates represents the average velocity of the last timestep, rather than the final velocity. -			// the time dilation above should guarrantee that dt is never less than HAVOK_TIMESTEP, theoretically +			// the time dilation above should guarantee that dt is never less than PHYSICS_TIMESTEP, theoretically  			//   			// There is a problem here if dt is negative. . . @@ -2074,7 +2076,7 @@ BOOL LLViewerObject::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)  			if (!(accel.isExactlyZero() && vel.isExactlyZero()))  			{ -				LLVector3 pos 	= (vel + (0.5f * (dt-HAVOK_TIMESTEP)) * accel) * dt;	 +				LLVector3 pos 	= (vel + (0.5f * (dt-PHYSICS_TIMESTEP)) * accel) * dt;	  				// region local    				setPositionRegion(pos + getPositionRegion()); @@ -3526,36 +3528,21 @@ void LLViewerObject::sendRotationUpdate() const  	gMessageSystem->sendReliable( regionp->getHost() );  } -// formerly send_object_position_global -void LLViewerObject::sendPositionUpdate() const -{ -	gMessageSystem->newMessageFast(_PREHASH_ObjectPosition); -	gMessageSystem->nextBlockFast(_PREHASH_AgentData); -	gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); -	gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); -	gMessageSystem->nextBlockFast(_PREHASH_ObjectData); -	gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID,	mLocalID ); -	gMessageSystem->addVector3Fast(_PREHASH_Position, getPositionRegion()); -	LLViewerRegion* regionp = getRegion(); -	gMessageSystem->sendReliable(regionp->getHost()); -} - - -//formerly send_object_scale -void LLViewerObject::sendScaleUpdate() -{ -	gMessageSystem->newMessageFast(_PREHASH_ObjectScale); -	gMessageSystem->nextBlockFast(_PREHASH_AgentData); -	gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); -	gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); -	gMessageSystem->nextBlockFast(_PREHASH_ObjectData); -	gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID,	mLocalID ); -	gMessageSystem->addVector3Fast(_PREHASH_Scale,	(getScale())); - -	LLViewerRegion *regionp = getRegion(); -	gMessageSystem->sendReliable(regionp->getHost() ); -} - +/* Obsolete, we use MultipleObjectUpdate instead +//// formerly send_object_position_global +//void LLViewerObject::sendPositionUpdate() const +//{ +//	gMessageSystem->newMessageFast(_PREHASH_ObjectPosition); +//	gMessageSystem->nextBlockFast(_PREHASH_AgentData); +//	gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); +//	gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); +//	gMessageSystem->nextBlockFast(_PREHASH_ObjectData); +//	gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID,	mLocalID ); +//	gMessageSystem->addVector3Fast(_PREHASH_Position, getPositionRegion()); +//	LLViewerRegion* regionp = getRegion(); +//	gMessageSystem->sendReliable(regionp->getHost()); +//} +*/  //formerly send_object_shape(LLViewerObject *object)  void LLViewerObject::sendShapeUpdate() diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index 06cf2b2266..20616b32d6 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -268,7 +268,6 @@ public:  	void setPositionAgent(const LLVector3 &pos_agent, BOOL damped = FALSE);  	void setPositionParent(const LLVector3 &pos_parent, BOOL damped = FALSE);  	void setPositionAbsoluteGlobal( const LLVector3d &pos_global, BOOL damped = FALSE ); -	void sendPositionUpdate() const;  	virtual const LLMatrix4& getWorldMatrix(LLXformMatrix* xform) const		{ return xform->getWorldMatrix(); } @@ -303,7 +302,6 @@ public:  	void sendTEUpdate() const;			// Sends packed representation of all texture entry information  	virtual void setScale(const LLVector3 &scale, BOOL damped = FALSE); -	void sendScaleUpdate();  	void sendShapeUpdate(); diff --git a/indra/newview/llviewerpartsim.cpp b/indra/newview/llviewerpartsim.cpp index 6cfef5b18f..ccf7a5d1d7 100644 --- a/indra/newview/llviewerpartsim.cpp +++ b/indra/newview/llviewerpartsim.cpp @@ -243,7 +243,7 @@ void LLViewerPartGroup::updateParticles(const F32 lastdt)  	S32 i;  	F32 dt; -	LLVector3 gravity(0.f, 0.f, -9.8f); +	LLVector3 gravity(0.f, 0.f, GRAVITY);  	LLViewerRegion *regionp = getRegion();  	S32 end = (S32) mParticles.size(); diff --git a/indra/newview/llviewerstats.h b/indra/newview/llviewerstats.h index 819438832d..bd16e61149 100644 --- a/indra/newview/llviewerstats.h +++ b/indra/newview/llviewerstats.h @@ -69,6 +69,11 @@ public:  	LLStat mSimNetMsec;  	LLStat mSimSimOtherMsec;  	LLStat mSimSimPhysicsMsec; + +	LLStat mSimSimPhysicsStepMsec; +	LLStat mSimSimPhysicsShapeUpdateMsec; +	LLStat mSimSimPhysicsOtherMsec; +  	LLStat mSimAgentMsec;  	LLStat mSimImagesMsec;  	LLStat mSimScriptMsec; @@ -86,6 +91,9 @@ public:  	LLStat mSimPendingLocalUploads;  	LLStat mSimTotalUnackedBytes; +	LLStat mPhysicsPinnedTasks; +	LLStat mPhysicsLODTasks; +	LLStat mPhysicsMemoryAllocated;  	/*  	LLStat mSimCPUUsageStat;  	LLStat mSimMemTotalStat; diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 5c3128b8e0..697aea8582 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -131,7 +131,7 @@  #include "llresmgr.h"  #include "llrootview.h"  #include "llselectmgr.h" -#include "llsphere.h" +#include "llrendersphere.h"  #include "llstartup.h"  #include "llstatusbar.h"  #include "llstatview.h" diff --git a/indra/newview/llvotextbubble.cpp b/indra/newview/llvotextbubble.cpp index 775b1ec61d..b48a5a989c 100644 --- a/indra/newview/llvotextbubble.cpp +++ b/indra/newview/llvotextbubble.cpp @@ -36,7 +36,7 @@  #include "imageids.h"  #include "llviewercontrol.h"  #include "llprimitive.h" -#include "llsphere.h" +#include "llrendersphere.h"  #include "llagent.h"  #include "llbox.h" diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index a1b3c32e01..2b8cf93b2d 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -83,8 +83,8 @@ LLVOVolume::LLVOVolume(const LLUUID &id, const LLPCode pcode, LLViewerRegion *re  	  mVolumeImpl(NULL)  {  	mTexAnimMode = 0; -	mRelativeXform.identity(); -	mRelativeXformInvTrans.identity(); +	mRelativeXform.setIdentity(); +	mRelativeXformInvTrans.setIdentity();  	mLOD = MIN_LOD;  	mTextureAnimp = NULL; @@ -326,7 +326,7 @@ void LLVOVolume::animateTextures()  			}  			LLMatrix4& tex_mat = *facep->mTextureMatrix; -			tex_mat.identity(); +			tex_mat.setIdentity();  			tex_mat.translate(LLVector3(-0.5f, -0.5f, 0.f));  			tex_mat.rotate(quat);				 diff --git a/indra/newview/llvowater.cpp b/indra/newview/llvowater.cpp index 8755a5ae4a..3cc834d323 100644 --- a/indra/newview/llvowater.cpp +++ b/indra/newview/llvowater.cpp @@ -67,7 +67,6 @@ const U32 N_RES_HALF	= (N_RES >> 1);  const U32 WIDTH			= (N_RES * WAVE_STEP); //128.f //64		// width of wave tile, in meters  const F32 WAVE_STEP_INV	= (1. / WAVE_STEP); -const F32 g				= 9.81f;          // gravitational constant (m/s^2)  LLVOWater::LLVOWater(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp)  :	LLStaticViewerObject(id, LL_VO_WATER, regionp) diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp index 923b45fc5a..ca947bed97 100644 --- a/indra/newview/llworld.cpp +++ b/indra/newview/llworld.cpp @@ -527,6 +527,11 @@ F32 LLWorld::resolveStepHeightGlobal(const LLVOAvatar* avatarp, const LLVector3d  			intersection.mdV[VZ] -= norm_dist_from_plane * segment_length;  			intersection_normal = foot_plane_normal;  		} +		else +		{ +			intersection = land_intersection; +			intersection_normal = resolveLandNormalGlobal(land_intersection); +		}  	}  	return normalized_land_distance; diff --git a/indra/newview/llworld.h b/indra/newview/llworld.h index cb6102268e..9dd90480b6 100644 --- a/indra/newview/llworld.h +++ b/indra/newview/llworld.h @@ -113,7 +113,7 @@ public:  	// region X and Y size in meters  	F32						getRegionWidthInMeters() const	{ return mWidthInMeters; }  	F32						getRegionMinHeight() const		{ return -mWidthInMeters; } -	F32						getRegionMaxHeight() const		{ return 3.f*mWidthInMeters; } +	F32						getRegionMaxHeight() const		{ return MAX_OBJECT_Z; }  	void					updateRegions(F32 max_update_time);  	void					updateVisibilities(); diff --git a/indra/newview/macview_Prefix.h b/indra/newview/macview_Prefix.h index ac19cd924e..b6dcc1d127 100644 --- a/indra/newview/macview_Prefix.h +++ b/indra/newview/macview_Prefix.h @@ -82,7 +82,7 @@  #include "llmoveview.h"  #include "llselectmgr.h"  #include "llsky.h" -#include "llsphere.h" +#include "llrendersphere.h"  #include "llstatusbar.h"  #include "lltalkview.h"  #include "lltool.h" diff --git a/indra/test/io.cpp b/indra/test/io.cpp index c322522ce3..3de1e8edef 100644 --- a/indra/test/io.cpp +++ b/indra/test/io.cpp @@ -1151,7 +1151,7 @@ namespace tut  		chain.push_back(LLIOPipe::ptr_t(new LLPipeStringInjector("hi")));  		chain.push_back(LLIOPipe::ptr_t(new LLIOSocketWriter(client)));  		chain.push_back(LLIOPipe::ptr_t(new LLIONull)); -		mPump->addChain(chain, 0.2); +		mPump->addChain(chain, 0.2f);  		chain.clear();  		// pump for a bit and make sure all 3 chains are running diff --git a/indra/test/lltut.h b/indra/test/lltut.h index 1827624dbf..375d558182 100644 --- a/indra/test/lltut.h +++ b/indra/test/lltut.h @@ -44,6 +44,16 @@ class LLSD;  namespace tut  { +	inline void ensure_approximately_equals(const char* msg, F64 actual, F64 expected, U32 frac_bits) +	{ +		if(!is_approx_equal_fraction(actual, expected, frac_bits)) +		{ +			std::stringstream ss; +			ss << (msg?msg:"") << (msg?": ":"") << "not equal actual: " << actual << " expected: " << expected; +			throw tut::failure(ss.str().c_str()); +		} +	} +  	inline void ensure_approximately_equals(const char* msg, F32 actual, F32 expected, U32 frac_bits)  	{  		if(!is_approx_equal_fraction(actual, expected, frac_bits)) diff --git a/indra/test/prim_linkability_tut.cpp b/indra/test/prim_linkability_tut.cpp new file mode 100644 index 0000000000..d2236a5cff --- /dev/null +++ b/indra/test/prim_linkability_tut.cpp @@ -0,0 +1,477 @@ +/**  + * @file linkability.cpp + * @author andrew@lindenlab.com + * @date 2007-04-23 + * @brief Tests for the LLPrimLinkInfo template which computes the linkability of prims + * + * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc. + * $License$ + */ + +#include "linden_common.h" +#include "lltut.h" +#include "llprimlinkinfo.h" +#include "llrand.h" + + +// helper function +void randomize_sphere(LLSphere& sphere, F32 center_range, F32 radius_range) +{ +	F32 radius = ll_frand(2.f * radius_range) - radius_range; +	LLVector3 center; +	for (S32 i=0; i<3; ++i) +	{ +		center.mV[i] = ll_frand(2.f * center_range) - center_range; +	} +	sphere.setRadius(radius); +	sphere.setCenter(center); +} + +// helper function.  Same as above with a min and max radius. +void randomize_sphere(LLSphere& sphere, F32 center_range, F32 minimum_radius, F32 maximum_radius) +{ +	F32 radius = ll_frand(maximum_radius - minimum_radius) + minimum_radius;  +	LLVector3 center; +	for (S32 i=0; i<3; ++i) +	{ +		center.mV[i] = ll_frand(2.f * center_range) - center_range; +	} +	sphere.setRadius(radius); +	sphere.setCenter(center); +} + +// helper function +bool random_sort( const LLPrimLinkInfo< S32 >&, const LLPrimLinkInfo< S32 >& b) +{ +	return (ll_rand(64) < 32); +} + +namespace tut +{ +	struct linkable_data +	{ +		LLPrimLinkInfo<S32> info; +	}; + +	typedef test_group<linkable_data> linkable_test; +	typedef linkable_test::object linkable_object; +	tut::linkable_test wtf("prim linkability"); + +	template<> template<> +	void linkable_object::test<1>() +	{ +		// Here we test the boundary of the LLPrimLinkInfo::canLink() method  +		// between semi-random middle-sized objects. + +		S32 number_of_tests = 100; +		for (S32 test = 0; test < number_of_tests; ++test) +		{ +			// compute the radii that would provide the above max link distance +			F32 first_radius = 0.f; +			F32 second_radius = 0.f; +			 +			// compute a random center for the first sphere +			// compute some random max link distance +			F32 max_link_span = ll_frand(MAX_OBJECT_SPAN); +			if (max_link_span < OBJECT_SPAN_BONUS) +			{ +				max_link_span += OBJECT_SPAN_BONUS; +			} +			LLVector3 first_center( +					ll_frand(2.f * max_link_span) - max_link_span,  +					ll_frand(2.f * max_link_span) - max_link_span,  +					ll_frand(2.f * max_link_span) - max_link_span); + +			// put the second sphere at the right distance from the origin +			// such that it is within the max_link_distance of the first +			LLVector3 direction(ll_frand(2.f) - 1.f, ll_frand(2.f) - 1.f, ll_frand(2.f) - 1.f); +			direction.normalize(); +			F32 half_milimeter = 0.0005f; +			LLVector3 second_center; + +			// max_span = 3 * (first_radius + second_radius) + OBJECT_SPAN_BONUS +			// make sure they link at short distances +			{ +				second_center = first_center + (OBJECT_SPAN_BONUS - half_milimeter) * direction; +				LLPrimLinkInfo<S32> first_info(0, LLSphere(first_center, first_radius) ); +				LLPrimLinkInfo<S32> second_info(1, LLSphere(second_center, second_radius) ); +				ensure("these nearby objects should link", first_info.canLink(second_info) ); +			} + +			// make sure they fail to link if we move them apart just a little bit +			{ +				second_center = first_center + (OBJECT_SPAN_BONUS + half_milimeter) * direction; +				LLPrimLinkInfo<S32> first_info(0, LLSphere(first_center, first_radius) ); +				LLPrimLinkInfo<S32> second_info(1, LLSphere(second_center, second_radius) ); +				ensure("these nearby objects should NOT link", !first_info.canLink(second_info) ); +			} + +			// make sure the objects link or not at medium distances +			{ +				first_radius = 0.3f * ll_frand(max_link_span - OBJECT_SPAN_BONUS); + +				// This is the exact second radius that will link at exactly our random max_link_distance +				second_radius = ((max_link_span - OBJECT_SPAN_BONUS) / 3.f) - first_radius; +				second_center = first_center + (max_link_span - first_radius - second_radius - half_milimeter) * direction; + +				LLPrimLinkInfo<S32> first_info(0, LLSphere(first_center, first_radius) ); +				LLPrimLinkInfo<S32> second_info(1, LLSphere(second_center, second_radius) ); + +				ensure("these objects should link", first_info.canLink(second_info) ); +			} + +			// make sure they fail to link if we move them apart just a little bit +			{ +				// move the second sphere such that it is a little too far from the first +				second_center += (2.f * half_milimeter) * direction; +				LLPrimLinkInfo<S32> first_info(0, LLSphere(first_center, first_radius) ); +				LLPrimLinkInfo<S32> second_info(1, LLSphere(second_center, second_radius) ); +				 +				ensure("these objects should NOT link", !first_info.canLink(second_info) ); +			} + +			// make sure things don't link at far distances +			{ +				second_center = first_center + (MAX_OBJECT_SPAN + 2.f * half_milimeter) * direction; +				second_radius = 0.3f * MAX_OBJECT_SPAN; +				LLPrimLinkInfo<S32> first_info(0, LLSphere(first_center, first_radius) ); +				LLPrimLinkInfo<S32> second_info(1, LLSphere(second_center, second_radius) ); +				ensure("these objects should NOT link", !first_info.canLink(second_info) ); +			} +			 +		} +	} + +	template<> template<> +	void linkable_object::test<2>() +	{ + +		// Consider a row of eight spheres in a row, each 10m in diameter and centered +		// at 10m intervals:  01234567. + +		F32 radius = 5.f; +		F32 spacing = 10.f; + +		LLVector3 line_direction(ll_frand(2.f) - 1.f, ll_frand(2.f) - 1.f, ll_frand(2.f) - 1.f); +		line_direction.normalize(); + +		LLVector3 first_center(ll_frand(2.f * spacing) -spacing, ll_frand(2.f * spacing) - spacing, ll_frand(2.f * spacing) - spacing); + +		LLPrimLinkInfo<S32> infos[8]; + +		for (S32 index = 0; index < 8; ++index) +		{ +			LLVector3 center = first_center + ((F32)(index) * spacing) * line_direction; +			infos[index].set(index, LLSphere(center, radius)); +		} + +		// Max span for 2 spheres of 5m radius is 3 * (5 + 5) + 1 = 31m +		// spheres 0&2 have a 30m span (from outside edge to outside edge) and should link +		{ +			LLPrimLinkInfo<S32> root_info = infos[0]; +			std::list< LLPrimLinkInfo<S32> > info_list; +			info_list.push_back(infos[2]); +			root_info.mergeLinkableSet(info_list); +			S32 prim_count = root_info.getPrimCount(); +			ensure_equals("0&2 prim count should be 2", prim_count, 2); +			ensure_equals("0&2 unlinkable list should have length 0", (S32) info_list.size(), 0); +		} + +		 +		// spheres 0&3 have a 40 meter span and should NOT link outright +		{ +			LLPrimLinkInfo<S32> root_info = infos[0]; +			std::list< LLPrimLinkInfo<S32> > info_list; +			info_list.push_back(infos[3]); +			root_info.mergeLinkableSet(info_list); +			S32 prim_count = root_info.getPrimCount(); +			ensure_equals("0&4 prim count should be 1", prim_count, 1); +			ensure_equals("0&4 unlinkable list should have length 1", (S32) info_list.size(), 1); +		} + +		 +		// spheres 0-4 should link no matter what order : 01234 +		// Total span = 50m, 012 link with a r=15.5 giving max span of 3 * (15.5 + 5) + 1 = 62.5, but the cap is 54m +		{ +			LLPrimLinkInfo<S32> root_info = infos[0]; +			std::list< LLPrimLinkInfo<S32> > info_list; +			for (S32 index = 1; index < 5; ++index) +			{ +				info_list.push_back(infos[index]); +			} +			root_info.mergeLinkableSet(info_list); +			S32 prim_count = root_info.getPrimCount(); +			ensure_equals("01234 prim count should be 5", prim_count, 5); +			ensure_equals("01234 unlinkable list should have length 0", (S32) info_list.size(), 0); +		} + +		 +		// spheres 0-5 should link no matter what order : 04321 +		{ +			LLPrimLinkInfo<S32> root_info = infos[0]; +			std::list< LLPrimLinkInfo<S32> > info_list; +			for (S32 index = 4; index > 0; --index) +			{ +				info_list.push_back(infos[index]); +			} +			root_info.mergeLinkableSet(info_list); +			S32 prim_count = root_info.getPrimCount(); +			ensure_equals("04321 prim count should be 5", prim_count, 5); +			ensure_equals("04321 unlinkable list should have length 0", (S32) info_list.size(), 0); +		} + +		// spheres 0-4 should link no matter what order : 01423 +		{ +			LLPrimLinkInfo<S32> root_info = infos[0]; +			std::list< LLPrimLinkInfo<S32> > info_list; +			info_list.push_back(infos[1]); +			info_list.push_back(infos[4]); +			info_list.push_back(infos[2]); +			info_list.push_back(infos[3]); +			root_info.mergeLinkableSet(info_list); +			S32 prim_count = root_info.getPrimCount(); +			ensure_equals("01423 prim count should be 5", prim_count, 5); +			ensure_equals("01423 unlinkable list should have length 0", (S32) info_list.size(), 0); +		} + +		// spheres 0-5 should NOT fully link, only 0-4  +		{ +			LLPrimLinkInfo<S32> root_info = infos[0]; +			std::list< LLPrimLinkInfo<S32> > info_list; +			for (S32 index = 1; index < 6; ++index) +			{ +				info_list.push_back(infos[index]); +			} +			root_info.mergeLinkableSet(info_list); +			S32 prim_count = root_info.getPrimCount(); +			ensure_equals("012345 prim count should be 5", prim_count, 5); +			ensure_equals("012345 unlinkable list should have length 1", (S32) info_list.size(), 1); +			std::list< LLPrimLinkInfo<S32> >::iterator info_itr = info_list.begin(); +			if (info_itr != info_list.end()) +			{ +				// examine the contents of the unlinked info +				std::list<S32> unlinked_indecies; +				info_itr->getData(unlinked_indecies); +				// make sure there is only one index in the unlinked_info +				ensure_equals("012345 unlinkable index count should be 1", (S32) unlinked_indecies.size(), 1); +				// make sure its value is 6 +				std::list<S32>::iterator unlinked_index_itr = unlinked_indecies.begin(); +				S32 unlinkable_index = *unlinked_index_itr; +				ensure_equals("012345 unlinkable index should be 5", (S32) unlinkable_index, 5); +			} +		} +		 +		// spheres 0-7 should NOT fully link, only 0-5  +		{ +			LLPrimLinkInfo<S32> root_info = infos[0]; +			std::list< LLPrimLinkInfo<S32> > info_list; +			for (S32 index = 1; index < 8; ++index) +			{ +				info_list.push_back(infos[index]); +			} +			root_info.mergeLinkableSet(info_list); +			S32 prim_count = root_info.getPrimCount(); +			ensure_equals("01234567 prim count should be 5", prim_count, 5); +			// Should be 1 linkinfo on unlinkable that has 2 prims +			ensure_equals("01234567 unlinkable list should have length 1", (S32) info_list.size(), 1); +			std::list< LLPrimLinkInfo<S32> >::iterator info_itr = info_list.begin(); +			if (info_itr != info_list.end()) +			{ +				// make sure there is only one index in the unlinked_info +				std::list<S32> unlinked_indecies; +				info_itr->getData(unlinked_indecies); +				ensure_equals("0123456 unlinkable index count should be 3", (S32) unlinked_indecies.size(), 3); + +				// make sure its values are 6 and 7 +				std::list<S32>::iterator unlinked_index_itr = unlinked_indecies.begin(); +				S32 unlinkable_index = *unlinked_index_itr; +				ensure_equals("0123456 first unlinkable index should be 5", (S32) unlinkable_index, 5); +				++unlinked_index_itr; +				unlinkable_index = *unlinked_index_itr; +				ensure_equals("0123456 second unlinkable index should be 6", (S32) unlinkable_index, 6); +				++unlinked_index_itr; +				unlinkable_index = *unlinked_index_itr; +				ensure_equals("0123456 third unlinkable index should be 7", (S32) unlinkable_index, 7); + +			} +		} +	} + +	template<> template<> +	void linkable_object::test<3>() +	{ +		// Here we test the link results between an LLPrimLinkInfo and a set of +		// randomized LLPrimLinkInfos where the expected results are known. +		S32 number_of_tests = 5; +		for (S32 test = 0; test < number_of_tests; ++test) +		{ +			// the radii are known +			F32 first_radius = 1.f; +			F32 second_radius = 2.f; +			F32 third_radius = 3.f; + +			// compute the distances +			F32 half_milimeter = 0.0005f; +			F32 max_first_second_span = 3.f * (first_radius + second_radius) + OBJECT_SPAN_BONUS; +			F32 linkable_distance = max_first_second_span - first_radius - second_radius - half_milimeter; + +			F32 max_full_span = 3.f * (0.5f * max_first_second_span + third_radius) + OBJECT_SPAN_BONUS; +			F32 unlinkable_distance = max_full_span - 0.5f * linkable_distance - third_radius + half_milimeter; + +			// compute some random directions +			LLVector3 first_direction(ll_frand(2.f) - 1.f, ll_frand(2.f) - 1.f, ll_frand(2.f) - 1.f); +			first_direction.normalize(); +			LLVector3 second_direction(ll_frand(2.f) - 1.f, ll_frand(2.f) - 1.f, ll_frand(2.f) - 1.f); +			second_direction.normalize(); +			LLVector3 third_direction(ll_frand(2.f) - 1.f, ll_frand(2.f) - 1.f, ll_frand(2.f) - 1.f); +			third_direction.normalize(); +	 +			// compute the centers +			LLVector3 first_center = ll_frand(10.f) * first_direction; +			LLVector3 second_center = first_center + ll_frand(linkable_distance) * second_direction; +			LLVector3 first_join_center = 0.5f * (first_center + second_center); +			LLVector3 third_center = first_join_center + unlinkable_distance * third_direction; + +			// make sure the second info links and the third does not +			{ +				// initialize the infos +				S32 index = 0; +				LLPrimLinkInfo<S32> first_info(index++, LLSphere(first_center, first_radius)); +				LLPrimLinkInfo<S32> second_info(index++, LLSphere(second_center, second_radius)); +				LLPrimLinkInfo<S32> third_info(index++, LLSphere(third_center, third_radius)); +	 +				// put the second and third infos in a list +				std::list< LLPrimLinkInfo<S32> > info_list; +				info_list.push_back(second_info); +				info_list.push_back(third_info);  +	 +				// merge the list with the first_info +				first_info.mergeLinkableSet(info_list); +				S32 prim_count = first_info.getPrimCount(); + +				ensure_equals("prim count should be 2", prim_count, 2); +				ensure_equals("unlinkable list should have length 1", (S32) info_list.size(), 1); +			} + +			// reverse the order and make sure we get the same results +			{ +				// initialize the infos +				S32 index = 0; +				LLPrimLinkInfo<S32> first_info(index++, LLSphere(first_center, first_radius)); +				LLPrimLinkInfo<S32> second_info(index++, LLSphere(second_center, second_radius)); +				LLPrimLinkInfo<S32> third_info(index++, LLSphere(third_center, third_radius)); +	 +				// build the list in the reverse order +				std::list< LLPrimLinkInfo<S32> > info_list; +				info_list.push_back(third_info);  +				info_list.push_back(second_info); +	 +				// merge the list with the first_info +				first_info.mergeLinkableSet(info_list); +				S32 prim_count = first_info.getPrimCount(); + +				ensure_equals("prim count should be 2", prim_count, 2); +				ensure_equals("unlinkable list should have length 1", (S32) info_list.size(), 1); +			} +		} +	} + +	template<> template<> +	void linkable_object::test<4>() +	{ +		// Here we test whether linkability is invarient under permutations +		// of link order.  To do this we generate a bunch of random spheres +		// and then try to link them in different ways. +		// +		// NOTE: the linkability will only be invarient if there is only one +		// linkable solution.  Multiple solutions will exist if the set of  +		// candidates are larger than the maximum linkable distance, or more  +		// numerous than a single linked object can contain.  This is easily  +		// understood by considering a very large set of link candidates,  +		// and first linking preferentially to the left until linking fails,  +		// then doing the same to the right -- the final solutions will differ. +		// Hence for this test we must generate candidate sets that lie within  +		// the linkability envelope of a single object. +		// +		// NOTE: a random set of objects will tend to either be totally linkable +		// or totally not.  That is, the random orientations that  + +		F32 root_center_range = 0.f; +		F32 min_prim_radius = 0.1f; +		F32 max_prim_radius = 2.f; +		 +		// Linkability is min(MAX_OBJECT_SPAN,3 *( R1 + R2 ) + BONUS) +		// 3 * (min_prim_radius + min_prim_radius) + OBJECT_SPAN_BONUS = 6 * min_prim_radius + OBJECT_SPAN_BONUS; +		// Use .45 instead of .5 to gaurantee objects are within the minimum span. +		F32 child_center_range = 0.45f * ( (6*min_prim_radius) + OBJECT_SPAN_BONUS ); + +		S32 number_of_tests = 100; +		S32 number_of_spheres = 10; +		S32 number_of_scrambles = 10; +		S32 number_of_random_bubble_sorts = 10; + +		for (S32 test = 0; test < number_of_tests; ++test) +		{ +			LLSphere sphere; +			S32 sphere_index = 0; + +			// build the root piece +			randomize_sphere(sphere, root_center_range, min_prim_radius, max_prim_radius); +			info.set( sphere_index++, sphere ); + +			// build the unlinked pieces +			std::list< LLPrimLinkInfo<S32> > info_list; +			for (; sphere_index < number_of_spheres; ++sphere_index) +			{ +				randomize_sphere(sphere, child_center_range, min_prim_radius, max_prim_radius); +				LLPrimLinkInfo<S32> child_info( sphere_index, sphere ); +				info_list.push_back(child_info); +			} + +			// declare the variables used to store the results +			std::list<S32> first_linked_list; + +			{ +				// the link attempt will modify our original info's, so we +				// have to make copies of the originals for testing +				LLPrimLinkInfo<S32> test_info( 0, LLSphere(info.getCenter(), 0.5f * info.getDiameter()) ); +				std::list< LLPrimLinkInfo<S32> > test_list; +				test_list.assign(info_list.begin(), info_list.end()); + +				// try to link +				test_info.mergeLinkableSet(test_list); +	 +				ensure("All prims should link, but did not.",test_list.empty()); + +				// store the results  +				test_info.getData(first_linked_list); +				first_linked_list.sort(); +			} + +			// try to link the spheres in various random orders +			for (S32 scramble = 0; scramble < number_of_scrambles; ++scramble) +			{ +				LLPrimLinkInfo<S32> test_info(0, LLSphere(info.getCenter(), 0.5f * info.getDiameter()) ); + +				// scramble the order of the info_list +				std::list< LLPrimLinkInfo<S32> > test_list; +				test_list.assign(info_list.begin(), info_list.end()); +				for (S32 i = 0; i < number_of_random_bubble_sorts; i++) +				{ +					test_list.sort(random_sort); +				} + +				// try to link +				test_info.mergeLinkableSet(test_list); +	 +				// get the results  +				std::list<S32> linked_list; +				test_info.getData(linked_list); +				linked_list.sort(); + +				ensure_equals("linked set size should be order independent",linked_list.size(),first_linked_list.size()); +			} +		} +	} +} + | 
