summaryrefslogtreecommitdiff
path: root/indra/llmath
diff options
context:
space:
mode:
authorAndreyL ProductEngine <alihatskiy@productengine.com>2018-11-14 22:47:31 +0200
committerAndreyL ProductEngine <alihatskiy@productengine.com>2018-11-14 22:47:31 +0200
commitc21396181b090b626d7a9f989bcead2e517bb75f (patch)
treec543941ee817a5b5952ff670d8ae03cd4663bd88 /indra/llmath
parent62085f9f7904aa20406aa4f0122065aec3a786ee (diff)
parent8558ce5c600b810356010ba3cd6d534ef22f4081 (diff)
Merged in lindenlab/viewer-release
Diffstat (limited to 'indra/llmath')
-rw-r--r--indra/llmath/CMakeLists.txt3
-rw-r--r--indra/llmath/llmatrix4a.cpp80
-rw-r--r--indra/llmath/llmatrix4a.h14
-rw-r--r--indra/llmath/llrigginginfo.cpp159
-rw-r--r--indra/llmath/llrigginginfo.h100
-rw-r--r--indra/llmath/llvector4a.h7
-rw-r--r--indra/llmath/llvolume.cpp104
-rw-r--r--indra/llmath/llvolume.h7
-rw-r--r--indra/llmath/v3math.cpp36
-rw-r--r--indra/llmath/v3math.h2
10 files changed, 411 insertions, 101 deletions
diff --git a/indra/llmath/CMakeLists.txt b/indra/llmath/CMakeLists.txt
index 4c8bcdac91..379c3ee9ea 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 a34999b6fd..e7a8ca2f9d 100644
--- a/indra/llmath/llvolume.cpp
+++ b/indra/llmath/llvolume.cpp
@@ -1,5 +1,4 @@
/**
-
* @file llvolume.cpp
*
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
@@ -2646,6 +2645,7 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size)
}
//calculate bounding box
+ // VFExtents change
LLVector4a& min = face.mExtents[0];
LLVector4a& max = face.mExtents[1];
@@ -4775,6 +4775,7 @@ LLVolumeFace::~LLVolumeFace()
{
ll_aligned_free_16(mExtents);
mExtents = NULL;
+ mCenter = NULL;
freeData();
}
@@ -4956,7 +4957,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);
}
@@ -5577,7 +5578,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];
@@ -5854,7 +5855,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];
@@ -6293,6 +6294,9 @@ void LLVolumeFace::resizeVertices(S32 num_verts)
mNumVertices = num_verts;
mNumAllocatedVertices = num_verts;
+
+ // Force update
+ mJointRiggingInfoTab.clear();
}
void LLVolumeFace::pushVertex(const LLVolumeFace::VertexData& cv)
@@ -6414,96 +6418,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
@@ -6649,7 +6563,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)
{