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-448master
parent
b5936a4b1d
commit
dc48f1c741
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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_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;
|
||||
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_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;
|
||||
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_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;
|
||||
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_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;
|
||||
const U32 AGENT_CONTROL_AWAY = 0x1 << CONTROL_AWAY_INDEX; // 0x08000000
|
||||
|
||||
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_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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
|
||||
#include "llerror.h"
|
||||
//#include "vmath.h"
|
||||
#include "llrand.h"
|
||||
|
||||
/////////////////////////////////////////////
|
||||
//
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
#ifndef LL_LLSKIPLIST_H
|
||||
#define LL_LLSKIPLIST_H
|
||||
|
||||
#include "llrand.h"
|
||||
#include "llrand.h"
|
||||
|
||||
// NOTA BENE: Insert first needs to be < NOT <=
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -33,6 +33,9 @@
|
|||
#define LL_LLSTL_H
|
||||
|
||||
#include <functional>
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <deque>
|
||||
|
||||
|
|
|
|||
|
|
@ -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 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;
|
||||
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)
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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,10 @@ void LLQuaternion::quantize8(F32 lower, F32 upper)
|
|||
|
||||
// Set LLQuaternion routines
|
||||
|
||||
const LLQuaternion& LLQuaternion::setQuat(F32 angle, F32 x, F32 y, F32 z)
|
||||
const LLQuaternion& LLQuaternion::setAngleAxis(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 +153,14 @@ 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);
|
||||
}
|
||||
|
||||
const LLQuaternion& LLQuaternion::setQuat(F32 angle, const LLVector3 &vec)
|
||||
const LLQuaternion& LLQuaternion::setAngleAxis(F32 angle, const LLVector3 &vec)
|
||||
{
|
||||
LLVector3 v(vec);
|
||||
v.normVec();
|
||||
v.normalize();
|
||||
|
||||
angle *= 0.5f;
|
||||
F32 c, s;
|
||||
|
|
@ -172,14 +172,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)
|
||||
const LLQuaternion& LLQuaternion::setAngleAxis(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 +190,91 @@ const LLQuaternion& LLQuaternion::setQuat(F32 angle, const LLVector4 &vec)
|
|||
mQ[VZ] = v.mV[VZ]*s;
|
||||
mQ[VW] = c;
|
||||
|
||||
normQuat();
|
||||
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.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);
|
||||
}
|
||||
|
||||
// deprecated
|
||||
const LLQuaternion& LLQuaternion::setQuat(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::setQuat(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);
|
||||
}
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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]);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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)
|
||||
{
|
||||
llwarns << "Couldn't allocate triangle indices" << llendl;
|
||||
num_indices = 0;
|
||||
return NULL;
|
||||
}
|
||||
num_indices = count;
|
||||
memcpy(indices, index, count * sizeof(S32)); /* Flawfinder: ignore */
|
||||
return indices;
|
||||
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 */
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
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;
|
||||
|
||||
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]))
|
||||
//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[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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 << "{ "
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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]);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
inline void clear(); // Clears LLVector4 to (0, 0, 0, 1)
|
||||
inline void clearVec(); // deprecated
|
||||
inline void zeroVec(); // deprecated
|
||||
|
||||
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 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]);
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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()->.
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1955,10 +1955,19 @@ version 2.0
|
|||
}
|
||||
|
||||
|
||||
// ObjectPosition
|
||||
// viewer -> simulator
|
||||
// DEPRECATED: ObjectPosition
|
||||
// == Old Behavior ==
|
||||
// Set the position on objects
|
||||
//
|
||||
// == Reason for deprecation ==
|
||||
// Unused code path was removed in the move to Havok4
|
||||
// Object position, scale and rotation messages were already unified
|
||||
// to MultipleObjectUpdate and this message was unused cruft.
|
||||
//
|
||||
// == New Location ==
|
||||
// MultipleObjectUpdate can be used instead.
|
||||
{
|
||||
ObjectPosition Medium 4 NotTrusted Zerocoded
|
||||
ObjectPosition Medium 4 NotTrusted Zerocoded Deprecated
|
||||
{
|
||||
AgentData Single
|
||||
{ AgentID LLUUID }
|
||||
|
|
@ -1972,10 +1981,19 @@ version 2.0
|
|||
}
|
||||
|
||||
|
||||
// ObjectScale
|
||||
// viewer -> simulator
|
||||
// DEPRECATED: ObjectScale
|
||||
// == Old Behavior ==
|
||||
// Set the scale on objects
|
||||
//
|
||||
// == Reason for deprecation ==
|
||||
// Unused code path was removed in the move to Havok4
|
||||
// Object position, scale and rotation messages were already unified
|
||||
// to MultipleObjectUpdate and this message was unused cruft.
|
||||
//
|
||||
// == New Location ==
|
||||
// MultipleObjectUpdate can be used instead.
|
||||
{
|
||||
ObjectScale Low 92 NotTrusted Zerocoded
|
||||
ObjectScale Low 92 NotTrusted Zerocoded Deprecated
|
||||
{
|
||||
AgentData Single
|
||||
{ AgentID LLUUID }
|
||||
|
|
|
|||
Loading…
Reference in New Issue