diff options
Diffstat (limited to 'indra/llmath')
| -rw-r--r-- | indra/llmath/CMakeLists.txt | 3 | ||||
| -rw-r--r-- | indra/llmath/llmatrix4a.cpp | 80 | ||||
| -rw-r--r-- | indra/llmath/llmatrix4a.h | 14 | ||||
| -rw-r--r-- | indra/llmath/llrigginginfo.cpp | 159 | ||||
| -rw-r--r-- | indra/llmath/llrigginginfo.h | 100 | ||||
| -rw-r--r-- | indra/llmath/llvector4a.h | 7 | ||||
| -rw-r--r-- | indra/llmath/llvolume.cpp | 104 | ||||
| -rw-r--r-- | indra/llmath/llvolume.h | 7 | ||||
| -rw-r--r-- | indra/llmath/v3math.cpp | 36 | ||||
| -rw-r--r-- | indra/llmath/v3math.h | 2 | 
10 files changed, 411 insertions, 101 deletions
| diff --git a/indra/llmath/CMakeLists.txt b/indra/llmath/CMakeLists.txt index 61d13c0b1c..999bee0a3f 100644 --- a/indra/llmath/CMakeLists.txt +++ b/indra/llmath/CMakeLists.txt @@ -20,10 +20,12 @@ set(llmath_SOURCE_FILES      llcoordframe.cpp      llline.cpp      llmatrix3a.cpp +    llmatrix4a.cpp      llmodularmath.cpp      lloctree.cpp      llperlin.cpp      llquaternion.cpp +    llrigginginfo.cpp      llrect.cpp      llsphere.cpp      llvector4a.cpp @@ -70,6 +72,7 @@ set(llmath_HEADER_FILES      llquaternion2.h      llquaternion2.inl      llrect.h +    llrigginginfo.h      llsimdmath.h      llsimdtypes.h      llsimdtypes.inl diff --git a/indra/llmath/llmatrix4a.cpp b/indra/llmath/llmatrix4a.cpp new file mode 100644 index 0000000000..fe8f0b98f3 --- /dev/null +++ b/indra/llmath/llmatrix4a.cpp @@ -0,0 +1,80 @@ +/** +* @file llmatrix4a.cpp +* @brief  Functions for vectorized matrix/vector operations +* +* $LicenseInfo:firstyear=2018&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2018, 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 "llmatrix4a.h" + +// Convert a bounding box into other coordinate system. Should give +// the same results as transforming every corner of the bounding box +// and extracting the bounding box of that, although that's not +// necessarily the fastest way to implement. +void matMulBoundBox(const LLMatrix4a &mat, const LLVector4a *in_extents, LLVector4a *out_extents) +{ +		//get 8 corners of bounding box +		LLVector4Logical mask[6]; + +		for (U32 i = 0; i < 6; ++i) +		{ +			mask[i].clear(); +		} + +		mask[0].setElement<2>(); //001 +		mask[1].setElement<1>(); //010 +		mask[2].setElement<1>(); //011 +		mask[2].setElement<2>(); +		mask[3].setElement<0>(); //100 +		mask[4].setElement<0>(); //101 +		mask[4].setElement<2>(); +		mask[5].setElement<0>(); //110 +		mask[5].setElement<1>(); + +		LLVector4a v[8]; + +		v[6] = in_extents[0]; +		v[7] = in_extents[1]; + +		for (U32 i = 0; i < 6; ++i) +		{ +			v[i].setSelectWithMask(mask[i], in_extents[0], in_extents[1]); +		} + +		LLVector4a tv[8]; + +		//transform bounding box into drawable space +		for (U32 i = 0; i < 8; ++i) +		{ +			mat.affineTransform(v[i], tv[i]); +		} +	 +		//find bounding box +		out_extents[0] = out_extents[1] = tv[0]; + +		for (U32 i = 1; i < 8; ++i) +		{ +			out_extents[0].setMin(out_extents[0], tv[i]); +			out_extents[1].setMax(out_extents[1], tv[i]); +		} +} diff --git a/indra/llmath/llmatrix4a.h b/indra/llmath/llmatrix4a.h index 216334752a..7ba347062f 100644 --- a/indra/llmath/llmatrix4a.h +++ b/indra/llmath/llmatrix4a.h @@ -121,7 +121,7 @@ public:  		res.add(z);  	} -	inline void affineTransformSSE(const LLVector4a& v, LLVector4a& res) +	inline void affineTransformSSE(const LLVector4a& v, LLVector4a& res) const  	{  		LLVector4a x,y,z; @@ -138,7 +138,7 @@ public:  		res.setAdd(x,z);  	} -    inline void affineTransformNonSSE(const LLVector4a& v, LLVector4a& res) +    inline void affineTransformNonSSE(const LLVector4a& v, LLVector4a& res) const      {          F32 x = v[0] * mMatrix[0][0] + v[1] * mMatrix[1][0] + v[2] * mMatrix[2][0] + mMatrix[3][0];          F32 y = v[0] * mMatrix[0][1] + v[1] * mMatrix[1][1] + v[2] * mMatrix[2][1] + mMatrix[3][1]; @@ -147,7 +147,7 @@ public:          res.set(x,y,z,w);      } -	inline void affineTransform(const LLVector4a& v, LLVector4a& res) +	inline void affineTransform(const LLVector4a& v, LLVector4a& res) const      {          affineTransformSSE(v,res);      } @@ -176,4 +176,12 @@ inline void matMul(const LLMatrix4a &a, const LLMatrix4a &b, LLMatrix4a &res)      res.mMatrix[3] = row3;  } +inline std::ostream& operator<<(std::ostream& s, const LLMatrix4a& m) +{ +    s << "[" << m.mMatrix[0] << ", " << m.mMatrix[1] << ", " << m.mMatrix[2] << ", " << m.mMatrix[3] << "]"; +    return s; +}  + +void matMulBoundBox(const LLMatrix4a &a, const LLVector4a *in_extents, LLVector4a *out_extents); +  #endif diff --git a/indra/llmath/llrigginginfo.cpp b/indra/llmath/llrigginginfo.cpp new file mode 100644 index 0000000000..0de07950c1 --- /dev/null +++ b/indra/llmath/llrigginginfo.cpp @@ -0,0 +1,159 @@ +/** +* @file llrigginginfo.cpp +* @brief  Functions for tracking rigged box extents +* +* $LicenseInfo:firstyear=2018&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2018, 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 "llrigginginfo.h" + +//----------------------------------------------------------------------------- +// LLJointRiggingInfo +//----------------------------------------------------------------------------- +LLJointRiggingInfo::LLJointRiggingInfo() +{ +    mRiggedExtents[0].clear(); +    mRiggedExtents[1].clear(); +    mIsRiggedTo = false; +} + +bool LLJointRiggingInfo::isRiggedTo() const +{ +    return mIsRiggedTo; +} + +void LLJointRiggingInfo::setIsRiggedTo(bool val) +{ +    mIsRiggedTo = val; +} +     +LLVector4a *LLJointRiggingInfo::getRiggedExtents() +{ +    return mRiggedExtents; +} + +const LLVector4a *LLJointRiggingInfo::getRiggedExtents() const +{ +    return mRiggedExtents; +} + +// Combine two rigging info states. +// - isRiggedTo if either of the source infos are rigged to +// - box is union of the two sources +void LLJointRiggingInfo::merge(const LLJointRiggingInfo& other) +{ +    if (other.mIsRiggedTo) +    { +        if (mIsRiggedTo) +        { +            // Combine existing boxes +            update_min_max(mRiggedExtents[0], mRiggedExtents[1], other.mRiggedExtents[0]); +            update_min_max(mRiggedExtents[0], mRiggedExtents[1], other.mRiggedExtents[1]); +        } +        else +        { +            // Initialize box +            mIsRiggedTo = true; +            mRiggedExtents[0] = other.mRiggedExtents[0]; +            mRiggedExtents[1] = other.mRiggedExtents[1]; +        } +    } +} + +LLJointRiggingInfoTab::LLJointRiggingInfoTab(): +    mRigInfoPtr(NULL), +    mSize(0), +    mNeedsUpdate(true) +{ +} + +LLJointRiggingInfoTab::~LLJointRiggingInfoTab() +{ +    clear(); +} + +// This doesn't preserve data if the size changes. In practice +// this doesn't matter because the size is always either +// LL_CHARACTER_MAX_ANIMATED_JOINTS or 0. +void LLJointRiggingInfoTab::resize(S32 size) +{ +    if (size != mSize) +    { +        clear(); +        if (size > 0) +        { +            mRigInfoPtr = new LLJointRiggingInfo[size]; +            mSize = size; +        } +    } +} + +void LLJointRiggingInfoTab::clear() +{ +    if (mRigInfoPtr) +    { +        delete[](mRigInfoPtr); +        mRigInfoPtr = NULL; +        mSize = 0; +    } +} + +void showDetails(const LLJointRiggingInfoTab& src, const std::string& str) +{ +	S32 count_rigged = 0; +	S32 count_box = 0; +    LLVector4a zero_vec; +    zero_vec.clear(); +    for (S32 i=0; i<src.size(); i++) +    { +        if (src[i].isRiggedTo()) +        { +            count_rigged++; +            if ((!src[i].getRiggedExtents()[0].equals3(zero_vec)) || +                (!src[i].getRiggedExtents()[1].equals3(zero_vec))) +            { +                count_box++; +            } +       } +    } +    LL_DEBUGS("RigSpammish") << "details: " << str << " has " << count_rigged << " rigged joints, of which " << count_box << " are non-empty" << LL_ENDL; +} + +void LLJointRiggingInfoTab::merge(const LLJointRiggingInfoTab& src) +{ +    //showDetails(*this, "input this"); +    // Size should be either LL_CHARACTER_MAX_ANIMATED_JOINTS, or 0 if +    // no data. Not necessarily the same for both inputs. +    if (src.size() > size()) +    { +        resize(src.size()); +    } +    S32 min_size = llmin(size(), src.size()); +    for (S32 i=0; i<min_size; i++) +    { +        (*this)[i].merge(src[i]); +    } +    //showDetails(src, "input src"); +    //showDetails(*this, "output this"); + +} diff --git a/indra/llmath/llrigginginfo.h b/indra/llmath/llrigginginfo.h new file mode 100644 index 0000000000..b3d6bc2d19 --- /dev/null +++ b/indra/llmath/llrigginginfo.h @@ -0,0 +1,100 @@ +/** +* @file llrigginginfo.h +* @brief  Functions for tracking rigged box extents +* +* $LicenseInfo:firstyear=2018&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2018, 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$ +*/ + +// Stores information related to associated rigged mesh vertices +// This lives in llmath because llvolume lives in llmath. + +#ifndef	LL_LLRIGGINGINFO_H +#define	LL_LLRIGGINGINFO_H + +#include "llvector4a.h" + +// Extents are in joint space +// isRiggedTo is based on the state of all currently associated rigged meshes +LL_ALIGN_PREFIX(16) +class LLJointRiggingInfo +{ +public: +    LLJointRiggingInfo(); +    bool isRiggedTo() const; +    void setIsRiggedTo(bool val); +    LLVector4a *getRiggedExtents(); +    const LLVector4a *getRiggedExtents() const; +    void merge(const LLJointRiggingInfo& other); + +	void* operator new(size_t size) +	{ +		return ll_aligned_malloc_16(size); +	} + +	void operator delete(void* ptr) +	{ +		ll_aligned_free_16(ptr); +	} + +	void* operator new[](size_t size) +	{ +		return ll_aligned_malloc_16(size); +	} + +	void operator delete[](void* ptr) +	{ +		ll_aligned_free_16(ptr); +	} + + +private: +	LL_ALIGN_16(LLVector4a mRiggedExtents[2]); +    bool mIsRiggedTo; +} LL_ALIGN_POSTFIX(16); + +// For storing all the rigging info associated with a given avatar or +// object, keyed by joint_num. +// Using direct memory management instead of std::vector<> to avoid alignment issues. +class LLJointRiggingInfoTab +{ +public: +    LLJointRiggingInfoTab(); +    ~LLJointRiggingInfoTab(); +    void resize(S32 size); +    void clear(); +    S32 size() const { return mSize; } +    void merge(const LLJointRiggingInfoTab& src); +    LLJointRiggingInfo& operator[](S32 i) { return mRigInfoPtr[i]; } +    const LLJointRiggingInfo& operator[](S32 i) const { return mRigInfoPtr[i]; }; +    bool needsUpdate() { return mNeedsUpdate; } +    void setNeedsUpdate(bool val) { mNeedsUpdate = val; } +private: +    // Not implemented +    LLJointRiggingInfoTab& operator=(const LLJointRiggingInfoTab& src); +    LLJointRiggingInfoTab(const LLJointRiggingInfoTab& src); + +    LLJointRiggingInfo *mRigInfoPtr; +    S32 mSize; +    bool mNeedsUpdate; +}; + +#endif diff --git a/indra/llmath/llvector4a.h b/indra/llmath/llvector4a.h index 79d0a44551..222f3cf235 100644 --- a/indra/llmath/llvector4a.h +++ b/indra/llmath/llvector4a.h @@ -320,7 +320,7 @@ public:  	inline const LLVector4a& operator= ( const LLQuad& rhs );  	inline operator LLQuad() const;	 - +      private:  	LLQuad mQ;  } LL_ALIGN_POSTFIX(16); @@ -331,4 +331,9 @@ inline void update_min_max(LLVector4a& min, LLVector4a& max, const LLVector4a& p  	max.setMax(max, p);  } +inline std::ostream& operator<<(std::ostream& s, const LLVector4a& v) +{ +    s << "(" << v[0] << ", " << v[1] << ", " << v[2] << ", " << v[3] << ")"; +    return s; +}  #endif diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index b1d1b9a3e8..0e1748b337 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -1,5 +1,4 @@  /**  -   * @file llvolume.cpp   *   * $LicenseInfo:firstyear=2002&license=viewerlgpl$ @@ -2645,6 +2644,7 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size)  			}  			//calculate bounding box +			// VFExtents change  			LLVector4a& min = face.mExtents[0];  			LLVector4a& max = face.mExtents[1]; @@ -4774,6 +4774,7 @@ LLVolumeFace::~LLVolumeFace()  {  	ll_aligned_free_16(mExtents);  	mExtents = NULL; +	mCenter = NULL;  	freeData();  } @@ -4955,7 +4956,7 @@ void LLVolumeFace::optimize(F32 angle_cutoff)  	//  	if (new_face.mNumVertices <= mNumVertices)  	{ -	llassert(new_face.mNumIndices == mNumIndices); +        llassert(new_face.mNumIndices == mNumIndices);  		swapData(new_face);  	} @@ -5576,7 +5577,7 @@ BOOL LLVolumeFace::createUnCutCubeCap(LLVolume* volume, BOOL partial_build)  	// S32 i;  	S32	grid_size = (profile.size()-1)/4; - +	// VFExtents change  	LLVector4a& min = mExtents[0];  	LLVector4a& max = mExtents[1]; @@ -5853,7 +5854,7 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build)  	LLVector2 cuv;  	LLVector2 min_uv, max_uv; - +	// VFExtents change  	LLVector4a& min = mExtents[0];  	LLVector4a& max = mExtents[1]; @@ -6292,6 +6293,9 @@ void LLVolumeFace::resizeVertices(S32 num_verts)  	mNumVertices = num_verts;  	mNumAllocatedVertices = num_verts; + +    // Force update +    mJointRiggingInfoTab.clear();  }  void LLVolumeFace::pushVertex(const LLVolumeFace::VertexData& cv) @@ -6413,96 +6417,6 @@ void LLVolumeFace::fillFromLegacyData(std::vector<LLVolumeFace::VertexData>& v,  	}  } -void LLVolumeFace::appendFace(const LLVolumeFace& face, LLMatrix4& mat_in, LLMatrix4& norm_mat_in) -{ -	U16 offset = mNumVertices; - -	S32 new_count = face.mNumVertices + mNumVertices; - -	if (new_count > 65536) -	{ -		LL_ERRS() << "Cannot append face -- 16-bit overflow will occur." << LL_ENDL; -	} -	 -	if (face.mNumVertices == 0) -	{ -		LL_ERRS() << "Cannot append empty face." << LL_ENDL; -	} - -	U32 old_vsize = mNumVertices*16; -	U32 new_vsize = new_count * 16; -	U32 old_tcsize = (mNumVertices*sizeof(LLVector2)+0xF) & ~0xF; -	U32 new_tcsize = (new_count*sizeof(LLVector2)+0xF) & ~0xF; -	U32 new_size = new_vsize * 2 + new_tcsize; - -	//allocate new buffer space -	LLVector4a* old_buf = mPositions; -	mPositions = (LLVector4a*) ll_aligned_malloc<64>(new_size); -	mNormals = mPositions + new_count; -	mTexCoords = (LLVector2*) (mNormals+new_count); - -	mNumAllocatedVertices = new_count; - -	LLVector4a::memcpyNonAliased16((F32*) mPositions, (F32*) old_buf, old_vsize); -	LLVector4a::memcpyNonAliased16((F32*) mNormals, (F32*) (old_buf+mNumVertices), old_vsize); -	LLVector4a::memcpyNonAliased16((F32*) mTexCoords, (F32*) (old_buf+mNumVertices*2), old_tcsize); -	 -	mNumVertices = new_count; - -	//get destination address of appended face -	LLVector4a* dst_pos = mPositions+offset; -	LLVector2* dst_tc = mTexCoords+offset; -	LLVector4a* dst_norm = mNormals+offset; - -	//get source addresses of appended face -	const LLVector4a* src_pos = face.mPositions; -	const LLVector2* src_tc = face.mTexCoords; -	const LLVector4a* src_norm = face.mNormals; - -	//load aligned matrices -	LLMatrix4a mat, norm_mat; -	mat.loadu(mat_in); -	norm_mat.loadu(norm_mat_in); - -	for (U32 i = 0; i < face.mNumVertices; ++i) -	{ -		//transform appended face position and store -		mat.affineTransform(src_pos[i], dst_pos[i]); - -		//transform appended face normal and store -		norm_mat.rotate(src_norm[i], dst_norm[i]); -		dst_norm[i].normalize3fast(); - -		//copy appended face texture coordinate -		dst_tc[i] = src_tc[i]; - -		if (offset == 0 && i == 0) -		{ //initialize bounding box -			mExtents[0] = mExtents[1] = dst_pos[i]; -		} -		else -		{ -			//stretch bounding box -			update_min_max(mExtents[0], mExtents[1], dst_pos[i]); -		} -	} - - -	new_count = mNumIndices + face.mNumIndices; - -	//allocate new index buffer -	mIndices = (U16*) ll_aligned_realloc_16(mIndices, (new_count*sizeof(U16)+0xF) & ~0xF, (mNumIndices*sizeof(U16)+0xF) & ~0xF); -	 -	//get destination address into new index buffer -	U16* dst_idx = mIndices+mNumIndices; -	mNumIndices = new_count; - -	for (U32 i = 0; i < face.mNumIndices; ++i) -	{ //copy indices, offsetting by old vertex count -		dst_idx[i] = face.mIndices[i]+offset; -	} -} -  BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)  {  	LL_CHECK_MEMORY @@ -6648,7 +6562,7 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)  	{  		update_min_max(face_min, face_max, *cur_pos++);  	} - +	// VFExtents change  	mExtents[0] = face_min;  	mExtents[1] = face_max; diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h index d3c1ac46fe..1d6d35c432 100644 --- a/indra/llmath/llvolume.h +++ b/indra/llmath/llvolume.h @@ -57,6 +57,7 @@ class LLVolumeTriangle;  #include "llpointer.h"  #include "llfile.h"  #include "llalignedarray.h" +#include "llrigginginfo.h"  //============================================================================ @@ -871,8 +872,6 @@ public:  	BOOL create(LLVolume* volume, BOOL partial_build = FALSE);  	void createTangents(); -	void appendFace(const LLVolumeFace& face, LLMatrix4& transform, LLMatrix4& normal_tranform); -  	void resizeVertices(S32 num_verts);  	void allocateTangents(S32 num_verts);  	void allocateWeights(S32 num_verts); @@ -958,6 +957,10 @@ public:  	LLVector4a* mWeights;      mutable BOOL mWeightsScrubbed; + +    // Which joints are rigged to, and the bounding box of any rigged +    // vertices per joint. +    LLJointRiggingInfoTab mJointRiggingInfoTab;  	LLOctreeNode<LLVolumeTriangle>* mOctree; diff --git a/indra/llmath/v3math.cpp b/indra/llmath/v3math.cpp index e7107dee16..b04c67d926 100644 --- a/indra/llmath/v3math.cpp +++ b/indra/llmath/v3math.cpp @@ -369,3 +369,39 @@ BOOL LLVector3::parseVector3(const std::string& buf, LLVector3* value)  	return FALSE;  } + +// Displacement from query point to nearest neighbor point on bounding box. +// Returns zero vector for points within or on the box. +LLVector3 point_to_box_offset(LLVector3& pos, const LLVector3* box) +{ +    LLVector3 offset; +    for (S32 k=0; k<3; k++) +    { +        offset[k] = 0; +        if (pos[k] < box[0][k]) +        { +            offset[k] = pos[k] - box[0][k]; +        } +        else if (pos[k] > box[1][k]) +        { +            offset[k] = pos[k] - box[1][k]; +        } +    } +    return offset; +} + +bool box_valid_and_non_zero(const LLVector3* box) +{ +    if (!box[0].isFinite() || !box[1].isFinite()) +    { +        return false; +    } +    LLVector3 zero_vec; +    zero_vec.clear(); +    if ((box[0] != zero_vec) || (box[1] != zero_vec)) +    { +        return true; +    } +    return false; +} + diff --git a/indra/llmath/v3math.h b/indra/llmath/v3math.h index f3fbce4843..6f857d7061 100644 --- a/indra/llmath/v3math.h +++ b/indra/llmath/v3math.h @@ -163,6 +163,8 @@ LLVector3 inverse_projected_vec(const LLVector3 &a, const LLVector3 &b); // Retu  LLVector3 parallel_component(const LLVector3 &a, const LLVector3 &b); // Returns vector a projected on vector b (same as projected_vec)  LLVector3 orthogonal_component(const LLVector3 &a, const LLVector3 &b); // Returns component of vector a not parallel to vector b (same as projected_vec)  LLVector3 lerp(const LLVector3 &a, const LLVector3 &b, F32 u); // Returns a vector that is a linear interpolation between a and b +LLVector3 point_to_box_offset(LLVector3& pos, const LLVector3* box); // Displacement from query point to nearest point on bounding box. +bool box_valid_and_non_zero(const LLVector3* box);  inline LLVector3::LLVector3(void)  { | 
