summaryrefslogtreecommitdiff
path: root/indra/llmath
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llmath')
-rw-r--r--indra/llmath/llline.cpp176
-rw-r--r--indra/llmath/llline.h62
-rw-r--r--indra/llmath/llmath.h33
-rw-r--r--indra/llmath/llquaternion.cpp186
-rw-r--r--indra/llmath/llquaternion.h164
-rw-r--r--indra/llmath/llsphere.cpp351
-rw-r--r--indra/llmath/llsphere.h59
-rw-r--r--indra/llmath/llvolume.cpp266
-rw-r--r--indra/llmath/llvolume.h35
-rw-r--r--indra/llmath/llvolumemgr.cpp182
-rw-r--r--indra/llmath/llvolumemgr.h47
-rw-r--r--indra/llmath/m3math.cpp91
-rw-r--r--indra/llmath/m3math.h24
-rw-r--r--indra/llmath/m4math.cpp2
-rw-r--r--indra/llmath/m4math.h8
-rw-r--r--indra/llmath/v2math.h95
-rw-r--r--indra/llmath/v3dmath.h13
-rw-r--r--indra/llmath/v3math.cpp16
-rw-r--r--indra/llmath/v3math.h123
-rw-r--r--indra/llmath/v4math.cpp8
-rw-r--r--indra/llmath/v4math.h127
-rw-r--r--indra/llmath/xform.h10
22 files changed, 1790 insertions, 288 deletions
diff --git a/indra/llmath/llline.cpp b/indra/llmath/llline.cpp
new file mode 100644
index 0000000000..b62631072b
--- /dev/null
+++ b/indra/llmath/llline.cpp
@@ -0,0 +1,176 @@
+/**
+ * @file llline.cpp
+ * @author Andrew Meadows
+ * @brief Simple line class that can compute nearest approach between two lines
+ *
+ * Copyright (c) 2001-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#include "llline.h"
+#include "llrand.h"
+
+const F32 SOME_SMALL_NUMBER = 1.0e-5f;
+const F32 SOME_VERY_SMALL_NUMBER = 1.0e-8f;
+
+LLLine::LLLine()
+: mPoint(0.f, 0.f, 0.f),
+ mDirection(1.f, 0.f, 0.f)
+{ }
+
+LLLine::LLLine( const LLVector3& first_point, const LLVector3& second_point )
+{
+ setPoints(first_point, second_point);
+}
+
+void LLLine::setPoints( const LLVector3& first_point, const LLVector3& second_point )
+{
+ mPoint = first_point;
+ mDirection = second_point - first_point;
+ mDirection.normalize();
+}
+
+void LLLine::setPointDirection( const LLVector3& first_point, const LLVector3& second_point )
+{
+ setPoints(first_point, first_point + second_point);
+}
+
+bool LLLine::intersects( const LLVector3& point, F32 radius ) const
+{
+ LLVector3 other_direction = point - mPoint;
+ LLVector3 nearest_point = mPoint + mDirection * (other_direction * mDirection);
+ F32 nearest_approach = (nearest_point - point).length();
+ return (nearest_approach <= radius);
+}
+
+// returns the point on this line that is closest to some_point
+LLVector3 LLLine::nearestApproach( const LLVector3& some_point ) const
+{
+ return (mPoint + mDirection * ((some_point - mPoint) * mDirection));
+}
+
+// the accuracy of this method sucks when you give it two nearly
+// parallel lines, so you should probably check for parallelism
+// before you call this
+//
+// returns the point on this line that is closest to other_line
+LLVector3 LLLine::nearestApproach( const LLLine& other_line ) const
+{
+ LLVector3 between_points = other_line.mPoint - mPoint;
+ F32 dir_dot_dir = mDirection * other_line.mDirection;
+ F32 one_minus_dir_dot_dir = 1.0f - fabs(dir_dot_dir);
+ if ( one_minus_dir_dot_dir < SOME_VERY_SMALL_NUMBER )
+ {
+#ifdef LL_DEBUG
+ llwarns << "LLLine::nearestApproach() was given two very "
+ << "nearly parallel lines dir1 = " << mDirection
+ << " dir2 = " << other_line.mDirection << " with 1-dot_product = "
+ << one_minus_dir_dot_dir << llendl;
+#endif
+ // the lines are approximately parallel
+ // We shouldn't fall in here because this check should have been made
+ // BEFORE this function was called. We dare not continue with the
+ // computations for fear of division by zero, but we have to return
+ // something so we return a bogus point -- caller beware.
+ return 0.5f * (mPoint + other_line.mPoint);
+ }
+
+ F32 odir_dot_bp = other_line.mDirection * between_points;
+
+ F32 numerator = 0;
+ F32 denominator = 0;
+ for (S32 i=0; i<3; i++)
+ {
+ F32 factor = dir_dot_dir * other_line.mDirection.mV[i] - mDirection.mV[i];
+ numerator += ( between_points.mV[i] - odir_dot_bp * other_line.mDirection.mV[i] ) * factor;
+ denominator -= factor * factor;
+ }
+
+ F32 length_to_nearest_approach = numerator / denominator;
+
+ return mPoint + length_to_nearest_approach * mDirection;
+}
+
+std::ostream& operator<<( std::ostream& output_stream, const LLLine& line )
+{
+ output_stream << "{point=" << line.mPoint << "," << "dir=" << line.mDirection << "}";
+ return output_stream;
+}
+
+
+F32 ALMOST_PARALLEL = 0.99f;
+F32 TOO_SMALL_FOR_DIVISION = 0.0001f;
+
+// returns 'true' if this line intersects the plane
+// on success stores the intersection point in 'result'
+bool LLLine::intersectsPlane( LLVector3& result, const LLLine& plane ) const
+{
+ // p = P + l * d equation for a line
+ //
+ // N * p = D equation for a point
+ //
+ // N * (P + l * d) = D
+ // N*P + l * (N*d) = D
+ // l * (N*d) = D - N*P
+ // l = ( D - N*P ) / ( N*d )
+ //
+
+ F32 dot = plane.mDirection * mDirection;
+ if (fabs(dot) < TOO_SMALL_FOR_DIVISION)
+ {
+ return false;
+ }
+
+ F32 plane_dot = plane.mDirection * plane.mPoint;
+ F32 length = ( plane_dot - (plane.mDirection * mPoint) ) / dot;
+ result = mPoint + length * mDirection;
+ return true;
+}
+
+//static
+// returns 'true' if planes intersect, and stores the result
+// the second and third arguments are treated as planes
+// where mPoint is on the plane and mDirection is the normal
+// result.mPoint will be the intersection line's closest approach
+// to first_plane.mPoint
+bool LLLine::getIntersectionBetweenTwoPlanes( LLLine& result, const LLLine& first_plane, const LLLine& second_plane )
+{
+ // TODO -- if we ever get some generic matrix solving code in our libs
+ // then we should just use that, since this problem is really just
+ // linear algebra.
+
+ F32 dot = fabs(first_plane.mDirection * second_plane.mDirection);
+ if (dot > ALMOST_PARALLEL)
+ {
+ // the planes are nearly parallel
+ return false;
+ }
+
+ LLVector3 direction = first_plane.mDirection % second_plane.mDirection;
+ direction.normalize();
+
+ LLVector3 first_intersection;
+ {
+ LLLine intersection_line(first_plane);
+ intersection_line.mDirection = direction % first_plane.mDirection;
+ intersection_line.mDirection.normalize();
+ intersection_line.intersectsPlane(first_intersection, second_plane);
+ }
+
+ /*
+ LLVector3 second_intersection;
+ {
+ LLLine intersection_line(second_plane);
+ intersection_line.mDirection = direction % second_plane.mDirection;
+ intersection_line.mDirection.normalize();
+ intersection_line.intersectsPlane(second_intersection, first_plane);
+ }
+ */
+
+ result.mPoint = first_intersection;
+ result.mDirection = direction;
+
+ return true;
+}
+
+
diff --git a/indra/llmath/llline.h b/indra/llmath/llline.h
new file mode 100644
index 0000000000..cdae3fc1fe
--- /dev/null
+++ b/indra/llmath/llline.h
@@ -0,0 +1,62 @@
+// llline.h
+/**
+ * @file llline.cpp
+ * @author Andrew Meadows
+ * @brief Simple line for computing nearest approach between two infinite lines
+ *
+ * Copyright (c) 2006-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#ifndef LL_LINE_H
+#define LL_LINE_H
+
+#include <iostream>
+#include "stdtypes.h"
+#include "v3math.h"
+
+const F32 DEFAULT_INTERSECTION_ERROR = 0.000001f;
+
+class LLLine
+{
+public:
+ LLLine();
+ LLLine( const LLVector3& first_point, const LLVector3& second_point );
+ virtual ~LLLine() {};
+
+ void setPointDirection( const LLVector3& first_point, const LLVector3& second_point );
+ void setPoints( const LLVector3& first_point, const LLVector3& second_point );
+
+ bool intersects( const LLVector3& point, F32 radius = DEFAULT_INTERSECTION_ERROR ) const;
+
+ // returns the point on this line that is closest to some_point
+ LLVector3 nearestApproach( const LLVector3& some_point ) const;
+
+ // returns the point on this line that is closest to other_line
+ LLVector3 nearestApproach( const LLLine& other_line ) const;
+
+ friend std::ostream& operator<<( std::ostream& output_stream, const LLLine& line );
+
+ // returns 'true' if this line intersects the plane
+ // on success stores the intersection point in 'result'
+ bool intersectsPlane( LLVector3& result, const LLLine& plane ) const;
+
+ // returns 'true' if planes intersect, and stores the result
+ // the second and third arguments are treated as planes
+ // where mPoint is on the plane and mDirection is the normal
+ // result.mPoint will be the intersection line's closest approach
+ // to first_plane.mPoint
+ static bool getIntersectionBetweenTwoPlanes( LLLine& result, const LLLine& first_plane, const LLLine& second_plane );
+
+ const LLVector3& getPoint() const { return mPoint; }
+ const LLVector3& getDirection() const { return mDirection; }
+
+protected:
+ // these are protected because some code assumes that the normal is
+ // always correct and properly normalized.
+ LLVector3 mPoint;
+ LLVector3 mDirection;
+};
+
+
+#endif
diff --git a/indra/llmath/llmath.h b/indra/llmath/llmath.h
index 6df241d3ab..5dfddff4eb 100644
--- a/indra/llmath/llmath.h
+++ b/indra/llmath/llmath.h
@@ -32,8 +32,14 @@
#ifndef LLMATH_H
#define LLMATH_H
+#include <cmath>
+//#include <math.h>
+//#include <stdlib.h>
+#include "lldefs.h"
+
// work around for Windows & older gcc non-standard function names.
#if LL_WINDOWS
+#include <float.h>
#define llisnan(val) _isnan(val)
#define llfinite(val) _finite(val)
#elif (LL_LINUX && __GNUC__ <= 2)
@@ -99,6 +105,12 @@ inline BOOL is_approx_equal(F32 x, F32 y)
return (abs((S32) ((U32&)x - (U32&)y) ) < COMPARE_MANTISSA_UP_TO_BIT);
}
+inline BOOL is_approx_equal(F64 x, F64 y)
+{
+ const S64 COMPARE_MANTISSA_UP_TO_BIT = 0x02;
+ return (abs((S32) ((U64&)x - (U64&)y) ) < COMPARE_MANTISSA_UP_TO_BIT);
+}
+
inline BOOL is_approx_equal_fraction(F32 x, F32 y, U32 frac_bits)
{
BOOL ret = TRUE;
@@ -120,6 +132,27 @@ inline BOOL is_approx_equal_fraction(F32 x, F32 y, U32 frac_bits)
return ret;
}
+inline BOOL is_approx_equal_fraction(F64 x, F64 y, U32 frac_bits)
+{
+ BOOL ret = TRUE;
+ F64 diff = (F64) fabs(x - y);
+
+ S32 diffInt = (S32) diff;
+ S32 diffFracTolerance = (S32) ((diff - (F64) diffInt) * (1 << frac_bits));
+
+ // if integer portion is not equal, not enough bits were used for packing
+ // so error out since either the use case is not correct OR there is
+ // an issue with pack/unpack. should fail in either case.
+ // for decimal portion, make sure that the delta is no more than 1
+ // based on the number of bits used for packing decimal portion.
+ if (diffInt != 0 || diffFracTolerance > 1)
+ {
+ ret = FALSE;
+ }
+
+ return ret;
+}
+
inline S32 llabs(const S32 a)
{
return S32(labs(a));
diff --git a/indra/llmath/llquaternion.cpp b/indra/llmath/llquaternion.cpp
index 34c1fd1762..c3e84e366d 100644
--- a/indra/llmath/llquaternion.cpp
+++ b/indra/llmath/llquaternion.cpp
@@ -51,19 +51,19 @@ const LLQuaternion LLQuaternion::DEFAULT;
LLQuaternion::LLQuaternion(const LLMatrix4 &mat)
{
*this = mat.quaternion();
- normQuat();
+ normalize();
}
LLQuaternion::LLQuaternion(const LLMatrix3 &mat)
{
*this = mat.quaternion();
- normQuat();
+ normalize();
}
LLQuaternion::LLQuaternion(F32 angle, const LLVector4 &vec)
{
LLVector3 v(vec.mV[VX], vec.mV[VY], vec.mV[VZ]);
- v.normVec();
+ v.normalize();
F32 c, s;
c = cosf(angle*0.5f);
@@ -73,13 +73,13 @@ LLQuaternion::LLQuaternion(F32 angle, const LLVector4 &vec)
mQ[VY] = v.mV[VY] * s;
mQ[VZ] = v.mV[VZ] * s;
mQ[VW] = c;
- normQuat();
+ normalize();
}
LLQuaternion::LLQuaternion(F32 angle, const LLVector3 &vec)
{
LLVector3 v(vec);
- v.normVec();
+ v.normalize();
F32 c, s;
c = cosf(angle*0.5f);
@@ -89,7 +89,7 @@ LLQuaternion::LLQuaternion(F32 angle, const LLVector3 &vec)
mQ[VY] = v.mV[VY] * s;
mQ[VZ] = v.mV[VZ] * s;
mQ[VW] = c;
- normQuat();
+ normalize();
}
LLQuaternion::LLQuaternion(const LLVector3 &x_axis,
@@ -99,7 +99,7 @@ LLQuaternion::LLQuaternion(const LLVector3 &x_axis,
LLMatrix3 mat;
mat.setRows(x_axis, y_axis, z_axis);
*this = mat.quaternion();
- normQuat();
+ normalize();
}
// Quatizations
@@ -138,10 +138,93 @@ void LLQuaternion::quantize8(F32 lower, F32 upper)
// Set LLQuaternion routines
+const LLQuaternion& LLQuaternion::setAngleAxis(F32 angle, F32 x, F32 y, F32 z)
+{
+ LLVector3 vec(x, y, z);
+ vec.normalize();
+
+ angle *= 0.5f;
+ F32 c, s;
+ c = cosf(angle);
+ s = sinf(angle);
+
+ mQ[VX] = vec.mV[VX]*s;
+ mQ[VY] = vec.mV[VY]*s;
+ mQ[VZ] = vec.mV[VZ]*s;
+ mQ[VW] = c;
+
+ normalize();
+ return (*this);
+}
+
+const LLQuaternion& LLQuaternion::setAngleAxis(F32 angle, const LLVector3 &vec)
+{
+ LLVector3 v(vec);
+ v.normalize();
+
+ angle *= 0.5f;
+ F32 c, s;
+ c = cosf(angle);
+ s = sinf(angle);
+
+ mQ[VX] = v.mV[VX]*s;
+ mQ[VY] = v.mV[VY]*s;
+ mQ[VZ] = v.mV[VZ]*s;
+ mQ[VW] = c;
+
+ normalize();
+ return (*this);
+}
+
+const LLQuaternion& LLQuaternion::setAngleAxis(F32 angle, const LLVector4 &vec)
+{
+ LLVector3 v(vec.mV[VX], vec.mV[VY], vec.mV[VZ]);
+ v.normalize();
+
+ F32 c, s;
+ c = cosf(angle*0.5f);
+ s = sinf(angle*0.5f);
+
+ mQ[VX] = v.mV[VX]*s;
+ mQ[VY] = v.mV[VY]*s;
+ mQ[VZ] = v.mV[VZ]*s;
+ mQ[VW] = c;
+
+ normalize();
+ return (*this);
+}
+
+const LLQuaternion& LLQuaternion::setEulerAngles(F32 roll, F32 pitch, F32 yaw)
+{
+ LLMatrix3 rot_mat(roll, pitch, yaw);
+ rot_mat.orthogonalize();
+ *this = rot_mat.quaternion();
+
+ normalize();
+ return (*this);
+}
+
+// deprecated
+const LLQuaternion& LLQuaternion::set(const LLMatrix3 &mat)
+{
+ *this = mat.quaternion();
+ normalize();
+ return (*this);
+}
+
+// deprecated
+const LLQuaternion& LLQuaternion::set(const LLMatrix4 &mat)
+{
+ *this = mat.quaternion();
+ normalize();
+ return (*this);
+}
+
+// deprecated
const LLQuaternion& LLQuaternion::setQuat(F32 angle, F32 x, F32 y, F32 z)
{
LLVector3 vec(x, y, z);
- vec.normVec();
+ vec.normalize();
angle *= 0.5f;
F32 c, s;
@@ -153,14 +236,15 @@ const LLQuaternion& LLQuaternion::setQuat(F32 angle, F32 x, F32 y, F32 z)
mQ[VZ] = vec.mV[VZ]*s;
mQ[VW] = c;
- normQuat();
+ normalize();
return (*this);
}
+// deprecated
const LLQuaternion& LLQuaternion::setQuat(F32 angle, const LLVector3 &vec)
{
LLVector3 v(vec);
- v.normVec();
+ v.normalize();
angle *= 0.5f;
F32 c, s;
@@ -172,14 +256,14 @@ const LLQuaternion& LLQuaternion::setQuat(F32 angle, const LLVector3 &vec)
mQ[VZ] = v.mV[VZ]*s;
mQ[VW] = c;
- normQuat();
+ normalize();
return (*this);
}
const LLQuaternion& LLQuaternion::setQuat(F32 angle, const LLVector4 &vec)
{
LLVector3 v(vec.mV[VX], vec.mV[VY], vec.mV[VZ]);
- v.normVec();
+ v.normalize();
F32 c, s;
c = cosf(angle*0.5f);
@@ -190,7 +274,7 @@ const LLQuaternion& LLQuaternion::setQuat(F32 angle, const LLVector4 &vec)
mQ[VZ] = v.mV[VZ]*s;
mQ[VW] = c;
- normQuat();
+ normalize();
return (*this);
}
@@ -200,7 +284,21 @@ const LLQuaternion& LLQuaternion::setQuat(F32 roll, F32 pitch, F32 yaw)
rot_mat.orthogonalize();
*this = rot_mat.quaternion();
- normQuat();
+ normalize();
+ return (*this);
+}
+
+const LLQuaternion& LLQuaternion::setQuat(const LLMatrix3 &mat)
+{
+ *this = mat.quaternion();
+ normalize();
+ return (*this);
+}
+
+const LLQuaternion& LLQuaternion::setQuat(const LLMatrix4 &mat)
+{
+ *this = mat.quaternion();
+ normalize();
return (*this);
//#if 1
// // NOTE: LLQuaternion's are actually inverted with respect to
@@ -337,8 +435,8 @@ void LLQuaternion::shortestArc(const LLVector3 &a, const LLVector3 &b)
// Make sure neither vector is zero length. Also normalize
// the vectors while we are at it.
- F32 vec_a_mag = vec_a.normVec();
- F32 vec_b_mag = vec_b.normVec();
+ F32 vec_a_mag = vec_a.normalize();
+ F32 vec_b_mag = vec_b.normalize();
if (vec_a_mag < F_APPROXIMATELY_ZERO ||
vec_b_mag < F_APPROXIMATELY_ZERO)
{
@@ -370,7 +468,7 @@ void LLQuaternion::shortestArc(const LLVector3 &a, const LLVector3 &b)
ortho_axis -= proj;
// Turn this into an orthonormal axis.
- F32 ortho_length = ortho_axis.normVec();
+ F32 ortho_length = ortho_axis.normalize();
// If the axis' length is 0, then our guess at an orthogonal axis
// was wrong (a is parallel to the x-axis).
if (ortho_length < F_APPROXIMATELY_ZERO)
@@ -391,7 +489,7 @@ void LLQuaternion::shortestArc(const LLVector3 &a, const LLVector3 &b)
// Return the rotation between these vectors.
F32 theta = (F32)acos(cos_theta);
- setQuat(theta, axis);
+ setAngleAxis(theta, axis);
}
}
@@ -516,7 +614,7 @@ LLQuaternion lerp(F32 t, const LLQuaternion &p, const LLQuaternion &q)
{
LLQuaternion r;
r = t * (q - p) + p;
- r.normQuat();
+ r.normalize();
return r;
}
#endif
@@ -529,7 +627,7 @@ LLQuaternion lerp(F32 t, const LLQuaternion &q)
r.mQ[VY] = t * q.mQ[VY];
r.mQ[VZ] = t * q.mQ[VZ];
r.mQ[VW] = t * (q.mQ[VZ] - 1.f) + 1.f;
- r.normQuat();
+ r.normalize();
return r;
}
@@ -544,7 +642,7 @@ LLQuaternion lerp(F32 t, const LLQuaternion &p, const LLQuaternion &q)
r.mQ[VY] = t * q.mQ[VY] + (inv_t * p.mQ[VY]);
r.mQ[VZ] = t * q.mQ[VZ] + (inv_t * p.mQ[VZ]);
r.mQ[VW] = t * q.mQ[VW] + (inv_t * p.mQ[VW]);
- r.normQuat();
+ r.normalize();
return r;
}
@@ -640,8 +738,8 @@ LLQuaternion slerp(F32 t, const LLQuaternion &q)
// when c < 0.0 then theta > PI/2
// since quat and -quat are the same rotation we invert one of
// p or q to reduce unecessary spins
- // A equivalent way to do it is to convert acos(c) as if it had been negative,
- // and to negate stp
+ // A equivalent way to do it is to convert acos(c) as if it had
+ // been negative, and to negate stp
angle = (F32) acos(-c);
stp = -(F32) sin(angle * (1.f - t));
stq = (F32) sin(angle * t);
@@ -742,20 +840,6 @@ LLQuaternion::Order StringToOrder( const char *str )
return LLQuaternion::XYZ;
}
-const LLQuaternion& LLQuaternion::setQuat(const LLMatrix3 &mat)
-{
- *this = mat.quaternion();
- normQuat();
- return (*this);
-}
-
-const LLQuaternion& LLQuaternion::setQuat(const LLMatrix4 &mat)
-{
- *this = mat.quaternion();
- normQuat();
- return (*this);
-}
-
void LLQuaternion::getAngleAxis(F32* angle, LLVector3 &vec) const
{
F32 cos_a = mQ[VW];
@@ -769,10 +853,28 @@ void LLQuaternion::getAngleAxis(F32* angle, LLVector3 &vec) const
else
sin_a = 1.f/sin_a;
- *angle = 2.0f * (F32) acos( cos_a );
- vec.mV[VX] = mQ[VX] * sin_a;
- vec.mV[VY] = mQ[VY] * sin_a;
- vec.mV[VZ] = mQ[VZ] * sin_a;
+ F32 temp_angle = 2.0f * (F32) acos( cos_a );
+ if (temp_angle > F_PI)
+ {
+ // The (angle,axis) pair should never have angles outside [PI, -PI]
+ // since we want the _shortest_ (angle,axis) solution.
+ // Since acos is defined for [0, PI], and we multiply by 2.0, we
+ // can push the angle outside the acceptible range.
+ // When this happens we set the angle to the other portion of a
+ // full 2PI rotation, and negate the axis, which reverses the
+ // direction of the rotation (by the right-hand rule).
+ *angle = 2.f * F_PI - temp_angle;
+ vec.mV[VX] = - mQ[VX] * sin_a;
+ vec.mV[VY] = - mQ[VY] * sin_a;
+ vec.mV[VZ] = - mQ[VZ] * sin_a;
+ }
+ else
+ {
+ *angle = temp_angle;
+ vec.mV[VX] = mQ[VX] * sin_a;
+ vec.mV[VY] = mQ[VY] * sin_a;
+ vec.mV[VZ] = mQ[VZ] * sin_a;
+ }
}
@@ -846,7 +948,7 @@ BOOL LLQuaternion::parseQuat(const char* buf, LLQuaternion* value)
S32 count = sscanf( buf, "%f %f %f %f", quat.mQ + 0, quat.mQ + 1, quat.mQ + 2, quat.mQ + 3 );
if( 4 == count )
{
- value->setQuat( quat );
+ value->set( quat );
return TRUE;
}
diff --git a/indra/llmath/llquaternion.h b/indra/llmath/llquaternion.h
index 01ddae94cb..a088d70674 100644
--- a/indra/llmath/llquaternion.h
+++ b/indra/llmath/llquaternion.h
@@ -57,10 +57,10 @@ public:
LLQuaternion(); // Initializes Quaternion to (0,0,0,1)
explicit LLQuaternion(const LLMatrix4 &mat); // Initializes Quaternion from Matrix4
explicit LLQuaternion(const LLMatrix3 &mat); // Initializes Quaternion from Matrix3
- LLQuaternion(F32 x, F32 y, F32 z, F32 w); // Initializes Quaternion to normQuat(x, y, z, w)
+ LLQuaternion(F32 x, F32 y, F32 z, F32 w); // Initializes Quaternion to normalize(x, y, z, w)
LLQuaternion(F32 angle, const LLVector4 &vec); // Initializes Quaternion to axis_angle2quat(angle, vec)
LLQuaternion(F32 angle, const LLVector3 &vec); // Initializes Quaternion to axis_angle2quat(angle, vec)
- LLQuaternion(const F32 *q); // Initializes Quaternion to normQuat(x, y, z, w)
+ LLQuaternion(const F32 *q); // Initializes Quaternion to normalize(x, y, z, w)
LLQuaternion(const LLVector3 &x_axis,
const LLVector3 &y_axis,
const LLVector3 &z_axis); // Initializes Quaternion from Matrix3 = [x_axis ; y_axis ; z_axis]
@@ -71,15 +71,27 @@ public:
void quantize16(F32 lower, F32 upper); // changes the vector to reflect quatization
void quantize8(F32 lower, F32 upper); // changes the vector to reflect quatization
void loadIdentity(); // Loads the quaternion that represents the identity rotation
- const LLQuaternion& setQuatInit(F32 x, F32 y, F32 z, F32 w); // Sets Quaternion to normQuat(x, y, z, w)
- const LLQuaternion& setQuat(const LLQuaternion &quat); // Copies Quaternion
- const LLQuaternion& setQuat(const F32 *q); // Sets Quaternion to normQuat(quat[VX], quat[VY], quat[VZ], quat[VW])
- const LLQuaternion& setQuat(const LLMatrix3 &mat); // Sets Quaternion to mat2quat(mat)
- const LLQuaternion& setQuat(const LLMatrix4 &mat); // Sets Quaternion to mat2quat(mat)
- const LLQuaternion& setQuat(F32 angle, F32 x, F32 y, F32 z); // Sets Quaternion to axis_angle2quat(angle, x, y, z)
- const LLQuaternion& setQuat(F32 angle, const LLVector3 &vec); // Sets Quaternion to axis_angle2quat(angle, vec)
- const LLQuaternion& setQuat(F32 angle, const LLVector4 &vec); // Sets Quaternion to axis_angle2quat(angle, vec)
- const LLQuaternion& setQuat(F32 roll, F32 pitch, F32 yaw); // Sets Quaternion to euler2quat(pitch, yaw, roll)
+
+ const LLQuaternion& set(F32 x, F32 y, F32 z, F32 w); // Sets Quaternion to normalize(x, y, z, w)
+ const LLQuaternion& set(const LLQuaternion &quat); // Copies Quaternion
+ const LLQuaternion& set(const F32 *q); // Sets Quaternion to normalize(quat[VX], quat[VY], quat[VZ], quat[VW])
+ const LLQuaternion& set(const LLMatrix3 &mat); // Sets Quaternion to mat2quat(mat)
+ const LLQuaternion& set(const LLMatrix4 &mat); // Sets Quaternion to mat2quat(mat)
+
+ const LLQuaternion& setAngleAxis(F32 angle, F32 x, F32 y, F32 z); // Sets Quaternion to axis_angle2quat(angle, x, y, z)
+ const LLQuaternion& setAngleAxis(F32 angle, const LLVector3 &vec); // Sets Quaternion to axis_angle2quat(angle, vec)
+ const LLQuaternion& setAngleAxis(F32 angle, const LLVector4 &vec); // Sets Quaternion to axis_angle2quat(angle, vec)
+ const LLQuaternion& setEulerAngles(F32 roll, F32 pitch, F32 yaw); // Sets Quaternion to euler2quat(pitch, yaw, roll)
+
+ const LLQuaternion& setQuatInit(F32 x, F32 y, F32 z, F32 w); // deprecated
+ const LLQuaternion& setQuat(const LLQuaternion &quat); // deprecated
+ const LLQuaternion& setQuat(const F32 *q); // deprecated
+ const LLQuaternion& setQuat(const LLMatrix3 &mat); // deprecated
+ const LLQuaternion& setQuat(const LLMatrix4 &mat); // deprecated
+ const LLQuaternion& setQuat(F32 angle, F32 x, F32 y, F32 z); // deprecated
+ const LLQuaternion& setQuat(F32 angle, const LLVector3 &vec); // deprecated
+ const LLQuaternion& setQuat(F32 angle, const LLVector4 &vec); // deprecated
+ const LLQuaternion& setQuat(F32 roll, F32 pitch, F32 yaw); // deprecated
LLMatrix4 getMatrix4(void) const; // Returns the Matrix4 equivalent of Quaternion
LLMatrix3 getMatrix3(void) const; // Returns the Matrix3 equivalent of Quaternion
@@ -87,11 +99,16 @@ public:
void getAngleAxis(F32* angle, LLVector3 &vec) const;
void getEulerAngles(F32 *roll, F32* pitch, F32 *yaw) const;
- F32 normQuat(); // Normalizes Quaternion and returns magnitude
- const LLQuaternion& conjQuat(void); // Conjugates Quaternion and returns result
+ F32 normalize(); // Normalizes Quaternion and returns magnitude
+ F32 normQuat(); // deprecated
+
+ const LLQuaternion& conjugate(void); // Conjugates Quaternion and returns result
+ const LLQuaternion& conjQuat(void); // deprecated
// Other useful methods
- const LLQuaternion& transQuat(); // Transpose
+ const LLQuaternion& transpose(); // transpose (same as conjugate)
+ const LLQuaternion& transQuat(); // deprecated
+
void shortestArc(const LLVector3 &a, const LLVector3 &b); // shortest rotation from a to b
const LLQuaternion& constrain(F32 radians); // constrains rotation to a cone angle specified in radians
@@ -189,7 +206,7 @@ inline LLQuaternion::LLQuaternion(F32 x, F32 y, F32 z, F32 w)
mQ[VS] = w;
//RN: don't normalize this case as its used mainly for temporaries during calculations
- //normQuat();
+ //normalize();
/*
F32 mag = sqrtf(mQ[VX]*mQ[VX] + mQ[VY]*mQ[VY] + mQ[VZ]*mQ[VZ] + mQ[VS]*mQ[VS]);
mag -= 1.f;
@@ -205,7 +222,7 @@ inline LLQuaternion::LLQuaternion(const F32 *q)
mQ[VZ] = q[VZ];
mQ[VS] = q[VW];
- normQuat();
+ normalize();
/*
F32 mag = sqrtf(mQ[VX]*mQ[VX] + mQ[VY]*mQ[VY] + mQ[VZ]*mQ[VZ] + mQ[VS]*mQ[VS]);
mag -= 1.f;
@@ -224,33 +241,67 @@ inline void LLQuaternion::loadIdentity()
}
+inline const LLQuaternion& LLQuaternion::set(F32 x, F32 y, F32 z, F32 w)
+{
+ mQ[VX] = x;
+ mQ[VY] = y;
+ mQ[VZ] = z;
+ mQ[VS] = w;
+ normalize();
+ return (*this);
+}
+
+inline const LLQuaternion& LLQuaternion::set(const LLQuaternion &quat)
+{
+ mQ[VX] = quat.mQ[VX];
+ mQ[VY] = quat.mQ[VY];
+ mQ[VZ] = quat.mQ[VZ];
+ mQ[VW] = quat.mQ[VW];
+ normalize();
+ return (*this);
+}
+
+inline const LLQuaternion& LLQuaternion::set(const F32 *q)
+{
+ mQ[VX] = q[VX];
+ mQ[VY] = q[VY];
+ mQ[VZ] = q[VZ];
+ mQ[VS] = q[VW];
+ normalize();
+ return (*this);
+}
+
+
+// deprecated
inline const LLQuaternion& LLQuaternion::setQuatInit(F32 x, F32 y, F32 z, F32 w)
{
mQ[VX] = x;
mQ[VY] = y;
mQ[VZ] = z;
mQ[VS] = w;
- normQuat();
+ normalize();
return (*this);
}
+// deprecated
inline const LLQuaternion& LLQuaternion::setQuat(const LLQuaternion &quat)
{
mQ[VX] = quat.mQ[VX];
mQ[VY] = quat.mQ[VY];
mQ[VZ] = quat.mQ[VZ];
mQ[VW] = quat.mQ[VW];
- normQuat();
+ normalize();
return (*this);
}
+// deprecated
inline const LLQuaternion& LLQuaternion::setQuat(const F32 *q)
{
mQ[VX] = q[VX];
mQ[VY] = q[VY];
mQ[VZ] = q[VZ];
mQ[VS] = q[VW];
- normQuat();
+ normalize();
return (*this);
}
@@ -270,10 +321,36 @@ inline void LLQuaternion::getAngleAxis(F32* angle, F32* x, F32* y, F32* z) const
else
sin_a = 1.f/sin_a;
- *angle = 2.0f * (F32) acos( cos_a );
- *x = mQ[VX] * sin_a;
- *y = mQ[VY] * sin_a;
- *z = mQ[VZ] * sin_a;
+ F32 temp_angle = 2.0f * (F32) acos( cos_a );
+ if (temp_angle > F_PI)
+ {
+ // The (angle,axis) pair should never have angles outside [PI, -PI]
+ // since we want the _shortest_ (angle,axis) solution.
+ // Since acos is defined for [0, PI], and we multiply by 2.0, we
+ // can push the angle outside the acceptible range.
+ // When this happens we set the angle to the other portion of a
+ // full 2PI rotation, and negate the axis, which reverses the
+ // direction of the rotation (by the right-hand rule).
+ *angle = 2.f * F_PI - temp_angle;
+ *x = - mQ[VX] * sin_a;
+ *y = - mQ[VY] * sin_a;
+ *z = - mQ[VZ] * sin_a;
+ }
+ else
+ {
+ *angle = temp_angle;
+ *x = mQ[VX] * sin_a;
+ *y = mQ[VY] * sin_a;
+ *z = mQ[VZ] * sin_a;
+ }
+}
+
+inline const LLQuaternion& LLQuaternion::conjugate()
+{
+ mQ[VX] *= -1.f;
+ mQ[VY] *= -1.f;
+ mQ[VZ] *= -1.f;
+ return (*this);
}
inline const LLQuaternion& LLQuaternion::conjQuat()
@@ -285,12 +362,21 @@ inline const LLQuaternion& LLQuaternion::conjQuat()
}
// Transpose
+inline const LLQuaternion& LLQuaternion::transpose()
+{
+ mQ[VX] *= -1.f;
+ mQ[VY] *= -1.f;
+ mQ[VZ] *= -1.f;
+ return (*this);
+}
+
+// deprecated
inline const LLQuaternion& LLQuaternion::transQuat()
{
- mQ[VX] = -mQ[VX];
- mQ[VY] = -mQ[VY];
- mQ[VZ] = -mQ[VZ];
- return *this;
+ mQ[VX] *= -1.f;
+ mQ[VY] *= -1.f;
+ mQ[VZ] *= -1.f;
+ return (*this);
}
@@ -382,6 +468,30 @@ inline const LLQuaternion& operator*=(LLQuaternion &a, const LLQuaternion &b)
return a;
}
+inline F32 LLQuaternion::normalize()
+{
+ F32 mag = sqrtf(mQ[VX]*mQ[VX] + mQ[VY]*mQ[VY] + mQ[VZ]*mQ[VZ] + mQ[VS]*mQ[VS]);
+
+ if (mag > FP_MAG_THRESHOLD)
+ {
+ F32 oomag = 1.f/mag;
+ mQ[VX] *= oomag;
+ mQ[VY] *= oomag;
+ mQ[VZ] *= oomag;
+ mQ[VS] *= oomag;
+ }
+ else
+ {
+ mQ[VX] = 0.f;
+ mQ[VY] = 0.f;
+ mQ[VZ] = 0.f;
+ mQ[VS] = 1.f;
+ }
+
+ return mag;
+}
+
+// deprecated
inline F32 LLQuaternion::normQuat()
{
F32 mag = sqrtf(mQ[VX]*mQ[VX] + mQ[VY]*mQ[VY] + mQ[VZ]*mQ[VZ] + mQ[VS]*mQ[VS]);
diff --git a/indra/llmath/llsphere.cpp b/indra/llmath/llsphere.cpp
new file mode 100644
index 0000000000..3428dc1487
--- /dev/null
+++ b/indra/llmath/llsphere.cpp
@@ -0,0 +1,351 @@
+/**
+ * @file llsphere.cpp
+ * @author Andrew Meadows
+ * @brief Simple line class that can compute nearest approach between two lines
+ *
+ * Copyright (c) 2006-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#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) ? TRUE : FALSE;
+}
+
+// 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 (separation <= mRadius + other_sphere.mRadius) ? TRUE : FALSE;
+}
+
+// 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
+{
+ // TODO? -- use approximate equality for centers?
+ return (mRadius == rhs.mRadius
+ && mCenter == rhs.mCenter);
+}
+
+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 );
+ S32 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
new file mode 100644
index 0000000000..709406eb5e
--- /dev/null
+++ b/indra/llmath/llsphere.h
@@ -0,0 +1,59 @@
+// llsphere.h
+/**
+ * @file llsphere.cpp
+ * @author Andrew Meadows
+ * @brief Simple sphere implementation for basic geometric operations
+ *
+ * Copyright (c) 2001-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#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/llvolume.cpp b/indra/llmath/llvolume.cpp
index 0c711cabcd..43b42bf182 100644
--- a/indra/llmath/llvolume.cpp
+++ b/indra/llmath/llvolume.cpp
@@ -2510,12 +2510,19 @@ bool LLVolumeParams::validate(U8 prof_curve, F32 prof_begin, F32 prof_end, F32 h
return true;
}
-#define MAX_INDEX 10000
S32 *LLVolume::getTriangleIndices(U32 &num_indices) const
{
- S32 index[MAX_INDEX];
+ S32 expected_num_triangle_indices = getNumTriangleIndices();
+ if (expected_num_triangle_indices > MAX_VOLUME_TRIANGLE_INDICES)
+ {
+ // we don't allow LLVolumes with this many vertices
+ llwarns << "Couldn't allocate triangle indices" << llendl;
+ num_indices = 0;
+ return NULL;
+ }
+
+ S32* index = new S32[expected_num_triangle_indices];
S32 count = 0;
- S32 *indices = NULL;
// Let's do this totally diffently, as we don't care about faces...
// Counter-clockwise triangles are forward facing...
@@ -2529,6 +2536,9 @@ S32 *LLVolume::getTriangleIndices(U32 &num_indices) const
size_s_out = getProfile().getTotalOut();
size_t = getPath().mPath.size();
+ // NOTE -- if the construction of the triangles below ever changes
+ // then getNumTriangleIndices() method may also have to be updated.
+
if (open) /* Flawfinder: ignore */
{
if (hollow)
@@ -2536,9 +2546,6 @@ S32 *LLVolume::getTriangleIndices(U32 &num_indices) const
// Open hollow -- much like the closed solid, except we
// we need to stitch up the gap between s=0 and s=size_s-1
- if ( (size_t - 1) * (((size_s -1) * 6) + 6) >= MAX_INDEX)
- goto noindices;
-
for (t = 0; t < size_t - 1; t++)
{
// The outer face, first cut, and inner face
@@ -2652,8 +2659,6 @@ S32 *LLVolume::getTriangleIndices(U32 &num_indices) const
if (use_tri1a2)
{
- if (count + 3 >= MAX_INDEX)
- goto noindices;
index[count++] = pt1 + i;
index[count++] = pt1 + 1 + i;
index[count++] = pt2 + i;
@@ -2661,8 +2666,6 @@ S32 *LLVolume::getTriangleIndices(U32 &num_indices) const
}
else
{
- if (count + 3 >= MAX_INDEX)
- goto noindices;
index[count++] = pt1 + i;
index[count++] = pt2 - 1 + i;
index[count++] = pt2 + i;
@@ -2753,8 +2756,6 @@ S32 *LLVolume::getTriangleIndices(U32 &num_indices) const
if (use_tri1a2)
{
- if (count + 3 >= MAX_INDEX)
- goto noindices;
index[count++] = pt1;
index[count++] = pt2;
index[count++] = pt1 + 1;
@@ -2762,8 +2763,6 @@ S32 *LLVolume::getTriangleIndices(U32 &num_indices) const
}
else
{
- if (count + 3 >= MAX_INDEX)
- goto noindices;
index[count++] = pt1;
index[count++] = pt2;
index[count++] = pt2 - 1;
@@ -2776,9 +2775,6 @@ S32 *LLVolume::getTriangleIndices(U32 &num_indices) const
{
// Open solid
- if ( (size_t - 1) * (((size_s -1) * 6) + 6) >= MAX_INDEX)
- goto noindices;
-
for (t = 0; t < size_t - 1; t++)
{
// Outer face + 1 cut face
@@ -2808,8 +2804,6 @@ S32 *LLVolume::getTriangleIndices(U32 &num_indices) const
// Do the top and bottom caps, if necessary
if (path_open)
{
- if ( count + (size_s - 2) * 3 >= MAX_INDEX)
- goto noindices;
for (s = 0; s < size_s - 2; s++)
{
index[count++] = s+1;
@@ -2819,8 +2813,6 @@ S32 *LLVolume::getTriangleIndices(U32 &num_indices) const
// We've got a top cap
S32 offset = (size_t - 1)*size_s;
- if ( count + (size_s - 2) * 3 >= MAX_INDEX)
- goto noindices;
for (s = 0; s < size_s - 2; s++)
{
// Inverted ordering from bottom cap.
@@ -2836,8 +2828,6 @@ S32 *LLVolume::getTriangleIndices(U32 &num_indices) const
// Closed hollow
// Outer face
- if ( (size_t - 1) * (size_s_out - 1) * 6 >= MAX_INDEX)
- goto noindices;
for (t = 0; t < size_t - 1; t++)
{
for (s = 0; s < size_s_out - 1; s++)
@@ -2856,8 +2846,6 @@ S32 *LLVolume::getTriangleIndices(U32 &num_indices) const
// Inner face
// Invert facing from outer face
- if ( count + (size_t - 1) * ((size_s - 1) - size_s_out) * 6 >= MAX_INDEX)
- goto noindices;
for (t = 0; t < size_t - 1; t++)
{
for (s = size_s_out; s < size_s - 1; s++)
@@ -2962,8 +2950,6 @@ S32 *LLVolume::getTriangleIndices(U32 &num_indices) const
if (use_tri1a2)
{
- if (count + 3 >= MAX_INDEX)
- goto noindices;
index[count++] = pt1 + i;
index[count++] = pt1 + 1 + i;
index[count++] = pt2 + i;
@@ -2971,8 +2957,6 @@ S32 *LLVolume::getTriangleIndices(U32 &num_indices) const
}
else
{
- if (count + 3 >= MAX_INDEX)
- goto noindices;
index[count++] = pt1 + i;
index[count++] = pt2 - 1 + i;
index[count++] = pt2 + i;
@@ -3063,8 +3047,6 @@ S32 *LLVolume::getTriangleIndices(U32 &num_indices) const
if (use_tri1a2)
{
- if (count + 3 >= MAX_INDEX)
- goto noindices;
index[count++] = pt1;
index[count++] = pt2;
index[count++] = pt1 + 1;
@@ -3072,8 +3054,6 @@ S32 *LLVolume::getTriangleIndices(U32 &num_indices) const
}
else
{
- if (count + 3 >= MAX_INDEX)
- goto noindices;
index[count++] = pt1;
index[count++] = pt2;
index[count++] = pt2 - 1;
@@ -3085,8 +3065,6 @@ S32 *LLVolume::getTriangleIndices(U32 &num_indices) const
else
{
// Closed solid. Easy case.
- if ( (size_t - 1) * (size_s - 1) * 6 > MAX_INDEX)
- goto noindices;
for (t = 0; t < size_t - 1; t++)
{
for (s = 0; s < size_s - 1; s++)
@@ -3108,8 +3086,6 @@ S32 *LLVolume::getTriangleIndices(U32 &num_indices) const
if (path_open)
{
// bottom cap
- if ( count + (size_s - 2 - 1) * 3 >= MAX_INDEX)
- goto noindices;
for (s = 1; s < size_s - 2; s++)
{
index[count++] = s+1;
@@ -3119,8 +3095,6 @@ S32 *LLVolume::getTriangleIndices(U32 &num_indices) const
// top cap
S32 offset = (size_t - 1)*size_s;
- if ( count + (size_s - 2 - 1) * 3 >= MAX_INDEX)
- goto noindices;
for (s = 1; s < size_s - 2; s++)
{
// Inverted ordering from bottom cap.
@@ -3131,7 +3105,18 @@ S32 *LLVolume::getTriangleIndices(U32 &num_indices) const
}
}
+#ifdef LL_DEBUG
+ // assert that we computed the correct number of indices
+ if (count != expected_num_triangle_indices )
+ {
+ llerrs << "bad index count prediciton:"
+ << " expected=" << expected_num_triangle_indices
+ << " actual=" << count << llendl;
+ }
+#endif
+
#if 0
+ // verify that each index does not point beyond the size of the mesh
S32 num_vertices = mMesh.size();
for (i = 0; i < count; i+=3)
{
@@ -3142,17 +3127,65 @@ S32 *LLVolume::getTriangleIndices(U32 &num_indices) const
}
#endif
- indices = new S32[count];
-noindices:
- if (!indices)
+ num_indices = count;
+ return index;
+}
+
+S32 LLVolume::getNumTriangleIndices() const
+{
+ BOOL profile_open = getProfile().isOpen();
+ BOOL hollow = getProfile().isHollow();
+ BOOL path_open = getPath().isOpen();
+
+ S32 size_s, size_s_out, size_t;
+ size_s = getProfile().getTotal();
+ size_s_out = getProfile().getTotalOut();
+ size_t = getPath().mPath.size();
+
+ S32 count = 0;
+ if (profile_open) /* Flawfinder: ignore */
{
- llwarns << "Couldn't allocate triangle indices" << llendl;
- num_indices = 0;
- return NULL;
+ if (hollow)
+ {
+ // Open hollow -- much like the closed solid, except we
+ // we need to stitch up the gap between s=0 and s=size_s-1
+ count = (size_t - 1) * (((size_s -1) * 6) + 6);
+ }
+ else
+ {
+ count = (size_t - 1) * (((size_s -1) * 6) + 6);
+ }
}
- num_indices = count;
- memcpy(indices, index, count * sizeof(S32)); /* Flawfinder: ignore */
- return indices;
+ else if (hollow)
+ {
+ // Closed hollow
+ // Outer face
+ count = (size_t - 1) * (size_s_out - 1) * 6;
+
+ // Inner face
+ count += (size_t - 1) * ((size_s - 1) - size_s_out) * 6;
+ }
+ else
+ {
+ // Closed solid. Easy case.
+ count = (size_t - 1) * (size_s - 1) * 6;
+ }
+
+ if (path_open)
+ {
+ S32 cap_triangle_count = size_s - 3;
+ if ( profile_open
+ || hollow )
+ {
+ cap_triangle_count = size_s - 2;
+ }
+ if ( cap_triangle_count > 0 )
+ {
+ // top and bottom caps
+ count += cap_triangle_count * 2 * 3;
+ }
+ }
+ return count;
}
//-----------------------------------------------------------------------------
@@ -3483,7 +3516,7 @@ struct lessTriangle
BOOL equalTriangle(const S32 *a, const S32 *b)
{
- if ((*a == *b) && (*(a+1) == *(b+1)) && ((*a+2) == (*b+2)))
+ if ((*a == *b) && (*(a+1) == *(b+1)) && (*(a+2) == *(b+2)))
{
return TRUE;
}
@@ -3499,6 +3532,21 @@ BOOL LLVolume::cleanupTriangleData( const S32 num_input_vertices,
S32 &num_output_triangles,
S32 **output_triangles)
{
+ /* Testing: avoid any cleanup
+ num_output_vertices = num_input_vertices;
+ num_output_triangles = num_input_triangles;
+
+ *output_vertices = new LLVector3[num_input_vertices];
+ for (S32 i = 0; i < num_input_vertices; i++)
+ {
+ (*output_vertices)[i] = input_vertices[i].mPos;
+ }
+
+ *output_triangles = new S32[num_input_triangles*3];
+ memcpy(*output_triangles, input_triangles, 3*num_input_triangles*sizeof(S32)); // Flawfinder: ignore
+ return TRUE;
+ */
+
// Here's how we do this:
// Create a structure which contains the original vertex index and the
// LLVector3 data.
@@ -3549,7 +3597,7 @@ BOOL LLVolume::cleanupTriangleData( const S32 num_input_vertices,
}
else
{
- //llinfos << "Removed duplicate vertex " << pairp->mVertex << llendl;
+ //llinfos << "Removed duplicate vertex " << pairp->mVertex << ", distance magVecSquared() is " << (pairp->mVertex - prev_pairp->mVertex).magVecSquared() << llendl;
}
vertex_mapping[pairp->mIndex] = new_num_vertices - 1;
}
@@ -3561,50 +3609,54 @@ BOOL LLVolume::cleanupTriangleData( const S32 num_input_vertices,
for (i = 0; i < num_input_triangles; i++)
{
- //llinfos << "Checking triangle " << input_triangles[i*3] << ":" << input_triangles[i*3+1] << ":" << input_triangles[i*3+2] << llendl;
- input_triangles[i*3] = vertex_mapping[input_triangles[i*3]];
- input_triangles[i*3+1] = vertex_mapping[input_triangles[i*3+1]];
- input_triangles[i*3+2] = vertex_mapping[input_triangles[i*3+2]];
+ S32 v1 = i*3;
+ S32 v2 = i*3 + 1;
+ S32 v3 = i*3 + 2;
+
+ //llinfos << "Checking triangle " << input_triangles[v1] << ":" << input_triangles[v2] << ":" << input_triangles[v3] << llendl;
+ input_triangles[v1] = vertex_mapping[input_triangles[v1]];
+ input_triangles[v2] = vertex_mapping[input_triangles[v2]];
+ input_triangles[v3] = vertex_mapping[input_triangles[v3]];
- if ((input_triangles[i*3] == input_triangles[i*3+1])
- || (input_triangles[i*3] == input_triangles[i*3+2])
- || (input_triangles[i*3+1] == input_triangles[i*3+2]))
+ if ((input_triangles[v1] == input_triangles[v2])
+ || (input_triangles[v1] == input_triangles[v3])
+ || (input_triangles[v2] == input_triangles[v3]))
{
- //llinfos << "Removing degenerate triangle " << input_triangles[i*3] << ":" << input_triangles[i*3+1] << ":" << input_triangles[i*3+2] << llendl;
+ //llinfos << "Removing degenerate triangle " << input_triangles[v1] << ":" << input_triangles[v2] << ":" << input_triangles[v3] << llendl;
// Degenerate triangle, skip
continue;
}
- if (input_triangles[i*3] < input_triangles[i*3+1])
+ if (input_triangles[v1] < input_triangles[v2])
{
- if (input_triangles[i*3] < input_triangles[i*3+2])
+ if (input_triangles[v1] < input_triangles[v3])
{
// (0 < 1) && (0 < 2)
- new_triangles[new_num_triangles*3] = input_triangles[i*3];
- new_triangles[new_num_triangles*3+1] = input_triangles[i*3+1];
- new_triangles[new_num_triangles*3+2] = input_triangles[i*3+2];
+ new_triangles[new_num_triangles*3] = input_triangles[v1];
+ new_triangles[new_num_triangles*3+1] = input_triangles[v2];
+ new_triangles[new_num_triangles*3+2] = input_triangles[v3];
}
else
{
// (0 < 1) && (2 < 0)
- new_triangles[new_num_triangles*3] = input_triangles[i*3+2];
- new_triangles[new_num_triangles*3+1] = input_triangles[i*3];
- new_triangles[new_num_triangles*3+2] = input_triangles[i*3+1];
+ new_triangles[new_num_triangles*3] = input_triangles[v3];
+ new_triangles[new_num_triangles*3+1] = input_triangles[v1];
+ new_triangles[new_num_triangles*3+2] = input_triangles[v2];
}
}
- else if (input_triangles[i*3+1] < input_triangles[i*3+2])
+ else if (input_triangles[v2] < input_triangles[v3])
{
// (1 < 0) && (1 < 2)
- new_triangles[new_num_triangles*3] = input_triangles[i*3+1];
- new_triangles[new_num_triangles*3+1] = input_triangles[i*3+2];
- new_triangles[new_num_triangles*3+2] = input_triangles[i*3];
+ new_triangles[new_num_triangles*3] = input_triangles[v2];
+ new_triangles[new_num_triangles*3+1] = input_triangles[v3];
+ new_triangles[new_num_triangles*3+2] = input_triangles[v1];
}
else
{
// (1 < 0) && (2 < 1)
- new_triangles[new_num_triangles*3] = input_triangles[i*3+2];
- new_triangles[new_num_triangles*3+1] = input_triangles[i*3];
- new_triangles[new_num_triangles*3+2] = input_triangles[i*3+1];
+ new_triangles[new_num_triangles*3] = input_triangles[v3];
+ new_triangles[new_num_triangles*3+1] = input_triangles[v1];
+ new_triangles[new_num_triangles*3+2] = input_triangles[v2];
}
new_num_triangles++;
}
@@ -3845,23 +3897,44 @@ void LLVolumeParams::reduceT(F32 begin, F32 end)
mPathParams.setEnd(a + end * (b - a));
}
+const F32 MIN_CONCAVE_PROFILE_WEDGE = 0.125f; // 1/8 unity
+const F32 MIN_CONCAVE_PATH_WEDGE = 0.111111f; // 1/9 unity
+
+// returns TRUE if the shape can be approximated with a convex shape
+// for collison purposes
BOOL LLVolumeParams::isConvex() const
{
- // The logic for determining convexity is a little convoluted.
+ F32 path_length = mPathParams.getEnd() - mPathParams.getBegin();
- // Do we need to take getTwistBegin into account? DK 08/12/04
- if ( mProfileParams.getHollow() != 0.0f
- || mPathParams.getTwist() != mPathParams.getTwistBegin() )
+ if ( mPathParams.getTwist() != mPathParams.getTwistBegin()
+ && path_length > MIN_CONCAVE_PATH_WEDGE )
{
- // hollow or twist gaurantees concavity
+ // twist along a "not too short" path is concave
return FALSE;
}
F32 profile_length = mProfileParams.getEnd() - mProfileParams.getBegin();
- BOOL concave_profile = (profile_length < 1.0f) && (profile_length > 0.5f);
- if (concave_profile)
+ F32 hollow = mProfileParams.getHollow();
+ BOOL same_hole = hollow == 0.f
+ || (mProfileParams.getCurveType() & LL_PCODE_HOLE_MASK) == LL_PCODE_HOLE_SAME;
+
+ F32 min_profile_wedge = MIN_CONCAVE_PROFILE_WEDGE;
+ U8 profile_type = mProfileParams.getCurveType() & LL_PCODE_PROFILE_MASK;
+ if ( LL_PCODE_PROFILE_CIRCLE_HALF == profile_type )
{
- // concave profile
+ // it is a sphere and spheres get twice the minimum profile wedge
+ min_profile_wedge = 2.f * MIN_CONCAVE_PROFILE_WEDGE;
+ }
+
+ BOOL convex_profile = ( ( profile_length == 1.f
+ || profile_length <= 0.5f )
+ && hollow == 0.f ) // trivially convex
+ || ( profile_length <= min_profile_wedge
+ && same_hole ); // effectvely convex (even when hollow)
+
+ if (!convex_profile)
+ {
+ // profile is concave
return FALSE;
}
@@ -3872,7 +3945,6 @@ BOOL LLVolumeParams::isConvex() const
return TRUE;
}
- F32 path_length = mPathParams.getEnd() - mPathParams.getBegin();
BOOL concave_path = (path_length < 1.0f) && (path_length > 0.5f);
if (concave_path)
{
@@ -3880,17 +3952,43 @@ BOOL LLVolumeParams::isConvex() const
}
// we're left with spheres, toroids and tubes
- // only the spheres can be convex
- U8 profile_type = mProfileParams.getCurveType() & LL_PCODE_PROFILE_MASK;
if ( LL_PCODE_PROFILE_CIRCLE_HALF == profile_type )
{
+ // at this stage all spheres must be convex
return TRUE;
}
// it's a toroid or tube
+ if ( path_length <= MIN_CONCAVE_PATH_WEDGE )
+ {
+ // effectively convex
+ return TRUE;
+ }
+
return FALSE;
}
+// debug
+void LLVolumeParams::setCube()
+{
+ mProfileParams.setCurveType(LL_PCODE_PROFILE_SQUARE);
+ mProfileParams.setBegin(0.f);
+ mProfileParams.setEnd(1.f);
+ mProfileParams.setHollow(0.f);
+
+ mPathParams.setBegin(0.f);
+ mPathParams.setEnd(1.f);
+ mPathParams.setScale(1.f, 1.f);
+ mPathParams.setShear(0.f, 0.f);
+ mPathParams.setCurveType(LL_PCODE_PATH_LINE);
+ mPathParams.setTwistBegin(0.f);
+ mPathParams.setTwistEnd(0.f);
+ mPathParams.setRadiusOffset(0.f);
+ mPathParams.setTaper(0.f, 0.f);
+ mPathParams.setRevolutions(0.f);
+ mPathParams.setSkew(0.f);
+}
+
LLFaceID LLVolume::generateFaceMask()
{
LLFaceID new_mask = 0x0000;
diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h
index 9af02d2629..a1eba9de38 100644
--- a/indra/llmath/llvolume.h
+++ b/indra/llmath/llvolume.h
@@ -72,6 +72,8 @@ const F32 TAPER_QUANTA = 0.01f;
const F32 REV_QUANTA = 0.015f;
const F32 HOLLOW_QUANTA = 0.00002f;
+const S32 MAX_VOLUME_TRIANGLE_INDICES = 10000;
+
//============================================================================
// useful masks
@@ -187,10 +189,10 @@ class LLProfileParams
public:
LLProfileParams()
{
- mBegin = 0;
- mEnd = 1;
- mHollow = 0;
mCurveType = LL_PCODE_PROFILE_SQUARE;
+ mBegin = 0.f;
+ mEnd = 1.f;
+ mHollow = 0.f;
}
LLProfileParams(U8 curve, F32 begin, F32 end, F32 hollow)
@@ -307,17 +309,17 @@ class LLPathParams
public:
LLPathParams()
{
- mBegin = 0;
- mEnd = 1;
- mScale.setVec(1,1);
- mShear.setVec(0,0);
+ mBegin = 0.f;
+ mEnd = 1.f;
+ mScale.setVec(1.f,1.f);
+ mShear.setVec(0.f,0.f);
mCurveType = LL_PCODE_PATH_LINE;
- mTwistBegin = 0;
- mTwistEnd = 0;
- mRadiusOffset = 0;
- mTaper.setVec(0,0);
- mRevolutions = 1;
- mSkew = 0;
+ mTwistBegin = 0.f;
+ mTwistEnd = 0.f;
+ mRadiusOffset = 0.f;
+ mTaper.setVec(0.f,0.f);
+ mRevolutions = 1.f;
+ mSkew = 0.f;
}
LLPathParams(U8 curve, F32 begin, F32 end, F32 scx, F32 scy, F32 shx, F32 shy, F32 twistend, F32 twistbegin, F32 radiusoffset, F32 tx, F32 ty, F32 revolutions, F32 skew)
@@ -627,6 +629,9 @@ public:
friend std::ostream& operator<<(std::ostream &s, const LLVolumeParams &volume_params);
+ // debug helper functions
+ void setCube();
+
protected:
LLProfileParams mProfileParams;
LLPathParams mPathParams;
@@ -869,6 +874,10 @@ public:
S32 getSculptLevel() const { return mSculptLevel; }
S32 *getTriangleIndices(U32 &num_indices) const;
+
+ // returns number of triangle indeces required for path/profile mesh
+ S32 getNumTriangleIndices() const;
+
void generateSilhouetteVertices(std::vector<LLVector3> &vertices, std::vector<LLVector3> &normals, std::vector<S32> &segments, const LLVector3& view_vec,
const LLMatrix4& mat,
const LLMatrix3& norm_mat);
diff --git a/indra/llmath/llvolumemgr.cpp b/indra/llmath/llvolumemgr.cpp
index 1a448ed8e0..f3a6b7d157 100644
--- a/indra/llmath/llvolumemgr.cpp
+++ b/indra/llmath/llvolumemgr.cpp
@@ -36,7 +36,7 @@
//#define DEBUG_VOLUME
-LLVolumeMgr* gVolumeMgr = 0;
+//LLVolumeMgr* gVolumeMgr = 0;
const F32 BASE_THRESHOLD = 0.03f;
@@ -49,37 +49,23 @@ F32 LLVolumeLODGroup::mDetailThresholds[NUM_LODS] = {BASE_THRESHOLD,
//static
F32 LLVolumeLODGroup::mDetailScales[NUM_LODS] = {1.f, 1.5f, 2.5f, 4.f};
-//============================================================================
-//static
-void LLVolumeMgr::initClass()
-{
- gVolumeMgr = new LLVolumeMgr();
-}
-
-//static
-BOOL LLVolumeMgr::cleanupClass()
-{
- BOOL res = FALSE;
- if (gVolumeMgr) {
- res = gVolumeMgr->cleanup();
- delete gVolumeMgr;
- gVolumeMgr = 0;
- }
- return res;
-}
//============================================================================
LLVolumeMgr::LLVolumeMgr()
+: mDataMutex(NULL)
{
- mDataMutex = new LLMutex(gAPRPoolp);
-// mNumVolumes = 0;
+ // the LLMutex magic interferes with easy unit testing,
+ // so you now must manually call useMutex() to use it
+ //mDataMutex = new LLMutex(gAPRPoolp);
}
LLVolumeMgr::~LLVolumeMgr()
{
cleanup();
+
delete mDataMutex;
+ mDataMutex = NULL;
}
BOOL LLVolumeMgr::cleanup()
@@ -90,7 +76,10 @@ BOOL LLVolumeMgr::cleanup()
}
#endif
BOOL no_refs = TRUE;
- mDataMutex->lock();
+ if (mDataMutex)
+ {
+ mDataMutex->lock();
+ }
for (volume_lod_group_map_t::iterator iter = mVolumeLODGroups.begin(),
end = mVolumeLODGroups.end();
iter != end; iter++)
@@ -106,29 +95,37 @@ BOOL LLVolumeMgr::cleanup()
volgroupp->unref();// this );
}
mVolumeLODGroups.clear();
- mDataMutex->unlock();
+ if (mDataMutex)
+ {
+ mDataMutex->unlock();
+ }
return no_refs;
}
+// whatever calls getVolume() never owns the LLVolume* and
+// cannot keep references for long since it may be deleted
+// later. For best results hold it in an LLPointer<LLVolume>.
LLVolume *LLVolumeMgr::getVolume(const LLVolumeParams &volume_params, const S32 detail)
{
LLVolumeLODGroup* volgroupp;
- mDataMutex->lock();
+ if (mDataMutex)
+ {
+ mDataMutex->lock();
+ }
volume_lod_group_map_t::iterator iter = mVolumeLODGroups.find(&volume_params);
if( iter == mVolumeLODGroups.end() )
{
- volgroupp = new LLVolumeLODGroup(volume_params);
- const LLVolumeParams* params = &(volgroupp->getParams());
- mVolumeLODGroups[params] = volgroupp;
- volgroupp->ref(); // initial reference
+ volgroupp = createNewGroup(volume_params);
}
else
{
volgroupp = iter->second;
}
- volgroupp->ref();// this );
- mDataMutex->unlock();
- // mNumVolumes++;
+ volgroupp->ref();
+ if (mDataMutex)
+ {
+ mDataMutex->unlock();
+ }
#ifdef DEBUG_VOLUME
{
lldebugs << "LLVolumeMgr::getVolume() " << (*this) << llendl;
@@ -137,6 +134,27 @@ LLVolume *LLVolumeMgr::getVolume(const LLVolumeParams &volume_params, const S32
return volgroupp->getLOD(detail);
}
+// virtual
+LLVolumeLODGroup* LLVolumeMgr::getGroup( const LLVolumeParams& volume_params ) const
+{
+ LLVolumeLODGroup* volgroupp = NULL;
+ if (mDataMutex)
+ {
+ mDataMutex->lock();
+ }
+ volume_lod_group_map_t::const_iterator iter = mVolumeLODGroups.find(&volume_params);
+ if( iter != mVolumeLODGroups.end() )
+ {
+ volgroupp = iter->second;
+ }
+ if (mDataMutex)
+ {
+ mDataMutex->unlock();
+ }
+ return volgroupp;
+}
+
+// virtual
void LLVolumeMgr::cleanupVolume(LLVolume *volumep)
{
if (volumep->isUnique())
@@ -145,12 +163,18 @@ void LLVolumeMgr::cleanupVolume(LLVolume *volumep)
return;
}
LLVolumeParams* params = (LLVolumeParams*) &(volumep->getParams());
- mDataMutex->lock();
+ if (mDataMutex)
+ {
+ mDataMutex->lock();
+ }
volume_lod_group_map_t::iterator iter = mVolumeLODGroups.find(params);
if( iter == mVolumeLODGroups.end() )
{
llerrs << "Warning! Tried to cleanup unknown volume type! " << *params << llendl;
- mDataMutex->unlock();
+ if (mDataMutex)
+ {
+ mDataMutex->unlock();
+ }
return;
}
else
@@ -164,9 +188,11 @@ void LLVolumeMgr::cleanupVolume(LLVolume *volumep)
mVolumeLODGroups.erase(params);
volgroupp->unref();// this );
}
- // mNumVolumes--;
}
- mDataMutex->unlock();
+ if (mDataMutex)
+ {
+ mDataMutex->unlock();
+ }
#ifdef DEBUG_VOLUME
{
@@ -175,10 +201,43 @@ void LLVolumeMgr::cleanupVolume(LLVolume *volumep)
#endif
}
+#ifdef DEBUG_VOLUME
+S32 LLVolumeMgr::getTotalRefCount() const
+{
+ S32 total_ref_count = 0;
+ for ( volume_lod_group_map_t::const_iterator iter = mVolumeLODGroups.begin(),
+ end = mVolumeLODGroups.end();
+ iter != end; iter++)
+ {
+ total_ref_count += iter->second->getTotalVolumeRefCount();
+ }
+ return total_ref_count;
+}
+
+S32 LLVolumeMgr::getGroupCount() const
+{
+ return mVolumeLODGroups.size();
+}
+#endif
+
+// protected
+LLVolumeLODGroup* LLVolumeMgr::createNewGroup(const LLVolumeParams& volume_params)
+{
+ LLVolumeLODGroup* group = new LLVolumeLODGroup(volume_params);
+ const LLVolumeParams* params = &(group->getParams());
+ mVolumeLODGroups[params] = group;
+ group->ref(); // initial reference
+ return group;
+}
+
+// virtual
void LLVolumeMgr::dump()
{
F32 avg = 0.f;
- mDataMutex->lock();
+ if (mDataMutex)
+ {
+ mDataMutex->lock();
+ }
for (volume_lod_group_map_t::iterator iter = mVolumeLODGroups.begin(),
end = mVolumeLODGroups.end();
iter != end; iter++)
@@ -188,16 +247,30 @@ void LLVolumeMgr::dump()
}
int count = (int)mVolumeLODGroups.size();
avg = count ? avg / (F32)count : 0.0f;
- mDataMutex->unlock();
+ if (mDataMutex)
+ {
+ mDataMutex->unlock();
+ }
llinfos << "Average usage of LODs " << avg << llendl;
}
+void LLVolumeMgr::useMutex()
+{
+ if (!mDataMutex)
+ {
+ mDataMutex = new LLMutex(gAPRPoolp);
+ }
+}
+
std::ostream& operator<<(std::ostream& s, const LLVolumeMgr& volume_mgr)
{
s << "{ numLODgroups=" << volume_mgr.mVolumeLODGroups.size() << ", ";
S32 total_refs = 0;
- volume_mgr.mDataMutex->lock();
+ if (volume_mgr.mDataMutex)
+ {
+ volume_mgr.mDataMutex->lock();
+ }
LLVolumeMgr::volume_lod_group_map_iter iter = volume_mgr.mVolumeLODGroups.begin();
LLVolumeMgr::volume_lod_group_map_iter end = volume_mgr.mVolumeLODGroups.end();
@@ -208,7 +281,10 @@ std::ostream& operator<<(std::ostream& s, const LLVolumeMgr& volume_mgr)
s << ", " << (*volgroupp);
}
- volume_mgr.mDataMutex->unlock();
+ if (volume_mgr.mDataMutex)
+ {
+ volume_mgr.mDataMutex->unlock();
+ }
s << ", total_refs=" << total_refs << " }";
return s;
@@ -222,15 +298,39 @@ LLVolumeLODGroup::LLVolumeLODGroup(const LLVolumeParams &params)
for (i = 0; i < NUM_LODS; i++)
{
mLODRefs[i] = 0;
- mVolumeLODs[i] = NULL;
+ // no need to initialize mVolumeLODs, they are smart pointers
+ //mVolumeLODs[i] = NULL;
mAccessCount[i] = 0;
}
}
+#ifdef DEBUG_VOLUME
+S32 LLVolumeLODGroup::getTotalVolumeRefCount() const
+{
+ S32 total_ref_count = 0;
+ for (S32 i = 0; i < NUM_LODS; i++)
+ {
+ total_ref_count += mLODRefs[i];
+ }
+ return total_ref_count;
+}
+#endif
+
+// protected
LLVolumeLODGroup::~LLVolumeLODGroup()
{
+ destroy();
}
+// protected
+void LLVolumeLODGroup::destroy()
+{
+ for (S32 i = 0; i < NUM_LODS; i++)
+ {
+ // remember that mVolumeLODs are smart pointers!
+ mVolumeLODs[i] = NULL;
+ }
+}
LLVolume * LLVolumeLODGroup::getLOD(const S32 detail)
{
@@ -242,7 +342,7 @@ LLVolume * LLVolumeLODGroup::getLOD(const S32 detail)
mVolumeLODs[detail] = new LLVolume(mParams, mDetailScales[detail]);
}
mLODRefs[detail]++;
- return mVolumeLODs[detail];
+ return mVolumeLODs[detail].get();
}
BOOL LLVolumeLODGroup::derefLOD(LLVolume *volumep)
diff --git a/indra/llmath/llvolumemgr.h b/indra/llmath/llvolumemgr.h
index f3d4b5ee6b..c28ffce631 100644
--- a/indra/llmath/llvolumemgr.h
+++ b/indra/llmath/llvolumemgr.h
@@ -43,9 +43,6 @@ class LLVolumeLODGroup;
class LLVolumeLODGroup : public LLThreadSafeRefCount
{
-protected:
- ~LLVolumeLODGroup();
-
public:
enum
{
@@ -60,11 +57,19 @@ public:
static F32 getVolumeScaleFromDetail(const S32 detail);
LLVolume *getLOD(const S32 detail);
- const LLVolumeParams &getParams() const { return mParams; };
+ const LLVolumeParams& getParams() const { return mParams; };
F32 dump();
friend std::ostream& operator<<(std::ostream& s, const LLVolumeLODGroup& volgroup);
+#ifdef DEBUG_VOLUME
+ S32 getTotalVolumeRefCount() const;
+#endif
+
+protected:
+ virtual ~LLVolumeLODGroup();
+ void destroy();
+
protected:
LLVolumeParams mParams;
@@ -77,30 +82,50 @@ protected:
class LLVolumeMgr
{
-public:
- static void initClass();
- static BOOL cleanupClass();
+//public:
+// static void initClass();
+// static BOOL cleanupClass();
public:
LLVolumeMgr();
- ~LLVolumeMgr();
+ virtual ~LLVolumeMgr();
BOOL cleanup(); // Cleanup all volumes being managed, returns TRUE if no dangling references
+
+ virtual LLVolumeLODGroup* getGroup( const LLVolumeParams& volume_params ) const;
+
+ // whatever calls getVolume() never owns the LLVolume* and
+ // cannot keep references for long since it may be deleted
+ // later. For best results hold it in an LLPointer<LLVolume>.
LLVolume *getVolume(const LLVolumeParams &volume_params, const S32 detail);
+
void cleanupVolume(LLVolume *volumep);
void dump();
+
+ // manually call this for mutex magic
+ void useMutex();
+
+#ifdef DEBUG_VOLUME
+ S32 getTotalRefCount() const;
+ S32 getGroupCount() const;
+#endif
friend std::ostream& operator<<(std::ostream& s, const LLVolumeMgr& volume_mgr);
protected:
+ virtual LLVolumeLODGroup* createNewGroup(const LLVolumeParams& volume_params);
+
+protected:
typedef std::map<const LLVolumeParams*, LLVolumeLODGroup*, LLVolumeParams::compare> volume_lod_group_map_t;
typedef volume_lod_group_map_t::const_iterator volume_lod_group_map_iter;
volume_lod_group_map_t mVolumeLODGroups;
LLMutex* mDataMutex;
-
-// S32 mNumVolumes;
+
+ // We need to be able to disable threadsafe checks to prevent
+ // some unit_tests from blocking on failure
+ bool mThreadSafe;
};
-extern LLVolumeMgr* gVolumeMgr;
+//extern LLVolumeMgr* gVolumeMgr;
#endif // LL_LLVOLUMEMGR_H
diff --git a/indra/llmath/m3math.cpp b/indra/llmath/m3math.cpp
index d4f99cb8c9..184b87c000 100644
--- a/indra/llmath/m3math.cpp
+++ b/indra/llmath/m3math.cpp
@@ -136,7 +136,7 @@ void LLMatrix3::getEulerAngles(F32 *roll, F32 *pitch, F32 *yaw) const
// Clear and Assignment Functions
-const LLMatrix3& LLMatrix3::identity()
+const LLMatrix3& LLMatrix3::setIdentity()
{
mMatrix[0][0] = 1.f;
mMatrix[0][1] = 0.f;
@@ -152,7 +152,23 @@ const LLMatrix3& LLMatrix3::identity()
return (*this);
}
-const LLMatrix3& LLMatrix3::zero()
+const LLMatrix3& LLMatrix3::clear()
+{
+ mMatrix[0][0] = 0.f;
+ mMatrix[0][1] = 0.f;
+ mMatrix[0][2] = 0.f;
+
+ mMatrix[1][0] = 0.f;
+ mMatrix[1][1] = 0.f;
+ mMatrix[1][2] = 0.f;
+
+ mMatrix[2][0] = 0.f;
+ mMatrix[2][1] = 0.f;
+ mMatrix[2][2] = 0.f;
+ return (*this);
+}
+
+const LLMatrix3& LLMatrix3::setZero()
{
mMatrix[0][0] = 0.f;
mMatrix[0][1] = 0.f;
@@ -190,15 +206,26 @@ F32 LLMatrix3::determinant() const
mMatrix[0][2] * (mMatrix[1][0] * mMatrix[2][1] - mMatrix[1][1] * mMatrix[2][0]);
}
-// This is identical to the transMat3() method because we assume a rotation matrix
-const LLMatrix3& LLMatrix3::invert()
+// inverts this matrix
+void LLMatrix3::invert()
{
- // transpose the matrix
- F32 temp;
- temp = mMatrix[VX][VY]; mMatrix[VX][VY] = mMatrix[VY][VX]; mMatrix[VY][VX] = temp;
- temp = mMatrix[VX][VZ]; mMatrix[VX][VZ] = mMatrix[VZ][VX]; mMatrix[VZ][VX] = temp;
- temp = mMatrix[VY][VZ]; mMatrix[VY][VZ] = mMatrix[VZ][VY]; mMatrix[VZ][VY] = temp;
- return *this;
+ // fails silently if determinant is zero too small
+ F32 det = determinant();
+ const F32 VERY_SMALL_DETERMINANT = 0.000001f;
+ if (fabs(det) > VERY_SMALL_DETERMINANT)
+ {
+ // invertiable
+ LLMatrix3 t(*this);
+ mMatrix[VX][VX] = ( t.mMatrix[VY][VY] * t.mMatrix[VZ][VZ] - t.mMatrix[VY][VZ] * t.mMatrix[VZ][VY] ) / det;
+ mMatrix[VY][VX] = ( t.mMatrix[VY][VZ] * t.mMatrix[VZ][VX] - t.mMatrix[VY][VX] * t.mMatrix[VZ][VZ] ) / det;
+ mMatrix[VZ][VX] = ( t.mMatrix[VY][VX] * t.mMatrix[VZ][VY] - t.mMatrix[VY][VY] * t.mMatrix[VZ][VX] ) / det;
+ mMatrix[VX][VY] = ( t.mMatrix[VZ][VY] * t.mMatrix[VX][VZ] - t.mMatrix[VZ][VZ] * t.mMatrix[VX][VY] ) / det;
+ mMatrix[VY][VY] = ( t.mMatrix[VZ][VZ] * t.mMatrix[VX][VX] - t.mMatrix[VZ][VX] * t.mMatrix[VX][VZ] ) / det;
+ mMatrix[VZ][VY] = ( t.mMatrix[VZ][VX] * t.mMatrix[VX][VY] - t.mMatrix[VZ][VY] * t.mMatrix[VX][VX] ) / det;
+ mMatrix[VX][VZ] = ( t.mMatrix[VX][VY] * t.mMatrix[VY][VZ] - t.mMatrix[VX][VZ] * t.mMatrix[VY][VY] ) / det;
+ mMatrix[VY][VZ] = ( t.mMatrix[VX][VZ] * t.mMatrix[VY][VX] - t.mMatrix[VX][VX] * t.mMatrix[VY][VZ] ) / det;
+ mMatrix[VZ][VZ] = ( t.mMatrix[VX][VX] * t.mMatrix[VY][VY] - t.mMatrix[VX][VY] * t.mMatrix[VY][VX] ) / det;
+ }
}
// does not assume a rotation matrix, and does not divide by determinant, assuming results will be renormalized
@@ -351,6 +378,27 @@ const LLMatrix3& LLMatrix3::setRows(const LLVector3 &fwd, const LLVector3 &left,
return *this;
}
+const LLMatrix3& LLMatrix3::setRow( U32 rowIndex, const LLVector3& row )
+{
+ llassert( rowIndex >= 0 && rowIndex < NUM_VALUES_IN_MAT3 );
+
+ mMatrix[rowIndex][0] = row[0];
+ mMatrix[rowIndex][1] = row[1];
+ mMatrix[rowIndex][2] = row[2];
+
+ return *this;
+}
+
+const LLMatrix3& LLMatrix3::setCol( U32 colIndex, const LLVector3& col )
+{
+ llassert( colIndex >= 0 && colIndex < NUM_VALUES_IN_MAT3 );
+
+ mMatrix[0][colIndex] = col[0];
+ mMatrix[1][colIndex] = col[1];
+ mMatrix[2][colIndex] = col[2];
+
+ return *this;
+}
// Rotate exisitng mMatrix
const LLMatrix3& LLMatrix3::rotate(const F32 angle, const F32 x, const F32 y, const F32 z)
@@ -384,6 +432,16 @@ const LLMatrix3& LLMatrix3::rotate(const LLQuaternion &q)
return *this;
}
+void LLMatrix3::add(const LLMatrix3& other_matrix)
+{
+ for (S32 i = 0; i < 3; ++i)
+ {
+ for (S32 j = 0; j < 3; ++j)
+ {
+ mMatrix[i][j] += other_matrix.mMatrix[i][j];
+ }
+ }
+}
LLVector3 LLMatrix3::getFwdRow() const
{
@@ -536,6 +594,19 @@ const LLMatrix3& operator*=(LLMatrix3 &a, const LLMatrix3 &b)
return a;
}
+const LLMatrix3& operator*=(LLMatrix3 &a, F32 scalar )
+{
+ for( U32 i = 0; i < NUM_VALUES_IN_MAT3; ++i )
+ {
+ for( U32 j = 0; j < NUM_VALUES_IN_MAT3; ++j )
+ {
+ a.mMatrix[i][j] *= scalar;
+ }
+ }
+
+ return a;
+}
+
std::ostream& operator<<(std::ostream& s, const LLMatrix3 &a)
{
s << "{ "
diff --git a/indra/llmath/m3math.h b/indra/llmath/m3math.h
index d2848aaf5a..5f37456f51 100644
--- a/indra/llmath/m3math.h
+++ b/indra/llmath/m3math.h
@@ -33,6 +33,7 @@
#define LL_M3MATH_H
#include "llerror.h"
+#include "stdtypes.h"
class LLVector4;
class LLVector3;
@@ -76,8 +77,9 @@ class LLMatrix3
//
// various useful matrix functions
- const LLMatrix3& identity(); // Load identity matrix
- const LLMatrix3& zero(); // Clears Matrix to zero
+ const LLMatrix3& setIdentity(); // Load identity matrix
+ const LLMatrix3& clear(); // Clears Matrix to zero
+ const LLMatrix3& setZero(); // Clears Matrix to zero
///////////////////////////
//
@@ -91,6 +93,9 @@ class LLMatrix3
const LLMatrix3& setRot(const LLQuaternion &q); // Transform matrix by Euler angles and translating by pos
const LLMatrix3& setRows(const LLVector3 &x_axis, const LLVector3 &y_axis, const LLVector3 &z_axis);
+ const LLMatrix3& setRow( U32 rowIndex, const LLVector3& row );
+ const LLMatrix3& setCol( U32 colIndex, const LLVector3& col );
+
///////////////////////////
//
@@ -103,29 +108,31 @@ class LLMatrix3
LLVector3 getFwdRow() const;
LLVector3 getLeftRow() const;
LLVector3 getUpRow() const;
- F32 determinant() const; // Return determinant
+ F32 determinant() const; // Return determinant
///////////////////////////
//
// Operations on an existing matrix
//
- const LLMatrix3& transpose(); // Transpose MAT4
- const LLMatrix3& invert(); // Invert MAT4
- const LLMatrix3& orthogonalize(); // Orthogonalizes X, then Y, then Z
- const LLMatrix3& adjointTranspose(); // returns transpose of matrix adjoint, for multiplying normals
+ const LLMatrix3& transpose(); // Transpose MAT4
+ const LLMatrix3& orthogonalize(); // Orthogonalizes X, then Y, then Z
+ void invert(); // Invert MAT4
+ const LLMatrix3& adjointTranspose();// returns transpose of matrix adjoint, for multiplying normals
// Rotate existing matrix
// Note: the two lines below are equivalent:
// foo.rotate(bar)
// foo = foo * bar
- // That is, foo.rotMat3(bar) multiplies foo by bar FROM THE RIGHT
+ // That is, foo.rotate(bar) multiplies foo by bar FROM THE RIGHT
const LLMatrix3& rotate(const F32 angle, const F32 x, const F32 y, const F32 z); // Rotate matrix by rotating angle radians about (x, y, z)
const LLMatrix3& rotate(const F32 angle, const LLVector3 &vec); // Rotate matrix by rotating angle radians about vec
const LLMatrix3& rotate(const F32 roll, const F32 pitch, const F32 yaw); // Rotate matrix by roll (about x), pitch (about y), and yaw (about z)
const LLMatrix3& rotate(const LLQuaternion &q); // Transform matrix by Euler angles and translating by pos
+ void add(const LLMatrix3& other_matrix); // add other_matrix to this one
+
// This operator is misleading as to operation direction
// friend LLVector3 operator*(const LLMatrix3 &a, const LLVector3 &b); // Apply rotation a to vector b
@@ -137,6 +144,7 @@ class LLMatrix3
friend bool operator!=(const LLMatrix3 &a, const LLMatrix3 &b); // Return a != b
friend const LLMatrix3& operator*=(LLMatrix3 &a, const LLMatrix3 &b); // Return a * b
+ friend const LLMatrix3& operator*=(LLMatrix3 &a, F32 scalar ); // Return a * scalar
friend std::ostream& operator<<(std::ostream& s, const LLMatrix3 &a); // Stream a
};
diff --git a/indra/llmath/m4math.cpp b/indra/llmath/m4math.cpp
index 4e7cf847dc..836b3178d5 100644
--- a/indra/llmath/m4math.cpp
+++ b/indra/llmath/m4math.cpp
@@ -163,7 +163,7 @@ LLMatrix4::~LLMatrix4(void)
// Clear and Assignment Functions
-const LLMatrix4& LLMatrix4::zero()
+const LLMatrix4& LLMatrix4::setZero()
{
mMatrix[0][0] = 0.f;
mMatrix[0][1] = 0.f;
diff --git a/indra/llmath/m4math.h b/indra/llmath/m4math.h
index 4958777b29..7eacbf6542 100644
--- a/indra/llmath/m4math.h
+++ b/indra/llmath/m4math.h
@@ -132,8 +132,8 @@ public:
const LLVector4 &row3);
// various useful matrix functions
- const LLMatrix4& identity(); // Load identity matrix
- const LLMatrix4& zero(); // Clears matrix to all zeros.
+ const LLMatrix4& setIdentity(); // Load identity matrix
+ const LLMatrix4& setZero(); // Clears matrix to all zeros.
const LLMatrix4& initRotation(const F32 angle, const F32 x, const F32 y, const F32 z); // Calculate rotation matrix by rotating angle radians about (x, y, z)
const LLMatrix4& initRotation(const F32 angle, const LLVector4 &axis); // Calculate rotation matrix for rotating angle radians about vec
@@ -243,10 +243,10 @@ public:
inline LLMatrix4::LLMatrix4()
{
- identity();
+ setIdentity();
}
-inline const LLMatrix4& LLMatrix4::identity()
+inline const LLMatrix4& LLMatrix4::setIdentity()
{
mMatrix[0][0] = 1.f;
mMatrix[0][1] = 0.f;
diff --git a/indra/llmath/v2math.h b/indra/llmath/v2math.h
index f2450b1fd3..5f46655a07 100644
--- a/indra/llmath/v2math.h
+++ b/indra/llmath/v2math.h
@@ -54,18 +54,26 @@ class LLVector2
LLVector2(const F32 *vec); // Initializes LLVector2 to (vec[0]. vec[1])
// Clears LLVector2 to (0, 0). DEPRECATED - prefer zeroVec.
- void clearVec();
+ void clear();
+ void setZero();
+ void clearVec(); // deprecated
+ void zeroVec(); // deprecated
- // Zero LLVector2 to (0, 0)
- void zeroVec();
+ void set(F32 x, F32 y); // Sets LLVector2 to (x, y)
+ void set(const LLVector2 &vec); // Sets LLVector2 to vec
+ void set(const F32 *vec); // Sets LLVector2 to vec
- void setVec(F32 x, F32 y); // Sets LLVector2 to (x, y)
- void setVec(const LLVector2 &vec); // Sets LLVector2 to vec
- void setVec(const F32 *vec); // Sets LLVector2 to vec
+ void setVec(F32 x, F32 y); // deprecated
+ void setVec(const LLVector2 &vec); // deprecated
+ void setVec(const F32 *vec); // deprecated
- F32 magVec() const; // Returns magnitude of LLVector2
- F32 magVecSquared() const; // Returns magnitude squared of LLVector2
- F32 normVec(); // Normalizes and returns the magnitude of LLVector2
+ F32 length() const; // Returns magnitude of LLVector2
+ F32 lengthSquared() const; // Returns magnitude squared of LLVector2
+ F32 normalize(); // Normalizes and returns the magnitude of LLVector2
+
+ F32 magVec() const; // deprecated
+ F32 magVecSquared() const; // deprecated
+ F32 normVec(); // deprecated
BOOL abs(); // sets all values to absolute value of original value (first octant), returns TRUE if changed
@@ -132,30 +140,66 @@ inline LLVector2::LLVector2(const F32 *vec)
// Clear and Assignment Functions
+inline void LLVector2::clear(void)
+{
+ mV[VX] = 0.f;
+ mV[VY] = 0.f;
+}
+
+inline void LLVector2::setZero(void)
+{
+ mV[VX] = 0.f;
+ mV[VY] = 0.f;
+}
+
+// deprecated
inline void LLVector2::clearVec(void)
{
mV[VX] = 0.f;
mV[VY] = 0.f;
}
+// deprecated
inline void LLVector2::zeroVec(void)
{
mV[VX] = 0.f;
mV[VY] = 0.f;
}
+inline void LLVector2::set(F32 x, F32 y)
+{
+ mV[VX] = x;
+ mV[VY] = y;
+}
+
+inline void LLVector2::set(const LLVector2 &vec)
+{
+ mV[VX] = vec.mV[VX];
+ mV[VY] = vec.mV[VY];
+}
+
+inline void LLVector2::set(const F32 *vec)
+{
+ mV[VX] = vec[VX];
+ mV[VY] = vec[VY];
+}
+
+
+// deprecated
inline void LLVector2::setVec(F32 x, F32 y)
{
mV[VX] = x;
mV[VY] = y;
}
+// deprecated
inline void LLVector2::setVec(const LLVector2 &vec)
{
mV[VX] = vec.mV[VX];
mV[VY] = vec.mV[VY];
}
+// deprecated
inline void LLVector2::setVec(const F32 *vec)
{
mV[VX] = vec[VX];
@@ -164,16 +208,49 @@ inline void LLVector2::setVec(const F32 *vec)
// LLVector2 Magnitude and Normalization Functions
+inline F32 LLVector2::length(void) const
+{
+ return fsqrtf(mV[0]*mV[0] + mV[1]*mV[1]);
+}
+
+inline F32 LLVector2::lengthSquared(void) const
+{
+ return mV[0]*mV[0] + mV[1]*mV[1];
+}
+
+inline F32 LLVector2::normalize(void)
+{
+ F32 mag = fsqrtf(mV[0]*mV[0] + mV[1]*mV[1]);
+ F32 oomag;
+
+ if (mag > FP_MAG_THRESHOLD)
+ {
+ oomag = 1.f/mag;
+ mV[0] *= oomag;
+ mV[1] *= oomag;
+ }
+ else
+ {
+ mV[0] = 0.f;
+ mV[1] = 0.f;
+ mag = 0;
+ }
+ return (mag);
+}
+
+// deprecated
inline F32 LLVector2::magVec(void) const
{
return fsqrtf(mV[0]*mV[0] + mV[1]*mV[1]);
}
+// deprecated
inline F32 LLVector2::magVecSquared(void) const
{
return mV[0]*mV[0] + mV[1]*mV[1];
}
+// deprecated
inline F32 LLVector2::normVec(void)
{
F32 mag = fsqrtf(mV[0]*mV[0] + mV[1]*mV[1]);
diff --git a/indra/llmath/v3dmath.h b/indra/llmath/v3dmath.h
index ac3f06c453..667c335f51 100644
--- a/indra/llmath/v3dmath.h
+++ b/indra/llmath/v3dmath.h
@@ -83,8 +83,9 @@ class LLVector3d
BOOL clamp(const F64 min, const F64 max); // Clamps all values to (min,max), returns TRUE if data changed
BOOL abs(); // sets all values to absolute value of original value (first octant), returns TRUE if changed
- inline const LLVector3d& clearVec(); // Clears LLVector3d to (0, 0, 0, 1)
- inline const LLVector3d& zeroVec(); // Zero LLVector3d to (0, 0, 0, 0)
+ inline const LLVector3d& clearVec(); // Clears LLVector3d to (0, 0, 0, 1)
+ inline const LLVector3d& setZero(); // Zero LLVector3d to (0, 0, 0, 0)
+ inline const LLVector3d& zeroVec(); // deprecated
inline const LLVector3d& setVec(const F64 x, const F64 y, const F64 z); // Sets LLVector3d to (x, y, z, 1)
inline const LLVector3d& setVec(const LLVector3d &vec); // Sets LLVector3d to vec
inline const LLVector3d& setVec(const F64 *vec); // Sets LLVector3d to vec
@@ -198,6 +199,14 @@ inline const LLVector3d& LLVector3d::clearVec(void)
return (*this);
}
+inline const LLVector3d& LLVector3d::setZero(void)
+{
+ mdV[0] = 0.f;
+ mdV[1] = 0.f;
+ mdV[2] = 0.f;
+ return (*this);
+}
+
inline const LLVector3d& LLVector3d::zeroVec(void)
{
mdV[0] = 0.f;
diff --git a/indra/llmath/v3math.cpp b/indra/llmath/v3math.cpp
index 5ffd1dd428..f1fe1a780e 100644
--- a/indra/llmath/v3math.cpp
+++ b/indra/llmath/v3math.cpp
@@ -172,6 +172,22 @@ LLVector3 LLVector3::scaledVec(const LLVector3& vec) const
return ret;
}
+const LLVector3& LLVector3::set(const LLVector3d &vec)
+{
+ mV[0] = (F32)vec.mdV[0];
+ mV[1] = (F32)vec.mdV[1];
+ mV[2] = (F32)vec.mdV[2];
+ return (*this);
+}
+
+const LLVector3& LLVector3::set(const LLVector4 &vec)
+{
+ mV[0] = vec.mV[0];
+ mV[1] = vec.mV[1];
+ mV[2] = vec.mV[2];
+ return (*this);
+}
+
const LLVector3& LLVector3::setVec(const LLVector3d &vec)
{
mV[0] = (F32)vec.mdV[0];
diff --git a/indra/llmath/v3math.h b/indra/llmath/v3math.h
index e18b20ddd0..03c780a1f4 100644
--- a/indra/llmath/v3math.h
+++ b/indra/llmath/v3math.h
@@ -81,18 +81,33 @@ class LLVector3
BOOL abs(); // sets all values to absolute value of original value (first octant), returns TRUE if changed
- inline void clearVec(); // Clears LLVector3 to (0, 0, 0, 1)
- inline void zeroVec(); // Zero LLVector3 to (0, 0, 0, 0)
- inline void setVec(F32 x, F32 y, F32 z); // Sets LLVector3 to (x, y, z, 1)
- inline void setVec(const LLVector3 &vec); // Sets LLVector3 to vec
- inline void setVec(const F32 *vec); // Sets LLVector3 to vec
+ inline void clear(); // Clears LLVector3 to (0, 0, 0)
+ inline void setZero(); // Clears LLVector3 to (0, 0, 0)
+ inline void clearVec(); // deprecated
+ inline void zeroVec(); // deprecated
- const LLVector3& setVec(const LLVector4 &vec);
- const LLVector3& setVec(const LLVector3d &vec); // Sets LLVector3 to vec
+ inline void set(F32 x, F32 y, F32 z); // Sets LLVector3 to (x, y, z, 1)
+ inline void set(const LLVector3 &vec); // Sets LLVector3 to vec
+ inline void set(const F32 *vec); // Sets LLVector3 to vec
+ const LLVector3& set(const LLVector4 &vec);
+ const LLVector3& set(const LLVector3d &vec);// Sets LLVector3 to vec
- F32 magVec() const; // Returns magnitude of LLVector3
- F32 magVecSquared() const; // Returns magnitude squared of LLVector3
- inline F32 normVec(); // Normalizes and returns the magnitude of LLVector3
+ inline void setVec(F32 x, F32 y, F32 z); // deprecated
+ inline void setVec(const LLVector3 &vec); // deprecated
+ inline void setVec(const F32 *vec); // deprecated
+
+ 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
+
+ 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
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
@@ -188,6 +203,20 @@ inline BOOL LLVector3::isFinite() const
// Clear and Assignment Functions
+inline void LLVector3::clear(void)
+{
+ mV[0] = 0.f;
+ mV[1] = 0.f;
+ mV[2] = 0.f;
+}
+
+inline void LLVector3::setZero(void)
+{
+ mV[0] = 0.f;
+ mV[1] = 0.f;
+ mV[2] = 0.f;
+}
+
inline void LLVector3::clearVec(void)
{
mV[0] = 0.f;
@@ -202,6 +231,28 @@ inline void LLVector3::zeroVec(void)
mV[2] = 0.f;
}
+inline void LLVector3::set(F32 x, F32 y, F32 z)
+{
+ mV[VX] = x;
+ mV[VY] = y;
+ mV[VZ] = z;
+}
+
+inline void LLVector3::set(const LLVector3 &vec)
+{
+ mV[0] = vec.mV[0];
+ mV[1] = vec.mV[1];
+ mV[2] = vec.mV[2];
+}
+
+inline void LLVector3::set(const F32 *vec)
+{
+ mV[0] = vec[0];
+ mV[1] = vec[1];
+ mV[2] = vec[2];
+}
+
+// deprecated
inline void LLVector3::setVec(F32 x, F32 y, F32 z)
{
mV[VX] = x;
@@ -209,6 +260,7 @@ inline void LLVector3::setVec(F32 x, F32 y, F32 z)
mV[VZ] = z;
}
+// deprecated
inline void LLVector3::setVec(const LLVector3 &vec)
{
mV[0] = vec.mV[0];
@@ -216,6 +268,7 @@ inline void LLVector3::setVec(const LLVector3 &vec)
mV[2] = vec.mV[2];
}
+// deprecated
inline void LLVector3::setVec(const F32 *vec)
{
mV[0] = vec[0];
@@ -223,6 +276,29 @@ inline void LLVector3::setVec(const F32 *vec)
mV[2] = vec[2];
}
+inline F32 LLVector3::normalize(void)
+{
+ F32 mag = fsqrtf(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]);
+ F32 oomag;
+
+ if (mag > FP_MAG_THRESHOLD)
+ {
+ oomag = 1.f/mag;
+ mV[0] *= oomag;
+ mV[1] *= oomag;
+ mV[2] *= oomag;
+ }
+ else
+ {
+ mV[0] = 0.f;
+ mV[1] = 0.f;
+ mV[2] = 0.f;
+ mag = 0;
+ }
+ return (mag);
+}
+
+// deprecated
inline F32 LLVector3::normVec(void)
{
F32 mag = fsqrtf(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]);
@@ -247,6 +323,16 @@ inline F32 LLVector3::normVec(void)
// LLVector3 Magnitude and Normalization Functions
+inline F32 LLVector3::length(void) const
+{
+ return fsqrtf(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]);
+}
+
+inline F32 LLVector3::lengthSquared(void) const
+{
+ return mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2];
+}
+
inline F32 LLVector3::magVec(void) const
{
return fsqrtf(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]);
@@ -257,6 +343,13 @@ inline F32 LLVector3::magVecSquared(void) const
return mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2];
}
+inline BOOL LLVector3::inRange( F32 min, F32 max ) const
+{
+ return mV[0] >= min && mV[0] <= max &&
+ mV[1] >= min && mV[1] <= max &&
+ mV[2] >= min && mV[2] <= max;
+}
+
inline LLVector3 operator+(const LLVector3 &a, const LLVector3 &b)
{
LLVector3 c(a);
@@ -397,7 +490,7 @@ inline F32 dist_vec_squared2D(const LLVector3 &a, const LLVector3 &b)
inline LLVector3 projected_vec(const LLVector3 &a, const LLVector3 &b)
{
LLVector3 project_axis = b;
- project_axis.normVec();
+ project_axis.normalize();
return project_axis * (a * project_axis);
}
@@ -438,8 +531,8 @@ inline F32 angle_between(const LLVector3& a, const LLVector3& b)
{
LLVector3 an = a;
LLVector3 bn = b;
- an.normVec();
- bn.normVec();
+ an.normalize();
+ bn.normalize();
F32 cosine = an * bn;
F32 angle = (cosine >= 1.0f) ? 0.0f :
(cosine <= -1.0f) ? F_PI :
@@ -451,8 +544,8 @@ inline BOOL are_parallel(const LLVector3 &a, const LLVector3 &b, F32 epsilon)
{
LLVector3 an = a;
LLVector3 bn = b;
- an.normVec();
- bn.normVec();
+ an.normalize();
+ bn.normalize();
F32 dot = an * bn;
if ( (1.0f - fabs(dot)) < epsilon)
{
diff --git a/indra/llmath/v4math.cpp b/indra/llmath/v4math.cpp
index b753778ba1..9da4b501d6 100644
--- a/indra/llmath/v4math.cpp
+++ b/indra/llmath/v4math.cpp
@@ -113,8 +113,8 @@ F32 angle_between( const LLVector4& a, const LLVector4& b )
{
LLVector4 an = a;
LLVector4 bn = b;
- an.normVec();
- bn.normVec();
+ an.normalize();
+ bn.normalize();
F32 cosine = an * bn;
F32 angle = (cosine >= 1.0f) ? 0.0f :
(cosine <= -1.0f) ? F_PI :
@@ -126,8 +126,8 @@ BOOL are_parallel(const LLVector4 &a, const LLVector4 &b, F32 epsilon)
{
LLVector4 an = a;
LLVector4 bn = b;
- an.normVec();
- bn.normVec();
+ an.normalize();
+ bn.normalize();
F32 dot = an * bn;
if ( (1.0f - fabs(dot)) < epsilon)
return TRUE;
diff --git a/indra/llmath/v4math.h b/indra/llmath/v4math.h
index 34b5f9e33c..9f71d3452a 100644
--- a/indra/llmath/v4math.h
+++ b/indra/llmath/v4math.h
@@ -68,17 +68,29 @@ class LLVector4
inline BOOL isFinite() const; // checks to see if all values of LLVector3 are finite
- inline void clearVec(); // Clears LLVector4 to (0, 0, 0, 1)
- inline void zeroVec(); // zero LLVector4 to (0, 0, 0, 0)
- inline void setVec(F32 x, F32 y, F32 z); // Sets LLVector4 to (x, y, z, 1)
- inline void setVec(F32 x, F32 y, F32 z, F32 w); // Sets LLVector4 to (x, y, z, w)
- inline void setVec(const LLVector4 &vec); // Sets LLVector4 to vec
- inline void setVec(const LLVector3 &vec, F32 w = 1.f); // Sets LLVector4 to LLVector3 vec
- inline void setVec(const F32 *vec); // Sets LLVector4 to vec
-
- F32 magVec() const; // Returns magnitude of LLVector4
- F32 magVecSquared() const; // Returns magnitude squared of LLVector4
- F32 normVec(); // Normalizes and returns the magnitude of LLVector4
+ inline void clear(); // Clears LLVector4 to (0, 0, 0, 1)
+ inline void clearVec(); // deprecated
+ inline void zeroVec(); // deprecated
+
+ inline void set(F32 x, F32 y, F32 z); // Sets LLVector4 to (x, y, z, 1)
+ inline void set(F32 x, F32 y, F32 z, F32 w); // Sets LLVector4 to (x, y, z, w)
+ inline void set(const LLVector4 &vec); // Sets LLVector4 to vec
+ inline void set(const LLVector3 &vec, F32 w = 1.f); // Sets LLVector4 to LLVector3 vec
+ inline void set(const F32 *vec); // Sets LLVector4 to vec
+
+ inline void setVec(F32 x, F32 y, F32 z); // deprecated
+ inline void setVec(F32 x, F32 y, F32 z, F32 w); // deprecated
+ inline void setVec(const LLVector4 &vec); // deprecated
+ inline void setVec(const LLVector3 &vec, F32 w = 1.f); // deprecated
+ inline void setVec(const F32 *vec); // deprecated
+
+ F32 length() const; // Returns magnitude of LLVector4
+ 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
// Sets all values to absolute value of their original values
// Returns TRUE if data changed
@@ -192,6 +204,15 @@ inline BOOL LLVector4::isFinite() const
// Clear and Assignment Functions
+inline void LLVector4::clear(void)
+{
+ mV[VX] = 0.f;
+ mV[VY] = 0.f;
+ mV[VZ] = 0.f;
+ mV[VW] = 1.f;
+}
+
+// deprecated
inline void LLVector4::clearVec(void)
{
mV[VX] = 0.f;
@@ -200,6 +221,7 @@ inline void LLVector4::clearVec(void)
mV[VW] = 1.f;
}
+// deprecated
inline void LLVector4::zeroVec(void)
{
mV[VX] = 0.f;
@@ -208,6 +230,48 @@ inline void LLVector4::zeroVec(void)
mV[VW] = 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;
+}
+
+inline void LLVector4::set(F32 x, F32 y, F32 z, F32 w)
+{
+ mV[VX] = x;
+ mV[VY] = y;
+ mV[VZ] = z;
+ mV[VW] = 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];
+}
+
+inline void LLVector4::set(const LLVector3 &vec, F32 w)
+{
+ mV[VX] = vec.mV[VX];
+ mV[VY] = vec.mV[VY];
+ mV[VZ] = vec.mV[VZ];
+ mV[VW] = w;
+}
+
+inline void LLVector4::set(const F32 *vec)
+{
+ mV[VX] = vec[VX];
+ mV[VY] = vec[VY];
+ mV[VZ] = vec[VZ];
+ mV[VW] = vec[VW];
+}
+
+
+// deprecated
inline void LLVector4::setVec(F32 x, F32 y, F32 z)
{
mV[VX] = x;
@@ -216,6 +280,7 @@ inline void LLVector4::setVec(F32 x, F32 y, F32 z)
mV[VW] = 1.f;
}
+// deprecated
inline void LLVector4::setVec(F32 x, F32 y, F32 z, F32 w)
{
mV[VX] = x;
@@ -224,6 +289,7 @@ inline void LLVector4::setVec(F32 x, F32 y, F32 z, F32 w)
mV[VW] = w;
}
+// deprecated
inline void LLVector4::setVec(const LLVector4 &vec)
{
mV[VX] = vec.mV[VX];
@@ -232,6 +298,7 @@ inline void LLVector4::setVec(const LLVector4 &vec)
mV[VW] = vec.mV[VW];
}
+// deprecated
inline void LLVector4::setVec(const LLVector3 &vec, F32 w)
{
mV[VX] = vec.mV[VX];
@@ -240,6 +307,7 @@ inline void LLVector4::setVec(const LLVector3 &vec, F32 w)
mV[VW] = w;
}
+// deprecated
inline void LLVector4::setVec(const F32 *vec)
{
mV[VX] = vec[VX];
@@ -250,6 +318,16 @@ inline void LLVector4::setVec(const F32 *vec)
// LLVector4 Magnitude and Normalization Functions
+inline F32 LLVector4::length(void) const
+{
+ return fsqrtf(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]);
+}
+
+inline F32 LLVector4::lengthSquared(void) const
+{
+ return mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ];
+}
+
inline F32 LLVector4::magVec(void) const
{
return fsqrtf(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]);
@@ -364,13 +442,13 @@ inline LLVector4 operator-(const LLVector4 &a)
inline F32 dist_vec(const LLVector4 &a, const LLVector4 &b)
{
LLVector4 vec = a - b;
- return (vec.magVec());
+ return (vec.length());
}
inline F32 dist_vec_squared(const LLVector4 &a, const LLVector4 &b)
{
LLVector4 vec = a - b;
- return (vec.magVecSquared());
+ return (vec.lengthSquared());
}
inline LLVector4 lerp(const LLVector4 &a, const LLVector4 &b, F32 u)
@@ -382,6 +460,29 @@ 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(void)
+{
+ F32 mag = fsqrtf(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[0] = 0.f;
+ mV[1] = 0.f;
+ mV[2] = 0.f;
+ mag = 0;
+ }
+ return (mag);
+}
+
+// deprecated
inline F32 LLVector4::normVec(void)
{
F32 mag = fsqrtf(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]);
diff --git a/indra/llmath/xform.h b/indra/llmath/xform.h
index 9a5c99140e..feca790820 100644
--- a/indra/llmath/xform.h
+++ b/indra/llmath/xform.h
@@ -35,10 +35,12 @@
#include "m4math.h"
#include "llquaternion.h"
-const F32 MAX_OBJECT_Z = 768.f;
+const F32 MAX_OBJECT_Z = 4096.f; // should match REGION_HEIGHT_METERS, Pre-havok4: 768.f
const F32 MIN_OBJECT_Z = -256.f;
-const F32 MIN_OBJECT_SCALE = 0.01f;
-const F32 MAX_OBJECT_SCALE = 10.f;
+const F32 DEFAULT_MAX_PRIM_SCALE = 10.f;
+const F32 MIN_PRIM_SCALE = 0.01f;
+const F32 MAX_PRIM_SCALE = 65536.f; // something very high but not near FLT_MAX
+
class LLXform
{
@@ -138,7 +140,7 @@ public:
void init()
{
- mWorldMatrix.identity();
+ mWorldMatrix.setIdentity();
mMin.clearVec();
mMax.clearVec();