aboutsummaryrefslogtreecommitdiff
path: root/mp/src/public/mathlib/vector.h
diff options
context:
space:
mode:
authorJoe Ludwig <[email protected]>2013-06-26 15:22:04 -0700
committerJoe Ludwig <[email protected]>2013-06-26 15:22:04 -0700
commit39ed87570bdb2f86969d4be821c94b722dc71179 (patch)
treeabc53757f75f40c80278e87650ea92808274aa59 /mp/src/public/mathlib/vector.h
downloadsource-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.tar.xz
source-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.zip
First version of the SOurce SDK 2013
Diffstat (limited to 'mp/src/public/mathlib/vector.h')
-rw-r--r--mp/src/public/mathlib/vector.h2312
1 files changed, 2312 insertions, 0 deletions
diff --git a/mp/src/public/mathlib/vector.h b/mp/src/public/mathlib/vector.h
new file mode 100644
index 00000000..4b361640
--- /dev/null
+++ b/mp/src/public/mathlib/vector.h
@@ -0,0 +1,2312 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+
+#ifndef VECTOR_H
+#define VECTOR_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <math.h>
+#include <float.h>
+
+// For vec_t, put this somewhere else?
+#include "tier0/basetypes.h"
+
+// For rand(). We really need a library!
+#include <stdlib.h>
+
+#ifndef _X360
+// For MMX intrinsics
+#include <xmmintrin.h>
+#endif
+
+#include "tier0/dbg.h"
+#include "tier0/threadtools.h"
+#include "mathlib/vector2d.h"
+#include "mathlib/math_pfns.h"
+#include "minmax.h"
+
+// Uncomment this to add extra Asserts to check for NANs, uninitialized vecs, etc.
+//#define VECTOR_PARANOIA 1
+
+// Uncomment this to make sure we don't do anything slow with our vectors
+//#define VECTOR_NO_SLOW_OPERATIONS 1
+
+
+// Used to make certain code easier to read.
+#define X_INDEX 0
+#define Y_INDEX 1
+#define Z_INDEX 2
+
+
+#ifdef VECTOR_PARANOIA
+#define CHECK_VALID( _v) Assert( (_v).IsValid() )
+#else
+#ifdef GNUC
+#define CHECK_VALID( _v)
+#else
+#define CHECK_VALID( _v) 0
+#endif
+#endif
+
+#define VecToString(v) (static_cast<const char *>(CFmtStr("(%f, %f, %f)", (v).x, (v).y, (v).z))) // ** Note: this generates a temporary, don't hold reference!
+
+class VectorByValue;
+
+//=========================================================
+// 3D Vector
+//=========================================================
+class Vector
+{
+public:
+ // Members
+ vec_t x, y, z;
+
+ // Construction/destruction:
+ Vector(void);
+ Vector(vec_t X, vec_t Y, vec_t Z);
+ explicit Vector(vec_t XYZ); ///< broadcast initialize
+
+ // Initialization
+ void Init(vec_t ix=0.0f, vec_t iy=0.0f, vec_t iz=0.0f);
+ // TODO (Ilya): Should there be an init that takes a single float for consistency?
+
+ // Got any nasty NAN's?
+ bool IsValid() const;
+ void Invalidate();
+
+ // array access...
+ vec_t operator[](int i) const;
+ vec_t& operator[](int i);
+
+ // Base address...
+ vec_t* Base();
+ vec_t const* Base() const;
+
+ // Cast to Vector2D...
+ Vector2D& AsVector2D();
+ const Vector2D& AsVector2D() const;
+
+ // Initialization methods
+ void Random( vec_t minVal, vec_t maxVal );
+ inline void Zero(); ///< zero out a vector
+
+ // equality
+ bool operator==(const Vector& v) const;
+ bool operator!=(const Vector& v) const;
+
+ // arithmetic operations
+ FORCEINLINE Vector& operator+=(const Vector &v);
+ FORCEINLINE Vector& operator-=(const Vector &v);
+ FORCEINLINE Vector& operator*=(const Vector &v);
+ FORCEINLINE Vector& operator*=(float s);
+ FORCEINLINE Vector& operator/=(const Vector &v);
+ FORCEINLINE Vector& operator/=(float s);
+ FORCEINLINE Vector& operator+=(float fl) ; ///< broadcast add
+ FORCEINLINE Vector& operator-=(float fl) ; ///< broadcast sub
+
+// negate the vector components
+ void Negate();
+
+ // Get the vector's magnitude.
+ inline vec_t Length() const;
+
+ // Get the vector's magnitude squared.
+ FORCEINLINE vec_t LengthSqr(void) const
+ {
+ CHECK_VALID(*this);
+ return (x*x + y*y + z*z);
+ }
+
+ // return true if this vector is (0,0,0) within tolerance
+ bool IsZero( float tolerance = 0.01f ) const
+ {
+ return (x > -tolerance && x < tolerance &&
+ y > -tolerance && y < tolerance &&
+ z > -tolerance && z < tolerance);
+ }
+
+ vec_t NormalizeInPlace();
+ Vector Normalized() const;
+ bool IsLengthGreaterThan( float val ) const;
+ bool IsLengthLessThan( float val ) const;
+
+ // check if a vector is within the box defined by two other vectors
+ FORCEINLINE bool WithinAABox( Vector const &boxmin, Vector const &boxmax);
+
+ // Get the distance from this vector to the other one.
+ vec_t DistTo(const Vector &vOther) const;
+
+ // Get the distance from this vector to the other one squared.
+ // NJS: note, VC wasn't inlining it correctly in several deeply nested inlines due to being an 'out of line' inline.
+ // may be able to tidy this up after switching to VC7
+ FORCEINLINE vec_t DistToSqr(const Vector &vOther) const
+ {
+ Vector delta;
+
+ delta.x = x - vOther.x;
+ delta.y = y - vOther.y;
+ delta.z = z - vOther.z;
+
+ return delta.LengthSqr();
+ }
+
+ // Copy
+ void CopyToArray(float* rgfl) const;
+
+ // Multiply, add, and assign to this (ie: *this = a + b * scalar). This
+ // is about 12% faster than the actual vector equation (because it's done per-component
+ // rather than per-vector).
+ void MulAdd(const Vector& a, const Vector& b, float scalar);
+
+ // Dot product.
+ vec_t Dot(const Vector& vOther) const;
+
+ // assignment
+ Vector& operator=(const Vector &vOther);
+
+ // 2d
+ vec_t Length2D(void) const;
+ vec_t Length2DSqr(void) const;
+
+ operator VectorByValue &() { return *((VectorByValue *)(this)); }
+ operator const VectorByValue &() const { return *((const VectorByValue *)(this)); }
+
+#ifndef VECTOR_NO_SLOW_OPERATIONS
+ // copy constructors
+// Vector(const Vector &vOther);
+
+ // arithmetic operations
+ Vector operator-(void) const;
+
+ Vector operator+(const Vector& v) const;
+ Vector operator-(const Vector& v) const;
+ Vector operator*(const Vector& v) const;
+ Vector operator/(const Vector& v) const;
+ Vector operator*(float fl) const;
+ Vector operator/(float fl) const;
+
+ // Cross product between two vectors.
+ Vector Cross(const Vector &vOther) const;
+
+ // Returns a vector with the min or max in X, Y, and Z.
+ Vector Min(const Vector &vOther) const;
+ Vector Max(const Vector &vOther) const;
+
+#else
+
+private:
+ // No copy constructors allowed if we're in optimal mode
+ Vector(const Vector& vOther);
+#endif
+};
+
+FORCEINLINE void NetworkVarConstruct( Vector &v ) { v.Zero(); }
+
+
+#define USE_M64S ( ( !defined( _X360 ) ) )
+
+
+
+//=========================================================
+// 4D Short Vector (aligned on 8-byte boundary)
+//=========================================================
+class ALIGN8 ShortVector
+{
+public:
+
+ short x, y, z, w;
+
+ // Initialization
+ void Init(short ix = 0, short iy = 0, short iz = 0, short iw = 0 );
+
+
+#if USE_M64S
+ __m64 &AsM64() { return *(__m64*)&x; }
+ const __m64 &AsM64() const { return *(const __m64*)&x; }
+#endif
+
+ // Setter
+ void Set( const ShortVector& vOther );
+ void Set( const short ix, const short iy, const short iz, const short iw );
+
+ // array access...
+ short operator[](int i) const;
+ short& operator[](int i);
+
+ // Base address...
+ short* Base();
+ short const* Base() const;
+
+ // equality
+ bool operator==(const ShortVector& v) const;
+ bool operator!=(const ShortVector& v) const;
+
+ // Arithmetic operations
+ FORCEINLINE ShortVector& operator+=(const ShortVector &v);
+ FORCEINLINE ShortVector& operator-=(const ShortVector &v);
+ FORCEINLINE ShortVector& operator*=(const ShortVector &v);
+ FORCEINLINE ShortVector& operator*=(float s);
+ FORCEINLINE ShortVector& operator/=(const ShortVector &v);
+ FORCEINLINE ShortVector& operator/=(float s);
+ FORCEINLINE ShortVector operator*(float fl) const;
+
+private:
+
+ // No copy constructors allowed if we're in optimal mode
+// ShortVector(ShortVector const& vOther);
+
+ // No assignment operators either...
+// ShortVector& operator=( ShortVector const& src );
+
+} ALIGN8_POST;
+
+
+
+
+
+
+//=========================================================
+// 4D Integer Vector
+//=========================================================
+class IntVector4D
+{
+public:
+
+ int x, y, z, w;
+
+ // Initialization
+ void Init(int ix = 0, int iy = 0, int iz = 0, int iw = 0 );
+
+#if USE_M64S
+ __m64 &AsM64() { return *(__m64*)&x; }
+ const __m64 &AsM64() const { return *(const __m64*)&x; }
+#endif
+
+ // Setter
+ void Set( const IntVector4D& vOther );
+ void Set( const int ix, const int iy, const int iz, const int iw );
+
+ // array access...
+ int operator[](int i) const;
+ int& operator[](int i);
+
+ // Base address...
+ int* Base();
+ int const* Base() const;
+
+ // equality
+ bool operator==(const IntVector4D& v) const;
+ bool operator!=(const IntVector4D& v) const;
+
+ // Arithmetic operations
+ FORCEINLINE IntVector4D& operator+=(const IntVector4D &v);
+ FORCEINLINE IntVector4D& operator-=(const IntVector4D &v);
+ FORCEINLINE IntVector4D& operator*=(const IntVector4D &v);
+ FORCEINLINE IntVector4D& operator*=(float s);
+ FORCEINLINE IntVector4D& operator/=(const IntVector4D &v);
+ FORCEINLINE IntVector4D& operator/=(float s);
+ FORCEINLINE IntVector4D operator*(float fl) const;
+
+private:
+
+ // No copy constructors allowed if we're in optimal mode
+ // IntVector4D(IntVector4D const& vOther);
+
+ // No assignment operators either...
+ // IntVector4D& operator=( IntVector4D const& src );
+
+};
+
+
+
+//-----------------------------------------------------------------------------
+// Allows us to specifically pass the vector by value when we need to
+//-----------------------------------------------------------------------------
+class VectorByValue : public Vector
+{
+public:
+ // Construction/destruction:
+ VectorByValue(void) : Vector() {}
+ VectorByValue(vec_t X, vec_t Y, vec_t Z) : Vector( X, Y, Z ) {}
+ VectorByValue(const VectorByValue& vOther) { *this = vOther; }
+};
+
+
+//-----------------------------------------------------------------------------
+// Utility to simplify table construction. No constructor means can use
+// traditional C-style initialization
+//-----------------------------------------------------------------------------
+class TableVector
+{
+public:
+ vec_t x, y, z;
+
+ operator Vector &() { return *((Vector *)(this)); }
+ operator const Vector &() const { return *((const Vector *)(this)); }
+
+ // array access...
+ inline vec_t& operator[](int i)
+ {
+ Assert( (i >= 0) && (i < 3) );
+ return ((vec_t*)this)[i];
+ }
+
+ inline vec_t operator[](int i) const
+ {
+ Assert( (i >= 0) && (i < 3) );
+ return ((vec_t*)this)[i];
+ }
+};
+
+
+//-----------------------------------------------------------------------------
+// Here's where we add all those lovely SSE optimized routines
+//-----------------------------------------------------------------------------
+
+class ALIGN16 VectorAligned : public Vector
+{
+public:
+ inline VectorAligned(void) {};
+ inline VectorAligned(vec_t X, vec_t Y, vec_t Z)
+ {
+ Init(X,Y,Z);
+ }
+
+#ifdef VECTOR_NO_SLOW_OPERATIONS
+
+private:
+ // No copy constructors allowed if we're in optimal mode
+ VectorAligned(const VectorAligned& vOther);
+ VectorAligned(const Vector &vOther);
+
+#else
+public:
+ explicit VectorAligned(const Vector &vOther)
+ {
+ Init(vOther.x, vOther.y, vOther.z);
+ }
+
+ VectorAligned& operator=(const Vector &vOther)
+ {
+ Init(vOther.x, vOther.y, vOther.z);
+ return *this;
+ }
+
+#endif
+ float w; // this space is used anyway
+} ALIGN16_POST;
+
+//-----------------------------------------------------------------------------
+// Vector related operations
+//-----------------------------------------------------------------------------
+
+// Vector clear
+FORCEINLINE void VectorClear( Vector& a );
+
+// Copy
+FORCEINLINE void VectorCopy( const Vector& src, Vector& dst );
+
+// Vector arithmetic
+FORCEINLINE void VectorAdd( const Vector& a, const Vector& b, Vector& result );
+FORCEINLINE void VectorSubtract( const Vector& a, const Vector& b, Vector& result );
+FORCEINLINE void VectorMultiply( const Vector& a, vec_t b, Vector& result );
+FORCEINLINE void VectorMultiply( const Vector& a, const Vector& b, Vector& result );
+FORCEINLINE void VectorDivide( const Vector& a, vec_t b, Vector& result );
+FORCEINLINE void VectorDivide( const Vector& a, const Vector& b, Vector& result );
+inline void VectorScale ( const Vector& in, vec_t scale, Vector& result );
+// Don't mark this as inline in its function declaration. That's only necessary on its
+// definition, and 'inline' here leads to gcc warnings.
+void VectorMA( const Vector& start, float scale, const Vector& direction, Vector& dest );
+
+// Vector equality with tolerance
+bool VectorsAreEqual( const Vector& src1, const Vector& src2, float tolerance = 0.0f );
+
+#define VectorExpand(v) (v).x, (v).y, (v).z
+
+
+// Normalization
+// FIXME: Can't use quite yet
+//vec_t VectorNormalize( Vector& v );
+
+// Length
+inline vec_t VectorLength( const Vector& v );
+
+// Dot Product
+FORCEINLINE vec_t DotProduct(const Vector& a, const Vector& b);
+
+// Cross product
+void CrossProduct(const Vector& a, const Vector& b, Vector& result );
+
+// Store the min or max of each of x, y, and z into the result.
+void VectorMin( const Vector &a, const Vector &b, Vector &result );
+void VectorMax( const Vector &a, const Vector &b, Vector &result );
+
+// Linearly interpolate between two vectors
+void VectorLerp(const Vector& src1, const Vector& src2, vec_t t, Vector& dest );
+Vector VectorLerp(const Vector& src1, const Vector& src2, vec_t t );
+
+FORCEINLINE Vector ReplicateToVector( float x )
+{
+ return Vector( x, x, x );
+}
+
+// check if a point is in the field of a view of an object. supports up to 180 degree fov.
+FORCEINLINE bool PointWithinViewAngle( Vector const &vecSrcPosition,
+ Vector const &vecTargetPosition,
+ Vector const &vecLookDirection, float flCosHalfFOV )
+{
+ Vector vecDelta = vecTargetPosition - vecSrcPosition;
+ float cosDiff = DotProduct( vecLookDirection, vecDelta );
+
+ if ( cosDiff < 0 )
+ return false;
+
+ float flLen2 = vecDelta.LengthSqr();
+
+ // a/sqrt(b) > c == a^2 > b * c ^2
+ return ( cosDiff * cosDiff > flLen2 * flCosHalfFOV * flCosHalfFOV );
+
+}
+
+
+#ifndef VECTOR_NO_SLOW_OPERATIONS
+
+// Cross product
+Vector CrossProduct( const Vector& a, const Vector& b );
+
+// Random vector creation
+Vector RandomVector( vec_t minVal, vec_t maxVal );
+
+#endif
+
+float RandomVectorInUnitSphere( Vector *pVector );
+float RandomVectorInUnitCircle( Vector2D *pVector );
+
+
+//-----------------------------------------------------------------------------
+//
+// Inlined Vector methods
+//
+//-----------------------------------------------------------------------------
+
+
+//-----------------------------------------------------------------------------
+// constructors
+//-----------------------------------------------------------------------------
+inline Vector::Vector(void)
+{
+#ifdef _DEBUG
+#ifdef VECTOR_PARANOIA
+ // Initialize to NAN to catch errors
+ x = y = z = VEC_T_NAN;
+#endif
+#endif
+}
+
+inline Vector::Vector(vec_t X, vec_t Y, vec_t Z)
+{
+ x = X; y = Y; z = Z;
+ CHECK_VALID(*this);
+}
+
+inline Vector::Vector(vec_t XYZ)
+{
+ x = y = z = XYZ;
+ CHECK_VALID(*this);
+}
+
+//inline Vector::Vector(const float *pFloat)
+//{
+// Assert( pFloat );
+// x = pFloat[0]; y = pFloat[1]; z = pFloat[2];
+// CHECK_VALID(*this);
+//}
+
+#if 0
+//-----------------------------------------------------------------------------
+// copy constructor
+//-----------------------------------------------------------------------------
+
+inline Vector::Vector(const Vector &vOther)
+{
+ CHECK_VALID(vOther);
+ x = vOther.x; y = vOther.y; z = vOther.z;
+}
+#endif
+
+//-----------------------------------------------------------------------------
+// initialization
+//-----------------------------------------------------------------------------
+
+inline void Vector::Init( vec_t ix, vec_t iy, vec_t iz )
+{
+ x = ix; y = iy; z = iz;
+ CHECK_VALID(*this);
+}
+
+inline void Vector::Random( vec_t minVal, vec_t maxVal )
+{
+ x = minVal + ((float)rand() / VALVE_RAND_MAX) * (maxVal - minVal);
+ y = minVal + ((float)rand() / VALVE_RAND_MAX) * (maxVal - minVal);
+ z = minVal + ((float)rand() / VALVE_RAND_MAX) * (maxVal - minVal);
+ CHECK_VALID(*this);
+}
+
+// This should really be a single opcode on the PowerPC (move r0 onto the vec reg)
+inline void Vector::Zero()
+{
+ x = y = z = 0.0f;
+}
+
+inline void VectorClear( Vector& a )
+{
+ a.x = a.y = a.z = 0.0f;
+}
+
+//-----------------------------------------------------------------------------
+// assignment
+//-----------------------------------------------------------------------------
+
+inline Vector& Vector::operator=(const Vector &vOther)
+{
+ CHECK_VALID(vOther);
+ x=vOther.x; y=vOther.y; z=vOther.z;
+ return *this;
+}
+
+
+//-----------------------------------------------------------------------------
+// Array access
+//-----------------------------------------------------------------------------
+inline vec_t& Vector::operator[](int i)
+{
+ Assert( (i >= 0) && (i < 3) );
+ return ((vec_t*)this)[i];
+}
+
+inline vec_t Vector::operator[](int i) const
+{
+ Assert( (i >= 0) && (i < 3) );
+ return ((vec_t*)this)[i];
+}
+
+
+//-----------------------------------------------------------------------------
+// Base address...
+//-----------------------------------------------------------------------------
+inline vec_t* Vector::Base()
+{
+ return (vec_t*)this;
+}
+
+inline vec_t const* Vector::Base() const
+{
+ return (vec_t const*)this;
+}
+
+//-----------------------------------------------------------------------------
+// Cast to Vector2D...
+//-----------------------------------------------------------------------------
+
+inline Vector2D& Vector::AsVector2D()
+{
+ return *(Vector2D*)this;
+}
+
+inline const Vector2D& Vector::AsVector2D() const
+{
+ return *(const Vector2D*)this;
+}
+
+//-----------------------------------------------------------------------------
+// IsValid?
+//-----------------------------------------------------------------------------
+
+inline bool Vector::IsValid() const
+{
+ return IsFinite(x) && IsFinite(y) && IsFinite(z);
+}
+
+//-----------------------------------------------------------------------------
+// Invalidate
+//-----------------------------------------------------------------------------
+
+inline void Vector::Invalidate()
+{
+//#ifdef _DEBUG
+//#ifdef VECTOR_PARANOIA
+ x = y = z = VEC_T_NAN;
+//#endif
+//#endif
+}
+
+//-----------------------------------------------------------------------------
+// comparison
+//-----------------------------------------------------------------------------
+
+inline bool Vector::operator==( const Vector& src ) const
+{
+ CHECK_VALID(src);
+ CHECK_VALID(*this);
+ return (src.x == x) && (src.y == y) && (src.z == z);
+}
+
+inline bool Vector::operator!=( const Vector& src ) const
+{
+ CHECK_VALID(src);
+ CHECK_VALID(*this);
+ return (src.x != x) || (src.y != y) || (src.z != z);
+}
+
+
+//-----------------------------------------------------------------------------
+// Copy
+//-----------------------------------------------------------------------------
+
+FORCEINLINE void VectorCopy( const Vector& src, Vector& dst )
+{
+ CHECK_VALID(src);
+ dst.x = src.x;
+ dst.y = src.y;
+ dst.z = src.z;
+}
+
+inline void Vector::CopyToArray(float* rgfl) const
+{
+ Assert( rgfl );
+ CHECK_VALID(*this);
+ rgfl[0] = x, rgfl[1] = y, rgfl[2] = z;
+}
+
+//-----------------------------------------------------------------------------
+// standard math operations
+//-----------------------------------------------------------------------------
+// #pragma message("TODO: these should be SSE")
+
+inline void Vector::Negate()
+{
+ CHECK_VALID(*this);
+ x = -x; y = -y; z = -z;
+}
+
+FORCEINLINE Vector& Vector::operator+=(const Vector& v)
+{
+ CHECK_VALID(*this);
+ CHECK_VALID(v);
+ x+=v.x; y+=v.y; z += v.z;
+ return *this;
+}
+
+FORCEINLINE Vector& Vector::operator-=(const Vector& v)
+{
+ CHECK_VALID(*this);
+ CHECK_VALID(v);
+ x-=v.x; y-=v.y; z -= v.z;
+ return *this;
+}
+
+FORCEINLINE Vector& Vector::operator*=(float fl)
+{
+ x *= fl;
+ y *= fl;
+ z *= fl;
+ CHECK_VALID(*this);
+ return *this;
+}
+
+FORCEINLINE Vector& Vector::operator*=(const Vector& v)
+{
+ CHECK_VALID(v);
+ x *= v.x;
+ y *= v.y;
+ z *= v.z;
+ CHECK_VALID(*this);
+ return *this;
+}
+
+// this ought to be an opcode.
+FORCEINLINE Vector& Vector::operator+=(float fl)
+{
+ x += fl;
+ y += fl;
+ z += fl;
+ CHECK_VALID(*this);
+ return *this;
+}
+
+FORCEINLINE Vector& Vector::operator-=(float fl)
+{
+ x -= fl;
+ y -= fl;
+ z -= fl;
+ CHECK_VALID(*this);
+ return *this;
+}
+
+
+
+FORCEINLINE Vector& Vector::operator/=(float fl)
+{
+ Assert( fl != 0.0f );
+ float oofl = 1.0f / fl;
+ x *= oofl;
+ y *= oofl;
+ z *= oofl;
+ CHECK_VALID(*this);
+ return *this;
+}
+
+FORCEINLINE Vector& Vector::operator/=(const Vector& v)
+{
+ CHECK_VALID(v);
+ Assert( v.x != 0.0f && v.y != 0.0f && v.z != 0.0f );
+ x /= v.x;
+ y /= v.y;
+ z /= v.z;
+ CHECK_VALID(*this);
+ return *this;
+}
+
+
+
+//-----------------------------------------------------------------------------
+//
+// Inlined Short Vector methods
+//
+//-----------------------------------------------------------------------------
+
+
+inline void ShortVector::Init( short ix, short iy, short iz, short iw )
+{
+ x = ix; y = iy; z = iz; w = iw;
+}
+
+FORCEINLINE void ShortVector::Set( const ShortVector& vOther )
+{
+ x = vOther.x;
+ y = vOther.y;
+ z = vOther.z;
+ w = vOther.w;
+}
+
+FORCEINLINE void ShortVector::Set( const short ix, const short iy, const short iz, const short iw )
+{
+ x = ix;
+ y = iy;
+ z = iz;
+ w = iw;
+}
+
+
+//-----------------------------------------------------------------------------
+// Array access
+//-----------------------------------------------------------------------------
+inline short ShortVector::operator[](int i) const
+{
+ Assert( (i >= 0) && (i < 4) );
+ return ((short*)this)[i];
+}
+
+inline short& ShortVector::operator[](int i)
+{
+ Assert( (i >= 0) && (i < 4) );
+ return ((short*)this)[i];
+}
+
+//-----------------------------------------------------------------------------
+// Base address...
+//-----------------------------------------------------------------------------
+inline short* ShortVector::Base()
+{
+ return (short*)this;
+}
+
+inline short const* ShortVector::Base() const
+{
+ return (short const*)this;
+}
+
+
+//-----------------------------------------------------------------------------
+// comparison
+//-----------------------------------------------------------------------------
+
+inline bool ShortVector::operator==( const ShortVector& src ) const
+{
+ return (src.x == x) && (src.y == y) && (src.z == z) && (src.w == w);
+}
+
+inline bool ShortVector::operator!=( const ShortVector& src ) const
+{
+ return (src.x != x) || (src.y != y) || (src.z != z) || (src.w != w);
+}
+
+
+
+//-----------------------------------------------------------------------------
+// standard math operations
+//-----------------------------------------------------------------------------
+
+FORCEINLINE ShortVector& ShortVector::operator+=(const ShortVector& v)
+{
+ x+=v.x; y+=v.y; z += v.z; w += v.w;
+ return *this;
+}
+
+FORCEINLINE ShortVector& ShortVector::operator-=(const ShortVector& v)
+{
+ x-=v.x; y-=v.y; z -= v.z; w -= v.w;
+ return *this;
+}
+
+FORCEINLINE ShortVector& ShortVector::operator*=(float fl)
+{
+ x *= fl;
+ y *= fl;
+ z *= fl;
+ w *= fl;
+ return *this;
+}
+
+FORCEINLINE ShortVector& ShortVector::operator*=(const ShortVector& v)
+{
+ x *= v.x;
+ y *= v.y;
+ z *= v.z;
+ w *= v.w;
+ return *this;
+}
+
+FORCEINLINE ShortVector& ShortVector::operator/=(float fl)
+{
+ Assert( fl != 0.0f );
+ float oofl = 1.0f / fl;
+ x *= oofl;
+ y *= oofl;
+ z *= oofl;
+ w *= oofl;
+ return *this;
+}
+
+FORCEINLINE ShortVector& ShortVector::operator/=(const ShortVector& v)
+{
+ Assert( v.x != 0 && v.y != 0 && v.z != 0 && v.w != 0 );
+ x /= v.x;
+ y /= v.y;
+ z /= v.z;
+ w /= v.w;
+ return *this;
+}
+
+FORCEINLINE void ShortVectorMultiply( const ShortVector& src, float fl, ShortVector& res )
+{
+ Assert( IsFinite(fl) );
+ res.x = src.x * fl;
+ res.y = src.y * fl;
+ res.z = src.z * fl;
+ res.w = src.w * fl;
+}
+
+FORCEINLINE ShortVector ShortVector::operator*(float fl) const
+{
+ ShortVector res;
+ ShortVectorMultiply( *this, fl, res );
+ return res;
+}
+
+
+
+
+
+
+//-----------------------------------------------------------------------------
+//
+// Inlined Integer Vector methods
+//
+//-----------------------------------------------------------------------------
+
+
+inline void IntVector4D::Init( int ix, int iy, int iz, int iw )
+{
+ x = ix; y = iy; z = iz; w = iw;
+}
+
+FORCEINLINE void IntVector4D::Set( const IntVector4D& vOther )
+{
+ x = vOther.x;
+ y = vOther.y;
+ z = vOther.z;
+ w = vOther.w;
+}
+
+FORCEINLINE void IntVector4D::Set( const int ix, const int iy, const int iz, const int iw )
+{
+ x = ix;
+ y = iy;
+ z = iz;
+ w = iw;
+}
+
+
+//-----------------------------------------------------------------------------
+// Array access
+//-----------------------------------------------------------------------------
+inline int IntVector4D::operator[](int i) const
+{
+ Assert( (i >= 0) && (i < 4) );
+ return ((int*)this)[i];
+}
+
+inline int& IntVector4D::operator[](int i)
+{
+ Assert( (i >= 0) && (i < 4) );
+ return ((int*)this)[i];
+}
+
+//-----------------------------------------------------------------------------
+// Base address...
+//-----------------------------------------------------------------------------
+inline int* IntVector4D::Base()
+{
+ return (int*)this;
+}
+
+inline int const* IntVector4D::Base() const
+{
+ return (int const*)this;
+}
+
+
+//-----------------------------------------------------------------------------
+// comparison
+//-----------------------------------------------------------------------------
+
+inline bool IntVector4D::operator==( const IntVector4D& src ) const
+{
+ return (src.x == x) && (src.y == y) && (src.z == z) && (src.w == w);
+}
+
+inline bool IntVector4D::operator!=( const IntVector4D& src ) const
+{
+ return (src.x != x) || (src.y != y) || (src.z != z) || (src.w != w);
+}
+
+
+
+//-----------------------------------------------------------------------------
+// standard math operations
+//-----------------------------------------------------------------------------
+
+FORCEINLINE IntVector4D& IntVector4D::operator+=(const IntVector4D& v)
+{
+ x+=v.x; y+=v.y; z += v.z; w += v.w;
+ return *this;
+}
+
+FORCEINLINE IntVector4D& IntVector4D::operator-=(const IntVector4D& v)
+{
+ x-=v.x; y-=v.y; z -= v.z; w -= v.w;
+ return *this;
+}
+
+FORCEINLINE IntVector4D& IntVector4D::operator*=(float fl)
+{
+ x *= fl;
+ y *= fl;
+ z *= fl;
+ w *= fl;
+ return *this;
+}
+
+FORCEINLINE IntVector4D& IntVector4D::operator*=(const IntVector4D& v)
+{
+ x *= v.x;
+ y *= v.y;
+ z *= v.z;
+ w *= v.w;
+ return *this;
+}
+
+FORCEINLINE IntVector4D& IntVector4D::operator/=(float fl)
+{
+ Assert( fl != 0.0f );
+ float oofl = 1.0f / fl;
+ x *= oofl;
+ y *= oofl;
+ z *= oofl;
+ w *= oofl;
+ return *this;
+}
+
+FORCEINLINE IntVector4D& IntVector4D::operator/=(const IntVector4D& v)
+{
+ Assert( v.x != 0 && v.y != 0 && v.z != 0 && v.w != 0 );
+ x /= v.x;
+ y /= v.y;
+ z /= v.z;
+ w /= v.w;
+ return *this;
+}
+
+FORCEINLINE void IntVector4DMultiply( const IntVector4D& src, float fl, IntVector4D& res )
+{
+ Assert( IsFinite(fl) );
+ res.x = src.x * fl;
+ res.y = src.y * fl;
+ res.z = src.z * fl;
+ res.w = src.w * fl;
+}
+
+FORCEINLINE IntVector4D IntVector4D::operator*(float fl) const
+{
+ IntVector4D res;
+ IntVector4DMultiply( *this, fl, res );
+ return res;
+}
+
+
+
+// =======================
+
+
+FORCEINLINE void VectorAdd( const Vector& a, const Vector& b, Vector& c )
+{
+ CHECK_VALID(a);
+ CHECK_VALID(b);
+ c.x = a.x + b.x;
+ c.y = a.y + b.y;
+ c.z = a.z + b.z;
+}
+
+FORCEINLINE void VectorSubtract( const Vector& a, const Vector& b, Vector& c )
+{
+ CHECK_VALID(a);
+ CHECK_VALID(b);
+ c.x = a.x - b.x;
+ c.y = a.y - b.y;
+ c.z = a.z - b.z;
+}
+
+FORCEINLINE void VectorMultiply( const Vector& a, vec_t b, Vector& c )
+{
+ CHECK_VALID(a);
+ Assert( IsFinite(b) );
+ c.x = a.x * b;
+ c.y = a.y * b;
+ c.z = a.z * b;
+}
+
+FORCEINLINE void VectorMultiply( const Vector& a, const Vector& b, Vector& c )
+{
+ CHECK_VALID(a);
+ CHECK_VALID(b);
+ c.x = a.x * b.x;
+ c.y = a.y * b.y;
+ c.z = a.z * b.z;
+}
+
+// for backwards compatability
+inline void VectorScale ( const Vector& in, vec_t scale, Vector& result )
+{
+ VectorMultiply( in, scale, result );
+}
+
+
+FORCEINLINE void VectorDivide( const Vector& a, vec_t b, Vector& c )
+{
+ CHECK_VALID(a);
+ Assert( b != 0.0f );
+ vec_t oob = 1.0f / b;
+ c.x = a.x * oob;
+ c.y = a.y * oob;
+ c.z = a.z * oob;
+}
+
+FORCEINLINE void VectorDivide( const Vector& a, const Vector& b, Vector& c )
+{
+ CHECK_VALID(a);
+ CHECK_VALID(b);
+ Assert( (b.x != 0.0f) && (b.y != 0.0f) && (b.z != 0.0f) );
+ c.x = a.x / b.x;
+ c.y = a.y / b.y;
+ c.z = a.z / b.z;
+}
+
+// FIXME: Remove
+// For backwards compatability
+inline void Vector::MulAdd(const Vector& a, const Vector& b, float scalar)
+{
+ CHECK_VALID(a);
+ CHECK_VALID(b);
+ x = a.x + b.x * scalar;
+ y = a.y + b.y * scalar;
+ z = a.z + b.z * scalar;
+}
+
+inline void VectorLerp(const Vector& src1, const Vector& src2, vec_t t, Vector& dest )
+{
+ CHECK_VALID(src1);
+ CHECK_VALID(src2);
+ dest.x = src1.x + (src2.x - src1.x) * t;
+ dest.y = src1.y + (src2.y - src1.y) * t;
+ dest.z = src1.z + (src2.z - src1.z) * t;
+}
+
+inline Vector VectorLerp(const Vector& src1, const Vector& src2, vec_t t )
+{
+ Vector result;
+ VectorLerp( src1, src2, t, result );
+ return result;
+}
+
+//-----------------------------------------------------------------------------
+// Temporary storage for vector results so const Vector& results can be returned
+//-----------------------------------------------------------------------------
+inline Vector &AllocTempVector()
+{
+ static Vector s_vecTemp[128];
+ static CInterlockedInt s_nIndex;
+
+ int nIndex;
+ for (;;)
+ {
+ int nOldIndex = s_nIndex;
+ nIndex = ( (nOldIndex + 0x10001) & 0x7F );
+
+ if ( s_nIndex.AssignIf( nOldIndex, nIndex ) )
+ {
+ break;
+ }
+ ThreadPause();
+ }
+ return s_vecTemp[nIndex & 0xffff];
+}
+
+
+
+//-----------------------------------------------------------------------------
+// dot, cross
+//-----------------------------------------------------------------------------
+FORCEINLINE vec_t DotProduct(const Vector& a, const Vector& b)
+{
+ CHECK_VALID(a);
+ CHECK_VALID(b);
+ return( a.x*b.x + a.y*b.y + a.z*b.z );
+}
+
+// for backwards compatability
+inline vec_t Vector::Dot( const Vector& vOther ) const
+{
+ CHECK_VALID(vOther);
+ return DotProduct( *this, vOther );
+}
+
+inline void CrossProduct(const Vector& a, const Vector& b, Vector& result )
+{
+ CHECK_VALID(a);
+ CHECK_VALID(b);
+ Assert( &a != &result );
+ Assert( &b != &result );
+ result.x = a.y*b.z - a.z*b.y;
+ result.y = a.z*b.x - a.x*b.z;
+ result.z = a.x*b.y - a.y*b.x;
+}
+
+inline vec_t DotProductAbs( const Vector &v0, const Vector &v1 )
+{
+ CHECK_VALID(v0);
+ CHECK_VALID(v1);
+ return FloatMakePositive(v0.x*v1.x) + FloatMakePositive(v0.y*v1.y) + FloatMakePositive(v0.z*v1.z);
+}
+
+inline vec_t DotProductAbs( const Vector &v0, const float *v1 )
+{
+ return FloatMakePositive(v0.x * v1[0]) + FloatMakePositive(v0.y * v1[1]) + FloatMakePositive(v0.z * v1[2]);
+}
+
+//-----------------------------------------------------------------------------
+// length
+//-----------------------------------------------------------------------------
+
+inline vec_t VectorLength( const Vector& v )
+{
+ CHECK_VALID(v);
+ return (vec_t)FastSqrt(v.x*v.x + v.y*v.y + v.z*v.z);
+}
+
+
+inline vec_t Vector::Length(void) const
+{
+ CHECK_VALID(*this);
+ return VectorLength( *this );
+}
+
+
+//-----------------------------------------------------------------------------
+// Normalization
+//-----------------------------------------------------------------------------
+
+/*
+// FIXME: Can't use until we're un-macroed in mathlib.h
+inline vec_t VectorNormalize( Vector& v )
+{
+ Assert( v.IsValid() );
+ vec_t l = v.Length();
+ if (l != 0.0f)
+ {
+ v /= l;
+ }
+ else
+ {
+ // FIXME:
+ // Just copying the existing implemenation; shouldn't res.z == 0?
+ v.x = v.y = 0.0f; v.z = 1.0f;
+ }
+ return l;
+}
+*/
+
+
+// check a point against a box
+bool Vector::WithinAABox( Vector const &boxmin, Vector const &boxmax)
+{
+ return (
+ ( x >= boxmin.x ) && ( x <= boxmax.x) &&
+ ( y >= boxmin.y ) && ( y <= boxmax.y) &&
+ ( z >= boxmin.z ) && ( z <= boxmax.z)
+ );
+}
+
+//-----------------------------------------------------------------------------
+// Get the distance from this vector to the other one
+//-----------------------------------------------------------------------------
+inline vec_t Vector::DistTo(const Vector &vOther) const
+{
+ Vector delta;
+ VectorSubtract( *this, vOther, delta );
+ return delta.Length();
+}
+
+
+//-----------------------------------------------------------------------------
+// Vector equality with tolerance
+//-----------------------------------------------------------------------------
+inline bool VectorsAreEqual( const Vector& src1, const Vector& src2, float tolerance )
+{
+ if (FloatMakePositive(src1.x - src2.x) > tolerance)
+ return false;
+ if (FloatMakePositive(src1.y - src2.y) > tolerance)
+ return false;
+ return (FloatMakePositive(src1.z - src2.z) <= tolerance);
+}
+
+
+//-----------------------------------------------------------------------------
+// Computes the closest point to vecTarget no farther than flMaxDist from vecStart
+//-----------------------------------------------------------------------------
+inline void ComputeClosestPoint( const Vector& vecStart, float flMaxDist, const Vector& vecTarget, Vector *pResult )
+{
+ Vector vecDelta;
+ VectorSubtract( vecTarget, vecStart, vecDelta );
+ float flDistSqr = vecDelta.LengthSqr();
+ if ( flDistSqr <= flMaxDist * flMaxDist )
+ {
+ *pResult = vecTarget;
+ }
+ else
+ {
+ vecDelta /= FastSqrt( flDistSqr );
+ VectorMA( vecStart, flMaxDist, vecDelta, *pResult );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Takes the absolute value of a vector
+//-----------------------------------------------------------------------------
+inline void VectorAbs( const Vector& src, Vector& dst )
+{
+ dst.x = FloatMakePositive(src.x);
+ dst.y = FloatMakePositive(src.y);
+ dst.z = FloatMakePositive(src.z);
+}
+
+
+//-----------------------------------------------------------------------------
+//
+// Slow methods
+//
+//-----------------------------------------------------------------------------
+
+#ifndef VECTOR_NO_SLOW_OPERATIONS
+
+//-----------------------------------------------------------------------------
+// Returns a vector with the min or max in X, Y, and Z.
+//-----------------------------------------------------------------------------
+inline Vector Vector::Min(const Vector &vOther) const
+{
+ return Vector(x < vOther.x ? x : vOther.x,
+ y < vOther.y ? y : vOther.y,
+ z < vOther.z ? z : vOther.z);
+}
+
+inline Vector Vector::Max(const Vector &vOther) const
+{
+ return Vector(x > vOther.x ? x : vOther.x,
+ y > vOther.y ? y : vOther.y,
+ z > vOther.z ? z : vOther.z);
+}
+
+
+//-----------------------------------------------------------------------------
+// arithmetic operations
+//-----------------------------------------------------------------------------
+
+inline Vector Vector::operator-(void) const
+{
+ return Vector(-x,-y,-z);
+}
+
+inline Vector Vector::operator+(const Vector& v) const
+{
+ Vector res;
+ VectorAdd( *this, v, res );
+ return res;
+}
+
+inline Vector Vector::operator-(const Vector& v) const
+{
+ Vector res;
+ VectorSubtract( *this, v, res );
+ return res;
+}
+
+inline Vector Vector::operator*(float fl) const
+{
+ Vector res;
+ VectorMultiply( *this, fl, res );
+ return res;
+}
+
+inline Vector Vector::operator*(const Vector& v) const
+{
+ Vector res;
+ VectorMultiply( *this, v, res );
+ return res;
+}
+
+inline Vector Vector::operator/(float fl) const
+{
+ Vector res;
+ VectorDivide( *this, fl, res );
+ return res;
+}
+
+inline Vector Vector::operator/(const Vector& v) const
+{
+ Vector res;
+ VectorDivide( *this, v, res );
+ return res;
+}
+
+inline Vector operator*(float fl, const Vector& v)
+{
+ return v * fl;
+}
+
+//-----------------------------------------------------------------------------
+// cross product
+//-----------------------------------------------------------------------------
+
+inline Vector Vector::Cross(const Vector& vOther) const
+{
+ Vector res;
+ CrossProduct( *this, vOther, res );
+ return res;
+}
+
+//-----------------------------------------------------------------------------
+// 2D
+//-----------------------------------------------------------------------------
+
+inline vec_t Vector::Length2D(void) const
+{
+ return (vec_t)FastSqrt(x*x + y*y);
+}
+
+inline vec_t Vector::Length2DSqr(void) const
+{
+ return (x*x + y*y);
+}
+
+inline Vector CrossProduct(const Vector& a, const Vector& b)
+{
+ return Vector( a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x );
+}
+
+inline void VectorMin( const Vector &a, const Vector &b, Vector &result )
+{
+ result.x = fpmin(a.x, b.x);
+ result.y = fpmin(a.y, b.y);
+ result.z = fpmin(a.z, b.z);
+}
+
+inline void VectorMax( const Vector &a, const Vector &b, Vector &result )
+{
+ result.x = fpmax(a.x, b.x);
+ result.y = fpmax(a.y, b.y);
+ result.z = fpmax(a.z, b.z);
+}
+
+inline float ComputeVolume( const Vector &vecMins, const Vector &vecMaxs )
+{
+ Vector vecDelta;
+ VectorSubtract( vecMaxs, vecMins, vecDelta );
+ return DotProduct( vecDelta, vecDelta );
+}
+
+// Get a random vector.
+inline Vector RandomVector( float minVal, float maxVal )
+{
+ Vector random;
+ random.Random( minVal, maxVal );
+ return random;
+}
+
+#endif //slow
+
+//-----------------------------------------------------------------------------
+// Helper debugging stuff....
+//-----------------------------------------------------------------------------
+
+inline bool operator==( float const* f, const Vector& v )
+{
+ // AIIIEEEE!!!!
+ Assert(0);
+ return false;
+}
+
+inline bool operator==( const Vector& v, float const* f )
+{
+ // AIIIEEEE!!!!
+ Assert(0);
+ return false;
+}
+
+inline bool operator!=( float const* f, const Vector& v )
+{
+ // AIIIEEEE!!!!
+ Assert(0);
+ return false;
+}
+
+inline bool operator!=( const Vector& v, float const* f )
+{
+ // AIIIEEEE!!!!
+ Assert(0);
+ return false;
+}
+
+
+//-----------------------------------------------------------------------------
+// AngularImpulse
+//-----------------------------------------------------------------------------
+// AngularImpulse are exponetial maps (an axis scaled by a "twist" angle in degrees)
+typedef Vector AngularImpulse;
+
+#ifndef VECTOR_NO_SLOW_OPERATIONS
+
+inline AngularImpulse RandomAngularImpulse( float minVal, float maxVal )
+{
+ AngularImpulse angImp;
+ angImp.Random( minVal, maxVal );
+ return angImp;
+}
+
+#endif
+
+
+//-----------------------------------------------------------------------------
+// Quaternion
+//-----------------------------------------------------------------------------
+
+class RadianEuler;
+
+class Quaternion // same data-layout as engine's vec4_t,
+{ // which is a vec_t[4]
+public:
+ inline Quaternion(void) {
+
+ // Initialize to NAN to catch errors
+#ifdef _DEBUG
+#ifdef VECTOR_PARANOIA
+ x = y = z = w = VEC_T_NAN;
+#endif
+#endif
+ }
+ inline Quaternion(vec_t ix, vec_t iy, vec_t iz, vec_t iw) : x(ix), y(iy), z(iz), w(iw) { }
+ inline Quaternion(RadianEuler const &angle); // evil auto type promotion!!!
+
+ inline void Init(vec_t ix=0.0f, vec_t iy=0.0f, vec_t iz=0.0f, vec_t iw=0.0f) { x = ix; y = iy; z = iz; w = iw; }
+
+ bool IsValid() const;
+ void Invalidate();
+
+ bool operator==( const Quaternion &src ) const;
+ bool operator!=( const Quaternion &src ) const;
+
+ vec_t* Base() { return (vec_t*)this; }
+ const vec_t* Base() const { return (vec_t*)this; }
+
+ // array access...
+ vec_t operator[](int i) const;
+ vec_t& operator[](int i);
+
+ vec_t x, y, z, w;
+};
+
+
+//-----------------------------------------------------------------------------
+// Array access
+//-----------------------------------------------------------------------------
+inline vec_t& Quaternion::operator[](int i)
+{
+ Assert( (i >= 0) && (i < 4) );
+ return ((vec_t*)this)[i];
+}
+
+inline vec_t Quaternion::operator[](int i) const
+{
+ Assert( (i >= 0) && (i < 4) );
+ return ((vec_t*)this)[i];
+}
+
+
+//-----------------------------------------------------------------------------
+// Equality test
+//-----------------------------------------------------------------------------
+inline bool Quaternion::operator==( const Quaternion &src ) const
+{
+ return ( x == src.x ) && ( y == src.y ) && ( z == src.z ) && ( w == src.w );
+}
+
+inline bool Quaternion::operator!=( const Quaternion &src ) const
+{
+ return !operator==( src );
+}
+
+
+//-----------------------------------------------------------------------------
+// Quaternion equality with tolerance
+//-----------------------------------------------------------------------------
+inline bool QuaternionsAreEqual( const Quaternion& src1, const Quaternion& src2, float tolerance )
+{
+ if (FloatMakePositive(src1.x - src2.x) > tolerance)
+ return false;
+ if (FloatMakePositive(src1.y - src2.y) > tolerance)
+ return false;
+ if (FloatMakePositive(src1.z - src2.z) > tolerance)
+ return false;
+ return (FloatMakePositive(src1.w - src2.w) <= tolerance);
+}
+
+
+//-----------------------------------------------------------------------------
+// Here's where we add all those lovely SSE optimized routines
+//-----------------------------------------------------------------------------
+class ALIGN16 QuaternionAligned : public Quaternion
+{
+public:
+ inline QuaternionAligned(void) {};
+ inline QuaternionAligned(vec_t X, vec_t Y, vec_t Z, vec_t W)
+ {
+ Init(X,Y,Z,W);
+ }
+
+#ifdef VECTOR_NO_SLOW_OPERATIONS
+
+private:
+ // No copy constructors allowed if we're in optimal mode
+ QuaternionAligned(const QuaternionAligned& vOther);
+ QuaternionAligned(const Quaternion &vOther);
+
+#else
+public:
+ explicit QuaternionAligned(const Quaternion &vOther)
+ {
+ Init(vOther.x, vOther.y, vOther.z, vOther.w);
+ }
+
+ QuaternionAligned& operator=(const Quaternion &vOther)
+ {
+ Init(vOther.x, vOther.y, vOther.z, vOther.w);
+ return *this;
+ }
+
+#endif
+} ALIGN16_POST;
+
+
+//-----------------------------------------------------------------------------
+// Radian Euler angle aligned to axis (NOT ROLL/PITCH/YAW)
+//-----------------------------------------------------------------------------
+class QAngle;
+class RadianEuler
+{
+public:
+ inline RadianEuler(void) { }
+ inline RadianEuler(vec_t X, vec_t Y, vec_t Z) { x = X; y = Y; z = Z; }
+ inline RadianEuler(Quaternion const &q); // evil auto type promotion!!!
+ inline RadianEuler(QAngle const &angles); // evil auto type promotion!!!
+
+ // Initialization
+ inline void Init(vec_t ix=0.0f, vec_t iy=0.0f, vec_t iz=0.0f) { x = ix; y = iy; z = iz; }
+
+ // conversion to qangle
+ QAngle ToQAngle( void ) const;
+ bool IsValid() const;
+ void Invalidate();
+
+ // array access...
+ vec_t operator[](int i) const;
+ vec_t& operator[](int i);
+
+ vec_t x, y, z;
+};
+
+
+extern void AngleQuaternion( RadianEuler const &angles, Quaternion &qt );
+extern void QuaternionAngles( Quaternion const &q, RadianEuler &angles );
+
+FORCEINLINE void NetworkVarConstruct( Quaternion &q ) { q.x = q.y = q.z = q.w = 0.0f; }
+
+inline Quaternion::Quaternion(RadianEuler const &angle)
+{
+ AngleQuaternion( angle, *this );
+}
+
+inline bool Quaternion::IsValid() const
+{
+ return IsFinite(x) && IsFinite(y) && IsFinite(z) && IsFinite(w);
+}
+
+inline void Quaternion::Invalidate()
+{
+//#ifdef _DEBUG
+//#ifdef VECTOR_PARANOIA
+ x = y = z = w = VEC_T_NAN;
+//#endif
+//#endif
+}
+
+inline RadianEuler::RadianEuler(Quaternion const &q)
+{
+ QuaternionAngles( q, *this );
+}
+
+inline void VectorCopy( RadianEuler const& src, RadianEuler &dst )
+{
+ CHECK_VALID(src);
+ dst.x = src.x;
+ dst.y = src.y;
+ dst.z = src.z;
+}
+
+inline void VectorScale( RadianEuler const& src, float b, RadianEuler &dst )
+{
+ CHECK_VALID(src);
+ Assert( IsFinite(b) );
+ dst.x = src.x * b;
+ dst.y = src.y * b;
+ dst.z = src.z * b;
+}
+
+inline bool RadianEuler::IsValid() const
+{
+ return IsFinite(x) && IsFinite(y) && IsFinite(z);
+}
+
+inline void RadianEuler::Invalidate()
+{
+//#ifdef _DEBUG
+//#ifdef VECTOR_PARANOIA
+ x = y = z = VEC_T_NAN;
+//#endif
+//#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Array access
+//-----------------------------------------------------------------------------
+inline vec_t& RadianEuler::operator[](int i)
+{
+ Assert( (i >= 0) && (i < 3) );
+ return ((vec_t*)this)[i];
+}
+
+inline vec_t RadianEuler::operator[](int i) const
+{
+ Assert( (i >= 0) && (i < 3) );
+ return ((vec_t*)this)[i];
+}
+
+
+//-----------------------------------------------------------------------------
+// Degree Euler QAngle pitch, yaw, roll
+//-----------------------------------------------------------------------------
+class QAngleByValue;
+
+class QAngle
+{
+public:
+ // Members
+ vec_t x, y, z;
+
+ // Construction/destruction
+ QAngle(void);
+ QAngle(vec_t X, vec_t Y, vec_t Z);
+// QAngle(RadianEuler const &angles); // evil auto type promotion!!!
+
+ // Allow pass-by-value
+ operator QAngleByValue &() { return *((QAngleByValue *)(this)); }
+ operator const QAngleByValue &() const { return *((const QAngleByValue *)(this)); }
+
+ // Initialization
+ void Init(vec_t ix=0.0f, vec_t iy=0.0f, vec_t iz=0.0f);
+ void Random( vec_t minVal, vec_t maxVal );
+
+ // Got any nasty NAN's?
+ bool IsValid() const;
+ void Invalidate();
+
+ // array access...
+ vec_t operator[](int i) const;
+ vec_t& operator[](int i);
+
+ // Base address...
+ vec_t* Base();
+ vec_t const* Base() const;
+
+ // equality
+ bool operator==(const QAngle& v) const;
+ bool operator!=(const QAngle& v) const;
+
+ // arithmetic operations
+ QAngle& operator+=(const QAngle &v);
+ QAngle& operator-=(const QAngle &v);
+ QAngle& operator*=(float s);
+ QAngle& operator/=(float s);
+
+ // Get the vector's magnitude.
+ vec_t Length() const;
+ vec_t LengthSqr() const;
+
+ // negate the QAngle components
+ //void Negate();
+
+ // No assignment operators either...
+ QAngle& operator=( const QAngle& src );
+
+#ifndef VECTOR_NO_SLOW_OPERATIONS
+ // copy constructors
+
+ // arithmetic operations
+ QAngle operator-(void) const;
+
+ QAngle operator+(const QAngle& v) const;
+ QAngle operator-(const QAngle& v) const;
+ QAngle operator*(float fl) const;
+ QAngle operator/(float fl) const;
+#else
+
+private:
+ // No copy constructors allowed if we're in optimal mode
+ QAngle(const QAngle& vOther);
+
+#endif
+};
+
+FORCEINLINE void NetworkVarConstruct( QAngle &q ) { q.x = q.y = q.z = 0.0f; }
+
+//-----------------------------------------------------------------------------
+// Allows us to specifically pass the vector by value when we need to
+//-----------------------------------------------------------------------------
+class QAngleByValue : public QAngle
+{
+public:
+ // Construction/destruction:
+ QAngleByValue(void) : QAngle() {}
+ QAngleByValue(vec_t X, vec_t Y, vec_t Z) : QAngle( X, Y, Z ) {}
+ QAngleByValue(const QAngleByValue& vOther) { *this = vOther; }
+};
+
+
+inline void VectorAdd( const QAngle& a, const QAngle& b, QAngle& result )
+{
+ CHECK_VALID(a);
+ CHECK_VALID(b);
+ result.x = a.x + b.x;
+ result.y = a.y + b.y;
+ result.z = a.z + b.z;
+}
+
+inline void VectorMA( const QAngle &start, float scale, const QAngle &direction, QAngle &dest )
+{
+ CHECK_VALID(start);
+ CHECK_VALID(direction);
+ dest.x = start.x + scale * direction.x;
+ dest.y = start.y + scale * direction.y;
+ dest.z = start.z + scale * direction.z;
+}
+
+
+//-----------------------------------------------------------------------------
+// constructors
+//-----------------------------------------------------------------------------
+inline QAngle::QAngle(void)
+{
+#ifdef _DEBUG
+#ifdef VECTOR_PARANOIA
+ // Initialize to NAN to catch errors
+ x = y = z = VEC_T_NAN;
+#endif
+#endif
+}
+
+inline QAngle::QAngle(vec_t X, vec_t Y, vec_t Z)
+{
+ x = X; y = Y; z = Z;
+ CHECK_VALID(*this);
+}
+
+
+//-----------------------------------------------------------------------------
+// initialization
+//-----------------------------------------------------------------------------
+inline void QAngle::Init( vec_t ix, vec_t iy, vec_t iz )
+{
+ x = ix; y = iy; z = iz;
+ CHECK_VALID(*this);
+}
+
+inline void QAngle::Random( vec_t minVal, vec_t maxVal )
+{
+ x = minVal + ((float)rand() / VALVE_RAND_MAX) * (maxVal - minVal);
+ y = minVal + ((float)rand() / VALVE_RAND_MAX) * (maxVal - minVal);
+ z = minVal + ((float)rand() / VALVE_RAND_MAX) * (maxVal - minVal);
+ CHECK_VALID(*this);
+}
+
+#ifndef VECTOR_NO_SLOW_OPERATIONS
+
+inline QAngle RandomAngle( float minVal, float maxVal )
+{
+ Vector random;
+ random.Random( minVal, maxVal );
+ QAngle ret( random.x, random.y, random.z );
+ return ret;
+}
+
+#endif
+
+
+inline RadianEuler::RadianEuler(QAngle const &angles)
+{
+ Init(
+ angles.z * 3.14159265358979323846f / 180.f,
+ angles.x * 3.14159265358979323846f / 180.f,
+ angles.y * 3.14159265358979323846f / 180.f );
+}
+
+
+
+
+inline QAngle RadianEuler::ToQAngle( void) const
+{
+ return QAngle(
+ y * 180.f / 3.14159265358979323846f,
+ z * 180.f / 3.14159265358979323846f,
+ x * 180.f / 3.14159265358979323846f );
+}
+
+
+//-----------------------------------------------------------------------------
+// assignment
+//-----------------------------------------------------------------------------
+inline QAngle& QAngle::operator=(const QAngle &vOther)
+{
+ CHECK_VALID(vOther);
+ x=vOther.x; y=vOther.y; z=vOther.z;
+ return *this;
+}
+
+
+//-----------------------------------------------------------------------------
+// Array access
+//-----------------------------------------------------------------------------
+inline vec_t& QAngle::operator[](int i)
+{
+ Assert( (i >= 0) && (i < 3) );
+ return ((vec_t*)this)[i];
+}
+
+inline vec_t QAngle::operator[](int i) const
+{
+ Assert( (i >= 0) && (i < 3) );
+ return ((vec_t*)this)[i];
+}
+
+
+//-----------------------------------------------------------------------------
+// Base address...
+//-----------------------------------------------------------------------------
+inline vec_t* QAngle::Base()
+{
+ return (vec_t*)this;
+}
+
+inline vec_t const* QAngle::Base() const
+{
+ return (vec_t const*)this;
+}
+
+
+//-----------------------------------------------------------------------------
+// IsValid?
+//-----------------------------------------------------------------------------
+inline bool QAngle::IsValid() const
+{
+ return IsFinite(x) && IsFinite(y) && IsFinite(z);
+}
+
+//-----------------------------------------------------------------------------
+// Invalidate
+//-----------------------------------------------------------------------------
+
+inline void QAngle::Invalidate()
+{
+//#ifdef _DEBUG
+//#ifdef VECTOR_PARANOIA
+ x = y = z = VEC_T_NAN;
+//#endif
+//#endif
+}
+
+//-----------------------------------------------------------------------------
+// comparison
+//-----------------------------------------------------------------------------
+inline bool QAngle::operator==( const QAngle& src ) const
+{
+ CHECK_VALID(src);
+ CHECK_VALID(*this);
+ return (src.x == x) && (src.y == y) && (src.z == z);
+}
+
+inline bool QAngle::operator!=( const QAngle& src ) const
+{
+ CHECK_VALID(src);
+ CHECK_VALID(*this);
+ return (src.x != x) || (src.y != y) || (src.z != z);
+}
+
+
+//-----------------------------------------------------------------------------
+// Copy
+//-----------------------------------------------------------------------------
+inline void VectorCopy( const QAngle& src, QAngle& dst )
+{
+ CHECK_VALID(src);
+ dst.x = src.x;
+ dst.y = src.y;
+ dst.z = src.z;
+}
+
+
+//-----------------------------------------------------------------------------
+// standard math operations
+//-----------------------------------------------------------------------------
+inline QAngle& QAngle::operator+=(const QAngle& v)
+{
+ CHECK_VALID(*this);
+ CHECK_VALID(v);
+ x+=v.x; y+=v.y; z += v.z;
+ return *this;
+}
+
+inline QAngle& QAngle::operator-=(const QAngle& v)
+{
+ CHECK_VALID(*this);
+ CHECK_VALID(v);
+ x-=v.x; y-=v.y; z -= v.z;
+ return *this;
+}
+
+inline QAngle& QAngle::operator*=(float fl)
+{
+ x *= fl;
+ y *= fl;
+ z *= fl;
+ CHECK_VALID(*this);
+ return *this;
+}
+
+inline QAngle& QAngle::operator/=(float fl)
+{
+ Assert( fl != 0.0f );
+ float oofl = 1.0f / fl;
+ x *= oofl;
+ y *= oofl;
+ z *= oofl;
+ CHECK_VALID(*this);
+ return *this;
+}
+
+
+//-----------------------------------------------------------------------------
+// length
+//-----------------------------------------------------------------------------
+inline vec_t QAngle::Length( ) const
+{
+ CHECK_VALID(*this);
+ return (vec_t)FastSqrt( LengthSqr( ) );
+}
+
+
+inline vec_t QAngle::LengthSqr( ) const
+{
+ CHECK_VALID(*this);
+ return x * x + y * y + z * z;
+}
+
+
+//-----------------------------------------------------------------------------
+// Vector equality with tolerance
+//-----------------------------------------------------------------------------
+inline bool QAnglesAreEqual( const QAngle& src1, const QAngle& src2, float tolerance = 0.0f )
+{
+ if (FloatMakePositive(src1.x - src2.x) > tolerance)
+ return false;
+ if (FloatMakePositive(src1.y - src2.y) > tolerance)
+ return false;
+ return (FloatMakePositive(src1.z - src2.z) <= tolerance);
+}
+
+
+//-----------------------------------------------------------------------------
+// arithmetic operations (SLOW!!)
+//-----------------------------------------------------------------------------
+#ifndef VECTOR_NO_SLOW_OPERATIONS
+
+inline QAngle QAngle::operator-(void) const
+{
+ QAngle ret(-x,-y,-z);
+ return ret;
+}
+
+inline QAngle QAngle::operator+(const QAngle& v) const
+{
+ QAngle res;
+ res.x = x + v.x;
+ res.y = y + v.y;
+ res.z = z + v.z;
+ return res;
+}
+
+inline QAngle QAngle::operator-(const QAngle& v) const
+{
+ QAngle res;
+ res.x = x - v.x;
+ res.y = y - v.y;
+ res.z = z - v.z;
+ return res;
+}
+
+inline QAngle QAngle::operator*(float fl) const
+{
+ QAngle res;
+ res.x = x * fl;
+ res.y = y * fl;
+ res.z = z * fl;
+ return res;
+}
+
+inline QAngle QAngle::operator/(float fl) const
+{
+ QAngle res;
+ res.x = x / fl;
+ res.y = y / fl;
+ res.z = z / fl;
+ return res;
+}
+
+inline QAngle operator*(float fl, const QAngle& v)
+{
+ QAngle ret( v * fl );
+ return ret;
+}
+
+#endif // VECTOR_NO_SLOW_OPERATIONS
+
+
+//-----------------------------------------------------------------------------
+// NOTE: These are not completely correct. The representations are not equivalent
+// unless the QAngle represents a rotational impulse along a coordinate axis (x,y,z)
+inline void QAngleToAngularImpulse( const QAngle &angles, AngularImpulse &impulse )
+{
+ impulse.x = angles.z;
+ impulse.y = angles.x;
+ impulse.z = angles.y;
+}
+
+inline void AngularImpulseToQAngle( const AngularImpulse &impulse, QAngle &angles )
+{
+ angles.x = impulse.y;
+ angles.y = impulse.z;
+ angles.z = impulse.x;
+}
+
+#if !defined( _X360 )
+
+FORCEINLINE vec_t InvRSquared( float const *v )
+{
+#if defined(__i386__) || defined(_M_IX86)
+ float sqrlen = v[0]*v[0]+v[1]*v[1]+v[2]*v[2] + 1.0e-10f, result;
+ _mm_store_ss(&result, _mm_rcp_ss( _mm_max_ss( _mm_set_ss(1.0f), _mm_load_ss(&sqrlen) ) ));
+ return result;
+#else
+ return 1.f/fpmax(1.f, v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
+#endif
+}
+
+FORCEINLINE vec_t InvRSquared( const Vector &v )
+{
+ return InvRSquared(&v.x);
+}
+
+#if defined(__i386__) || defined(_M_IX86)
+inline void _SSE_RSqrtInline( float a, float* out )
+{
+ __m128 xx = _mm_load_ss( &a );
+ __m128 xr = _mm_rsqrt_ss( xx );
+ __m128 xt;
+ xt = _mm_mul_ss( xr, xr );
+ xt = _mm_mul_ss( xt, xx );
+ xt = _mm_sub_ss( _mm_set_ss(3.f), xt );
+ xt = _mm_mul_ss( xt, _mm_set_ss(0.5f) );
+ xr = _mm_mul_ss( xr, xt );
+ _mm_store_ss( out, xr );
+}
+#endif
+
+// FIXME: Change this back to a #define once we get rid of the vec_t version
+FORCEINLINE float VectorNormalize( Vector& vec )
+{
+#ifndef DEBUG // stop crashing my edit-and-continue!
+ #if defined(__i386__) || defined(_M_IX86)
+ #define DO_SSE_OPTIMIZATION
+ #endif
+#endif
+
+#if defined( DO_SSE_OPTIMIZATION )
+ float sqrlen = vec.LengthSqr() + 1.0e-10f, invlen;
+ _SSE_RSqrtInline(sqrlen, &invlen);
+ vec.x *= invlen;
+ vec.y *= invlen;
+ vec.z *= invlen;
+ return sqrlen * invlen;
+#else
+ extern float (FASTCALL *pfVectorNormalize)(Vector& v);
+ return (*pfVectorNormalize)(vec);
+#endif
+}
+
+// FIXME: Obsolete version of VectorNormalize, once we remove all the friggin float*s
+FORCEINLINE float VectorNormalize( float * v )
+{
+ return VectorNormalize(*(reinterpret_cast<Vector *>(v)));
+}
+
+FORCEINLINE void VectorNormalizeFast( Vector &vec )
+{
+ VectorNormalize(vec);
+}
+
+#else
+
+FORCEINLINE float _VMX_InvRSquared( const Vector &v )
+{
+ XMVECTOR xmV = XMVector3ReciprocalLength( XMLoadVector3( v.Base() ) );
+ xmV = XMVector3Dot( xmV, xmV );
+ return xmV.x;
+}
+
+// call directly
+FORCEINLINE float _VMX_VectorNormalize( Vector &vec )
+{
+ float mag = XMVector3Length( XMLoadVector3( vec.Base() ) ).x;
+ float den = 1.f / (mag + FLT_EPSILON );
+ vec.x *= den;
+ vec.y *= den;
+ vec.z *= den;
+ return mag;
+}
+
+#define InvRSquared(x) _VMX_InvRSquared(x)
+
+// FIXME: Change this back to a #define once we get rid of the vec_t version
+FORCEINLINE float VectorNormalize( Vector& v )
+{
+ return _VMX_VectorNormalize( v );
+}
+// FIXME: Obsolete version of VectorNormalize, once we remove all the friggin float*s
+FORCEINLINE float VectorNormalize( float *pV )
+{
+ return _VMX_VectorNormalize(*(reinterpret_cast<Vector*>(pV)));
+}
+
+// call directly
+FORCEINLINE void VectorNormalizeFast( Vector &vec )
+{
+ XMVECTOR xmV = XMVector3LengthEst( XMLoadVector3( vec.Base() ) );
+ float den = 1.f / (xmV.x + FLT_EPSILON);
+ vec.x *= den;
+ vec.y *= den;
+ vec.z *= den;
+}
+
+#endif // _X360
+
+
+inline vec_t Vector::NormalizeInPlace()
+{
+ return VectorNormalize( *this );
+}
+
+inline Vector Vector::Normalized() const
+{
+ Vector norm = *this;
+ VectorNormalize( norm );
+ return norm;
+}
+
+inline bool Vector::IsLengthGreaterThan( float val ) const
+{
+ return LengthSqr() > val*val;
+}
+
+inline bool Vector::IsLengthLessThan( float val ) const
+{
+ return LengthSqr() < val*val;
+}
+
+#endif
+