Merge branch 'V2Mesh' of https://github.com/Shyotl/SingularityViewer into future
Conflicts: indra/llvfs/lldiriterator.cpp indra/newview/app_settings/settings.xml indra/newview/llviewerregion.cpp
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -38,6 +38,8 @@
|
||||
#include <iosfwd>
|
||||
#include <string>
|
||||
|
||||
#include "llpreprocessor.h"
|
||||
|
||||
#include "stdtypes.h"
|
||||
|
||||
/**
|
||||
|
||||
@@ -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
107
indra/llcommon/stringize.h
Normal 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) */
|
||||
@@ -89,7 +89,8 @@ LLCrashLogger::LLCrashLogger() :
|
||||
mCrashBehavior(CRASH_BEHAVIOR_ASK),
|
||||
mCrashInPreviousExec(false),
|
||||
mSentCrashLogs(false),
|
||||
mCrashHost("")
|
||||
mCrashHost(""),
|
||||
mCrashSettings("CrashSettings")
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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); }
|
||||
|
||||
|
||||
@@ -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 ¢er, const LLVector3& radius)
|
||||
S32 LLCamera::AABBInFrustum(const LLVector4a ¢er, 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 ¢er, 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);
|
||||
|
||||
@@ -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 ¢er, const F32 radius) const;
|
||||
S32 pointInFrustum(const LLVector3 &point) const { return sphereInFrustum(point, 0.0f); }
|
||||
S32 sphereInFrustumFull(const LLVector3 ¢er, const F32 radius) const { return sphereInFrustum(center, radius); }
|
||||
S32 AABBInFrustum(const LLVector3 ¢er, const LLVector3& radius);
|
||||
S32 AABBInFrustumNoFarClip(const LLVector3 ¢er, 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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
134
indra/llmath/llmatrix3a.cpp
Normal 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
128
indra/llmath/llmatrix3a.h
Normal 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
119
indra/llmath/llmatrix3a.inl
Normal 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
143
indra/llmath/llmatrix4a.h
Normal 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
|
||||
@@ -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 ¢er, const LLVector3d &size, const T* data)
|
||||
static void pushCenter(LLVector4a ¢er, 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 ¢er,
|
||||
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
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
105
indra/llmath/llquaternion2.h
Normal file
105
indra/llmath/llquaternion2.h
Normal 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
|
||||
102
indra/llmath/llquaternion2.inl
Normal file
102
indra/llmath/llquaternion2.inl
Normal 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();
|
||||
}
|
||||
|
||||
@@ -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
93
indra/llmath/llsimdmath.h
Normal 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
124
indra/llmath/llsimdtypes.h
Normal 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
|
||||
157
indra/llmath/llsimdtypes.inl
Normal file
157
indra/llmath/llsimdtypes.inl
Normal 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;
|
||||
}
|
||||
@@ -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
222
indra/llmath/llvector4a.cpp
Normal 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
324
indra/llmath/llvector4a.h
Normal 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
593
indra/llmath/llvector4a.inl
Normal 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;
|
||||
}
|
||||
124
indra/llmath/llvector4logical.h
Normal file
124
indra/llmath/llvector4logical.h
Normal 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
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
257
indra/llmath/llvolumeoctree.cpp
Normal file
257
indra/llmath/llvolumeoctree.cpp
Normal 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
|
||||
|
||||
135
indra/llmath/llvolumeoctree.h
Normal file
135
indra/llmath/llvolumeoctree.h
Normal 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
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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:
|
||||
/**
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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() ;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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()*/);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user