summaryrefslogtreecommitdiff
path: root/indra/llmath
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llmath')
-rw-r--r--indra/llmath/CMakeLists.txt12
-rw-r--r--indra/llmath/camera.h27
-rw-r--r--indra/llmath/coordframe.h27
-rw-r--r--indra/llmath/llbbox.h4
-rw-r--r--indra/llmath/llbboxlocal.h3
-rw-r--r--indra/llmath/llcalc.cpp11
-rw-r--r--indra/llmath/llcalc.h7
-rw-r--r--indra/llmath/llcalcparser.h12
-rw-r--r--indra/llmath/llcamera.h12
-rw-r--r--indra/llmath/llcoordframe.cpp26
-rw-r--r--indra/llmath/llline.h5
-rw-r--r--indra/llmath/llmath.h2
-rw-r--r--indra/llmath/llmatrix3a.cpp2
-rw-r--r--indra/llmath/llmatrix3a.h13
-rw-r--r--indra/llmath/llmatrix4a.h12
-rw-r--r--indra/llmath/llplane.h10
-rw-r--r--indra/llmath/llquantize.h8
-rw-r--r--indra/llmath/llquaternion.cpp4
-rw-r--r--indra/llmath/llquaternion.h4
-rw-r--r--indra/llmath/llquaternion2.h7
-rw-r--r--indra/llmath/llquaternion2.inl7
-rw-r--r--indra/llmath/llrect.h8
-rw-r--r--indra/llmath/llrigginginfo.h7
-rw-r--r--indra/llmath/llsimdmath.h8
-rw-r--r--indra/llmath/llsimdtypes.h12
-rw-r--r--indra/llmath/llsimdtypes.inl4
-rw-r--r--indra/llmath/llsphere.cpp370
-rw-r--r--indra/llmath/llsphere.h77
-rw-r--r--indra/llmath/llvector4a.cpp14
-rw-r--r--indra/llmath/llvector4a.h11
-rw-r--r--indra/llmath/llvector4a.inl49
-rw-r--r--indra/llmath/llvector4logical.h10
-rw-r--r--indra/llmath/llvolume.cpp262
-rw-r--r--indra/llmath/llvolumemgr.cpp1
-rw-r--r--indra/llmath/llvolumeoctree.h18
-rw-r--r--indra/llmath/m3math.h4
-rw-r--r--indra/llmath/m4math.cpp4
-rw-r--r--indra/llmath/m4math.h6
-rw-r--r--indra/llmath/raytrace.cpp1
-rw-r--r--indra/llmath/tests/alignment_test.cpp5
-rw-r--r--indra/llmath/tests/llquaternion_test.cpp6
-rw-r--r--indra/llmath/tests/mathmisc_test.cpp161
-rw-r--r--indra/llmath/v2math.cpp7
-rw-r--r--indra/llmath/v2math.h93
-rw-r--r--indra/llmath/v3color.h5
-rw-r--r--indra/llmath/v3dmath.h4
-rw-r--r--indra/llmath/v3math.h154
-rw-r--r--indra/llmath/v4color.h4
-rw-r--r--indra/llmath/v4coloru.h4
-rw-r--r--indra/llmath/v4math.h158
50 files changed, 580 insertions, 1102 deletions
diff --git a/indra/llmath/CMakeLists.txt b/indra/llmath/CMakeLists.txt
index e21b6fdb84..b54bfb7705 100644
--- a/indra/llmath/CMakeLists.txt
+++ b/indra/llmath/CMakeLists.txt
@@ -23,7 +23,6 @@ set(llmath_SOURCE_FILES
llquaternion.cpp
llrigginginfo.cpp
llrect.cpp
- llsphere.cpp
llvector4a.cpp
llvolume.cpp
llvolumemgr.cpp
@@ -45,8 +44,6 @@ set(llmath_SOURCE_FILES
set(llmath_HEADER_FILES
CMakeLists.txt
- camera.h
- coordframe.h
llbbox.h
llbboxlocal.h
llcalc.h
@@ -73,7 +70,6 @@ set(llmath_HEADER_FILES
llsimdmath.h
llsimdtypes.h
llsimdtypes.inl
- llsphere.h
lltreenode.h
llvector4a.h
llvector4a.inl
@@ -100,10 +96,14 @@ list(APPEND llmath_SOURCE_FILES ${llmath_HEADER_FILES})
include_directories(${LIBS_PREBUILT_DIR}/include)
-add_library (llmath ${llmath_SOURCE_FILES})
+add_library(llmath ${llmath_SOURCE_FILES})
target_link_libraries(llmath llcommon llmeshoptimizer)
-target_include_directories( llmath INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
+target_include_directories(llmath INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
+
+if (USE_PRECOMPILED_HEADERS)
+ target_precompile_headers(llmath REUSE_FROM llprecompiled)
+endif ()
if (CMAKE_CXX_COMPILER_ID MATCHES GNU)
set_source_files_properties(llcalc.cpp PROPERTIES
diff --git a/indra/llmath/camera.h b/indra/llmath/camera.h
deleted file mode 100644
index 14a08c5985..0000000000
--- a/indra/llmath/camera.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/**
- * @file camera.h
- * @brief Legacy wrapper header.
- *
- * $LicenseInfo:firstyear=2000&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 "llcamera.h"
diff --git a/indra/llmath/coordframe.h b/indra/llmath/coordframe.h
deleted file mode 100644
index e7395b1212..0000000000
--- a/indra/llmath/coordframe.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/**
- * @file coordframe.h
- * @brief Legacy wrapper header.
- *
- * $LicenseInfo:firstyear=2000&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 "llcoordframe.h"
diff --git a/indra/llmath/llbbox.h b/indra/llmath/llbbox.h
index 5617eaebde..3a4e09a598 100644
--- a/indra/llmath/llbbox.h
+++ b/indra/llmath/llbbox.h
@@ -95,6 +95,10 @@ private:
bool mEmpty; // Nothing has been added to this bbox yet
};
+static_assert(std::is_trivially_copyable<LLBBox>::value, "LLBBox must be trivial copy");
+static_assert(std::is_trivially_move_assignable<LLBBox>::value, "LLBBox must be trivial move");
+static_assert(std::is_standard_layout<LLBBox>::value, "LLBBox must be a standard layout type");
+
//LLBBox operator*(const LLBBox &a, const LLMatrix4 &b);
diff --git a/indra/llmath/llbboxlocal.h b/indra/llmath/llbboxlocal.h
index e215e55460..f743bc0ee4 100644
--- a/indra/llmath/llbboxlocal.h
+++ b/indra/llmath/llbboxlocal.h
@@ -61,5 +61,8 @@ private:
LLBBoxLocal operator*(const LLBBoxLocal &a, const LLMatrix4 &b);
+static_assert(std::is_trivially_copyable<LLBBoxLocal>::value, "LLBBoxLocal must be trivial copy");
+static_assert(std::is_trivially_move_assignable<LLBBoxLocal>::value, "LLBBoxLocal must be trivial move");
+static_assert(std::is_standard_layout<LLBBoxLocal>::value, "LLBBoxLocal must be a standard layout type");
#endif // LL_BBOXLOCAL_H
diff --git a/indra/llmath/llcalc.cpp b/indra/llmath/llcalc.cpp
index e060b5df58..311e1e7059 100644
--- a/indra/llmath/llcalc.cpp
+++ b/indra/llmath/llcalc.cpp
@@ -116,17 +116,6 @@ void LLCalc::clearAllVariables()
mVariables.clear();
}
-/*
-void LLCalc::updateVariables(LLSD& vars)
-{
- LLSD::map_iterator cIt = vars.beginMap();
- for(; cIt != vars.endMap(); cIt++)
- {
- setVar(cIt->first, (F32)(LLSD::Real)cIt->second);
- }
-}
-*/
-
bool LLCalc::evalString(const std::string& expression, F32& result)
{
std::string expr_upper = expression;
diff --git a/indra/llmath/llcalc.h b/indra/llmath/llcalc.h
index 09672eb13b..14797de996 100644
--- a/indra/llmath/llcalc.h
+++ b/indra/llmath/llcalc.h
@@ -73,10 +73,9 @@ public:
void setVar(const std::string& name, const F32& value);
void clearVar(const std::string& name);
void clearAllVariables();
-// void updateVariables(LLSD& vars);
bool evalString(const std::string& expression, F32& result);
- std::string::size_type getLastErrorPos() { return mLastErrorPos; }
+ std::string::size_type getLastErrorPos() const { return mLastErrorPos; }
static LLCalc* getInstance();
static void cleanUp();
@@ -89,10 +88,6 @@ private:
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.
-// calc_map_t mUserVariables;
-
// "There shall be only one"
static LLCalc* sInstance;
};
diff --git a/indra/llmath/llcalcparser.h b/indra/llmath/llcalcparser.h
index ec7f6a2cb6..fe4e6bb1a4 100644
--- a/indra/llmath/llcalcparser.h
+++ b/indra/llmath/llcalcparser.h
@@ -27,6 +27,13 @@
#ifndef LL_CALCPARSER_H
#define LL_CALCPARSER_H
+#include "llpreprocessor.h"
+
+#if defined(LL_GNUC) && GCC_VERSION >= 130000
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wdangling-pointer"
+#endif
+
#include <boost/spirit/include/classic_attribute.hpp>
#include <boost/spirit/include/classic_core.hpp>
#include <boost/spirit/include/classic_error_handling.hpp>
@@ -35,6 +42,10 @@
#include <boost/spirit/include/classic_symbols.hpp>
using namespace boost::spirit::classic;
+#if defined(LL_GNUC) && GCC_VERSION >= 130000
+# pragma GCC diagnostic pop
+#endif
+
#include "llcalc.h"
#include "llmath.h"
@@ -182,7 +193,6 @@ private:
LLCalc::calc_map_t* mConstants;
LLCalc::calc_map_t* mVariables;
-// LLCalc::calc_map_t* mUserVariables;
F32& mResult;
};
diff --git a/indra/llmath/llcamera.h b/indra/llmath/llcamera.h
index 6201761c46..3863588407 100644
--- a/indra/llmath/llcamera.h
+++ b/indra/llmath/llcamera.h
@@ -60,10 +60,10 @@ constexpr F32 MAX_FIELD_OF_VIEW = 175.f * DEG_TO_RAD;
// roll(), pitch(), yaw()
// etc...
-LL_ALIGN_PREFIX(16)
-class LLCamera
+class alignas(16) LLCamera
: public LLCoordFrame
{
+ LL_ALIGN_NEW
public:
LLCamera(const LLCamera& rhs)
{
@@ -120,9 +120,9 @@ public:
};
private:
- LL_ALIGN_16(LLPlane mAgentPlanes[AGENT_PLANE_USER_CLIP_NUM]); //frustum planes in agent space a la gluUnproject (I'm a bastard, I know) - DaveP
- LL_ALIGN_16(LLPlane mRegionPlanes[AGENT_PLANE_USER_CLIP_NUM]); //frustum planes in a local region space, derived from mAgentPlanes
- LL_ALIGN_16(LLPlane mLastAgentPlanes[AGENT_PLANE_USER_CLIP_NUM]);
+ LLPlane mAgentPlanes[AGENT_PLANE_USER_CLIP_NUM]; //frustum planes in agent space a la gluUnproject (I'm a bastard, I know) - DaveP
+ LLPlane mRegionPlanes[AGENT_PLANE_USER_CLIP_NUM]; //frustum planes in a local region space, derived from mAgentPlanes
+ LLPlane mLastAgentPlanes[AGENT_PLANE_USER_CLIP_NUM];
U8 mPlaneMask[PLANE_MASK_NUM]; // 8 for alignment
F32 mView; // angle between top and bottom frustum planes in radians.
@@ -218,7 +218,7 @@ protected:
void calculateFrustumPlanes();
void calculateFrustumPlanes(F32 left, F32 right, F32 top, F32 bottom);
void calculateFrustumPlanesFromWindow(F32 x1, F32 y1, F32 x2, F32 y2);
-} LL_ALIGN_POSTFIX(16);
+};
#endif
diff --git a/indra/llmath/llcoordframe.cpp b/indra/llmath/llcoordframe.cpp
index 15c9f6ff3f..b42541c7c0 100644
--- a/indra/llmath/llcoordframe.cpp
+++ b/indra/llmath/llcoordframe.cpp
@@ -328,28 +328,30 @@ void LLCoordFrame::rotate(const LLMatrix3 &rotation_matrix)
}
+// Rotate 2 normalized orthogonal vectors in direction from `source` to `target`
+static void rotate2(LLVector3& source, LLVector3& target, F32 angle)
+{
+ F32 sx = source[VX], sy = source[VY], sz = source[VZ];
+ F32 tx = target[VX], ty = target[VY], tz = target[VZ];
+ F32 c = cosf(angle), s = sinf(angle);
+
+ source.set(sx * c + tx * s, sy * c + ty * s, sz * c + tz * s);
+ target.set(tx * c - sx * s, ty * c - sy * s, tz * c - sz * s);
+}
+
void LLCoordFrame::roll(F32 angle)
{
- LLQuaternion q(angle, mXAxis);
- LLMatrix3 rotation_matrix(q);
- rotate(rotation_matrix);
- CHECK_FINITE_OBJ();
+ rotate2(mYAxis, mZAxis, angle);
}
void LLCoordFrame::pitch(F32 angle)
{
- LLQuaternion q(angle, mYAxis);
- LLMatrix3 rotation_matrix(q);
- rotate(rotation_matrix);
- CHECK_FINITE_OBJ();
+ rotate2(mZAxis, mXAxis, angle);
}
void LLCoordFrame::yaw(F32 angle)
{
- LLQuaternion q(angle, mZAxis);
- LLMatrix3 rotation_matrix(q);
- rotate(rotation_matrix);
- CHECK_FINITE_OBJ();
+ rotate2(mXAxis, mYAxis, angle);
}
// get*() routines
diff --git a/indra/llmath/llline.h b/indra/llmath/llline.h
index e98e173d1f..fa151f8b20 100644
--- a/indra/llmath/llline.h
+++ b/indra/llmath/llline.h
@@ -40,7 +40,7 @@ class LLLine
public:
LLLine();
LLLine( const LLVector3& first_point, const LLVector3& second_point );
- virtual ~LLLine() {};
+ ~LLLine() = default;
void setPointDirection( const LLVector3& first_point, const LLVector3& second_point );
void setPoints( const LLVector3& first_point, const LLVector3& second_point );
@@ -76,5 +76,8 @@ protected:
LLVector3 mDirection;
};
+static_assert(std::is_trivially_copyable<LLLine>::value, "LLLine must be trivial copy");
+static_assert(std::is_trivially_move_assignable<LLLine>::value, "LLLine must be trivial move");
+static_assert(std::is_standard_layout<LLLine>::value, "LLLine must be a standard layout type");
#endif
diff --git a/indra/llmath/llmath.h b/indra/llmath/llmath.h
index 7f51de7820..891f0ffc4c 100644
--- a/indra/llmath/llmath.h
+++ b/indra/llmath/llmath.h
@@ -65,7 +65,7 @@ constexpr F32 DEG_TO_RAD = 0.017453292519943295769236907684886f;
constexpr F32 RAD_TO_DEG = 57.295779513082320876798154814105f;
constexpr F32 F_APPROXIMATELY_ZERO = 0.00001f;
constexpr F32 F_LN10 = 2.3025850929940456840179914546844f;
-constexpr F32 OO_LN10 = 0.43429448190325182765112891891661;
+constexpr F32 OO_LN10 = 0.43429448190325182765112891891661f;
constexpr F32 F_LN2 = 0.69314718056f;
constexpr F32 OO_LN2 = 1.4426950408889634073599246810019f;
diff --git a/indra/llmath/llmatrix3a.cpp b/indra/llmath/llmatrix3a.cpp
index c0b00201cf..904c9de2a1 100644
--- a/indra/llmath/llmatrix3a.cpp
+++ b/indra/llmath/llmatrix3a.cpp
@@ -28,7 +28,7 @@
#include "llmath.h"
-static LL_ALIGN_16(const F32 M_IDENT_3A[12]) =
+alignas(16) static 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
diff --git a/indra/llmath/llmatrix3a.h b/indra/llmath/llmatrix3a.h
index dff6604ae5..742a2488fd 100644
--- a/indra/llmath/llmatrix3a.h
+++ b/indra/llmath/llmatrix3a.h
@@ -40,8 +40,9 @@
// LLMatrix3a is the base class for LLRotation, which should be used instead any time you're dealing with a
// rotation matrix.
-class LLMatrix3a
+class alignas(16) LLMatrix3a
{
+ LL_ALIGN_NEW
public:
// Utility function for quickly transforming an array of LLVector4a's
@@ -56,7 +57,7 @@ public:
//////////////////////////
// Ctor
- LLMatrix3a() {}
+ LLMatrix3a() = default;
// Ctor for setting by columns
inline LLMatrix3a( const LLVector4a& c0, const LLVector4a& c1, const LLVector4a& c2 );
@@ -111,18 +112,22 @@ public:
protected:
- LL_ALIGN_16(LLVector4a mColumns[3]);
+ LLVector4a mColumns[3];
};
+static_assert(std::is_trivial<LLMatrix3a>::value, "LLMatrix3a must be a trivial type");
+
class LLRotation : public LLMatrix3a
{
public:
- LLRotation() {}
+ LLRotation() = default;
// Returns true if this rotation is orthonormal with det ~= 1
inline bool isOkRotation() const;
};
+static_assert(std::is_trivial<LLRotation>::value, "LLRotation must be a trivial type");
+
#endif
diff --git a/indra/llmath/llmatrix4a.h b/indra/llmath/llmatrix4a.h
index 3b423f783a..2967949993 100644
--- a/indra/llmath/llmatrix4a.h
+++ b/indra/llmath/llmatrix4a.h
@@ -31,15 +31,13 @@
#include "m4math.h"
#include "m3math.h"
-class LLMatrix4a
+class alignas(16) LLMatrix4a
{
+ LL_ALIGN_NEW
public:
- LL_ALIGN_16(LLVector4a mMatrix[4]);
+ LLVector4a mMatrix[4];
- LLMatrix4a()
- {
-
- }
+ LLMatrix4a() = default;
explicit LLMatrix4a(const LLMatrix4& val)
{
@@ -228,6 +226,8 @@ public:
const LLVector4a& getTranslation() const { return mMatrix[3]; }
};
+static_assert(std::is_trivial<LLMatrix4a>::value, "LLMatrix4a must be a trivial type");
+
inline LLVector4a rowMul(const LLVector4a &row, const LLMatrix4a &mat)
{
LLVector4a result;
diff --git a/indra/llmath/llplane.h b/indra/llmath/llplane.h
index 4e8546e32b..822e6a7b6f 100644
--- a/indra/llmath/llplane.h
+++ b/indra/llmath/llplane.h
@@ -36,14 +36,13 @@
// The plane normal = [A, B, C]
// The closest approach = D / sqrt(A*A + B*B + C*C)
-
-LL_ALIGN_PREFIX(16)
-class LLPlane
+class alignas(16) LLPlane
{
+ LL_ALIGN_NEW
public:
// Constructors
- LLPlane() {}; // no default constructor
+ LLPlane() = default;
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) { mV.set(p0[0], p0[1], p0[2], d); }
@@ -102,8 +101,9 @@ public:
private:
LLVector4a mV;
-} LL_ALIGN_POSTFIX(16);
+};
+static_assert(std::is_trivial<LLPlane>::value, "LLPlane must be a trivial type");
#endif // LL_LLPLANE_H
diff --git a/indra/llmath/llquantize.h b/indra/llmath/llquantize.h
index e8d880122e..2a53fdbf84 100644
--- a/indra/llmath/llquantize.h
+++ b/indra/llmath/llquantize.h
@@ -29,16 +29,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 };
+alignas(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 };
+alignas(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 };
+alignas(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 };
+alignas(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
diff --git a/indra/llmath/llquaternion.cpp b/indra/llmath/llquaternion.cpp
index 1ab3a73d79..3a6748bdb3 100644
--- a/indra/llmath/llquaternion.cpp
+++ b/indra/llmath/llquaternion.cpp
@@ -57,7 +57,7 @@ LLQuaternion::LLQuaternion(const LLMatrix3 &mat)
LLQuaternion::LLQuaternion(F32 angle, const LLVector4 &vec)
{
- F32 mag = sqrtf(vec.mV[VX] * vec.mV[VX] + vec.mV[VY] * vec.mV[VY] + vec.mV[VZ] * vec.mV[VZ]);
+ F32 mag = vec.length();
if (mag > FP_MAG_THRESHOLD)
{
angle *= 0.5;
@@ -76,7 +76,7 @@ LLQuaternion::LLQuaternion(F32 angle, const LLVector4 &vec)
LLQuaternion::LLQuaternion(F32 angle, const LLVector3 &vec)
{
- F32 mag = sqrtf(vec.mV[VX] * vec.mV[VX] + vec.mV[VY] * vec.mV[VY] + vec.mV[VZ] * vec.mV[VZ]);
+ F32 mag = vec.length();
if (mag > FP_MAG_THRESHOLD)
{
angle *= 0.5;
diff --git a/indra/llmath/llquaternion.h b/indra/llmath/llquaternion.h
index 762d13eded..472d7ca62d 100644
--- a/indra/llmath/llquaternion.h
+++ b/indra/llmath/llquaternion.h
@@ -174,6 +174,10 @@ public:
//static U32 mMultCount;
};
+static_assert(std::is_trivially_copyable<LLQuaternion>::value, "LLQuaternion must be trivial copy");
+static_assert(std::is_trivially_move_assignable<LLQuaternion>::value, "LLQuaternion must be trivial move");
+static_assert(std::is_standard_layout<LLQuaternion>::value, "LLQuaternion must be a standard layout type");
+
inline LLSD LLQuaternion::getValue() const
{
LLSD ret;
diff --git a/indra/llmath/llquaternion2.h b/indra/llmath/llquaternion2.h
index 902bfb7134..d73e1a0ca2 100644
--- a/indra/llmath/llquaternion2.h
+++ b/indra/llmath/llquaternion2.h
@@ -40,8 +40,9 @@
/////////////////////////////
#include "llquaternion.h"
-class LLQuaternion2
+class alignas(16) LLQuaternion2
{
+ LL_ALIGN_NEW
public:
//////////////////////////
@@ -49,7 +50,7 @@ public:
//////////////////////////
// Ctor
- LLQuaternion2() {}
+ LLQuaternion2() = default;
// Ctor from LLQuaternion
explicit LLQuaternion2( const class LLQuaternion& quat );
@@ -102,4 +103,6 @@ protected:
};
+static_assert(std::is_trivial<LLQuaternion2>::value, "LLQuaternion2 must be a trivial type");
+
#endif
diff --git a/indra/llmath/llquaternion2.inl b/indra/llmath/llquaternion2.inl
index ce5ed73926..8cc5020bb8 100644
--- a/indra/llmath/llquaternion2.inl
+++ b/indra/llmath/llquaternion2.inl
@@ -26,8 +26,13 @@
#include "llquaternion2.h"
+#if _M_ARM64
+static const LLQuad LL_V4A_PLUS_ONE = {.n128_f32 = {1.f, 1.f, 1.f, 1.f}};
+static const LLQuad LL_V4A_MINUS_ONE = {.n128_f32 = {-1.f, -1.f, -1.f, -1.f}};
+#else
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};
+#endif
// Ctor from LLQuaternion
inline LLQuaternion2::LLQuaternion2( const LLQuaternion& quat )
@@ -57,7 +62,7 @@ inline LLVector4a& LLQuaternion2::getVector4aRw()
// 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 };
+ alignas(16) static 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));
}
diff --git a/indra/llmath/llrect.h b/indra/llmath/llrect.h
index 317578da06..0a3da2fee0 100644
--- a/indra/llmath/llrect.h
+++ b/indra/llmath/llrect.h
@@ -51,10 +51,6 @@ public:
LLRectBase(): mLeft(0), mTop(0), mRight(0), mBottom(0)
{}
- LLRectBase(const LLRectBase &r):
- mLeft(r.mLeft), mTop(r.mTop), mRight(r.mRight), mBottom(r.mBottom)
- {}
-
LLRectBase(Type left, Type top, Type right, Type bottom):
mLeft(left), mTop(top), mRight(right), mBottom(bottom)
{}
@@ -295,4 +291,8 @@ template <class Type> LLRectBase<Type> LLRectBase<Type>::null(0,0,0,0);
typedef LLRectBase<S32> LLRect;
typedef LLRectBase<F32> LLRectf;
+static_assert(std::is_trivially_copyable<LLRect>::value, "LLRect must be trivial copy");
+static_assert(std::is_trivially_move_assignable<LLRect>::value, "LLRect must be trivial move");
+static_assert(std::is_standard_layout<LLRect>::value, "LLRect must be a standard layout type");
+
#endif
diff --git a/indra/llmath/llrigginginfo.h b/indra/llmath/llrigginginfo.h
index d761af68b1..e5a41d2ecf 100644
--- a/indra/llmath/llrigginginfo.h
+++ b/indra/llmath/llrigginginfo.h
@@ -70,11 +70,10 @@ public:
LLJointRiggingInfo* begin() { return mRigInfoPtr; }
LLJointRiggingInfo* end() { return mRigInfoPtr + mSize; }
-private:
- // Not implemented
- LLJointRiggingInfoTab& operator=(const LLJointRiggingInfoTab& src);
- LLJointRiggingInfoTab(const LLJointRiggingInfoTab& src);
+ LLJointRiggingInfoTab& operator=(const LLJointRiggingInfoTab& src) = delete;
+ LLJointRiggingInfoTab(const LLJointRiggingInfoTab& src) = delete;
+private:
LLJointRiggingInfo *mRigInfoPtr;
S32 mSize;
bool mNeedsUpdate;
diff --git a/indra/llmath/llsimdmath.h b/indra/llmath/llsimdmath.h
index 6242095456..440561e589 100644
--- a/indra/llmath/llsimdmath.h
+++ b/indra/llmath/llsimdmath.h
@@ -31,8 +31,12 @@
#error "Please include llmath.h before this file."
#endif
-#if ( ( LL_DARWIN || LL_LINUX ) && !(__SSE2__ || __ARM_NEON) ) || ( LL_WINDOWS && ( _M_IX86_FP < 2 && ADDRESS_SIZE == 32 ) )
-#error SSE2 not enabled. LLVector4a and related class will not compile.
+#if ( ( LL_DARWIN || LL_LINUX ) )
+ #if !(__SSE2__ || __ARM_NEON)
+ #error SSE2 not enabled. LLVector4a and related class will not compile.
+ #endif
+#elif ( LL_WINDOWS && ( _M_IX86_FP < 2 && ADDRESS_SIZE == 32 ) )
+ #error SSE2 not enabled. LLVector4a and related class will not compile.
#endif
#if !LL_WINDOWS
diff --git a/indra/llmath/llsimdtypes.h b/indra/llmath/llsimdtypes.h
index a407f51029..6c4f55b0c0 100644
--- a/indra/llmath/llsimdtypes.h
+++ b/indra/llmath/llsimdtypes.h
@@ -36,7 +36,7 @@ typedef __m128 LLQuad;
class LLBool32
{
public:
- inline LLBool32() {}
+ inline LLBool32() = default;
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); }
@@ -46,13 +46,15 @@ public:
inline operator bool() const { return static_cast<const bool&>(m_bool); }
private:
- int m_bool{ 0 };
+ int m_bool;
};
+static_assert(std::is_trivial<LLBool32>::value, "LLBool32 must be a standard layout type");
+
class LLSimdScalar
{
public:
- inline LLSimdScalar() {}
+ inline LLSimdScalar() = default;
inline LLSimdScalar(LLQuad q)
{
mQ = q;
@@ -100,7 +102,9 @@ public:
}
private:
- LLQuad mQ{};
+ LLQuad mQ;
};
+static_assert(std::is_trivial<LLSimdScalar>::value, "LLSimdScalar must be a standard layout type");
+
#endif //LL_SIMD_TYPES_H
diff --git a/indra/llmath/llsimdtypes.inl b/indra/llmath/llsimdtypes.inl
index 125f4b9df5..20ea7640b6 100644
--- a/indra/llmath/llsimdtypes.inl
+++ b/indra/llmath/llsimdtypes.inl
@@ -61,7 +61,7 @@ inline LLSimdScalar operator/(const LLSimdScalar& a, const LLSimdScalar& b)
inline LLSimdScalar operator-(const LLSimdScalar& a)
{
- static LL_ALIGN_16(const U32 signMask[4]) = {0x80000000, 0x80000000, 0x80000000, 0x80000000 };
+ alignas(16) static const U32 signMask[4] = {0x80000000, 0x80000000, 0x80000000, 0x80000000 };
ll_assert_aligned(signMask,16);
return _mm_xor_ps(*reinterpret_cast<const LLQuad*>(signMask), a);
}
@@ -146,7 +146,7 @@ inline LLSimdScalar& LLSimdScalar::operator/=(const LLSimdScalar& rhs)
inline LLSimdScalar LLSimdScalar::getAbs() const
{
- static const LL_ALIGN_16(U32 F_ABS_MASK_4A[4]) = { 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF };
+ alignas(16) static const U32 F_ABS_MASK_4A[4] = { 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF };
ll_assert_aligned(F_ABS_MASK_4A,16);
return _mm_and_ps( mQ, *reinterpret_cast<const LLQuad*>(F_ABS_MASK_4A));
}
diff --git a/indra/llmath/llsphere.cpp b/indra/llmath/llsphere.cpp
deleted file mode 100644
index 5f48764455..0000000000
--- a/indra/llmath/llsphere.cpp
+++ /dev/null
@@ -1,370 +0,0 @@
-/**
- * @file llsphere.cpp
- * @author Andrew Meadows
- * @brief Simple line class that can compute nearest approach between two lines
- *
- * $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$
- */
-
-#include "linden_common.h"
-
-#include "llsphere.h"
-
-LLSphere::LLSphere()
-: mCenter(0.f, 0.f, 0.f),
- mRadius(0.f)
-{ }
-
-LLSphere::LLSphere( const LLVector3& center, F32 radius)
-{
- set(center, radius);
-}
-
-void LLSphere::set( const LLVector3& center, F32 radius )
-{
- mCenter = center;
- setRadius(radius);
-}
-
-void LLSphere::setCenter( const LLVector3& center)
-{
- mCenter = center;
-}
-
-void LLSphere::setRadius( F32 radius)
-{
- if (radius < 0.f)
- {
- radius = -radius;
- }
- mRadius = radius;
-}
-
-const LLVector3& LLSphere::getCenter() const
-{
- return mCenter;
-}
-
-F32 LLSphere::getRadius() const
-{
- return mRadius;
-}
-
-// returns 'true' if this sphere completely contains other_sphere
-bool LLSphere::contains(const LLSphere& other_sphere) const
-{
- F32 separation = (mCenter - other_sphere.mCenter).length();
- return mRadius >= separation + other_sphere.mRadius;
-}
-
-// returns 'true' if this sphere completely contains other_sphere
-bool LLSphere::overlaps(const LLSphere& other_sphere) const
-{
- F32 separation = (mCenter - other_sphere.mCenter).length();
- return mRadius >= separation - other_sphere.mRadius;
-}
-
-// returns overlap
-// negative overlap is closest approach
-F32 LLSphere::getOverlap(const LLSphere& other_sphere) const
-{
- // separation is distance from other_sphere's edge and this center
- return (mCenter - other_sphere.mCenter).length() - mRadius - other_sphere.mRadius;
-}
-
-bool LLSphere::operator==(const LLSphere& rhs) const
-{
- return fabs(mRadius - rhs.mRadius) <= FLT_EPSILON &&
- (mCenter - rhs.mCenter).length() <= FLT_EPSILON;
-}
-
-std::ostream& operator<<( std::ostream& output_stream, const LLSphere& sphere)
-{
- output_stream << "{center=" << sphere.mCenter << "," << "radius=" << sphere.mRadius << "}";
- return output_stream;
-}
-
-// static
-// removes any spheres that are contained in others
-void LLSphere::collapse(std::vector<LLSphere>& sphere_list)
-{
- std::vector<LLSphere>::iterator first_itr = sphere_list.begin();
- while (first_itr != sphere_list.end())
- {
- bool delete_from_front = false;
-
- std::vector<LLSphere>::iterator second_itr = first_itr;
- ++second_itr;
- while (second_itr != sphere_list.end())
- {
- if (second_itr->contains(*first_itr))
- {
- delete_from_front = true;
- break;
- }
- else if (first_itr->contains(*second_itr))
- {
- sphere_list.erase(second_itr++);
- }
- else
- {
- ++second_itr;
- }
- }
-
- if (delete_from_front)
- {
- sphere_list.erase(first_itr++);
- }
- else
- {
- ++first_itr;
- }
- }
-}
-
-// static
-// returns the bounding sphere that contains both spheres
-LLSphere LLSphere::getBoundingSphere(const LLSphere& first_sphere, const LLSphere& second_sphere)
-{
- LLVector3 direction = second_sphere.mCenter - first_sphere.mCenter;
-
- // HACK -- it is possible to get enough floating point error in the
- // other getBoundingSphere() method that we have to add some slop
- // at the end. Unfortunately, this breaks the link-order invarience
- // for the linkability tests... unless we also apply the same slop
- // here.
- F32 half_milimeter = 0.0005f;
-
- F32 distance = direction.length();
- if (0.f == distance)
- {
- direction.setVec(1.f, 0.f, 0.f);
- }
- else
- {
- direction.normVec();
- }
- // the 'edge' is measured from the first_sphere's center
- F32 max_edge = 0.f;
- F32 min_edge = 0.f;
-
- max_edge = llmax(max_edge + first_sphere.getRadius(), max_edge + distance + second_sphere.getRadius() + half_milimeter);
- min_edge = llmin(min_edge - first_sphere.getRadius(), min_edge + distance - second_sphere.getRadius() - half_milimeter);
- F32 radius = 0.5f * (max_edge - min_edge);
- LLVector3 center = first_sphere.mCenter + (0.5f * (max_edge + min_edge)) * direction;
- return LLSphere(center, radius);
-}
-
-// static
-// returns the bounding sphere that contains an arbitrary set of spheres
-LLSphere LLSphere::getBoundingSphere(const std::vector<LLSphere>& sphere_list)
-{
- // this algorithm can get relatively inaccurate when the sphere
- // collection is 'small' (contained within a bounding sphere of about
- // 2 meters or less)
- // TODO -- improve the accuracy for small collections of spheres
-
- LLSphere bounding_sphere( LLVector3(0.f, 0.f, 0.f), 0.f );
- auto sphere_count = sphere_list.size();
- if (1 == sphere_count)
- {
- // trivial case -- single sphere
- std::vector<LLSphere>::const_iterator sphere_itr = sphere_list.begin();
- bounding_sphere = *sphere_itr;
- }
- else if (2 == sphere_count)
- {
- // trivial case -- two spheres
- std::vector<LLSphere>::const_iterator first_sphere = sphere_list.begin();
- std::vector<LLSphere>::const_iterator second_sphere = first_sphere;
- ++second_sphere;
- bounding_sphere = LLSphere::getBoundingSphere(*first_sphere, *second_sphere);
- }
- else if (sphere_count > 0)
- {
- // non-trivial case -- we will approximate the solution
- //
- // NOTE -- there is a fancy/fast way to do this for large
- // numbers of arbirary N-dimensional spheres -- you can look it
- // up on the net. We're dealing with 3D spheres at collection
- // sizes of 256 spheres or smaller, so we just use this
- // brute force method.
-
- // TODO -- perhaps would be worthwile to test for the solution where
- // the largest spanning radius just happens to work. That is, where
- // there are really two spheres that determine the bounding sphere,
- // and all others are contained therein.
-
- // compute the AABB
- std::vector<LLSphere>::const_iterator first_itr = sphere_list.begin();
- LLVector3 max_corner = first_itr->getCenter() + first_itr->getRadius() * LLVector3(1.f, 1.f, 1.f);
- LLVector3 min_corner = first_itr->getCenter() - first_itr->getRadius() * LLVector3(1.f, 1.f, 1.f);
- {
- std::vector<LLSphere>::const_iterator sphere_itr = sphere_list.begin();
- for (++sphere_itr; sphere_itr != sphere_list.end(); ++sphere_itr)
- {
- LLVector3 center = sphere_itr->getCenter();
- F32 radius = sphere_itr->getRadius();
- for (S32 i=0; i<3; ++i)
- {
- if (center.mV[i] + radius > max_corner.mV[i])
- {
- max_corner.mV[i] = center.mV[i] + radius;
- }
- if (center.mV[i] - radius < min_corner.mV[i])
- {
- min_corner.mV[i] = center.mV[i] - radius;
- }
- }
- }
- }
-
- // get the starting center and radius from the AABB
- LLVector3 diagonal = max_corner - min_corner;
- F32 bounding_radius = 0.5f * diagonal.length();
- LLVector3 bounding_center = 0.5f * (max_corner + min_corner);
-
- // compute the starting step-size
- F32 minimum_radius = 0.5f * llmin(diagonal.mV[VX], llmin(diagonal.mV[VY], diagonal.mV[VZ]));
- F32 step_length = bounding_radius - minimum_radius;
- //S32 step_count = 0;
- //S32 max_step_count = 12;
- F32 half_milimeter = 0.0005f;
-
- // wander the center around in search of tighter solutions
- S32 last_dx = 2; // 2 is out of bounds --> no match
- S32 last_dy = 2;
- S32 last_dz = 2;
-
- while (step_length > half_milimeter
- /*&& step_count < max_step_count*/)
- {
- // the algorithm for testing the maximum radius could be expensive enough
- // that it makes sense to NOT duplicate testing when possible, so we keep
- // track of where we last tested, and only test the new points
-
- S32 best_dx = 0;
- S32 best_dy = 0;
- S32 best_dz = 0;
-
- // sample near the center of the box
- bool found_better_center = false;
- for (S32 dx = -1; dx < 2; ++dx)
- {
- for (S32 dy = -1; dy < 2; ++dy)
- {
- for (S32 dz = -1; dz < 2; ++dz)
- {
- if (dx == 0 && dy == 0 && dz == 0)
- {
- continue;
- }
-
- // count the number of indecies that match the last_*'s
- S32 match_count = 0;
- if (last_dx == dx) ++match_count;
- if (last_dy == dy) ++match_count;
- if (last_dz == dz) ++match_count;
- if (match_count == 2)
- {
- // we've already tested this point
- continue;
- }
-
- LLVector3 center = bounding_center;
- center.mV[VX] += (F32) dx * step_length;
- center.mV[VY] += (F32) dy * step_length;
- center.mV[VZ] += (F32) dz * step_length;
-
- // compute the radius of the bounding sphere
- F32 max_radius = 0.f;
- std::vector<LLSphere>::const_iterator sphere_itr;
- for (sphere_itr = sphere_list.begin(); sphere_itr != sphere_list.end(); ++sphere_itr)
- {
- F32 radius = (sphere_itr->getCenter() - center).length() + sphere_itr->getRadius();
- if (radius > max_radius)
- {
- max_radius = radius;
- }
- }
- if (max_radius < bounding_radius)
- {
- best_dx = dx;
- best_dy = dy;
- best_dz = dz;
- bounding_center = center;
- bounding_radius = max_radius;
- found_better_center = true;
- }
- }
- }
- }
- if (found_better_center)
- {
- // remember where we came from so we can avoid retesting
- last_dx = -best_dx;
- last_dy = -best_dy;
- last_dz = -best_dz;
- }
- else
- {
- // reduce the step size
- step_length *= 0.5f;
- //++step_count;
- // reset the last_*'s
- last_dx = 2; // 2 is out of bounds --> no match
- last_dy = 2;
- last_dz = 2;
- }
- }
-
- // HACK -- it is possible to get enough floating point error for the
- // bounding sphere to too small on the order of 10e-6, but we only need
- // it to be accurate to within about half a millimeter
- bounding_radius += half_milimeter;
-
- // this algorithm can get relatively inaccurate when the sphere
- // collection is 'small' (contained within a bounding sphere of about
- // 2 meters or less)
- // TODO -- fix this
- /* debug code
- {
- std::vector<LLSphere>::const_iterator sphere_itr;
- for (sphere_itr = sphere_list.begin(); sphere_itr != sphere_list.end(); ++sphere_itr)
- {
- F32 radius = (sphere_itr->getCenter() - bounding_center).length() + sphere_itr->getRadius();
- if (radius + 0.1f > bounding_radius)
- {
- std::cout << " rad = " << radius << " bounding - rad = " << (bounding_radius - radius) << std::endl;
- }
- }
- std::cout << "\n" << std::endl;
- }
- */
-
- bounding_sphere.set(bounding_center, bounding_radius);
- }
- return bounding_sphere;
-}
-
-
diff --git a/indra/llmath/llsphere.h b/indra/llmath/llsphere.h
deleted file mode 100644
index cb923dcd3c..0000000000
--- a/indra/llmath/llsphere.h
+++ /dev/null
@@ -1,77 +0,0 @@
-// llsphere.h
-/**
- * @file llsphere.cpp
- * @author Andrew Meadows
- * @brief Simple sphere implementation for basic geometric operations
- *
- * $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_SPHERE_H
-#define LL_SPHERE_H
-
-#include "stdtypes.h"
-#include "v3math.h"
-#include <iostream>
-#include <vector>
-
-class LLSphere
-{
-public:
- LLSphere();
- LLSphere( const LLVector3& center, F32 radius );
-
- void set( const LLVector3& center, F32 radius );
- void setCenter( const LLVector3& center );
- void setRadius( F32 radius );
-
- const LLVector3& getCenter() const;
- F32 getRadius() const;
-
- // returns true if this sphere completely contains other_sphere
- bool contains(const LLSphere& other_sphere) const;
-
- // returns true if this sphere overlaps other_sphere
- bool overlaps(const LLSphere& other_sphere) const;
-
- // returns overlap distance
- // negative overlap is closest approach
- F32 getOverlap(const LLSphere& other_sphere) const;
-
- // removes any spheres that are contained in others
- static void collapse(std::vector<LLSphere>& sphere_list);
-
- // returns minimum sphere bounding sphere for a set of spheres
- static LLSphere getBoundingSphere(const LLSphere& first_sphere, const LLSphere& second_sphere);
- static LLSphere getBoundingSphere(const std::vector<LLSphere>& sphere_list);
-
- bool operator==(const LLSphere& rhs) const;
-
- friend std::ostream& operator<<( std::ostream& output_stream, const LLSphere& line );
-
-protected:
- LLVector3 mCenter;
- F32 mRadius;
-};
-
-
-#endif
diff --git a/indra/llmath/llvector4a.cpp b/indra/llmath/llvector4a.cpp
index b81d50f0f9..c1845b0d94 100644
--- a/indra/llmath/llvector4a.cpp
+++ b/indra/llmath/llvector4a.cpp
@@ -30,6 +30,15 @@
#include "llmath.h"
#include "llquantize.h"
+#if _M_ARM64
+extern const LLQuad F_ZERO_4A = {.n128_f32 = {0, 0, 0, 0}};
+extern const LLQuad F_APPROXIMATELY_ZERO_4A = {.n128_f32 = {
+ F_APPROXIMATELY_ZERO,
+ F_APPROXIMATELY_ZERO,
+ F_APPROXIMATELY_ZERO,
+ F_APPROXIMATELY_ZERO
+}};
+#else
extern const LLQuad F_ZERO_4A = { 0, 0, 0, 0 };
extern const LLQuad F_APPROXIMATELY_ZERO_4A = {
F_APPROXIMATELY_ZERO,
@@ -37,6 +46,7 @@ extern const LLQuad F_APPROXIMATELY_ZERO_4A = {
F_APPROXIMATELY_ZERO,
F_APPROXIMATELY_ZERO
};
+#endif
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 );
@@ -101,7 +111,7 @@ void LLVector4a::quantize8( const LLVector4a& low, const LLVector4a& high )
// 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 };
+// alignas(16) static 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
@@ -146,7 +156,7 @@ void LLVector4a::quantize16( const LLVector4a& low, const LLVector4a& high )
// 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 };
+ alignas(16) static const F32 F_TWO_4A[4] = { 2.f, 2.f, 2.f, 2.f };
ll_assert_aligned(F_TWO_4A,16);
LLVector4a two; two.load4a( F_TWO_4A );
diff --git a/indra/llmath/llvector4a.h b/indra/llmath/llvector4a.h
index 4004852e06..764a3b94e6 100644
--- a/indra/llmath/llvector4a.h
+++ b/indra/llmath/llvector4a.h
@@ -95,10 +95,7 @@ public:
////////////////////////////////////
//LLVector4a is plain data which should never have a default constructor or destructor(malloc&free won't trigger it)
- LLVector4a()
- { //DO NOT INITIALIZE -- The overhead is completely unnecessary
- ll_assert_aligned(this,16);
- }
+ LLVector4a() = default;
LLVector4a(F32 x, F32 y, F32 z, F32 w = 0.f)
{
@@ -361,8 +358,6 @@ public:
////////////////////////////////////
// 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;
@@ -378,9 +373,11 @@ public:
};
private:
- LLQuad mQ{};
+ LLQuad mQ;
};
+static_assert(std::is_trivial<LLVector4a>::value, "LLVector4a must be a trivial type");
+
inline void update_min_max(LLVector4a& min, LLVector4a& max, const LLVector4a& p)
{
min.setMin(min, p);
diff --git a/indra/llmath/llvector4a.inl b/indra/llmath/llvector4a.inl
index 36dbec078c..e6153a27e6 100644
--- a/indra/llmath/llvector4a.inl
+++ b/indra/llmath/llvector4a.inl
@@ -115,7 +115,7 @@ inline void LLVector4a::set(F32 x, F32 y, F32 z, F32 w)
// Set to all zeros
inline void LLVector4a::clear()
{
- mQ = LLVector4a::getZero().mQ;
+ mQ = _mm_setzero_ps();
}
inline void LLVector4a::splat(const F32 x)
@@ -196,7 +196,7 @@ inline void LLVector4a::setDiv(const LLVector4a& a, const LLVector4a& b)
// 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 };
+ alignas(16) static const U32 F_ABS_MASK_4A[4] = { 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF };
mQ = _mm_and_ps(src.mQ, *reinterpret_cast<const LLQuad*>(F_ABS_MASK_4A));
}
@@ -272,6 +272,9 @@ inline void LLVector4a::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 LLVector4a::setAllDot3(const LLVector4a& a, const LLVector4a& b)
{
+#if (defined(__arm64__) || defined(__aarch64__))
+ mQ = _mm_dp_ps(a.mQ, b.mQ, 0x7f);
+#else
// 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] }
@@ -284,11 +287,15 @@ inline void LLVector4a::setAllDot3(const LLVector4a& a, const LLVector4a& b)
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);
+#endif
}
// 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)
{
+#if (defined(__arm64__) || defined(__aarch64__))
+ mQ = _mm_dp_ps(a.mQ, b.mQ, 0xff);
+#else
// 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] }
@@ -301,21 +308,29 @@ inline void LLVector4a::setAllDot4(const LLVector4a& a, const LLVector4a& b)
// 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);
+#endif
}
// Return the 3D dot product of this vector and b
inline LLSimdScalar LLVector4a::dot3(const LLVector4a& b) const
{
+#if (defined(__arm64__) || defined(__aarch64__))
+ return _mm_dp_ps(mQ, b.mQ, 0x7f);
+#else
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 );
+#endif
}
// Return the 4D dot product of this vector and b
inline LLSimdScalar LLVector4a::dot4(const LLVector4a& b) const
{
+#if (defined(__arm64__) || defined(__aarch64__))
+ return _mm_dp_ps(mQ, b.mQ, 0xff);
+#else
// ab = { w, z, y, x }
const LLQuad ab = _mm_mul_ps( mQ, b.mQ );
// upperProdsInLowerElems = { y, x, y, x }
@@ -325,6 +340,7 @@ inline LLSimdScalar LLVector4a::dot4(const LLVector4a& b) const
// 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 );
+#endif
}
// Normalize this vector with respect to the x, y, and z components only. Accurate to 22 bites of precision. W component is destroyed
@@ -335,8 +351,13 @@ inline void LLVector4a::normalize3()
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);
+#if _M_ARM64
+ static const LLQuad half = {.n128_f32 = {0.5f, 0.5f, 0.5f, 0.5f}};
+ static const LLQuad three = {.n128_f32 = {3.f, 3.f, 3.f, 3.f }};
+#else
static const LLQuad half = { 0.5f, 0.5f, 0.5f, 0.5f };
static const LLQuad three = {3.f, 3.f, 3.f, 3.f };
+#endif
// 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))
@@ -359,8 +380,13 @@ inline void LLVector4a::normalize4()
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);
+#if _M_ARM64
+ static const LLQuad half = {.n128_f32 = {0.5f, 0.5f, 0.5f, 0.5f}};
+ static const LLQuad three = {.n128_f32 = {3.f, 3.f, 3.f, 3.f}};
+#else
static const LLQuad half = { 0.5f, 0.5f, 0.5f, 0.5f };
static const LLQuad three = {3.f, 3.f, 3.f, 3.f };
+#endif
// 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))
@@ -383,8 +409,13 @@ inline LLSimdScalar LLVector4a::normalize3withLength()
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);
+#if _M_ARM64
+ static const LLQuad half = {.n128_f32 = {0.5f, 0.5f, 0.5f, 0.5f}};
+ static const LLQuad three = {.n128_f32 = {3.f, 3.f, 3.f, 3.f}};
+#else
static const LLQuad half = { 0.5f, 0.5f, 0.5f, 0.5f };
static const LLQuad three = {3.f, 3.f, 3.f, 3.f };
+#endif
// 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))
@@ -432,7 +463,7 @@ inline void LLVector4a::normalize3fast_checked(LLVector4a* d)
// 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 };
+ alignas(16) static 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 );
@@ -444,7 +475,7 @@ inline LLBool32 LLVector4a::isNormalized3( F32 tolerance ) const
// 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 };
+ alignas(16) static 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 );
@@ -491,7 +522,7 @@ inline void LLVector4a::setLerp(const LLVector4a& lhs, const LLVector4a& rhs, F3
inline LLBool32 LLVector4a::isFinite3() const
{
- static LL_ALIGN_16(const U32 nanOrInfMask[4]) = { 0x7f800000, 0x7f800000, 0x7f800000, 0x7f800000 };
+ alignas(16) static const U32 nanOrInfMask[4] = { 0x7f800000, 0x7f800000, 0x7f800000, 0x7f800000 };
ll_assert_aligned(nanOrInfMask,16);
const __m128i nanOrInfMaskV = *reinterpret_cast<const __m128i*> (nanOrInfMask);
const __m128i maskResult = _mm_and_si128( _mm_castps_si128(mQ), nanOrInfMaskV );
@@ -501,7 +532,7 @@ inline LLBool32 LLVector4a::isFinite3() const
inline LLBool32 LLVector4a::isFinite4() const
{
- static LL_ALIGN_16(const U32 nanOrInfMask[4]) = { 0x7f800000, 0x7f800000, 0x7f800000, 0x7f800000 };
+ alignas(16) static 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 ));
@@ -593,12 +624,6 @@ inline bool LLVector4a::equals3(const LLVector4a& rhs, F32 tolerance ) const
////////////////////////////////////
// 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;
diff --git a/indra/llmath/llvector4logical.h b/indra/llmath/llvector4logical.h
index 70759eef5c..411971c42d 100644
--- a/indra/llmath/llvector4logical.h
+++ b/indra/llmath/llvector4logical.h
@@ -39,7 +39,7 @@
// contact someone with SSE experience (Falcon, Richard, Davep, e.g.)
////////////////////////////
-static LL_ALIGN_16(const U32 S_V4LOGICAL_MASK_TABLE[4*4]) =
+alignas(16) static const U32 S_V4LOGICAL_MASK_TABLE[4*4] =
{
0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0xFFFFFFFF, 0x00000000, 0x00000000,
@@ -61,7 +61,7 @@ public:
};
// Empty default ctor
- LLVector4Logical() {}
+ LLVector4Logical() = default;
LLVector4Logical( const LLQuad& quad )
{
@@ -77,7 +77,7 @@ public:
// Invert this mask
inline LLVector4Logical& invert()
{
- static const LL_ALIGN_16(U32 allOnes[4]) = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+ alignas(16) static const U32 allOnes[4] = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
ll_assert_aligned(allOnes,16);
mQ = _mm_andnot_ps( mQ, *(LLQuad*)(allOnes) );
return *this;
@@ -120,7 +120,9 @@ public:
private:
- LLQuad mQ{};
+ LLQuad mQ;
};
+static_assert(std::is_trivial<LLVector4Logical>::value, "LLVector4Logical must be a standard layout type");
+
#endif //LL_VECTOR4ALOGICAL_H
diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp
index d56891cab3..e2407860b3 100644
--- a/indra/llmath/llvolume.cpp
+++ b/indra/llmath/llvolume.cpp
@@ -52,6 +52,7 @@
#include "llmeshoptimizer.h"
#include "lltimer.h"
#include "llvolumeoctree.h"
+#include "workqueue.h"
#include "mikktspace/mikktspace.hh"
@@ -912,7 +913,7 @@ bool LLProfile::generate(const LLProfileParams& params, bool path_open,F32 detai
case LL_PCODE_HOLE_CIRCLE:
case LL_PCODE_HOLE_SAME:
default:
- addHole(params, true, circle_detail, 0, hollow, 1.f);
+ addHole(params, false, circle_detail, 0, hollow, 1.f);
break;
}
}
@@ -2292,30 +2293,149 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
+ // Sanity-check before even trying to decompress
+ constexpr S32 MAX_MESH_COMPRESSED_SIZE = 128 * 1024 * 1024; // 128 MB
+ const LLUUID& mesh_id = getParams().getSculptID();
+
+ if (size <= 0 || size > MAX_MESH_COMPRESSED_SIZE)
+ {
+ LL_WARNS("MeshStreaming") << "Rejecting implausible compressed mesh size " << size
+ << " for mesh id " << mesh_id << LL_ENDL;
+ return false;
+ }
+
//input stream is now pointing at a zlib compressed block of LLSD
//decompress block
- LLSD mdl;
- U32 uzip_result = LLUZipHelper::unzip_llsd(mdl, is, size);
- if (uzip_result != LLUZipHelper::ZR_OK)
+ try
+ {
+ LLSD mdl;
+ U32 uzip_result = LLUZipHelper::unzip_llsd(mdl, is, size);
+ if (uzip_result != LLUZipHelper::ZR_OK)
+ {
+ LL_DEBUGS("MeshStreaming") << "Failed to unzip LLSD blob for LoD with code " << uzip_result << " , will probably fetch from sim again." << LL_ENDL;
+ return false;
+ }
+ return unpackVolumeFacesInternal(mdl);
+ }
+ catch (const std::bad_alloc&)
+ {
+ constexpr S32 SMALL_MESH_THRESHOLD = 4000;
+ if (size < SMALL_MESH_THRESHOLD)
+ {
+ // showOutOfMemory and LL_ERRS must run on the main thread.
+ // Post to mainloop WorkQueue, mirroring LLThread::tryRun().
+ LL::WorkQueue::ptr_t main_queue = LL::WorkQueue::getInstance("mainloop");
+ bool done = false;
+ if (main_queue)
+ {
+ const LLUUID mesh_id_copy = mesh_id; // capture by value for the lambda
+ done = main_queue->post([mesh_id_copy, size]()
+ {
+ LLError::LLUserWarningMsg::showOutOfMemory();
+ LL_ERRS("MeshStreaming") << "Out of memory unpacking mesh id " << mesh_id_copy
+ << " of compressed size " << size << LL_ENDL;
+ });
+ }
+ if (!done)
+ {
+ // No main queue available (e.g. during shutdown)
+ LL_WARNS("MeshStreaming") << "Out of memory unpacking mesh id " << mesh_id
+ << " of compressed size " << size << " (main queue unavailable)" << LL_ENDL;
+ }
+ }
+ else
+ {
+ LL_WARNS("MeshStreaming") << "Out of memory unpacking mesh id " << mesh_id
+ << " of compressed size " << size << LL_ENDL;
+ }
+ return false;
+ }
+ catch (const std::exception& e)
{
- LL_DEBUGS("MeshStreaming") << "Failed to unzip LLSD blob for LoD with code " << uzip_result << " , will probably fetch from sim again." << LL_ENDL;
+ LL_WARNS("MeshStreaming") << "Exception unpacking mesh id " << mesh_id
+ << " of compressed size " << size << ": " << e.what() << LL_ENDL;
+ return false;
+ }
+ catch (...)
+ {
+ LL_WARNS("MeshStreaming") << "Unknown exception unpacking mesh id " << mesh_id
+ << " of compressed size " << size << LL_ENDL;
return false;
}
- return unpackVolumeFacesInternal(mdl);
}
bool LLVolume::unpackVolumeFaces(U8* in_data, S32 size)
{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
+ constexpr S32 MAX_MESH_COMPRESSED_SIZE = 128 * 1024 * 1024; // 128 MB
+ const LLUUID& mesh_id = getParams().getSculptID();
+
+ if (!in_data || size <= 0 || size > MAX_MESH_COMPRESSED_SIZE)
+ {
+ LL_WARNS("MeshStreaming") << "Rejecting implausible compressed mesh size " << size
+ << " for mesh id " << mesh_id << LL_ENDL;
+ return false;
+ }
+
//input data is now pointing at a zlib compressed block of LLSD
//decompress block
- LLSD mdl;
- U32 uzip_result = LLUZipHelper::unzip_llsd(mdl, in_data, size);
- if (uzip_result != LLUZipHelper::ZR_OK)
+ try
+ {
+ LLSD mdl;
+ U32 uzip_result = LLUZipHelper::unzip_llsd(mdl, in_data, size);
+ if (uzip_result != LLUZipHelper::ZR_OK)
+ {
+ LL_DEBUGS("MeshStreaming") << "Failed to unzip LLSD blob for LoD, mesh id " << mesh_id
+ << ", code " << uzip_result << " , will probably fetch from sim again." << LL_ENDL;
+ return false;
+ }
+ return unpackVolumeFacesInternal(mdl);
+ }
+ catch (const std::bad_alloc&)
+ {
+ constexpr S32 SMALL_MESH_THRESHOLD = 4000;
+ if (size < SMALL_MESH_THRESHOLD)
+ {
+ // showOutOfMemory and LL_ERRS must run on the main thread.
+ // Post to mainloop WorkQueue, mirroring LLThread::tryRun().
+ LL::WorkQueue::ptr_t main_queue = LL::WorkQueue::getInstance("mainloop");
+ bool done = false;
+ if (main_queue)
+ {
+ const LLUUID mesh_id_copy = mesh_id; // capture by value for the lambda
+ done = main_queue->post([mesh_id_copy, size]()
+ {
+ LLError::LLUserWarningMsg::showOutOfMemory();
+ LL_ERRS("MeshStreaming") << "Out of memory unpacking mesh id " << mesh_id_copy
+ << " of compressed size " << size << LL_ENDL;
+ });
+ }
+ if (!done)
+ {
+ // No main queue available (e.g. during shutdown)
+ LL_WARNS("MeshStreaming") << "Out of memory unpacking mesh id " << mesh_id
+ << " of compressed size " << size << " (main queue unavailable)" << LL_ENDL;
+ }
+ }
+ else
+ {
+ LL_WARNS("MeshStreaming") << "Out of memory unpacking mesh id " << mesh_id
+ << " of compressed size " << size << LL_ENDL;
+ }
+ return false;
+ }
+ catch (const std::exception& e)
{
- LL_DEBUGS("MeshStreaming") << "Failed to unzip LLSD blob for LoD with code " << uzip_result << " , will probably fetch from sim again." << LL_ENDL;
+ LL_WARNS("MeshStreaming") << "Exception unpacking mesh id " << mesh_id
+ << " of compressed size " << size << ": " << e.what() << LL_ENDL;
+ return false;
+ }
+ catch (...)
+ {
+ LL_WARNS("MeshStreaming") << "Unknown exception unpacking mesh id " << mesh_id
+ << " of compressed size " << size << LL_ENDL;
return false;
}
- return unpackVolumeFacesInternal(mdl);
}
bool LLVolume::unpackVolumeFacesInternal(const LLSD& mdl)
@@ -2348,7 +2468,9 @@ bool LLVolume::unpackVolumeFacesInternal(const LLSD& mdl)
const LLSD::Binary& pos = mdl[i]["Position"].asBinary();
const LLSD::Binary& norm = mdl[i]["Normal"].asBinary();
+#if 0 // keep this code for now in case we decide to add support for on-the-wire tangents
const LLSD::Binary& tangent = mdl[i]["Tangent"].asBinary();
+#endif
const LLSD::Binary& tc = mdl[i]["TexCoord0"].asBinary();
const LLSD::Binary& idx = mdl[i]["TriangleList"].asBinary();
@@ -2383,11 +2505,31 @@ bool LLVolume::unpackVolumeFacesInternal(const LLSD& mdl)
//copy out vertices
U32 num_verts = static_cast<U32>(pos.size())/(3*2);
+ if (num_verts == 0)
+ {
+ LL_WARNS() << "Zero vertices for face index: " << i << LL_ENDL;
+ face.resizeIndices(3);
+ face.resizeVertices(1);
+ face.mPositions->clear();
+ face.mNormals->clear();
+ face.mTexCoords->setZero();
+ memset(face.mIndices, 0, sizeof(U16) * 3);
+ continue;
+ }
+
+ if (num_verts > 65535) // U16 indices
+ {
+ LL_WARNS() << "Invalid vertex count " << num_verts << " exceeds maximum for face index: " << i << LL_ENDL;
+ mVolumeFaces.clear();
+ return false;
+ }
+
face.resizeVertices(num_verts);
if (num_verts > 0 && !face.mPositions)
{
LL_WARNS() << "Failed to allocate " << num_verts << " vertices for face index: " << i << " Total: " << face_count << LL_ENDL;
+ face.resizeVertices(0);
face.resizeIndices(0);
continue;
}
@@ -4943,9 +5085,17 @@ LLVolumeFace::LLVolumeFace(const LLVolumeFace& src)
mOctree(NULL),
mOctreeTriangles(NULL)
{
- mExtents = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*3);
- mCenter = mExtents+2;
- *this = src;
+ try
+ {
+ mExtents = (LLVector4a*)ll_aligned_malloc_16(sizeof(LLVector4a) * 3);
+ mCenter = mExtents + 2;
+ *this = src;
+ }
+ catch (std::bad_alloc&)
+ {
+ LLError::LLUserWarningMsg::showOutOfMemory();
+ LL_ERRS("LLVolume") << "Bad memory allocation in LLVolumeFace" << LL_ENDL;
+ }
}
LLVolumeFace& LLVolumeFace::operator=(const LLVolumeFace& src)
@@ -5163,7 +5313,7 @@ void LLVolumeFace::remap()
// Documentation for meshopt_generateVertexRemapMulti claims that remap should use vertice count
// but all examples use indice count. There are out of bounds crashes when using vertice count.
// To be on the safe side use bigger of the two.
- std::vector<unsigned int> remap(llmax(mNumIndices, mNumVertices));
+ std::vector<unsigned int> remap(llmax(mNumIndices, mNumVertices), 0);
S32 remap_vertices_count = static_cast<S32>(LLMeshOptimizer::generateRemapMultiU16(&remap[0],
mIndices,
mNumIndices,
@@ -5669,7 +5819,40 @@ bool LLVolumeFace::cacheOptimize(bool gen_tangents)
mOptimized = true;
if (gen_tangents && mNormals && mTexCoords)
- { // generate mikkt space tangents before cache optimizing since the index buffer may change
+ {
+ if (!mPositions || !mIndices || mNumVertices <= 0 || mNumIndices <= 0)
+ {
+ LL_WARNS_ONCE("LLVolume") << "Invalid volume face data for tangent generation: "
+ << "mPositions=" << (void*)mPositions
+ << ", mIndices=" << (void*)mIndices
+ << ", mNumVertices=" << mNumVertices
+ << ", mNumIndices=" << mNumIndices << LL_ENDL;
+ return false;
+ }
+
+ if (mNumIndices % 3 != 0)
+ {
+ LL_WARNS_ONCE("LLVolume") << "Non-triangulated mesh, mNumIndices=" << mNumIndices << LL_ENDL;
+ return false;
+ }
+
+ for (S32 i = 0; i < mNumIndices; ++i)
+ {
+ if (mIndices[i] >= mNumVertices)
+ {
+ LL_WARNS_ONCE("LLVolume") << "Out of bounds index detected: mIndices[" << i << "]="
+ << mIndices[i] << " >= mNumVertices=" << mNumVertices << LL_ENDL;
+ return false;
+ }
+ }
+
+ if (mNormalizedScale.mV[0] == 0.0f || mNormalizedScale.mV[1] == 0.0f || mNormalizedScale.mV[2] == 0.0f)
+ {
+ LL_WARNS_ONCE("LLVolume") << "Invalid normalized scale: " << mNormalizedScale << LL_ENDL;
+ return false;
+ }
+
+ // generate mikkt space tangents before cache optimizing since the index buffer may change
// a bit of a hack to do this here, but this function gets called exactly once for the lifetime of a mesh
// and is executed on a background thread
MikktData data(this);
@@ -5681,7 +5864,12 @@ bool LLVolumeFace::cacheOptimize(bool gen_tangents)
catch (std::bad_alloc&)
{
LLError::LLUserWarningMsg::showOutOfMemory();
- LL_ERRS("LLCoros") << "Bad memory allocation in MikktData::genTangSpace" << LL_ENDL;
+ LL_ERRS("LLVolume") << "Bad memory allocation in MikktData::genTangSpace" << LL_ENDL;
+ }
+ catch (...)
+ {
+ LL_WARNS_ONCE("LLVolume") << "Mikktspace::genTangSpace() failed" << LL_ENDL;
+ return false;
}
@@ -5703,7 +5891,7 @@ bool LLVolumeFace::cacheOptimize(bool gen_tangents)
catch (std::bad_alloc&)
{
LLError::LLUserWarningMsg::showOutOfMemory();
- LL_ERRS("LLCoros") << "Failed to allocate memory for remap: " << (S32)data.p.size() << LL_ENDL;
+ LL_ERRS("LLVOLUME") << "Failed to allocate memory for remap: " << (S32)data.p.size() << LL_ENDL;
}
U32 stream_count = data.w.empty() ? 4 : 5;
@@ -5711,13 +5899,29 @@ bool LLVolumeFace::cacheOptimize(bool gen_tangents)
S32 vert_count = 0;
if (!data.p.empty())
{
- vert_count = static_cast<S32>(meshopt_generateVertexRemapMulti(&remap[0], nullptr, data.p.size(), data.p.size(), mos, stream_count));
+ try
+ {
+ // providing mIndices should help avoid unused vertices
+ // but those should have been filtered out on upload
+ vert_count = static_cast<S32>(meshopt_generateVertexRemapMulti(&remap[0], nullptr, data.p.size(), data.p.size(), mos, stream_count));
+ }
+ catch (std::bad_alloc&)
+ {
+ LLError::LLUserWarningMsg::showOutOfMemory();
+ LL_ERRS("LLVolume") << "Failed to allocate memory for VertexRemap: " << (S32)data.p.size() << LL_ENDL;
+ }
}
- if (vert_count < 65535 && vert_count != 0)
+ // Probably should be using meshopt_remapVertexBuffer instead of remaping manually
+ if (vert_count < 65535 && vert_count > 0)
{
//copy results back into volume
resizeVertices(vert_count);
+ if (mNumVertices == 0)
+ {
+ LLError::LLUserWarningMsg::showOutOfMemory();
+ LL_ERRS("LLVolume") << "Failed to allocate memory for resizeVertices(" << vert_count << ")" << LL_ENDL;
+ }
if (!data.w.empty())
{
@@ -5730,13 +5934,27 @@ bool LLVolumeFace::cacheOptimize(bool gen_tangents)
{
U32 src_idx = i;
U32 dst_idx = remap[i];
- if (dst_idx >= (U32)mNumVertices)
+ if (dst_idx == U32_MAX)
+ {
+ // Unused indices? Probably need to resize mIndices
+ dst_idx = mNumVertices - 1;
+ llassert(false);
+ LL_DEBUGS_ONCE("LLVOLUME") << "U32_MAX destination index, substituting" << LL_ENDL;
+ }
+ else if (dst_idx >= (U32)mNumVertices)
{
dst_idx = mNumVertices - 1;
// Shouldn't happen, figure out what gets returned in remap and why.
llassert(false);
LL_DEBUGS_ONCE("LLVOLUME") << "Invalid destination index, substituting" << LL_ENDL;
}
+ if (src_idx >= (U32)data.p.size())
+ {
+ // data.p.size() is supposed to be equal to mNumIndices
+ src_idx = (U32)(data.p.size() - 1);
+ llassert(false);
+ LL_DEBUGS_ONCE("LLVOLUME") << "Invalid source index, substituting" << LL_ENDL;
+ }
mIndices[i] = dst_idx;
mPositions[dst_idx].load3(data.p[src_idx].mV);
@@ -5770,7 +5988,7 @@ bool LLVolumeFace::cacheOptimize(bool gen_tangents)
}
else
{
- if (vert_count == 0)
+ if (vert_count <= 0)
{
LL_WARNS_ONCE("LLVOLUME") << "meshopt_generateVertexRemapMulti failed to process a model or model was invalid" << LL_ENDL;
}
diff --git a/indra/llmath/llvolumemgr.cpp b/indra/llmath/llvolumemgr.cpp
index bb0c94d513..d8f649140f 100644
--- a/indra/llmath/llvolumemgr.cpp
+++ b/indra/llmath/llvolumemgr.cpp
@@ -25,6 +25,7 @@
#include "linden_common.h"
+#include "llmutex.h"
#include "llvolumemgr.h"
#include "llvolume.h"
diff --git a/indra/llmath/llvolumeoctree.h b/indra/llmath/llvolumeoctree.h
index 1d74644715..0250bf8bfb 100644
--- a/indra/llmath/llvolumeoctree.h
+++ b/indra/llmath/llvolumeoctree.h
@@ -53,7 +53,7 @@ public:
}
- LL_ALIGN_16(LLVector4a mPositionGroup);
+ LLVector4a mPositionGroup;
const LLVector4a* mV[3];
U32 mIndex[3];
@@ -78,16 +78,8 @@ public:
LLVolumeOctreeListener(LLOctreeNode<LLVolumeTriangle, LLVolumeTriangle*>* node);
~LLVolumeOctreeListener();
- LLVolumeOctreeListener(const LLVolumeOctreeListener& rhs)
- {
- *this = rhs;
- }
-
- const LLVolumeOctreeListener& operator=(const LLVolumeOctreeListener& rhs)
- {
- LL_ERRS() << "Illegal operation!" << LL_ENDL;
- return *this;
- }
+ LLVolumeOctreeListener(const LLVolumeOctreeListener& rhs) = delete;
+ const LLVolumeOctreeListener& operator=(const LLVolumeOctreeListener& rhs) = delete;
//LISTENER FUNCTIONS
virtual void handleChildAddition(const LLOctreeNode<LLVolumeTriangle, LLVolumeTriangle*>* parent, LLOctreeNode<LLVolumeTriangle, LLVolumeTriangle*>* child);
@@ -99,8 +91,8 @@ public:
public:
- LL_ALIGN_16(LLVector4a mBounds[2]); // bounding box (center, size) of this node and all its children (tight fit to objects)
- LL_ALIGN_16(LLVector4a mExtents[2]); // extents (min, max) of this node and all its children
+ 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, LLVolumeTriangle*>
diff --git a/indra/llmath/m3math.h b/indra/llmath/m3math.h
index cd14290246..36661d2cb0 100644
--- a/indra/llmath/m3math.h
+++ b/indra/llmath/m3math.h
@@ -142,6 +142,10 @@ class LLMatrix3
friend std::ostream& operator<<(std::ostream& s, const LLMatrix3 &a); // Stream a
};
+static_assert(std::is_trivially_copyable<LLMatrix3>::value, "LLMatrix3 must be trivial copy");
+static_assert(std::is_trivially_move_assignable<LLMatrix3>::value, "LLMatrix3 must be trivial move");
+static_assert(std::is_standard_layout<LLMatrix3>::value, "LLMatrix3 must be a standard layout type");
+
inline LLMatrix3::LLMatrix3(void)
{
mMatrix[0][0] = 1.f;
diff --git a/indra/llmath/m4math.cpp b/indra/llmath/m4math.cpp
index a9853fe7e9..1724a50601 100644
--- a/indra/llmath/m4math.cpp
+++ b/indra/llmath/m4math.cpp
@@ -156,10 +156,6 @@ LLMatrix4::LLMatrix4(const F32 roll, const F32 pitch, const F32 yaw)
mMatrix[3][3] = 1.f;
}
-LLMatrix4::~LLMatrix4(void)
-{
-}
-
// Clear and Assignment Functions
const LLMatrix4& LLMatrix4::setZero()
diff --git a/indra/llmath/m4math.h b/indra/llmath/m4math.h
index b0f8c90cdf..f164779283 100644
--- a/indra/llmath/m4math.h
+++ b/indra/llmath/m4math.h
@@ -119,8 +119,6 @@ public:
const LLVector4 &pos); // Initializes Matrix with Euler angles
LLMatrix4(const F32 roll, const F32 pitch, const F32 yaw); // Initializes Matrix with Euler angles
- ~LLMatrix4(void); // Destructor
-
LLSD getValue() const;
void setValue(const LLSD&);
@@ -242,6 +240,10 @@ public:
friend std::ostream& operator<<(std::ostream& s, const LLMatrix4 &a); // Stream a
};
+static_assert(std::is_trivially_copyable<LLMatrix4>::value, "LLMatrix4 must be trivial copy");
+static_assert(std::is_trivially_move_assignable<LLMatrix4>::value, "LLMatrix4 must be trivial move");
+static_assert(std::is_standard_layout<LLMatrix4>::value, "LLMatrix4 must be a standard layout type");
+
inline const LLMatrix4& LLMatrix4::setIdentity()
{
mMatrix[0][0] = 1.f;
diff --git a/indra/llmath/raytrace.cpp b/indra/llmath/raytrace.cpp
index 893bf1fc70..c0b5f48f2d 100644
--- a/indra/llmath/raytrace.cpp
+++ b/indra/llmath/raytrace.cpp
@@ -27,7 +27,6 @@
#include "linden_common.h"
#include "math.h"
-//#include "vmath.h"
#include "v3math.h"
#include "llquaternion.h"
#include "m3math.h"
diff --git a/indra/llmath/tests/alignment_test.cpp b/indra/llmath/tests/alignment_test.cpp
index eb6fa4a3b8..f41ebe82aa 100644
--- a/indra/llmath/tests/alignment_test.cpp
+++ b/indra/llmath/tests/alignment_test.cpp
@@ -46,8 +46,7 @@ typedef test_group<alignment_test> alignment_test_t;
typedef alignment_test_t::object alignment_test_object_t;
tut::alignment_test_t tut_alignment_test("LLAlignment");
-LL_ALIGN_PREFIX(16)
-class MyVector4a
+class alignas(16) MyVector4a
{
public:
void* operator new(size_t size)
@@ -71,7 +70,7 @@ public:
}
LLQuad mQ;
-} LL_ALIGN_POSTFIX(16);
+};
// Verify that aligned allocators perform as advertised.
diff --git a/indra/llmath/tests/llquaternion_test.cpp b/indra/llmath/tests/llquaternion_test.cpp
index aa3c0ad843..ba18d54d55 100644
--- a/indra/llmath/tests/llquaternion_test.cpp
+++ b/indra/llmath/tests/llquaternion_test.cpp
@@ -349,9 +349,9 @@ namespace tut
ensure(
"2. LLVector4 operator*(const LLVector4 &a, const LLQuaternion &rot) failed",
is_approx_equal(-58153.5390f, result.mV[0]) &&
- (183787.8125f == result.mV[1]) &&
- (116864.164063f == result.mV[2]) &&
- (78.099998f == result.mV[3]));
+ is_approx_equal(183787.8125f, result.mV[1]) &&
+ is_approx_equal(116864.164063f, result.mV[2]) &&
+ is_approx_equal(78.099998f, result.mV[3]));
}
//test case for LLVector3 operator*(const LLVector3 &a, const LLQuaternion &rot) fn.
diff --git a/indra/llmath/tests/mathmisc_test.cpp b/indra/llmath/tests/mathmisc_test.cpp
index ff0899e975..810b0d80da 100644
--- a/indra/llmath/tests/mathmisc_test.cpp
+++ b/indra/llmath/tests/mathmisc_test.cpp
@@ -35,7 +35,6 @@
#include "../llline.h"
#include "../llmath.h"
-#include "../llsphere.h"
#include "../v3math.h"
namespace tut
@@ -280,166 +279,6 @@ namespace tut
namespace tut
{
- struct sphere_data
- {
- };
- typedef test_group<sphere_data> sphere_test;
- typedef sphere_test::object sphere_object;
- tut::sphere_test tsphere("LLSphere");
-
- template<> template<>
- void sphere_object::test<1>()
- {
- // test LLSphere::contains() and ::overlaps()
- S32 number_of_tests = 10;
- for (S32 test = 0; test < number_of_tests; ++test)
- {
- LLVector3 first_center(1.f, 1.f, 1.f);
- F32 first_radius = 3.f;
- LLSphere first_sphere( first_center, first_radius );
-
- F32 half_millimeter = 0.0005f;
- LLVector3 direction( ll_frand(2.f) - 1.f, ll_frand(2.f) - 1.f, ll_frand(2.f) - 1.f);
- direction.normalize();
-
- F32 distance = ll_frand(first_radius - 2.f * half_millimeter);
- LLVector3 second_center = first_center + distance * direction;
- F32 second_radius = first_radius - distance - half_millimeter;
- LLSphere second_sphere( second_center, second_radius );
- ensure("first sphere should contain the second", first_sphere.contains(second_sphere));
- ensure("first sphere should overlap the second", first_sphere.overlaps(second_sphere));
-
- distance = first_radius + ll_frand(first_radius);
- second_center = first_center + distance * direction;
- second_radius = distance - first_radius + half_millimeter;
- second_sphere.set( second_center, second_radius );
- ensure("first sphere should NOT contain the second", !first_sphere.contains(second_sphere));
- ensure("first sphere should overlap the second", first_sphere.overlaps(second_sphere));
-
- distance = first_radius + ll_frand(first_radius) + half_millimeter;
- second_center = first_center + distance * direction;
- second_radius = distance - first_radius - half_millimeter;
- second_sphere.set( second_center, second_radius );
- ensure("first sphere should NOT contain the second", !first_sphere.contains(second_sphere));
- ensure("first sphere should NOT overlap the second", !first_sphere.overlaps(second_sphere));
- }
- }
-
- template<> template<>
- void sphere_object::test<2>()
- {
- skip("See SNOW-620. Neither the test nor the code being tested seem good. Also sim-only.");
-
- // test LLSphere::getBoundingSphere()
- S32 number_of_tests = 100;
- S32 number_of_spheres = 10;
- F32 sphere_center_range = 32.f;
- F32 sphere_radius_range = 5.f;
-
- for (S32 test = 0; test < number_of_tests; ++test)
- {
- // gegnerate a bunch of random sphere
- std::vector< LLSphere > sphere_list;
- for (S32 sphere_count=0; sphere_count < number_of_spheres; ++sphere_count)
- {
- LLVector3 direction( ll_frand(2.f) - 1.f, ll_frand(2.f) - 1.f, ll_frand(2.f) - 1.f);
- direction.normalize();
- F32 distance = ll_frand(sphere_center_range);
- LLVector3 center = distance * direction;
- F32 radius = ll_frand(sphere_radius_range);
- LLSphere sphere( center, radius );
- sphere_list.push_back(sphere);
- }
-
- // compute the bounding sphere
- LLSphere bounding_sphere = LLSphere::getBoundingSphere(sphere_list);
-
- // make sure all spheres are inside the bounding sphere
- {
- std::vector< LLSphere >::const_iterator sphere_itr;
- for (sphere_itr = sphere_list.begin(); sphere_itr != sphere_list.end(); ++sphere_itr)
- {
- ensure("sphere should be contained by the bounding sphere", bounding_sphere.contains(*sphere_itr));
- }
- }
-
- // TODO -- improve LLSphere::getBoundingSphere() to the point where
- // we can reduce the 'expansion' in the two tests below to about
- // 2 mm or less
-
- F32 expansion = 0.005f;
- // move all spheres out a little bit
- // and count how many are NOT contained
- {
- std::vector< LLVector3 > uncontained_directions;
- std::vector< LLSphere >::iterator sphere_itr;
- for (sphere_itr = sphere_list.begin(); sphere_itr != sphere_list.end(); ++sphere_itr)
- {
- LLVector3 direction = sphere_itr->getCenter() - bounding_sphere.getCenter();
- direction.normalize();
-
- sphere_itr->setCenter( sphere_itr->getCenter() + expansion * direction );
- if (! bounding_sphere.contains( *sphere_itr ) )
- {
- uncontained_directions.push_back(direction);
- }
- }
- ensure("when moving spheres out there should be at least two uncontained spheres",
- uncontained_directions.size() > 1);
-
- /* TODO -- when the bounding sphere algorithm is improved we can open up this test
- * at the moment it occasionally fails when the sphere collection is tight and small
- * (2 meters or less)
- if (2 == uncontained_directions.size() )
- {
- // if there were only two uncontained spheres then
- // the two directions should be nearly opposite
- F32 dir_dot = uncontained_directions[0] * uncontained_directions[1];
- ensure("two uncontained spheres should lie opposite the bounding center", dir_dot < -0.95f);
- }
- */
- }
-
- // compute the new bounding sphere
- bounding_sphere = LLSphere::getBoundingSphere(sphere_list);
-
- // increase the size of all spheres a little bit
- // and count how many are NOT contained
- {
- std::vector< LLVector3 > uncontained_directions;
- std::vector< LLSphere >::iterator sphere_itr;
- for (sphere_itr = sphere_list.begin(); sphere_itr != sphere_list.end(); ++sphere_itr)
- {
- LLVector3 direction = sphere_itr->getCenter() - bounding_sphere.getCenter();
- direction.normalize();
-
- sphere_itr->setRadius( sphere_itr->getRadius() + expansion );
- if (! bounding_sphere.contains( *sphere_itr ) )
- {
- uncontained_directions.push_back(direction);
- }
- }
- ensure("when boosting sphere radii there should be at least two uncontained spheres",
- uncontained_directions.size() > 1);
-
- /* TODO -- when the bounding sphere algorithm is improved we can open up this test
- * at the moment it occasionally fails when the sphere collection is tight and small
- * (2 meters or less)
- if (2 == uncontained_directions.size() )
- {
- // if there were only two uncontained spheres then
- // the two directions should be nearly opposite
- F32 dir_dot = uncontained_directions[0] * uncontained_directions[1];
- ensure("two uncontained spheres should lie opposite the bounding center", dir_dot < -0.95f);
- }
- */
- }
- }
- }
-}
-
-namespace tut
-{
F32 SMALL_RADIUS = 1.0f;
F32 MEDIUM_RADIUS = 5.0f;
F32 LARGE_RADIUS = 10.0f;
diff --git a/indra/llmath/v2math.cpp b/indra/llmath/v2math.cpp
index 59e6d947ca..175f08df88 100644
--- a/indra/llmath/v2math.cpp
+++ b/indra/llmath/v2math.cpp
@@ -66,6 +66,13 @@ F32 angle_between(const LLVector2& a, const LLVector2& b)
return angle;
}
+F32 signed_angle_between(const LLVector2& a, const LLVector2& b)
+{
+ F32 angle = angle_between(a, b);
+ F32 rhombus_square = a[VX] * b[VY] - b[VX] * a[VY];
+ return rhombus_square < 0 ? -angle : angle;
+}
+
bool are_parallel(const LLVector2& a, const LLVector2& b, F32 epsilon)
{
LLVector2 an = a;
diff --git a/indra/llmath/v2math.h b/indra/llmath/v2math.h
index 18ad02a411..b31e4056a3 100644
--- a/indra/llmath/v2math.h
+++ b/indra/llmath/v2math.h
@@ -107,13 +107,17 @@ class LLVector2
friend LLVector2 operator-(const LLVector2 &a); // Return vector -a
- friend std::ostream& operator<<(std::ostream& s, const LLVector2 &a); // Stream a
+ friend std::ostream& operator<<(std::ostream& s, const LLVector2 &a); // Stream a
};
+static_assert(std::is_trivially_copyable<LLVector2>::value, "LLVector2 must be trivial copy");
+static_assert(std::is_trivially_move_assignable<LLVector2>::value, "LLVector2 must be trivial move");
+static_assert(std::is_standard_layout<LLVector2>::value, "LLVector2 must be a standard layout type");
// Non-member functions
F32 angle_between(const LLVector2& a, const LLVector2& b); // Returns angle (radians) between a and b
+F32 signed_angle_between(const LLVector2& a, const LLVector2& b); // Returns signed angle (radians) between a and b
bool are_parallel(const LLVector2& a, const LLVector2& b, F32 epsilon = F_APPROXIMATELY_ZERO); // Returns true if a and b are very close to parallel
F32 dist_vec(const LLVector2& a, const LLVector2& b); // Returns distance between a and b
F32 dist_vec_squared(const LLVector2& a, const LLVector2& b);// Returns distance squared between a and b
@@ -124,26 +128,22 @@ LLVector2 lerp(const LLVector2& a, const LLVector2& b, F32 u); // Returns a vect
inline LLVector2::LLVector2()
{
- mV[VX] = 0.f;
- mV[VY] = 0.f;
+ clear();
}
inline LLVector2::LLVector2(F32 x, F32 y)
{
- mV[VX] = x;
- mV[VY] = y;
+ set(x, y);
}
inline LLVector2::LLVector2(const F32 *vec)
{
- mV[VX] = vec[VX];
- mV[VY] = vec[VY];
+ set(vec);
}
inline LLVector2::LLVector2(const LLVector3 &vec)
{
- mV[VX] = vec.mV[VX];
- mV[VY] = vec.mV[VY];
+ set(vec.mV);
}
inline LLVector2::LLVector2(const LLSD &sd)
@@ -155,28 +155,24 @@ inline LLVector2::LLVector2(const LLSD &sd)
inline void LLVector2::clear()
{
- mV[VX] = 0.f;
- mV[VY] = 0.f;
+ mV[VX] = mV[VY] = 0.f;
}
inline void LLVector2::setZero()
{
- mV[VX] = 0.f;
- mV[VY] = 0.f;
+ clear();
}
// deprecated
inline void LLVector2::clearVec()
{
- mV[VX] = 0.f;
- mV[VY] = 0.f;
+ clear();
}
// deprecated
inline void LLVector2::zeroVec()
{
- mV[VX] = 0.f;
- mV[VY] = 0.f;
+ clear();
}
inline void LLVector2::set(F32 x, F32 y)
@@ -187,36 +183,31 @@ inline void LLVector2::set(F32 x, F32 y)
inline void LLVector2::set(const LLVector2 &vec)
{
- mV[VX] = vec.mV[VX];
- mV[VY] = vec.mV[VY];
+ set(vec.mV);
}
inline void LLVector2::set(const F32 *vec)
{
- mV[VX] = vec[VX];
- mV[VY] = vec[VY];
+ set(vec[VX], vec[VY]);
}
// deprecated
inline void LLVector2::setVec(F32 x, F32 y)
{
- mV[VX] = x;
- mV[VY] = y;
+ set(x, y);
}
// deprecated
inline void LLVector2::setVec(const LLVector2 &vec)
{
- mV[VX] = vec.mV[VX];
- mV[VY] = vec.mV[VY];
+ set(vec);
}
// deprecated
inline void LLVector2::setVec(const F32 *vec)
{
- mV[VX] = vec[VX];
- mV[VY] = vec[VY];
+ set(vec);
}
@@ -224,7 +215,7 @@ inline void LLVector2::setVec(const F32 *vec)
inline F32 LLVector2::length() const
{
- return sqrt(mV[VX]*mV[VX] + mV[VY]*mV[VY]);
+ return sqrt(lengthSquared());
}
inline F32 LLVector2::lengthSquared() const
@@ -234,61 +225,42 @@ inline F32 LLVector2::lengthSquared() const
inline F32 LLVector2::normalize()
{
- F32 mag = sqrt(mV[VX]*mV[VX] + mV[VY]*mV[VY]);
- F32 oomag;
+ F32 mag = length();
if (mag > FP_MAG_THRESHOLD)
{
- oomag = 1.f/mag;
- mV[VX] *= oomag;
- mV[VY] *= oomag;
+ *this /= mag;
}
else
{
- mV[VX] = 0.f;
- mV[VY] = 0.f;
+ clear();
mag = 0;
}
- return (mag);
+ return mag;
}
// checker
inline bool LLVector2::isFinite() const
{
- return (llfinite(mV[VX]) && llfinite(mV[VY]));
+ return llfinite(mV[VX]) && llfinite(mV[VY]);
}
// deprecated
inline F32 LLVector2::magVec() const
{
- return sqrt(mV[VX]*mV[VX] + mV[VY]*mV[VY]);
+ return length();
}
// deprecated
inline F32 LLVector2::magVecSquared() const
{
- return mV[VX]*mV[VX] + mV[VY]*mV[VY];
+ return lengthSquared();
}
// deprecated
inline F32 LLVector2::normVec()
{
- F32 mag = sqrt(mV[VX]*mV[VX] + mV[VY]*mV[VY]);
- F32 oomag;
-
- if (mag > FP_MAG_THRESHOLD)
- {
- oomag = 1.f/mag;
- mV[VX] *= oomag;
- mV[VY] *= oomag;
- }
- else
- {
- mV[VX] = 0.f;
- mV[VY] = 0.f;
- mag = 0;
- }
- return (mag);
+ return normalize();
}
inline const LLVector2& LLVector2::scaleVec(const LLVector2& vec)
@@ -301,11 +273,7 @@ inline const LLVector2& LLVector2::scaleVec(const LLVector2& vec)
inline bool LLVector2::isNull() const
{
- if (F_APPROXIMATELY_ZERO > mV[VX]*mV[VX] + mV[VY]*mV[VY])
- {
- return true;
- }
- return false;
+ return F_APPROXIMATELY_ZERO > mV[VX]*mV[VX] + mV[VY]*mV[VY];
}
@@ -405,10 +373,7 @@ inline const LLVector2& operator*=(LLVector2& a, F32 k)
inline const LLVector2& operator/=(LLVector2& a, F32 k)
{
- F32 t = 1.f / k;
- a.mV[VX] *= t;
- a.mV[VY] *= t;
- return a;
+ return a *= 1.f / k;
}
inline LLVector2 operator-(const LLVector2& a)
diff --git a/indra/llmath/v3color.h b/indra/llmath/v3color.h
index 48b36e7c8a..7357d93599 100644
--- a/indra/llmath/v3color.h
+++ b/indra/llmath/v3color.h
@@ -144,8 +144,11 @@ public:
inline void exp(); // Do an exponential on the color
};
-LLColor3 lerp(const LLColor3& a, const LLColor3& b, F32 u);
+static_assert(std::is_trivially_copyable<LLColor3>::value, "LLColor3 must be trivial copy");
+static_assert(std::is_trivially_move_assignable<LLColor3>::value, "LLColor3 must be trivial move");
+static_assert(std::is_standard_layout<LLColor3>::value, "LLColor3 must be a standard layout type");
+LLColor3 lerp(const LLColor3& a, const LLColor3& b, F32 u);
void LLColor3::clamp()
{
// Clamp the color...
diff --git a/indra/llmath/v3dmath.h b/indra/llmath/v3dmath.h
index fcce2c30eb..7c56cf138d 100644
--- a/indra/llmath/v3dmath.h
+++ b/indra/llmath/v3dmath.h
@@ -129,6 +129,10 @@ public:
static bool parseVector3d(const std::string& buf, LLVector3d* value);
};
+static_assert(std::is_trivially_copyable<LLVector3d>::value, "LLVector3d must be trivial copy");
+static_assert(std::is_trivially_move_assignable<LLVector3d>::value, "LLVector3d must be trivial move");
+static_assert(std::is_standard_layout<LLVector3d>::value, "LLVector3d must be a standard layout type");
+
typedef LLVector3d LLGlobalVec;
inline const LLVector3d &LLVector3d::set(const LLVector3 &vec)
diff --git a/indra/llmath/v3math.h b/indra/llmath/v3math.h
index 551c7df6c9..196ecdcf7d 100644
--- a/indra/llmath/v3math.h
+++ b/indra/llmath/v3math.h
@@ -112,24 +112,24 @@ class LLVector3
const LLVector3& setVec(const LLVector4 &vec); // deprecated
const LLVector3& setVec(const LLVector3d &vec); // deprecated
- F32 length() const; // Returns magnitude of LLVector3
- F32 lengthSquared() const; // Returns magnitude squared of LLVector3
- F32 magVec() const; // deprecated
- F32 magVecSquared() const; // deprecated
+ F32 length() const; // Returns magnitude of LLVector3
+ F32 lengthSquared() const; // Returns magnitude squared of LLVector3
+ F32 magVec() const; // deprecated
+ F32 magVecSquared() const; // deprecated
- inline F32 normalize(); // Normalizes and returns the magnitude of LLVector3
- inline F32 normVec(); // deprecated
+ inline F32 normalize(); // Normalizes and returns the magnitude of LLVector3
+ inline F32 normVec(); // deprecated
- inline bool inRange( F32 min, F32 max ) const; // Returns true if all values of the vector are between min and max
+ inline bool inRange(F32 min, F32 max) const; // Returns true if all values of the vector are between min and max
- const LLVector3& rotVec(F32 angle, const LLVector3 &vec); // Rotates about vec by angle radians
- const LLVector3& rotVec(F32 angle, F32 x, F32 y, F32 z); // Rotates about x,y,z by angle radians
- const LLVector3& rotVec(const LLMatrix3 &mat); // Rotates by LLMatrix4 mat
- const LLVector3& rotVec(const LLQuaternion &q); // Rotates by LLQuaternion q
- const LLVector3& transVec(const LLMatrix4& mat); // Transforms by LLMatrix4 mat (mat * v)
+ const LLVector3& rotVec(F32 angle, const LLVector3 &vec); // Rotates about vec by angle radians
+ const LLVector3& rotVec(F32 angle, F32 x, F32 y, F32 z); // Rotates about x,y,z by angle radians
+ const LLVector3& rotVec(const LLMatrix3 &mat); // Rotates by LLMatrix4 mat
+ const LLVector3& rotVec(const LLQuaternion &q); // Rotates by LLQuaternion q
+ const LLVector3& transVec(const LLMatrix4& mat); // Transforms by LLMatrix4 mat (mat * v)
- const LLVector3& scaleVec(const LLVector3& vec); // scales per component by vec
- LLVector3 scaledVec(const LLVector3& vec) const; // get a copy of this vector scaled by vec
+ const LLVector3& scaleVec(const LLVector3& vec); // scales per component by vec
+ LLVector3 scaledVec(const LLVector3& vec) const; // get a copy of this vector scaled by vec
bool isNull() const; // Returns true if vector has a _very_small_ length
bool isExactlyZero() const { return !mV[VX] && !mV[VY] && !mV[VZ]; }
@@ -164,6 +164,10 @@ class LLVector3
static bool parseVector3(const std::string& buf, LLVector3* value);
};
+static_assert(std::is_trivially_copyable<LLVector3>::value, "LLVector3 must be trivial copy");
+static_assert(std::is_trivially_move_assignable<LLVector3>::value, "LLVector3 must be trivial move");
+static_assert(std::is_standard_layout<LLVector3>::value, "LLVector3 must be a standard layout type");
+
typedef LLVector3 LLSimLocalVec;
// Non-member functions
@@ -183,23 +187,17 @@ bool box_valid_and_non_zero(const LLVector3* box);
inline LLVector3::LLVector3()
{
- mV[VX] = 0.f;
- mV[VY] = 0.f;
- mV[VZ] = 0.f;
+ clear();
}
inline LLVector3::LLVector3(const F32 x, const F32 y, const F32 z)
{
- mV[VX] = x;
- mV[VY] = y;
- mV[VZ] = z;
+ set(x, y, z);
}
inline LLVector3::LLVector3(const F32 *vec)
{
- mV[VX] = vec[VX];
- mV[VY] = vec[VY];
- mV[VZ] = vec[VZ];
+ set(vec);
}
inline LLVector3::LLVector3(const glm::vec3& vec)
@@ -230,7 +228,7 @@ inline LLVector3::LLVector3(const LLVector3 &copy)
// checker
inline bool LLVector3::isFinite() const
{
- return (llfinite(mV[VX]) && llfinite(mV[VY]) && llfinite(mV[VZ]));
+ return llfinite(mV[VX]) && llfinite(mV[VY]) && llfinite(mV[VZ]);
}
@@ -238,30 +236,22 @@ inline bool LLVector3::isFinite() const
inline void LLVector3::clear()
{
- mV[VX] = 0.f;
- mV[VY] = 0.f;
- mV[VZ] = 0.f;
+ set(0.f, 0.f, 0.f);
}
inline void LLVector3::setZero()
{
- mV[VX] = 0.f;
- mV[VY] = 0.f;
- mV[VZ] = 0.f;
+ clear();
}
inline void LLVector3::clearVec()
{
- mV[VX] = 0.f;
- mV[VY] = 0.f;
- mV[VZ] = 0.f;
+ clear();
}
inline void LLVector3::zeroVec()
{
- mV[VX] = 0.f;
- mV[VY] = 0.f;
- mV[VZ] = 0.f;
+ clear();
}
inline void LLVector3::set(F32 x, F32 y, F32 z)
@@ -273,16 +263,12 @@ inline void LLVector3::set(F32 x, F32 y, F32 z)
inline void LLVector3::set(const LLVector3& vec)
{
- mV[VX] = vec.mV[VX];
- mV[VY] = vec.mV[VY];
- mV[VZ] = vec.mV[VZ];
+ set(vec.mV[VX], vec.mV[VY], vec.mV[VZ]);
}
inline void LLVector3::set(const F32* vec)
{
- mV[VX] = vec[VX];
- mV[VY] = vec[VY];
- mV[VZ] = vec[VZ];
+ set(vec[VX], vec[VY], vec[VZ]);
}
inline void LLVector3::set(const glm::vec4& vec)
@@ -302,95 +288,66 @@ inline void LLVector3::set(const glm::vec3& vec)
// deprecated
inline void LLVector3::setVec(F32 x, F32 y, F32 z)
{
- mV[VX] = x;
- mV[VY] = y;
- mV[VZ] = z;
+ set(x, y, z);
}
// deprecated
inline void LLVector3::setVec(const LLVector3& vec)
{
- mV[VX] = vec.mV[VX];
- mV[VY] = vec.mV[VY];
- mV[VZ] = vec.mV[VZ];
+ set(vec);
}
// deprecated
inline void LLVector3::setVec(const F32* vec)
{
- mV[VX] = vec[0];
- mV[VY] = vec[1];
- mV[VZ] = vec[2];
+ set(vec);
}
inline F32 LLVector3::normalize()
{
F32 mag = (F32) sqrt(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]);
- F32 oomag;
if (mag > FP_MAG_THRESHOLD)
{
- oomag = 1.f/mag;
- mV[VX] *= oomag;
- mV[VY] *= oomag;
- mV[VZ] *= oomag;
+ *this /= mag;
}
else
{
- mV[VX] = 0.f;
- mV[VY] = 0.f;
- mV[VZ] = 0.f;
+ clear();
mag = 0;
}
- return (mag);
+ return mag;
}
// deprecated
inline F32 LLVector3::normVec()
{
- F32 mag = sqrt(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]);
- F32 oomag;
-
- if (mag > FP_MAG_THRESHOLD)
- {
- oomag = 1.f/mag;
- mV[VX] *= oomag;
- mV[VY] *= oomag;
- mV[VZ] *= oomag;
- }
- else
- {
- mV[VX] = 0.f;
- mV[VY] = 0.f;
- mV[VZ] = 0.f;
- mag = 0;
- }
- return (mag);
+ return normalize();
}
// LLVector3 Magnitude and Normalization Functions
-inline F32 LLVector3::length() const
+inline F32 LLVector3::length() const
{
- return sqrt(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]);
+ return sqrt(lengthSquared());
}
-inline F32 LLVector3::lengthSquared() const
+inline F32 LLVector3::lengthSquared() const
{
return mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ];
}
-inline F32 LLVector3::magVec() const
+inline F32 LLVector3::magVec() const
{
- return sqrt(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]);
+ return length();
}
-inline F32 LLVector3::magVecSquared() const
+inline F32 LLVector3::magVecSquared() const
{
- return mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ];
+ return lengthSquared();
}
-inline bool LLVector3::inRange( F32 min, F32 max ) const
+inline bool LLVector3::inRange(F32 min, F32 max) const
{
return mV[VX] >= min && mV[VX] <= max &&
mV[VY] >= min && mV[VY] <= max &&
@@ -416,7 +373,7 @@ inline F32 operator*(const LLVector3& a, const LLVector3& b)
inline LLVector3 operator%(const LLVector3& a, const LLVector3& b)
{
- return LLVector3( a.mV[VY]*b.mV[VZ] - b.mV[VY]*a.mV[VZ], a.mV[VZ]*b.mV[VX] - b.mV[VZ]*a.mV[VX], a.mV[VX]*b.mV[VY] - b.mV[VX]*a.mV[VY] );
+ return LLVector3(a.mV[VY]*b.mV[VZ] - b.mV[VY]*a.mV[VZ], a.mV[VZ]*b.mV[VX] - b.mV[VZ]*a.mV[VX], a.mV[VX]*b.mV[VY] - b.mV[VX]*a.mV[VY]);
}
inline LLVector3 operator/(const LLVector3& a, F32 k)
@@ -476,7 +433,7 @@ inline const LLVector3& operator-=(LLVector3& a, const LLVector3& b)
inline const LLVector3& operator%=(LLVector3& a, const LLVector3& b)
{
- LLVector3 ret( a.mV[VY]*b.mV[VZ] - b.mV[VY]*a.mV[VZ], a.mV[VZ]*b.mV[VX] - b.mV[VZ]*a.mV[VX], a.mV[VX]*b.mV[VY] - b.mV[VX]*a.mV[VY]);
+ LLVector3 ret(a.mV[VY]*b.mV[VZ] - b.mV[VY]*a.mV[VZ], a.mV[VZ]*b.mV[VX] - b.mV[VZ]*a.mV[VX], a.mV[VX]*b.mV[VY] - b.mV[VX]*a.mV[VY]);
a = ret;
return a;
}
@@ -499,9 +456,7 @@ inline const LLVector3& operator*=(LLVector3& a, const LLVector3& b)
inline const LLVector3& operator/=(LLVector3& a, F32 k)
{
- a.mV[VX] /= k;
- a.mV[VY] /= k;
- a.mV[VZ] /= k;
+ a *= 1.f / k;
return a;
}
@@ -526,7 +481,7 @@ inline F32 dist_vec(const LLVector3& a, const LLVector3& b)
F32 x = a.mV[VX] - b.mV[VX];
F32 y = a.mV[VY] - b.mV[VY];
F32 z = a.mV[VZ] - b.mV[VZ];
- return sqrt( x*x + y*y + z*z );
+ return sqrt(x*x + y*y + z*z);
}
inline F32 dist_vec_squared(const LLVector3& a, const LLVector3& b)
@@ -551,10 +506,7 @@ inline LLVector3 projected_vec(const LLVector3& a, const LLVector3& b)
{
return ((a * b) / bb) * b;
}
- else
- {
- return b.zero;
- }
+ return b.zero;
}
inline LLVector3 inverse_projected_vec(const LLVector3& a, const LLVector3& b)
@@ -591,11 +543,7 @@ inline LLVector3 lerp(const LLVector3& a, const LLVector3& b, F32 u)
inline bool LLVector3::isNull() const
{
- if ( F_APPROXIMATELY_ZERO > mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ] )
- {
- return true;
- }
- return false;
+ return F_APPROXIMATELY_ZERO > mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ];
}
inline void update_min_max(LLVector3& min, LLVector3& max, const LLVector3& pos)
@@ -636,7 +584,7 @@ inline F32 angle_between(const LLVector3& a, const LLVector3& b)
ab = 0.0f; // get rid of negative zero
}
LLVector3 c = a % b; // crossproduct
- return atan2f(sqrtf(c * c), ab); // return the angle
+ return atan2f(c.length(), ab); // return the angle
}
inline bool are_parallel(const LLVector3& a, const LLVector3& b, F32 epsilon)
@@ -646,7 +594,7 @@ inline bool are_parallel(const LLVector3& a, const LLVector3& b, F32 epsilon)
an.normalize();
bn.normalize();
F32 dot = an * bn;
- if ( (1.0f - fabs(dot)) < epsilon)
+ if (1.0f - fabs(dot) < epsilon)
{
return true;
}
diff --git a/indra/llmath/v4color.h b/indra/llmath/v4color.h
index 2f1cb21113..d48020c223 100644
--- a/indra/llmath/v4color.h
+++ b/indra/llmath/v4color.h
@@ -231,6 +231,10 @@ public:
inline void clamp();
};
+static_assert(std::is_trivially_copyable<LLColor4>::value, "LLColor4 must be trivial copy");
+static_assert(std::is_trivially_move_assignable<LLColor4>::value, "LLColor4 must be trivial move");
+static_assert(std::is_standard_layout<LLColor4>::value, "LLColor4 must be a standard layout type");
+
// Non-member functions
F32 distVec(const LLColor4& a, const LLColor4& b); // Returns distance between a and b
F32 distVec_squared(const LLColor4& a, const LLColor4& b); // Returns distance squared between a and b
diff --git a/indra/llmath/v4coloru.h b/indra/llmath/v4coloru.h
index bfa998bc58..e495fd3eea 100644
--- a/indra/llmath/v4coloru.h
+++ b/indra/llmath/v4coloru.h
@@ -123,6 +123,10 @@ public:
static LLColor4U blue;
};
+static_assert(std::is_trivially_copyable<LLColor4U>::value, "LLColor4U must be trivial copy");
+static_assert(std::is_trivially_move_assignable<LLColor4U>::value, "LLColor4U must be trivial move");
+static_assert(std::is_standard_layout<LLColor4U>::value, "LLColor4U must be a standard layout type");
+
// Non-member functions
F32 distVec(const LLColor4U& a, const LLColor4U& b); // Returns distance between a and b
F32 distVec_squared(const LLColor4U& a, const LLColor4U& b); // Returns distance squared between a and b
diff --git a/indra/llmath/v4math.h b/indra/llmath/v4math.h
index 37492e7f98..edfc2f8592 100644
--- a/indra/llmath/v4math.h
+++ b/indra/llmath/v4math.h
@@ -107,9 +107,9 @@ public:
F32 lengthSquared() const; // Returns magnitude squared of LLVector4
F32 normalize(); // Normalizes and returns the magnitude of LLVector4
- F32 magVec() const; // deprecated
- F32 magVecSquared() const; // deprecated
- F32 normVec(); // deprecated
+ F32 magVec() const; // deprecated
+ F32 magVecSquared() const; // deprecated
+ F32 normVec(); // deprecated
// Sets all values to absolute value of their original values
// Returns true if data changed
@@ -118,8 +118,8 @@ public:
bool isExactlyClear() const { return (mV[VW] == 1.0f) && !mV[VX] && !mV[VY] && !mV[VZ]; }
bool isExactlyZero() const { return !mV[VW] && !mV[VX] && !mV[VY] && !mV[VZ]; }
- const LLVector4& rotVec(const LLMatrix4 &mat); // Rotates by MAT4 mat
- const LLVector4& rotVec(const LLQuaternion &q); // Rotates by QUAT q
+ const LLVector4& rotVec(const LLMatrix4 &mat); // Rotates by MAT4 mat
+ const LLVector4& rotVec(const LLQuaternion &q); // Rotates by QUAT q
const LLVector4& scaleVec(const LLVector4& vec); // Scales component-wise by vec
@@ -146,6 +146,10 @@ public:
friend LLVector4 operator-(const LLVector4 &a); // Return vector -a
};
+static_assert(std::is_trivially_copyable<LLVector4>::value, "LLVector4 must be trivial copy");
+static_assert(std::is_trivially_move_assignable<LLVector4>::value, "LLVector4 must be trivial move");
+static_assert(std::is_standard_layout<LLVector4>::value, "LLVector4 must be a standard layout type");
+
// Non-member functions
F32 angle_between(const LLVector4 &a, const LLVector4 &b); // Returns angle (radians) between a and b
bool are_parallel(const LLVector4 &a, const LLVector4 &b, F32 epsilon = F_APPROXIMATELY_ZERO); // Returns true if a and b are very close to parallel
@@ -159,34 +163,22 @@ LLVector4 lerp(const LLVector4 &a, const LLVector4 &b, F32 u); // Returns a vect
inline LLVector4::LLVector4(void)
{
- mV[VX] = 0.f;
- mV[VY] = 0.f;
- mV[VZ] = 0.f;
- mV[VW] = 1.f;
+ clear();
}
inline LLVector4::LLVector4(F32 x, F32 y, F32 z)
{
- mV[VX] = x;
- mV[VY] = y;
- mV[VZ] = z;
- mV[VW] = 1.f;
+ set(x, y, z, 1.f);
}
inline LLVector4::LLVector4(F32 x, F32 y, F32 z, F32 w)
{
- mV[VX] = x;
- mV[VY] = y;
- mV[VZ] = z;
- mV[VW] = w;
+ set(x, y, z, w);
}
inline LLVector4::LLVector4(const F32 *vec)
{
- mV[VX] = vec[VX];
- mV[VY] = vec[VY];
- mV[VZ] = vec[VZ];
- mV[VW] = vec[VW];
+ set(vec);
}
inline LLVector4::LLVector4(const F64 *vec)
@@ -215,18 +207,12 @@ inline LLVector4::LLVector4(const LLVector2 &vec, F32 z, F32 w)
inline LLVector4::LLVector4(const LLVector3 &vec)
{
- mV[VX] = vec.mV[VX];
- mV[VY] = vec.mV[VY];
- mV[VZ] = vec.mV[VZ];
- mV[VW] = 1.f;
+ set(vec, 1.f);
}
inline LLVector4::LLVector4(const LLVector3 &vec, F32 w)
{
- mV[VX] = vec.mV[VX];
- mV[VY] = vec.mV[VY];
- mV[VZ] = vec.mV[VZ];
- mV[VW] = w;
+ set(vec, w);
}
inline LLVector4::LLVector4(const LLSD &sd)
@@ -252,43 +238,31 @@ inline LLVector4::LLVector4(const glm::vec4& vec)
inline bool LLVector4::isFinite() const
{
- return (llfinite(mV[VX]) && llfinite(mV[VY]) && llfinite(mV[VZ]) && llfinite(mV[VW]));
+ return llfinite(mV[VX]) && llfinite(mV[VY]) && llfinite(mV[VZ]) && llfinite(mV[VW]);
}
// Clear and Assignment Functions
inline void LLVector4::clear()
{
- mV[VX] = 0.f;
- mV[VY] = 0.f;
- mV[VZ] = 0.f;
- mV[VW] = 1.f;
+ set(0.f, 0.f, 0.f, 1.f);
}
// deprecated
inline void LLVector4::clearVec()
{
- mV[VX] = 0.f;
- mV[VY] = 0.f;
- mV[VZ] = 0.f;
- mV[VW] = 1.f;
+ clear();
}
// deprecated
inline void LLVector4::zeroVec()
{
- mV[VX] = 0.f;
- mV[VY] = 0.f;
- mV[VZ] = 0.f;
- mV[VW] = 0.f;
+ set(0.f, 0.f, 0.f, 0.f);
}
inline void LLVector4::set(F32 x, F32 y, F32 z)
{
- mV[VX] = x;
- mV[VY] = y;
- mV[VZ] = z;
- mV[VW] = 1.f;
+ set(x, y, z, 1.f);
}
inline void LLVector4::set(F32 x, F32 y, F32 z, F32 w)
@@ -301,10 +275,7 @@ inline void LLVector4::set(F32 x, F32 y, F32 z, F32 w)
inline void LLVector4::set(const LLVector4& vec)
{
- mV[VX] = vec.mV[VX];
- mV[VY] = vec.mV[VY];
- mV[VZ] = vec.mV[VZ];
- mV[VW] = vec.mV[VW];
+ set(vec.mV);
}
inline void LLVector4::set(const LLVector3& vec, F32 w)
@@ -322,7 +293,6 @@ inline void LLVector4::set(const F32* vec)
mV[VZ] = vec[VZ];
mV[VW] = vec[VW];
}
-
inline void LLVector4::set(const glm::vec4& vec)
{
mV[VX] = vec.x;
@@ -342,68 +312,53 @@ inline void LLVector4::set(const glm::vec3& vec, F32 w)
// deprecated
inline void LLVector4::setVec(F32 x, F32 y, F32 z)
{
- mV[VX] = x;
- mV[VY] = y;
- mV[VZ] = z;
- mV[VW] = 1.f;
+ set(x, y, z);
}
// deprecated
inline void LLVector4::setVec(F32 x, F32 y, F32 z, F32 w)
{
- mV[VX] = x;
- mV[VY] = y;
- mV[VZ] = z;
- mV[VW] = w;
+ set(x, y, z, w);
}
// deprecated
inline void LLVector4::setVec(const LLVector4& vec)
{
- mV[VX] = vec.mV[VX];
- mV[VY] = vec.mV[VY];
- mV[VZ] = vec.mV[VZ];
- mV[VW] = vec.mV[VW];
+ set(vec);
}
// deprecated
inline void LLVector4::setVec(const LLVector3& vec, F32 w)
{
- mV[VX] = vec.mV[VX];
- mV[VY] = vec.mV[VY];
- mV[VZ] = vec.mV[VZ];
- mV[VW] = w;
+ set(vec, w);
}
// deprecated
inline void LLVector4::setVec(const F32* vec)
{
- mV[VX] = vec[VX];
- mV[VY] = vec[VY];
- mV[VZ] = vec[VZ];
- mV[VW] = vec[VW];
+ set(vec);
}
// LLVector4 Magnitude and Normalization Functions
-inline F32 LLVector4::length() const
+inline F32 LLVector4::length() const
{
- return sqrt(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]);
+ return sqrt(lengthSquared());
}
-inline F32 LLVector4::lengthSquared() const
+inline F32 LLVector4::lengthSquared() const
{
return mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ];
}
-inline F32 LLVector4::magVec() const
+inline F32 LLVector4::magVec() const
{
- return sqrt(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]);
+ return length();
}
-inline F32 LLVector4::magVecSquared() const
+inline F32 LLVector4::magVecSquared() const
{
- return mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ];
+ return lengthSquared();
}
// LLVector4 Operators
@@ -422,7 +377,7 @@ inline LLVector4 operator-(const LLVector4& a, const LLVector4& b)
inline F32 operator*(const LLVector4& a, const LLVector4& b)
{
- return (a.mV[VX]*b.mV[VX] + a.mV[VY]*b.mV[VY] + a.mV[VZ]*b.mV[VZ]);
+ return a.mV[VX]*b.mV[VX] + a.mV[VY]*b.mV[VY] + a.mV[VZ]*b.mV[VZ];
}
inline LLVector4 operator%(const LLVector4& a, const LLVector4& b)
@@ -495,11 +450,7 @@ inline const LLVector4& operator*=(LLVector4& a, F32 k)
inline const LLVector4& operator/=(LLVector4& a, F32 k)
{
- F32 t = 1.f / k;
- a.mV[VX] *= t;
- a.mV[VY] *= t;
- a.mV[VZ] *= t;
- return a;
+ return a *= 1.f / k;
}
inline LLVector4 operator-(const LLVector4& a)
@@ -517,16 +468,16 @@ inline LLVector4::operator glm::vec4() const
return glm::make_vec4(mV);
}
-inline F32 dist_vec(const LLVector4& a, const LLVector4& b)
+inline F32 dist_vec(const LLVector4& a, const LLVector4& b)
{
LLVector4 vec = a - b;
- return (vec.length());
+ return vec.length();
}
-inline F32 dist_vec_squared(const LLVector4& a, const LLVector4& b)
+inline F32 dist_vec_squared(const LLVector4& a, const LLVector4& b)
{
LLVector4 vec = a - b;
- return (vec.lengthSquared());
+ return vec.lengthSquared();
}
inline LLVector4 lerp(const LLVector4& a, const LLVector4& b, F32 u)
@@ -538,17 +489,13 @@ inline LLVector4 lerp(const LLVector4& a, const LLVector4& b, F32 u)
a.mV[VW] + (b.mV[VW] - a.mV[VW]) * u);
}
-inline F32 LLVector4::normalize()
+inline F32 LLVector4::normalize()
{
F32 mag = sqrt(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]);
- F32 oomag;
if (mag > FP_MAG_THRESHOLD)
{
- oomag = 1.f/mag;
- mV[VX] *= oomag;
- mV[VY] *= oomag;
- mV[VZ] *= oomag;
+ *this /= mag;
}
else
{
@@ -557,30 +504,13 @@ inline F32 LLVector4::normalize()
mV[VZ] = 0.f;
mag = 0.f;
}
- return (mag);
+ return mag;
}
// deprecated
-inline F32 LLVector4::normVec()
+inline F32 LLVector4::normVec()
{
- F32 mag = sqrt(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]);
- F32 oomag;
-
- if (mag > FP_MAG_THRESHOLD)
- {
- oomag = 1.f/mag;
- mV[VX] *= oomag;
- mV[VY] *= oomag;
- mV[VZ] *= oomag;
- }
- else
- {
- mV[VX] = 0.f;
- mV[VY] = 0.f;
- mV[VZ] = 0.f;
- mag = 0.f;
- }
- return (mag);
+ return normalize();
}
// Because apparently some parts of the viewer use this for color info.