Conflicts:
	indra/llvfs/lldiriterator.cpp
	indra/newview/app_settings/settings.xml
	indra/newview/llviewerregion.cpp
This commit is contained in:
Siana Gearz
2011-07-21 00:20:06 +02:00
339 changed files with 8700 additions and 4498 deletions

View File

@@ -838,7 +838,11 @@ void LLKeyframeMotion::initializeConstraint(JointConstraint* constraint)
S32 joint_num;
LLVector3 source_pos = mCharacter->getVolumePos(shared_data->mSourceConstraintVolume, shared_data->mSourceConstraintOffset);
LLJoint* cur_joint = getJoint(shared_data->mJointStateIndices[0]);
if ( !cur_joint )
{
return;
}
F32 source_pos_offset = dist_vec(source_pos, cur_joint->getWorldPosition());
constraint->mTotalLength = constraint->mJointLengths[0] = dist_vec(cur_joint->getParent()->getWorldPosition(), source_pos);
@@ -889,6 +893,10 @@ void LLKeyframeMotion::activateConstraint(JointConstraint* constraint)
for (joint_num = 1; joint_num < shared_data->mChainLength; joint_num++)
{
LLJoint* cur_joint = getJoint(shared_data->mJointStateIndices[joint_num]);
if ( !cur_joint )
{
return;
}
constraint->mPositions[joint_num] = (cur_joint->getWorldPosition() - mPelvisp->getWorldPosition()) * ~mPelvisp->getWorldRotation();
}
@@ -949,6 +957,10 @@ void LLKeyframeMotion::applyConstraint(JointConstraint* constraint, F32 time, U8
}
LLJoint* root_joint = getJoint(shared_data->mJointStateIndices[shared_data->mChainLength]);
if (! root_joint)
{
return;
}
LLVector3 root_pos = root_joint->getWorldPosition();
// LLQuaternion root_rot =
root_joint->getParent()->getWorldRotation();
@@ -960,6 +972,11 @@ void LLKeyframeMotion::applyConstraint(JointConstraint* constraint, F32 time, U8
for (joint_num = 0; joint_num <= shared_data->mChainLength; joint_num++)
{
LLJoint* cur_joint = getJoint(shared_data->mJointStateIndices[joint_num]);
if (!cur_joint)
{
return;
}
if (joint_mask[cur_joint->getJointNum()] >= (0xff >> (7 - getPriority())))
{
// skip constraint
@@ -1050,7 +1067,14 @@ void LLKeyframeMotion::applyConstraint(JointConstraint* constraint, F32 time, U8
if (shared_data->mChainLength)
{
LLQuaternion end_rot = getJoint(shared_data->mJointStateIndices[0])->getWorldRotation();
LLJoint* end_joint = getJoint(shared_data->mJointStateIndices[0]);
if (!end_joint)
{
return;
}
LLQuaternion end_rot = end_joint->getWorldRotation();
// slam start and end of chain to the proper positions (rest of chain stays put)
positions[0] = lerp(keyframe_source_pos, target_pos, weight);
@@ -1059,7 +1083,14 @@ void LLKeyframeMotion::applyConstraint(JointConstraint* constraint, F32 time, U8
// grab keyframe-specified positions of joints
for (joint_num = 1; joint_num < shared_data->mChainLength; joint_num++)
{
LLVector3 kinematic_position = getJoint(shared_data->mJointStateIndices[joint_num])->getWorldPosition() +
LLJoint* cur_joint = getJoint(shared_data->mJointStateIndices[joint_num]);
if (!cur_joint)
{
return;
}
LLVector3 kinematic_position = cur_joint->getWorldPosition() +
(source_to_target * constraint->mJointLengthFractions[joint_num]);
// convert intermediate joint positions to world coordinates
@@ -1105,7 +1136,17 @@ void LLKeyframeMotion::applyConstraint(JointConstraint* constraint, F32 time, U8
for (joint_num = shared_data->mChainLength; joint_num > 0; joint_num--)
{
LLJoint* cur_joint = getJoint(shared_data->mJointStateIndices[joint_num]);
if (!cur_joint)
{
return;
}
LLJoint* child_joint = getJoint(shared_data->mJointStateIndices[joint_num - 1]);
if (!child_joint)
{
return;
}
LLQuaternion parent_rot = cur_joint->getParent()->getWorldRotation();
LLQuaternion cur_rot = cur_joint->getWorldRotation();
@@ -1139,7 +1180,6 @@ void LLKeyframeMotion::applyConstraint(JointConstraint* constraint, F32 time, U8
cur_joint->setRotation(target_rot);
}
LLJoint* end_joint = getJoint(shared_data->mJointStateIndices[0]);
LLQuaternion end_local_rot = end_rot * ~end_joint->getParent()->getWorldRotation();
if (weight == 1.f)
@@ -1162,12 +1202,18 @@ void LLKeyframeMotion::applyConstraint(JointConstraint* constraint, F32 time, U8
constraint->mPositions[joint_num] = new_pos;
}
constraint->mFixupDistanceRMS *= 1.f / (constraint->mTotalLength * (F32)(shared_data->mChainLength - 1));
constraint->mFixupDistanceRMS = fsqrtf(constraint->mFixupDistanceRMS);
constraint->mFixupDistanceRMS = (F32) sqrt(constraint->mFixupDistanceRMS);
//reset old joint rots
for (joint_num = 0; joint_num <= shared_data->mChainLength; joint_num++)
{
getJoint(shared_data->mJointStateIndices[joint_num])->setRotation(old_rots[joint_num]);
LLJoint* cur_joint = getJoint(shared_data->mJointStateIndices[joint_num]);
if (!cur_joint)
{
return;
}
cur_joint->setRotation(old_rots[joint_num]);
}
}
// simple positional constraint (pelvis only)
@@ -1816,7 +1862,15 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp)
constraintp->mJointStateIndices[i] = -1;
for (U32 j = 0; j < mJointMotionList->getNumJointMotions(); j++)
{
if(getJoint(j) == joint)
LLJoint* constraint_joint = getJoint(j);
if ( !constraint_joint )
{
llwarns << "Invalid joint " << j << llendl;
return FALSE;
}
if(constraint_joint == joint)
{
constraintp->mJointStateIndices[i] = (S32)j;
break;

View File

@@ -319,6 +319,14 @@ const F32 CHAT_SHOUT_RADIUS = 100.f;
const F32 CHAT_MAX_RADIUS = CHAT_SHOUT_RADIUS;
const F32 CHAT_MAX_RADIUS_BY_TWO = CHAT_MAX_RADIUS / 2.f;
// squared editions of the above for distance checks
const F32 CHAT_WHISPER_RADIUS_SQUARED = CHAT_WHISPER_RADIUS * CHAT_WHISPER_RADIUS;
const F32 CHAT_NORMAL_RADIUS_SQUARED = CHAT_NORMAL_RADIUS * CHAT_NORMAL_RADIUS;
const F32 CHAT_SHOUT_RADIUS_SQUARED = CHAT_SHOUT_RADIUS * CHAT_SHOUT_RADIUS;
const F32 CHAT_MAX_RADIUS_SQUARED = CHAT_SHOUT_RADIUS_SQUARED;
const F32 CHAT_MAX_RADIUS_BY_TWO_SQUARED = CHAT_MAX_RADIUS_BY_TWO * CHAT_MAX_RADIUS_BY_TWO;
// this times above gives barely audible radius
const F32 CHAT_BARELY_AUDIBLE_FACTOR = 2.0f;

View File

@@ -25,10 +25,6 @@
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
/*
Ported to Phoenix by Wolfspirit Magic.
*/
#include "linden_common.h"
#include "llavatarname.h"
@@ -52,7 +48,7 @@ LLAvatarName::LLAvatarName()
mLegacyFirstName(),
mLegacyLastName(),
mIsDisplayNameDefault(false),
mIsDummy(false),
mIsTemporaryName(false),
mExpires(F64_MAX),
mNextUpdate(0.0)
{ }
@@ -94,21 +90,16 @@ void LLAvatarName::fromLLSD(const LLSD& sd)
std::string LLAvatarName::getCompleteName(bool linefeed) const
{
std::string name;
if (!mUsername.empty())
if (mUsername.empty() || mIsDisplayNameDefault)
// If the display name feature is off
// OR this particular display name is defaulted (i.e. based on user name),
// then display only the easier to read instance of the person's name.
{
if (linefeed)
{
name = mDisplayName + "\n(" + mUsername + ")";
}
else
{
name = mDisplayName + " (" + mUsername + ")";
}
name = mDisplayName;
}
else
{
// ...display names are off, legacy name is in mDisplayName
name = mDisplayName;
name = mDisplayName + (linefeed ? "\n(" : "(") + mUsername + ")";
}
return name;
}

View File

@@ -79,7 +79,7 @@ public:
// Under error conditions, we may insert "dummy" records with
// names like "???" into caches as placeholders. These can be
// shown in UI, but are not serialized.
bool mIsDummy;
bool mIsTemporaryName;
// Names can change, so need to keep track of when name was
// last checked.

View File

@@ -56,7 +56,8 @@ typedef enum e_chat_type
CHAT_TYPE_STOP = 5,
CHAT_TYPE_DEBUG_MSG = 6,
CHAT_TYPE_REGION = 7,
CHAT_TYPE_OWNER = 8
CHAT_TYPE_OWNER = 8,
CHAT_TYPE_DIRECT = 9 // From llRegionSayTo()
} EChatType;
typedef enum e_chat_audible_level

View File

@@ -42,5 +42,6 @@ const U8 CLICK_ACTION_PAY = 3;
const U8 CLICK_ACTION_OPEN = 4;
const U8 CLICK_ACTION_PLAY = 5;
const U8 CLICK_ACTION_OPEN_MEDIA = 6;
const U8 CLICK_ACTION_ZOOM = 7;
// DO NOT CHANGE THE SEQUENCE OF THIS LIST!!
#endif

View File

@@ -38,6 +38,8 @@
#include <iosfwd>
#include <string>
#include "llpreprocessor.h"
#include "stdtypes.h"
/**

View File

@@ -45,6 +45,83 @@ const U32 LLREFCOUNT_SENTINEL_VALUE = 0xAAAAAAAA;
//----------------------------------------------------------------------------
#if LL_DEBUG
inline void* ll_aligned_malloc( size_t size, int align )
{
void* mem = malloc( size + (align - 1) + sizeof(void*) );
char* aligned = ((char*)mem) + sizeof(void*);
aligned += align - ((uintptr_t)aligned & (align - 1));
((void**)aligned)[-1] = mem;
return aligned;
}
inline void ll_aligned_free( void* ptr )
{
free( ((void**)ptr)[-1] );
}
inline void* ll_aligned_malloc_16(size_t size) // returned hunk MUST be freed with ll_aligned_free_16().
{
#if defined(LL_WINDOWS)
return _mm_malloc(size, 16);
#elif defined(LL_DARWIN)
return malloc(size); // default osx malloc is 16 byte aligned.
#else
void *rtn;
if (LL_LIKELY(0 == posix_memalign(&rtn, 16, size)))
return rtn;
else // bad alignment requested, or out of memory
return NULL;
#endif
}
inline void ll_aligned_free_16(void *p)
{
#if defined(LL_WINDOWS)
_mm_free(p);
#elif defined(LL_DARWIN)
return free(p);
#else
free(p); // posix_memalign() is compatible with heap deallocator
#endif
}
inline void* ll_aligned_malloc_32(size_t size) // returned hunk MUST be freed with ll_aligned_free_32().
{
#if defined(LL_WINDOWS)
return _mm_malloc(size, 32);
#elif defined(LL_DARWIN)
return ll_aligned_malloc( size, 32 );
#else
void *rtn;
if (LL_LIKELY(0 == posix_memalign(&rtn, 32, size)))
return rtn;
else // bad alignment requested, or out of memory
return NULL;
#endif
}
inline void ll_aligned_free_32(void *p)
{
#if defined(LL_WINDOWS)
_mm_free(p);
#elif defined(LL_DARWIN)
ll_aligned_free( p );
#else
free(p); // posix_memalign() is compatible with heap deallocator
#endif
}
#else // LL_DEBUG
// ll_aligned_foo are noops now that we use tcmalloc everywhere (tcmalloc aligns automatically at appropriate intervals)
#define ll_aligned_malloc( size, align ) malloc(size)
#define ll_aligned_free( ptr ) free(ptr)
#define ll_aligned_malloc_16 malloc
#define ll_aligned_free_16 free
#define ll_aligned_malloc_32 malloc
#define ll_aligned_free_32 free
#endif // LL_DEBUG
class LL_COMMON_API LLMemory
{
public:

107
indra/llcommon/stringize.h Normal file
View File

@@ -0,0 +1,107 @@
/**
* @file stringize.h
* @author Nat Goodspeed
* @date 2008-12-17
* @brief stringize(item) template function and STRINGIZE(expression) macro
*
* $LicenseInfo:firstyear=2008&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#if ! defined(LL_STRINGIZE_H)
#define LL_STRINGIZE_H
#include <sstream>
#include <boost/lambda/lambda.hpp>
/**
* stringize(item) encapsulates an idiom we use constantly, using
* operator<<(std::ostringstream&, TYPE) followed by std::ostringstream::str()
* to render a string expressing some item.
*/
template <typename T>
std::string stringize(const T& item)
{
std::ostringstream out;
out << item;
return out.str();
}
/**
* stringize_f(functor)
*/
template <typename Functor>
std::string stringize_f(Functor const & f)
{
std::ostringstream out;
f(out);
return out.str();
}
/**
* STRINGIZE(item1 << item2 << item3 ...) effectively expands to the
* following:
* @code
* std::ostringstream out;
* out << item1 << item2 << item3 ... ;
* return out.str();
* @endcode
*/
#define STRINGIZE(EXPRESSION) (stringize_f(boost::lambda::_1 << EXPRESSION))
/**
* destringize(str)
* defined for symmetry with stringize
* *NOTE - this has distinct behavior from boost::lexical_cast<T> regarding
* leading/trailing whitespace and handling of bad_lexical_cast exceptions
*/
template <typename T>
T destringize(std::string const & str)
{
T val;
std::istringstream in(str);
in >> val;
return val;
}
/**
* destringize_f(str, functor)
*/
template <typename Functor>
void destringize_f(std::string const & str, Functor const & f)
{
std::istringstream in(str);
f(in);
}
/**
* DESTRINGIZE(str, item1 >> item2 >> item3 ...) effectively expands to the
* following:
* @code
* std::istringstream in(str);
* in >> item1 >> item2 >> item3 ... ;
* @endcode
*/
#define DESTRINGIZE(STR, EXPRESSION) (destringize_f((STR), (boost::lambda::_1 >> EXPRESSION)))
#endif /* ! defined(LL_STRINGIZE_H) */

View File

@@ -89,7 +89,8 @@ LLCrashLogger::LLCrashLogger() :
mCrashBehavior(CRASH_BEHAVIOR_ASK),
mCrashInPreviousExec(false),
mSentCrashLogs(false),
mCrashHost("")
mCrashHost(""),
mCrashSettings("CrashSettings")
{
}

View File

@@ -138,8 +138,7 @@ void LLImageBase::sanityCheck()
// virtual
void LLImageBase::deleteData()
{
if(mData)
delete[] mData;
delete[] mData;
mData = NULL;
mDataSize = 0;
}
@@ -154,7 +153,7 @@ U8* LLImageBase::allocateData(S32 size)
size = mWidth * mHeight * mComponents;
if (size <= 0)
{
llerrs << llformat("LLImageBase::allocateData called with bad dimensions: %dx%dx%d",mWidth,mHeight,mComponents) << llendl;
llerrs << llformat("LLImageBase::allocateData called with bad dimensions: %dx%dx%d",mWidth,mHeight,(S32)mComponents) << llendl;
}
}
else if (size <= 0 || (size > 4096*4096*16 && !mAllowOverSize))
@@ -1297,28 +1296,7 @@ bool LLImageRaw::createFromFile(const std::string &filename, bool j2c_lowest_mip
return false;
}
LLPointer<LLImageFormatted> image;
switch(codec)
{
//case IMG_CODEC_RGB:
case IMG_CODEC_BMP:
image = new LLImageBMP();
break;
case IMG_CODEC_TGA:
image = new LLImageTGA();
break;
case IMG_CODEC_JPEG:
image = new LLImageJPEG();
break;
case IMG_CODEC_J2C:
image = new LLImageJ2C();
break;
case IMG_CODEC_DXT:
image = new LLImageDXT();
break;
default:
return false;
}
LLPointer<LLImageFormatted> image = LLImageFormatted::createFromType(codec);
llassert(image.notNull());
U8 *buffer = image->allocateData(length);

View File

@@ -452,7 +452,7 @@ BOOL LLParcel::allowTerraformBy(const LLUUID &agent_id) const
bool LLParcel::isAgentBlockedFromParcel(LLParcel* parcelp,
const LLUUID& agent_id,
const std::vector<LLUUID>& group_ids,
const uuid_vec_t& group_ids,
const BOOL is_agent_identified,
const BOOL is_agent_transacted,
const BOOL is_agent_ageverified)

View File

@@ -135,9 +135,15 @@ class LLSD;
class LLAccessEntry
{
public:
LLUUID mID;
S32 mTime;
U32 mFlags;
LLAccessEntry()
: mID(),
mTime(0),
mFlags(0)
{}
LLUUID mID; // Agent ID
S32 mTime; // Time (unix seconds) when entry expires
U32 mFlags; // Not used - currently should always be zero
};
typedef std::map<LLUUID,LLAccessEntry>::iterator access_map_iterator;

View File

@@ -17,13 +17,16 @@ set(llmath_SOURCE_FILES
llcamera.cpp
llcoordframe.cpp
llline.cpp
llmatrix3a.cpp
llmodularmath.cpp
llperlin.cpp
llquaternion.cpp
llrect.cpp
llsphere.cpp
llvector4a.cpp
llvolume.cpp
llvolumemgr.cpp
llvolumeoctree.cpp
llsdutil_math.cpp
m3math.cpp
m4math.cpp
@@ -53,21 +56,32 @@ set(llmath_HEADER_FILES
llinterp.h
llline.h
llmath.h
llmatrix3a.h
llmatrix3a.inl
llmodularmath.h
lloctree.h
llperlin.h
llplane.h
llquantize.h
llquaternion.h
llquaternion2.h
llquaternion2.inl
llrect.h
llsimdmath.h
llsimdtypes.h
llsimdtypes.inl
llsphere.h
lltreenode.h
llvector4a.h
llvector4a.inl
llvector4logical.h
llv4math.h
llv4matrix3.h
llv4matrix4.h
llv4vector3.h
llvolume.h
llvolumemgr.h
llvolumeoctree.h
llsdutil_math.h
m3math.h
m4math.h

View File

@@ -54,28 +54,20 @@ LLCalc* LLCalc::sInstance = NULL;
LLCalc::LLCalc() : mLastErrorPos(0)
{
// mUserVariables = new calc_map_t;
mVariables = new calc_map_t;
mConstants = new calc_map_t;
// Init table of constants
(*mConstants)["PI"] = F_PI;
(*mConstants)["TWO_PI"] = F_TWO_PI;
(*mConstants)["PI_BY_TWO"] = F_PI_BY_TWO;
(*mConstants)["SQRT2"] = F_SQRT2;
(*mConstants)["DEG_TO_RAD"] = DEG_TO_RAD;
(*mConstants)["RAD_TO_DEG"] = RAD_TO_DEG;
(*mConstants)["GRAVITY"] = GRAVITY;
(*mConstants)["ALMOST_ZERO"] = F_ALMOST_ZERO;
(*mConstants)["ALMOST_ONE"] = F_ALMOST_ONE;
(*mConstants)["THE_ANSWER"] = 42;
mConstants["PI"] = F_PI;
mConstants["TWO_PI"] = F_TWO_PI;
mConstants["PI_BY_TWO"] = F_PI_BY_TWO;
mConstants["SQRT_TWO_PI"] = F_SQRT_TWO_PI;
mConstants["SQRT2"] = F_SQRT2;
mConstants["SQRT3"] = F_SQRT3;
mConstants["DEG_TO_RAD"] = DEG_TO_RAD;
mConstants["RAD_TO_DEG"] = RAD_TO_DEG;
mConstants["GRAVITY"] = GRAVITY;
}
LLCalc::~LLCalc()
{
delete mConstants;
delete mVariables;
// delete mUserVariables;
}
//static
@@ -94,17 +86,17 @@ LLCalc* LLCalc::getInstance()
void LLCalc::setVar(const std::string& name, const F32& value)
{
(*mVariables)[name] = value;
mVariables[name] = value;
}
void LLCalc::clearVar(const std::string& name)
{
mVariables->erase(name);
mVariables.erase(name);
}
void LLCalc::clearAllVariables()
{
mVariables->clear();
mVariables.clear();
}
/*
@@ -123,7 +115,7 @@ bool LLCalc::evalString(const std::string& expression, F32& result)
std::string expr_upper = expression;
LLStringUtil::toUpper(expr_upper);
LLCalcParser calc(result, mConstants, mVariables);
LLCalcParser calc(result, &mConstants, &mVariables);
mLastErrorPos = 0;
std::string::iterator start = expr_upper.begin();

View File

@@ -69,8 +69,8 @@ public:
private:
std::string::size_type mLastErrorPos;
calc_map_t* mConstants;
calc_map_t* mVariables;
calc_map_t mConstants;
calc_map_t mVariables;
// *TODO: Add support for storing user defined variables, and stored functions.
// Will need UI work, and a means to save them between sessions.

View File

@@ -73,7 +73,9 @@ struct LLCalcParser : grammar<LLCalcParser>
(str_p("SQRT") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_sqrt)(self,arg1)]) |
(str_p("LOG") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_log)(self,arg1)]) |
(str_p("EXP") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_exp)(self,arg1)]) |
(str_p("ABS") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_fabs)(self,arg1)])
(str_p("ABS") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_fabs)(self,arg1)]) |
(str_p("FLR") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_floor)(self,arg1)]) |
(str_p("CEIL") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_ceil)(self,arg1)])
) >> assert_syntax(ch_p(')'))
;
@@ -118,7 +120,8 @@ struct LLCalcParser : grammar<LLCalcParser>
term =
power[term.value = arg1] >>
*(('*' >> assert_syntax(power[term.value *= arg1])) |
('/' >> assert_syntax(power[term.value /= arg1]))
('/' >> assert_syntax(power[term.value /= arg1])) |
('%' >> assert_syntax(power[term.value = bind(&fmodf)(term.value, arg1)]))
)
;
@@ -153,7 +156,9 @@ private:
F32 _sqrt(const F32& a) const { return sqrt(a); }
F32 _log(const F32& a) const { return log(a); }
F32 _exp(const F32& a) const { return exp(a); }
F32 _fabs(const F32& a) const { return fabs(a) * RAD_TO_DEG; }
F32 _fabs(const F32& a) const { return fabs(a); }
F32 _floor(const F32& a) const { return llfloor(a); }
F32 _ceil(const F32& a) const { return llceil(a); }
F32 _atan2(const F32& a,const F32& b) const { return atan2(a,b); }

View File

@@ -92,7 +92,7 @@ F32 LLCamera::getMaxView() const
// ---------------- LLCamera::setFoo() member functions ----------------
void LLCamera::setUserClipPlane(LLPlane const& plane)
void LLCamera::setUserClipPlane(LLPlane& plane)
{
mPlaneCount = 7;
mAgentPlanes[6] = plane;
@@ -168,166 +168,91 @@ size_t LLCamera::readFrustumFromBuffer(const char *buffer)
// ---------------- test methods ----------------
S32 LLCamera::AABBInFrustum(const LLVector3 &center, const LLVector3& radius)
S32 LLCamera::AABBInFrustum(const LLVector4a &center, const LLVector4a& radius)
{
static const LLVector3 scaler[] = {
LLVector3(-1,-1,-1),
LLVector3( 1,-1,-1),
LLVector3(-1, 1,-1),
LLVector3( 1, 1,-1),
LLVector3(-1,-1, 1),
LLVector3( 1,-1, 1),
LLVector3(-1, 1, 1),
LLVector3( 1, 1, 1)
static const LLVector4a scaler[] = {
LLVector4a(-1,-1,-1),
LLVector4a( 1,-1,-1),
LLVector4a(-1, 1,-1),
LLVector4a( 1, 1,-1),
LLVector4a(-1,-1, 1),
LLVector4a( 1,-1, 1),
LLVector4a(-1, 1, 1),
LLVector4a( 1, 1, 1)
};
U8 mask = 0;
S32 result = 2;
/*if (radius.magVecSquared() > mFrustumCornerDist * mFrustumCornerDist)
{ //box is larger than frustum, check frustum quads against box planes
static const LLVector3 dir[] =
{
LLVector3(1, 0, 0),
LLVector3(-1, 0, 0),
LLVector3(0, 1, 0),
LLVector3(0, -1, 0),
LLVector3(0, 0, 1),
LLVector3(0, 0, -1)
};
U32 quads[] =
{
0, 1, 2, 3,
0, 1, 5, 4,
2, 3, 7, 6,
3, 0, 7, 4,
1, 2, 6, 4,
4, 5, 6, 7
};
result = 0;
BOOL total_inside = TRUE;
for (U32 i = 0; i < 6; i++)
{
LLVector3 p = center + radius.scaledVec(dir[i]);
F32 d = -p*dir[i];
for (U32 j = 0; j < 6; j++)
{ //for each quad
F32 dist = mAgentFrustum[quads[j*4+0]]*dir[i] + d;
if (dist > 0)
{ //at least one frustum point is outside the AABB
total_inside = FALSE;
for (U32 k = 1; k < 4; k++)
{ //for each other point on quad
if ( mAgentFrustum[quads[j*4+k]]*dir[i]+d <= 0.f)
{ //quad is straddling some plane of AABB
return 1;
}
}
}
else
{
for (U32 k = 1; k < 4; k++)
{
if (mAgentFrustum[quads[j*4+k]]*dir[i]+d > 0.f)
{
return 1;
}
}
}
}
}
if (total_inside)
{
result = 1;
}
}
else*/
bool result = false;
LLVector4a rscale, maxp, minp;
LLSimdScalar d;
for (U32 i = 0; i < mPlaneCount; i++)
{
for (U32 i = 0; i < mPlaneCount; i++)
mask = mPlaneMask[i];
if (mask != 0xff)
{
mask = mPlaneMask[i];
if (mask == 0xff)
{
continue;
}
LLPlane p = mAgentPlanes[i];
LLVector3 n = LLVector3(p);
float d = p.mV[3];
LLVector3 rscale = radius.scaledVec(scaler[mask]);
LLVector3 minp = center - rscale;
LLVector3 maxp = center + rscale;
if (n * minp > -d)
const LLPlane& p(mAgentPlanes[i]);
p.getAt<3>(d);
rscale.setMul(radius, scaler[mask]);
minp.setSub(center, rscale);
d = -d;
if (p.dot3(minp).getF32() > d)
{
return 0;
}
if (n * maxp > -d)
if(!result)
{
result = 1;
maxp.setAdd(center, rscale);
result = (p.dot3(maxp).getF32() > d);
}
}
}
return result;
return result?1:2;
}
S32 LLCamera::AABBInFrustumNoFarClip(const LLVector3 &center, const LLVector3& radius)
S32 LLCamera::AABBInFrustumNoFarClip(const LLVector4a& center, const LLVector4a& radius)
{
static const LLVector3 scaler[] = {
LLVector3(-1,-1,-1),
LLVector3( 1,-1,-1),
LLVector3(-1, 1,-1),
LLVector3( 1, 1,-1),
LLVector3(-1,-1, 1),
LLVector3( 1,-1, 1),
LLVector3(-1, 1, 1),
LLVector3( 1, 1, 1)
static const LLVector4a scaler[] = {
LLVector4a(-1,-1,-1),
LLVector4a( 1,-1,-1),
LLVector4a(-1, 1,-1),
LLVector4a( 1, 1,-1),
LLVector4a(-1,-1, 1),
LLVector4a( 1,-1, 1),
LLVector4a(-1, 1, 1),
LLVector4a( 1, 1, 1)
};
U8 mask = 0;
S32 result = 2;
bool result = false;
LLVector4a rscale, maxp, minp;
LLSimdScalar d;
for (U32 i = 0; i < mPlaneCount; i++)
{
if (i == 5)
{
continue;
}
mask = mPlaneMask[i];
if (mask == 0xff)
if ((i != 5) && (mask != 0xff))
{
continue;
}
LLPlane p = mAgentPlanes[i];
LLVector3 n = LLVector3(p);
float d = p.mV[3];
LLVector3 rscale = radius.scaledVec(scaler[mask]);
LLVector3 minp = center - rscale;
LLVector3 maxp = center + rscale;
if (n * minp > -d)
{
return 0;
}
if (n * maxp > -d)
{
result = 1;
const LLPlane& p(mAgentPlanes[i]);
p.getAt<3>(d);
rscale.setMul(radius, scaler[mask]);
minp.setSub(center, rscale);
d = -d;
if (p.dot3(minp).getF32() > d)
{
return 0;
}
if(!result)
{
maxp.setAdd(center, rscale);
result = (p.dot3(maxp).getF32() > d);
}
}
}
return result;
return result?1:2;
}
int LLCamera::sphereInFrustumQuick(const LLVector3 &sphere_center, const F32 radius)
@@ -715,9 +640,10 @@ void LLCamera::calculateWorldFrustumPlanes()
F32 d;
LLVector3 center = mOrigin - mXAxis*mNearPlane;
mWorldPlanePos = center;
LLVector3 pnorm;
for (int p=0; p<4; p++)
{
LLVector3 pnorm = LLVector3(mLocalPlanes[p]);
mLocalPlanes[p].getVector3(pnorm);
LLVector3 norm = rotateToAbsolute(pnorm);
norm.normVec();
d = -(center * norm);
@@ -727,13 +653,15 @@ void LLCamera::calculateWorldFrustumPlanes()
LLVector3 zaxis(0, 0, 1.0f);
F32 yaw = getYaw();
{
LLVector3 tnorm = LLVector3(mLocalPlanes[PLANE_LEFT]);
LLVector3 tnorm;
mLocalPlanes[PLANE_LEFT].getVector3(tnorm);
tnorm.rotVec(yaw, zaxis);
d = -(mOrigin * tnorm);
mHorizPlanes[HORIZ_PLANE_LEFT] = LLPlane(tnorm, d);
}
{
LLVector3 tnorm = LLVector3(mLocalPlanes[PLANE_RIGHT]);
LLVector3 tnorm;
mLocalPlanes[PLANE_RIGHT].getVector3(tnorm);
tnorm.rotVec(yaw, zaxis);
d = -(mOrigin * tnorm);
mHorizPlanes[HORIZ_PLANE_RIGHT] = LLPlane(tnorm, d);

View File

@@ -37,6 +37,7 @@
#include "llmath.h"
#include "llcoordframe.h"
#include "llplane.h"
#include "llvector4a.h"
const F32 DEFAULT_FIELD_OF_VIEW = 60.f * DEG_TO_RAD;
const F32 DEFAULT_ASPECT_RATIO = 640.f / 480.f;
@@ -143,7 +144,7 @@ public:
virtual ~LLCamera();
void setUserClipPlane(LLPlane const& plane);
void setUserClipPlane(LLPlane& plane);
void disableUserClipPlane();
virtual void setView(F32 vertical_fov_rads);
void setViewHeightInPixels(S32 height);
@@ -191,8 +192,8 @@ public:
S32 sphereInFrustum(const LLVector3 &center, const F32 radius) const;
S32 pointInFrustum(const LLVector3 &point) const { return sphereInFrustum(point, 0.0f); }
S32 sphereInFrustumFull(const LLVector3 &center, const F32 radius) const { return sphereInFrustum(center, radius); }
S32 AABBInFrustum(const LLVector3 &center, const LLVector3& radius);
S32 AABBInFrustumNoFarClip(const LLVector3 &center, const LLVector3& radius);
S32 AABBInFrustum(const LLVector4a& center, const LLVector4a& radius);
S32 AABBInFrustumNoFarClip(const LLVector4a& center, const LLVector4a& radius);
//does a quick 'n dirty sphere-sphere check
S32 sphereInFrustumQuick(const LLVector3 &sphere_center, const F32 radius);

View File

@@ -38,6 +38,7 @@
// So, let's define _USE_MATH_DEFINES before including math.h
#define _USE_MATH_DEFINES
#endif
#include "math.h"
// Class from which different types of interpolators can be derived

View File

@@ -35,7 +35,7 @@
#include <cmath>
#include <cstdlib>
#include <complex>
#include <vector>
#include "lldefs.h"
#include "llstl.h" // *TODO: Remove when LLString is gone
#include "llstring.h" // *TODO: Remove when LLString is gone
@@ -61,32 +61,11 @@
#endif
// Single Precision Floating Point Routines
#ifndef sqrtf
#define sqrtf(x) ((F32)sqrt((F64)(x)))
#endif
#ifndef fsqrtf
#define fsqrtf(x) sqrtf(x)
#endif
#ifndef cosf
#define cosf(x) ((F32)cos((F64)(x)))
#endif
#ifndef sinf
#define sinf(x) ((F32)sin((F64)(x)))
#endif
#ifndef tanf
// (There used to be more defined here, but they appeared to be redundant and
// were breaking some other includes. Removed by Falcon, reviewed by Andrew, 11/25/09)
/*#ifndef tanf
#define tanf(x) ((F32)tan((F64)(x)))
#endif
#ifndef acosf
#define acosf(x) ((F32)acos((F64)(x)))
#endif
#ifndef powf
#define powf(x,y) ((F32)pow((F64)(x),(F64)(y)))
#endif
#ifndef expf
#define expf(x) ((F32)exp((F64)(x)))
#endif
#endif*/
const F32 GRAVITY = -9.8f;
@@ -206,7 +185,7 @@ inline S32 llfloor( F32 f )
}
return result;
#else
return (S32)floorf(f);
return (S32)floor(f);
#endif
}
@@ -562,4 +541,7 @@ inline void ll_remove_outliers(std::vector<VEC_TYPE>& data, F32 k)
data.erase(data.begin(), data.begin()+i);
}
}
// Include simd math header
#include "llsimdmath.h"
#endif

134
indra/llmath/llmatrix3a.cpp Normal file
View File

@@ -0,0 +1,134 @@
/**
* @file llvector4a.cpp
* @brief SIMD vector implementation
*
* $LicenseInfo:firstyear=2010&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "llmath.h"
static LL_ALIGN_16(const F32 M_IDENT_3A[12]) =
{ 1.f, 0.f, 0.f, 0.f, // Column 1
0.f, 1.f, 0.f, 0.f, // Column 2
0.f, 0.f, 1.f, 0.f }; // Column 3
extern const LLMatrix3a LL_M3A_IDENTITY = *reinterpret_cast<const LLMatrix3a*> (M_IDENT_3A);
void LLMatrix3a::setMul( const LLMatrix3a& lhs, const LLMatrix3a& rhs )
{
const LLVector4a col0 = lhs.getColumn(0);
const LLVector4a col1 = lhs.getColumn(1);
const LLVector4a col2 = lhs.getColumn(2);
for ( int i = 0; i < 3; i++ )
{
LLVector4a xxxx = _mm_load_ss( rhs.mColumns[i].getF32ptr() );
xxxx.splat<0>( xxxx );
xxxx.mul( col0 );
{
LLVector4a yyyy = _mm_load_ss( rhs.mColumns[i].getF32ptr() + 1 );
yyyy.splat<0>( yyyy );
yyyy.mul( col1 );
xxxx.add( yyyy );
}
{
LLVector4a zzzz = _mm_load_ss( rhs.mColumns[i].getF32ptr() + 2 );
zzzz.splat<0>( zzzz );
zzzz.mul( col2 );
xxxx.add( zzzz );
}
xxxx.store4a( mColumns[i].getF32ptr() );
}
}
/*static */void LLMatrix3a::batchTransform( const LLMatrix3a& xform, const LLVector4a* src, int numVectors, LLVector4a* dst )
{
const LLVector4a col0 = xform.getColumn(0);
const LLVector4a col1 = xform.getColumn(1);
const LLVector4a col2 = xform.getColumn(2);
const LLVector4a* maxAddr = src + numVectors;
if ( numVectors & 0x1 )
{
LLVector4a xxxx = _mm_load_ss( (const F32*)src );
LLVector4a yyyy = _mm_load_ss( (const F32*)src + 1 );
LLVector4a zzzz = _mm_load_ss( (const F32*)src + 2 );
xxxx.splat<0>( xxxx );
yyyy.splat<0>( yyyy );
zzzz.splat<0>( zzzz );
xxxx.mul( col0 );
yyyy.mul( col1 );
zzzz.mul( col2 );
xxxx.add( yyyy );
xxxx.add( zzzz );
xxxx.store4a( (F32*)dst );
src++;
dst++;
}
numVectors >>= 1;
while ( src < maxAddr )
{
_mm_prefetch( (const char*)(src + 32 ), _MM_HINT_NTA );
_mm_prefetch( (const char*)(dst + 32), _MM_HINT_NTA );
LLVector4a xxxx = _mm_load_ss( (const F32*)src );
LLVector4a xxxx1= _mm_load_ss( (const F32*)(src + 1) );
xxxx.splat<0>( xxxx );
xxxx1.splat<0>( xxxx1 );
xxxx.mul( col0 );
xxxx1.mul( col0 );
{
LLVector4a yyyy = _mm_load_ss( (const F32*)src + 1 );
LLVector4a yyyy1 = _mm_load_ss( (const F32*)(src + 1) + 1);
yyyy.splat<0>( yyyy );
yyyy1.splat<0>( yyyy1 );
yyyy.mul( col1 );
yyyy1.mul( col1 );
xxxx.add( yyyy );
xxxx1.add( yyyy1 );
}
{
LLVector4a zzzz = _mm_load_ss( (const F32*)(src) + 2 );
LLVector4a zzzz1 = _mm_load_ss( (const F32*)(++src) + 2 );
zzzz.splat<0>( zzzz );
zzzz1.splat<0>( zzzz1 );
zzzz.mul( col2 );
zzzz1.mul( col2 );
xxxx.add( zzzz );
xxxx1.add( zzzz1 );
}
xxxx.store4a(dst->getF32ptr());
src++;
dst++;
xxxx1.store4a((F32*)dst++);
}
}

128
indra/llmath/llmatrix3a.h Normal file
View File

@@ -0,0 +1,128 @@
/**
* @file llmatrix3a.h
* @brief LLMatrix3a class header file - memory aligned and vectorized 3x3 matrix
*
* $LicenseInfo:firstyear=2010&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LL_LLMATRIX3A_H
#define LL_LLMATRIX3A_H
/////////////////////////////
// LLMatrix3a, LLRotation
/////////////////////////////
// This class stores a 3x3 (technically 4x3) matrix in column-major order
/////////////////////////////
/////////////////////////////
// These classes are intentionally minimal right now. If you need additional
// functionality, please contact someone with SSE experience (e.g., Falcon or
// Huseby).
/////////////////////////////
// LLMatrix3a is the base class for LLRotation, which should be used instead any time you're dealing with a
// rotation matrix.
class LLMatrix3a
{
public:
// Utility function for quickly transforming an array of LLVector4a's
// For transforming a single LLVector4a, see LLVector4a::setRotated
static void batchTransform( const LLMatrix3a& xform, const LLVector4a* src, int numVectors, LLVector4a* dst );
// Utility function to obtain the identity matrix
static inline const LLMatrix3a& getIdentity();
//////////////////////////
// Ctors
//////////////////////////
// Ctor
LLMatrix3a() {}
// Ctor for setting by columns
inline LLMatrix3a( const LLVector4a& c0, const LLVector4a& c1, const LLVector4a& c2 );
//////////////////////////
// Get/Set
//////////////////////////
// Loads from an LLMatrix3
inline void loadu(const LLMatrix3& src);
// Set rows
inline void setRows(const LLVector4a& r0, const LLVector4a& r1, const LLVector4a& r2);
// Set columns
inline void setColumns(const LLVector4a& c0, const LLVector4a& c1, const LLVector4a& c2);
// Get the read-only access to a specified column. Valid columns are 0-2, but the
// function is unchecked. You've been warned.
inline const LLVector4a& getColumn(const U32 column) const;
/////////////////////////
// Matrix modification
/////////////////////////
// Set this matrix to the product of lhs and rhs ( this = lhs * rhs )
void setMul( const LLMatrix3a& lhs, const LLMatrix3a& rhs );
// Set this matrix to the transpose of src
inline void setTranspose(const LLMatrix3a& src);
// Set this matrix to a*w + b*(1-w)
inline void setLerp(const LLMatrix3a& a, const LLMatrix3a& b, F32 w);
/////////////////////////
// Matrix inspection
/////////////////////////
// Sets all 4 elements in 'dest' to the determinant of this matrix.
// If you will be using the determinant in subsequent ops with LLVector4a, use this version
inline void getDeterminant( LLVector4a& dest ) const;
// Returns the determinant as an LLSimdScalar. Use this if you will be using the determinant
// primary for scalar operations.
inline LLSimdScalar getDeterminant() const;
// Returns nonzero if rows 0-2 and colums 0-2 contain no NaN or INF values. Row 3 is ignored
inline LLBool32 isFinite() const;
// Returns true if this matrix is equal to 'rhs' up to 'tolerance'
inline bool isApproximatelyEqual( const LLMatrix3a& rhs, F32 tolerance = F_APPROXIMATELY_ZERO ) const;
protected:
LLVector4a mColumns[3];
};
class LLRotation : public LLMatrix3a
{
public:
LLRotation() {}
// Returns true if this rotation is orthonormal with det ~= 1
inline bool isOkRotation() const;
};
#endif

119
indra/llmath/llmatrix3a.inl Normal file
View File

@@ -0,0 +1,119 @@
/**
* @file llmatrix3a.inl
* @brief LLMatrix3a inline definitions
*
* $LicenseInfo:firstyear=2010&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "llmatrix3a.h"
#include "m3math.h"
inline LLMatrix3a::LLMatrix3a( const LLVector4a& c0, const LLVector4a& c1, const LLVector4a& c2 )
{
setColumns( c0, c1, c2 );
}
inline void LLMatrix3a::loadu(const LLMatrix3& src)
{
mColumns[0].load3(src.mMatrix[0]);
mColumns[1].load3(src.mMatrix[1]);
mColumns[2].load3(src.mMatrix[2]);
}
inline void LLMatrix3a::setRows(const LLVector4a& r0, const LLVector4a& r1, const LLVector4a& r2)
{
mColumns[0] = r0;
mColumns[1] = r1;
mColumns[2] = r2;
setTranspose( *this );
}
inline void LLMatrix3a::setColumns(const LLVector4a& c0, const LLVector4a& c1, const LLVector4a& c2)
{
mColumns[0] = c0;
mColumns[1] = c1;
mColumns[2] = c2;
}
inline void LLMatrix3a::setTranspose(const LLMatrix3a& src)
{
const LLQuad srcCol0 = src.mColumns[0];
const LLQuad srcCol1 = src.mColumns[1];
const LLQuad unpacklo = _mm_unpacklo_ps( srcCol0, srcCol1 );
mColumns[0] = _mm_movelh_ps( unpacklo, src.mColumns[2] );
mColumns[1] = _mm_shuffle_ps( _mm_movehl_ps( srcCol0, unpacklo ), src.mColumns[2], _MM_SHUFFLE(0, 1, 1, 0) );
mColumns[2] = _mm_shuffle_ps( _mm_unpackhi_ps( srcCol0, srcCol1 ), src.mColumns[2], _MM_SHUFFLE(0, 2, 1, 0) );
}
inline const LLVector4a& LLMatrix3a::getColumn(const U32 column) const
{
llassert( column < 3 );
return mColumns[column];
}
inline void LLMatrix3a::setLerp(const LLMatrix3a& a, const LLMatrix3a& b, F32 w)
{
mColumns[0].setLerp( a.mColumns[0], b.mColumns[0], w );
mColumns[1].setLerp( a.mColumns[1], b.mColumns[1], w );
mColumns[2].setLerp( a.mColumns[2], b.mColumns[2], w );
}
inline LLBool32 LLMatrix3a::isFinite() const
{
return mColumns[0].isFinite3() && mColumns[1].isFinite3() && mColumns[2].isFinite3();
}
inline void LLMatrix3a::getDeterminant( LLVector4a& dest ) const
{
LLVector4a col1xcol2; col1xcol2.setCross3( mColumns[1], mColumns[2] );
dest.setAllDot3( col1xcol2, mColumns[0] );
}
inline LLSimdScalar LLMatrix3a::getDeterminant() const
{
LLVector4a col1xcol2; col1xcol2.setCross3( mColumns[1], mColumns[2] );
return col1xcol2.dot3( mColumns[0] );
}
inline bool LLMatrix3a::isApproximatelyEqual( const LLMatrix3a& rhs, F32 tolerance /*= F_APPROXIMATELY_ZERO*/ ) const
{
return rhs.getColumn(0).equals3(mColumns[0], tolerance)
&& rhs.getColumn(1).equals3(mColumns[1], tolerance)
&& rhs.getColumn(2).equals3(mColumns[2], tolerance);
}
inline const LLMatrix3a& LLMatrix3a::getIdentity()
{
extern const LLMatrix3a LL_M3A_IDENTITY;
return LL_M3A_IDENTITY;
}
inline bool LLRotation::isOkRotation() const
{
LLMatrix3a transpose; transpose.setTranspose( *this );
LLMatrix3a product; product.setMul( *this, transpose );
LLSimdScalar detMinusOne = getDeterminant() - 1.f;
return product.isApproximatelyEqual( LLMatrix3a::getIdentity() ) && (detMinusOne.getAbs() < F_APPROXIMATELY_ZERO);
}

143
indra/llmath/llmatrix4a.h Normal file
View File

@@ -0,0 +1,143 @@
/**
* @file llmatrix4a.h
* @brief LLMatrix4a class header file - memory aligned and vectorized 4x4 matrix
*
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LL_LLMATRIX4A_H
#define LL_LLMATRIX4A_H
#include "llvector4a.h"
#include "m4math.h"
#include "m3math.h"
class LLMatrix4a
{
public:
LLVector4a mMatrix[4];
inline void clear()
{
mMatrix[0].clear();
mMatrix[1].clear();
mMatrix[2].clear();
mMatrix[3].clear();
}
inline void loadu(const LLMatrix4& src)
{
mMatrix[0] = _mm_loadu_ps(src.mMatrix[0]);
mMatrix[1] = _mm_loadu_ps(src.mMatrix[1]);
mMatrix[2] = _mm_loadu_ps(src.mMatrix[2]);
mMatrix[3] = _mm_loadu_ps(src.mMatrix[3]);
}
inline void loadu(const LLMatrix3& src)
{
mMatrix[0].load3(src.mMatrix[0]);
mMatrix[1].load3(src.mMatrix[1]);
mMatrix[2].load3(src.mMatrix[2]);
mMatrix[3].set(0,0,0,1.f);
}
inline void add(const LLMatrix4a& rhs)
{
mMatrix[0].add(rhs.mMatrix[0]);
mMatrix[1].add(rhs.mMatrix[1]);
mMatrix[2].add(rhs.mMatrix[2]);
mMatrix[3].add(rhs.mMatrix[3]);
}
inline void setRows(const LLVector4a& r0, const LLVector4a& r1, const LLVector4a& r2)
{
mMatrix[0] = r0;
mMatrix[1] = r1;
mMatrix[2] = r2;
}
inline void setMul(const LLMatrix4a& m, const F32 s)
{
mMatrix[0].setMul(m.mMatrix[0], s);
mMatrix[1].setMul(m.mMatrix[1], s);
mMatrix[2].setMul(m.mMatrix[2], s);
mMatrix[3].setMul(m.mMatrix[3], s);
}
inline void setLerp(const LLMatrix4a& a, const LLMatrix4a& b, F32 w)
{
LLVector4a d0,d1,d2,d3;
d0.setSub(b.mMatrix[0], a.mMatrix[0]);
d1.setSub(b.mMatrix[1], a.mMatrix[1]);
d2.setSub(b.mMatrix[2], a.mMatrix[2]);
d3.setSub(b.mMatrix[3], a.mMatrix[3]);
// this = a + d*w
d0.mul(w);
d1.mul(w);
d2.mul(w);
d3.mul(w);
mMatrix[0].setAdd(a.mMatrix[0],d0);
mMatrix[1].setAdd(a.mMatrix[1],d1);
mMatrix[2].setAdd(a.mMatrix[2],d2);
mMatrix[3].setAdd(a.mMatrix[3],d3);
}
inline void rotate(const LLVector4a& v, LLVector4a& res)
{
res = _mm_shuffle_ps(v, v, _MM_SHUFFLE(0, 0, 0, 0));
res.mul(mMatrix[0]);
LLVector4a y;
y = _mm_shuffle_ps(v, v, _MM_SHUFFLE(1, 1, 1, 1));
y.mul(mMatrix[1]);
LLVector4a z;
z = _mm_shuffle_ps(v, v, _MM_SHUFFLE(2, 2, 2, 2));
z.mul(mMatrix[2]);
res.add(y);
res.add(z);
}
inline void affineTransform(const LLVector4a& v, LLVector4a& res)
{
LLVector4a x,y,z;
x = _mm_shuffle_ps(v, v, _MM_SHUFFLE(0, 0, 0, 0));
y = _mm_shuffle_ps(v, v, _MM_SHUFFLE(1, 1, 1, 1));
z = _mm_shuffle_ps(v, v, _MM_SHUFFLE(2, 2, 2, 2));
x.mul(mMatrix[0]);
y.mul(mMatrix[1]);
z.mul(mMatrix[2]);
x.add(y);
z.add(mMatrix[3]);
res.setAdd(x,z);
}
};
#endif

View File

@@ -35,6 +35,7 @@
#include "lltreenode.h"
#include "v3math.h"
#include "llvector4a.h"
#include <vector>
#include <set>
@@ -44,13 +45,14 @@
#define OCT_ERRS LL_WARNS("OctreeErrors")
#endif
extern U32 gOctreeMaxCapacity;
#if LL_DEBUG
#define LL_OCTREE_PARANOIA_CHECK 0
#else
#define LL_OCTREE_PARANOIA_CHECK 0
#endif
#define LL_OCTREE_MAX_CAPACITY 128
//#define LL_OCTREE_MAX_CAPACITY 128
template <class T> class LLOctreeNode;
@@ -84,6 +86,7 @@ template <class T>
class LLOctreeNode : public LLTreeNode<T>
{
public:
typedef LLOctreeTraveler<T> oct_traveler;
typedef LLTreeTraveler<T> tree_traveler;
typedef typename std::set<LLPointer<T> > element_list;
@@ -95,23 +98,30 @@ public:
typedef LLOctreeNode<T> oct_node;
typedef LLOctreeListener<T> oct_listener;
static const U8 OCTANT_POSITIVE_X = 0x01;
static const U8 OCTANT_POSITIVE_Y = 0x02;
static const U8 OCTANT_POSITIVE_Z = 0x04;
LLOctreeNode( LLVector3d center,
LLVector3d size,
/*void* operator new(size_t size)
{
return ll_aligned_malloc_16(size);
}
void operator delete(void* ptr)
{
ll_aligned_free_16(ptr);
}*/
LLOctreeNode( const LLVector4a& center,
const LLVector4a& size,
BaseType* parent,
U8 octant = 255)
: mParent((oct_node*)parent),
mCenter(center),
mSize(size),
mOctant(octant)
{
mCenter = center;
mSize = size;
updateMinMax();
if ((mOctant == 255) && mParent)
{
mOctant = ((oct_node*) mParent)->getOctant(mCenter.mdV);
mOctant = ((oct_node*) mParent)->getOctant(mCenter);
}
clearChildren();
@@ -128,39 +138,24 @@ public:
}
inline const BaseType* getParent() const { return mParent; }
inline void setParent(BaseType* parent) { mParent = (oct_node*) parent; }
inline const LLVector3d& getCenter() const { return mCenter; }
inline const LLVector3d& getSize() const { return mSize; }
inline void setCenter(const LLVector3d center) { mCenter = center; }
inline void setSize(const LLVector3d size) { mSize = size; }
inline void setParent(BaseType* parent) { mParent = (oct_node*) parent; }
inline const LLVector4a& getCenter() const { return mCenter; }
inline const LLVector4a& getSize() const { return mSize; }
inline void setCenter(const LLVector4a& center) { mCenter = center; }
inline void setSize(const LLVector4a& size) { mSize = size; }
inline oct_node* getNodeAt(T* data) { return getNodeAt(data->getPositionGroup(), data->getBinRadius()); }
inline U8 getOctant() const { return mOctant; }
inline const oct_node* getOctParent() const { return (const oct_node*) getParent(); }
inline oct_node* getOctParent() { return (oct_node*) getParent(); }
U8 getOctant(const F64 pos[]) const //get the octant pos is in
U8 getOctant(const LLVector4a& pos) const //get the octant pos is in
{
U8 ret = 0;
if (pos[0] > mCenter.mdV[0])
{
ret |= OCTANT_POSITIVE_X;
}
if (pos[1] > mCenter.mdV[1])
{
ret |= OCTANT_POSITIVE_Y;
}
if (pos[2] > mCenter.mdV[2])
{
ret |= OCTANT_POSITIVE_Z;
}
return ret;
return (U8) (pos.greaterThan(mCenter).getGatheredBits() & 0x7);
}
inline bool isInside(const LLVector3d& pos, const F64& rad) const
inline bool isInside(const LLVector4a& pos, const F32& rad) const
{
return rad <= mSize.mdV[0]*2.0 && isInside(pos);
return rad <= mSize[0]*2.f && isInside(pos);
}
inline bool isInside(T* data) const
@@ -168,29 +163,27 @@ public:
return isInside(data->getPositionGroup(), data->getBinRadius());
}
bool isInside(const LLVector3d& pos) const
bool isInside(const LLVector4a& pos) const
{
const F64& x = pos.mdV[0];
const F64& y = pos.mdV[1];
const F64& z = pos.mdV[2];
if (x > mMax.mdV[0] || x <= mMin.mdV[0] ||
y > mMax.mdV[1] || y <= mMin.mdV[1] ||
z > mMax.mdV[2] || z <= mMin.mdV[2])
S32 gt = pos.greaterThan(mMax).getGatheredBits() & 0x7;
if (gt)
{
return false;
}
S32 lt = pos.lessEqual(mMin).getGatheredBits() & 0x7;
if (lt)
{
return false;
}
return true;
}
void updateMinMax()
{
for (U32 i = 0; i < 3; i++)
{
mMax.mdV[i] = mCenter.mdV[i] + mSize.mdV[i];
mMin.mdV[i] = mCenter.mdV[i] - mSize.mdV[i];
}
mMax.setAdd(mCenter, mSize);
mMin.setSub(mCenter, mSize);
}
inline oct_listener* getOctListener(U32 index)
@@ -217,20 +210,20 @@ public:
(radius <= p_size && radius > size);
}
static void pushCenter(LLVector3d &center, const LLVector3d &size, const T* data)
static void pushCenter(LLVector4a &center, const LLVector4a &size, const T* data)
{
const LLVector3d& pos = data->getPositionGroup();
for (U32 i = 0; i < 3; i++)
{
if (pos.mdV[i] > center.mdV[i])
{
center.mdV[i] += size.mdV[i];
}
else
{
center.mdV[i] -= size.mdV[i];
}
}
const LLVector4a& pos = data->getPositionGroup();
LLVector4Logical gt = pos.greaterThan(center);
LLVector4a up;
up = _mm_and_ps(size, gt);
LLVector4a down;
down = _mm_andnot_ps(gt, size);
center.add(up);
center.sub(down);
}
void accept(oct_traveler* visitor) { visitor->visit(this); }
@@ -272,14 +265,14 @@ public:
}
oct_node* getNodeAt(const LLVector3d& pos, const F32& rad)
oct_node* getNodeAt(const LLVector4a& pos, const F32& rad)
{
LLOctreeNode<T>* node = this;
if (node->isInside(pos, rad))
{
//do a quick search by octant
U8 octant = node->getOctant(pos.mdV);
U8 octant = node->getOctant(pos);
//traverse the tree until we find a node that has no node
//at the appropriate octant or is smaller than the object.
@@ -290,7 +283,7 @@ public:
while (next_node != 255 && node->getSize()[0] >= rad)
{
node = node->getChild(next_node);
octant = node->getOctant(pos.mdV);
octant = node->getOctant(pos);
next_node = node->mChildMap[octant];
}
}
@@ -314,16 +307,14 @@ public:
//is it here?
if (isInside(data->getPositionGroup()))
{
if (getElementCount() < LL_OCTREE_MAX_CAPACITY &&
(contains(data->getBinRadius()) ||
(data->getBinRadius() > getSize().mdV[0] &&
parent && parent->getElementCount() >= LL_OCTREE_MAX_CAPACITY)))
if ((getElementCount() < gOctreeMaxCapacity && contains(data->getBinRadius()) ||
(data->getBinRadius() > getSize()[0] && parent && parent->getElementCount() >= gOctreeMaxCapacity)))
{ //it belongs here
#if LL_OCTREE_PARANOIA_CHECK
//if this is a redundant insertion, error out (should never happen)
if (mData.find(data) != mData.end())
{
llerrs << "Redundant octree insertion detected. " << data << llendl;
llwarns << "Redundant octree insertion detected. " << data << llendl;
return false;
}
#endif
@@ -341,23 +332,28 @@ public:
child = getChild(i);
if (child->isInside(data->getPositionGroup()))
{
llassert(child->getElementCount() <= LL_OCTREE_MAX_CAPACITY);
llassert(child->getElementCount() <= gOctreeMaxCapacity);
child->insert(data);
return false;
}
}
//it's here, but no kids are in the right place, make a new kid
LLVector3d center(getCenter());
LLVector3d size(getSize()*0.5);
LLVector4a center = getCenter();
LLVector4a size = getSize();
size.mul(0.5f);
//push center in direction of data
LLOctreeNode<T>::pushCenter(center, size, data);
// handle case where floating point number gets too small
if( llabs(center.mdV[0] - getCenter().mdV[0]) < F_APPROXIMATELY_ZERO &&
llabs(center.mdV[1] - getCenter().mdV[1]) < F_APPROXIMATELY_ZERO &&
llabs(center.mdV[2] - getCenter().mdV[2]) < F_APPROXIMATELY_ZERO)
LLVector4a val;
val.setSub(center, getCenter());
val.setAbs(val);
S32 lt = val.lessThan(LLVector4a::getEpsilon()).getGatheredBits() & 0x7;
if( lt == 0x7 )
{
mData.insert(data);
BaseType::insert(data);
@@ -375,7 +371,7 @@ public:
//make sure no existing node matches this position
for (U32 i = 0; i < getChildCount(); i++)
{
if (mChild[i]->getCenter() == center)
if (mChild[i]->getCenter().equals3(center))
{
OCT_ERRS << "Octree detected duplicate child center and gave up." << llendl;
return false;
@@ -504,18 +500,18 @@ public:
{
#if LL_OCTREE_PARANOIA_CHECK
if (child->getSize() == getSize())
if (child->getSize().equals3(getSize()))
{
OCT_ERRS << "Child size is same as parent size!" << llendl;
}
for (U32 i = 0; i < getChildCount(); i++)
{
if(mChild[i]->getSize() != child->getSize())
if(!mChild[i]->getSize().equals3(child->getSize()))
{
OCT_ERRS <<"Invalid octree child size." << llendl;
}
if (mChild[i]->getCenter() == child->getCenter())
if (mChild[i]->getCenter().equals3(child->getCenter()))
{
OCT_ERRS <<"Duplicate octree child position." << llendl;
}
@@ -606,11 +602,11 @@ protected:
MIN = 3
} eDName;
LLVector3d mCenter;
LLVector3d mSize;
LLVector3d mMax;
LLVector3d mMin;
LLVector4a mCenter;
LLVector4a mSize;
LLVector4a mMax;
LLVector4a mMin;
oct_node* mParent;
U8 mOctant;
@@ -629,9 +625,9 @@ public:
typedef LLOctreeNode<T> BaseType;
typedef LLOctreeNode<T> oct_node;
LLOctreeRoot( const LLVector3d &center,
const LLVector3d &size,
BaseType* parent)
LLOctreeRoot(const LLVector4a& center,
const LLVector4a& size,
BaseType* parent)
: BaseType(center, size, parent)
{
}
@@ -684,18 +680,23 @@ public:
return false;
}
const F64 MAX_MAG = 1024.0*1024.0;
LLVector4a MAX_MAG;
MAX_MAG.splat(1024.f*1024.f);
const LLVector3d& v = data->getPositionGroup();
if (!(fabs(v.mdV[0]-this->mCenter.mdV[0]) < MAX_MAG &&
fabs(v.mdV[1]-this->mCenter.mdV[1]) < MAX_MAG &&
fabs(v.mdV[2]-this->mCenter.mdV[2]) < MAX_MAG))
const LLVector4a& v = data->getPositionGroup();
LLVector4a val;
val.setSub(v, BaseType::mCenter);
val.setAbs(val);
S32 lt = val.lessThan(MAX_MAG).getGatheredBits() & 0x7;
if (lt != 0x7)
{
//OCT_ERRS << "!!! ELEMENT EXCEEDS RANGE OF SPATIAL PARTITION !!!" << llendl;
return false;
}
if (this->getSize().mdV[0] > data->getBinRadius() && isInside(data->getPositionGroup()))
if (this->getSize()[0] > data->getBinRadius() && isInside(data->getPositionGroup()))
{
//we got it, just act like a branch
oct_node* node = getNodeAt(data);
@@ -711,31 +712,34 @@ public:
else if (this->getChildCount() == 0)
{
//first object being added, just wrap it up
while (!(this->getSize().mdV[0] > data->getBinRadius() && isInside(data->getPositionGroup())))
while (!(this->getSize()[0] > data->getBinRadius() && isInside(data->getPositionGroup())))
{
LLVector3d center, size;
LLVector4a center, size;
center = this->getCenter();
size = this->getSize();
LLOctreeNode<T>::pushCenter(center, size, data);
this->setCenter(center);
this->setSize(size*2);
size.mul(2.f);
this->setSize(size);
this->updateMinMax();
}
LLOctreeNode<T>::insert(data);
}
else
{
while (!(this->getSize().mdV[0] > data->getBinRadius() && isInside(data->getPositionGroup())))
while (!(this->getSize()[0] > data->getBinRadius() && isInside(data->getPositionGroup())))
{
//the data is outside the root node, we need to grow
LLVector3d center(this->getCenter());
LLVector3d size(this->getSize());
LLVector4a center(this->getCenter());
LLVector4a size(this->getSize());
//expand this node
LLVector3d newcenter(center);
LLVector4a newcenter(center);
LLOctreeNode<T>::pushCenter(newcenter, size, data);
this->setCenter(newcenter);
this->setSize(size*2);
LLVector4a size2 = size;
size2.mul(2.f);
this->setSize(size2);
this->updateMinMax();
//copy our children to a new branch

View File

@@ -42,13 +42,17 @@
// The plane normal = [A, B, C]
// The closest approach = D / sqrt(A*A + B*B + C*C)
class LLPlane : public LLVector4
class LLPlane
{
public:
// Constructors
LLPlane() {}; // no default constructor
LLPlane(const LLVector3 &p0, F32 d) { setVec(p0, d); }
LLPlane(const LLVector3 &p0, const LLVector3 &n) { setVec(p0, n); }
inline void setVec(const LLVector3 &p0, F32 d) { LLVector4::setVec(p0[0], p0[1], p0[2], d); }
inline void setVec(const LLVector3 &p0, F32 d) { mV.set(p0[0], p0[1], p0[2], d); }
// Set
inline void setVec(const LLVector3 &p0, const LLVector3 &n)
{
F32 d = -(p0 * n);
@@ -64,39 +68,38 @@ public:
F32 d = -(w * p0);
setVec(w, d);
}
inline LLPlane& operator=(const LLVector4& v2) { LLVector4::setVec(v2[0],v2[1],v2[2],v2[3]); return *this;}
inline void set(const LLPlane& p2) { LLVector4::setVec(p2); }
inline LLPlane& operator=(const LLVector4& v2) { mV.set(v2[0],v2[1],v2[2],v2[3]); return *this;}
inline LLPlane& operator=(const LLVector4a& v2) { mV.set(v2[0],v2[1],v2[2],v2[3]); return *this;}
inline void set(const LLPlane& p2) { mV = p2.mV; }
//
F32 dist(const LLVector3 &v2) const { return mV[0]*v2[0] + mV[1]*v2[1] + mV[2]*v2[2] + mV[3]; }
inline LLSimdScalar dot3(const LLVector4a& b) const { return mV.dot3(b); }
// Read-only access a single float in this vector. Do not use in proximity to any function call that manipulates
// the data at the whole vector level or you will incur a substantial penalty. Consider using the splat functions instead
inline F32 operator[](const S32 idx) const { return mV[idx]; }
// preferable when index is known at compile time
template <int N> LL_FORCE_INLINE void getAt(LLSimdScalar& v) const { v = mV.getScalarAt<N>(); }
// reset the vector to 0, 0, 0, 1
inline void clear() { LLVector4::setVec(0, 0, 0, 1); }
inline void clear() { mV.set(0, 0, 0, 1); }
inline void getVector3(LLVector3& vec) const { vec.set(mV[0], mV[1], mV[2]); }
// Retrieve the mask indicating which of the x, y, or z axis are greater or equal to zero.
inline U8 calcPlaneMask() const
{
U8 mask = 0;
if (mV[0] >= 0)
{
mask |= 1;
}
if (mV[1] >= 0)
{
mask |= 2;
}
if (mV[2] >= 0)
{
mask |= 4;
}
return mask;
// Retrieve the mask indicating which of the x, y, or z axis are greater or equal to zero.
inline U8 calcPlaneMask()
{
return mV.greaterEqual(LLVector4a::getZero()).getGatheredBits() & LLVector4Logical::MASK_XYZ;
}
private:
LLVector4a mV;
};

View File

@@ -35,10 +35,16 @@
#define LL_LLQUANTIZE_H
const U16 U16MAX = 65535;
LL_ALIGN_16( const F32 F_U16MAX_4A[4] ) = { 65535.f, 65535.f, 65535.f, 65535.f };
const F32 OOU16MAX = 1.f/(F32)(U16MAX);
LL_ALIGN_16( const F32 F_OOU16MAX_4A[4] ) = { OOU16MAX, OOU16MAX, OOU16MAX, OOU16MAX };
const U8 U8MAX = 255;
LL_ALIGN_16( const F32 F_U8MAX_4A[4] ) = { 255.f, 255.f, 255.f, 255.f };
const F32 OOU8MAX = 1.f/(F32)(U8MAX);
LL_ALIGN_16( const F32 F_OOU8MAX_4A[4] ) = { OOU8MAX, OOU8MAX, OOU8MAX, OOU8MAX };
const U8 FIRSTVALIDCHAR = 54;
const U8 MAXSTRINGVAL = U8MAX - FIRSTVALIDCHAR; //we don't allow newline or null

View File

@@ -0,0 +1,105 @@
/**
* @file llquaternion2.h
* @brief LLQuaternion2 class header file - SIMD-enabled quaternion class
*
* $LicenseInfo:firstyear=2010&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LL_QUATERNION2_H
#define LL_QUATERNION2_H
/////////////////////////////
// LLQuaternion2
/////////////////////////////
// This class stores a quaternion x*i + y*j + z*k + w in <x, y, z, w> order
// (i.e., w in high order element of vector)
/////////////////////////////
/////////////////////////////
// These classes are intentionally minimal right now. If you need additional
// functionality, please contact someone with SSE experience (e.g., Falcon or
// Huseby).
/////////////////////////////
#include "llquaternion.h"
class LLQuaternion2
{
public:
//////////////////////////
// Ctors
//////////////////////////
// Ctor
LLQuaternion2() {}
// Ctor from LLQuaternion
explicit LLQuaternion2( const class LLQuaternion& quat );
//////////////////////////
// Get/Set
//////////////////////////
// Load from an LLQuaternion
inline void operator=( const LLQuaternion& quat )
{
mQ.loadua( quat.mQ );
}
// Return the internal LLVector4a representation of the quaternion
inline const LLVector4a& getVector4a() const;
inline LLVector4a& getVector4aRw();
/////////////////////////
// Quaternion modification
/////////////////////////
// Set this quaternion to the conjugate of src
inline void setConjugate(const LLQuaternion2& src);
// Renormalizes the quaternion. Assumes it has nonzero length.
inline void normalize();
// Quantize this quaternion to 8 bit precision
inline void quantize8();
// Quantize this quaternion to 16 bit precision
inline void quantize16();
/////////////////////////
// Quaternion inspection
/////////////////////////
// Return true if this quaternion is equal to 'rhs'.
// Note! Quaternions exhibit "double-cover", so any rotation has two equally valid
// quaternion representations and they will NOT compare equal.
inline bool equals(const LLQuaternion2& rhs, F32 tolerance = F_APPROXIMATELY_ZERO ) const;
// Return true if all components are finite and the quaternion is normalized
inline bool isOkRotation() const;
protected:
LLVector4a mQ;
};
#endif

View File

@@ -0,0 +1,102 @@
/**
* @file llquaternion2.inl
* @brief LLQuaternion2 inline definitions
*
* $LicenseInfo:firstyear=2010&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "llquaternion2.h"
static const LLQuad LL_V4A_PLUS_ONE = {1.f, 1.f, 1.f, 1.f};
static const LLQuad LL_V4A_MINUS_ONE = {-1.f, -1.f, -1.f, -1.f};
// Ctor from LLQuaternion
inline LLQuaternion2::LLQuaternion2( const LLQuaternion& quat )
{
mQ.set(quat.mQ[VX], quat.mQ[VY], quat.mQ[VZ], quat.mQ[VW]);
}
//////////////////////////
// Get/Set
//////////////////////////
// Return the internal LLVector4a representation of the quaternion
inline const LLVector4a& LLQuaternion2::getVector4a() const
{
return mQ;
}
inline LLVector4a& LLQuaternion2::getVector4aRw()
{
return mQ;
}
/////////////////////////
// Quaternion modification
/////////////////////////
// Set this quaternion to the conjugate of src
inline void LLQuaternion2::setConjugate(const LLQuaternion2& src)
{
static LL_ALIGN_16( const U32 F_QUAT_INV_MASK_4A[4] ) = { 0x80000000, 0x80000000, 0x80000000, 0x00000000 };
mQ = _mm_xor_ps(src.mQ, *reinterpret_cast<const LLQuad*>(&F_QUAT_INV_MASK_4A));
}
// Renormalizes the quaternion. Assumes it has nonzero length.
inline void LLQuaternion2::normalize()
{
mQ.normalize4();
}
// Quantize this quaternion to 8 bit precision
inline void LLQuaternion2::quantize8()
{
mQ.quantize8( LL_V4A_MINUS_ONE, LL_V4A_PLUS_ONE );
normalize();
}
// Quantize this quaternion to 16 bit precision
inline void LLQuaternion2::quantize16()
{
mQ.quantize16( LL_V4A_MINUS_ONE, LL_V4A_PLUS_ONE );
normalize();
}
/////////////////////////
// Quaternion inspection
/////////////////////////
// Return true if this quaternion is equal to 'rhs'.
// Note! Quaternions exhibit "double-cover", so any rotation has two equally valid
// quaternion representations and they will NOT compare equal.
inline bool LLQuaternion2::equals(const LLQuaternion2 &rhs, F32 tolerance/* = F_APPROXIMATELY_ZERO*/) const
{
return mQ.equals4(rhs.mQ, tolerance);
}
// Return true if all components are finite and the quaternion is normalized
inline bool LLQuaternion2::isOkRotation() const
{
return mQ.isFinite4() && mQ.isNormalized4();
}

View File

@@ -31,4 +31,5 @@
#include "linden_common.h"
// implementation is all in the header, this include dep ensures the unit test is rerun if the implementation changes.
#include "llrect.h"

93
indra/llmath/llsimdmath.h Normal file
View File

@@ -0,0 +1,93 @@
/**
* @file llsimdmath.h
* @brief Common header for SIMD-based math library (llvector4a, llmatrix3a, etc.)
*
* $LicenseInfo:firstyear=2010&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LL_SIMD_MATH_H
#define LL_SIMD_MATH_H
#ifndef LLMATH_H
#error "Please include llmath.h before this file."
#endif
#if ( ( LL_DARWIN || LL_LINUX ) && !(__SSE2__) ) || ( LL_WINDOWS && ( _M_IX86_FP < 2 ) )
#error SSE2 not enabled. LLVector4a and related class will not compile.
#endif
#if !LL_WINDOWS
#include <stdint.h>
#endif
template <typename T> T* LL_NEXT_ALIGNED_ADDRESS(T* address)
{
return reinterpret_cast<T*>(
(reinterpret_cast<uintptr_t>(address) + 0xF) & ~0xF);
}
template <typename T> T* LL_NEXT_ALIGNED_ADDRESS_64(T* address)
{
return reinterpret_cast<T*>(
(reinterpret_cast<uintptr_t>(address) + 0x3F) & ~0x3F);
}
#if LL_LINUX || LL_DARWIN
#define LL_ALIGN_PREFIX(x)
#define LL_ALIGN_POSTFIX(x) __attribute__((aligned(x)))
#elif LL_WINDOWS
#define LL_ALIGN_PREFIX(x) __declspec(align(x))
#define LL_ALIGN_POSTFIX(x)
#else
#error "LL_ALIGN_PREFIX and LL_ALIGN_POSTFIX undefined"
#endif
#define LL_ALIGN_16(var) LL_ALIGN_PREFIX(16) var LL_ALIGN_POSTFIX(16)
#include <xmmintrin.h>
#include <emmintrin.h>
#include "llsimdtypes.h"
#include "llsimdtypes.inl"
class LLMatrix3a;
class LLRotation;
class LLMatrix3;
#include "llquaternion.h"
#include "llvector4logical.h"
#include "llvector4a.h"
#include "llmatrix3a.h"
#include "llquaternion2.h"
#include "llvector4a.inl"
#include "llmatrix3a.inl"
#include "llquaternion2.inl"
#endif //LL_SIMD_MATH_H

124
indra/llmath/llsimdtypes.h Normal file
View File

@@ -0,0 +1,124 @@
/**
* @file llsimdtypes.h
* @brief Declaration of basic SIMD math related types
*
* $LicenseInfo:firstyear=2010&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LL_SIMD_TYPES_H
#define LL_SIMD_TYPES_H
#ifndef LL_SIMD_MATH_H
#error "Please include llmath.h before this file."
#endif
typedef __m128 LLQuad;
#if LL_WINDOWS
#pragma warning(push)
#pragma warning( disable : 4800 3 ) // Disable warning about casting int to bool for this class.
#if defined(_MSC_VER) && (_MSC_VER < 1500)
// VC++ 2005 is missing these intrinsics
// __forceinline is MSVC specific and attempts to override compiler inlining judgment. This is so
// even in debug builds this call is a NOP.
__forceinline const __m128 _mm_castsi128_ps( const __m128i a ) { return reinterpret_cast<const __m128&>(a); }
__forceinline const __m128i _mm_castps_si128( const __m128 a ) { return reinterpret_cast<const __m128i&>(a); }
#endif // _MSC_VER
#endif // LL_WINDOWS
class LLBool32
{
public:
inline LLBool32() {}
inline LLBool32(int rhs) : m_bool(rhs) {}
inline LLBool32(unsigned int rhs) : m_bool(rhs) {}
inline LLBool32(bool rhs) { m_bool = static_cast<const int>(rhs); }
inline LLBool32& operator= (bool rhs) { m_bool = (int)rhs; return *this; }
inline bool operator== (bool rhs) const { return static_cast<const bool&>(m_bool) == rhs; }
inline bool operator!= (bool rhs) const { return !operator==(rhs); }
inline operator bool() const { return static_cast<const bool&>(m_bool); }
private:
int m_bool;
};
#if LL_WINDOWS
#pragma warning(pop)
#endif
class LLSimdScalar
{
public:
inline LLSimdScalar() {}
inline LLSimdScalar(LLQuad q)
{
mQ = q;
}
inline LLSimdScalar(F32 f)
{
mQ = _mm_set_ss(f);
}
static inline const LLSimdScalar& getZero()
{
extern const LLQuad F_ZERO_4A;
return reinterpret_cast<const LLSimdScalar&>(F_ZERO_4A);
}
inline F32 getF32() const;
inline LLBool32 isApproximatelyEqual(const LLSimdScalar& rhs, F32 tolerance = F_APPROXIMATELY_ZERO) const;
inline LLSimdScalar getAbs() const;
inline void setMax( const LLSimdScalar& a, const LLSimdScalar& b );
inline void setMin( const LLSimdScalar& a, const LLSimdScalar& b );
inline LLSimdScalar& operator=(F32 rhs);
inline LLSimdScalar& operator+=(const LLSimdScalar& rhs);
inline LLSimdScalar& operator-=(const LLSimdScalar& rhs);
inline LLSimdScalar& operator*=(const LLSimdScalar& rhs);
inline LLSimdScalar& operator/=(const LLSimdScalar& rhs);
inline operator LLQuad() const
{
return mQ;
}
inline const LLQuad& getQuad() const
{
return mQ;
}
private:
LLQuad mQ;
};
#endif //LL_SIMD_TYPES_H

View File

@@ -0,0 +1,157 @@
/**
* @file llsimdtypes.inl
* @brief Inlined definitions of basic SIMD math related types
*
* $LicenseInfo:firstyear=2010&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
//////////////////
// LLSimdScalar
//////////////////
inline LLSimdScalar operator+(const LLSimdScalar& a, const LLSimdScalar& b)
{
LLSimdScalar t(a);
t += b;
return t;
}
inline LLSimdScalar operator-(const LLSimdScalar& a, const LLSimdScalar& b)
{
LLSimdScalar t(a);
t -= b;
return t;
}
inline LLSimdScalar operator*(const LLSimdScalar& a, const LLSimdScalar& b)
{
LLSimdScalar t(a);
t *= b;
return t;
}
inline LLSimdScalar operator/(const LLSimdScalar& a, const LLSimdScalar& b)
{
LLSimdScalar t(a);
t /= b;
return t;
}
inline LLSimdScalar operator-(const LLSimdScalar& a)
{
static LL_ALIGN_16(const U32 signMask[4]) = {0x80000000, 0x80000000, 0x80000000, 0x80000000 };
return _mm_xor_ps(*reinterpret_cast<const LLQuad*>(signMask), a);
}
inline LLBool32 operator==(const LLSimdScalar& a, const LLSimdScalar& b)
{
return _mm_comieq_ss(a, b);
}
inline LLBool32 operator!=(const LLSimdScalar& a, const LLSimdScalar& b)
{
return _mm_comineq_ss(a, b);
}
inline LLBool32 operator<(const LLSimdScalar& a, const LLSimdScalar& b)
{
return _mm_comilt_ss(a, b);
}
inline LLBool32 operator<=(const LLSimdScalar& a, const LLSimdScalar& b)
{
return _mm_comile_ss(a, b);
}
inline LLBool32 operator>(const LLSimdScalar& a, const LLSimdScalar& b)
{
return _mm_comigt_ss(a, b);
}
inline LLBool32 operator>=(const LLSimdScalar& a, const LLSimdScalar& b)
{
return _mm_comige_ss(a, b);
}
inline LLBool32 LLSimdScalar::isApproximatelyEqual(const LLSimdScalar& rhs, F32 tolerance /* = F_APPROXIMATELY_ZERO */) const
{
const LLSimdScalar tol( tolerance );
const LLSimdScalar diff = _mm_sub_ss( mQ, rhs.mQ );
const LLSimdScalar absDiff = diff.getAbs();
return absDiff <= tol;
}
inline void LLSimdScalar::setMax( const LLSimdScalar& a, const LLSimdScalar& b )
{
mQ = _mm_max_ss( a, b );
}
inline void LLSimdScalar::setMin( const LLSimdScalar& a, const LLSimdScalar& b )
{
mQ = _mm_min_ss( a, b );
}
inline LLSimdScalar& LLSimdScalar::operator=(F32 rhs)
{
mQ = _mm_set_ss(rhs);
return *this;
}
inline LLSimdScalar& LLSimdScalar::operator+=(const LLSimdScalar& rhs)
{
mQ = _mm_add_ss( mQ, rhs );
return *this;
}
inline LLSimdScalar& LLSimdScalar::operator-=(const LLSimdScalar& rhs)
{
mQ = _mm_sub_ss( mQ, rhs );
return *this;
}
inline LLSimdScalar& LLSimdScalar::operator*=(const LLSimdScalar& rhs)
{
mQ = _mm_mul_ss( mQ, rhs );
return *this;
}
inline LLSimdScalar& LLSimdScalar::operator/=(const LLSimdScalar& rhs)
{
mQ = _mm_div_ss( mQ, rhs );
return *this;
}
inline LLSimdScalar LLSimdScalar::getAbs() const
{
static const LL_ALIGN_16(U32 F_ABS_MASK_4A[4]) = { 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF };
return _mm_and_ps( mQ, *reinterpret_cast<const LLQuad*>(F_ABS_MASK_4A));
}
inline F32 LLSimdScalar::getF32() const
{
F32 ret;
_mm_store_ss(&ret, mQ);
return ret;
}

View File

@@ -34,6 +34,7 @@
#include "stdtypes.h"
#include "xform.h"
#include "llmemory.h"
#include <vector>
template <class T> class LLTreeNode;

222
indra/llmath/llvector4a.cpp Normal file
View File

@@ -0,0 +1,222 @@
/**
* @file llvector4a.cpp
* @brief SIMD vector implementation
*
* $LicenseInfo:firstyear=2010&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "llmath.h"
#include "llquantize.h"
extern const LLQuad F_ZERO_4A = { 0, 0, 0, 0 };
extern const LLQuad F_APPROXIMATELY_ZERO_4A = {
F_APPROXIMATELY_ZERO,
F_APPROXIMATELY_ZERO,
F_APPROXIMATELY_ZERO,
F_APPROXIMATELY_ZERO
};
extern const LLVector4a LL_V4A_ZERO = reinterpret_cast<const LLVector4a&> ( F_ZERO_4A );
extern const LLVector4a LL_V4A_EPSILON = reinterpret_cast<const LLVector4a&> ( F_APPROXIMATELY_ZERO_4A );
/*static */void LLVector4a::memcpyNonAliased16(F32* __restrict dst, const F32* __restrict src, size_t bytes)
{
assert(src != NULL);
assert(dst != NULL);
assert(bytes > 0);
assert((bytes % sizeof(F32))== 0);
F32* end = dst + (bytes / sizeof(F32) );
if (bytes > 64)
{
F32* begin_64 = LL_NEXT_ALIGNED_ADDRESS_64(dst);
//at least 64 (16*4) bytes before the end of the destination, switch to 16 byte copies
F32* end_64 = end-16;
_mm_prefetch((char*)begin_64, _MM_HINT_NTA);
_mm_prefetch((char*)begin_64 + 64, _MM_HINT_NTA);
_mm_prefetch((char*)begin_64 + 128, _MM_HINT_NTA);
_mm_prefetch((char*)begin_64 + 192, _MM_HINT_NTA);
while (dst < begin_64)
{
copy4a(dst, src);
dst += 4;
src += 4;
}
while (dst < end_64)
{
_mm_prefetch((char*)src + 512, _MM_HINT_NTA);
_mm_prefetch((char*)dst + 512, _MM_HINT_NTA);
copy4a(dst, src);
copy4a(dst+4, src+4);
copy4a(dst+8, src+8);
copy4a(dst+12, src+12);
dst += 16;
src += 16;
}
}
while (dst < end)
{
copy4a(dst, src);
dst += 4;
src += 4;
}
}
void LLVector4a::setRotated( const LLRotation& rot, const LLVector4a& vec )
{
const LLVector4a col0 = rot.getColumn(0);
const LLVector4a col1 = rot.getColumn(1);
const LLVector4a col2 = rot.getColumn(2);
LLVector4a result = _mm_load_ss( vec.getF32ptr() );
result.splat<0>( result );
result.mul( col0 );
{
LLVector4a yyyy = _mm_load_ss( vec.getF32ptr() + 1 );
yyyy.splat<0>( yyyy );
yyyy.mul( col1 );
result.add( yyyy );
}
{
LLVector4a zzzz = _mm_load_ss( vec.getF32ptr() + 2 );
zzzz.splat<0>( zzzz );
zzzz.mul( col2 );
result.add( zzzz );
}
*this = result;
}
void LLVector4a::setRotated( const LLQuaternion2& quat, const LLVector4a& vec )
{
const LLVector4a& quatVec = quat.getVector4a();
LLVector4a temp; temp.setCross3(quatVec, vec);
temp.add( temp );
const LLVector4a realPart( quatVec.getScalarAt<3>() );
LLVector4a tempTimesReal; tempTimesReal.setMul( temp, realPart );
mQ = vec;
add( tempTimesReal );
LLVector4a imagCrossTemp; imagCrossTemp.setCross3( quatVec, temp );
add(imagCrossTemp);
}
void LLVector4a::quantize8( const LLVector4a& low, const LLVector4a& high )
{
LLVector4a val(mQ);
LLVector4a delta; delta.setSub( high, low );
{
val.clamp(low, high);
val.sub(low);
// 8-bit quantization means we can do with just 12 bits of reciprocal accuracy
const LLVector4a oneOverDelta = _mm_rcp_ps(delta.mQ);
// {
// static LL_ALIGN_16( const F32 F_TWO_4A[4] ) = { 2.f, 2.f, 2.f, 2.f };
// LLVector4a two; two.load4a( F_TWO_4A );
//
// // Here we use _mm_rcp_ps plus one round of newton-raphson
// // We wish to find 'x' such that x = 1/delta
// // As a first approximation, we take x0 = _mm_rcp_ps(delta)
// // Then x1 = 2 * x0 - a * x0^2 or x1 = x0 * ( 2 - a * x0 )
// // See Intel AP-803 http://ompf.org/!/Intel_application_note_AP-803.pdf
// const LLVector4a recipApprox = _mm_rcp_ps(delta.mQ);
// oneOverDelta.setMul( delta, recipApprox );
// oneOverDelta.setSub( two, oneOverDelta );
// oneOverDelta.mul( recipApprox );
// }
val.mul(oneOverDelta);
val.mul(*reinterpret_cast<const LLVector4a*>(F_U8MAX_4A));
}
val = _mm_cvtepi32_ps(_mm_cvtps_epi32( val.mQ ));
{
val.mul(*reinterpret_cast<const LLVector4a*>(F_OOU8MAX_4A));
val.mul(delta);
val.add(low);
}
{
LLVector4a maxError; maxError.setMul(delta, *reinterpret_cast<const LLVector4a*>(F_OOU8MAX_4A));
LLVector4a absVal; absVal.setAbs( val );
setSelectWithMask( absVal.lessThan( maxError ), F_ZERO_4A, val );
}
}
void LLVector4a::quantize16( const LLVector4a& low, const LLVector4a& high )
{
LLVector4a val(mQ);
LLVector4a delta; delta.setSub( high, low );
{
val.clamp(low, high);
val.sub(low);
// 16-bit quantization means we need a round of Newton-Raphson
LLVector4a oneOverDelta;
{
static LL_ALIGN_16( const F32 F_TWO_4A[4] ) = { 2.f, 2.f, 2.f, 2.f };
LLVector4a two; two.load4a( F_TWO_4A );
// Here we use _mm_rcp_ps plus one round of newton-raphson
// We wish to find 'x' such that x = 1/delta
// As a first approximation, we take x0 = _mm_rcp_ps(delta)
// Then x1 = 2 * x0 - a * x0^2 or x1 = x0 * ( 2 - a * x0 )
// See Intel AP-803 http://ompf.org/!/Intel_application_note_AP-803.pdf
const LLVector4a recipApprox = _mm_rcp_ps(delta.mQ);
oneOverDelta.setMul( delta, recipApprox );
oneOverDelta.setSub( two, oneOverDelta );
oneOverDelta.mul( recipApprox );
}
val.mul(oneOverDelta);
val.mul(*reinterpret_cast<const LLVector4a*>(F_U16MAX_4A));
}
val = _mm_cvtepi32_ps(_mm_cvtps_epi32( val.mQ ));
{
val.mul(*reinterpret_cast<const LLVector4a*>(F_OOU16MAX_4A));
val.mul(delta);
val.add(low);
}
{
LLVector4a maxError; maxError.setMul(delta, *reinterpret_cast<const LLVector4a*>(F_OOU16MAX_4A));
LLVector4a absVal; absVal.setAbs( val );
setSelectWithMask( absVal.lessThan( maxError ), F_ZERO_4A, val );
}
}

324
indra/llmath/llvector4a.h Normal file
View File

@@ -0,0 +1,324 @@
/**
* @file llvector4a.h
* @brief LLVector4a class header file - memory aligned and vectorized 4 component vector
*
* $LicenseInfo:firstyear=2010&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LL_LLVECTOR4A_H
#define LL_LLVECTOR4A_H
class LLRotation;
#include <assert.h>
#include "llpreprocessor.h"
///////////////////////////////////
// FIRST TIME USERS PLEASE READ
//////////////////////////////////
// This is just the beginning of LLVector4a. There are many more useful functions
// yet to be implemented. For example, setNeg to negate a vector, rotate() to apply
// a matrix rotation, various functions to manipulate only the X, Y, and Z elements
// and many others (including a whole variety of accessors). So if you don't see a
// function here that you need, please contact Falcon or someone else with SSE
// experience (Richard, I think, has some and davep has a little as of the time
// of this writing, July 08, 2010) about getting it implemented before you resort to
// LLVector3/LLVector4.
/////////////////////////////////
class LLVector4a
{
public:
///////////////////////////////////
// STATIC METHODS
///////////////////////////////////
// Call initClass() at startup to avoid 15,000+ cycle penalties from denormalized numbers
static void initClass()
{
_MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
_MM_SET_ROUNDING_MODE(_MM_ROUND_NEAREST);
}
// Return a vector of all zeros
static inline const LLVector4a& getZero()
{
extern const LLVector4a LL_V4A_ZERO;
return LL_V4A_ZERO;
}
// Return a vector of all epsilon, where epsilon is a small float suitable for approximate equality checks
static inline const LLVector4a& getEpsilon()
{
extern const LLVector4a LL_V4A_EPSILON;
return LL_V4A_EPSILON;
}
// Copy 16 bytes from src to dst. Source and destination must be 16-byte aligned
static inline void copy4a(F32* dst, const F32* src)
{
_mm_store_ps(dst, _mm_load_ps(src));
}
// Copy words 16-byte blocks from src to dst. Source and destination must not overlap.
static void memcpyNonAliased16(F32* __restrict dst, const F32* __restrict src, size_t bytes);
////////////////////////////////////
// CONSTRUCTORS
////////////////////////////////////
LLVector4a()
{ //DO NOT INITIALIZE -- The overhead is completely unnecessary
}
LLVector4a(F32 x, F32 y, F32 z, F32 w = 0.f)
{
set(x,y,z,w);
}
LLVector4a(F32 x)
{
splat(x);
}
LLVector4a(const LLSimdScalar& x)
{
splat(x);
}
LLVector4a(LLQuad q)
{
mQ = q;
}
////////////////////////////////////
// LOAD/STORE
////////////////////////////////////
// Load from 16-byte aligned src array (preferred method of loading)
inline void load4a(const F32* src);
// Load from unaligned src array (NB: Significantly slower than load4a)
inline void loadua(const F32* src);
// Load only three floats beginning at address 'src'. Slowest method.
inline void load3(const F32* src);
// Store to a 16-byte aligned memory address
inline void store4a(F32* dst) const;
////////////////////////////////////
// BASIC GET/SET
////////////////////////////////////
// Return a "this" as an F32 pointer. Do not use unless you have a very good reason. (Not sure? Ask Falcon)
inline F32* getF32ptr();
// Return a "this" as a const F32 pointer. Do not use unless you have a very good reason. (Not sure? Ask Falcon)
inline const F32* const getF32ptr() const;
// Read-only access a single float in this vector. Do not use in proximity to any function call that manipulates
// the data at the whole vector level or you will incur a substantial penalty. Consider using the splat functions instead
inline F32 operator[](const S32 idx) const;
// Prefer this method for read-only access to a single element. Prefer the templated version if the elem is known at compile time.
inline LLSimdScalar getScalarAt(const S32 idx) const;
// Prefer this method for read-only access to a single element. Prefer the templated version if the elem is known at compile time.
template <int N> LL_FORCE_INLINE LLSimdScalar getScalarAt() const;
// Set to an x, y, z and optional w provided
inline void set(F32 x, F32 y, F32 z, F32 w = 0.f);
// Set to all zeros. This is preferred to using ::getZero()
inline void clear();
// Set all elements to 'x'
inline void splat(const F32 x);
// Set all elements to 'x'
inline void splat(const LLSimdScalar& x);
// Set all 4 elements to element N of src, with N known at compile time
template <int N> void splat(const LLVector4a& src);
// Set all 4 elements to element i of v, with i NOT known at compile time
inline void splat(const LLVector4a& v, U32 i);
// Select bits from sourceIfTrue and sourceIfFalse according to bits in mask
inline void setSelectWithMask( const LLVector4Logical& mask, const LLVector4a& sourceIfTrue, const LLVector4a& sourceIfFalse );
////////////////////////////////////
// ALGEBRAIC
////////////////////////////////////
// Set this to the element-wise (a + b)
inline void setAdd(const LLVector4a& a, const LLVector4a& b);
// Set this to element-wise (a - b)
inline void setSub(const LLVector4a& a, const LLVector4a& b);
// Set this to element-wise multiply (a * b)
inline void setMul(const LLVector4a& a, const LLVector4a& b);
// Set this to element-wise quotient (a / b)
inline void setDiv(const LLVector4a& a, const LLVector4a& b);
// Set this to the element-wise absolute value of src
inline void setAbs(const LLVector4a& src);
// Add to each component in this vector the corresponding component in rhs
inline void add(const LLVector4a& rhs);
// Subtract from each component in this vector the corresponding component in rhs
inline void sub(const LLVector4a& rhs);
// Multiply each component in this vector by the corresponding component in rhs
inline void mul(const LLVector4a& rhs);
// Divide each component in this vector by the corresponding component in rhs
inline void div(const LLVector4a& rhs);
// Multiply this vector by x in a scalar fashion
inline void mul(const F32 x);
// Set this to (a x b) (geometric cross-product)
inline void setCross3(const LLVector4a& a, const LLVector4a& b);
// Set all elements to the dot product of the x, y, and z elements in a and b
inline void setAllDot3(const LLVector4a& a, const LLVector4a& b);
// Set all elements to the dot product of the x, y, z, and w elements in a and b
inline void setAllDot4(const LLVector4a& a, const LLVector4a& b);
// Return the 3D dot product of this vector and b
inline LLSimdScalar dot3(const LLVector4a& b) const;
// Return the 4D dot product of this vector and b
inline LLSimdScalar dot4(const LLVector4a& b) const;
// Normalize this vector with respect to the x, y, and z components only. Accurate to 22 bites of precision. W component is destroyed
// Note that this does not consider zero length vectors!
inline void normalize3();
// Same as normalize3() but with respect to all 4 components
inline void normalize4();
// Same as normalize3(), but returns length as a SIMD scalar
inline LLSimdScalar normalize3withLength();
// Normalize this vector with respect to the x, y, and z components only. Accurate only to 10-12 bits of precision. W component is destroyed
// Note that this does not consider zero length vectors!
inline void normalize3fast();
// Return true if this vector is normalized with respect to x,y,z up to tolerance
inline LLBool32 isNormalized3( F32 tolerance = 1e-3 ) const;
// Return true if this vector is normalized with respect to all components up to tolerance
inline LLBool32 isNormalized4( F32 tolerance = 1e-3 ) const;
// Set all elements to the length of vector 'v'
inline void setAllLength3( const LLVector4a& v );
// Get this vector's length
inline LLSimdScalar getLength3() const;
// Set the components of this vector to the minimum of the corresponding components of lhs and rhs
inline void setMin(const LLVector4a& lhs, const LLVector4a& rhs);
// Set the components of this vector to the maximum of the corresponding components of lhs and rhs
inline void setMax(const LLVector4a& lhs, const LLVector4a& rhs);
// Clamps this vector to be within the component-wise range low to high (inclusive)
inline void clamp( const LLVector4a& low, const LLVector4a& high );
// Set this to (c * lhs) + rhs * ( 1 - c)
inline void setLerp(const LLVector4a& lhs, const LLVector4a& rhs, F32 c);
// Return true (nonzero) if x, y, z (and w for Finite4) are all finite floats
inline LLBool32 isFinite3() const;
inline LLBool32 isFinite4() const;
// Set this vector to 'vec' rotated by the LLRotation or LLQuaternion2 provided
void setRotated( const LLRotation& rot, const LLVector4a& vec );
void setRotated( const class LLQuaternion2& quat, const LLVector4a& vec );
// Set this vector to 'vec' rotated by the INVERSE of the LLRotation or LLQuaternion2 provided
inline void setRotatedInv( const LLRotation& rot, const LLVector4a& vec );
inline void setRotatedInv( const class LLQuaternion2& quat, const LLVector4a& vec );
// Quantize this vector to 8 or 16 bit precision
void quantize8( const LLVector4a& low, const LLVector4a& high );
void quantize16( const LLVector4a& low, const LLVector4a& high );
////////////////////////////////////
// LOGICAL
////////////////////////////////////
// The functions in this section will compare the elements in this vector
// to those in rhs and return an LLVector4Logical with all bits set in elements
// where the comparison was true and all bits unset in elements where the comparison
// was false. See llvector4logica.h
////////////////////////////////////
// WARNING: Other than equals3 and equals4, these functions do NOT account
// for floating point tolerance. You should include the appropriate tolerance
// in the inputs.
////////////////////////////////////
inline LLVector4Logical greaterThan(const LLVector4a& rhs) const;
inline LLVector4Logical lessThan(const LLVector4a& rhs) const;
inline LLVector4Logical greaterEqual(const LLVector4a& rhs) const;
inline LLVector4Logical lessEqual(const LLVector4a& rhs) const;
inline LLVector4Logical equal(const LLVector4a& rhs) const;
// Returns true if this and rhs are componentwise equal up to the specified absolute tolerance
inline bool equals4(const LLVector4a& rhs, F32 tolerance = F_APPROXIMATELY_ZERO ) const;
inline bool equals3(const LLVector4a& rhs, F32 tolerance = F_APPROXIMATELY_ZERO ) const;
////////////////////////////////////
// OPERATORS
////////////////////////////////////
// Do NOT add aditional operators without consulting someone with SSE experience
inline const LLVector4a& operator= ( const LLVector4a& rhs );
inline const LLVector4a& operator= ( const LLQuad& rhs );
inline operator LLQuad() const;
private:
LLQuad mQ;
};
inline void update_min_max(LLVector4a& min, LLVector4a& max, const LLVector4a& p)
{
min.setMin(min, p);
max.setMax(max, p);
}
#endif

593
indra/llmath/llvector4a.inl Normal file
View File

@@ -0,0 +1,593 @@
/**
* @file llvector4a.inl
* @brief LLVector4a inline function implementations
*
* $LicenseInfo:firstyear=2010&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
////////////////////////////////////
// LOAD/STORE
////////////////////////////////////
// Load from 16-byte aligned src array (preferred method of loading)
inline void LLVector4a::load4a(const F32* src)
{
mQ = _mm_load_ps(src);
}
// Load from unaligned src array (NB: Significantly slower than load4a)
inline void LLVector4a::loadua(const F32* src)
{
mQ = _mm_loadu_ps(src);
}
// Load only three floats beginning at address 'src'. Slowest method.
inline void LLVector4a::load3(const F32* src)
{
// mQ = { 0.f, src[2], src[1], src[0] } = { W, Z, Y, X }
// NB: This differs from the convention of { Z, Y, X, W }
mQ = _mm_set_ps(0.f, src[2], src[1], src[0]);
}
// Store to a 16-byte aligned memory address
inline void LLVector4a::store4a(F32* dst) const
{
_mm_store_ps(dst, mQ);
}
////////////////////////////////////
// BASIC GET/SET
////////////////////////////////////
// Return a "this" as an F32 pointer. Do not use unless you have a very good reason. (Not sure? Ask Falcon)
F32* LLVector4a::getF32ptr()
{
return (F32*) &mQ;
}
// Return a "this" as a const F32 pointer. Do not use unless you have a very good reason. (Not sure? Ask Falcon)
const F32* const LLVector4a::getF32ptr() const
{
return (const F32* const) &mQ;
}
// Read-only access a single float in this vector. Do not use in proximity to any function call that manipulates
// the data at the whole vector level or you will incur a substantial penalty. Consider using the splat functions instead
inline F32 LLVector4a::operator[](const S32 idx) const
{
return ((F32*)&mQ)[idx];
}
// Prefer this method for read-only access to a single element. Prefer the templated version if the elem is known at compile time.
inline LLSimdScalar LLVector4a::getScalarAt(const S32 idx) const
{
// Return appropriate LLQuad. It will be cast to LLSimdScalar automatically (should be effectively a nop)
switch (idx)
{
case 0:
return mQ;
case 1:
return _mm_shuffle_ps(mQ, mQ, _MM_SHUFFLE(1, 1, 1, 1));
case 2:
return _mm_shuffle_ps(mQ, mQ, _MM_SHUFFLE(2, 2, 2, 2));
case 3:
default:
return _mm_shuffle_ps(mQ, mQ, _MM_SHUFFLE(3, 3, 3, 3));
}
}
// Prefer this method for read-only access to a single element. Prefer the templated version if the elem is known at compile time.
template <int N> LL_FORCE_INLINE LLSimdScalar LLVector4a::getScalarAt() const
{
return _mm_shuffle_ps(mQ, mQ, _MM_SHUFFLE(N, N, N, N));
}
template<> LL_FORCE_INLINE LLSimdScalar LLVector4a::getScalarAt<0>() const
{
return mQ;
}
// Set to an x, y, z and optional w provided
inline void LLVector4a::set(F32 x, F32 y, F32 z, F32 w)
{
mQ = _mm_set_ps(w, z, y, x);
}
// Set to all zeros
inline void LLVector4a::clear()
{
mQ = LLVector4a::getZero().mQ;
}
inline void LLVector4a::splat(const F32 x)
{
mQ = _mm_set1_ps(x);
}
inline void LLVector4a::splat(const LLSimdScalar& x)
{
mQ = _mm_shuffle_ps( x.getQuad(), x.getQuad(), _MM_SHUFFLE(0,0,0,0) );
}
// Set all 4 elements to element N of src, with N known at compile time
template <int N> void LLVector4a::splat(const LLVector4a& src)
{
mQ = _mm_shuffle_ps(src.mQ, src.mQ, _MM_SHUFFLE(N, N, N, N) );
}
// Set all 4 elements to element i of v, with i NOT known at compile time
inline void LLVector4a::splat(const LLVector4a& v, U32 i)
{
switch (i)
{
case 0:
mQ = _mm_shuffle_ps(v.mQ, v.mQ, _MM_SHUFFLE(0, 0, 0, 0));
break;
case 1:
mQ = _mm_shuffle_ps(v.mQ, v.mQ, _MM_SHUFFLE(1, 1, 1, 1));
break;
case 2:
mQ = _mm_shuffle_ps(v.mQ, v.mQ, _MM_SHUFFLE(2, 2, 2, 2));
break;
case 3:
mQ = _mm_shuffle_ps(v.mQ, v.mQ, _MM_SHUFFLE(3, 3, 3, 3));
break;
}
}
// Select bits from sourceIfTrue and sourceIfFalse according to bits in mask
inline void LLVector4a::setSelectWithMask( const LLVector4Logical& mask, const LLVector4a& sourceIfTrue, const LLVector4a& sourceIfFalse )
{
// ((( sourceIfTrue ^ sourceIfFalse ) & mask) ^ sourceIfFalse )
// E.g., sourceIfFalse = 1010b, sourceIfTrue = 0101b, mask = 1100b
// (sourceIfTrue ^ sourceIfFalse) = 1111b --> & mask = 1100b --> ^ sourceIfFalse = 0110b,
// as expected (01 from sourceIfTrue, 10 from sourceIfFalse)
// Courtesy of Mark++, http://markplusplus.wordpress.com/2007/03/14/fast-sse-select-operation/
mQ = _mm_xor_ps( sourceIfFalse, _mm_and_ps( mask, _mm_xor_ps( sourceIfTrue, sourceIfFalse ) ) );
}
////////////////////////////////////
// ALGEBRAIC
////////////////////////////////////
// Set this to the element-wise (a + b)
inline void LLVector4a::setAdd(const LLVector4a& a, const LLVector4a& b)
{
mQ = _mm_add_ps(a.mQ, b.mQ);
}
// Set this to element-wise (a - b)
inline void LLVector4a::setSub(const LLVector4a& a, const LLVector4a& b)
{
mQ = _mm_sub_ps(a.mQ, b.mQ);
}
// Set this to element-wise multiply (a * b)
inline void LLVector4a::setMul(const LLVector4a& a, const LLVector4a& b)
{
mQ = _mm_mul_ps(a.mQ, b.mQ);
}
// Set this to element-wise quotient (a / b)
inline void LLVector4a::setDiv(const LLVector4a& a, const LLVector4a& b)
{
mQ = _mm_div_ps( a.mQ, b.mQ );
}
// Set this to the element-wise absolute value of src
inline void LLVector4a::setAbs(const LLVector4a& src)
{
static const LL_ALIGN_16(U32 F_ABS_MASK_4A[4]) = { 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF };
mQ = _mm_and_ps(src.mQ, *reinterpret_cast<const LLQuad*>(F_ABS_MASK_4A));
}
// Add to each component in this vector the corresponding component in rhs
inline void LLVector4a::add(const LLVector4a& rhs)
{
mQ = _mm_add_ps(mQ, rhs.mQ);
}
// Subtract from each component in this vector the corresponding component in rhs
inline void LLVector4a::sub(const LLVector4a& rhs)
{
mQ = _mm_sub_ps(mQ, rhs.mQ);
}
// Multiply each component in this vector by the corresponding component in rhs
inline void LLVector4a::mul(const LLVector4a& rhs)
{
mQ = _mm_mul_ps(mQ, rhs.mQ);
}
// Divide each component in this vector by the corresponding component in rhs
inline void LLVector4a::div(const LLVector4a& rhs)
{
// TODO: Check accuracy, maybe add divFast
mQ = _mm_div_ps(mQ, rhs.mQ);
}
// Multiply this vector by x in a scalar fashion
inline void LLVector4a::mul(const F32 x)
{
LLVector4a t;
t.splat(x);
mQ = _mm_mul_ps(mQ, t.mQ);
}
// Set this to (a x b) (geometric cross-product)
inline void LLVector4a::setCross3(const LLVector4a& a, const LLVector4a& b)
{
// Vectors are stored in memory in w, z, y, x order from high to low
// Set vector1 = { a[W], a[X], a[Z], a[Y] }
const LLQuad vector1 = _mm_shuffle_ps( a.mQ, a.mQ, _MM_SHUFFLE( 3, 0, 2, 1 ));
// Set vector2 = { b[W], b[Y], b[X], b[Z] }
const LLQuad vector2 = _mm_shuffle_ps( b.mQ, b.mQ, _MM_SHUFFLE( 3, 1, 0, 2 ));
// mQ = { a[W]*b[W], a[X]*b[Y], a[Z]*b[X], a[Y]*b[Z] }
mQ = _mm_mul_ps( vector1, vector2 );
// vector3 = { a[W], a[Y], a[X], a[Z] }
const LLQuad vector3 = _mm_shuffle_ps( a.mQ, a.mQ, _MM_SHUFFLE( 3, 1, 0, 2 ));
// vector4 = { b[W], b[X], b[Z], b[Y] }
const LLQuad vector4 = _mm_shuffle_ps( b.mQ, b.mQ, _MM_SHUFFLE( 3, 0, 2, 1 ));
// mQ = { 0, a[X]*b[Y] - a[Y]*b[X], a[Z]*b[X] - a[X]*b[Z], a[Y]*b[Z] - a[Z]*b[Y] }
mQ = _mm_sub_ps( mQ, _mm_mul_ps( vector3, vector4 ));
}
/* This function works, but may be slightly slower than the one below on older machines
inline void LLVector4a::setAllDot3(const LLVector4a& a, const LLVector4a& b)
{
// ab = { a[W]*b[W], a[Z]*b[Z], a[Y]*b[Y], a[X]*b[X] }
const LLQuad ab = _mm_mul_ps( a.mQ, b.mQ );
// yzxw = { a[W]*b[W], a[Z]*b[Z], a[X]*b[X], a[Y]*b[Y] }
const LLQuad wzxy = _mm_shuffle_ps( ab, ab, _MM_SHUFFLE(3, 2, 0, 1 ));
// xPlusY = { 2*a[W]*b[W], 2 * a[Z] * b[Z], a[Y]*b[Y] + a[X] * b[X], a[X] * b[X] + a[Y] * b[Y] }
const LLQuad xPlusY = _mm_add_ps(ab, wzxy);
// xPlusYSplat = { a[Y]*b[Y] + a[X] * b[X], a[X] * b[X] + a[Y] * b[Y], a[Y]*b[Y] + a[X] * b[X], a[X] * b[X] + a[Y] * b[Y] }
const LLQuad xPlusYSplat = _mm_movelh_ps(xPlusY, xPlusY);
// zSplat = { a[Z]*b[Z], a[Z]*b[Z], a[Z]*b[Z], a[Z]*b[Z] }
const LLQuad zSplat = _mm_shuffle_ps( ab, ab, _MM_SHUFFLE( 2, 2, 2, 2 ));
// mQ = { a[Z] * b[Z] + a[Y] * b[Y] + a[X] * b[X], same, same, same }
mQ = _mm_add_ps(zSplat, xPlusYSplat);
}*/
// Set all elements to the dot product of the x, y, and z elements in a and b
inline void LLVector4a::setAllDot3(const LLVector4a& a, const LLVector4a& b)
{
// ab = { a[W]*b[W], a[Z]*b[Z], a[Y]*b[Y], a[X]*b[X] }
const LLQuad ab = _mm_mul_ps( a.mQ, b.mQ );
// yzxw = { a[W]*b[W], a[Z]*b[Z], a[X]*b[X], a[Y]*b[Y] }
const __m128i wzxy = _mm_shuffle_epi32(_mm_castps_si128(ab), _MM_SHUFFLE(3, 2, 0, 1 ));
// xPlusY = { 2*a[W]*b[W], 2 * a[Z] * b[Z], a[Y]*b[Y] + a[X] * b[X], a[X] * b[X] + a[Y] * b[Y] }
const LLQuad xPlusY = _mm_add_ps(ab, _mm_castsi128_ps(wzxy));
// xPlusYSplat = { a[Y]*b[Y] + a[X] * b[X], a[X] * b[X] + a[Y] * b[Y], a[Y]*b[Y] + a[X] * b[X], a[X] * b[X] + a[Y] * b[Y] }
const LLQuad xPlusYSplat = _mm_movelh_ps(xPlusY, xPlusY);
// zSplat = { a[Z]*b[Z], a[Z]*b[Z], a[Z]*b[Z], a[Z]*b[Z] }
const __m128i zSplat = _mm_shuffle_epi32(_mm_castps_si128(ab), _MM_SHUFFLE( 2, 2, 2, 2 ));
// mQ = { a[Z] * b[Z] + a[Y] * b[Y] + a[X] * b[X], same, same, same }
mQ = _mm_add_ps(_mm_castsi128_ps(zSplat), xPlusYSplat);
}
// Set all elements to the dot product of the x, y, z, and w elements in a and b
inline void LLVector4a::setAllDot4(const LLVector4a& a, const LLVector4a& b)
{
// ab = { a[W]*b[W], a[Z]*b[Z], a[Y]*b[Y], a[X]*b[X] }
const LLQuad ab = _mm_mul_ps( a.mQ, b.mQ );
// yzxw = { a[W]*b[W], a[Z]*b[Z], a[X]*b[X], a[Y]*b[Y] }
const __m128i zwxy = _mm_shuffle_epi32(_mm_castps_si128(ab), _MM_SHUFFLE(2, 3, 0, 1 ));
// zPlusWandXplusY = { a[W]*b[W] + a[Z]*b[Z], a[Z] * b[Z] + a[W]*b[W], a[Y]*b[Y] + a[X] * b[X], a[X] * b[X] + a[Y] * b[Y] }
const LLQuad zPlusWandXplusY = _mm_add_ps(ab, _mm_castsi128_ps(zwxy));
// xPlusYSplat = { a[Y]*b[Y] + a[X] * b[X], a[X] * b[X] + a[Y] * b[Y], a[Y]*b[Y] + a[X] * b[X], a[X] * b[X] + a[Y] * b[Y] }
const LLQuad xPlusYSplat = _mm_movelh_ps(zPlusWandXplusY, zPlusWandXplusY);
const LLQuad zPlusWSplat = _mm_movehl_ps(zPlusWandXplusY, zPlusWandXplusY);
// mQ = { a[W]*b[W] + a[Z] * b[Z] + a[Y] * b[Y] + a[X] * b[X], same, same, same }
mQ = _mm_add_ps(xPlusYSplat, zPlusWSplat);
}
// Return the 3D dot product of this vector and b
inline LLSimdScalar LLVector4a::dot3(const LLVector4a& b) const
{
const LLQuad ab = _mm_mul_ps( mQ, b.mQ );
const LLQuad splatY = _mm_castsi128_ps( _mm_shuffle_epi32( _mm_castps_si128(ab), _MM_SHUFFLE(1, 1, 1, 1) ) );
const LLQuad splatZ = _mm_castsi128_ps( _mm_shuffle_epi32( _mm_castps_si128(ab), _MM_SHUFFLE(2, 2, 2, 2) ) );
const LLQuad xPlusY = _mm_add_ps( ab, splatY );
return _mm_add_ps( xPlusY, splatZ );
}
// Return the 4D dot product of this vector and b
inline LLSimdScalar LLVector4a::dot4(const LLVector4a& b) const
{
// ab = { w, z, y, x }
const LLQuad ab = _mm_mul_ps( mQ, b.mQ );
// upperProdsInLowerElems = { y, x, y, x }
const LLQuad upperProdsInLowerElems = _mm_movehl_ps( ab, ab );
// sumOfPairs = { w+y, z+x, 2y, 2x }
const LLQuad sumOfPairs = _mm_add_ps( upperProdsInLowerElems, ab );
// shuffled = { z+x, z+x, z+x, z+x }
const LLQuad shuffled = _mm_castsi128_ps( _mm_shuffle_epi32( _mm_castps_si128( sumOfPairs ), _MM_SHUFFLE(1, 1, 1, 1) ) );
return _mm_add_ss( sumOfPairs, shuffled );
}
// Normalize this vector with respect to the x, y, and z components only. Accurate to 22 bites of precision. W component is destroyed
// Note that this does not consider zero length vectors!
inline void LLVector4a::normalize3()
{
// lenSqrd = a dot a
LLVector4a lenSqrd; lenSqrd.setAllDot3( *this, *this );
// rsqrt = approximate reciprocal square (i.e., { ~1/len(a)^2, ~1/len(a)^2, ~1/len(a)^2, ~1/len(a)^2 }
const LLQuad rsqrt = _mm_rsqrt_ps(lenSqrd.mQ);
static const LLQuad half = { 0.5f, 0.5f, 0.5f, 0.5f };
static const LLQuad three = {3.f, 3.f, 3.f, 3.f };
// Now we do one round of Newton-Raphson approximation to get full accuracy
// According to the Newton-Raphson method, given a first 'w' for the root of f(x) = 1/x^2 - a (i.e., x = 1/sqrt(a))
// the next better approximation w[i+1] = w - f(w)/f'(w) = w - (1/w^2 - a)/(-2*w^(-3))
// w[i+1] = w + 0.5 * (1/w^2 - a) * w^3 = w + 0.5 * (w - a*w^3) = 1.5 * w - 0.5 * a * w^3
// = 0.5 * w * (3 - a*w^2)
// Our first approx is w = rsqrt. We need out = a * w[i+1] (this is the input vector 'a', not the 'a' from the above formula
// which is actually lenSqrd). So out = a * [0.5*rsqrt * (3 - lenSqrd*rsqrt*rsqrt)]
const LLQuad AtimesRsqrt = _mm_mul_ps( lenSqrd.mQ, rsqrt );
const LLQuad AtimesRsqrtTimesRsqrt = _mm_mul_ps( AtimesRsqrt, rsqrt );
const LLQuad threeMinusAtimesRsqrtTimesRsqrt = _mm_sub_ps(three, AtimesRsqrtTimesRsqrt );
const LLQuad nrApprox = _mm_mul_ps(half, _mm_mul_ps(rsqrt, threeMinusAtimesRsqrtTimesRsqrt));
mQ = _mm_mul_ps( mQ, nrApprox );
}
// Normalize this vector with respect to all components. Accurate to 22 bites of precision.
// Note that this does not consider zero length vectors!
inline void LLVector4a::normalize4()
{
// lenSqrd = a dot a
LLVector4a lenSqrd; lenSqrd.setAllDot4( *this, *this );
// rsqrt = approximate reciprocal square (i.e., { ~1/len(a)^2, ~1/len(a)^2, ~1/len(a)^2, ~1/len(a)^2 }
const LLQuad rsqrt = _mm_rsqrt_ps(lenSqrd.mQ);
static const LLQuad half = { 0.5f, 0.5f, 0.5f, 0.5f };
static const LLQuad three = {3.f, 3.f, 3.f, 3.f };
// Now we do one round of Newton-Raphson approximation to get full accuracy
// According to the Newton-Raphson method, given a first 'w' for the root of f(x) = 1/x^2 - a (i.e., x = 1/sqrt(a))
// the next better approximation w[i+1] = w - f(w)/f'(w) = w - (1/w^2 - a)/(-2*w^(-3))
// w[i+1] = w + 0.5 * (1/w^2 - a) * w^3 = w + 0.5 * (w - a*w^3) = 1.5 * w - 0.5 * a * w^3
// = 0.5 * w * (3 - a*w^2)
// Our first approx is w = rsqrt. We need out = a * w[i+1] (this is the input vector 'a', not the 'a' from the above formula
// which is actually lenSqrd). So out = a * [0.5*rsqrt * (3 - lenSqrd*rsqrt*rsqrt)]
const LLQuad AtimesRsqrt = _mm_mul_ps( lenSqrd.mQ, rsqrt );
const LLQuad AtimesRsqrtTimesRsqrt = _mm_mul_ps( AtimesRsqrt, rsqrt );
const LLQuad threeMinusAtimesRsqrtTimesRsqrt = _mm_sub_ps(three, AtimesRsqrtTimesRsqrt );
const LLQuad nrApprox = _mm_mul_ps(half, _mm_mul_ps(rsqrt, threeMinusAtimesRsqrtTimesRsqrt));
mQ = _mm_mul_ps( mQ, nrApprox );
}
// Normalize this vector with respect to the x, y, and z components only. Accurate to 22 bites of precision. W component is destroyed
// Note that this does not consider zero length vectors!
inline LLSimdScalar LLVector4a::normalize3withLength()
{
// lenSqrd = a dot a
LLVector4a lenSqrd; lenSqrd.setAllDot3( *this, *this );
// rsqrt = approximate reciprocal square (i.e., { ~1/len(a)^2, ~1/len(a)^2, ~1/len(a)^2, ~1/len(a)^2 }
const LLQuad rsqrt = _mm_rsqrt_ps(lenSqrd.mQ);
static const LLQuad half = { 0.5f, 0.5f, 0.5f, 0.5f };
static const LLQuad three = {3.f, 3.f, 3.f, 3.f };
// Now we do one round of Newton-Raphson approximation to get full accuracy
// According to the Newton-Raphson method, given a first 'w' for the root of f(x) = 1/x^2 - a (i.e., x = 1/sqrt(a))
// the next better approximation w[i+1] = w - f(w)/f'(w) = w - (1/w^2 - a)/(-2*w^(-3))
// w[i+1] = w + 0.5 * (1/w^2 - a) * w^3 = w + 0.5 * (w - a*w^3) = 1.5 * w - 0.5 * a * w^3
// = 0.5 * w * (3 - a*w^2)
// Our first approx is w = rsqrt. We need out = a * w[i+1] (this is the input vector 'a', not the 'a' from the above formula
// which is actually lenSqrd). So out = a * [0.5*rsqrt * (3 - lenSqrd*rsqrt*rsqrt)]
const LLQuad AtimesRsqrt = _mm_mul_ps( lenSqrd.mQ, rsqrt );
const LLQuad AtimesRsqrtTimesRsqrt = _mm_mul_ps( AtimesRsqrt, rsqrt );
const LLQuad threeMinusAtimesRsqrtTimesRsqrt = _mm_sub_ps(three, AtimesRsqrtTimesRsqrt );
const LLQuad nrApprox = _mm_mul_ps(half, _mm_mul_ps(rsqrt, threeMinusAtimesRsqrtTimesRsqrt));
mQ = _mm_mul_ps( mQ, nrApprox );
return _mm_sqrt_ss(lenSqrd);
}
// Normalize this vector with respect to the x, y, and z components only. Accurate only to 10-12 bits of precision. W component is destroyed
// Note that this does not consider zero length vectors!
inline void LLVector4a::normalize3fast()
{
LLVector4a lenSqrd; lenSqrd.setAllDot3( *this, *this );
const LLQuad approxRsqrt = _mm_rsqrt_ps(lenSqrd.mQ);
mQ = _mm_mul_ps( mQ, approxRsqrt );
}
// Return true if this vector is normalized with respect to x,y,z up to tolerance
inline LLBool32 LLVector4a::isNormalized3( F32 tolerance ) const
{
static LL_ALIGN_16(const U32 ones[4]) = { 0x3f800000, 0x3f800000, 0x3f800000, 0x3f800000 };
LLSimdScalar tol = _mm_load_ss( &tolerance );
tol = _mm_mul_ss( tol, tol );
LLVector4a lenSquared; lenSquared.setAllDot3( *this, *this );
lenSquared.sub( *reinterpret_cast<const LLVector4a*>(ones) );
lenSquared.setAbs(lenSquared);
return _mm_comile_ss( lenSquared, tol );
}
// Return true if this vector is normalized with respect to all components up to tolerance
inline LLBool32 LLVector4a::isNormalized4( F32 tolerance ) const
{
static LL_ALIGN_16(const U32 ones[4]) = { 0x3f800000, 0x3f800000, 0x3f800000, 0x3f800000 };
LLSimdScalar tol = _mm_load_ss( &tolerance );
tol = _mm_mul_ss( tol, tol );
LLVector4a lenSquared; lenSquared.setAllDot4( *this, *this );
lenSquared.sub( *reinterpret_cast<const LLVector4a*>(ones) );
lenSquared.setAbs(lenSquared);
return _mm_comile_ss( lenSquared, tol );
}
// Set all elements to the length of vector 'v'
inline void LLVector4a::setAllLength3( const LLVector4a& v )
{
LLVector4a lenSqrd;
lenSqrd.setAllDot3(v, v);
mQ = _mm_sqrt_ps(lenSqrd.mQ);
}
// Get this vector's length
inline LLSimdScalar LLVector4a::getLength3() const
{
return _mm_sqrt_ss( dot3( (const LLVector4a)mQ ) );
}
// Set the components of this vector to the minimum of the corresponding components of lhs and rhs
inline void LLVector4a::setMin(const LLVector4a& lhs, const LLVector4a& rhs)
{
mQ = _mm_min_ps(lhs.mQ, rhs.mQ);
}
// Set the components of this vector to the maximum of the corresponding components of lhs and rhs
inline void LLVector4a::setMax(const LLVector4a& lhs, const LLVector4a& rhs)
{
mQ = _mm_max_ps(lhs.mQ, rhs.mQ);
}
// Set this to (c * lhs) + rhs * ( 1 - c)
inline void LLVector4a::setLerp(const LLVector4a& lhs, const LLVector4a& rhs, F32 c)
{
LLVector4a a = lhs;
a.mul(c);
LLVector4a b = rhs;
b.mul(1.f-c);
setAdd(a, b);
}
inline LLBool32 LLVector4a::isFinite3() const
{
static LL_ALIGN_16(const U32 nanOrInfMask[4]) = { 0x7f800000, 0x7f800000, 0x7f800000, 0x7f800000 };
const __m128i nanOrInfMaskV = *reinterpret_cast<const __m128i*> (nanOrInfMask);
const __m128i maskResult = _mm_and_si128( _mm_castps_si128(mQ), nanOrInfMaskV );
const LLVector4Logical equalityCheck = _mm_castsi128_ps(_mm_cmpeq_epi32( maskResult, nanOrInfMaskV ));
return !equalityCheck.areAnySet( LLVector4Logical::MASK_XYZ );
}
inline LLBool32 LLVector4a::isFinite4() const
{
static LL_ALIGN_16(const U32 nanOrInfMask[4]) = { 0x7f800000, 0x7f800000, 0x7f800000, 0x7f800000 };
const __m128i nanOrInfMaskV = *reinterpret_cast<const __m128i*> (nanOrInfMask);
const __m128i maskResult = _mm_and_si128( _mm_castps_si128(mQ), nanOrInfMaskV );
const LLVector4Logical equalityCheck = _mm_castsi128_ps(_mm_cmpeq_epi32( maskResult, nanOrInfMaskV ));
return !equalityCheck.areAnySet( LLVector4Logical::MASK_XYZW );
}
inline void LLVector4a::setRotatedInv( const LLRotation& rot, const LLVector4a& vec )
{
LLRotation inv; inv.setTranspose( rot );
setRotated( inv, vec );
}
inline void LLVector4a::setRotatedInv( const LLQuaternion2& quat, const LLVector4a& vec )
{
LLQuaternion2 invRot; invRot.setConjugate( quat );
setRotated(invRot, vec);
}
inline void LLVector4a::clamp( const LLVector4a& low, const LLVector4a& high )
{
const LLVector4Logical highMask = greaterThan( high );
const LLVector4Logical lowMask = lessThan( low );
setSelectWithMask( highMask, high, *this );
setSelectWithMask( lowMask, low, *this );
}
////////////////////////////////////
// LOGICAL
////////////////////////////////////
// The functions in this section will compare the elements in this vector
// to those in rhs and return an LLVector4Logical with all bits set in elements
// where the comparison was true and all bits unset in elements where the comparison
// was false. See llvector4logica.h
////////////////////////////////////
// WARNING: Other than equals3 and equals4, these functions do NOT account
// for floating point tolerance. You should include the appropriate tolerance
// in the inputs.
////////////////////////////////////
inline LLVector4Logical LLVector4a::greaterThan(const LLVector4a& rhs) const
{
return _mm_cmpgt_ps(mQ, rhs.mQ);
}
inline LLVector4Logical LLVector4a::lessThan(const LLVector4a& rhs) const
{
return _mm_cmplt_ps(mQ, rhs.mQ);
}
inline LLVector4Logical LLVector4a::greaterEqual(const LLVector4a& rhs) const
{
return _mm_cmpge_ps(mQ, rhs.mQ);
}
inline LLVector4Logical LLVector4a::lessEqual(const LLVector4a& rhs) const
{
return _mm_cmple_ps(mQ, rhs.mQ);
}
inline LLVector4Logical LLVector4a::equal(const LLVector4a& rhs) const
{
return _mm_cmpeq_ps(mQ, rhs.mQ);
}
// Returns true if this and rhs are componentwise equal up to the specified absolute tolerance
inline bool LLVector4a::equals4(const LLVector4a& rhs, F32 tolerance ) const
{
LLVector4a diff; diff.setSub( *this, rhs );
diff.setAbs( diff );
const LLQuad tol = _mm_set1_ps( tolerance );
const LLQuad cmp = _mm_cmplt_ps( diff, tol );
return (_mm_movemask_ps( cmp ) & LLVector4Logical::MASK_XYZW) == LLVector4Logical::MASK_XYZW;
}
inline bool LLVector4a::equals3(const LLVector4a& rhs, F32 tolerance ) const
{
LLVector4a diff; diff.setSub( *this, rhs );
diff.setAbs( diff );
const LLQuad tol = _mm_set1_ps( tolerance );
const LLQuad t = _mm_cmplt_ps( diff, tol );
return (_mm_movemask_ps( t ) & LLVector4Logical::MASK_XYZ) == LLVector4Logical::MASK_XYZ;
}
////////////////////////////////////
// OPERATORS
////////////////////////////////////
// Do NOT add aditional operators without consulting someone with SSE experience
inline const LLVector4a& LLVector4a::operator= ( const LLVector4a& rhs )
{
mQ = rhs.mQ;
return *this;
}
inline const LLVector4a& LLVector4a::operator= ( const LLQuad& rhs )
{
mQ = rhs;
return *this;
}
inline LLVector4a::operator LLQuad() const
{
return mQ;
}

View File

@@ -0,0 +1,124 @@
/**
* @file llvector4logical.h
* @brief LLVector4Logical class header file - Companion class to LLVector4a for logical and bit-twiddling operations
*
* $LicenseInfo:firstyear=2010&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LL_VECTOR4LOGICAL_H
#define LL_VECTOR4LOGICAL_H
////////////////////////////
// LLVector4Logical
////////////////////////////
// This class is incomplete. If you need additional functionality,
// for example setting/unsetting particular elements or performing
// other boolean operations, feel free to implement. If you need
// assistance in determining the most optimal implementation,
// contact someone with SSE experience (Falcon, Richard, Davep, e.g.)
////////////////////////////
static LL_ALIGN_16(const U32 S_V4LOGICAL_MASK_TABLE[4*4]) =
{
0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0xFFFFFFFF, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0xFFFFFFFF, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF
};
class LLVector4Logical
{
public:
enum {
MASK_X = 1,
MASK_Y = 1 << 1,
MASK_Z = 1 << 2,
MASK_W = 1 << 3,
MASK_XYZ = MASK_X | MASK_Y | MASK_Z,
MASK_XYZW = MASK_XYZ | MASK_W
};
// Empty default ctor
LLVector4Logical() {}
LLVector4Logical( const LLQuad& quad )
{
mQ = quad;
}
// Create and return a mask consisting of the lowest order bit of each element
inline U32 getGatheredBits() const
{
return _mm_movemask_ps(mQ);
};
// Invert this mask
inline LLVector4Logical& invert()
{
static const LL_ALIGN_16(U32 allOnes[4]) = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
mQ = _mm_andnot_ps( mQ, *(LLQuad*)(allOnes) );
return *this;
}
inline LLBool32 areAllSet( U32 mask ) const
{
return ( getGatheredBits() & mask) == mask;
}
inline LLBool32 areAllSet() const
{
return areAllSet( MASK_XYZW );
}
inline LLBool32 areAnySet( U32 mask ) const
{
return getGatheredBits() & mask;
}
inline LLBool32 areAnySet() const
{
return areAnySet( MASK_XYZW );
}
inline operator LLQuad() const
{
return mQ;
}
inline void clear()
{
mQ = _mm_setzero_ps();
}
template<int N> void setElement()
{
mQ = _mm_or_ps( mQ, *reinterpret_cast<const LLQuad*>(S_V4LOGICAL_MASK_TABLE + 4*N) );
}
private:
LLQuad mQ;
};
#endif //LL_VECTOR4ALOGICAL_H

View File

@@ -30,6 +30,7 @@
*/
#include "linden_common.h"
#include "llmemory.h"
#include "llmath.h"
#include <set>
@@ -43,9 +44,15 @@
#include "v4math.h"
#include "m4math.h"
#include "m3math.h"
#include "llmatrix3a.h"
#include "lloctree.h"
#include "lldarray.h"
#include "llvolume.h"
#include "llstl.h"
#include "llsdserialize.h"
#include "llvector4a.h"
#include "llmatrix4a.h"
#include "lltimer.h"
#define DEBUG_SILHOUETTE_BINORMALS 0
#define DEBUG_SILHOUETTE_NORMALS 0 // TomY: Use this to display normals using the silhouette
@@ -135,102 +142,231 @@ BOOL LLLineSegmentBoxIntersect(const F32* start, const F32* end, const F32* cent
// and returns the intersection point along dir in intersection_t.
// Moller-Trumbore algorithm
BOOL LLTriangleRayIntersect(const LLVector3& vert0, const LLVector3& vert1, const LLVector3& vert2, const LLVector3& orig, const LLVector3& dir,
F32* intersection_a, F32* intersection_b, F32* intersection_t, BOOL two_sided)
BOOL LLTriangleRayIntersect(const LLVector4a& vert0, const LLVector4a& vert1, const LLVector4a& vert2, const LLVector4a& orig, const LLVector4a& dir,
F32& intersection_a, F32& intersection_b, F32& intersection_t)
{
/* find vectors for two edges sharing vert0 */
LLVector4a edge1;
edge1.setSub(vert1, vert0);
LLVector4a edge2;
edge2.setSub(vert2, vert0);
/* begin calculating determinant - also used to calculate U parameter */
LLVector4a pvec;
pvec.setCross3(dir, edge2);
/* if determinant is near zero, ray lies in plane of triangle */
LLVector4a det;
det.setAllDot3(edge1, pvec);
if (det.greaterEqual(LLVector4a::getEpsilon()).getGatheredBits() & 0x7)
{
/* calculate distance from vert0 to ray origin */
LLVector4a tvec;
tvec.setSub(orig, vert0);
/* calculate U parameter and test bounds */
LLVector4a u;
u.setAllDot3(tvec,pvec);
if ((u.greaterEqual(LLVector4a::getZero()).getGatheredBits() & 0x7) &&
(u.lessEqual(det).getGatheredBits() & 0x7))
{
/* prepare to test V parameter */
LLVector4a qvec;
qvec.setCross3(tvec, edge1);
/* calculate V parameter and test bounds */
LLVector4a v;
v.setAllDot3(dir, qvec);
//if (!(v < 0.f || u + v > det))
LLVector4a sum_uv;
sum_uv.setAdd(u, v);
S32 v_gequal = v.greaterEqual(LLVector4a::getZero()).getGatheredBits() & 0x7;
S32 sum_lequal = sum_uv.lessEqual(det).getGatheredBits() & 0x7;
if (v_gequal && sum_lequal)
{
/* calculate t, scale parameters, ray intersects triangle */
LLVector4a t;
t.setAllDot3(edge2,qvec);
t.div(det);
u.div(det);
v.div(det);
intersection_a = u[0];
intersection_b = v[0];
intersection_t = t[0];
return TRUE;
}
}
}
return FALSE;
}
BOOL LLTriangleRayIntersectTwoSided(const LLVector4a& vert0, const LLVector4a& vert1, const LLVector4a& vert2, const LLVector4a& orig, const LLVector4a& dir,
F32& intersection_a, F32& intersection_b, F32& intersection_t)
{
F32 u, v, t;
/* find vectors for two edges sharing vert0 */
LLVector3 edge1 = vert1 - vert0;
LLVector4a edge1;
edge1.setSub(vert1, vert0);
LLVector3 edge2 = vert2 - vert0;;
LLVector4a edge2;
edge2.setSub(vert2, vert0);
/* begin calculating determinant - also used to calculate U parameter */
LLVector3 pvec = dir % edge2;
LLVector4a pvec;
pvec.setCross3(dir, edge2);
/* if determinant is near zero, ray lies in plane of triangle */
F32 det = edge1 * pvec;
F32 det = edge1.dot3(pvec).getF32();
if (!two_sided)
if (det > -F_APPROXIMATELY_ZERO && det < F_APPROXIMATELY_ZERO)
{
if (det < F_APPROXIMATELY_ZERO)
{
return FALSE;
}
/* calculate distance from vert0 to ray origin */
LLVector3 tvec = orig - vert0;
/* calculate U parameter and test bounds */
u = tvec * pvec;
if (u < 0.f || u > det)
{
return FALSE;
}
/* prepare to test V parameter */
LLVector3 qvec = tvec % edge1;
/* calculate V parameter and test bounds */
v = dir * qvec;
if (v < 0.f || u + v > det)
{
return FALSE;
}
/* calculate t, scale parameters, ray intersects triangle */
t = edge2 * qvec;
F32 inv_det = 1.0 / det;
t *= inv_det;
u *= inv_det;
v *= inv_det;
return FALSE;
}
F32 inv_det = 1.f / det;
/* calculate distance from vert0 to ray origin */
LLVector4a tvec;
tvec.setSub(orig, vert0);
else // two sided
{
if (det > -F_APPROXIMATELY_ZERO && det < F_APPROXIMATELY_ZERO)
{
return FALSE;
}
F32 inv_det = 1.0 / det;
/* calculate distance from vert0 to ray origin */
LLVector3 tvec = orig - vert0;
/* calculate U parameter and test bounds */
u = (tvec * pvec) * inv_det;
if (u < 0.f || u > 1.f)
{
return FALSE;
}
/* prepare to test V parameter */
LLVector3 qvec = tvec - edge1;
/* calculate V parameter and test bounds */
v = (dir * qvec) * inv_det;
if (v < 0.f || u + v > 1.f)
{
return FALSE;
}
/* calculate t, ray intersects triangle */
t = (edge2 * qvec) * inv_det;
/* calculate U parameter and test bounds */
u = (tvec.dot3(pvec).getF32()) * inv_det;
if (u < 0.f || u > 1.f)
{
return FALSE;
}
/* prepare to test V parameter */
tvec.sub(edge1);
/* calculate V parameter and test bounds */
v = (dir.dot3(tvec).getF32()) * inv_det;
if (intersection_a != NULL)
*intersection_a = u;
if (intersection_b != NULL)
*intersection_b = v;
if (intersection_t != NULL)
*intersection_t = t;
if (v < 0.f || u + v > 1.f)
{
return FALSE;
}
/* calculate t, ray intersects triangle */
t = (edge2.dot3(tvec).getF32()) * inv_det;
intersection_a = u;
intersection_b = v;
intersection_t = t;
return TRUE;
}
//helper for non-aligned vectors
BOOL LLTriangleRayIntersect(const LLVector3& vert0, const LLVector3& vert1, const LLVector3& vert2, const LLVector3& orig, const LLVector3& dir,
F32& intersection_a, F32& intersection_b, F32& intersection_t, BOOL two_sided)
{
LLVector4a vert0a, vert1a, vert2a, origa, dira;
vert0a.load3(vert0.mV);
vert1a.load3(vert1.mV);
vert2a.load3(vert2.mV);
origa.load3(orig.mV);
dira.load3(dir.mV);
if (two_sided)
{
return LLTriangleRayIntersectTwoSided(vert0a, vert1a, vert2a, origa, dira,
intersection_a, intersection_b, intersection_t);
}
else
{
return LLTriangleRayIntersect(vert0a, vert1a, vert2a, origa, dira,
intersection_a, intersection_b, intersection_t);
}
}
/*
class LLVolumeOctreeRebound : public LLOctreeTravelerDepthFirst<LLVolumeTriangle>
{
public:
const LLVolumeFace* mFace;
LLVolumeOctreeRebound(const LLVolumeFace* face)
{
mFace = face;
}
virtual void visit(const LLOctreeNode<LLVolumeTriangle>* branch)
{ //this is a depth first traversal, so it's safe to assum all children have complete
//bounding data
LLVolumeOctreeListener* node = (LLVolumeOctreeListener*) branch->getListener(0);
LLVector4a& min = node->mExtents[0];
LLVector4a& max = node->mExtents[1];
if (!branch->getData().empty())
{ //node has data, find AABB that binds data set
const LLVolumeTriangle* tri = *(branch->getData().begin());
//initialize min/max to first available vertex
min = *(tri->mV[0]);
max = *(tri->mV[0]);
for (LLOctreeNode<LLVolumeTriangle>::const_element_iter iter =
branch->getData().begin(); iter != branch->getData().end(); ++iter)
{ //for each triangle in node
//stretch by triangles in node
tri = *iter;
min.setMin(min, *tri->mV[0]);
min.setMin(min, *tri->mV[1]);
min.setMin(min, *tri->mV[2]);
max.setMax(max, *tri->mV[0]);
max.setMax(max, *tri->mV[1]);
max.setMax(max, *tri->mV[2]);
}
}
else if (!branch->getChildren().empty())
{ //no data, but child nodes exist
LLVolumeOctreeListener* child = (LLVolumeOctreeListener*) branch->getChild(0)->getListener(0);
//initialize min/max to extents of first child
min = child->mExtents[0];
max = child->mExtents[1];
}
else
{
llerrs << "Empty leaf" << llendl;
}
for (S32 i = 0; i < branch->getChildCount(); ++i)
{ //stretch by child extents
LLVolumeOctreeListener* child = (LLVolumeOctreeListener*) branch->getChild(i)->getListener(0);
min.setMin(min, child->mExtents[0]);
max.setMax(max, child->mExtents[1]);
}
node->mBounds[0].setAdd(min, max);
node->mBounds[0].mul(0.5f);
node->mBounds[1].setSub(max,min);
node->mBounds[1].mul(0.5f);
}
};*/
//-------------------------------------------------------------------
// statics
@@ -2199,7 +2335,7 @@ void sculpt_calc_mesh_resolution(U16 width, U16 height, U8 type, F32 detail, S32
ratio = (F32) width / (F32) height;
s = (S32)fsqrtf(((F32)vertices / ratio));
s = (S32)(F32) sqrt(((F32)vertices / ratio));
s = llmax(s, 4); // no degenerate sizes, please
t = vertices / s;
@@ -3396,13 +3532,22 @@ S32 LLVolume::getNumTriangleIndices() const
void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
std::vector<LLVector3> &normals,
std::vector<S32> &segments,
const LLVector3& obj_cam_vec,
const LLMatrix4& mat,
const LLMatrix3& norm_mat,
const LLVector3& obj_cam_vec_in,
const LLMatrix4& mat_in,
const LLMatrix3& norm_mat_in,
S32 face_mask)
{
LLMemType m1(LLMemType::MTYPE_VOLUME);
LLMatrix4a mat;
mat.loadu(mat_in);
LLMatrix4a norm_mat;
norm_mat.loadu(norm_mat_in);
LLVector4a obj_cam_vec;
obj_cam_vec.load3(obj_cam_vec_in.mV);
vertices.clear();
normals.clear();
segments.clear();
@@ -3414,10 +3559,12 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
{
const LLVolumeFace& face = *iter;
if (!(face_mask & (0x1 << cur_index++)))
if (!(face_mask & (0x1 << cur_index++)) ||
face.mIndices.empty() || face.mEdge.empty())
{
continue;
}
if (face.mTypeMask & (LLVolumeFace::CAP_MASK)) {
}
@@ -3517,18 +3664,30 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
S32 v2 = face.mIndices[j*3+1];
S32 v3 = face.mIndices[j*3+2];
LLVector3 norm = (face.mVertices[v1].mPosition - face.mVertices[v2].mPosition) %
(face.mVertices[v2].mPosition - face.mVertices[v3].mPosition);
if (norm.magVecSquared() < 0.00000001f)
//ew. Face verts arent aligned yet.
LLVector4a va1,va3;
va1.load3(face.mVertices[v1].mPosition.mV);
va3.load3(face.mVertices[v3].mPosition.mV);
LLVector4a c1,c2;
c2.load3(face.mVertices[v2].mPosition.mV);
c1.setSub(va1,c2);
c2.sub(va3);
LLVector4a norm;
norm.setCross3(c1, c2);
if (norm.dot3(norm) < 0.00000001f)
{
fFacing[j] = AWAY | TOWARDS;
}
else
{
//get view vector
LLVector3 view = (obj_cam_vec-face.mVertices[v1].mPosition);
bool away = view * norm > 0.0f;
LLVector4a view;
view.setSub(obj_cam_vec, va1);
bool away = view.dot3(norm) > 0.0f;
if (away)
{
fFacing[j] = AWAY;
@@ -3574,13 +3733,13 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
S32 v1 = face.mIndices[j*3+k];
S32 v2 = face.mIndices[j*3+((k+1)%3)];
vertices.push_back(face.mVertices[v1].mPosition*mat);
LLVector3 norm1 = face.mVertices[v1].mNormal * norm_mat;
vertices.push_back(face.mVertices[v1].mPosition*mat_in);
LLVector3 norm1 = face.mVertices[v1].mNormal * norm_mat_in;
norm1.normVec();
normals.push_back(norm1);
vertices.push_back(face.mVertices[v2].mPosition*mat);
LLVector3 norm2 = face.mVertices[v2].mNormal * norm_mat;
vertices.push_back(face.mVertices[v2].mPosition*mat_in);
LLVector3 norm2 = face.mVertices[v2].mNormal * norm_mat_in;
norm2.normVec();
normals.push_back(norm2);
@@ -3596,6 +3755,19 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
S32 LLVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& end,
S32 face,
LLVector3* intersection,LLVector2* tex_coord, LLVector3* normal, LLVector3* bi_normal)
{
LLVector4a starta, enda;
starta.load3(start.mV);
enda.load3(end.mV);
return lineSegmentIntersect(starta, enda, face, intersection, tex_coord, normal, bi_normal);
}
S32 LLVolume::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end,
S32 face,
LLVector3* intersection,LLVector2* tex_coord, LLVector3* normal, LLVector3* bi_normal)
{
S32 hit_face = -1;
@@ -3613,7 +3785,8 @@ S32 LLVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& end,
end_face = face;
}
LLVector3 dir = end - start;
LLVector4a dir;
dir.setSub(end, start);
F32 closest_t = 2.f; // must be larger than 1
@@ -3621,8 +3794,12 @@ S32 LLVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& end,
{
const LLVolumeFace &face = getVolumeFace((U32)i);
LLVector3 box_center = (face.mExtents[0] + face.mExtents[1]) / 2.f;
LLVector3 box_size = face.mExtents[1] - face.mExtents[0];
LLVector4a box_center;
box_center.setAdd(face.mExtents[0], face.mExtents[1]);
box_center.mul(0.5f);
LLVector4a box_size;
box_size.setSub(face.mExtents[1], face.mExtents[0]);
if (LLLineSegmentBoxIntersect(start, end, box_center, box_size))
{
@@ -3638,11 +3815,15 @@ S32 LLVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& end,
S32 index3 = face.mIndices[tri*3+2];
F32 a, b, t;
if (LLTriangleRayIntersect(face.mVertices[index1].mPosition,
face.mVertices[index2].mPosition,
face.mVertices[index3].mPosition,
start, dir, &a, &b, &t, FALSE))
LLVector4a pos[3];
pos[0].load3(face.mVertices[index1].mPosition.mV);
pos[1].load3(face.mVertices[index2].mPosition.mV);
pos[2].load3(face.mVertices[index3].mPosition.mV);
if (LLTriangleRayIntersect(pos[0],
pos[1],
pos[2],
start, dir, a, b, t))
{
if ((t >= 0.f) && // if hit is after start
(t <= 1.f) && // and before end
@@ -3653,7 +3834,10 @@ S32 LLVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& end,
if (intersection != NULL)
{
*intersection = start + dir * closest_t;
LLVector4a v;
v.setMul(dir,closest_t);
v.add(start);
intersection->set(v.getF32ptr());
}
if (tex_coord != NULL)
@@ -4421,7 +4605,69 @@ std::ostream& operator<<(std::ostream &s, const LLVolume *volumep)
return s;
}
LLVolumeFace::LLVolumeFace() :
mID(0),
mTypeMask(0),
mHasBinormals(FALSE),
mBeginS(0),
mBeginT(0),
mNumS(0),
mNumT(0)
{
mExtents = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*3);
mExtents[0].splat(-0.5f);
mExtents[1].splat(0.5f);
mCenter = mExtents+2;
}
LLVolumeFace::LLVolumeFace(const LLVolumeFace& src)
: mID(0),
mTypeMask(0),
mHasBinormals(FALSE),
mBeginS(0),
mBeginT(0),
mNumS(0),
mNumT(0)
{
mExtents = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*3);
mCenter = mExtents+2;
*this = src;
}
LLVolumeFace& LLVolumeFace::operator=(const LLVolumeFace& src)
{
if (&src == this)
{ //self assignment, do nothing
return *this;
}
mID = src.mID;
mTypeMask = src.mTypeMask;
mHasBinormals = src.mHasBinormals,
mBeginS = src.mBeginS;
mBeginT = src.mBeginT;
mNumS = src.mNumS;
mNumT = src.mNumT;
mExtents[0] = src.mExtents[0];
mExtents[1] = src.mExtents[1];
*mCenter = *src.mCenter;
LLVector4a::memcpyNonAliased16((F32*) mExtents, (F32*) src.mExtents, 3*sizeof(LLVector4a));
mVertices = src.mVertices;
mIndices = src.mIndices;
mEdge = src.mEdge;
return *this;
}
LLVolumeFace::~LLVolumeFace()
{
ll_aligned_free_16(mExtents);
mExtents = NULL;
}
BOOL LLVolumeFace::create(LLVolume* volume, BOOL partial_build)
{
BOOL ret = FALSE ;
@@ -4504,78 +4750,99 @@ BOOL LLVolumeFace::createUnCutCubeCap(LLVolume* volume, BOOL partial_build)
num_vertices = (grid_size+1)*(grid_size+1);
num_indices = quad_count * 4;
LLVector3& min = mExtents[0];
LLVector3& max = mExtents[1];
LLVector4a& min = mExtents[0];
LLVector4a& max = mExtents[1];
S32 offset = 0;
if (mTypeMask & TOP_MASK)
offset = (max_t-1) * max_s;
else
offset = mBeginS;
VertexData corners[4];
VertexData baseVert;
for(int t = 0; t < 4; t++){
corners[t].mPosition = mesh[offset + (grid_size*t)].mPos;
corners[t].mTexCoord.mV[0] = profile[grid_size*t].mV[0]+0.5f;
corners[t].mTexCoord.mV[1] = 0.5f - profile[grid_size*t].mV[1];
}
baseVert.mNormal =
((corners[1].mPosition-corners[0].mPosition) %
(corners[2].mPosition-corners[1].mPosition));
baseVert.mNormal.normVec();
if(!(mTypeMask & TOP_MASK)){
baseVert.mNormal *= -1.0f;
}else{
//Swap the UVs on the U(X) axis for top face
LLVector2 swap;
swap = corners[0].mTexCoord;
corners[0].mTexCoord=corners[3].mTexCoord;
corners[3].mTexCoord=swap;
swap = corners[1].mTexCoord;
corners[1].mTexCoord=corners[2].mTexCoord;
corners[2].mTexCoord=swap;
}
baseVert.mBinormal = calc_binormal_from_triangle(
corners[0].mPosition, corners[0].mTexCoord,
corners[1].mPosition, corners[1].mTexCoord,
corners[2].mPosition, corners[2].mTexCoord);
for(int t = 0; t < 4; t++){
corners[t].mBinormal = baseVert.mBinormal;
corners[t].mNormal = baseVert.mNormal;
}
mHasBinormals = TRUE;
if (partial_build)
{
mVertices.clear();
offset = (max_t-1) * max_s;
}
else
{
offset = mBeginS;
}
S32 vtop = mVertices.size();
for(int gx = 0;gx<grid_size+1;gx++){
for(int gy = 0;gy<grid_size+1;gy++){
VertexData newVert;
LerpPlanarVertex(
corners[0],
corners[1],
corners[3],
newVert,
(F32)gx/(F32)grid_size,
(F32)gy/(F32)grid_size);
mVertices.push_back(newVert);
S32 vtop;
{
VertexData corners[4];
VertexData baseVert;
for(S32 t = 0; t < 4; t++){
corners[t].mPosition = mesh[offset + (grid_size*t)].mPos;
corners[t].mTexCoord.mV[0] = profile[grid_size*t].mV[0]+0.5f;
corners[t].mTexCoord.mV[1] = 0.5f - profile[grid_size*t].mV[1];
}
if (gx == 0 && gy == 0)
{
baseVert.mNormal =
((corners[1].mPosition-corners[0].mPosition) %
(corners[2].mPosition-corners[1].mPosition));
baseVert.mNormal.normalize();
}
if(!(mTypeMask & TOP_MASK))
{
baseVert.mNormal *= -.1f;
}
else
{
//Swap the UVs on the U(X) axis for top face
LLVector2 swap;
swap = corners[0].mTexCoord;
corners[0].mTexCoord=corners[3].mTexCoord;
corners[3].mTexCoord=swap;
swap = corners[1].mTexCoord;
corners[1].mTexCoord=corners[2].mTexCoord;
corners[2].mTexCoord=swap;
}
baseVert.mBinormal = calc_binormal_from_triangle(
corners[0].mPosition, corners[0].mTexCoord,
corners[1].mPosition, corners[1].mTexCoord,
corners[2].mPosition, corners[2].mTexCoord);
for(int t = 0; t < 4; t++){
corners[t].mBinormal = baseVert.mBinormal;
corners[t].mNormal = baseVert.mNormal;
}
mHasBinormals = TRUE;
if (partial_build)
{
mVertices.clear();
}
vtop = mVertices.size();
for(int gx = 0;gx<grid_size+1;gx++)
{
for(int gy = 0;gy<grid_size+1;gy++)
{
min = max = newVert.mPosition;
}
else
{
update_min_max(min,max,newVert.mPosition);
VertexData newVert;
LerpPlanarVertex(
corners[0],
corners[1],
corners[3],
newVert,
(F32)gx/(F32)grid_size,
(F32)gy/(F32)grid_size);
mVertices.push_back(newVert);
if (gx == 0 && gy == 0)
{
max.load3(newVert.mPosition.mV);
min = max;
}
else
{
LLVector4a pos;
pos.load3(newVert.mPosition.mV);
update_min_max(min,max,pos);
}
}
}
}
mCenter = (min + max) * 0.5f;
mCenter->setAdd(min, max);
mCenter->mul(0.5f);
}
if (!partial_build)
{
@@ -4640,7 +4907,7 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build)
S32 max_s = volume->getProfile().getTotal();
S32 max_t = volume->getPath().mPath.size();
mCenter.clearVec();
mCenter->clear();
S32 offset = 0;
if (mTypeMask & TOP_MASK)
@@ -4658,8 +4925,8 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build)
LLVector2 cuv;
LLVector2 min_uv, max_uv;
LLVector3& min = mExtents[0];
LLVector3& max = mExtents[1];
LLVector4a& min = mExtents[0];
LLVector4a& max = mExtents[1];
// Copy the vertices into the array
for (S32 i = 0; i < num_vertices; i++)
@@ -4680,38 +4947,54 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build)
if (i == 0)
{
min = max = mVertices[i].mPosition;
max.load3(mVertices[i].mPosition.mV);
min = max;
min_uv = max_uv = mVertices[i].mTexCoord;
}
else
{
update_min_max(min,max, mVertices[i].mPosition);
LLVector4a pos;
pos.load3(mVertices[i].mPosition.mV);
update_min_max(min,max, pos);
update_min_max(min_uv, max_uv, mVertices[i].mTexCoord);
}
}
mCenter = (min+max)*0.5f;
mCenter->setAdd(min, max);
mCenter->mul(0.5f);
cuv = (min_uv + max_uv)*0.5f;
LLVector3 binormal = calc_binormal_from_triangle(
mCenter, cuv,
LLVector3 binormal = calc_binormal_from_triangle(
LLVector3(mCenter->getF32ptr()), cuv,
mVertices[0].mPosition, mVertices[0].mTexCoord,
mVertices[1].mPosition, mVertices[1].mTexCoord);
binormal.normVec();
LLVector3 d0;
LLVector3 d1;
LLVector3 normal;
LLVector4a pos[2];
pos[0].load3(mVertices[0].mPosition.mV);
pos[1].load3(mVertices[1].mPosition.mV);
LLVector4a normal;
LLVector4a d0, d1;
d0 = mCenter-mVertices[0].mPosition;
d1 = mCenter-mVertices[1].mPosition;
d0.setSub(*mCenter, pos[0]);
d1.setSub(*mCenter, pos[1]);
normal = (mTypeMask & TOP_MASK) ? (d0%d1) : (d1%d0);
normal.normVec();
if (mTypeMask & TOP_MASK)
{
normal.setCross3(d0, d1);
}
else
{
normal.setCross3(d1, d0);
}
normal.normalize3fast();
VertexData vd;
vd.mPosition = mCenter;
vd.mNormal = normal;
vd.mPosition.set(mCenter->getF32ptr());
vd.mNormal.set(normal.getF32ptr());
vd.mBinormal = binormal;
vd.mTexCoord = cuv;
@@ -4729,7 +5012,7 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build)
for (S32 i = 0; i < num_vertices; i++)
{
mVertices[i].mBinormal = binormal;
mVertices[i].mNormal = normal;
mVertices[i].mNormal.set(normal.getF32ptr());
}
mHasBinormals = TRUE;
@@ -5146,17 +5429,21 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
//get bounding box for this side
LLVector3& face_min = mExtents[0];
LLVector3& face_max = mExtents[1];
mCenter.clearVec();
LLVector4a& face_min = mExtents[0];
LLVector4a& face_max = mExtents[1];
mCenter->clear();
face_min = face_max = mVertices[0].mPosition;
face_max.load3(mVertices[0].mPosition.mV);
face_min = face_max;
for (U32 i = 1; i < mVertices.size(); ++i)
{
update_min_max(face_min, face_max, mVertices[i].mPosition);
LLVector4a pos;
pos.load3(mVertices[i].mPosition.mV);
update_min_max(face_min, face_max, pos);
}
mCenter = (face_min + face_max) * 0.5f;
mCenter->setAdd(face_min, face_max);
mCenter->mul(0.5f);
S32 cur_index = 0;
S32 cur_edge = 0;

View File

@@ -49,6 +49,8 @@ class LLVolume;
//#include "vmath.h"
#include "v2math.h"
#include "v3math.h"
#include "v3dmath.h"
#include "v4math.h"
#include "llquaternion.h"
#include "llstrider.h"
#include "v4coloru.h"
@@ -786,20 +788,6 @@ public:
class LLVolumeFace
{
public:
LLVolumeFace() :
mID(0),
mTypeMask(0),
mHasBinormals(FALSE),
mBeginS(0),
mBeginT(0),
mNumS(0),
mNumT(0)
{
}
BOOL create(LLVolume* volume, BOOL partial_build = FALSE);
void createBinormals();
class VertexData
{
public:
@@ -808,6 +796,14 @@ public:
LLVector3 mBinormal;
LLVector2 mTexCoord;
};
LLVolumeFace();
LLVolumeFace(const LLVolumeFace& src);
LLVolumeFace& operator=(const LLVolumeFace& rhs);
~LLVolumeFace();
BOOL create(LLVolume* volume, BOOL partial_build = FALSE);
void createBinormals();
enum
{
@@ -827,7 +823,6 @@ public:
public:
S32 mID;
U32 mTypeMask;
LLVector3 mCenter;
BOOL mHasBinormals;
// Only used for INNER/OUTER faces
@@ -836,8 +831,9 @@ public:
S32 mNumS;
S32 mNumT;
LLVector3 mExtents[2]; //minimum and maximum point of face
LLVector2 mTexCoordExtents[2]; //minimum and maximum of texture coordinates of the face.
LLVector4a* mExtents; //minimum and maximum point of face
LLVector4a* mCenter;
LLVector2 mTexCoordExtents[2]; //minimum and maximum of texture coordinates of the face.
std::vector<VertexData> mVertices;
std::vector<U16> mIndices;
@@ -898,6 +894,7 @@ public:
BOOL isUnique() const { return mUnique; }
S32 getSculptLevel() const { return mSculptLevel; }
void setSculptLevel(S32 level) { mSculptLevel = level; }
S32 *getTriangleIndices(U32 &num_indices) const;
@@ -922,6 +919,13 @@ public:
LLVector3* normal = NULL, // return the surface normal at the intersection point
LLVector3* bi_normal = NULL // return the surface bi-normal at the intersection point
);
S32 lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end,
S32 face = 1,
LLVector3* intersection = NULL,
LLVector2* tex_coord = NULL,
LLVector3* normal = NULL,
LLVector3* bi_normal = NULL);
// The following cleans up vertices and triangles,
// getting rid of degenerate triangles and duplicate vertices,
@@ -986,8 +990,15 @@ LLVector3 calc_binormal_from_triangle(
BOOL LLLineSegmentBoxIntersect(const F32* start, const F32* end, const F32* center, const F32* size);
BOOL LLLineSegmentBoxIntersect(const LLVector3& start, const LLVector3& end, const LLVector3& center, const LLVector3& size);
BOOL LLLineSegmentBoxIntersect(const LLVector4a& start, const LLVector4a& end, const LLVector4a& center, const LLVector4a& size);
BOOL LLTriangleRayIntersect(const LLVector3& vert0, const LLVector3& vert1, const LLVector3& vert2, const LLVector3& orig, const LLVector3& dir,
F32* intersection_a, F32* intersection_b, F32* intersection_t, BOOL two_sided);
F32& intersection_a, F32& intersection_b, F32& intersection_t, BOOL two_sided);
BOOL LLTriangleRayIntersect(const LLVector4a& vert0, const LLVector4a& vert1, const LLVector4a& vert2, const LLVector4a& orig, const LLVector4a& dir,
F32& intersection_a, F32& intersection_b, F32& intersection_t);
BOOL LLTriangleRayIntersectTwoSided(const LLVector4a& vert0, const LLVector4a& vert1, const LLVector4a& vert2, const LLVector4a& orig, const LLVector4a& dir,
F32& intersection_a, F32& intersection_b, F32& intersection_t);

View File

@@ -320,7 +320,7 @@ BOOL LLVolumeLODGroup::derefLOD(LLVolume *volumep)
{
llassert_always(mLODRefs[i] > 0);
mLODRefs[i]--;
#if 1 // SJB: Possible opt: keep other lods around
#if 0 // SJB: Possible opt: keep other lods around
if (!mLODRefs[i])
{
mVolumeLODs[i] = NULL;
@@ -375,6 +375,19 @@ F32 LLVolumeLODGroup::getVolumeScaleFromDetail(const S32 detail)
return mDetailScales[detail];
}
S32 LLVolumeLODGroup::getVolumeDetailFromScale(const F32 detail)
{
for (S32 i = 1; i < 4; i++)
{
if (mDetailScales[i] > detail)
{
return i-1;
}
}
return 3;
}
F32 LLVolumeLODGroup::dump()
{
F32 usage = 0.f;

View File

@@ -59,6 +59,7 @@ public:
static S32 getDetailFromTan(const F32 tan_angle);
static void getDetailProximity(const F32 tan_angle, F32 &to_lower, F32& to_higher);
static F32 getVolumeScaleFromDetail(const S32 detail);
static S32 getVolumeDetailFromScale(F32 scale);
LLVolume* refLOD(const S32 detail);
BOOL derefLOD(LLVolume *volumep);
@@ -92,8 +93,8 @@ public:
// 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 *refVolume(const LLVolumeParams &volume_params, const S32 detail);
void unrefVolume(LLVolume *volumep);
virtual LLVolume *refVolume(const LLVolumeParams &volume_params, const S32 detail);
virtual void unrefVolume(LLVolume *volumep);
void dump();

View File

@@ -0,0 +1,257 @@
/**
* @file llvolumeoctree.cpp
*
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "llvolumeoctree.h"
#include "llvector4a.h"
BOOL LLLineSegmentBoxIntersect(const LLVector4a& start, const LLVector4a& end, const LLVector4a& center, const LLVector4a& size)
{
LLVector4a fAWdU;
LLVector4a dir;
LLVector4a diff;
dir.setSub(end, start);
dir.mul(0.5f);
diff.setAdd(end,start);
diff.mul(0.5f);
diff.sub(center);
fAWdU.setAbs(dir);
LLVector4a rhs;
rhs.setAdd(size, fAWdU);
LLVector4a lhs;
lhs.setAbs(diff);
U32 grt = lhs.greaterThan(rhs).getGatheredBits();
if (grt & 0x7)
{
return false;
}
LLVector4a f;
f.setCross3(dir, diff);
f.setAbs(f);
LLVector4a v0, v1;
v0 = _mm_shuffle_ps(size, size,_MM_SHUFFLE(3,0,0,1));
v1 = _mm_shuffle_ps(fAWdU, fAWdU, _MM_SHUFFLE(3,1,2,2));
lhs.setMul(v0, v1);
v0 = _mm_shuffle_ps(size, size, _MM_SHUFFLE(3,1,2,2));
v1 = _mm_shuffle_ps(fAWdU, fAWdU, _MM_SHUFFLE(3,0,0,1));
rhs.setMul(v0, v1);
rhs.add(lhs);
grt = f.greaterThan(rhs).getGatheredBits();
return (grt & 0x7) ? false : true;
}
#if 0 //MESH
LLVolumeOctreeListener::LLVolumeOctreeListener(LLOctreeNode<LLVolumeTriangle>* node)
{
node->addListener(this);
}
LLVolumeOctreeListener::~LLVolumeOctreeListener()
{
}
void LLVolumeOctreeListener::handleChildAddition(const LLOctreeNode<LLVolumeTriangle>* parent,
LLOctreeNode<LLVolumeTriangle>* child)
{
new LLVolumeOctreeListener(child);
}
LLOctreeTriangleRayIntersect::LLOctreeTriangleRayIntersect(const LLVector4a& start, const LLVector4a& dir,
const LLVolumeFace* face, F32* closest_t,
LLVector3* intersection,LLVector2* tex_coord, LLVector3* normal, LLVector3* bi_normal)
: mFace(face),
mStart(start),
mDir(dir),
mIntersection(intersection),
mTexCoord(tex_coord),
mNormal(normal),
mBinormal(bi_normal),
mClosestT(closest_t),
mHitFace(false)
{
mEnd.setAdd(mStart, mDir);
}
void LLOctreeTriangleRayIntersect::traverse(const LLOctreeNode<LLVolumeTriangle>* node)
{
LLVolumeOctreeListener* vl = (LLVolumeOctreeListener*) node->getListener(0);
/*const F32* start = mStart.getF32();
const F32* end = mEnd.getF32();
const F32* center = vl->mBounds[0].getF32();
const F32* size = vl->mBounds[1].getF32();*/
//if (LLLineSegmentBoxIntersect(mStart, mEnd, vl->mBounds[0], vl->mBounds[1]))
if (LLLineSegmentBoxIntersect(mStart.getF32ptr(), mEnd.getF32ptr(), vl->mBounds[0].getF32ptr(), vl->mBounds[1].getF32ptr()))
{
node->accept(this);
for (S32 i = 0; i < node->getChildCount(); ++i)
{
traverse(node->getChild(i));
}
}
}
void LLOctreeTriangleRayIntersect::visit(const LLOctreeNode<LLVolumeTriangle>* node)
{
for (LLOctreeNode<LLVolumeTriangle>::const_element_iter iter =
node->getData().begin(); iter != node->getData().end(); ++iter)
{
const LLVolumeTriangle* tri = *iter;
F32 a, b, t;
if (LLTriangleRayIntersect(*tri->mV[0], *tri->mV[1], *tri->mV[2],
mStart, mDir, a, b, t))
{
if ((t >= 0.f) && // if hit is after start
(t <= 1.f) && // and before end
(t < *mClosestT)) // and this hit is closer
{
*mClosestT = t;
mHitFace = true;
if (mIntersection != NULL)
{
LLVector4a intersect = mDir;
intersect.mul(*mClosestT);
intersect.add(mStart);
mIntersection->set(intersect.getF32ptr());
}
if (mTexCoord != NULL)
{
LLVector2* tc = (LLVector2*) mFace->mTexCoords;
*mTexCoord = ((1.f - a - b) * tc[tri->mIndex[0]] +
a * tc[tri->mIndex[1]] +
b * tc[tri->mIndex[2]]);
}
if (mNormal != NULL)
{
LLVector4* norm = (LLVector4*) mFace->mNormals;
*mNormal = ((1.f - a - b) * LLVector3(norm[tri->mIndex[0]]) +
a * LLVector3(norm[tri->mIndex[1]]) +
b * LLVector3(norm[tri->mIndex[2]]));
}
if (mBinormal != NULL)
{
LLVector4* binormal = (LLVector4*) mFace->mBinormals;
*mBinormal = ((1.f - a - b) * LLVector3(binormal[tri->mIndex[0]]) +
a * LLVector3(binormal[tri->mIndex[1]]) +
b * LLVector3(binormal[tri->mIndex[2]]));
}
}
}
}
}
const LLVector4a& LLVolumeTriangle::getPositionGroup() const
{
return mPositionGroup;
}
const F32& LLVolumeTriangle::getBinRadius() const
{
return mRadius;
}
//TEST CODE
void LLVolumeOctreeValidate::visit(const LLOctreeNode<LLVolumeTriangle>* branch)
{
LLVolumeOctreeListener* node = (LLVolumeOctreeListener*) branch->getListener(0);
//make sure bounds matches extents
LLVector4a& min = node->mExtents[0];
LLVector4a& max = node->mExtents[1];
LLVector4a& center = node->mBounds[0];
LLVector4a& size = node->mBounds[1];
LLVector4a test_min, test_max;
test_min.setSub(center, size);
test_max.setAdd(center, size);
if (!test_min.equals3(min, 0.001f) ||
!test_max.equals3(max, 0.001f))
{
llerrs << "Bad bounding box data found." << llendl;
}
test_min.sub(LLVector4a(0.001f));
test_max.add(LLVector4a(0.001f));
for (U32 i = 0; i < branch->getChildCount(); ++i)
{
LLVolumeOctreeListener* child = (LLVolumeOctreeListener*) branch->getChild(i)->getListener(0);
//make sure all children fit inside this node
if (child->mExtents[0].lessThan(test_min).areAnySet(LLVector4Logical::MASK_XYZ) ||
child->mExtents[1].greaterThan(test_max).areAnySet(LLVector4Logical::MASK_XYZ))
{
llerrs << "Child protrudes from bounding box." << llendl;
}
}
//children fit, check data
for (LLOctreeNode<LLVolumeTriangle>::const_element_iter iter = branch->getData().begin();
iter != branch->getData().end(); ++iter)
{
const LLVolumeTriangle* tri = *iter;
//validate triangle
for (U32 i = 0; i < 3; i++)
{
if (tri->mV[i]->greaterThan(test_max).areAnySet(LLVector4Logical::MASK_XYZ) ||
tri->mV[i]->lessThan(test_min).areAnySet(LLVector4Logical::MASK_XYZ))
{
llerrs << "Triangle protrudes from node." << llendl;
}
}
}
}
#endif

View File

@@ -0,0 +1,135 @@
/**
* @file llvolumeoctree.h
* @brief LLVolume octree classes.
*
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LL_LLVOLUME_OCTREE_H
#define LL_LLVOLUME_OCTREE_H
#include "linden_common.h"
#include "llmemory.h"
#include "lloctree.h"
#include "llvolume.h"
#include "llvector4a.h"
#if 0 //MESH
class LLVolumeTriangle : public LLRefCount
{
public:
LLVolumeTriangle()
{
}
LLVolumeTriangle(const LLVolumeTriangle& rhs)
{
*this = rhs;
}
const LLVolumeTriangle& operator=(const LLVolumeTriangle& rhs)
{
llerrs << "Illegal operation!" << llendl;
return *this;
}
~LLVolumeTriangle()
{
}
LLVector4a mPositionGroup;
const LLVector4a* mV[3];
U16 mIndex[3];
F32 mRadius;
virtual const LLVector4a& getPositionGroup() const;
virtual const F32& getBinRadius() const;
};
class LLVolumeOctreeListener : public LLOctreeListener<LLVolumeTriangle>
{
public:
LLVolumeOctreeListener(LLOctreeNode<LLVolumeTriangle>* node);
~LLVolumeOctreeListener();
LLVolumeOctreeListener(const LLVolumeOctreeListener& rhs)
{
*this = rhs;
}
const LLVolumeOctreeListener& operator=(const LLVolumeOctreeListener& rhs)
{
llerrs << "Illegal operation!" << llendl;
return *this;
}
//LISTENER FUNCTIONS
virtual void handleChildAddition(const LLOctreeNode<LLVolumeTriangle>* parent,
LLOctreeNode<LLVolumeTriangle>* child);
virtual void handleStateChange(const LLTreeNode<LLVolumeTriangle>* node) { }
virtual void handleChildRemoval(const LLOctreeNode<LLVolumeTriangle>* parent,
const LLOctreeNode<LLVolumeTriangle>* child) { }
virtual void handleInsertion(const LLTreeNode<LLVolumeTriangle>* node, LLVolumeTriangle* tri) { }
virtual void handleRemoval(const LLTreeNode<LLVolumeTriangle>* node, LLVolumeTriangle* tri) { }
virtual void handleDestruction(const LLTreeNode<LLVolumeTriangle>* node) { }
public:
LLVector4a mBounds[2]; // bounding box (center, size) of this node and all its children (tight fit to objects)
LLVector4a mExtents[2]; // extents (min, max) of this node and all its children
};
class LLOctreeTriangleRayIntersect : public LLOctreeTraveler<LLVolumeTriangle>
{
public:
const LLVolumeFace* mFace;
LLVector4a mStart;
LLVector4a mDir;
LLVector4a mEnd;
LLVector3* mIntersection;
LLVector2* mTexCoord;
LLVector3* mNormal;
LLVector3* mBinormal;
F32* mClosestT;
bool mHitFace;
LLOctreeTriangleRayIntersect(const LLVector4a& start, const LLVector4a& dir,
const LLVolumeFace* face, F32* closest_t,
LLVector3* intersection,LLVector2* tex_coord, LLVector3* normal, LLVector3* bi_normal);
void traverse(const LLOctreeNode<LLVolumeTriangle>* node);
virtual void visit(const LLOctreeNode<LLVolumeTriangle>* node);
};
class LLVolumeOctreeValidate : public LLOctreeTraveler<LLVolumeTriangle>
{
virtual void visit(const LLOctreeNode<LLVolumeTriangle>* branch);
};
#endif //0
#endif

View File

@@ -92,7 +92,7 @@ F32 dist_vec(const LLVector2 &a, const LLVector2 &b)
{
F32 x = a.mV[0] - b.mV[0];
F32 y = a.mV[1] - b.mV[1];
return fsqrtf( x*x + y*y );
return (F32) sqrt( x*x + y*y );
}
F32 dist_vec_squared(const LLVector2 &a, const LLVector2 &b)

View File

@@ -225,7 +225,7 @@ inline void LLVector2::setVec(const F32 *vec)
inline F32 LLVector2::length(void) const
{
return fsqrtf(mV[0]*mV[0] + mV[1]*mV[1]);
return (F32) sqrt(mV[0]*mV[0] + mV[1]*mV[1]);
}
inline F32 LLVector2::lengthSquared(void) const
@@ -235,7 +235,7 @@ inline F32 LLVector2::lengthSquared(void) const
inline F32 LLVector2::normalize(void)
{
F32 mag = fsqrtf(mV[0]*mV[0] + mV[1]*mV[1]);
F32 mag = (F32) sqrt(mV[0]*mV[0] + mV[1]*mV[1]);
F32 oomag;
if (mag > FP_MAG_THRESHOLD)
@@ -262,7 +262,7 @@ inline bool LLVector2::isFinite() const
// deprecated
inline F32 LLVector2::magVec(void) const
{
return fsqrtf(mV[0]*mV[0] + mV[1]*mV[1]);
return (F32) sqrt(mV[0]*mV[0] + mV[1]*mV[1]);
}
// deprecated
@@ -274,7 +274,7 @@ inline F32 LLVector2::magVecSquared(void) const
// deprecated
inline F32 LLVector2::normVec(void)
{
F32 mag = fsqrtf(mV[0]*mV[0] + mV[1]*mV[1]);
F32 mag = (F32) sqrt(mV[0]*mV[0] + mV[1]*mV[1]);
F32 oomag;
if (mag > FP_MAG_THRESHOLD)

View File

@@ -284,7 +284,7 @@ inline F32 LLColor3::brightness(void) const
inline F32 LLColor3::length(void) const
{
return fsqrtf(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]);
return (F32) sqrt(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]);
}
inline F32 LLColor3::lengthSquared(void) const
@@ -294,7 +294,7 @@ inline F32 LLColor3::lengthSquared(void) const
inline F32 LLColor3::normalize(void)
{
F32 mag = fsqrtf(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]);
F32 mag = (F32) sqrt(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]);
F32 oomag;
if (mag)
@@ -310,7 +310,7 @@ inline F32 LLColor3::normalize(void)
// deprecated
inline F32 LLColor3::magVec(void) const
{
return fsqrtf(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]);
return (F32) sqrt(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]);
}
// deprecated
@@ -322,7 +322,7 @@ inline F32 LLColor3::magVecSquared(void) const
// deprecated
inline F32 LLColor3::normVec(void)
{
F32 mag = fsqrtf(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]);
F32 mag = (F32) sqrt(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]);
F32 oomag;
if (mag)
@@ -444,7 +444,7 @@ inline F32 distVec(const LLColor3 &a, const LLColor3 &b)
F32 x = a.mV[0] - b.mV[0];
F32 y = a.mV[1] - b.mV[1];
F32 z = a.mV[2] - b.mV[2];
return fsqrtf( x*x + y*y + z*z );
return (F32) sqrt( x*x + y*y + z*z );
}
inline F32 distVec_squared(const LLColor3 &a, const LLColor3 &b)

View File

@@ -240,7 +240,7 @@ inline const LLVector3d& LLVector3d::setVec(const F64 *vec)
inline F64 LLVector3d::normVec(void)
{
F64 mag = fsqrtf(mdV[0]*mdV[0] + mdV[1]*mdV[1] + mdV[2]*mdV[2]);
F64 mag = (F32) sqrt(mdV[0]*mdV[0] + mdV[1]*mdV[1] + mdV[2]*mdV[2]);
F64 oomag;
if (mag > FP_MAG_THRESHOLD)
@@ -262,7 +262,7 @@ inline F64 LLVector3d::normVec(void)
inline F64 LLVector3d::normalize(void)
{
F64 mag = fsqrtf(mdV[0]*mdV[0] + mdV[1]*mdV[1] + mdV[2]*mdV[2]);
F64 mag = (F32) sqrt(mdV[0]*mdV[0] + mdV[1]*mdV[1] + mdV[2]*mdV[2]);
F64 oomag;
if (mag > FP_MAG_THRESHOLD)
@@ -286,7 +286,7 @@ inline F64 LLVector3d::normalize(void)
inline F64 LLVector3d::magVec(void) const
{
return fsqrtf(mdV[0]*mdV[0] + mdV[1]*mdV[1] + mdV[2]*mdV[2]);
return (F32) sqrt(mdV[0]*mdV[0] + mdV[1]*mdV[1] + mdV[2]*mdV[2]);
}
inline F64 LLVector3d::magVecSquared(void) const
@@ -296,7 +296,7 @@ inline F64 LLVector3d::magVecSquared(void) const
inline F64 LLVector3d::length(void) const
{
return fsqrtf(mdV[0]*mdV[0] + mdV[1]*mdV[1] + mdV[2]*mdV[2]);
return (F32) sqrt(mdV[0]*mdV[0] + mdV[1]*mdV[1] + mdV[2]*mdV[2]);
}
inline F64 LLVector3d::lengthSquared(void) const
@@ -406,7 +406,7 @@ inline F64 dist_vec(const LLVector3d &a, const LLVector3d &b)
F64 x = a.mdV[0] - b.mdV[0];
F64 y = a.mdV[1] - b.mdV[1];
F64 z = a.mdV[2] - b.mdV[2];
return fsqrtf( x*x + y*y + z*z );
return (F32) sqrt( x*x + y*y + z*z );
}
inline F64 dist_vec_squared(const LLVector3d &a, const LLVector3d &b)

View File

@@ -285,7 +285,7 @@ inline void LLVector3::setVec(const F32 *vec)
inline F32 LLVector3::normalize(void)
{
F32 mag = fsqrtf(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]);
F32 mag = (F32) sqrt(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]);
F32 oomag;
if (mag > FP_MAG_THRESHOLD)
@@ -308,7 +308,7 @@ inline F32 LLVector3::normalize(void)
// deprecated
inline F32 LLVector3::normVec(void)
{
F32 mag = fsqrtf(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]);
F32 mag = (F32) sqrt(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]);
F32 oomag;
if (mag > FP_MAG_THRESHOLD)
@@ -332,7 +332,7 @@ inline F32 LLVector3::normVec(void)
inline F32 LLVector3::length(void) const
{
return fsqrtf(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]);
return (F32) sqrt(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]);
}
inline F32 LLVector3::lengthSquared(void) const
@@ -342,7 +342,7 @@ inline F32 LLVector3::lengthSquared(void) const
inline F32 LLVector3::magVec(void) const
{
return fsqrtf(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]);
return (F32) sqrt(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]);
}
inline F32 LLVector3::magVecSquared(void) const
@@ -476,7 +476,7 @@ inline F32 dist_vec(const LLVector3 &a, const LLVector3 &b)
F32 x = a.mV[0] - b.mV[0];
F32 y = a.mV[1] - b.mV[1];
F32 z = a.mV[2] - b.mV[2];
return fsqrtf( x*x + y*y + z*z );
return (F32) sqrt( x*x + y*y + z*z );
}
inline F32 dist_vec_squared(const LLVector3 &a, const LLVector3 &b)

View File

@@ -392,7 +392,7 @@ inline const LLColor4& LLColor4::setAlpha(F32 a)
inline F32 LLColor4::length(void) const
{
return fsqrtf(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]);
return (F32) sqrt(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]);
}
inline F32 LLColor4::lengthSquared(void) const
@@ -402,7 +402,7 @@ inline F32 LLColor4::lengthSquared(void) const
inline F32 LLColor4::normalize(void)
{
F32 mag = fsqrtf(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]);
F32 mag = (F32) sqrt(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]);
F32 oomag;
if (mag)
@@ -418,7 +418,7 @@ inline F32 LLColor4::normalize(void)
// deprecated
inline F32 LLColor4::magVec(void) const
{
return fsqrtf(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]);
return (F32) sqrt(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]);
}
// deprecated
@@ -430,7 +430,7 @@ inline F32 LLColor4::magVecSquared(void) const
// deprecated
inline F32 LLColor4::normVec(void)
{
F32 mag = fsqrtf(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]);
F32 mag = (F32) sqrt(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]);
F32 oomag;
if (mag)

View File

@@ -300,7 +300,7 @@ inline const LLColor4U& LLColor4U::setAlpha(U8 a)
inline F32 LLColor4U::length(void) const
{
return fsqrtf( ((F32)mV[VX]) * mV[VX] + ((F32)mV[VY]) * mV[VY] + ((F32)mV[VZ]) * mV[VZ] );
return (F32) sqrt( ((F32)mV[VX]) * mV[VX] + ((F32)mV[VY]) * mV[VY] + ((F32)mV[VZ]) * mV[VZ] );
}
inline F32 LLColor4U::lengthSquared(void) const
@@ -311,7 +311,7 @@ inline F32 LLColor4U::lengthSquared(void) const
// deprecated
inline F32 LLColor4U::magVec(void) const
{
return fsqrtf( ((F32)mV[VX]) * mV[VX] + ((F32)mV[VY]) * mV[VY] + ((F32)mV[VZ]) * mV[VZ] );
return (F32) sqrt( ((F32)mV[VX]) * mV[VX] + ((F32)mV[VY]) * mV[VY] + ((F32)mV[VZ]) * mV[VZ] );
}
// deprecated

View File

@@ -321,7 +321,7 @@ inline void LLVector4::setVec(const F32 *vec)
inline F32 LLVector4::length(void) const
{
return fsqrtf(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]);
return (F32) sqrt(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]);
}
inline F32 LLVector4::lengthSquared(void) const
@@ -331,7 +331,7 @@ inline F32 LLVector4::lengthSquared(void) const
inline F32 LLVector4::magVec(void) const
{
return fsqrtf(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]);
return (F32) sqrt(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]);
}
inline F32 LLVector4::magVecSquared(void) const
@@ -463,7 +463,7 @@ inline LLVector4 lerp(const LLVector4 &a, const LLVector4 &b, F32 u)
inline F32 LLVector4::normalize(void)
{
F32 mag = fsqrtf(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]);
F32 mag = (F32) sqrt(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]);
F32 oomag;
if (mag > FP_MAG_THRESHOLD)
@@ -486,7 +486,7 @@ inline F32 LLVector4::normalize(void)
// deprecated
inline F32 LLVector4::normVec(void)
{
F32 mag = fsqrtf(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]);
F32 mag = (F32) sqrt(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]);
F32 oomag;
if (mag > FP_MAG_THRESHOLD)

View File

@@ -56,7 +56,6 @@ set(llmessage_SOURCE_FILES
llmessagethrottle.cpp
llmime.cpp
llnamevalue.cpp
llnetcanary.cpp
llnullcipher.cpp
llpacketack.cpp
llpacketbuffer.cpp
@@ -152,7 +151,6 @@ set(llmessage_HEADER_FILES
llmime.h
llmsgvariabletype.h
llnamevalue.h
llnetcanary.h
llnullcipher.h
llpacketack.h
llpacketbuffer.h

View File

@@ -25,10 +25,6 @@
* $/LicenseInfo$
*/
/*
Ported to Phoenix by Wolfspirit Magic.
*/
#include "linden_common.h"
#include "llavatarnamecache.h"
@@ -91,8 +87,11 @@ namespace LLAvatarNameCache
// only need per-frame timing resolution
LLFrameTimer sRequestTimer;
// Periodically clean out expired entries from the cache
//LLFrameTimer sEraseExpiredTimer;
/// Maximum time an unrefreshed cache entry is allowed
const F64 MAX_UNREFRESHED_TIME = 20.0 * 60.0;
/// Time when unrefreshed cached names were checked last
static F64 sLastExpireCheck;
//-----------------------------------------------------------------------
// Internal methods
@@ -107,10 +106,11 @@ namespace LLAvatarNameCache
void requestNamesViaCapability();
// agent_id/group_id, first_name, last_name, is_group, user_data
// Legacy name system callback
void legacyNameCallback(const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group, void* data);
void legacyNameCallback(const LLUUID& agent_id,
const std::string& full_name,
bool is_group
);
void requestNamesViaLegacy();
@@ -124,9 +124,10 @@ namespace LLAvatarNameCache
const LLAvatarName& av_name);
// Is a request in-flight over the network?
bool isRequestPending(const LLUUID& agent_id);
// Erase expired names from cache
void eraseExpired();
void eraseUnrefreshed();
bool expirationFromCacheControl(LLSD headers, F64 *expires);
}
@@ -196,6 +197,7 @@ public:
{
// Pull expiration out of headers if available
F64 expires = LLAvatarNameCache::nameExpirationFromHeaders(mHeaders);
F64 now = LLFrameTimer::getTotalSeconds();
LLSD agents = content["agents"];
LLSD::array_const_iterator it = agents.beginArray();
@@ -216,118 +218,91 @@ public:
av_name.mDisplayName = av_name.mUsername;
}
LL_DEBUGS("AvNameCache") << "LLAvatarNameResponder::result for " << agent_id << " "
<< "user '" << av_name.mUsername << "' "
<< "display '" << av_name.mDisplayName << "' "
<< "expires in " << expires - now << " seconds"
<< LL_ENDL;
// cache it and fire signals
LLAvatarNameCache::processName(agent_id, av_name, true);
}
// Same logic as error response case
LLSD unresolved_agents = content["bad_ids"];
if (unresolved_agents.size() > 0)
S32 num_unresolved = unresolved_agents.size();
if (num_unresolved > 0)
{
const std::string DUMMY_NAME("\?\?\?");
LLAvatarName av_name;
av_name.mUsername = DUMMY_NAME;
av_name.mDisplayName = DUMMY_NAME;
av_name.mIsDisplayNameDefault = false;
av_name.mIsDummy = true;
av_name.mExpires = expires;
LL_WARNS("AvNameCache") << "LLAvatarNameResponder::result " << num_unresolved << " unresolved ids; "
<< "expires in " << expires - now << " seconds"
<< LL_ENDL;
it = unresolved_agents.beginArray();
for ( ; it != unresolved_agents.endArray(); ++it)
{
const LLUUID& agent_id = *it;
// cache it and fire signals
// Wolfspirit: Do not use ??? as username. Try to get a username out of the old legacy name
std::string oldname;
gCacheName->getFullName(agent_id, oldname);
LLStringUtil::toLower(oldname);
LLStringUtil::replaceString(oldname," ",".");
LLStringUtil::replaceString(oldname,".resident","");
av_name.mUsername = oldname;
LL_WARNS("AvNameCache") << "LLAvatarNameResponder::result "
<< "failed id " << agent_id
<< LL_ENDL;
LLAvatarNameCache::processName(agent_id, av_name, true);
LLAvatarNameCache::handleAgentError(agent_id);
}
}
}
LL_DEBUGS("AvNameCache") << "LLAvatarNameResponder::result "
<< LLAvatarNameCache::sCache.size() << " cached names"
<< LL_ENDL;
}
/*virtual*/ void error(U32 status, const std::string& reason)
{
// We're going to construct a dummy record and cache it for a while,
// either briefly for a 503 Service Unavailable, or longer for other
// errors.
F64 retry_timestamp = errorRetryTimestamp(status);
// If there's an error, it might be caused by PeopleApi,
// or when loading textures on startup and using a very slow
// network, this query may time out.
// What we should do depends on whether or not we have a cached name
LL_WARNS("AvNameCache") << "LLAvatarNameResponder::error " << status << " " << reason
<< LL_ENDL;
// *NOTE: "??" starts trigraphs in C/C++, escape the question marks.
const std::string DUMMY_NAME("\?\?\?");
LLAvatarName av_name;
av_name.mUsername = DUMMY_NAME;
av_name.mDisplayName = DUMMY_NAME;
av_name.mIsDisplayNameDefault = false;
av_name.mIsDummy = true;
av_name.mExpires = retry_timestamp;
// Add dummy records for all agent IDs in this request
// Add dummy records for any agent IDs in this request that we do not have cached already
std::vector<LLUUID>::const_iterator it = mAgentIDs.begin();
for ( ; it != mAgentIDs.end(); ++it)
{
const LLUUID& agent_id = *it;
// cache it and fire signals
// Wolfspirit: Do not use ??? as username. Try to get a username out of the old legacy name
std::string oldname;
gCacheName->getFullName(agent_id, oldname);
LLStringUtil::toLower(oldname);
LLStringUtil::replaceString(oldname," ",".");
LLStringUtil::replaceString(oldname,".resident","");
av_name.mUsername = oldname;
LLAvatarNameCache::processName(agent_id, av_name, true);
}
}
// Return time to retry a request that generated an error, based on
// error type and headers. Return value is seconds-since-epoch.
F64 errorRetryTimestamp(S32 status)
{
F64 now = LLFrameTimer::getTotalSeconds();
// Retry-After takes priority
LLSD retry_after = mHeaders["retry-after"];
if (retry_after.isDefined())
{
// We only support the delta-seconds type
S32 delta_seconds = retry_after.asInteger();
if (delta_seconds > 0)
{
// ...valid delta-seconds
return now + F64(delta_seconds);
}
}
// If no Retry-After, look for Cache-Control max-age
F64 expires = 0.0;
if (LLAvatarNameCache::expirationFromCacheControl(mHeaders, &expires))
{
return expires;
}
// No information in header, make a guess
if (status == 503)
{
// ...service unavailable, retry soon
const F64 SERVICE_UNAVAILABLE_DELAY = 600.0; // 10 min
return now + SERVICE_UNAVAILABLE_DELAY;
}
else
{
// ...other unexpected error
const F64 DEFAULT_DELAY = 3600.0; // 1 hour
return now + DEFAULT_DELAY;
LLAvatarNameCache::handleAgentError(agent_id);
}
}
};
// Provide some fallback for agents that return errors
void LLAvatarNameCache::handleAgentError(const LLUUID& agent_id)
{
std::map<LLUUID,LLAvatarName>::iterator existing = sCache.find(agent_id);
if (existing == sCache.end())
{
// there is no existing cache entry, so make a temporary name from legacy
LL_WARNS("AvNameCache") << "LLAvatarNameCache get legacy for agent "
<< agent_id << LL_ENDL;
gCacheName->get(agent_id, false, // legacy compatibility
boost::bind(&LLAvatarNameCache::legacyNameCallback,
_1, _2, _3));
}
else
{
// we have a chached (but probably expired) entry - since that would have
// been returned by the get method, there is no need to signal anyone
// Clear this agent from the pending list
LLAvatarNameCache::sPendingQueue.erase(agent_id);
const LLAvatarName& av_name = existing->second;
LL_DEBUGS("AvNameCache") << "LLAvatarNameCache use cache for agent "
<< agent_id
<< "user '" << av_name.mUsername << "' "
<< "display '" << av_name.mDisplayName << "' "
<< "expires in " << av_name.mExpires - LLFrameTimer::getTotalSeconds() << " seconds"
<< LL_ENDL;
}
}
void LLAvatarNameCache::processName(const LLUUID& agent_id,
const LLAvatarName& av_name,
bool add_to_cache)
@@ -336,12 +311,12 @@ void LLAvatarNameCache::processName(const LLUUID& agent_id,
{
// sCache[agent_id] = av_name;
// [SL:KB] - Patch: Agent-DisplayNames | Checked: 2010-12-28 (Catznip-2.4.0h) | Added: Catznip-2.4.0h
// Don't replace existing entries with dummies
cache_t::iterator itName = (av_name.mIsDummy) ? sCache.find(agent_id) : sCache.end();
if (sCache.end() != itName)
itName->second.mExpires = av_name.mExpires;
else
sCache[agent_id] = av_name;
// Don't replace existing entries with dummies
cache_t::iterator itName = (av_name.mIsTemporaryName) ? sCache.find(agent_id) : sCache.end();
if (sCache.end() != itName)
itName->second.mExpires = av_name.mExpires;
else
sCache[agent_id] = av_name;
// [/SL:KB]
}
@@ -377,6 +352,7 @@ void LLAvatarNameCache::requestNamesViaCapability()
std::vector<LLUUID> agent_ids;
agent_ids.reserve(128);
U32 ids = 0;
ask_queue_t::const_iterator it = sAskQueue.begin();
for ( ; it != sAskQueue.end(); ++it)
{
@@ -387,11 +363,13 @@ void LLAvatarNameCache::requestNamesViaCapability()
// ...starting new request
url += sNameLookupURL;
url += "?ids=";
ids = 1;
}
else
{
// ...continuing existing request
url += "&ids=";
ids++;
}
url += agent_id.asString();
agent_ids.push_back(agent_id);
@@ -401,7 +379,9 @@ void LLAvatarNameCache::requestNamesViaCapability()
if (url.size() > NAME_URL_SEND_THRESHOLD)
{
//llinfos << "requestNames " << url << llendl;
LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::requestNamesViaCapability first "
<< ids << " ids"
<< LL_ENDL;
LLHTTPClient::get(url, new LLAvatarNameResponder(agent_ids));
url.clear();
agent_ids.clear();
@@ -410,7 +390,9 @@ void LLAvatarNameCache::requestNamesViaCapability()
if (!url.empty())
{
//llinfos << "requestNames " << url << llendl;
LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::requestNamesViaCapability all "
<< ids << " ids"
<< LL_ENDL;
LLHTTPClient::get(url, new LLAvatarNameResponder(agent_ids));
url.clear();
agent_ids.clear();
@@ -419,18 +401,25 @@ void LLAvatarNameCache::requestNamesViaCapability()
// We've moved all asks to the pending request queue
sAskQueue.clear();
}
void LLAvatarNameCache::legacyNameCallback(const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group, void* data)
void LLAvatarNameCache::legacyNameCallback(const LLUUID& agent_id,
const std::string& full_name,
bool is_group)
{
std::string full_name = first + " " +last;
// Construct a dummy record for this name. By convention, SLID is blank
// Never expires, but not written to disk, so lasts until end of session.
LLAvatarName av_name;
LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::legacyNameCallback "
<< "agent " << agent_id << " "
<< "full name '" << full_name << "'"
<< ( is_group ? " [group]" : "" )
<< LL_ENDL;
buildLegacyName(full_name, &av_name);
// Don't add to cache, the data already exists in the legacy name system
// cache and we don't want or need duplicate storage, because keeping the
// two copies in sync is complex.
processName(id, av_name, false);
processName(agent_id, av_name, false);
}
void LLAvatarNameCache::requestNamesViaLegacy()
@@ -446,7 +435,11 @@ void LLAvatarNameCache::requestNamesViaLegacy()
// invoked below. This should never happen in practice.
sPendingQueue[agent_id] = now;
gCacheName->get(agent_id, false, legacyNameCallback);
LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::requestNamesViaLegacy agent " << agent_id << LL_ENDL;
gCacheName->get(agent_id, false, // legacy compatibility
boost::bind(&LLAvatarNameCache::legacyNameCallback,
_1, _2, _3));
}
// We've either answered immediately or moved all asks to the
@@ -482,21 +475,24 @@ void LLAvatarNameCache::importFile(std::istream& istr)
av_name.fromLLSD( it->second );
sCache[agent_id] = av_name;
}
// entries may have expired since we last ran the viewer, just
// clean them out now
eraseExpired();
llinfos << "loaded " << sCache.size() << llendl;
LL_INFOS("AvNameCache") << "loaded " << sCache.size() << LL_ENDL;
// Some entries may have expired since the cache was stored,
// but they will be flushed in the first call to eraseUnrefreshed
// from LLAvatarNameResponder::idle
}
void LLAvatarNameCache::exportFile(std::ostream& ostr)
{
LLSD agents;
F64 max_unrefreshed = LLFrameTimer::getTotalSeconds() - MAX_UNREFRESHED_TIME;
cache_t::const_iterator it = sCache.begin();
for ( ; it != sCache.end(); ++it)
{
const LLUUID& agent_id = it->first;
const LLAvatarName& av_name = it->second;
if (!av_name.mIsDummy)
// Do not write temporary or expired entries to the stored cache
if (!av_name.mIsTemporaryName && av_name.mExpires >= max_unrefreshed)
{
// key must be a string
agents[agent_id.asString()] = av_name.asLLSD();
@@ -531,36 +527,26 @@ void LLAvatarNameCache::idle()
// return;
//}
// Must be large relative to above
// No longer deleting expired entries, just re-requesting in the get
// this way first synchronous get call on an expired entry won't return
// legacy name. LF
//const F32 ERASE_EXPIRED_TIMEOUT = 60.f; // seconds
//if (sEraseExpiredTimer.checkExpirationAndReset(ERASE_EXPIRED_TIMEOUT))
//{
// eraseExpired();
//}
if (sAskQueue.empty())
if (!sAskQueue.empty())
{
return;
if (useDisplayNames())
{
requestNamesViaCapability();
}
else
{
// ...fall back to legacy name cache system
requestNamesViaLegacy();
}
}
if (useDisplayNames())
{
requestNamesViaCapability();
}
else
{
// ...fall back to legacy name cache system
requestNamesViaLegacy();
}
// erase anything that has not been refreshed for more than MAX_UNREFRESHED_TIME
eraseUnrefreshed();
}
bool LLAvatarNameCache::isRequestPending(const LLUUID& agent_id)
{
bool isPending = false;
const F64 PENDING_TIMEOUT_SECS = 5.0 * 60.0;
pending_queue_t::const_iterator it = sPendingQueue.find(agent_id);
@@ -568,26 +554,38 @@ bool LLAvatarNameCache::isRequestPending(const LLUUID& agent_id)
{
// in the list of requests in flight, retry if too old
F64 expire_time = LLFrameTimer::getTotalSeconds() - PENDING_TIMEOUT_SECS;
return it->second > expire_time;
isPending = (it->second > expire_time);
}
return false;
return isPending;
}
void LLAvatarNameCache::eraseExpired()
void LLAvatarNameCache::eraseUnrefreshed()
{
F64 now = LLFrameTimer::getTotalSeconds();
cache_t::iterator it = sCache.begin();
for (cache_t::iterator it = sCache.begin(); it != sCache.end();)
{
const LLAvatarName& av_name = it->second;
if (av_name.mExpires < now)
{
sCache.erase(it++);
}
else
{
++it;
}
F64 max_unrefreshed = now - MAX_UNREFRESHED_TIME;
if (!sLastExpireCheck || sLastExpireCheck < max_unrefreshed)
{
sLastExpireCheck = now;
for (cache_t::iterator it = sCache.begin(); it != sCache.end();)
{
const LLAvatarName& av_name = it->second;
if (av_name.mExpires < max_unrefreshed)
{
const LLUUID& agent_id = it->first;
LL_DEBUGS("AvNameCache") << agent_id
<< " user '" << av_name.mUsername << "' "
<< "expired " << now - av_name.mExpires << " secs ago"
<< LL_ENDL;
sCache.erase(it++);
}
else
{
++it;
}
}
LL_INFOS("AvNameCache") << sCache.size() << " cached avatar names" << LL_ENDL;
}
}
@@ -598,8 +596,11 @@ void LLAvatarNameCache::buildLegacyName(const std::string& full_name,
av_name->mUsername = "";
av_name->mDisplayName = full_name;
av_name->mIsDisplayNameDefault = true;
av_name->mIsDummy = true;
av_name->mExpires = F64_MAX;
av_name->mIsTemporaryName = true;
av_name->mExpires = F64_MAX; // not used because these are not cached
LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::buildLegacyName "
<< full_name
<< LL_ENDL;
// [Ansariel/Henri]
// Why ain't those set? In case of disabled display names
@@ -632,6 +633,9 @@ bool LLAvatarNameCache::get(const LLUUID& agent_id, LLAvatarName *av_name)
{
if (!isRequestPending(agent_id))
{
LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::get "
<< "refresh agent " << agent_id
<< LL_ENDL;
sAskQueue.insert(agent_id);
}
}
@@ -641,7 +645,6 @@ bool LLAvatarNameCache::get(const LLUUID& agent_id, LLAvatarName *av_name)
}
else
{
// ...use legacy names cache
std::string full_name;
if (gCacheName->getFullName(agent_id, full_name))
@@ -654,6 +657,9 @@ bool LLAvatarNameCache::get(const LLUUID& agent_id, LLAvatarName *av_name)
if (!isRequestPending(agent_id))
{
LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::get "
<< "queue request for agent " << agent_id
<< LL_ENDL;
sAskQueue.insert(agent_id);
}
@@ -800,6 +806,8 @@ F64 LLAvatarNameCache::nameExpirationFromHeaders(LLSD headers)
bool LLAvatarNameCache::expirationFromCacheControl(LLSD headers, F64 *expires)
{
bool fromCacheControl = false;
F64 now = LLFrameTimer::getTotalSeconds();
// Allow the header to override the default
LLSD cache_control_header = headers["cache-control"];
if (cache_control_header.isDefined())
@@ -808,12 +816,16 @@ bool LLAvatarNameCache::expirationFromCacheControl(LLSD headers, F64 *expires)
std::string cache_control = cache_control_header.asString();
if (max_age_from_cache_control(cache_control, &max_age))
{
F64 now = LLFrameTimer::getTotalSeconds();
*expires = now + (F64)max_age;
return true;
fromCacheControl = true;
}
}
return false;
LL_DEBUGS("AvNameCache")
<< ( fromCacheControl ? "expires based on cache control " : "default expiration " )
<< "in " << *expires - now << " seconds"
<< LL_ENDL;
return fromCacheControl;
}

View File

@@ -85,10 +85,11 @@ namespace LLAvatarNameCache
void setForceDisplayNames(bool force);
// [/RLVa:KB]
bool isRequestPending(const LLUUID& agent_id);
void erase(const LLUUID& agent_id);
/// Provide some fallback for agents that return errors
void handleAgentError(const LLUUID& agent_id);
// Force a re-fetch of the most recent data, but keep the current
// data in cache
void fetch(const LLUUID& agent_id);

View File

@@ -43,10 +43,7 @@
#include "lluuid.h"
#include "message.h"
// Constants
static const std::string CN_WAITING("(Loading...)"); // *TODO: translate
static const std::string CN_NOBODY("(nobody)"); // *TODO: translate
static const std::string CN_NONE("(none)"); // *TODO: translate
#include <boost/regex.hpp>
// llsd serialization constants
static const std::string AGENTS("agents");
@@ -65,6 +62,7 @@ const S32 CN_FILE_VERSION = 2;
// Globals
LLCacheName* gCacheName = NULL;
std::map<std::string, std::string> LLCacheName::sCacheName;
/// ---------------------------------------------------------------------------
/// class LLCacheNameEntry
@@ -84,6 +82,8 @@ public:
};
LLCacheNameEntry::LLCacheNameEntry()
: mIsGroup(false),
mCreateTime(0)
{
}
@@ -92,17 +92,19 @@ class PendingReply
{
public:
LLUUID mID;
LLCacheNameCallback mCallback;
LLCacheNameSignal mSignal;
LLHost mHost;
void* mData;
PendingReply(const LLUUID& id, LLCacheNameCallback callback, void* data = NULL)
: mID(id), mCallback(callback), mData(data)
{ }
PendingReply(const LLUUID& id, const LLHost& host)
: mID(id), mCallback(0), mHost(host)
{ }
: mID(id), mHost(host)
{
}
boost::signals2::connection setCallback(const LLCacheNameCallback& cb)
{
return mSignal.connect(cb);
}
void done() { mID.setNull(); }
bool isDone() const { return mID.isNull() != FALSE; }
};
@@ -126,7 +128,7 @@ private:
};
ReplySender::ReplySender(LLMessageSystem* msg)
: mMsg(msg), mPending(false)
: mMsg(msg), mPending(false), mCurrIsGroup(false)
{ }
ReplySender::~ReplySender()
@@ -187,10 +189,10 @@ void ReplySender::flush()
typedef std::set<LLUUID> AskQueue;
typedef std::vector<PendingReply> ReplyQueue;
typedef std::list<PendingReply*> ReplyQueue;
typedef std::map<LLUUID,U32> PendingQueue;
typedef std::map<LLUUID, LLCacheNameEntry*> Cache;
typedef std::vector<LLCacheNameCallback> Observers;
typedef std::map<std::string, LLUUID> ReverseCache;
class LLCacheName::Impl
{
@@ -200,7 +202,9 @@ public:
Cache mCache;
// the map of UUIDs to names
ReverseCache mReverseCache;
// map of names to UUIDs
AskQueue mAskNameQueue;
AskQueue mAskGroupQueue;
// UUIDs to ask our upstream host about
@@ -211,13 +215,18 @@ public:
ReplyQueue mReplyQueue;
// requests awaiting replies from us
Observers mObservers;
LLCacheNameSignal mSignal;
LLFrameTimer mProcessTimer;
Impl(LLMessageSystem* msg);
~Impl();
BOOL getName(const LLUUID& id, std::string& first, std::string& last);
boost::signals2::connection addPending(const LLUUID& id, const LLCacheNameCallback& callback);
void addPending(const LLUUID& id, const LLHost& host);
void processPendingAsks();
void processPendingReplies();
void sendRequest(const char* msg_name, const AskQueue& queue);
@@ -231,8 +240,6 @@ public:
static void handleUUIDNameReply(LLMessageSystem* msg, void** userdata);
static void handleUUIDGroupNameRequest(LLMessageSystem* msg, void** userdata);
static void handleUUIDGroupNameReply(LLMessageSystem* msg, void** userdata);
void notifyObservers(const LLUUID& id, const std::string& first, const std::string& last, BOOL group);
};
@@ -247,6 +254,9 @@ LLCacheName::LLCacheName(LLMessageSystem* msg)
LLCacheName::LLCacheName(LLMessageSystem* msg, const LLHost& upstream_host)
: impl(* new Impl(msg))
{
sCacheName["waiting"] = "(Loading...)";
sCacheName["nobody"] = "(nobody)";
sCacheName["none"] = "(none)";
setUpstream(upstream_host);
}
@@ -272,54 +282,34 @@ LLCacheName::Impl::Impl(LLMessageSystem* msg)
LLCacheName::Impl::~Impl()
{
for_each(mCache.begin(), mCache.end(), DeletePairedPointer());
for_each(mReplyQueue.begin(), mReplyQueue.end(), DeletePointer());
}
boost::signals2::connection LLCacheName::Impl::addPending(const LLUUID& id, const LLCacheNameCallback& callback)
{
PendingReply* reply = new PendingReply(id, LLHost());
boost::signals2::connection res = reply->setCallback(callback);
mReplyQueue.push_back(reply);
return res;
}
void LLCacheName::Impl::addPending(const LLUUID& id, const LLHost& host)
{
PendingReply* reply = new PendingReply(id, host);
mReplyQueue.push_back(reply);
}
void LLCacheName::setUpstream(const LLHost& upstream_host)
{
impl.mUpstreamHost = upstream_host;
}
void LLCacheName::addObserver(LLCacheNameCallback callback)
boost::signals2::connection LLCacheName::addObserver(const LLCacheNameCallback& callback)
{
impl.mObservers.push_back(callback);
}
void LLCacheName::removeObserver(LLCacheNameCallback callback)
{
Observers::iterator it = impl.mObservers.begin();
Observers::iterator end = impl.mObservers.end();
for ( ; it != end; ++it)
{
const LLCacheNameCallback& cb = (*it);
if (cb == callback)
{
impl.mObservers.erase(it);
return;
}
}
}
void LLCacheName::cancelCallback(const LLUUID& id, LLCacheNameCallback callback, void* user_data)
{
ReplyQueue::iterator it = impl.mReplyQueue.begin();
ReplyQueue::iterator end = impl.mReplyQueue.end();
for(; it != end; ++it)
{
const PendingReply& reply = (*it);
if ((callback == reply.mCallback)
&& (id == reply.mID)
&& (user_data == reply.mData) )
{
impl.mReplyQueue.erase(it);
return;
}
}
return impl.mSignal.connect(callback);
}
#if 0
void LLCacheName::importFile(LLFILE* fp)
{
S32 count = 0;
@@ -396,11 +386,12 @@ void LLCacheName::importFile(LLFILE* fp)
llinfos << "LLCacheName loaded " << count << " names" << llendl;
}
#endif
bool LLCacheName::importFile(std::istream& istr)
{
LLSD data;
if(LLSDSerialize::fromXML(data, istr) < 1)
if(LLSDSerialize::fromXMLDocument(data, istr) < 1)
return false;
// We'll expire entries more than a week old
@@ -426,6 +417,9 @@ bool LLCacheName::importFile(std::istream& istr)
entry->mFirstName = agent[FIRST].asString();
entry->mLastName = agent[LAST].asString();
impl.mCache[id] = entry;
std::string fullname = buildFullName(entry->mFirstName, entry->mLastName);
impl.mReverseCache[fullname] = id;
++count;
}
llinfos << "LLCacheName loaded " << count << " agent names" << llendl;
@@ -446,6 +440,7 @@ bool LLCacheName::importFile(std::istream& istr)
entry->mCreateTime = ctime;
entry->mGroupName = group[NAME].asString();
impl.mCache[id] = entry;
impl.mReverseCache[entry->mGroupName] = id;
++count;
}
llinfos << "LLCacheName loaded " << count << " group names" << llendl;
@@ -488,16 +483,16 @@ void LLCacheName::exportFile(std::ostream& ostr)
}
BOOL LLCacheName::getName(const LLUUID& id, std::string& first, std::string& last)
BOOL LLCacheName::Impl::getName(const LLUUID& id, std::string& first, std::string& last)
{
if(id.isNull())
{
first = CN_NOBODY;
first = sCacheName["nobody"];
last.clear();
return FALSE;
return TRUE;
}
LLCacheNameEntry* entry = get_ptr_in_map(impl.mCache, id );
LLCacheNameEntry* entry = get_ptr_in_map(mCache, id );
if (entry)
{
first = entry->mFirstName;
@@ -506,32 +501,42 @@ BOOL LLCacheName::getName(const LLUUID& id, std::string& first, std::string& las
}
else
{
first = CN_WAITING;
first = sCacheName["waiting"];
last.clear();
if (!impl.isRequestPending(id))
if (!isRequestPending(id))
{
impl.mAskNameQueue.insert(id);
mAskNameQueue.insert(id);
}
return FALSE;
}
}
// static
void LLCacheName::localizeCacheName(std::string key, std::string value)
{
if (key!="" && value!= "" )
sCacheName[key]=value;
else
llwarns<< " Error localizing cache key " << key << " To "<< value<<llendl;
}
BOOL LLCacheName::getFullName(const LLUUID& id, std::string& fullname)
{
std::string first_name, last_name;
BOOL res = getName(id, first_name, last_name);
if(res)
fullname = first_name + " " + last_name;
BOOL res = impl.getName(id, first_name, last_name);
fullname = buildFullName(first_name, last_name);
return res;
}
BOOL LLCacheName::getGroupName(const LLUUID& id, std::string& group)
{
if(id.isNull())
{
group = CN_NONE;
return FALSE;
group = sCacheName["none"];
return TRUE;
}
LLCacheNameEntry* entry = get_ptr_in_map(impl.mCache,id);
@@ -551,7 +556,7 @@ BOOL LLCacheName::getGroupName(const LLUUID& id, std::string& group)
}
else
{
group = CN_WAITING;
group = sCacheName["waiting"];
if (!impl.isRequestPending(id))
{
impl.mAskGroupQueue.insert(id);
@@ -560,27 +565,151 @@ BOOL LLCacheName::getGroupName(const LLUUID& id, std::string& group)
}
}
// TODO: Make the cache name callback take a SINGLE std::string,
// not a separate first and last name.
void LLCacheName::get(const LLUUID& id, BOOL is_group, LLCacheNameCallback callback, void* user_data)
BOOL LLCacheName::getUUID(const std::string& first, const std::string& last, LLUUID& id)
{
std::string full_name = buildFullName(first, last);
return getUUID(full_name, id);
}
BOOL LLCacheName::getUUID(const std::string& full_name, LLUUID& id)
{
ReverseCache::iterator iter = impl.mReverseCache.find(full_name);
if (iter != impl.mReverseCache.end())
{
id = iter->second;
return TRUE;
}
else
{
return FALSE;
}
}
//static
std::string LLCacheName::buildFullName(const std::string& first, const std::string& last)
{
std::string fullname = first;
if (!last.empty()
&& last != "Resident")
{
fullname += ' ';
fullname += last;
}
return fullname;
}
//static
std::string LLCacheName::cleanFullName(const std::string& full_name)
{
return full_name.substr(0, full_name.find(" Resident"));
}
//static
std::string LLCacheName::buildUsername(const std::string& full_name)
{
// rare, but handle hard-coded error names returned from server
if (full_name == "(\?\?\?) (\?\?\?)")
{
return "(\?\?\?)";
}
std::string::size_type index = full_name.find(' ');
if (index != std::string::npos)
{
std::string username;
username = full_name.substr(0, index);
std::string lastname = full_name.substr(index+1);
if (lastname != "Resident")
{
username = username + "." + lastname;
}
LLStringUtil::toLower(username);
return username;
}
// if the input wasn't a correctly formatted legacy name just return it unchanged
return full_name;
}
//static
std::string LLCacheName::buildLegacyName(const std::string& complete_name)
{
//boost::regexp was showing up in the crashreporter, so doing
//painfully manual parsing using substr. LF
S32 open_paren = complete_name.rfind(" (");
S32 close_paren = complete_name.rfind(')');
if (open_paren != std::string::npos &&
close_paren == complete_name.length()-1)
{
S32 length = close_paren - open_paren - 2;
std::string legacy_name = complete_name.substr(open_paren+2, length);
if (legacy_name.length() > 0)
{
std::string cap_letter = legacy_name.substr(0, 1);
LLStringUtil::toUpper(cap_letter);
legacy_name = cap_letter + legacy_name.substr(1);
S32 separator = legacy_name.find('.');
if (separator != std::string::npos)
{
std::string last_name = legacy_name.substr(separator+1);
legacy_name = legacy_name.substr(0, separator);
if (last_name.length() > 0)
{
cap_letter = last_name.substr(0, 1);
LLStringUtil::toUpper(cap_letter);
legacy_name = legacy_name + " " + cap_letter + last_name.substr(1);
}
}
return legacy_name;
}
}
return complete_name;
}
// This is a little bit kludgy. LLCacheNameCallback is a slot instead of a function pointer.
// The reason it is a slot is so that the legacy get() function below can bind an old callback
// and pass it as a slot. The reason it isn't a boost::function is so that trackable behavior
// doesn't get lost. As a result, we have to bind the slot to a signal to call it, even when
// we call it immediately. -Steve
// NOTE: Even though passing first and last name is a bit of extra overhead, it eliminates the
// potential need for any parsing should any code need to handle first and last name independently.
boost::signals2::connection LLCacheName::get(const LLUUID& id, bool is_group, const LLCacheNameCallback& callback)
{
boost::signals2::connection res;
if(id.isNull())
{
callback(id, CN_NOBODY, "", is_group, user_data);
return;
LLCacheNameSignal signal;
signal.connect(callback);
signal(id, sCacheName["nobody"], is_group);
return res;
}
LLCacheNameEntry* entry = get_ptr_in_map(impl.mCache, id );
if (entry)
{
LLCacheNameSignal signal;
signal.connect(callback);
// id found in map therefore we can call the callback immediately.
if (entry->mIsGroup)
{
callback(id, entry->mGroupName, "", entry->mIsGroup, user_data);
signal(id, entry->mGroupName, entry->mIsGroup);
}
else
{
callback(id, entry->mFirstName, entry->mLastName, entry->mIsGroup, user_data);
std::string fullname =
buildFullName(entry->mFirstName, entry->mLastName);
signal(id, fullname, entry->mIsGroup);
}
}
else
@@ -597,16 +726,29 @@ void LLCacheName::get(const LLUUID& id, BOOL is_group, LLCacheNameCallback callb
impl.mAskNameQueue.insert(id);
}
}
impl.mReplyQueue.push_back(PendingReply(id, callback, user_data));
res = impl.addPending(id, callback);
}
return res;
}
boost::signals2::connection LLCacheName::getGroup(const LLUUID& group_id,
const LLCacheNameCallback& callback)
{
return get(group_id, true, callback);
}
boost::signals2::connection LLCacheName::get(const LLUUID& id, bool is_group, old_callback_t callback, void* user_data)
{
return get(id, is_group, boost::bind(callback, _1, _2, _3, user_data));
}
// <edit>
BOOL LLCacheName::getIfThere(const LLUUID& id, std::string& fullname, BOOL& is_group)
bool LLCacheName::getIfThere(const LLUUID& id, std::string& fullname, BOOL& is_group)
{
if(id.isNull())
{
fullname = "";
return FALSE;
return false;
}
LLCacheNameEntry* entry = get_ptr_in_map(impl.mCache, id );
@@ -621,10 +763,10 @@ BOOL LLCacheName::getIfThere(const LLUUID& id, std::string& fullname, BOOL& is_g
fullname = entry->mFirstName + " " + entry->mLastName;
}
is_group = entry->mIsGroup;
return TRUE;
return true;
}
fullname = "";
return FALSE;
return false;
}
// </edit>
void LLCacheName::processPending()
@@ -695,7 +837,7 @@ void LLCacheName::dump()
{
llinfos
<< iter->first << " = "
<< entry->mFirstName << " " << entry->mLastName
<< buildFullName(entry->mFirstName, entry->mLastName)
<< " @ " << entry->mCreateTime
<< llendl;
}
@@ -710,16 +852,27 @@ void LLCacheName::dumpStats()
<< " AskGroup=" << impl.mAskGroupQueue.size()
<< " Pending=" << impl.mPendingQueue.size()
<< " Reply=" << impl.mReplyQueue.size()
<< " Observers=" << impl.mObservers.size()
// << " Observers=" << impl.mSignal.size()
<< llendl;
}
void LLCacheName::clear()
{
for_each(impl.mCache.begin(), impl.mCache.end(), DeletePairedPointer());
impl.mCache.clear();
}
//static
std::string LLCacheName::getDefaultName()
{
return CN_WAITING;
return sCacheName["waiting"];
}
//static
std::string LLCacheName::getDefaultLastName()
{
return "Resident";
}
void LLCacheName::Impl::processPendingAsks()
{
sendRequest(_PREHASH_UUIDNameRequest, mAskNameQueue);
@@ -730,50 +883,51 @@ void LLCacheName::Impl::processPendingAsks()
void LLCacheName::Impl::processPendingReplies()
{
ReplyQueue::iterator it = mReplyQueue.begin();
ReplyQueue::iterator end = mReplyQueue.end();
// First call all the callbacks, because they might send messages.
for(; it != end; ++it)
for(ReplyQueue::iterator it = mReplyQueue.begin(); it != mReplyQueue.end(); ++it)
{
LLCacheNameEntry* entry = get_ptr_in_map(mCache, it->mID);
PendingReply* reply = *it;
LLCacheNameEntry* entry = get_ptr_in_map(mCache, reply->mID);
if(!entry) continue;
if (it->mCallback)
if (!entry->mIsGroup)
{
if (!entry->mIsGroup)
{
(it->mCallback)(it->mID,
entry->mFirstName, entry->mLastName,
FALSE, it->mData);
}
else {
(it->mCallback)(it->mID,
entry->mGroupName, "",
TRUE, it->mData);
}
std::string fullname =
LLCacheName::buildFullName(entry->mFirstName, entry->mLastName);
(reply->mSignal)(reply->mID, fullname, false);
}
else
{
(reply->mSignal)(reply->mID, entry->mGroupName, true);
}
}
// Forward on all replies, if needed.
ReplySender sender(mMsg);
for (it = mReplyQueue.begin(); it != end; ++it)
for(ReplyQueue::iterator it = mReplyQueue.begin(); it != mReplyQueue.end(); ++it)
{
LLCacheNameEntry* entry = get_ptr_in_map(mCache, it->mID);
PendingReply* reply = *it;
LLCacheNameEntry* entry = get_ptr_in_map(mCache, reply->mID);
if(!entry) continue;
if (it->mHost.isOk())
if (reply->mHost.isOk())
{
sender.send(it->mID, *entry, it->mHost);
sender.send(reply->mID, *entry, reply->mHost);
}
it->done();
reply->done();
}
for(ReplyQueue::iterator it = mReplyQueue.begin(); it != mReplyQueue.end(); )
{
ReplyQueue::iterator curit = it++;
PendingReply* reply = *curit;
if (reply->isDone())
{
delete reply;
mReplyQueue.erase(curit);
}
}
mReplyQueue.erase(
remove_if(mReplyQueue.begin(), mReplyQueue.end(),
std::mem_fun_ref(&PendingReply::isDone)),
mReplyQueue.end());
}
@@ -811,18 +965,6 @@ void LLCacheName::Impl::sendRequest(
}
}
void LLCacheName::Impl::notifyObservers(const LLUUID& id,
const std::string& first, const std::string& last, BOOL is_group)
{
for (Observers::const_iterator i = mObservers.begin(),
end = mObservers.end();
i != end;
++i)
{
(**i)(id, first, last, is_group, NULL);
}
}
bool LLCacheName::Impl::isRequestPending(const LLUUID& id)
{
U32 now = (U32)time(NULL);
@@ -889,7 +1031,7 @@ void LLCacheName::Impl::processUUIDRequest(LLMessageSystem* msg, bool isGroup)
}
}
mReplyQueue.push_back(PendingReply(id, fromHost));
addPending(id, fromHost);
}
}
}
@@ -927,11 +1069,32 @@ void LLCacheName::Impl::processUUIDReply(LLMessageSystem* msg, bool isGroup)
if (!isGroup)
{
notifyObservers(id, entry->mFirstName, entry->mLastName, FALSE);
// NOTE: Very occasionally the server sends down a full name
// in the first name field with an empty last name, for example,
// first = "Ladanie1 Resident", last = "".
// I cannot reproduce this, nor can I find a bug in the server code.
// Ensure "Resident" does not appear via cleanFullName, because
// buildFullName only checks last name. JC
std::string full_name;
if (entry->mLastName.empty())
{
full_name = cleanFullName(entry->mFirstName);
//fix what we are putting in the cache
entry->mFirstName = full_name;
entry->mLastName = "Resident";
}
else
{
full_name = LLCacheName::buildFullName(entry->mFirstName, entry->mLastName);
}
mSignal(id, full_name, false);
mReverseCache[full_name] = id;
}
else
{
notifyObservers(id, entry->mGroupName, "", TRUE);
mSignal(id, entry->mGroupName, true);
mReverseCache[entry->mGroupName] = id;
}
}
}

View File

@@ -33,12 +33,21 @@
#ifndef LL_LLCACHENAME_H
#define LL_LLCACHENAME_H
#include <boost/bind.hpp>
#include <boost/signals2.hpp>
class LLMessageSystem;
class LLHost;
class LLUUID;
// agent_id/group_id, first_name, last_name, is_group, user_data
typedef void (*LLCacheNameCallback)(const LLUUID&, const std::string&, const std::string&, BOOL, void*);
typedef boost::signals2::signal<void (const LLUUID& id,
const std::string& name,
bool is_group)> LLCacheNameSignal;
typedef LLCacheNameSignal::slot_type LLCacheNameCallback;
// Old callback with user data for compatability
typedef void (*old_callback_t)(const LLUUID&, const std::string&, bool, void*);
// Here's the theory:
// If you request a name that isn't in the cache, it returns "waiting"
@@ -59,25 +68,44 @@ public:
// for simulators, this is the data server
void setUpstream(const LLHost& upstream_host);
void addObserver(LLCacheNameCallback callback);
void removeObserver(LLCacheNameCallback callback);
void cancelCallback(const LLUUID& id, LLCacheNameCallback callback, void* user_data = NULL);
boost::signals2::connection addObserver(const LLCacheNameCallback& callback);
// janky old format. Remove after a while. Phoenix. 2008-01-30
#if 0
void importFile(LLFILE* fp);
#endif
// storing cache on disk; for viewer, in name.cache
bool importFile(std::istream& istr);
void exportFile(std::ostream& ostr);
// If available, copies the first and last name into the strings provided.
// first must be at least DB_FIRST_NAME_BUF_SIZE characters.
// last must be at least DB_LAST_NAME_BUF_SIZE characters.
// If available, copies name ("bobsmith123" or "James Linden") into string
// If not available, copies the string "waiting".
// Returns TRUE iff available.
BOOL getName(const LLUUID& id, std::string& first, std::string& last);
BOOL getFullName(const LLUUID& id, std::string& fullname);
BOOL getFullName(const LLUUID& id, std::string& full_name);
// Reverse lookup of UUID from name
BOOL getUUID(const std::string& first, const std::string& last, LLUUID& id);
BOOL getUUID(const std::string& fullname, LLUUID& id);
// IDEVO Temporary code
// Clean up new-style "bobsmith123 Resident" names to "bobsmith123" for display
static std::string buildFullName(const std::string& first, const std::string& last);
// Clean up legacy "bobsmith123 Resident" to "bobsmith123"
// If name does not contain "Resident" returns it unchanged.
static std::string cleanFullName(const std::string& full_name);
// Converts a standard legacy name to a username
// "bobsmith123 Resident" -> "bobsmith"
// "Random Linden" -> "random.linden"
static std::string buildUsername(const std::string& name);
// Converts a complete display name to a legacy name
// if possible, otherwise returns the input
// "Alias (random.linden)" -> "Random Linden"
// "Something random" -> "Something random"
static std::string buildLegacyName(const std::string& name);
// If available, this method copies the group name into the string
// provided. The caller must allocate at least
@@ -89,16 +117,19 @@ public:
// If the data is currently available, may call the callback immediatly
// otherwise, will request the data, and will call the callback when
// available. There is no garuntee the callback will ever be called.
void get(const LLUUID& id, BOOL is_group, LLCacheNameCallback callback, void* user_data = NULL);
boost::signals2::connection get(const LLUUID& id, bool is_group, const LLCacheNameCallback& callback);
// <edit>
BOOL getIfThere(const LLUUID& id, std::string& fullname, BOOL& is_group);
// </edit>
//<edit>
bool getIfThere(const LLUUID& id, std::string& fullname, BOOL& is_group);
//</edit>
// Convenience method for looking up a group name, so you can
// tell the difference between avatar lookup and group lookup
// in global searches
boost::signals2::connection getGroup(const LLUUID& group_id, const LLCacheNameCallback& callback);
// LEGACY
void getName(const LLUUID& id, LLCacheNameCallback callback, void* user_data = NULL)
{ get(id, FALSE, callback, user_data); }
boost::signals2::connection get(const LLUUID& id, bool is_group, old_callback_t callback, void* user_data);
// This method needs to be called from time to time to send out
// requests.
void processPending();
@@ -109,9 +140,16 @@ public:
// Debugging
void dump(); // Dumps the contents of the cache
void dumpStats(); // Dumps the sizes of the cache and associated queues.
void clear(); // Deletes all entries from the cache
static std::string getDefaultName();
// Returns "Resident", the default last name for SLID-based accounts
// that have no last name.
static std::string getDefaultLastName();
static void localizeCacheName(std::string key, std::string value);
static std::map<std::string, std::string> sCacheName;
private:
class Impl;

View File

@@ -174,10 +174,17 @@ public:
S32 getCurrentSize() const { return (S32)(mCurBufferp - mBufferp); }
S32 getBufferSize() const { return mBufferSize; }
const U8* getBuffer() const { return mBufferp; }
void reset() { mCurBufferp = mBufferp; mWriteEnabled = (mCurBufferp != NULL); }
void freeBuffer() { delete [] mBufferp; mBufferp = mCurBufferp = NULL; mBufferSize = 0; mWriteEnabled = FALSE; }
void assignBuffer(U8 *bufferp, S32 size)
{
//No no no no no! This breaks the paradigm of callers handling buffer allocation/deallocation
//Also, buffers can be on stack! Calling delete[] on such a buffer would be VERY bad.
/*if(mBufferp && mBufferp != bufferp)
{
freeBuffer() ;
}*/
mBufferp = bufferp;
mCurBufferp = bufferp;
mBufferSize = size;

View File

@@ -178,7 +178,7 @@ LLSocket::ptr_t LLSocket::create(EType type, U16 port)
port = PORT_EPHEMERAL;
}
rv->mPort = port;
rv->setOptions();
rv->setNonBlocking();
return rv;
}
@@ -201,7 +201,7 @@ LLSocket::ptr_t LLSocket::create(apr_status_t& status, LLSocket::ptr_t& listen_s
return rv;
}
rv->mPort = PORT_EPHEMERAL;
rv->setOptions();
rv->setNonBlocking();
return rv;
}
@@ -221,10 +221,10 @@ bool LLSocket::blockingConnect(const LLHost& host)
{
return false;
}
apr_socket_timeout_set(mSocket, 1000);
setBlocking(1000);
ll_debug_socket("Blocking connect", mSocket);
if(ll_apr_warn_status(apr_socket_connect(mSocket, sa))) return false;
setOptions();
setNonBlocking();
return true;
}
@@ -246,11 +246,27 @@ LLSocket::~LLSocket()
}
}
void LLSocket::setOptions()
// See http://dev.ariel-networks.com/apr/apr-tutorial/html/apr-tutorial-13.html#ss13.4
// for an explanation of how to get non-blocking sockets and timeouts with
// consistent behavior across platforms.
void LLSocket::setBlocking(S32 timeout)
{
LLMemType m1(LLMemType::MTYPE_IO_TCP);
// set up the socket options
ll_apr_warn_status(apr_socket_timeout_set(mSocket, timeout));
ll_apr_warn_status(apr_socket_opt_set(mSocket, APR_SO_NONBLOCK, 0));
ll_apr_warn_status(apr_socket_opt_set(mSocket, APR_SO_SNDBUF, LL_SEND_BUFFER_SIZE));
ll_apr_warn_status(apr_socket_opt_set(mSocket, APR_SO_RCVBUF, LL_RECV_BUFFER_SIZE));
}
void LLSocket::setNonBlocking()
{
LLMemType m1(LLMemType::MTYPE_IO_TCP);
// set up the socket options
ll_apr_warn_status(apr_socket_timeout_set(mSocket, 0));
ll_apr_warn_status(apr_socket_opt_set(mSocket, APR_SO_NONBLOCK, 1));
ll_apr_warn_status(apr_socket_opt_set(mSocket, APR_SO_SNDBUF, LL_SEND_BUFFER_SIZE));
ll_apr_warn_status(apr_socket_opt_set(mSocket, APR_SO_RCVBUF, LL_RECV_BUFFER_SIZE));
@@ -588,6 +604,7 @@ LLIOPipe::EStatus LLIOServerSocket::process_impl(
{
chain.push_back(LLIOPipe::ptr_t(new LLIOSocketWriter(llsocket)));
pump->addChain(chain, mResponseTimeout);
status = STATUS_OK;
}
else
{

View File

@@ -146,9 +146,16 @@ protected:
LLSocket(void);
/**
* @brief Set default socket options.
* @brief Set default socket options, with SO_NONBLOCK = 0 and a timeout in us.
* @param timeout Number of microseconds to wait on this socket. Any
* negative number means block-forever. TIMEOUT OF 0 IS NON-PORTABLE.
*/
void setOptions();
void setBlocking(S32 timeout);
/**
* @brief Set default socket options, with SO_NONBLOCK = 1 and timeout = 0.
*/
void setNonBlocking();
public:
/**

View File

@@ -1,149 +0,0 @@
// <edit>
#include "linden_common.h"
#include "llnetcanary.h"
#include "llerror.h"
#ifdef _MSC_VER
#include <winsock2.h>
static WSADATA trapWSAData;
#define socklen_t int
#else
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#if LL_DARWIN
#ifndef _SOCKLEN_T
#define _SOCKLEN_T
typedef int socklen_t;
#endif
#endif
extern int errno; //error number
#define SOCKADDR_IN struct sockaddr_in
#define SOCKADDR struct sockaddr
#define SOCKET int
#define INVALID_SOCKET -1
#define SOCKET_ERROR -1
#define SD_BOTH 2
#define closesocket close
#endif
SOCKADDR_IN trapLclAddr;
LLNetCanary::LLNetCanary(int requested_port)
{
mGood = TRUE;
int nRet;
int hSocket;
int snd_size = 400000;
int rec_size = 400000;
int buff_size = 4;
#ifdef _MSC_VER
if(WSAStartup(0x0202, &trapWSAData))
{
S32 err = WSAGetLastError();
WSACleanup();
llwarns << "WSAStartup() failure: " << err << llendl;
mGood = FALSE;
return;
}
#endif
// Get a datagram socket
hSocket = (int)socket(AF_INET, SOCK_DGRAM, 0);
if (hSocket == INVALID_SOCKET)
{
#ifdef _MSC_VER
S32 err = WSAGetLastError();
WSACleanup();
#else
S32 err = errno;
#endif
mGood = FALSE;
llwarns << "socket() failure: " << err << llendl;
return;
}
// Name the socket (assign the local port number to receive on)
trapLclAddr.sin_family = AF_INET;
trapLclAddr.sin_addr.s_addr = htonl(INADDR_ANY);
trapLclAddr.sin_port = htons(requested_port);
//llinfos << "bind() port: " << requested_port << llendl;
nRet = bind(hSocket, (struct sockaddr*) &trapLclAddr, sizeof(trapLclAddr));
if (nRet == SOCKET_ERROR)
{
#ifdef _MSC_VER
S32 err = WSAGetLastError();
WSACleanup();
#else
S32 err = errno;
#endif
mGood = FALSE;
llwarns << "bind() failed: " << err << llendl;
return;
}
// Find out what address we got
SOCKADDR_IN socket_address;
socklen_t socket_address_size = sizeof(socket_address);
getsockname(hSocket, (SOCKADDR*) &socket_address, &socket_address_size);
mPort = ntohs(socket_address.sin_port);
//llinfos << "got port " << mPort << llendl;
// Set socket to be non-blocking
#ifdef _MSC_VER
unsigned long argp = 1;
nRet = ioctlsocket (hSocket, FIONBIO, &argp);
#else
nRet = fcntl(hSocket, F_SETFL, O_NONBLOCK);
#endif
if (nRet == SOCKET_ERROR)
{
#ifdef _MSC_VER
S32 err = WSAGetLastError();
WSACleanup();
#else
S32 err = errno;
#endif
mGood = FALSE;
llwarns << "Failed to set socket non-blocking, Err: " << err << llendl;
return;
}
// set a large receive buffer
nRet = setsockopt(hSocket, SOL_SOCKET, SO_RCVBUF, (char *)&rec_size, buff_size);
if (nRet)
{
llinfos << "Can't set receive buffer size!" << llendl;
}
// set a large send buffer
nRet = setsockopt(hSocket, SOL_SOCKET, SO_SNDBUF, (char *)&snd_size, buff_size);
if (nRet)
{
llinfos << "Can't set send buffer size!" << llendl;
}
//getsockopt(hSocket, SOL_SOCKET, SO_RCVBUF, (char *)&rec_size, &buff_size);
//getsockopt(hSocket, SOL_SOCKET, SO_SNDBUF, (char *)&snd_size, &buff_size);
//LL_DEBUGS("AppInit") << "startNet - receive buffer size : " << rec_size << LL_ENDL;
//LL_DEBUGS("AppInit") << "startNet - send buffer size : " << snd_size << LL_ENDL;
mSocket = hSocket;
}
LLNetCanary::~LLNetCanary()
{
if(mGood)
{
if(mSocket)
{
shutdown(mSocket, SD_BOTH);
closesocket(mSocket);
}
#ifdef _MSC_VER
WSACleanup();
#endif
}
}
// </edit>

View File

@@ -1,25 +0,0 @@
// <edit>
#ifndef LL_LLNETCANARY_H
#define LL_LLNETCANARY_H
#include "stdtypes.h"
#include <string>
class LLNetCanary
{
public:
LLNetCanary(int requested_port);
~LLNetCanary();
BOOL mGood;
S32 mSocket;
U16 mPort;
U8 mBuffer[8192];
typedef struct
{
F64 time; // LLTimer::getElapsedSeconds();
//U8 message[4];
U32 message;
U32 points;
std::string name;
} entry;
};
#endif
// </edit>

View File

@@ -52,10 +52,13 @@ static const U32 HTTP_STATUS_PIPE_ERROR = 499;
* String constants
*/
const std::string CONTEXT_DEST_URI_SD_LABEL("dest_uri");
const std::string CONTEXT_TRANSFERED_BYTES("transfered_bytes");
static size_t headerCallback(void* data, size_t size, size_t nmemb, void* user);
/**
* class LLURLRequestDetail
*/
@@ -99,6 +102,26 @@ LLURLRequestDetail::~LLURLRequestDetail()
* class LLURLRequest
*/
// static
std::string LLURLRequest::actionAsVerb(LLURLRequest::ERequestAction action)
{
static const std::string VERBS[] =
{
"(invalid)",
"HEAD",
"GET",
"PUT",
"POST",
"DELETE",
"MOVE"
};
if(((S32)action <=0) || ((S32)action >= REQUEST_ACTION_COUNT))
{
return VERBS[0];
}
return VERBS[action];
}
LLURLRequest::LLURLRequest(LLURLRequest::ERequestAction action) :
mAction(action)
{
@@ -128,6 +151,10 @@ void LLURLRequest::setURL(const std::string& url)
mDetail->mURL = url;
}
std::string LLURLRequest::getURL() const
{
return mDetail->mURL;
}
void LLURLRequest::addHeader(const char* header)
{
LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
@@ -201,6 +228,11 @@ void LLURLRequest::useProxy(const std::string &proxy)
mDetail->mCurlRequest->setoptString(CURLOPT_PROXY, proxy);
}
void LLURLRequest::allowCookies()
{
mDetail->mCurlRequest->setoptString(CURLOPT_COOKIEFILE, "");
}
// virtual
LLIOPipe::EStatus LLURLRequest::handleError(
LLIOPipe::EStatus status,
@@ -232,8 +264,30 @@ LLIOPipe::EStatus LLURLRequest::process_impl(
PUMP_DEBUG;
LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
//llinfos << "LLURLRequest::process_impl()" << llendl;
if(!buffer) return STATUS_ERROR;
if(!mDetail) return STATUS_ERROR; //Seems to happen on occasion. Need to hunt down why.
if (!buffer) return STATUS_ERROR;
if (!mDetail) return STATUS_ERROR; //Seems to happen on occasion. Need to hunt down why.
// we're still waiting or prcessing, check how many
// bytes we have accumulated.
const S32 MIN_ACCUMULATION = 100000;
if(pump && (mDetail->mByteAccumulator > MIN_ACCUMULATION))
{
// This is a pretty sloppy calculation, but this
// tries to make the gross assumption that if data
// is coming in at 56kb/s, then this transfer will
// probably succeed. So, if we're accumlated
// 100,000 bytes (MIN_ACCUMULATION) then let's
// give this client another 2s to complete.
const F32 TIMEOUT_ADJUSTMENT = 2.0f;
mDetail->mByteAccumulator = 0;
pump->adjustTimeoutSeconds(TIMEOUT_ADJUSTMENT);
lldebugs << "LLURLRequest adjustTimeoutSeconds for request: " << mDetail->mURL << llendl;
if (mState == STATE_INITIALIZED)
{
llinfos << "LLURLRequest adjustTimeoutSeconds called during upload" << llendl;
}
}
switch(mState)
{
case STATE_INITIALIZED:
@@ -272,27 +326,14 @@ LLIOPipe::EStatus LLURLRequest::process_impl(
bool newmsg = mDetail->mCurlRequest->getResult(&result);
if(!newmsg)
{
// we're still waiting or prcessing, check how many
// bytes we have accumulated.
const S32 MIN_ACCUMULATION = 100000;
if(pump && (mDetail->mByteAccumulator > MIN_ACCUMULATION))
{
// This is a pretty sloppy calculation, but this
// tries to make the gross assumption that if data
// is coming in at 56kb/s, then this transfer will
// probably succeed. So, if we're accumlated
// 100,000 bytes (MIN_ACCUMULATION) then let's
// give this client another 2s to complete.
const F32 TIMEOUT_ADJUSTMENT = 2.0f;
mDetail->mByteAccumulator = 0;
pump->adjustTimeoutSeconds(TIMEOUT_ADJUSTMENT);
}
// keep processing
break;
}
mState = STATE_HAVE_RESPONSE;
context[CONTEXT_REQUEST][CONTEXT_TRANSFERED_BYTES] = mRequestTransferedBytes;
context[CONTEXT_RESPONSE][CONTEXT_TRANSFERED_BYTES] = mResponseTransferedBytes;
lldebugs << this << "Setting context to " << context << llendl;
switch(result)
{
case CURLE_OK:
@@ -339,10 +380,16 @@ LLIOPipe::EStatus LLURLRequest::process_impl(
// we already stuffed everything into channel in in the curl
// callback, so we are done.
eos = true;
context[CONTEXT_REQUEST][CONTEXT_TRANSFERED_BYTES] = mRequestTransferedBytes;
context[CONTEXT_RESPONSE][CONTEXT_TRANSFERED_BYTES] = mResponseTransferedBytes;
lldebugs << this << "Setting context to " << context << llendl;
return STATUS_DONE;
default:
PUMP_DEBUG;
context[CONTEXT_REQUEST][CONTEXT_TRANSFERED_BYTES] = mRequestTransferedBytes;
context[CONTEXT_RESPONSE][CONTEXT_TRANSFERED_BYTES] = mResponseTransferedBytes;
lldebugs << this << "Setting context to " << context << llendl;
return STATUS_ERROR;
}
}
@@ -355,6 +402,8 @@ void LLURLRequest::initialize()
mDetail->mCurlRequest->setopt(CURLOPT_NOSIGNAL, 1);
mDetail->mCurlRequest->setWriteCallback(&downCallback, (void*)this);
mDetail->mCurlRequest->setReadCallback(&upCallback, (void*)this);
mRequestTransferedBytes = 0;
mResponseTransferedBytes = 0;
}
bool LLURLRequest::configure()
@@ -375,6 +424,9 @@ bool LLURLRequest::configure()
case HTTP_GET:
mDetail->mCurlRequest->setopt(CURLOPT_HTTPGET, 1);
mDetail->mCurlRequest->setopt(CURLOPT_FOLLOWLOCATION, 1);
// Set Accept-Encoding to allow response compression
mDetail->mCurlRequest->setoptString(CURLOPT_ENCODING, "");
rv = true;
break;
@@ -399,6 +451,9 @@ bool LLURLRequest::configure()
// Set the handle for an http post
mDetail->mCurlRequest->setPost(NULL, bytes);
// Set Accept-Encoding to allow response compression
mDetail->mCurlRequest->setoptString(CURLOPT_ENCODING, "");
rv = true;
break;
@@ -457,6 +512,7 @@ size_t LLURLRequest::downCallback(
req->mDetail->mChannels.out(),
(U8*)data,
bytes);
req->mResponseTransferedBytes += bytes;
req->mDetail->mByteAccumulator += bytes;
return bytes;
}
@@ -480,6 +536,7 @@ size_t LLURLRequest::upCallback(
req->mDetail->mLastRead,
(U8*)data,
bytes);
req->mRequestTransferedBytes += bytes;
return bytes;
}

View File

@@ -45,6 +45,11 @@
#include "llchainio.h"
#include "llerror.h"
extern const std::string CONTEXT_REQUEST;
extern const std::string CONTEXT_DEST_URI_SD_LABEL;
extern const std::string CONTEXT_RESPONSE;
extern const std::string CONTEXT_TRANSFERED_BYTES;
class LLURLRequestDetail;
class LLURLRequestComplete;
@@ -81,6 +86,11 @@ public:
REQUEST_ACTION_COUNT
};
/**
* @brief Turn the requst action into an http verb.
*/
static std::string actionAsVerb(ERequestAction action);
/**
* @brief Constructor.
*
@@ -114,7 +124,7 @@ public:
*
*/
void setURL(const std::string& url);
std::string getURL() const;
/**
* @brief Add a header to the http post.
*
@@ -173,6 +183,11 @@ public:
*/
void useProxy(const std::string& proxy);
/**
* @brief Turn on cookie handling for this request with CURLOPT_COOKIEFILE.
*/
void allowCookies();
public:
/**
* @brief Give this pipe a chance to handle a generated error
@@ -203,6 +218,8 @@ protected:
ERequestAction mAction;
LLURLRequestDetail* mDetail;
LLIOPipe::ptr_t mCompletionCallback;
S32 mRequestTransferedBytes;
S32 mResponseTransferedBytes;
private:
/**
@@ -351,62 +368,6 @@ protected:
};
/**
* @class LLURLRequestClientFactory
* @brief Template class to build url request based client chains
*
* This class eases construction of a basic sd rpc client. Here is an
* example of it's use:
* <code>
* class LLUsefulService : public LLService { ... }<br>
* LLService::registerCreator(<br>
* "useful",<br>
* LLService::creator_t(new LLURLRequestClientFactory<LLUsefulService>))<br>
* </code>
*
* This class should work, but I never got around to using/testing it.
*
*/
#if 0
template<class Client>
class LLURLRequestClientFactory : public LLChainIOFactory
{
public:
LLURLRequestClientFactory(LLURLRequest::ERequestAction action) {}
LLURLRequestClientFactory(
LLURLRequest::ERequestAction action,
const std::string& fixed_url) :
mAction(action),
mURL(fixed_url)
{
}
virtual bool build(LLPumpIO::chain_t& chain, LLSD context) const
{
lldebugs << "LLURLRequestClientFactory::build" << llendl;
LLIOPipe::ptr_t service(new Client);
chain.push_back(service);
LLURLRequest* http(new LLURLRequest(mAction));
LLIOPipe::ptr_t http_pipe(http);
// *FIX: how do we know the content type?
//http->addHeader("Content-Type: text/llsd");
if(mURL.empty())
{
chain.push_back(LLIOPipe::ptr_t(new LLContextURLExtractor(http)));
}
else
{
http->setURL(mURL);
}
chain.push_back(http_pipe);
chain.push_back(service);
return true;
}
protected:
LLURLRequest::ERequestAction mAction;
std::string mURL;
};
#endif
/**
* External constants

View File

@@ -61,7 +61,7 @@ public:
LLMeanCollisionData(LLMeanCollisionData *mcd)
: mVictim(mcd->mVictim), mPerp(mcd->mPerp), mTime(mcd->mTime), mType(mcd->mType), mMag(mcd->mMag),
mFirstName(mcd->mFirstName), mLastName(mcd->mLastName)
mFullName(mcd->mFullName)
{
}
@@ -95,8 +95,7 @@ public:
time_t mTime;
EMeanCollisionType mType;
F32 mMag;
std::string mFirstName;
std::string mLastName;
std::string mFullName;
};

View File

@@ -67,9 +67,6 @@
#include "llstoredmessage.h"
#include "llsocks5.h"
// <edit>
#include "llnetcanary.h"
// </edit>
const U32 MESSAGE_MAX_STRINGS_LENGTH = 64;
const U32 MESSAGE_NUMBER_OF_HASH_BUCKETS = 8192;

View File

@@ -744,7 +744,11 @@ BOOL LLPrimitive::setVolume(const LLVolumeParams &volume_params, const S32 detai
setNumTEs(mVolumep->getNumFaces());
return TRUE;
}
#if 0
// #if 0'd out by davep
// this is a lot of cruft to set texture entry values that just stay the same for LOD switch
// or immediately get overridden by an object update message, also crashes occasionally
U32 old_face_mask = mVolumep->mFaceMask;
S32 face_bit = 0;
@@ -942,6 +946,13 @@ BOOL LLPrimitive::setVolume(const LLVolumeParams &volume_params, const S32 detai
setTE(te_num, *(old_tes.getTexture(face_mapping[face_bit])));
}
}
#else
// build the new object
sVolumeManager->unrefVolume(mVolumep);
mVolumep = volumep;
setNumTEs(mVolumep->getNumFaces());
#endif
return TRUE;
}

View File

@@ -1330,10 +1330,6 @@ void LLGLState::checkTextureChannels(const std::string& msg)
}
}
GLint maxTextureUnits = 0;
glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &maxTextureUnits);
stop_glerror();
static const char* label[] =
{
"GL_TEXTURE_2D",
@@ -1366,7 +1362,7 @@ void LLGLState::checkTextureChannels(const std::string& msg)
glh::matrix4f identity;
identity.identity();
for (GLint i = 1; i < maxTextureUnits; i++)
for (GLint i = 1; i < gGLManager.mNumTextureUnits; i++)
{
gGL.getTexUnit(i)->activate();
glClientActiveTextureARB(GL_TEXTURE0_ARB+i);
@@ -1426,8 +1422,27 @@ void LLGLState::checkTextureChannels(const std::string& msg)
gFailLog << "Texture matrix " << i << " is not identity." << std::endl;
}
}
{
GLint tex = 0;
stop_glerror();
glGetIntegerv(GL_TEXTURE_BINDING_2D, &tex);
stop_glerror();
if (tex != 0)
{
error = TRUE;
LL_WARNS("RenderState") << "Texture channel " << i << " still has texture " << tex << " bound." << llendl;
if (gDebugSession)
{
gFailLog << "Texture channel " << i << " still has texture " << tex << " bound." << std::endl;
}
}
}
}
stop_glerror();
gGL.getTexUnit(0)->activate();
glClientActiveTextureARB(GL_TEXTURE0_ARB);
stop_glerror();

View File

@@ -1015,12 +1015,17 @@ void LLImageGL::generateTextures(S32 numTextures, U32 *textures)
}
// static
void LLImageGL::deleteTextures(S32 numTextures, U32 *textures)
void LLImageGL::deleteTextures(S32 numTextures, U32 *textures, bool immediate)
{
for (S32 i = 0; i < numTextures; i++)
{
sDeadTextureList.push_back(textures[i]);
}
if (immediate)
{
LLImageGL::deleteDeadTextures();
}
}
// static

View File

@@ -102,7 +102,7 @@ public:
// These 3 functions currently wrap glGenTextures(), glDeleteTextures(), and glTexImage2D()
// for tracking purposes and will be deprecated in the future
static void generateTextures(S32 numTextures, U32 *textures);
static void deleteTextures(S32 numTextures, U32 *textures);
static void deleteTextures(S32 numTextures, U32 *textures, bool immediate = false);
static void setManualImage(U32 target, S32 miplevel, S32 intformat, S32 width, S32 height, U32 pixformat, U32 pixtype, const void *pixels);
BOOL createGLTexture() ;

View File

@@ -261,7 +261,7 @@ void LLRenderTarget::release()
}
else
{
LLImageGL::deleteTextures(1, &mDepth);
LLImageGL::deleteTextures(1, &mDepth, true);
stop_glerror();
}
mDepth = 0;
@@ -290,7 +290,7 @@ void LLRenderTarget::release()
if (mTex.size() > 0)
{
LLImageGL::deleteTextures(mTex.size(), &mTex[0]);
LLImageGL::deleteTextures(mTex.size(), &mTex[0], true);
mTex.clear();
}

View File

@@ -255,7 +255,8 @@ void LLDragHandleTop::reshapeTitleBox()
getRect().getWidth() - LEFT_PAD - RIGHT_PAD,
title_height);
getTitleBox()->setRect( title_rect );
// calls reshape on mTitleBox
getTitleBox()->setShape( title_rect );
}
void LLDragHandleTop::reshape(S32 width, S32 height, BOOL called_from_parent)
@@ -337,14 +338,14 @@ BOOL LLDragHandle::handleHover(S32 x, S32 y, MASK mask)
LLView* snap_view = getParent()->findSnapRect(new_rect, mouse_dir, SNAP_PARENT_AND_SIBLINGS, sSnapMargin);
getParent()->snappedTo(snap_view);
getParent()->setSnappedTo(snap_view);
delta_x = new_rect.mLeft - pre_snap_x;
delta_y = new_rect.mBottom - pre_snap_y;
translated_rect.translate(delta_x, delta_y);
// restore original rect so delta are detected, then call user reshape method to handle snapped floaters, etc
getParent()->setRect(original_rect);
getParent()->userSetShape(translated_rect);
getParent()->setShape(translated_rect,true);
mDragLastScreenX += delta_x;
mDragLastScreenY += delta_y;

View File

@@ -763,7 +763,7 @@ BOOL LLFloater::canSnapTo(const LLView* other_view)
return LLPanel::canSnapTo(other_view);
}
void LLFloater::snappedTo(const LLView* snap_view)
void LLFloater::setSnappedTo(const LLView* snap_view)
{
if (!snap_view || snap_view == getParent())
{
@@ -780,10 +780,10 @@ void LLFloater::snappedTo(const LLView* snap_view)
}
}
void LLFloater::userSetShape(const LLRect& new_rect)
void LLFloater::handleReshape(const LLRect& new_rect, bool by_user)
{
const LLRect old_rect = getRect();
LLView::userSetShape(new_rect);
LLView::handleReshape(new_rect, by_user);
// if not minimized, adjust all snapped dependents to new shape
if (!isMinimized())
@@ -818,7 +818,7 @@ void LLFloater::userSetShape(const LLRect& new_rect)
delta_y += new_rect.mBottom - old_rect.mBottom;
dependent_rect.translate(delta_x, delta_y);
floaterp->userSetShape(dependent_rect);
floaterp->setShape(dependent_rect, by_user);
}
}
}
@@ -2274,11 +2274,11 @@ void LLFloaterView::adjustToFitScreen(LLFloater* floater, BOOL allow_partial_out
// floater is hosted elsewhere, so ignore
return;
}
S32 screen_width = getSnapRect().getWidth();
S32 screen_height = getSnapRect().getHeight();
// convert to local coordinate frame
LLRect snap_rect_local = getLocalSnapRect();
LLRect::tCoordType screen_width = getSnapRect().getWidth();
LLRect::tCoordType screen_height = getSnapRect().getHeight();
// only automatically resize non-minimized, resizable floaters
if( floater->isResizable() && !floater->isMinimized() )
{
LLRect view_rect = floater->getRect();
@@ -2302,7 +2302,11 @@ void LLFloaterView::adjustToFitScreen(LLFloater* floater, BOOL allow_partial_out
new_width = llmax(new_width, min_width);
new_height = llmax(new_height, min_height);
floater->reshape( new_width, new_height, TRUE );
LLRect new_rect;
new_rect.setLeftTopAndSize(view_rect.mLeft,view_rect.mTop,new_width, new_height);
floater->setShape(new_rect);
if (floater->followsRight())
{
floater->translate(old_width - new_width, 0);
@@ -2316,7 +2320,7 @@ void LLFloaterView::adjustToFitScreen(LLFloater* floater, BOOL allow_partial_out
}
// move window fully onscreen
if (floater->translateIntoRect( snap_rect_local, allow_partial_outside ))
if (floater->translateIntoRect( getLocalSnapRect(), allow_partial_outside ))
{
floater->clearSnapTarget();
}

View File

@@ -128,9 +128,9 @@ public:
static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory);
void initFloaterXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory, BOOL open = TRUE);
/*virtual*/ void userSetShape(const LLRect& new_rect);
/*virtual*/ void handleReshape(const LLRect& new_rect, bool by_user = false);
/*virtual*/ BOOL canSnapTo(const LLView* other_view);
/*virtual*/ void snappedTo(const LLView* snap_view);
/*virtual*/ void setSnappedTo(const LLView* snap_view);
/*virtual*/ void setFocus( BOOL b );
/*virtual*/ void setIsChrome(BOOL is_chrome);

View File

@@ -817,7 +817,7 @@ void LLMenuItemCallGL::setEnabledControl(std::string enabled_control, LLView *co
control = context->findControl(enabled_control);
llassert_always(control);
}
control->getSignal()->connect(boost::bind(&LLView::controlListener, _1, getHandle(), std::string("enabled")));
control->getSignal()->connect(boost::bind(&LLView::controlListener, _2, getHandle(), std::string("enabled")));
setEnabled(control->getValue());
}
}
@@ -834,7 +834,7 @@ void LLMenuItemCallGL::setVisibleControl(std::string visible_control, LLView *co
control = context->findControl(visible_control);
llassert_always(control);
}
control->getSignal()->connect(boost::bind(&LLView::controlListener, _1, getHandle(), std::string("visible")));
control->getSignal()->connect(boost::bind(&LLView::controlListener, _2, getHandle(), std::string("visible")));
setVisible(control->getValue());
}
}
@@ -990,7 +990,7 @@ void LLMenuItemCheckGL::setCheckedControl(std::string checked_control, LLView *c
control = context->findControl(checked_control);
llassert_always(control);
}
control->getSignal()->connect(boost::bind(&LLView::controlListener, _1, getHandle(), std::string("value")));
control->getSignal()->connect(boost::bind(&LLView::controlListener, _2, getHandle(), std::string("value")));
mChecked = control->getValue();
}
}

View File

@@ -1344,7 +1344,7 @@ bool LLNotifications::loadTemplates()
if (!sound.empty())
{
// TODO: test for bad sound effect name / missing effect
pTemplate->mSoundEffect = LLUUID(LLUI::sConfigGroup->getString(sound.c_str()));
pTemplate->mSoundEffect = LLUUID(LLUI::sConfigGroup->findString(sound.c_str()));
}
for (LLXMLNodePtr child = item->getFirstChild();

View File

@@ -506,7 +506,7 @@ BOOL LLPanel::initPanelXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *f
// override rectangle with embedding parameters as provided
createRect(node, new_rect, parent);
setOrigin(new_rect.mLeft, new_rect.mBottom);
reshape(new_rect.getWidth(), new_rect.getHeight());
setShape(new_rect);
// optionally override follows flags from including nodes
parseFollowsFlags(node);
}

View File

@@ -185,30 +185,31 @@ BOOL LLResizeBar::handleHover(S32 x, S32 y, MASK mask)
if (mSnappingEnabled)
{
static LLCachedControl<S32> snap_margin (*LLUI::sConfigGroup,"SnapMargin", 0);
switch( mSide )
{
case LEFT:
snap_view = mResizingView->findSnapEdge(scaled_rect.mLeft, mouse_dir, SNAP_LEFT, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
snap_view = mResizingView->findSnapEdge(scaled_rect.mLeft, mouse_dir, SNAP_LEFT, SNAP_PARENT_AND_SIBLINGS, snap_margin);
break;
case TOP:
snap_view = mResizingView->findSnapEdge(scaled_rect.mTop, mouse_dir, SNAP_TOP, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
snap_view = mResizingView->findSnapEdge(scaled_rect.mTop, mouse_dir, SNAP_TOP, SNAP_PARENT_AND_SIBLINGS, snap_margin);
break;
case RIGHT:
snap_view = mResizingView->findSnapEdge(scaled_rect.mRight, mouse_dir, SNAP_RIGHT, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
snap_view = mResizingView->findSnapEdge(scaled_rect.mRight, mouse_dir, SNAP_RIGHT, SNAP_PARENT_AND_SIBLINGS, snap_margin);
break;
case BOTTOM:
snap_view = mResizingView->findSnapEdge(scaled_rect.mBottom, mouse_dir, SNAP_BOTTOM, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
snap_view = mResizingView->findSnapEdge(scaled_rect.mBottom, mouse_dir, SNAP_BOTTOM, SNAP_PARENT_AND_SIBLINGS, snap_margin);
break;
}
}
// register "snap" behavior with snapped view
mResizingView->snappedTo(snap_view);
mResizingView->setSnappedTo(snap_view);
// restore original rectangle so the appropriate changes are detected
mResizingView->setRect(orig_rect);
// change view shape as user operation
mResizingView->userSetShape(scaled_rect);
mResizingView->setShape(scaled_rect, true);
// update last valid mouse cursor position based on resized view's actual size
LLRect new_rect = mResizingView->getRect();
@@ -284,7 +285,7 @@ BOOL LLResizeBar::handleDoubleClick(S32 x, S32 y, MASK mask)
break;
}
mResizingView->userSetShape(scaled_rect);
mResizingView->setShape(scaled_rect,true);
}
return TRUE;

View File

@@ -205,36 +205,37 @@ BOOL LLResizeHandle::handleHover(S32 x, S32 y, MASK mask)
LLView* snap_view = NULL;
LLView* test_view = NULL;
static LLCachedControl<S32> snap_margin (*LLUI::sConfigGroup,"SnapMargin", 0);
// now do snapping
switch(mCorner)
{
case LEFT_TOP:
snap_view = resizing_view->findSnapEdge(scaled_rect.mLeft, mouse_dir, SNAP_LEFT, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
test_view = resizing_view->findSnapEdge(scaled_rect.mTop, mouse_dir, SNAP_TOP, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
snap_view = resizing_view->findSnapEdge(scaled_rect.mLeft, mouse_dir, SNAP_LEFT, SNAP_PARENT_AND_SIBLINGS, snap_margin);
test_view = resizing_view->findSnapEdge(scaled_rect.mTop, mouse_dir, SNAP_TOP, SNAP_PARENT_AND_SIBLINGS, snap_margin);
if (!snap_view)
{
snap_view = test_view;
}
break;
case LEFT_BOTTOM:
snap_view = resizing_view->findSnapEdge(scaled_rect.mLeft, mouse_dir, SNAP_LEFT, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
test_view = resizing_view->findSnapEdge(scaled_rect.mBottom, mouse_dir, SNAP_BOTTOM, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
snap_view = resizing_view->findSnapEdge(scaled_rect.mLeft, mouse_dir, SNAP_LEFT, SNAP_PARENT_AND_SIBLINGS, snap_margin);
test_view = resizing_view->findSnapEdge(scaled_rect.mBottom, mouse_dir, SNAP_BOTTOM, SNAP_PARENT_AND_SIBLINGS, snap_margin);
if (!snap_view)
{
snap_view = test_view;
}
break;
case RIGHT_TOP:
snap_view = resizing_view->findSnapEdge(scaled_rect.mRight, mouse_dir, SNAP_RIGHT, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
test_view = resizing_view->findSnapEdge(scaled_rect.mTop, mouse_dir, SNAP_TOP, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
snap_view = resizing_view->findSnapEdge(scaled_rect.mRight, mouse_dir, SNAP_RIGHT, SNAP_PARENT_AND_SIBLINGS, snap_margin);
test_view = resizing_view->findSnapEdge(scaled_rect.mTop, mouse_dir, SNAP_TOP, SNAP_PARENT_AND_SIBLINGS, snap_margin);
if (!snap_view)
{
snap_view = test_view;
}
break;
case RIGHT_BOTTOM:
snap_view = resizing_view->findSnapEdge(scaled_rect.mRight, mouse_dir, SNAP_RIGHT, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
test_view = resizing_view->findSnapEdge(scaled_rect.mBottom, mouse_dir, SNAP_BOTTOM, SNAP_PARENT_AND_SIBLINGS, LLUI::sConfigGroup->getS32("SnapMargin"));
snap_view = resizing_view->findSnapEdge(scaled_rect.mRight, mouse_dir, SNAP_RIGHT, SNAP_PARENT_AND_SIBLINGS, snap_margin);
test_view = resizing_view->findSnapEdge(scaled_rect.mBottom, mouse_dir, SNAP_BOTTOM, SNAP_PARENT_AND_SIBLINGS, snap_margin);
if (!snap_view)
{
snap_view = test_view;
@@ -243,13 +244,13 @@ BOOL LLResizeHandle::handleHover(S32 x, S32 y, MASK mask)
}
// register "snap" behavior with snapped view
resizing_view->snappedTo(snap_view);
resizing_view->setSnappedTo(snap_view);
// reset parent rect
resizing_view->setRect(orig_rect);
// translate and scale to new shape
resizing_view->userSetShape(scaled_rect);
resizing_view->setShape(scaled_rect,true);
// update last valid mouse cursor position based on resized view's actual size
LLRect new_rect = resizing_view->getRect();

View File

@@ -3833,7 +3833,7 @@ BOOL LLColumnHeader::handleDoubleClick(S32 x, S32 y, MASK mask)
// reshape column to max content width
LLRect column_rect = getRect();
column_rect.mRight = column_rect.mLeft + mColumn->mMaxContentWidth;
userSetShape(column_rect);
setShape(column_rect,true);
}
else
{
@@ -4045,7 +4045,7 @@ LLView* LLColumnHeader::findSnapEdge(S32& new_edge_val, const LLCoordGL& mouse_d
return this;
}
void LLColumnHeader::userSetShape(const LLRect& new_rect)
void LLColumnHeader::handleReshape(const LLRect& new_rect, bool by_user)
{
S32 new_width = new_rect.getWidth();
S32 delta_width = new_width - (getRect().getWidth() /*+ mColumn->mParentCtrl->getColumnPadding()*/);

View File

@@ -271,7 +271,7 @@ public:
/*virtual*/ void showList();
/*virtual*/ LLView* findSnapEdge(S32& new_edge_val, const LLCoordGL& mouse_dir, ESnapEdge snap_edge, ESnapType snap_type, S32 threshold, S32 padding);
/*virtual*/ void userSetShape(const LLRect& new_rect);
/*virtual*/ void handleReshape(const LLRect& new_rect, bool by_user = false);
void setImage(const std::string &image_name);
void setImageOverlay(const std::string &overlay_image, LLFontGL::HAlign alignment = LLFontGL::HCENTER, const LLColor4& color = LLColor4::white);

View File

@@ -1579,7 +1579,7 @@ void LLUI::initClass(LLControlGroup* config,
LLFontGL::sShadowColor = colors->getColor("ColorDropShadow");
LLUI::sShowXUINames = LLUI::sConfigGroup->getBOOL("ShowXUINames");
LLUI::sConfigGroup->getControl("ShowXUINames")->getSignal()->connect(&handleShowXUINamesChanged);
LLUI::sConfigGroup->getControl("ShowXUINames")->getSignal()->connect(boost::bind(&handleShowXUINamesChanged,_2));
}
void LLUI::cleanupClass()

View File

@@ -678,7 +678,7 @@ BOOL LLView::canSnapTo(const LLView* other_view)
}
// virtual
void LLView::snappedTo(const LLView* snap_view)
void LLView::setSnappedTo(const LLView* snap_view)
{
}
@@ -2135,7 +2135,12 @@ const LLCtrlQuery & LLView::getFocusRootsQuery()
}
void LLView::userSetShape(const LLRect& new_rect)
void LLView::setShape(const LLRect& new_rect, bool by_user)
{
handleReshape(new_rect, by_user);
}
void LLView::handleReshape(const LLRect& new_rect, bool by_user)
{
reshape(new_rect.getWidth(), new_rect.getHeight());
translate(new_rect.mLeft - getRect().mLeft, new_rect.mBottom - getRect().mBottom);
@@ -2820,7 +2825,7 @@ bool LLView::setControlValue(const LLSD& value)
std::string ctrlname = getControlName();
if (!ctrlname.empty())
{
LLUI::sConfigGroup->setValue(ctrlname, value);
LLUI::sConfigGroup->setUntypedValue(ctrlname, value);
return true;
}
return false;
@@ -2848,7 +2853,7 @@ void LLView::setControlName(const std::string& control_name, LLView *context)
if (control)
{
mControlName = control_name;
mControlConnection = control->getSignal()->connect(boost::bind(&controlListener, _1, getHandle(), std::string("value")));
mControlConnection = control->getSignal()->connect(boost::bind(&controlListener, _2, getHandle(), std::string("value")));
setValue(control->getValue());
}
}

View File

@@ -104,14 +104,14 @@ virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
LLUICtrl, et. al.
virtual void translate( S32 x, S32 y );
LLMenuGL
virtual void userSetShape(const LLRect& new_rect);
virtual void handleReshape(const LLRect& new_rect, bool by_user = false);
LLFloater, LLScrollLIstVtrl
virtual LLView* findSnapRect(LLRect& new_rect, const LLCoordGL& mouse_dir, LLView::ESnapType snap_type, S32 threshold, S32 padding = 0);
virtual LLView* findSnapEdge(S32& new_edge_val, const LLCoordGL& mouse_dir, ESnapEdge snap_edge, ESnapType snap_type, S32 threshold, S32 padding = 0);
LLScrollListCtrl
virtual BOOL canSnapTo(const LLView* other_view) { return other_view != this && other_view->getVisible(); }
LLFloater
virtual void snappedTo(const LLView* snap_view) {}
virtual void setSnappedTo(const LLView* snap_view) {}
LLFloater
virtual BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent);
*
@@ -389,13 +389,13 @@ public:
BOOL translateIntoRect( const LLRect& constraint, BOOL allow_partial_outside );
void centerWithin(const LLRect& bounds);
virtual void userSetShape(const LLRect& new_rect);
void setShape(const LLRect& new_rect, bool by_user = false);
virtual LLView* findSnapRect(LLRect& new_rect, const LLCoordGL& mouse_dir, LLView::ESnapType snap_type, S32 threshold, S32 padding = 0);
virtual LLView* findSnapEdge(S32& new_edge_val, const LLCoordGL& mouse_dir, ESnapEdge snap_edge, ESnapType snap_type, S32 threshold, S32 padding = 0);
virtual BOOL canSnapTo(const LLView* other_view);
virtual void snappedTo(const LLView* snap_view);
virtual void setSnappedTo(const LLView* snap_view);
// inherited from LLFocusableElement
/* virtual */ BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent);
@@ -586,7 +586,7 @@ public:
static BOOL deleteViewByHandle(LLHandle<LLView> handle);
static LLWindow* getWindow(void) { return LLUI::sWindow; }
virtual void handleReshape(const LLRect& rect, bool by_user);
protected:
virtual BOOL handleKeyHere(KEY key, MASK mask);
virtual BOOL handleUnicodeCharHere(llwchar uni_char);

View File

@@ -128,6 +128,14 @@ bool LLDirIterator::Impl::next(std::string &fname)
return found;
}
/**
Converts the incoming glob into a regex. This involves
converting incoming glob expressions to regex equivilents and
at the same time, escaping any regex meaningful characters which
do not have glob meaning, i.e.
.()+|^$
in the input.
*/
std::string glob_to_regex(const std::string& glob)
{
std::string regex;
@@ -174,16 +182,16 @@ std::string glob_to_regex(const std::string& glob)
case '!':
regex+= square_brace_open ? '^' : c;
break;
case '.': // This collection have different regex meaning
case '^': // And so need escaping
case '(':
case '.': // This collection have different regex meaning
case '^': // and so need escaping.
case '(':
case ')':
case '+':
case '|':
case '$':
regex+='\\';
regex += '\\';
default:
regex+=c;
regex += c;
break;
}

View File

@@ -53,9 +53,47 @@
#if LL_RELEASE_WITH_DEBUG_INFO || LL_DEBUG
#define CONTROL_ERRS LL_ERRS("ControlErrors")
#else
#define CONTROL_ERRS LL_WARNS("ControlErrors")
#define CONTROL_ERRS LL_ERRS("ControlErrors")
#endif
template <> eControlType get_control_type<U32>();
template <> eControlType get_control_type<S32>();
template <> eControlType get_control_type<F32>();
template <> eControlType get_control_type<bool>();
// Yay BOOL, its really an S32.
//template <> eControlType get_control_type<BOOL> () ;
template <> eControlType get_control_type<std::string>();
template <> eControlType get_control_type<LLVector3>();
template <> eControlType get_control_type<LLVector3d>();
template <> eControlType get_control_type<LLRect>();
template <> eControlType get_control_type<LLColor4>();
template <> eControlType get_control_type<LLColor3>();
template <> eControlType get_control_type<LLColor4U>();
template <> eControlType get_control_type<LLSD>();
template <> LLSD convert_to_llsd<U32>(const U32& in);
template <> LLSD convert_to_llsd<LLVector3>(const LLVector3& in);
template <> LLSD convert_to_llsd<LLVector3d>(const LLVector3d& in);
template <> LLSD convert_to_llsd<LLRect>(const LLRect& in);
template <> LLSD convert_to_llsd<LLColor4>(const LLColor4& in);
template <> LLSD convert_to_llsd<LLColor3>(const LLColor3& in);
template <> LLSD convert_to_llsd<LLColor4U>(const LLColor4U& in);
template <> bool convert_from_llsd<bool>(const LLSD& sd, eControlType type, const std::string& control_name);
template <> S32 convert_from_llsd<S32>(const LLSD& sd, eControlType type, const std::string& control_name);
template <> U32 convert_from_llsd<U32>(const LLSD& sd, eControlType type, const std::string& control_name);
template <> F32 convert_from_llsd<F32>(const LLSD& sd, eControlType type, const std::string& control_name);
template <> std::string convert_from_llsd<std::string>(const LLSD& sd, eControlType type, const std::string& control_name);
template <> LLWString convert_from_llsd<LLWString>(const LLSD& sd, eControlType type, const std::string& control_name);
template <> LLVector3 convert_from_llsd<LLVector3>(const LLSD& sd, eControlType type, const std::string& control_name);
template <> LLVector3d convert_from_llsd<LLVector3d>(const LLSD& sd, eControlType type, const std::string& control_name);
template <> LLRect convert_from_llsd<LLRect>(const LLSD& sd, eControlType type, const std::string& control_name);
template <> LLColor4 convert_from_llsd<LLColor4>(const LLSD& sd, eControlType type, const std::string& control_name);
template <> LLColor4U convert_from_llsd<LLColor4U>(const LLSD& sd, eControlType type, const std::string& control_name);
template <> LLColor3 convert_from_llsd<LLColor3>(const LLSD& sd, eControlType type, const std::string& control_name);
template <> LLSD convert_from_llsd<LLSD>(const LLSD& sd, eControlType type, const std::string& control_name);
//this defines the current version of the settings file
const S32 CURRENT_VERSION = 101;
@@ -120,9 +158,6 @@ bool LLControlVariable::llsd_compare(const LLSD& a, const LLSD & b)
case TYPE_COL3:
result = LLColor3(a) == LLColor3(b);
break;
case TYPE_COL4U:
result = LLColor4U(a) == LLColor4U(b);
break;
case TYPE_STRING:
result = a.asString() == b.asString();
break;
@@ -141,7 +176,8 @@ LLControlVariable::LLControlVariable(const std::string& name, eControlType type,
mType(type),
mPersist(persist),
mHideFromSettingsEditor(hidefromsettingseditor),
mSignal(new signal_t),
mCommitSignal(new commit_signal_t),
mValidateSignal(new validate_signal_t),
mIsCOA(IsCOA),
mIsCOAParent(false),
mCOAConnectedVar(NULL)
@@ -177,6 +213,20 @@ LLSD LLControlVariable::getComparableValue(const LLSD& value)
storable_value = false;
}
}
else if (TYPE_LLSD == type() && value.isString())
{
LLPointer<LLSDNotationParser> parser = new LLSDNotationParser;
LLSD result;
std::stringstream value_stream(value.asString());
if (parser->parse(value_stream, result, LLSDSerialize::SIZE_UNLIMITED) != LLSDParser::PARSE_FAILURE)
{
storable_value = result;
}
else
{
storable_value = value;
}
}
else
{
storable_value = value;
@@ -185,9 +235,15 @@ LLSD LLControlVariable::getComparableValue(const LLSD& value)
return storable_value;
}
void LLControlVariable::setValue(const LLSD& value, bool saved_value)
void LLControlVariable::setValue(const LLSD& new_value, bool saved_value)
{
LLSD storable_value = getComparableValue(value);
if ((*mValidateSignal)(this, new_value) == false)
{
// can not set new value, exit
return;
}
LLSD storable_value = getComparableValue(new_value);
bool value_changed = llsd_compare(getValue(), storable_value) == FALSE;
if(saved_value)
{
@@ -226,7 +282,7 @@ void LLControlVariable::setValue(const LLSD& value, bool saved_value)
if(value_changed)
{
if(getCOAActive() == this)
(*mSignal)(storable_value);
(*mCommitSignal)(this,storable_value);
}
}
@@ -342,7 +398,8 @@ LLControlVariable const* LLControlGroup::getControl(std::string const& name) con
////////////////////////////////////////////////////////////////////////////
LLControlGroup::LLControlGroup()
LLControlGroup::LLControlGroup(const std::string& name)
: LLInstanceTracker<LLControlGroup, std::string>(name)
{
mTypeString[TYPE_U32] = "U32";
mTypeString[TYPE_S32] = "S32";
@@ -354,7 +411,6 @@ LLControlGroup::LLControlGroup()
mTypeString[TYPE_RECT] = "Rect";
mTypeString[TYPE_COL4] = "Color4";
mTypeString[TYPE_COL3] = "Color3";
mTypeString[TYPE_COL4U] = "Color4u";
mTypeString[TYPE_LLSD] = "LLSD";
}
@@ -451,11 +507,6 @@ BOOL LLControlGroup::declareRect(const std::string& name, const LLRect &initial_
return declareControl(name, TYPE_RECT, initial_val.getValue(), comment, persist);
}
BOOL LLControlGroup::declareColor4U(const std::string& name, const LLColor4U &initial_val, const std::string& comment, BOOL persist )
{
return declareControl(name, TYPE_COL4U, initial_val.getValue(), comment, persist);
}
BOOL LLControlGroup::declareColor4(const std::string& name, const LLColor4 &initial_val, const std::string& comment, BOOL persist )
{
return declareControl(name, TYPE_COL4, initial_val.getValue(), comment, persist);
@@ -473,54 +524,22 @@ BOOL LLControlGroup::declareLLSD(const std::string& name, const LLSD &initial_va
BOOL LLControlGroup::getBOOL(const std::string& name)
{
LLControlVariable* control = getControl(name);
if (control && control->isType(TYPE_BOOLEAN))
return control->get().asBoolean();
else
{
CONTROL_ERRS << "Invalid BOOL control " << name << llendl;
return FALSE;
}
return (BOOL)get<bool>(name);
}
S32 LLControlGroup::getS32(const std::string& name)
{
LLControlVariable* control = getControl(name);
if (control && control->isType(TYPE_S32))
return control->get().asInteger();
else
{
CONTROL_ERRS << "Invalid S32 control " << name << llendl;
return 0;
}
return get<S32>(name);
}
U32 LLControlGroup::getU32(const std::string& name)
{
LLControlVariable* control = getControl(name);
if (control && control->isType(TYPE_U32))
return control->get().asInteger();
else
{
CONTROL_ERRS << "Invalid U32 control " << name << llendl;
return 0;
}
return get<U32>(name);
}
F32 LLControlGroup::getF32(const std::string& name)
{
LLControlVariable* control = getControl(name);
if (control && control->isType(TYPE_F32))
return (F32) control->get().asReal();
else
{
CONTROL_ERRS << "Invalid F32 control " << name << llendl;
return 0.0f;
}
return get<F32>(name);
}
std::string LLControlGroup::findString(const std::string& name)
@@ -534,20 +553,12 @@ std::string LLControlGroup::findString(const std::string& name)
std::string LLControlGroup::getString(const std::string& name) const
{
LLControlVariable const* control = getControl(name);
if (control && control->isType(TYPE_STRING))
return control->get().asString();
else
{
CONTROL_ERRS << "Invalid string control " << name << llendl;
return LLStringUtil::null;
}
return get<std::string>(name);
}
LLWString LLControlGroup::getWString(const std::string& name)
{
return utf8str_to_wstring(getString(name));
return get<LLWString>(name);
}
std::string LLControlGroup::getText(const std::string& name)
@@ -560,123 +571,38 @@ std::string LLControlGroup::getText(const std::string& name)
LLVector3 LLControlGroup::getVector3(const std::string& name)
{
LLControlVariable* control = getControl(name);
if (control && control->isType(TYPE_VEC3))
return control->get();
else
{
CONTROL_ERRS << "Invalid LLVector3 control " << name << llendl;
return LLVector3::zero;
}
return get<LLVector3>(name);
}
LLVector3d LLControlGroup::getVector3d(const std::string& name)
{
LLControlVariable* control = getControl(name);
if (control && control->isType(TYPE_VEC3D))
return control->get();
else
{
CONTROL_ERRS << "Invalid LLVector3d control " << name << llendl;
return LLVector3d::zero;
}
return get<LLVector3d>(name);
}
LLRect LLControlGroup::getRect(const std::string& name)
{
LLControlVariable* control = getControl(name);
if (control && control->isType(TYPE_RECT))
return control->get();
else
{
CONTROL_ERRS << "Invalid rect control " << name << llendl;
return LLRect::null;
}
return get<LLRect>(name);
}
LLColor4 LLControlGroup::getColor(const std::string& name)
{
ctrl_name_table_t::const_iterator i = mNameTable.find(name);
if (i != mNameTable.end())
{
LLControlVariable* control = i->second;
switch(control->mType)
{
case TYPE_COL4:
{
return LLColor4(control->get());
}
case TYPE_COL4U:
{
return LLColor4(LLColor4U(control->get()));
}
default:
{
CONTROL_ERRS << "Control " << name << " not a color" << llendl;
return LLColor4::white;
}
}
}
else
{
CONTROL_ERRS << "Invalid getColor control " << name << llendl;
return LLColor4::white;
}
}
LLColor4U LLControlGroup::getColor4U(const std::string& name)
{
LLControlVariable* control = getControl(name);
if (control && control->isType(TYPE_COL4U))
return control->get();
else
{
CONTROL_ERRS << "Invalid LLColor4 control " << name << llendl;
return LLColor4U::white;
}
return get<LLColor4>(name);
}
LLColor4 LLControlGroup::getColor4(const std::string& name)
{
LLControlVariable* control = getControl(name);
if (control && control->isType(TYPE_COL4))
return control->get();
else
{
CONTROL_ERRS << "Invalid LLColor4 control " << name << llendl;
return LLColor4::white;
}
return get<LLColor4>(name);
}
LLColor3 LLControlGroup::getColor3(const std::string& name)
{
LLControlVariable* control = getControl(name);
if (control && control->isType(TYPE_COL3))
return control->get();
else
{
CONTROL_ERRS << "Invalid LLColor3 control " << name << llendl;
return LLColor3::white;
}
return get<LLColor3>(name);
}
LLSD LLControlGroup::getLLSD(const std::string& name)
{
LLControlVariable* control = getControl(name);
if (control && control->isType(TYPE_LLSD))
return control->getValue();
CONTROL_ERRS << "Invalid LLSD control " << name << llendl;
return LLSD();
return get<LLSD>(name);
}
BOOL LLControlGroup::controlExists(const std::string& name) const
@@ -691,164 +617,65 @@ BOOL LLControlGroup::controlExists(const std::string& name) const
void LLControlGroup::setBOOL(const std::string& name, BOOL val)
{
LLControlVariable* control = getControl(name);
if (control && control->isType(TYPE_BOOLEAN))
{
control->set(val);
}
else
{
CONTROL_ERRS << "Invalid control " << name << llendl;
}
set<bool>(name, val);
}
void LLControlGroup::setS32(const std::string& name, S32 val)
{
LLControlVariable* control = getControl(name);
if (control && control->isType(TYPE_S32))
{
control->set(val);
}
else
{
CONTROL_ERRS << "Invalid control " << name << llendl;
}
set(name, val);
}
void LLControlGroup::setF32(const std::string& name, F32 val)
{
LLControlVariable* control = getControl(name);
if (control && control->isType(TYPE_F32))
{
control->set(val);
}
else
{
CONTROL_ERRS << "Invalid control " << name << llendl;
}
set(name, val);
}
void LLControlGroup::setU32(const std::string& name, U32 val)
{
LLControlVariable* control = getControl(name);
if (control && control->isType(TYPE_U32))
{
control->set((LLSD::Integer) val);
}
else
{
CONTROL_ERRS << "Invalid control " << name << llendl;
}
set(name, val);
}
void LLControlGroup::setString(const std::string& name, const std::string &val)
{
LLControlVariable* control = getControl(name);
if (control && control->isType(TYPE_STRING))
{
control->set(val);
}
else
{
CONTROL_ERRS << "Invalid control " << name << llendl;
}
set(name, val);
}
void LLControlGroup::setVector3(const std::string& name, const LLVector3 &val)
{
LLControlVariable* control = getControl(name);
if (control && control->isType(TYPE_VEC3))
{
control->set(val.getValue());
}
else
{
CONTROL_ERRS << "Invalid control " << name << llendl;
}
set(name, val);
}
void LLControlGroup::setVector3d(const std::string& name, const LLVector3d &val)
{
LLControlVariable* control = getControl(name);
if (control && control->isType(TYPE_VEC3D))
{
control->set(val.getValue());
}
else
{
CONTROL_ERRS << "Invalid control " << name << llendl;
}
set(name, val);
}
void LLControlGroup::setRect(const std::string& name, const LLRect &val)
{
LLControlVariable* control = getControl(name);
if (control && control->isType(TYPE_RECT))
{
control->set(val.getValue());
}
else
{
CONTROL_ERRS << "Invalid rect control " << name << llendl;
}
}
void LLControlGroup::setColor4U(const std::string& name, const LLColor4U &val)
{
LLControlVariable* control = getControl(name);
if (control && control->isType(TYPE_COL4U))
{
control->set(val.getValue());
}
else
{
CONTROL_ERRS << "Invalid LLColor4 control " << name << llendl;
}
set(name, val);
}
void LLControlGroup::setColor4(const std::string& name, const LLColor4 &val)
{
LLControlVariable* control = getControl(name);
if (control && control->isType(TYPE_COL4))
{
control->set(val.getValue());
}
else
{
CONTROL_ERRS << "Invalid LLColor4 control " << name << llendl;
}
set(name, val);
}
void LLControlGroup::setColor3(const std::string& name, const LLColor3 &val)
{
set(name, val);
}
void LLControlGroup::setLLSD(const std::string& name, const LLSD& val)
{
LLControlVariable* control = getControl(name);
if (control && control->isType(TYPE_LLSD))
{
setValue(name, val);
}
else
{
CONTROL_ERRS << "Invalid LLSD control " << name << llendl;
}
set(name, val);
}
void LLControlGroup::setValue(const std::string& name, const LLSD& val)
void LLControlGroup::setUntypedValue(const std::string& name, const LLSD& val)
{
if (name.empty())
{
@@ -859,7 +686,7 @@ void LLControlGroup::setValue(const std::string& name, const LLSD& val)
if (control)
{
control->set(val);
control->setValue(val);
}
else
{
@@ -867,6 +694,7 @@ void LLControlGroup::setValue(const std::string& name, const LLSD& val)
}
}
//---------------------------------------------------------------
// Load and save
//---------------------------------------------------------------
@@ -932,12 +760,10 @@ U32 LLControlGroup::loadFromFileLegacy(const std::string& filename, BOOL require
{
switch(declare_as)
{
case TYPE_COL4U:
case TYPE_COL4:
declareColor4(name, LLColor4::white, LLStringUtil::null, NO_PERSIST);
break;
case TYPE_COL4U:
declareColor4U(name, LLColor4U::white, LLStringUtil::null, NO_PERSIST);
break;
case TYPE_STRING:
default:
declareString(name, LLStringUtil::null, LLStringUtil::null, NO_PERSIST);
@@ -1035,21 +861,22 @@ U32 LLControlGroup::loadFromFileLegacy(const std::string& filename, BOOL require
validitems++;
}
break;
case TYPE_COL4U:
{
LLColor4U color;
child_nodep->getAttributeColor4U("value", color);
control->set(color.getValue());
validitems++;
}
break;
case TYPE_COL4:
{
LLColor4 color;
if(declare_as == TYPE_COL4U)
{
LLColor4U color;
child_nodep->getAttributeColor4("value", color);
control->set(color.getValue());
child_nodep->getAttributeColor4U("value", color);
control->set(LLColor4(color).getValue());
}
else
{
LLColor4 color;
child_nodep->getAttributeColor4("value", color);
control->set(color.getValue());
}
validitems++;
}
break;
@@ -1120,15 +947,13 @@ U32 LLControlGroup::saveToFile(const std::string& filename, BOOL nondefault_only
return num_saved;
}
U32 LLControlGroup::loadFromFile(const std::string& filename, bool set_default_values)
U32 LLControlGroup::loadFromFile(const std::string& filename, bool set_default_values, bool save_values)
{
if(mIncludedFiles.find(filename) != mIncludedFiles.end())
return 0; //Already included this file.
mIncludedFiles.insert(filename);
std::string name;
LLSD settings;
LLSD control_map;
llifstream infile;
infile.open(filename);
if(!infile.is_open())
@@ -1148,11 +973,12 @@ U32 LLControlGroup::loadFromFile(const std::string& filename, bool set_default_v
U32 validitems = 0;
bool hidefromsettingseditor = false;
for(LLSD::map_const_iterator itr = settings.beginMap(); itr != settings.endMap(); ++itr)
{
bool persist = true;
name = (*itr).first;
control_map = (*itr).second;
std::string const & name = itr->first;
LLSD const & control_map = itr->second;
if(name == "Include")
{
@@ -1214,8 +1040,7 @@ U32 LLControlGroup::loadFromFile(const std::string& filename, bool set_default_v
}
else if(existing_control->isPersisted())
{
existing_control->setValue(control_map["Value"]);
existing_control->setValue(control_map["Value"], save_values);
}
// *NOTE: If not persisted and not setting defaults,
// the value should not get loaded.
@@ -1294,7 +1119,7 @@ void LLControlGroup::connectCOAVars(LLControlGroup &OtherGroup)
}
if(pCOAVar)
{
pCOAVar->getSignal()->connect(boost::bind(&LLControlGroup::handleCOASettingChange, this, _1));
pCOAVar->getSignal()->connect(boost::bind(&LLControlGroup::handleCOASettingChange, this, _2));
pCOAVar->firePropertyChanged();
}
}
@@ -1427,4 +1252,298 @@ void main()
#endif
template <> eControlType get_control_type<U32>()
{
return TYPE_U32;
}
template <> eControlType get_control_type<S32>()
{
return TYPE_S32;
}
template <> eControlType get_control_type<F32>()
{
return TYPE_F32;
}
template <> eControlType get_control_type<bool> ()
{
return TYPE_BOOLEAN;
}
/*
// Yay BOOL, its really an S32.
template <> eControlType get_control_type<BOOL> ()
{
return TYPE_BOOLEAN;
}
*/
template <> eControlType get_control_type<std::string>()
{
return TYPE_STRING;
}
template <> eControlType get_control_type<LLVector3>()
{
return TYPE_VEC3;
}
template <> eControlType get_control_type<LLVector3d>()
{
return TYPE_VEC3D;
}
template <> eControlType get_control_type<LLRect>()
{
return TYPE_RECT;
}
template <> eControlType get_control_type<LLColor4>()
{
return TYPE_COL4;
}
template <> eControlType get_control_type<LLColor3>()
{
return TYPE_COL3;
}
template <> eControlType get_control_type<LLSD>()
{
return TYPE_LLSD;
}
template <> LLSD convert_to_llsd<U32>(const U32& in)
{
return (LLSD::Integer)in;
}
template <> LLSD convert_to_llsd<LLVector3>(const LLVector3& in)
{
return in.getValue();
}
template <> LLSD convert_to_llsd<LLVector3d>(const LLVector3d& in)
{
return in.getValue();
}
template <> LLSD convert_to_llsd<LLRect>(const LLRect& in)
{
return in.getValue();
}
template <> LLSD convert_to_llsd<LLColor4>(const LLColor4& in)
{
return in.getValue();
}
template <> LLSD convert_to_llsd<LLColor3>(const LLColor3& in)
{
return in.getValue();
}
template <> LLSD convert_to_llsd<LLColor4U>(const LLColor4U& in)
{
return in.getValue();
}
template<>
bool convert_from_llsd<bool>(const LLSD& sd, eControlType type, const std::string& control_name)
{
if (type == TYPE_BOOLEAN)
return sd.asBoolean();
else
{
CONTROL_ERRS << "Invalid BOOL value for " << control_name << ": " << sd << llendl;
return FALSE;
}
}
template<>
S32 convert_from_llsd<S32>(const LLSD& sd, eControlType type, const std::string& control_name)
{
if (type == TYPE_S32)
return sd.asInteger();
else
{
CONTROL_ERRS << "Invalid S32 value for " << control_name << ": " << sd << llendl;
return 0;
}
}
template<>
U32 convert_from_llsd<U32>(const LLSD& sd, eControlType type, const std::string& control_name)
{
if (type == TYPE_U32)
return sd.asInteger();
else
{
CONTROL_ERRS << "Invalid U32 value for " << control_name << ": " << sd << llendl;
return 0;
}
}
template<>
F32 convert_from_llsd<F32>(const LLSD& sd, eControlType type, const std::string& control_name)
{
if (type == TYPE_F32)
return (F32) sd.asReal();
else
{
CONTROL_ERRS << "Invalid F32 value for " << control_name << ": " << sd << llendl;
return 0.0f;
}
}
template<>
std::string convert_from_llsd<std::string>(const LLSD& sd, eControlType type, const std::string& control_name)
{
if (type == TYPE_STRING)
return sd.asString();
else
{
CONTROL_ERRS << "Invalid string value for " << control_name << ": " << sd << llendl;
return LLStringUtil::null;
}
}
template<>
LLWString convert_from_llsd<LLWString>(const LLSD& sd, eControlType type, const std::string& control_name)
{
return utf8str_to_wstring(convert_from_llsd<std::string>(sd, type, control_name));
}
template<>
LLVector3 convert_from_llsd<LLVector3>(const LLSD& sd, eControlType type, const std::string& control_name)
{
if (type == TYPE_VEC3)
return (LLVector3)sd;
else
{
CONTROL_ERRS << "Invalid LLVector3 value for " << control_name << ": " << sd << llendl;
return LLVector3::zero;
}
}
template<>
LLVector3d convert_from_llsd<LLVector3d>(const LLSD& sd, eControlType type, const std::string& control_name)
{
if (type == TYPE_VEC3D)
return (LLVector3d)sd;
else
{
CONTROL_ERRS << "Invalid LLVector3d value for " << control_name << ": " << sd << llendl;
return LLVector3d::zero;
}
}
template<>
LLRect convert_from_llsd<LLRect>(const LLSD& sd, eControlType type, const std::string& control_name)
{
if (type == TYPE_RECT)
return LLRect(sd);
else
{
CONTROL_ERRS << "Invalid rect value for " << control_name << ": " << sd << llendl;
return LLRect::null;
}
}
template<>
LLColor4 convert_from_llsd<LLColor4>(const LLSD& sd, eControlType type, const std::string& control_name)
{
if (type == TYPE_COL4)
{
LLColor4 color(sd);
if (color.mV[VRED] < 0.f || color.mV[VRED] > 1.f)
{
llwarns << "Color " << control_name << " red value out of range: " << color << llendflush;
}
else if (color.mV[VGREEN] < 0.f || color.mV[VGREEN] > 1.f)
{
llwarns << "Color " << control_name << " green value out of range: " << color << llendflush;
}
else if (color.mV[VBLUE] < 0.f || color.mV[VBLUE] > 1.f)
{
llwarns << "Color " << control_name << " blue value out of range: " << color << llendflush;
}
else if (color.mV[VALPHA] < 0.f || color.mV[VALPHA] > 1.f)
{
llwarns << "Color " << control_name << " alpha value out of range: " << color << llendflush;
}
return LLColor4(sd);
}
else
{
CONTROL_ERRS << "Control " << control_name << " not a color" << llendl;
return LLColor4::white;
}
}
template<>
LLColor3 convert_from_llsd<LLColor3>(const LLSD& sd, eControlType type, const std::string& control_name)
{
if (type == TYPE_COL3)
return sd;
else
{
CONTROL_ERRS << "Invalid LLColor3 value for " << control_name << ": " << sd << llendl;
return LLColor3::white;
}
}
template<>
LLSD convert_from_llsd<LLSD>(const LLSD& sd, eControlType type, const std::string& control_name)
{
return sd;
}
#if TEST_CACHED_CONTROL
#define DECL_LLCC(T, V) static LLCachedControl<T> mySetting_##T("TestCachedControl"#T, V)
DECL_LLCC(U32, (U32)666);
DECL_LLCC(S32, (S32)-666);
DECL_LLCC(F32, (F32)-666.666);
DECL_LLCC(bool, true);
DECL_LLCC(BOOL, FALSE);
static LLCachedControl<std::string> mySetting_string("TestCachedControlstring", "Default String Value");
DECL_LLCC(LLVector3, LLVector3(1.0f, 2.0f, 3.0f));
DECL_LLCC(LLVector3d, LLVector3d(6.0f, 5.0f, 4.0f));
DECL_LLCC(LLRect, LLRect(0, 0, 100, 500));
DECL_LLCC(LLColor4, LLColor4(0.0f, 0.5f, 1.0f));
DECL_LLCC(LLColor3, LLColor3(1.0f, 0.f, 0.5f));
LLSD test_llsd = LLSD()["testing1"] = LLSD()["testing2"];
DECL_LLCC(LLSD, test_llsd);
static LLCachedControl<std::string> test_BrowserHomePage("BrowserHomePage", "hahahahahha", "Not the real comment");
void test_cached_control()
{
#define TEST_LLCC(T, V) if((T)mySetting_##T != V) llerrs << "Fail "#T << llendl; \
mySetting_##T = V;\
if((T)mySetting_##T != V) llerrs << "Fail "#T << "Pass # 2" << llendl;
TEST_LLCC(U32, 666);
TEST_LLCC(S32, (S32)-666);
TEST_LLCC(F32, (F32)-666.666);
TEST_LLCC(bool, true);
TEST_LLCC(BOOL, FALSE);
if((std::string)mySetting_string != "Default String Value") llerrs << "Fail string" << llendl;
TEST_LLCC(LLVector3, LLVector3(1.0f, 2.0f, 3.0f));
TEST_LLCC(LLVector3d, LLVector3d(6.0f, 5.0f, 4.0f));
TEST_LLCC(LLRect, LLRect(0, 0, 100, 500));
TEST_LLCC(LLColor4, LLColor4(0.0f, 0.5f, 1.0f));
TEST_LLCC(LLColor3, LLColor3(1.0f, 0.f, 0.5f));
//There's no LLSD comparsion for LLCC yet. TEST_LLCC(LLSD, test_llsd);
if((std::string)test_BrowserHomePage != "http://www.singularityviewer.org") llerrs << "Fail BrowserHomePage" << llendl;
}
#endif // TEST_CACHED_CONTROL

View File

@@ -33,6 +33,7 @@
#ifndef LL_LLCONTROL_H
#define LL_LLCONTROL_H
#include "llboost.h"
#include "llevent.h"
#include "llnametable.h"
#include "llmap.h"
@@ -40,6 +41,7 @@
#include "llrect.h"
#include "v4color.h"
#include "v4coloru.h"
#include "llinstancetracker.h"
#include "llcontrolgroupreader.h"
@@ -55,7 +57,16 @@
#endif
#include <boost/bind.hpp>
#if LL_WINDOWS
#pragma warning (push)
#pragma warning (disable : 4263) // boost::signals2::expired_slot::what() has const mismatch
#pragma warning (disable : 4264)
#endif
#include <boost/signals2.hpp>
#if LL_WINDOWS
#pragma warning (pop)
#endif
#if LL_WINDOWS
# if (_MSC_VER >= 1300 && _MSC_VER < 1400)
@@ -66,7 +77,6 @@
class LLVector3;
class LLVector3d;
class LLColor3;
class LLColor4U;
const BOOL NO_PERSIST = FALSE;
@@ -86,8 +96,8 @@ typedef enum e_control_type
TYPE_VEC3D,
TYPE_RECT,
TYPE_COL4,
TYPE_COL4U, //exist merely for legacy colors.xml support. Not a real control type.
TYPE_COL3,
TYPE_COL4U,
TYPE_LLSD,
TYPE_COUNT
} eControlType;
@@ -95,7 +105,10 @@ typedef enum e_control_type
class LLControlVariable : public LLRefCount
{
friend class LLControlGroup;
typedef boost::signals2::signal<void(const LLSD&)> signal_t;
public:
typedef boost::signals2::signal<bool(LLControlVariable* control, const LLSD&), boost_boolean_combiner> validate_signal_t;
typedef boost::signals2::signal<void(LLControlVariable* control, const LLSD&)> commit_signal_t;
private:
std::string mName;
@@ -105,7 +118,8 @@ private:
bool mHideFromSettingsEditor;
std::vector<LLSD> mValues;
boost::shared_ptr<signal_t> mSignal; //Signals are non-copyable. Therefore, using a pointer so vars can 'share' signals for COA
boost::shared_ptr<commit_signal_t> mCommitSignal; //Signals are non-copyable. Therefore, using a pointer so vars can 'share' signals for COA
boost::shared_ptr<validate_signal_t> mValidateSignal;
//COA stuff:
bool mIsCOA; //To have COA connection set.
@@ -121,12 +135,14 @@ public:
const std::string& getName() const { return mName; }
const std::string& getComment() const { return mComment; }
eControlType type() { return mType; }
eControlType type() const { return mType; }
bool isType(eControlType tp) const { return tp == mType; }
void resetToDefault(bool fire_signal = false);
signal_t* getSignal() { return mSignal.get(); }
commit_signal_t* getSignal() { return mCommitSignal.get(); } // shorthand for commit signal
commit_signal_t* getCommitSignal() { return mCommitSignal.get(); }
validate_signal_t* getValidateSignal() { return mValidateSignal.get(); }
bool isDefault() { return (mValues.size() == 1); }
bool isSaveValueDefault();
@@ -146,7 +162,7 @@ public:
void firePropertyChanged()
{
(*mSignal)(mValues.back());
(*mCommitSignal)(this,mValues.back());
}
//COA stuff
@@ -161,31 +177,57 @@ public:
mIsCOAParent=IsParent;
mCOAConnectedVar=pConnect;
if(!IsParent)
mSignal = pConnect->mSignal; //Share a single signal.
{
mCommitSignal = pConnect->mCommitSignal; //Share a single signal.
mValidateSignal = pConnect->mValidateSignal;
}
}
private:
LLSD getComparableValue(const LLSD& value);
bool llsd_compare(const LLSD& a, const LLSD & b);
};
typedef LLPointer<LLControlVariable> LLControlVariablePtr;
//! Helper functions for converting between static types and LLControl values
template <class T>
eControlType get_control_type()
{
llwarns << "Usupported control type: " << typeid(T).name() << "." << llendl;
return TYPE_COUNT;
}
template <class T>
LLSD convert_to_llsd(const T& in)
{
// default implementation
return LLSD(in);
}
template <class T>
T convert_from_llsd(const LLSD& sd, eControlType type, const std::string& control_name)
{
// needs specialization
return T(sd);
}
//const U32 STRING_CACHE_SIZE = 10000;
class LLControlGroup : public LLControlGroupReader
class LLControlGroup : public LLInstanceTracker<LLControlGroup, std::string>
{
protected:
typedef std::map<std::string, LLPointer<LLControlVariable> > ctrl_name_table_t;
typedef std::map<std::string, LLControlVariablePtr > ctrl_name_table_t;
ctrl_name_table_t mNameTable;
std::set<std::string> mWarnings;
std::string mTypeString[TYPE_COUNT];
eControlType typeStringToEnum(const std::string& typestr);
std::string typeEnumToString(eControlType typeenum);
std::string typeEnumToString(eControlType typeenum);
std::set<std::string> mIncludedFiles; //To prevent perpetual recursion.
public:
LLControlGroup();
LLControlGroup(const std::string& name);
~LLControlGroup();
void cleanup();
typedef LLInstanceTracker<LLControlGroup, std::string>::instance_iter instance_iter;
LLControlVariable* getControl(std::string const& name);
LLControlVariable const* getControl(std::string const& name) const;
@@ -205,7 +247,6 @@ public:
BOOL declareVec3(const std::string& name, const LLVector3 &initial_val,const std::string& comment, BOOL persist = TRUE);
BOOL declareVec3d(const std::string& name, const LLVector3d &initial_val, const std::string& comment, BOOL persist = TRUE);
BOOL declareRect(const std::string& name, const LLRect &initial_val, const std::string& comment, BOOL persist = TRUE);
BOOL declareColor4U(const std::string& name, const LLColor4U &initial_val, const std::string& comment, BOOL persist = TRUE);
BOOL declareColor4(const std::string& name, const LLColor4 &initial_val, const std::string& comment, BOOL persist = TRUE);
BOOL declareColor3(const std::string& name, const LLColor3 &initial_val, const std::string& comment, BOOL persist = TRUE);
BOOL declareLLSD(const std::string& name, const LLSD &initial_val, const std::string& comment, BOOL persist = TRUE);
@@ -213,25 +254,44 @@ public:
std::string findString(const std::string& name);
std::string getString(const std::string& name) const;
LLWString getWString(const std::string& name);
std::string getText(const std::string& name);
LLVector3 getVector3(const std::string& name);
LLVector3d getVector3d(const std::string& name);
LLRect getRect(const std::string& name);
std::string getText(const std::string& name);
BOOL getBOOL(const std::string& name);
S32 getS32(const std::string& name);
F32 getF32(const std::string& name);
U32 getU32(const std::string& name);
LLWString getWString(const std::string& name);
LLVector3 getVector3(const std::string& name);
LLVector3d getVector3d(const std::string& name);
LLRect getRect(const std::string& name);
LLSD getLLSD(const std::string& name);
// Note: If an LLColor4U control exists, it will cast it to the correct
// LLColor4 for you.
LLColor4 getColor(const std::string& name);
LLColor4U getColor4U(const std::string& name);
LLColor4 getColor4(const std::string& name);
LLColor3 getColor3(const std::string& name);
// generic getter
template<typename T> T get(const std::string& name) const
{
const LLControlVariable* control = getControl(name);
LLSD value;
eControlType type = TYPE_COUNT;
if (control)
{
value = control->get();
type = control->type();
}
else
{
llwarns << "Control " << name << " not found." << llendl;
}
return convert_from_llsd<T>(value, type, name);
}
void setBOOL(const std::string& name, BOOL val);
void setS32(const std::string& name, S32 val);
void setF32(const std::string& name, F32 val);
@@ -240,12 +300,27 @@ public:
void setVector3(const std::string& name, const LLVector3 &val);
void setVector3d(const std::string& name, const LLVector3d &val);
void setRect(const std::string& name, const LLRect &val);
void setColor4U(const std::string& name, const LLColor4U &val);
void setColor4(const std::string& name, const LLColor4 &val);
void setColor3(const std::string& name, const LLColor3 &val);
void setLLSD(const std::string& name, const LLSD& val);
void setValue(const std::string& name, const LLSD& val);
// type agnostic setter that takes LLSD
void setUntypedValue(const std::string& name, const LLSD& val);
// generic setter
template<typename T> void set(const std::string& name, const T& val)
{
LLControlVariable* control = getControl(name);
if (control && control->isType(get_control_type<T>()))
{
control->set(convert_to_llsd(val));
}
else
{
llerrs << "Invalid control " << name << llendl;
}
}
BOOL controlExists(const std::string& name) const;
@@ -254,7 +329,7 @@ public:
// as the given type.
U32 loadFromFileLegacy(const std::string& filename, BOOL require_declaration = TRUE, eControlType declare_as = TYPE_STRING);
U32 saveToFile(const std::string& filename, BOOL nondefault_only);
U32 loadFromFile(const std::string& filename, bool default_values = false);
U32 loadFromFile(const std::string& filename, bool default_values = false, bool save_values = true);
void resetToDefaults();
@@ -275,89 +350,147 @@ public:
bool handleCOASettingChange(const LLSD& newvalue);
};
//! Helper function for LLCachedControl
template <class T>
eControlType get_control_type(const T& in, LLSD& out)
{
llerrs << "Usupported control type: " << typeid(T).name() << "." << llendl;
return TYPE_COUNT;
}
//! Publish/Subscribe object to interact with LLControlGroups.
//! An LLCachedControl instance to connect to a LLControlVariable
//! Use an LLCachedControl instance to connect to a LLControlVariable
//! without have to manually create and bind a listener to a local
//! object.
template <class T>
class LLCachedControl
class LLControlCache : public LLRefCount, public LLInstanceTracker<LLControlCache<T>, std::string>
{
private:
T mCachedValue;
LLPointer<LLControlVariable> mControl;
boost::signals2::connection mConnection;
LLControlGroup *mControlGroup;
public:
LLCachedControl(const std::string& name, const T& default_value, LLControlGroup *group, const std::string& comment = "Declared In Code")
{Init(name,default_value,comment,*group);} //for gSavedPerAccountSettings, etc
LLCachedControl(const std::string& name, const T& default_value, LLControlGroup &group, const std::string& comment = "Declared In Code")
{Init(name,default_value,comment,group);} //for LLUI::sConfigGroup, etc
LLCachedControl(const std::string& name,
// This constructor will declare a control if it doesn't exist in the contol group
LLControlCache(LLControlGroup& group,
const std::string& name,
const T& default_value,
const std::string& comment = "Declared In Code",
LLControlGroup &group = gSavedSettings)
{Init(name,default_value,comment,group);} //for default (gSavedSettings)
private:
void Init( const std::string& name,
const T& default_value,
const std::string& comment,
LLControlGroup &group)
const std::string& comment)
: LLInstanceTracker<LLControlCache<T>, std::string >(name)
{
mControlGroup = &group;
mControl = mControlGroup->getControl(name);
if(mControl.isNull())
if(!group.controlExists(name))
{
declareTypedControl(*mControlGroup, name, default_value, comment);
mControl = mControlGroup->getControl(name);
if(mControl.isNull())
if(!declareTypedControl(group, name, default_value, comment))
{
llerrs << "The control could not be created!!!" << llendl;
}
mCachedValue = default_value;
}
else
bindToControl(group, name);
}
LLControlCache(LLControlGroup& group,
const std::string& name)
: LLInstanceTracker<LLControlCache<T>, std::string >(name)
{
if(!group.controlExists(name))
{
handleValueChange(mControl->getValue());
llerrs << "Control named " << name << "not found." << llendl;
}
if(mConnection.connected())
mConnection.disconnect();
bindToControl(group, name);
}
~LLControlCache()
{
}
const T& getValue() const { return mCachedValue; }
void setTypeValue(const T& v) { mControl->set(convert_to_llsd(v)); }
private:
void bindToControl(LLControlGroup& group, const std::string& name)
{
LLControlVariablePtr controlp = group.getControl(name);
mType = controlp->type();
mCachedValue = convert_from_llsd<T>(controlp->get(), mType, name);
// Add a listener to the controls signal...
// and store the connection...
mConnection = mControl->getSignal()->connect(
boost::bind(&LLCachedControl<T>::handleValueChange, this, _1)
mConnection = controlp->getSignal()->connect(
boost::bind(&LLControlCache<T>::handleValueChange, this, _2)
);
mType = controlp->type();
mControl = controlp;
}
public:
~LLCachedControl()
bool declareTypedControl(LLControlGroup& group,
const std::string& name,
const T& default_value,
const std::string& comment)
{
if(mConnection.connected())
LLSD init_value;
eControlType type = get_control_type<T>();
init_value = convert_to_llsd(default_value);
if(type < TYPE_COUNT)
{
mConnection.disconnect();
group.declareControl(name, type, init_value, comment, FALSE);
return true;
}
return false;
}
bool handleValueChange(const LLSD& newvalue)
{
mCachedValue = convert_from_llsd<T>(newvalue, mType, "");
return true;
}
private:
T mCachedValue;
LLPointer<LLControlVariable> mControl; //Hold a pointer to the control so setters are possible in cachedctrl
eControlType mType;
boost::signals2::scoped_connection mConnection;
};
template <typename T>
class LLCachedControl
{
public:
LLCachedControl(const std::string& name,
const T& default_value,
const std::string& comment = "Declared In Code")
{
mCachedControlPtr = LLControlCache<T>::getInstance(name);
if (mCachedControlPtr.isNull())
{
mCachedControlPtr = new LLControlCache<T>(gSavedSettings, name, default_value, comment);
}
}
LLCachedControl& operator =(const T& newvalue)
LLCachedControl(const std::string& name)
{
setTypeValue(*mControl, newvalue);
return *this;
mCachedControlPtr = LLControlCache<T>::getInstance(name);
if (mCachedControlPtr.isNull())
{
mCachedControlPtr = new LLControlCache<T>(gSavedSettings, name);
}
}
operator const T&() const { return mCachedValue; }
LLCachedControl(LLControlGroup& group,
const std::string& name,
const T& default_value,
const std::string& comment = "Declared In Code")
{
mCachedControlPtr = LLControlCache<T>::getInstance(name);
if (mCachedControlPtr.isNull())
{
mCachedControlPtr = new LLControlCache<T>(group, name, default_value, comment);
}
}
LLCachedControl(LLControlGroup& group,
const std::string& name)
{
mCachedControlPtr = LLControlCache<T>::getInstance(name);
if (mCachedControlPtr.isNull())
{
mCachedControlPtr = new LLControlCache<T>(group, name);
}
}
operator const T&() const { return mCachedControlPtr->getValue(); }
operator boost::function<const T&()> () const { return boost::function<const T&()>(*this); }
const T& operator()() const { return mCachedControlPtr->getValue(); }
/* Sometimes implicit casting doesn't work.
For instance, something like "LLCachedControl<LLColor4> color("blah",LLColor4()); color.getValue();"
will not compile as it will look for the function getValue() in LLCachedControl, which doesn't exist.
@@ -365,71 +498,54 @@ public:
Manually casting to (const T) would work too, but it's ugly and requires knowledge of LLCachedControl's internals
*/
const T &get() const { return mCachedValue; }
const T &get() const { return mCachedControlPtr->getValue(); }
LLCachedControl& operator =(const T& newvalue)
{
mCachedControlPtr->setTypeValue(newvalue);
return *this;
}
private:
void declareTypedControl(LLControlGroup& group,
const std::string& name,
const T& default_value,
const std::string& comment)
{
LLSD init_value;
eControlType type = get_control_type<T>(default_value, init_value);
if(type < TYPE_COUNT)
{
group.declareControl(name, type, init_value, comment, FALSE);
}
}
void setValue(const LLSD& newvalue) //default behavior
{
mCachedValue = (const T &)newvalue;
}
bool handleValueChange(const LLSD& newvalue)
{
setValue(newvalue);
return true;
}
void setTypeValue(LLControlVariable& c, const T& v)
{
// Implicit conversion from T to LLSD...
c.set(v);
}
LLPointer<LLControlCache<T> > mCachedControlPtr;
};
template <> inline void LLCachedControl<LLColor4>::setValue(const LLSD& newvalue)
{
if(this->mControl->isType(TYPE_COL4U))
//a color4u LLSD cannot be auto-converted to color4.. so do it manually.
this->mCachedValue.set(LLColor4U(newvalue));
else
this->mCachedValue = (const LLColor4 &)newvalue;
}
template <> inline void LLCachedControl<U32>::setValue(const LLSD& newvalue)
{
if(mControl->isType(TYPE_U32) || mControl->isType(TYPE_S32)) //LLSD does not support U32 fully
mCachedValue = (U32)newvalue.asInteger();
else if(this->mControl->isType(TYPE_F32))
mCachedValue = (U32)newvalue.asReal();
else
mCachedValue = (U32)0; //What to do...
}
//Following is actually defined in newview/llviewercontrol.cpp, but extern access is fine (Unless GCC bites me)
template <> eControlType get_control_type<U32>(const U32& in, LLSD& out);
template <> eControlType get_control_type<S32>(const S32& in, LLSD& out);
template <> eControlType get_control_type<F32>(const F32& in, LLSD& out);
template <> eControlType get_control_type<bool> (const bool& in, LLSD& out);
template <> eControlType get_control_type<U32>();
template <> eControlType get_control_type<S32>();
template <> eControlType get_control_type<F32>();
template <> eControlType get_control_type<bool>();
// Yay BOOL, its really an S32.
//template <> eControlType get_control_type<BOOL> (const BOOL& in, LLSD& out)
template <> eControlType get_control_type<std::string>(const std::string& in, LLSD& out);
template <> eControlType get_control_type<LLVector3>(const LLVector3& in, LLSD& out);
template <> eControlType get_control_type<LLVector3d>(const LLVector3d& in, LLSD& out);
template <> eControlType get_control_type<LLRect>(const LLRect& in, LLSD& out);
template <> eControlType get_control_type<LLColor4>(const LLColor4& in, LLSD& out);
template <> eControlType get_control_type<LLColor3>(const LLColor3& in, LLSD& out);
template <> eControlType get_control_type<LLColor4U>(const LLColor4U& in, LLSD& out);
template <> eControlType get_control_type<LLSD>(const LLSD& in, LLSD& out);
//template <> eControlType get_control_type<BOOL> ()
template <> eControlType get_control_type<std::string>();
template <> eControlType get_control_type<LLVector3>();
template <> eControlType get_control_type<LLVector3d>();
template <> eControlType get_control_type<LLRect>();
template <> eControlType get_control_type<LLColor4>();
template <> eControlType get_control_type<LLColor3>();
template <> eControlType get_control_type<LLSD>();
template <> LLSD convert_to_llsd<U32>(const U32& in);
template <> LLSD convert_to_llsd<LLVector3>(const LLVector3& in);
template <> LLSD convert_to_llsd<LLVector3d>(const LLVector3d& in);
template <> LLSD convert_to_llsd<LLRect>(const LLRect& in);
template <> LLSD convert_to_llsd<LLColor4>(const LLColor4& in);
template <> LLSD convert_to_llsd<LLColor3>(const LLColor3& in);
template<> std::string convert_from_llsd<std::string>(const LLSD& sd, eControlType type, const std::string& control_name);
template<> LLWString convert_from_llsd<LLWString>(const LLSD& sd, eControlType type, const std::string& control_name);
template<> LLVector3 convert_from_llsd<LLVector3>(const LLSD& sd, eControlType type, const std::string& control_name);
template<> LLVector3d convert_from_llsd<LLVector3d>(const LLSD& sd, eControlType type, const std::string& control_name);
template<> LLRect convert_from_llsd<LLRect>(const LLSD& sd, eControlType type, const std::string& control_name);
template<> bool convert_from_llsd<bool>(const LLSD& sd, eControlType type, const std::string& control_name);
template<> S32 convert_from_llsd<S32>(const LLSD& sd, eControlType type, const std::string& control_name);
template<> F32 convert_from_llsd<F32>(const LLSD& sd, eControlType type, const std::string& control_name);
template<> U32 convert_from_llsd<U32>(const LLSD& sd, eControlType type, const std::string& control_name);
template<> LLColor3 convert_from_llsd<LLColor3>(const LLSD& sd, eControlType type, const std::string& control_name);
template<> LLColor4 convert_from_llsd<LLColor4>(const LLSD& sd, eControlType type, const std::string& control_name);
template<> LLSD convert_from_llsd<LLSD>(const LLSD& sd, eControlType type, const std::string& control_name);
//#define TEST_CACHED_CONTROL 1
#ifdef TEST_CACHED_CONTROL
void test_cached_control();
#endif // TEST_CACHED_CONTROL
#endif

View File

@@ -34,7 +34,7 @@
#define LL_LLXMLPARSER_H
#ifndef XML_STATIC
#define XML_STATIC 1
#define XML_STATIC
#endif
#ifdef LL_STANDALONE
#include <expat.h>

File diff suppressed because it is too large Load Diff

View File

@@ -23,8 +23,9 @@ uniform float sun_wash;
uniform int light_count;
uniform vec4 light[16];
uniform vec4 light_col[16];
#define MAX_LIGHT_COUNT 16
uniform vec4 light[MAX_LIGHT_COUNT];
uniform vec4 light_col[MAX_LIGHT_COUNT];
varying vec4 vary_fragcoord;
uniform vec2 screen_res;
@@ -63,50 +64,56 @@ void main()
float noise = texture2D(noiseMap, frag.xy/128.0).b;
vec3 out_col = vec3(0,0,0);
vec3 npos = normalize(-pos);
for (int i = 0; i < light_count; ++i)
// As of OSX 10.6.7 ATI Apple's crash when using a variable size loop
for (int i = 0; i < MAX_LIGHT_COUNT; ++i)
{
bool light_contrib = (i < light_count);
vec3 lv = light[i].xyz-pos;
float dist2 = dot(lv,lv);
dist2 /= light[i].w;
if (dist2 > 1.0)
{
continue;
light_contrib = false;
}
float da = dot(norm, lv);
if (da < 0.0)
{
continue;
light_contrib = false;
}
lv = normalize(lv);
da = dot(norm, lv);
float fa = light_col[i].a+1.0;
float dist_atten = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0);
dist_atten *= noise;
float lit = da * dist_atten;
vec3 col = light_col[i].rgb*lit*diff;
//vec3 col = vec3(dist2, light_col[i].a, lit);
if (spec.a > 0.0)
if (light_contrib)
{
//vec3 ref = dot(pos+lv, norm);
lv = normalize(lv);
da = dot(norm, lv);
float fa = light_col[i].a+1.0;
float dist_atten = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0);
dist_atten *= noise;
float lit = da * dist_atten;
float sa = dot(normalize(lv+npos),norm);
vec3 col = light_col[i].rgb*lit*diff;
//vec3 col = vec3(dist2, light_col[i].a, lit);
if (sa > 0.0)
if (spec.a > 0.0)
{
sa = texture2D(lightFunc,vec2(sa, spec.a)).a * min(dist_atten*4.0, 1.0);
sa *= noise;
col += da*sa*light_col[i].rgb*spec.rgb;
//vec3 ref = dot(pos+lv, norm);
float sa = dot(normalize(lv+npos),norm);
if (sa > 0.0)
{
sa = texture2D(lightFunc,vec2(sa, spec.a)).a * min(dist_atten*4.0, 1.0);
sa *= noise;
col += da*sa*light_col[i].rgb*spec.rgb;
}
}
out_col += col;
}
out_col += col;
}
if (dot(out_col, out_col) <= 0.0)

View File

@@ -39,9 +39,9 @@
BOOL AscentKeyword::hasKeyword(std::string msg,int source)
{
static const LLCachedControl<bool> mKeywordsOn("KeywordsOn", false, gSavedPerAccountSettings);
static const LLCachedControl<bool> mKeywordsInChat("KeywordsInChat", false, gSavedPerAccountSettings);
static const LLCachedControl<bool> mKeywordsInIM("KeywordsInIM", false, gSavedPerAccountSettings);
static const LLCachedControl<bool> mKeywordsOn(gSavedPerAccountSettings,"KeywordsOn", false);
static const LLCachedControl<bool> mKeywordsInChat(gSavedPerAccountSettings,"KeywordsInChat", false);
static const LLCachedControl<bool> mKeywordsInIM(gSavedPerAccountSettings, "KeywordsInIM", false);
if (mKeywordsOn)
{
@@ -61,9 +61,9 @@ BOOL AscentKeyword::hasKeyword(std::string msg,int source)
bool AscentKeyword::containsKeyWord(std::string source)
{
static const LLCachedControl<std::string> mKeywordsList("KeywordsList", "", gSavedPerAccountSettings);
static const LLCachedControl<bool> mKeywordsPlaySound("KeywordsPlaySound", false, gSavedPerAccountSettings);
static const LLCachedControl<std::string> mKeywordsSound("KeywordsSound", "", gSavedPerAccountSettings);
static const LLCachedControl<std::string> mKeywordsList(gSavedPerAccountSettings, "KeywordsList", "");
static const LLCachedControl<bool> mKeywordsPlaySound(gSavedPerAccountSettings, "KeywordsPlaySound", false);
static const LLCachedControl<std::string> mKeywordsSound(gSavedPerAccountSettings, "KeywordsSound", "");
std::string s = mKeywordsList;
LLStringUtil::toLower(s);

View File

@@ -310,12 +310,6 @@ void JCFloaterAreaSearch::results()
sInstance->mLastUpdateTimer.reset();
}
// static
void JCFloaterAreaSearch::callbackLoadOwnerName(const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group, void* data)
{
results();
}
// static
void JCFloaterAreaSearch::processObjectPropertiesFamily(LLMessageSystem* msg, void** user_data)
{
@@ -335,8 +329,8 @@ void JCFloaterAreaSearch::processObjectPropertiesFamily(LLMessageSystem* msg, vo
msg->getUUIDFast(_PREHASH_ObjectData, _PREHASH_GroupID, details->group_id);
msg->getStringFast(_PREHASH_ObjectData, _PREHASH_Name, details->name);
msg->getStringFast(_PREHASH_ObjectData, _PREHASH_Description, details->desc);
gCacheName->get(details->owner_id, FALSE, callbackLoadOwnerName);
gCacheName->get(details->group_id, TRUE, callbackLoadOwnerName);
gCacheName->get(details->owner_id, false, boost::bind(&JCFloaterAreaSearch::results));
gCacheName->get(details->group_id, true, boost::bind(&JCFloaterAreaSearch::results));
//llinfos << "Got info for " << (exists ? "requested" : "unknown") << " object " << object_id << llendl;
}
}

View File

@@ -61,7 +61,6 @@ public:
static void results();
static void toggle();
static JCFloaterAreaSearch* getInstance() { return sInstance; }
static void callbackLoadOwnerName(const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group, void* data);
static void processObjectPropertiesFamily(LLMessageSystem* msg, void** user_data);
private:

View File

@@ -1328,7 +1328,7 @@ void LLAgent::startAutoPilotGlobal(
else
{
// Guess at a reasonable stop distance.
mAutoPilotStopDistance = fsqrtf( distance );
mAutoPilotStopDistance = (F32) sqrt( distance );
if (mAutoPilotStopDistance < 0.5f)
{
mAutoPilotStopDistance = 0.5f;

View File

@@ -33,9 +33,9 @@
#include "llagentaccess.h"
#include "indra_constants.h"
#include "llcontrolgroupreader.h"
#include "llcontrol.h"
LLAgentAccess::LLAgentAccess(LLControlGroupReader& savedSettings) :
LLAgentAccess::LLAgentAccess(LLControlGroup& savedSettings) :
mSavedSettings(savedSettings),
mAccess(SIM_ACCESS_PG),
mAdminOverride(false),

View File

@@ -36,12 +36,12 @@
#include "stdtypes.h"
// forward declaration so that we don't have to include the whole class
class LLControlGroupReader;
class LLControlGroup;
class LLAgentAccess
{
public:
LLAgentAccess(LLControlGroupReader& savedSettings);
LLAgentAccess(LLControlGroup& savedSettings);
bool getAdminOverride() const;
void setAdminOverride(bool b);
@@ -84,9 +84,7 @@ private:
// all of the code that depends on it.
bool mAOTransition;
// we want this to be const but the getters for it aren't, so we're
// overriding it for now
/* const */ LLControlGroupReader& mSavedSettings;
LLControlGroup& mSavedSettings;
};
#endif // LL_LLAGENTACCESS_H

View File

@@ -407,10 +407,14 @@ LLVector3 LLAgentCamera::calcFocusOffset(LLViewerObject *object, LLVector3 origi
{
return original_focus_point - obj_pos;
}
LLQuaternion inv_obj_rot = ~obj_rot; // get inverse of rotation
LLVector3 object_extents = object->getScale();
LLVector3 object_extents = object->getScale();
//this stuff just seems to make camera snapping worse...
//const LLVector4a* oe4 = object->mDrawable->getSpatialExtents();
//object_extents.set( oe4[1][0], oe4[1][1], oe4[1][2] );
// make sure they object extents are non-zero
object_extents.clamp(0.001f, F32_MAX);

View File

@@ -33,7 +33,6 @@
#include "llviewerprecompiledheaders.h"
#include "llappviewer.h"
#include "llprimitive.h"
#include "hippogridmanager.h"
#include "hippolimits.h"
@@ -78,12 +77,19 @@
#include "statemachine/aifilepicker.h"
#include "llfirstuse.h"
#include "llrender.h"
#include "llvector4a.h"
#include "llfont.h"
#include "llimagej2c.h"
#include "llvocache.h"
#include "llfloaterteleporthistory.h"
#include "llweb.h"
#include "llsecondlifeurls.h"
// Linden library includes
#include "llavatarnamecache.h"
#include "lldiriterator.h"
#include "llimagej2c.h"
#include "llprimitive.h"
#include <boost/bind.hpp>
#if LL_WINDOWS
@@ -116,7 +122,6 @@
#include "lltoolmgr.h"
#include "llassetstorage.h"
#include "llpolymesh.h"
#include "llcachename.h"
#include "llaudioengine.h"
#include "llstreamingaudio.h"
#include "llviewermenu.h"
@@ -180,8 +185,6 @@
#include "llviewerthrottle.h"
#include "llparcel.h"
#include "lldiriterator.h"
#include "llavatarnamecache.h"
#include "llinventoryview.h"
#include "llcommandlineparser.h"
@@ -560,6 +563,8 @@ bool LLAppViewer::init()
// we run the "program crashed last time" error handler below.
//
// initialize SSE options
LLVector4a::initClass();
// Need to do this initialization before we do anything else, since anything
// that touches files should really go through the lldir API
gDirUtilp->initAppDirs("SecondLife");
@@ -624,7 +629,9 @@ bool LLAppViewer::init()
// OS-specific login dialogs
/////////////////////////////////////////////////
//test_cached_control();
#if TEST_CACHED_CONTROL
test_cached_control();
#endif
// track number of times that app has run
mNumSessions = gSavedSettings.getS32("NumSessions");
@@ -1262,15 +1269,14 @@ bool LLAppViewer::cleanup()
LLPolyMesh::freeAllMeshes();
LLAvatarNameCache::cleanupClass();
delete gCacheName;
gCacheName = NULL;
LLStartUp::cleanupNameCache();
// Note: this is where gLocalSpeakerMgr and gActiveSpeakerMgr used to be deleted.
LLWorldMap::getInstance()->reset(); // release any images
LLCalc::cleanUp();
llinfos << "Global stuff deleted" << llendflush;
if (gAudiop)
@@ -1458,6 +1464,8 @@ bool LLAppViewer::cleanup()
// Save file- and dirpicker {context, default paths} map.
AIFilePicker::saveFile("filepicker_contexts.xml");
LLFloaterTeleportHistory::saveFile("teleport_history.xml");
// save mute list. gMuteList used to also be deleted here too.
LLMuteList::getInstance()->cache(gAgent.getID());
@@ -1558,6 +1566,8 @@ bool LLAppViewer::cleanup()
}
#endif
llinfos << "Misc Cleanup" << llendflush;
// For safety, the LLVFS has to be deleted *after* LLVFSThread. This should be cleaned up.
// (LLVFS doesn't know about LLVFSThread so can't kill pending requests) -Steve
delete gStaticVFS;
@@ -1572,6 +1582,7 @@ bool LLAppViewer::cleanup()
LLWatchdog::getInstance()->cleanup();
llinfos << "Shutting down message system" << llendflush;
end_messaging_system();
llinfos << "Message system deleted." << llendflush;
@@ -1821,7 +1832,7 @@ bool LLAppViewer::initConfiguration()
//Load settings files list
std::string settings_file_list = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "settings_files.xml");
LLControlGroup settings_control;
LLControlGroup settings_control("groups");
llinfos << "Loading settings file list" << settings_file_list << llendl;
if (0 == settings_control.loadFromFile(settings_file_list))
{
@@ -1883,7 +1894,7 @@ bool LLAppViewer::initConfiguration()
gSavedSettings.setBOOL("WatchdogEnabled", FALSE);
#endif
gCrashSettings.getControl(CRASH_BEHAVIOR_SETTING)->getSignal()->connect(boost::bind(&handleCrashSubmitBehaviorChanged, _1));
gCrashSettings.getControl(CRASH_BEHAVIOR_SETTING)->getSignal()->connect(boost::bind(&handleCrashSubmitBehaviorChanged, _2));
// These are warnings that appear on the first experience of that condition.
// They are already set in the settings_default.xml file, but still need to be added to LLFirstUse
@@ -3047,11 +3058,23 @@ U32 LLAppViewer::getTextureCacheVersion()
return TEXTURE_CACHE_VERSION ;
}
//static
U32 LLAppViewer::getObjectCacheVersion()
{
// Viewer object cache version, change if object update
// format changes. JC
const U32 INDRA_OBJECT_CACHE_VERSION = 14;
return INDRA_OBJECT_CACHE_VERSION;
}
bool LLAppViewer::initCache()
{
mPurgeCache = false;
BOOL read_only = mSecondInstance ? TRUE : FALSE;
LLAppViewer::getTextureCache()->setReadOnly(read_only);
LLAppViewer::getTextureCache()->setReadOnly(read_only) ;
LLVOCache::getInstance()->setReadOnly(read_only);
bool texture_cache_mismatch = false;
if (gSavedSettings.getS32("LocalCacheVersion") != LLAppViewer::getTextureCacheVersion())
@@ -3131,6 +3154,8 @@ bool LLAppViewer::initCache()
S64 extra = LLAppViewer::getTextureCache()->initCache(LL_PATH_CACHE, texture_cache_size, texture_cache_mismatch);
texture_cache_size -= extra;
LLVOCache::getInstance()->initCache(LL_PATH_CACHE, gSavedSettings.getU32("CacheNumberOfRegionsForObjects"), getObjectCacheVersion()) ;
LLSplashScreen::update("Initializing VFS...");
// Init the VFS
@@ -3287,8 +3312,9 @@ bool LLAppViewer::initCache()
void LLAppViewer::purgeCache()
{
LL_INFOS("AppCache") << "Purging Cache and Texture Cache..." << LL_ENDL;
LL_INFOS("AppCache") << "Purging Cache and Texture Cache..." << llendl;
LLAppViewer::getTextureCache()->purgeCache(LL_PATH_CACHE);
LLVOCache::getInstance()->removeCache(LL_PATH_CACHE);
std::string mask = "*.*";
gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ""), mask);
}
@@ -3442,12 +3468,14 @@ void LLAppViewer::loadNameCache()
// Try to load from the legacy format. This should go away after a
// while. Phoenix 2008-01-30
#if 0
LLFILE* name_cache_fp = LLFile::fopen(name_cache, "r"); // Flawfinder: ignore
if (name_cache_fp)
{
gCacheName->importFile(name_cache_fp);
fclose(name_cache_fp);
}
#endif
}
void LLAppViewer::saveNameCache()
@@ -3645,9 +3673,6 @@ void LLAppViewer::idle()
{
LLFastTimer t(LLFastTimer::FTM_NETWORK);
// Phoenix: Wolfspirit: Prepare the namecache.
idleNameCache();
////////////////////////////////////////////////
//
// Network processing
@@ -3655,6 +3680,7 @@ void LLAppViewer::idle()
// NOTE: Starting at this point, we may still have pointers to "dead" objects
// floating throughout the various object lists.
//
idleNameCache();
gFrameStats.start(LLFrameStats::IDLE_NETWORK);
stop_glerror();
@@ -3999,11 +4025,9 @@ void LLAppViewer::idleNameCache()
if (had_capability != have_capability)
{
// name tags are persistant on screen, so make sure they refresh
//LLVOAvatar::invalidateNameTags();
LLVOAvatar::invalidateNameTags(); //Should this be commented out?
}
// Phoenix: Wolfspirit: Check if we are using Display Names and set it. Then idle the cache.
LLAvatarNameCache::idle();
}
@@ -4068,8 +4092,6 @@ void LLAppViewer::idleNetwork()
{
LLFastTimer t(LLFastTimer::FTM_IDLE_NETWORK); // decode
// deal with any queued name requests and replies.
gCacheName->processPending();
llpushcallstacks ;
LLTimer check_message_timer;
// Read all available packets from network
@@ -4251,7 +4273,10 @@ void LLAppViewer::disconnectViewer()
// This is where we used to call gObjectList.destroy() and then delete gWorldp.
// Now we just ask the LLWorld singleton to cleanly shut down.
LLWorld::getInstance()->destroyClass();
if(LLWorld::instanceExists())
{
LLWorld::getInstance()->destroyClass();
}
// call all self-registered classes
LLDestroyClassList::instance().fireCallbacks();

View File

@@ -96,7 +96,9 @@ public:
static LLImageDecodeThread* getImageDecodeThread() { return sImageDecodeThread; }
static LLTextureFetch* getTextureFetch() { return sTextureFetch; }
static U32 getTextureCacheVersion();
static U32 getTextureCacheVersion() ;
static U32 getObjectCacheVersion() ;
const std::string& getSerialNumber() { return mSerialNumber; }
bool getPurgeCache() const { return mPurgeCache; }

Some files were not shown because too many files have changed in this diff Show More