mirror of
https://github.com/jmarshall23/DoomRTX.git
synced 2026-08-12 16:21:04 +02:00
2330 lines
50 KiB
C++
2330 lines
50 KiB
C++
/*
|
|
===========================================================================
|
|
|
|
IceTech GPL Source Code
|
|
Copyright (C) 2026 Justin Marshall
|
|
|
|
This file is part of the IceTech GPL Source Code (?IceTech Source Code?).
|
|
|
|
IceTech Source Code is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
IceTech Source Code is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with IceTech Source Code. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
In addition, the IceTech Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the IceTech Source Code. If not, please request a copy in writing from id Software at the address below.
|
|
|
|
If you have questions concerning this license or the applicable additional terms, you may contact in writing Justin Marshall, justinmarshall20@gmail.com
|
|
|
|
===========================================================================
|
|
*/
|
|
|
|
#ifndef __MATH_VECTOR_H__
|
|
#define __MATH_VECTOR_H__
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
Vector classes
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
#define VECTOR_EPSILON 0.001f
|
|
|
|
class idAngles;
|
|
class idPolar3;
|
|
class idMat3;
|
|
|
|
#ifdef QUAKE4
|
|
class rvAngles;
|
|
#endif
|
|
|
|
//===============================================================
|
|
//
|
|
// idVec2 - 2D vector
|
|
//
|
|
//===============================================================
|
|
|
|
class idVec2 {
|
|
public:
|
|
float x;
|
|
float y;
|
|
|
|
idVec2(void);
|
|
explicit idVec2(const float x, const float y);
|
|
|
|
void Set(const float x, const float y);
|
|
void Zero(void);
|
|
|
|
float operator[](int index) const;
|
|
float& operator[](int index);
|
|
idVec2 operator-() const;
|
|
float operator*(const idVec2& a) const;
|
|
idVec2 operator*(const float a) const;
|
|
idVec2 operator/(const float a) const;
|
|
idVec2 operator+(const idVec2& a) const;
|
|
idVec2 operator-(const idVec2& a) const;
|
|
idVec2& operator+=(const idVec2& a);
|
|
idVec2& operator-=(const idVec2& a);
|
|
idVec2& operator/=(const idVec2& a);
|
|
idVec2& operator/=(const float a);
|
|
idVec2& operator*=(const float a);
|
|
|
|
friend idVec2 operator*(const float a, const idVec2 b);
|
|
|
|
bool Compare(const idVec2& a) const; // exact compare, no epsilon
|
|
bool Compare(const idVec2& a, const float epsilon) const; // compare with epsilon
|
|
bool operator==(const idVec2& a) const; // exact compare, no epsilon
|
|
bool operator!=(const idVec2& a) const; // exact compare, no epsilon
|
|
|
|
#ifdef QUAKE4
|
|
idVec2& operator~(void); // Raven: normalize operator
|
|
#endif
|
|
|
|
float Length(void) const;
|
|
float LengthFast(void) const;
|
|
float LengthSqr(void) const;
|
|
float Normalize(void); // returns length
|
|
float NormalizeFast(void); // returns length
|
|
idVec2& Truncate(float length); // cap length
|
|
void Clamp(const idVec2& min, const idVec2& max);
|
|
void Snap(void); // snap to closest integer value
|
|
void SnapInt(void); // snap towards integer (floor)
|
|
|
|
int GetDimension(void) const;
|
|
|
|
const float* ToFloatPtr(void) const;
|
|
float* ToFloatPtr(void);
|
|
const char* ToString(int precision = 2) const;
|
|
|
|
void Lerp(const idVec2& v1, const idVec2& v2, const float l);
|
|
|
|
#ifdef QUAKE4
|
|
void EnsureIncremental(void);
|
|
#endif
|
|
};
|
|
|
|
extern idVec2 vec2_origin;
|
|
#define vec2_zero vec2_origin
|
|
|
|
ID_INLINE idVec2::idVec2(void) {
|
|
}
|
|
|
|
ID_INLINE idVec2::idVec2(const float x, const float y) {
|
|
this->x = x;
|
|
this->y = y;
|
|
}
|
|
|
|
ID_INLINE void idVec2::Set(const float x, const float y) {
|
|
this->x = x;
|
|
this->y = y;
|
|
}
|
|
|
|
ID_INLINE void idVec2::Zero(void) {
|
|
x = y = 0.0f;
|
|
}
|
|
|
|
ID_INLINE bool idVec2::Compare(const idVec2& a) const {
|
|
return ((x == a.x) && (y == a.y));
|
|
}
|
|
|
|
ID_INLINE bool idVec2::Compare(const idVec2& a, const float epsilon) const {
|
|
if (idMath::Fabs(x - a.x) > epsilon) {
|
|
return false;
|
|
}
|
|
|
|
if (idMath::Fabs(y - a.y) > epsilon) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
ID_INLINE bool idVec2::operator==(const idVec2& a) const {
|
|
return Compare(a);
|
|
}
|
|
|
|
ID_INLINE bool idVec2::operator!=(const idVec2& a) const {
|
|
return !Compare(a);
|
|
}
|
|
|
|
ID_INLINE float idVec2::operator[](int index) const {
|
|
return (&x)[index];
|
|
}
|
|
|
|
ID_INLINE float& idVec2::operator[](int index) {
|
|
return (&x)[index];
|
|
}
|
|
|
|
#ifdef QUAKE4
|
|
ID_INLINE idVec2& idVec2::operator~(void) {
|
|
Normalize();
|
|
return *this;
|
|
}
|
|
#endif
|
|
|
|
ID_INLINE float idVec2::Length(void) const {
|
|
return (float)idMath::Sqrt(x * x + y * y);
|
|
}
|
|
|
|
ID_INLINE float idVec2::LengthFast(void) const {
|
|
float sqrLength;
|
|
|
|
sqrLength = x * x + y * y;
|
|
return sqrLength * idMath::RSqrt(sqrLength);
|
|
}
|
|
|
|
ID_INLINE float idVec2::LengthSqr(void) const {
|
|
return (x * x + y * y);
|
|
}
|
|
|
|
ID_INLINE float idVec2::Normalize(void) {
|
|
float sqrLength, invLength;
|
|
|
|
sqrLength = x * x + y * y;
|
|
invLength = idMath::InvSqrt(sqrLength);
|
|
x *= invLength;
|
|
y *= invLength;
|
|
return invLength * sqrLength;
|
|
}
|
|
|
|
ID_INLINE float idVec2::NormalizeFast(void) {
|
|
float lengthSqr, invLength;
|
|
|
|
lengthSqr = x * x + y * y;
|
|
invLength = idMath::RSqrt(lengthSqr);
|
|
x *= invLength;
|
|
y *= invLength;
|
|
return invLength * lengthSqr;
|
|
}
|
|
|
|
ID_INLINE idVec2& idVec2::Truncate(float length) {
|
|
float length2;
|
|
float ilength;
|
|
|
|
if (!length) {
|
|
Zero();
|
|
}
|
|
else {
|
|
length2 = LengthSqr();
|
|
if (length2 > length * length) {
|
|
ilength = length * idMath::InvSqrt(length2);
|
|
x *= ilength;
|
|
y *= ilength;
|
|
}
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
ID_INLINE void idVec2::Clamp(const idVec2& min, const idVec2& max) {
|
|
if (x < min.x) {
|
|
x = min.x;
|
|
}
|
|
else if (x > max.x) {
|
|
x = max.x;
|
|
}
|
|
if (y < min.y) {
|
|
y = min.y;
|
|
}
|
|
else if (y > max.y) {
|
|
y = max.y;
|
|
}
|
|
}
|
|
|
|
ID_INLINE void idVec2::Snap(void) {
|
|
x = floor(x + 0.5f);
|
|
y = floor(y + 0.5f);
|
|
}
|
|
|
|
ID_INLINE void idVec2::SnapInt(void) {
|
|
x = float(int(x));
|
|
y = float(int(y));
|
|
}
|
|
|
|
ID_INLINE idVec2 idVec2::operator-() const {
|
|
return idVec2(-x, -y);
|
|
}
|
|
|
|
ID_INLINE idVec2 idVec2::operator-(const idVec2& a) const {
|
|
return idVec2(x - a.x, y - a.y);
|
|
}
|
|
|
|
ID_INLINE float idVec2::operator*(const idVec2& a) const {
|
|
return x * a.x + y * a.y;
|
|
}
|
|
|
|
ID_INLINE idVec2 idVec2::operator*(const float a) const {
|
|
return idVec2(x * a, y * a);
|
|
}
|
|
|
|
ID_INLINE idVec2 idVec2::operator/(const float a) const {
|
|
float inva = 1.0f / a;
|
|
return idVec2(x * inva, y * inva);
|
|
}
|
|
|
|
ID_INLINE idVec2 operator*(const float a, const idVec2 b) {
|
|
return idVec2(b.x * a, b.y * a);
|
|
}
|
|
|
|
ID_INLINE idVec2 idVec2::operator+(const idVec2& a) const {
|
|
return idVec2(x + a.x, y + a.y);
|
|
}
|
|
|
|
ID_INLINE idVec2& idVec2::operator+=(const idVec2& a) {
|
|
x += a.x;
|
|
y += a.y;
|
|
|
|
return *this;
|
|
}
|
|
|
|
ID_INLINE idVec2& idVec2::operator/=(const idVec2& a) {
|
|
x /= a.x;
|
|
y /= a.y;
|
|
|
|
return *this;
|
|
}
|
|
|
|
ID_INLINE idVec2& idVec2::operator/=(const float a) {
|
|
float inva = 1.0f / a;
|
|
x *= inva;
|
|
y *= inva;
|
|
|
|
return *this;
|
|
}
|
|
|
|
ID_INLINE idVec2& idVec2::operator-=(const idVec2& a) {
|
|
x -= a.x;
|
|
y -= a.y;
|
|
|
|
return *this;
|
|
}
|
|
|
|
ID_INLINE idVec2& idVec2::operator*=(const float a) {
|
|
x *= a;
|
|
y *= a;
|
|
|
|
return *this;
|
|
}
|
|
|
|
ID_INLINE int idVec2::GetDimension(void) const {
|
|
return 2;
|
|
}
|
|
|
|
ID_INLINE const float* idVec2::ToFloatPtr(void) const {
|
|
return &x;
|
|
}
|
|
|
|
ID_INLINE float* idVec2::ToFloatPtr(void) {
|
|
return &x;
|
|
}
|
|
|
|
|
|
#ifdef QUAKE4
|
|
ID_INLINE void idVec2::EnsureIncremental(void) {
|
|
if (x >= y) {
|
|
float temp = x;
|
|
x = y;
|
|
y = temp;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
//===============================================================
|
|
//
|
|
// idVec3 - 3D vector
|
|
//
|
|
//===============================================================
|
|
|
|
#ifdef PREY
|
|
// HUMANHEAD pdm: support for 6 bit vector compression, direction masks
|
|
#define INDEX_IN_MASK(mask, index) ( ((mask) & (1<<(index)) ) != 0 )
|
|
#define MASK_NEGX 0x0001
|
|
#define MASK_POSX 0x0002
|
|
#define MASK_NEGY 0x0004
|
|
#define MASK_POSY 0x0008
|
|
#define MASK_NEGZ 0x0010
|
|
#define MASK_POSZ 0x0020
|
|
// HUMANHEAD END
|
|
#endif
|
|
|
|
class idVec3 {
|
|
public:
|
|
float x;
|
|
float y;
|
|
float z;
|
|
|
|
idVec3(void);
|
|
explicit idVec3(const float x, const float y, const float z);
|
|
|
|
void Set(const float x, const float y, const float z);
|
|
void Zero(void);
|
|
|
|
float operator[](const int index) const;
|
|
float& operator[](const int index);
|
|
idVec3 operator-() const;
|
|
idVec3& operator=(const idVec3& a); // required because of a msvc 6 & 7 bug
|
|
#ifdef QUAKE4
|
|
idVec3& operator=(const idVec2& a);
|
|
idVec3& operator*=(const idVec3& a);
|
|
#endif
|
|
float operator*(const idVec3& a) const;
|
|
idVec3 operator*(const float a) const;
|
|
idVec3 operator/(const float a) const;
|
|
idVec3 operator+(const idVec3& a) const;
|
|
idVec3 operator-(const idVec3& a) const;
|
|
idVec3& operator+=(const idVec3& a);
|
|
idVec3& operator-=(const idVec3& a);
|
|
idVec3& operator/=(const idVec3& a);
|
|
idVec3& operator/=(const float a);
|
|
idVec3& operator*=(const float a);
|
|
|
|
friend idVec3 operator*(const float a, const idVec3 b);
|
|
|
|
bool Compare(const idVec3& a) const; // exact compare, no epsilon
|
|
bool Compare(const idVec3& a, const float epsilon) const; // compare with epsilon
|
|
bool operator==(const idVec3& a) const; // exact compare, no epsilon
|
|
bool operator!=(const idVec3& a) const; // exact compare, no epsilon
|
|
|
|
bool FixDegenerateNormal(void); // fix degenerate axial cases
|
|
bool FixDenormals(void); // change tiny numbers to zero
|
|
|
|
idVec3 Cross(const idVec3& a) const;
|
|
idVec3& Cross(const idVec3& a, const idVec3& b);
|
|
#ifdef QUAKE4
|
|
idVec3& operator~(void);
|
|
#endif
|
|
float Length(void) const;
|
|
float LengthSqr(void) const;
|
|
float LengthFast(void) const;
|
|
float Normalize(void); // returns length
|
|
float NormalizeFast(void); // returns length
|
|
idVec3& Truncate(float length); // cap length
|
|
void Clamp(const idVec3& min, const idVec3& max);
|
|
#ifdef QUAKE4
|
|
void ClampMin(const float& minx, const float& miny, const float& minz);
|
|
#endif
|
|
void Snap(void); // snap to closest integer value
|
|
void SnapInt(void); // snap towards integer (floor)
|
|
|
|
int GetDimension(void) const;
|
|
|
|
float ToYaw(void) const;
|
|
float ToPitch(void) const;
|
|
idAngles ToAngles(void) const;
|
|
idPolar3 ToPolar(void) const;
|
|
idMat3 ToMat3(void) const; // vector should be normalized
|
|
const idVec2& ToVec2(void) const;
|
|
idVec2& ToVec2(void);
|
|
const float* ToFloatPtr(void) const;
|
|
float* ToFloatPtr(void);
|
|
const char* ToString(int precision = 2) const;
|
|
|
|
#ifdef QUAKE4
|
|
idMat3 ToMat3(int axis) const; // vector should be normalized
|
|
idVec3 Random(const idVec3& range, idRandom& random) const;
|
|
#endif
|
|
|
|
void NormalVectors(idVec3& left, idVec3& down) const; // vector should be normalized
|
|
void OrthogonalBasis(idVec3& left, idVec3& up) const;
|
|
|
|
void ProjectOntoPlane(const idVec3& normal, const float overBounce = 1.0f);
|
|
bool ProjectAlongPlane(const idVec3& normal, const float epsilon, const float overBounce = 1.0f);
|
|
void ProjectSelfOntoSphere(const float radius);
|
|
#ifdef QUAKE4
|
|
float ProjectOntoVector(const idVec3& U);
|
|
#endif
|
|
|
|
void Lerp(const idVec3& v1, const idVec3& v2, const float l);
|
|
void SLerp(const idVec3& v1, const idVec3& v2, const float l);
|
|
|
|
#ifdef QUAKE4
|
|
void EnsureIncremental(void);
|
|
int GetLargestAxis(void) const;
|
|
rvAngles ToRadians(void) const;
|
|
idMat3& ToMat3(idMat3& mat) const; // vector should be normalized
|
|
float Dist(const idVec3& Pt) const;
|
|
float Dist2(const idVec3& Pt) const;
|
|
float Dist2XY(const idVec3& Pt) const;
|
|
float DistXY(const idVec3& Pt) const;
|
|
float AreaParallelPipid(const idVec3& A, const idVec3& B) const;
|
|
bool IsLeftOf(const idVec3& Start, const idVec3& End) const;
|
|
float DistToLineSeg(const idVec3& Start, const idVec3& End, float& Scale) const;
|
|
bool ProjectToLineSeg(const idVec3& Start, const idVec3& End);
|
|
bool IsZero(void) const;
|
|
#endif
|
|
|
|
idVec3 ToNormal() const;
|
|
#ifdef PREY
|
|
// HUMANHEAD nla - Returns a Mat3 with Z up instead of down
|
|
idMat3 hhToMat3(void) const; // vector should be normalized
|
|
int DirectionMask() const; // calculate direction bitmask
|
|
idVec3(int directionMask); // construct from direction bitmask
|
|
// HUMANHEAD END
|
|
#endif
|
|
};
|
|
|
|
extern idVec3 vec3_origin;
|
|
#define vec3_zero vec3_origin
|
|
|
|
|
|
ID_INLINE idVec3 idVec3::ToNormal() const {
|
|
float sqrLength, invLength;
|
|
|
|
sqrLength = x * x + y * y + z * z;
|
|
invLength = idMath::InvSqrt(sqrLength);
|
|
return *this * invLength;
|
|
}
|
|
|
|
ID_INLINE idVec3::idVec3(void) {
|
|
}
|
|
|
|
ID_INLINE idVec3::idVec3(const float x, const float y, const float z) {
|
|
this->x = x;
|
|
this->y = y;
|
|
this->z = z;
|
|
}
|
|
|
|
ID_INLINE float idVec3::operator[](const int index) const {
|
|
return (&x)[index];
|
|
}
|
|
|
|
ID_INLINE float& idVec3::operator[](const int index) {
|
|
return (&x)[index];
|
|
}
|
|
|
|
ID_INLINE void idVec3::Set(const float x, const float y, const float z) {
|
|
this->x = x;
|
|
this->y = y;
|
|
this->z = z;
|
|
}
|
|
|
|
ID_INLINE void idVec3::Zero(void) {
|
|
x = y = z = 0.0f;
|
|
}
|
|
|
|
ID_INLINE idVec3 idVec3::operator-() const {
|
|
return idVec3(-x, -y, -z);
|
|
}
|
|
|
|
ID_INLINE idVec3& idVec3::operator=(const idVec3& a) {
|
|
x = a.x;
|
|
y = a.y;
|
|
z = a.z;
|
|
return *this;
|
|
}
|
|
|
|
#ifdef QUAKE4
|
|
ID_INLINE idVec3& idVec3::operator=(const idVec2& a) {
|
|
x = a.x;
|
|
y = a.y;
|
|
return *this;
|
|
}
|
|
|
|
ID_INLINE idVec3& idVec3::operator*=(const idVec3& a) {
|
|
x *= a.x;
|
|
y *= a.y;
|
|
z *= a.z;
|
|
return *this;
|
|
}
|
|
#endif
|
|
|
|
ID_INLINE idVec3 idVec3::operator-(const idVec3& a) const {
|
|
return idVec3(x - a.x, y - a.y, z - a.z);
|
|
}
|
|
|
|
ID_INLINE float idVec3::operator*(const idVec3& a) const {
|
|
return x * a.x + y * a.y + z * a.z;
|
|
}
|
|
|
|
ID_INLINE idVec3 idVec3::operator*(const float a) const {
|
|
return idVec3(x * a, y * a, z * a);
|
|
}
|
|
|
|
ID_INLINE idVec3 idVec3::operator/(const float a) const {
|
|
float inva = 1.0f / a;
|
|
return idVec3(x * inva, y * inva, z * inva);
|
|
}
|
|
|
|
ID_INLINE idVec3 operator*(const float a, const idVec3 b) {
|
|
return idVec3(b.x * a, b.y * a, b.z * a);
|
|
}
|
|
|
|
ID_INLINE idVec3 idVec3::operator+(const idVec3& a) const {
|
|
return idVec3(x + a.x, y + a.y, z + a.z);
|
|
}
|
|
|
|
ID_INLINE idVec3& idVec3::operator+=(const idVec3& a) {
|
|
x += a.x;
|
|
y += a.y;
|
|
z += a.z;
|
|
|
|
return *this;
|
|
}
|
|
|
|
ID_INLINE idVec3& idVec3::operator/=(const idVec3& a) {
|
|
x /= a.x;
|
|
y /= a.y;
|
|
z /= a.z;
|
|
|
|
return *this;
|
|
}
|
|
|
|
ID_INLINE idVec3& idVec3::operator/=(const float a) {
|
|
float inva = 1.0f / a;
|
|
x *= inva;
|
|
y *= inva;
|
|
z *= inva;
|
|
|
|
return *this;
|
|
}
|
|
|
|
ID_INLINE idVec3& idVec3::operator-=(const idVec3& a) {
|
|
x -= a.x;
|
|
y -= a.y;
|
|
z -= a.z;
|
|
|
|
return *this;
|
|
}
|
|
|
|
ID_INLINE idVec3& idVec3::operator*=(const float a) {
|
|
x *= a;
|
|
y *= a;
|
|
z *= a;
|
|
|
|
return *this;
|
|
}
|
|
|
|
ID_INLINE bool idVec3::Compare(const idVec3& a) const {
|
|
return ((x == a.x) && (y == a.y) && (z == a.z));
|
|
}
|
|
|
|
ID_INLINE bool idVec3::Compare(const idVec3& a, const float epsilon) const {
|
|
if (idMath::Fabs(x - a.x) > epsilon) {
|
|
return false;
|
|
}
|
|
|
|
if (idMath::Fabs(y - a.y) > epsilon) {
|
|
return false;
|
|
}
|
|
|
|
if (idMath::Fabs(z - a.z) > epsilon) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
ID_INLINE bool idVec3::operator==(const idVec3& a) const {
|
|
return Compare(a);
|
|
}
|
|
|
|
ID_INLINE bool idVec3::operator!=(const idVec3& a) const {
|
|
return !Compare(a);
|
|
}
|
|
|
|
ID_INLINE float idVec3::NormalizeFast(void) {
|
|
float sqrLength, invLength;
|
|
|
|
sqrLength = x * x + y * y + z * z;
|
|
invLength = idMath::RSqrt(sqrLength);
|
|
x *= invLength;
|
|
y *= invLength;
|
|
z *= invLength;
|
|
return invLength * sqrLength;
|
|
}
|
|
|
|
ID_INLINE bool idVec3::FixDegenerateNormal(void) {
|
|
if (x == 0.0f) {
|
|
if (y == 0.0f) {
|
|
if (z > 0.0f) {
|
|
if (z != 1.0f) {
|
|
z = 1.0f;
|
|
return true;
|
|
}
|
|
}
|
|
else {
|
|
if (z != -1.0f) {
|
|
z = -1.0f;
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
else if (z == 0.0f) {
|
|
if (y > 0.0f) {
|
|
if (y != 1.0f) {
|
|
y = 1.0f;
|
|
return true;
|
|
}
|
|
}
|
|
else {
|
|
if (y != -1.0f) {
|
|
y = -1.0f;
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
else if (y == 0.0f) {
|
|
if (z == 0.0f) {
|
|
if (x > 0.0f) {
|
|
if (x != 1.0f) {
|
|
x = 1.0f;
|
|
return true;
|
|
}
|
|
}
|
|
else {
|
|
if (x != -1.0f) {
|
|
x = -1.0f;
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
if (idMath::Fabs(x) == 1.0f) {
|
|
if (y != 0.0f || z != 0.0f) {
|
|
y = z = 0.0f;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
else if (idMath::Fabs(y) == 1.0f) {
|
|
if (x != 0.0f || z != 0.0f) {
|
|
x = z = 0.0f;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
else if (idMath::Fabs(z) == 1.0f) {
|
|
if (x != 0.0f || y != 0.0f) {
|
|
x = y = 0.0f;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
ID_INLINE bool idVec3::FixDenormals(void) {
|
|
bool denormal = false;
|
|
if (fabs(x) < 1e-30f) {
|
|
x = 0.0f;
|
|
denormal = true;
|
|
}
|
|
if (fabs(y) < 1e-30f) {
|
|
y = 0.0f;
|
|
denormal = true;
|
|
}
|
|
if (fabs(z) < 1e-30f) {
|
|
z = 0.0f;
|
|
denormal = true;
|
|
}
|
|
return denormal;
|
|
}
|
|
|
|
ID_INLINE idVec3 idVec3::Cross(const idVec3& a) const {
|
|
return idVec3(y * a.z - z * a.y, z * a.x - x * a.z, x * a.y - y * a.x);
|
|
}
|
|
|
|
ID_INLINE idVec3& idVec3::Cross(const idVec3& a, const idVec3& b) {
|
|
x = a.y * b.z - a.z * b.y;
|
|
y = a.z * b.x - a.x * b.z;
|
|
z = a.x * b.y - a.y * b.x;
|
|
|
|
return *this;
|
|
}
|
|
|
|
#ifdef QUAKE4
|
|
ID_INLINE idVec3& idVec3::operator~(void) {
|
|
Normalize();
|
|
return *this;
|
|
}
|
|
#endif
|
|
|
|
ID_INLINE float idVec3::Length(void) const {
|
|
return (float)idMath::Sqrt(x * x + y * y + z * z);
|
|
}
|
|
|
|
ID_INLINE float idVec3::LengthSqr(void) const {
|
|
return (x * x + y * y + z * z);
|
|
}
|
|
|
|
ID_INLINE float idVec3::LengthFast(void) const {
|
|
float sqrLength;
|
|
|
|
sqrLength = x * x + y * y + z * z;
|
|
return sqrLength * idMath::RSqrt(sqrLength);
|
|
}
|
|
|
|
ID_INLINE float idVec3::Normalize(void) {
|
|
float sqrLength, invLength;
|
|
|
|
sqrLength = x * x + y * y + z * z;
|
|
#ifdef QUAKE4
|
|
if (!sqrLength) {
|
|
return 0.0f;
|
|
}
|
|
#endif
|
|
invLength = idMath::InvSqrt(sqrLength);
|
|
x *= invLength;
|
|
y *= invLength;
|
|
z *= invLength;
|
|
return invLength * sqrLength;
|
|
}
|
|
|
|
ID_INLINE idVec3& idVec3::Truncate(float length) {
|
|
float length2;
|
|
float ilength;
|
|
|
|
if (!length) {
|
|
Zero();
|
|
}
|
|
else {
|
|
length2 = LengthSqr();
|
|
if (length2 > length * length) {
|
|
ilength = length * idMath::InvSqrt(length2);
|
|
x *= ilength;
|
|
y *= ilength;
|
|
z *= ilength;
|
|
}
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
ID_INLINE void idVec3::Clamp(const idVec3& min, const idVec3& max) {
|
|
if (x < min.x) {
|
|
x = min.x;
|
|
}
|
|
else if (x > max.x) {
|
|
x = max.x;
|
|
}
|
|
if (y < min.y) {
|
|
y = min.y;
|
|
}
|
|
else if (y > max.y) {
|
|
y = max.y;
|
|
}
|
|
if (z < min.z) {
|
|
z = min.z;
|
|
}
|
|
else if (z > max.z) {
|
|
z = max.z;
|
|
}
|
|
}
|
|
|
|
#ifdef QUAKE4
|
|
ID_INLINE void idVec3::ClampMin(const float& minx, const float& miny, const float& minz) {
|
|
if (x < minx) {
|
|
x = minx;
|
|
}
|
|
if (y < miny) {
|
|
y = miny;
|
|
}
|
|
if (z < minz) {
|
|
z = minz;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
ID_INLINE void idVec3::Snap(void) {
|
|
x = floor(x + 0.5f);
|
|
y = floor(y + 0.5f);
|
|
z = floor(z + 0.5f);
|
|
}
|
|
|
|
ID_INLINE void idVec3::SnapInt(void) {
|
|
x = float(int(x));
|
|
y = float(int(y));
|
|
z = float(int(z));
|
|
}
|
|
|
|
ID_INLINE int idVec3::GetDimension(void) const {
|
|
return 3;
|
|
}
|
|
|
|
ID_INLINE const idVec2& idVec3::ToVec2(void) const {
|
|
return *reinterpret_cast<const idVec2*>(this);
|
|
}
|
|
|
|
ID_INLINE idVec2& idVec3::ToVec2(void) {
|
|
return *reinterpret_cast<idVec2*>(this);
|
|
}
|
|
|
|
ID_INLINE const float* idVec3::ToFloatPtr(void) const {
|
|
return &x;
|
|
}
|
|
|
|
ID_INLINE float* idVec3::ToFloatPtr(void) {
|
|
return &x;
|
|
}
|
|
|
|
ID_INLINE void idVec3::NormalVectors(idVec3& left, idVec3& down) const {
|
|
float d;
|
|
|
|
d = x * x + y * y;
|
|
if (!d) {
|
|
left[0] = 1;
|
|
left[1] = 0;
|
|
left[2] = 0;
|
|
}
|
|
else {
|
|
d = idMath::InvSqrt(d);
|
|
left[0] = -y * d;
|
|
left[1] = x * d;
|
|
left[2] = 0;
|
|
}
|
|
down = left.Cross(*this);
|
|
}
|
|
|
|
ID_INLINE void idVec3::OrthogonalBasis(idVec3& left, idVec3& up) const {
|
|
float l, s;
|
|
|
|
if (idMath::Fabs(z) > 0.7f) {
|
|
l = y * y + z * z;
|
|
s = idMath::InvSqrt(l);
|
|
up[0] = 0;
|
|
up[1] = z * s;
|
|
up[2] = -y * s;
|
|
left[0] = l * s;
|
|
left[1] = -x * up[2];
|
|
left[2] = x * up[1];
|
|
}
|
|
else {
|
|
l = x * x + y * y;
|
|
s = idMath::InvSqrt(l);
|
|
left[0] = -y * s;
|
|
left[1] = x * s;
|
|
left[2] = 0;
|
|
up[0] = -z * left[1];
|
|
up[1] = z * left[0];
|
|
up[2] = l * s;
|
|
}
|
|
}
|
|
|
|
ID_INLINE void idVec3::ProjectOntoPlane(const idVec3& normal, const float overBounce) {
|
|
float backoff;
|
|
|
|
backoff = *this * normal;
|
|
|
|
if (overBounce != 1.0) {
|
|
if (backoff < 0) {
|
|
backoff *= overBounce;
|
|
}
|
|
else {
|
|
backoff /= overBounce;
|
|
}
|
|
}
|
|
|
|
*this -= backoff * normal;
|
|
}
|
|
|
|
#ifdef QUAKE4
|
|
ID_INLINE float idVec3::ProjectOntoVector(const idVec3& U) {
|
|
float scale = (*this * U) / U.LengthSqr();
|
|
*this = U;
|
|
*this *= scale;
|
|
return scale;
|
|
}
|
|
#endif
|
|
|
|
ID_INLINE bool idVec3::ProjectAlongPlane(const idVec3& normal, const float epsilon, const float overBounce) {
|
|
idVec3 cross;
|
|
float len;
|
|
|
|
cross = this->Cross(normal).Cross((*this));
|
|
// normalize so a fixed epsilon can be used
|
|
cross.Normalize();
|
|
len = normal * cross;
|
|
if (idMath::Fabs(len) < epsilon) {
|
|
return false;
|
|
}
|
|
cross *= overBounce * (normal * (*this)) / len;
|
|
(*this) -= cross;
|
|
return true;
|
|
}
|
|
|
|
|
|
#ifdef QUAKE4
|
|
ID_INLINE void idVec3::EnsureIncremental(void) {
|
|
float temp;
|
|
if (y < x) {
|
|
temp = x;
|
|
x = y;
|
|
y = temp;
|
|
}
|
|
if (z < y) {
|
|
temp = y;
|
|
y = z;
|
|
z = temp;
|
|
}
|
|
if (y < x) {
|
|
temp = x;
|
|
x = y;
|
|
y = temp;
|
|
}
|
|
}
|
|
|
|
ID_INLINE int idVec3::GetLargestAxis(void) const {
|
|
float a = fabs(x);
|
|
float b = fabs(y);
|
|
float c = fabs(z);
|
|
if (a >= b && a >= c) {
|
|
return 0;
|
|
}
|
|
if (b >= a && b >= c) {
|
|
return 1;
|
|
}
|
|
if (c >= a && c >= b) {
|
|
return 2;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
ID_INLINE idVec3 idVec3::Random(const idVec3& range, idRandom& random) const {
|
|
idVec3 v(*this);
|
|
for (int ix = 0; ix < GetDimension(); ix++) {
|
|
v[ix] += v[ix] * range[ix] * random.CRandomFloat();
|
|
}
|
|
return v;
|
|
}
|
|
|
|
ID_INLINE float idVec3::Dist(const idVec3& Pt) const {
|
|
idVec3 delta(x, y, z);
|
|
delta = delta - Pt;
|
|
return delta.LengthFast();
|
|
}
|
|
|
|
ID_INLINE float idVec3::Dist2(const idVec3& Pt) const {
|
|
return ((Pt.x - x) * (Pt.x - x) + (Pt.y - y) * (Pt.y - y) + (Pt.z - z) * (Pt.z - z));
|
|
}
|
|
|
|
ID_INLINE float idVec3::Dist2XY(const idVec3& Pt) const {
|
|
return ((Pt.x - x) * (Pt.x - x) + (Pt.y - y) * (Pt.y - y));
|
|
}
|
|
|
|
ID_INLINE float idVec3::DistXY(const idVec3& Pt) const {
|
|
idVec3 delta(x, y, Pt.z);
|
|
delta = delta - Pt;
|
|
return delta.LengthFast();
|
|
}
|
|
|
|
ID_INLINE float idVec3::AreaParallelPipid(const idVec3& A, const idVec3& B) const {
|
|
return ((A.x * B.y - A.y * B.x) + (B.x * y - x * B.y) + (x * A.y - A.x * y));
|
|
}
|
|
|
|
ID_INLINE bool idVec3::IsLeftOf(const idVec3& Start, const idVec3& End) const {
|
|
return (AreaParallelPipid(Start, End) > 0.0f);
|
|
}
|
|
|
|
ID_INLINE float idVec3::DistToLineSeg(const idVec3& Start, const idVec3& End, float& Scale) const {
|
|
idVec3 U;
|
|
idVec3 V;
|
|
float ULen2;
|
|
V = *this - Start;
|
|
U = End - Start;
|
|
ULen2 = U.LengthSqr();
|
|
Scale = (V * U / ULen2);
|
|
if (Scale < 0.0f) {
|
|
return Dist(Start);
|
|
}
|
|
if (Scale > 1.0f) {
|
|
return Dist(End);
|
|
}
|
|
return Dist(Start + (U * Scale));
|
|
}
|
|
|
|
ID_INLINE bool idVec3::ProjectToLineSeg(const idVec3& Start, const idVec3& End) {
|
|
idVec3 U;
|
|
idVec3 V;
|
|
float ULen2;
|
|
float Scale;
|
|
V = *this - Start;
|
|
U = End - Start;
|
|
ULen2 = U.LengthSqr();
|
|
Scale = (V * U / ULen2);
|
|
if (Scale < 0.0f) {
|
|
*this = Start;
|
|
return false;
|
|
}
|
|
else if (Scale > 1.0f) {
|
|
*this = End;
|
|
return false;
|
|
}
|
|
else {
|
|
*this = Start + (U * Scale);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
ID_INLINE bool idVec3::IsZero(void) const {
|
|
return (((*(const unsigned long*)&(x)) | (*(const unsigned long*)&(y)) | (*(const unsigned long*)&(z))) & ~(1 << 31)) == 0;
|
|
}
|
|
#endif
|
|
|
|
//===============================================================
|
|
//
|
|
// idVec4 - 4D vector
|
|
//
|
|
//===============================================================
|
|
|
|
class idVec4 {
|
|
public:
|
|
float x;
|
|
float y;
|
|
float z;
|
|
float w;
|
|
|
|
idVec4(void);
|
|
explicit idVec4(const float x, const float y, const float z, const float w);
|
|
|
|
void Set(const float x, const float y, const float z, const float w);
|
|
void Zero(void);
|
|
|
|
float operator[](const int index) const;
|
|
float& operator[](const int index);
|
|
idVec4 operator-() const;
|
|
float operator*(const idVec4& a) const;
|
|
idVec4 operator*(const float a) const;
|
|
idVec4 operator/(const float a) const;
|
|
idVec4 operator+(const idVec4& a) const;
|
|
idVec4 operator-(const idVec4& a) const;
|
|
idVec4& operator+=(const idVec4& a);
|
|
idVec4& operator-=(const idVec4& a);
|
|
idVec4& operator/=(const idVec4& a);
|
|
idVec4& operator/=(const float a);
|
|
idVec4& operator*=(const float a);
|
|
|
|
friend idVec4 operator*(const float a, const idVec4 b);
|
|
|
|
#ifdef QUAKE4
|
|
operator int(void);
|
|
#endif
|
|
|
|
bool Compare(const idVec4& a) const; // exact compare, no epsilon
|
|
bool Compare(const idVec4& a, const float epsilon) const; // compare with epsilon
|
|
bool operator==(const idVec4& a) const; // exact compare, no epsilon
|
|
bool operator!=(const idVec4& a) const; // exact compare, no epsilon
|
|
|
|
#ifdef QUAKE4
|
|
idVec4& operator~(void);
|
|
#endif
|
|
|
|
float Length(void) const;
|
|
float LengthSqr(void) const;
|
|
float Normalize(void); // returns length
|
|
float NormalizeFast(void); // returns length
|
|
|
|
int GetDimension(void) const;
|
|
|
|
const idVec2& ToVec2(void) const;
|
|
idVec2& ToVec2(void);
|
|
const idVec3& ToVec3(void) const;
|
|
idVec3& ToVec3(void);
|
|
const float* ToFloatPtr(void) const;
|
|
float* ToFloatPtr(void);
|
|
const char* ToString(int precision = 2) const;
|
|
|
|
void Lerp(const idVec4& v1, const idVec4& v2, const float l);
|
|
};
|
|
|
|
extern idVec4 vec4_origin;
|
|
extern idVec4 vec4_one;
|
|
#define vec4_zero vec4_origin
|
|
|
|
ID_INLINE idVec4::idVec4(void) {
|
|
}
|
|
|
|
ID_INLINE idVec4::idVec4(const float x, const float y, const float z, const float w) {
|
|
this->x = x;
|
|
this->y = y;
|
|
this->z = z;
|
|
this->w = w;
|
|
}
|
|
|
|
ID_INLINE void idVec4::Set(const float x, const float y, const float z, const float w) {
|
|
this->x = x;
|
|
this->y = y;
|
|
this->z = z;
|
|
this->w = w;
|
|
}
|
|
|
|
ID_INLINE void idVec4::Zero(void) {
|
|
x = y = z = w = 0.0f;
|
|
}
|
|
|
|
ID_INLINE float idVec4::operator[](int index) const {
|
|
return (&x)[index];
|
|
}
|
|
|
|
ID_INLINE float& idVec4::operator[](int index) {
|
|
return (&x)[index];
|
|
}
|
|
|
|
ID_INLINE idVec4 idVec4::operator-() const {
|
|
return idVec4(-x, -y, -z, -w);
|
|
}
|
|
|
|
ID_INLINE idVec4 idVec4::operator-(const idVec4& a) const {
|
|
return idVec4(x - a.x, y - a.y, z - a.z, w - a.w);
|
|
}
|
|
|
|
ID_INLINE float idVec4::operator*(const idVec4& a) const {
|
|
return x * a.x + y * a.y + z * a.z + w * a.w;
|
|
}
|
|
|
|
ID_INLINE idVec4 idVec4::operator*(const float a) const {
|
|
return idVec4(x * a, y * a, z * a, w * a);
|
|
}
|
|
|
|
ID_INLINE idVec4 idVec4::operator/(const float a) const {
|
|
float inva = 1.0f / a;
|
|
return idVec4(x * inva, y * inva, z * inva, w * inva);
|
|
}
|
|
|
|
ID_INLINE idVec4 operator*(const float a, const idVec4 b) {
|
|
return idVec4(b.x * a, b.y * a, b.z * a, b.w * a);
|
|
}
|
|
|
|
ID_INLINE idVec4 idVec4::operator+(const idVec4& a) const {
|
|
return idVec4(x + a.x, y + a.y, z + a.z, w + a.w);
|
|
}
|
|
|
|
ID_INLINE idVec4& idVec4::operator+=(const idVec4& a) {
|
|
x += a.x;
|
|
y += a.y;
|
|
z += a.z;
|
|
w += a.w;
|
|
|
|
return *this;
|
|
}
|
|
|
|
ID_INLINE idVec4& idVec4::operator/=(const idVec4& a) {
|
|
x /= a.x;
|
|
y /= a.y;
|
|
z /= a.z;
|
|
w /= a.w;
|
|
|
|
return *this;
|
|
}
|
|
|
|
ID_INLINE idVec4& idVec4::operator/=(const float a) {
|
|
float inva = 1.0f / a;
|
|
x *= inva;
|
|
y *= inva;
|
|
z *= inva;
|
|
w *= inva;
|
|
|
|
return *this;
|
|
}
|
|
|
|
ID_INLINE idVec4& idVec4::operator-=(const idVec4& a) {
|
|
x -= a.x;
|
|
y -= a.y;
|
|
z -= a.z;
|
|
w -= a.w;
|
|
|
|
return *this;
|
|
}
|
|
|
|
ID_INLINE idVec4& idVec4::operator*=(const float a) {
|
|
x *= a;
|
|
y *= a;
|
|
z *= a;
|
|
w *= a;
|
|
|
|
return *this;
|
|
}
|
|
|
|
#ifdef QUAKE4
|
|
ID_INLINE idVec4::operator int(void) {
|
|
int retval;
|
|
#if defined( _LITTLE_ENDIAN ) || defined( _WIN32 ) || defined( WIN32 )
|
|
retval = ((int)(x * 255.0f)) << 0;
|
|
retval |= ((int)(y * 255.0f)) << 8;
|
|
retval |= ((int)(z * 255.0f)) << 16;
|
|
retval |= ((int)(w * 255.0f)) << 24;
|
|
#else
|
|
retval = ((int)(x * 255.0f)) << 24;
|
|
retval |= ((int)(y * 255.0f)) << 16;
|
|
retval |= ((int)(z * 255.0f)) << 8;
|
|
retval |= ((int)(w * 255.0f)) << 0;
|
|
#endif
|
|
return retval;
|
|
}
|
|
#endif
|
|
|
|
ID_INLINE bool idVec4::Compare(const idVec4& a) const {
|
|
return ((x == a.x) && (y == a.y) && (z == a.z) && w == a.w);
|
|
}
|
|
|
|
ID_INLINE bool idVec4::Compare(const idVec4& a, const float epsilon) const {
|
|
if (idMath::Fabs(x - a.x) > epsilon) {
|
|
return false;
|
|
}
|
|
|
|
if (idMath::Fabs(y - a.y) > epsilon) {
|
|
return false;
|
|
}
|
|
|
|
if (idMath::Fabs(z - a.z) > epsilon) {
|
|
return false;
|
|
}
|
|
|
|
if (idMath::Fabs(w - a.w) > epsilon) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
ID_INLINE bool idVec4::operator==(const idVec4& a) const {
|
|
return Compare(a);
|
|
}
|
|
|
|
ID_INLINE bool idVec4::operator!=(const idVec4& a) const {
|
|
return !Compare(a);
|
|
}
|
|
|
|
#ifdef QUAKE4
|
|
ID_INLINE idVec4& idVec4::operator~(void) {
|
|
Normalize();
|
|
return *this;
|
|
}
|
|
#endif
|
|
|
|
ID_INLINE float idVec4::Length(void) const {
|
|
return (float)idMath::Sqrt(x * x + y * y + z * z + w * w);
|
|
}
|
|
|
|
ID_INLINE float idVec4::LengthSqr(void) const {
|
|
return (x * x + y * y + z * z + w * w);
|
|
}
|
|
|
|
ID_INLINE float idVec4::Normalize(void) {
|
|
float sqrLength, invLength;
|
|
|
|
sqrLength = x * x + y * y + z * z + w * w;
|
|
invLength = idMath::InvSqrt(sqrLength);
|
|
x *= invLength;
|
|
y *= invLength;
|
|
z *= invLength;
|
|
w *= invLength;
|
|
return invLength * sqrLength;
|
|
}
|
|
|
|
ID_INLINE float idVec4::NormalizeFast(void) {
|
|
float sqrLength, invLength;
|
|
|
|
sqrLength = x * x + y * y + z * z + w * w;
|
|
invLength = idMath::RSqrt(sqrLength);
|
|
x *= invLength;
|
|
y *= invLength;
|
|
z *= invLength;
|
|
w *= invLength;
|
|
return invLength * sqrLength;
|
|
}
|
|
|
|
ID_INLINE int idVec4::GetDimension(void) const {
|
|
return 4;
|
|
}
|
|
|
|
ID_INLINE const idVec2& idVec4::ToVec2(void) const {
|
|
return *reinterpret_cast<const idVec2*>(this);
|
|
}
|
|
|
|
ID_INLINE idVec2& idVec4::ToVec2(void) {
|
|
return *reinterpret_cast<idVec2*>(this);
|
|
}
|
|
|
|
ID_INLINE const idVec3& idVec4::ToVec3(void) const {
|
|
return *reinterpret_cast<const idVec3*>(this);
|
|
}
|
|
|
|
ID_INLINE idVec3& idVec4::ToVec3(void) {
|
|
return *reinterpret_cast<idVec3*>(this);
|
|
}
|
|
|
|
ID_INLINE const float* idVec4::ToFloatPtr(void) const {
|
|
return &x;
|
|
}
|
|
|
|
ID_INLINE float* idVec4::ToFloatPtr(void) {
|
|
return &x;
|
|
}
|
|
|
|
|
|
//===============================================================
|
|
//
|
|
// idVec5 - 5D vector
|
|
//
|
|
//===============================================================
|
|
|
|
class idVec5 {
|
|
public:
|
|
float x;
|
|
float y;
|
|
float z;
|
|
float s;
|
|
float t;
|
|
|
|
idVec5(void);
|
|
explicit idVec5(const idVec3& xyz, const idVec2& st);
|
|
explicit idVec5(const float x, const float y, const float z, const float s, const float t);
|
|
|
|
float operator[](int index) const;
|
|
float& operator[](int index);
|
|
idVec5& operator=(const idVec3& a);
|
|
|
|
int GetDimension(void) const;
|
|
|
|
const idVec3& ToVec3(void) const;
|
|
idVec3& ToVec3(void);
|
|
const float* ToFloatPtr(void) const;
|
|
float* ToFloatPtr(void);
|
|
const char* ToString(int precision = 2) const;
|
|
|
|
void Lerp(const idVec5& v1, const idVec5& v2, const float l);
|
|
};
|
|
|
|
extern idVec5 vec5_origin;
|
|
#define vec5_zero vec5_origin
|
|
|
|
ID_INLINE idVec5::idVec5(void) {
|
|
}
|
|
|
|
ID_INLINE idVec5::idVec5(const idVec3& xyz, const idVec2& st) {
|
|
x = xyz.x;
|
|
y = xyz.y;
|
|
z = xyz.z;
|
|
s = st[0];
|
|
t = st[1];
|
|
}
|
|
|
|
ID_INLINE idVec5::idVec5(const float x, const float y, const float z, const float s, const float t) {
|
|
this->x = x;
|
|
this->y = y;
|
|
this->z = z;
|
|
this->s = s;
|
|
this->t = t;
|
|
}
|
|
|
|
ID_INLINE float idVec5::operator[](int index) const {
|
|
return (&x)[index];
|
|
}
|
|
|
|
ID_INLINE float& idVec5::operator[](int index) {
|
|
return (&x)[index];
|
|
}
|
|
|
|
ID_INLINE idVec5& idVec5::operator=(const idVec3& a) {
|
|
x = a.x;
|
|
y = a.y;
|
|
z = a.z;
|
|
s = t = 0;
|
|
return *this;
|
|
}
|
|
|
|
ID_INLINE int idVec5::GetDimension(void) const {
|
|
return 5;
|
|
}
|
|
|
|
ID_INLINE const idVec3& idVec5::ToVec3(void) const {
|
|
return *reinterpret_cast<const idVec3*>(this);
|
|
}
|
|
|
|
ID_INLINE idVec3& idVec5::ToVec3(void) {
|
|
return *reinterpret_cast<idVec3*>(this);
|
|
}
|
|
|
|
ID_INLINE const float* idVec5::ToFloatPtr(void) const {
|
|
return &x;
|
|
}
|
|
|
|
ID_INLINE float* idVec5::ToFloatPtr(void) {
|
|
return &x;
|
|
}
|
|
|
|
|
|
//===============================================================
|
|
//
|
|
// idVec6 - 6D vector
|
|
//
|
|
//===============================================================
|
|
|
|
class idVec6 {
|
|
public:
|
|
idVec6(void);
|
|
explicit idVec6(const float* a);
|
|
explicit idVec6(const float a1, const float a2, const float a3, const float a4, const float a5, const float a6);
|
|
|
|
void Set(const float a1, const float a2, const float a3, const float a4, const float a5, const float a6);
|
|
void Zero(void);
|
|
|
|
float operator[](const int index) const;
|
|
float& operator[](const int index);
|
|
idVec6 operator-() const;
|
|
idVec6 operator*(const float a) const;
|
|
idVec6 operator/(const float a) const;
|
|
float operator*(const idVec6& a) const;
|
|
idVec6 operator-(const idVec6& a) const;
|
|
idVec6 operator+(const idVec6& a) const;
|
|
idVec6& operator*=(const float a);
|
|
idVec6& operator/=(const float a);
|
|
idVec6& operator+=(const idVec6& a);
|
|
idVec6& operator-=(const idVec6& a);
|
|
|
|
friend idVec6 operator*(const float a, const idVec6 b);
|
|
|
|
bool Compare(const idVec6& a) const; // exact compare, no epsilon
|
|
bool Compare(const idVec6& a, const float epsilon) const; // compare with epsilon
|
|
bool operator==(const idVec6& a) const; // exact compare, no epsilon
|
|
bool operator!=(const idVec6& a) const; // exact compare, no epsilon
|
|
|
|
float Length(void) const;
|
|
float LengthSqr(void) const;
|
|
float Normalize(void); // returns length
|
|
float NormalizeFast(void); // returns length
|
|
|
|
int GetDimension(void) const;
|
|
|
|
const idVec3& SubVec3(int index) const;
|
|
idVec3& SubVec3(int index);
|
|
const float* ToFloatPtr(void) const;
|
|
float* ToFloatPtr(void);
|
|
const char* ToString(int precision = 2) const;
|
|
|
|
private:
|
|
float p[6];
|
|
};
|
|
|
|
extern idVec6 vec6_origin;
|
|
#define vec6_zero vec6_origin
|
|
extern idVec6 vec6_infinity;
|
|
|
|
ID_INLINE idVec6::idVec6(void) {
|
|
}
|
|
|
|
ID_INLINE idVec6::idVec6(const float* a) {
|
|
memcpy(p, a, 6 * sizeof(float));
|
|
}
|
|
|
|
ID_INLINE idVec6::idVec6(const float a1, const float a2, const float a3, const float a4, const float a5, const float a6) {
|
|
p[0] = a1;
|
|
p[1] = a2;
|
|
p[2] = a3;
|
|
p[3] = a4;
|
|
p[4] = a5;
|
|
p[5] = a6;
|
|
}
|
|
|
|
ID_INLINE idVec6 idVec6::operator-() const {
|
|
return idVec6(-p[0], -p[1], -p[2], -p[3], -p[4], -p[5]);
|
|
}
|
|
|
|
ID_INLINE float idVec6::operator[](const int index) const {
|
|
return p[index];
|
|
}
|
|
|
|
ID_INLINE float& idVec6::operator[](const int index) {
|
|
return p[index];
|
|
}
|
|
|
|
ID_INLINE idVec6 idVec6::operator*(const float a) const {
|
|
return idVec6(p[0] * a, p[1] * a, p[2] * a, p[3] * a, p[4] * a, p[5] * a);
|
|
}
|
|
|
|
ID_INLINE float idVec6::operator*(const idVec6& a) const {
|
|
return p[0] * a[0] + p[1] * a[1] + p[2] * a[2] + p[3] * a[3] + p[4] * a[4] + p[5] * a[5];
|
|
}
|
|
|
|
ID_INLINE idVec6 idVec6::operator/(const float a) const {
|
|
float inva;
|
|
|
|
assert(a != 0.0f);
|
|
inva = 1.0f / a;
|
|
return idVec6(p[0] * inva, p[1] * inva, p[2] * inva, p[3] * inva, p[4] * inva, p[5] * inva);
|
|
}
|
|
|
|
ID_INLINE idVec6 idVec6::operator+(const idVec6& a) const {
|
|
return idVec6(p[0] + a[0], p[1] + a[1], p[2] + a[2], p[3] + a[3], p[4] + a[4], p[5] + a[5]);
|
|
}
|
|
|
|
ID_INLINE idVec6 idVec6::operator-(const idVec6& a) const {
|
|
return idVec6(p[0] - a[0], p[1] - a[1], p[2] - a[2], p[3] - a[3], p[4] - a[4], p[5] - a[5]);
|
|
}
|
|
|
|
ID_INLINE idVec6& idVec6::operator*=(const float a) {
|
|
p[0] *= a;
|
|
p[1] *= a;
|
|
p[2] *= a;
|
|
p[3] *= a;
|
|
p[4] *= a;
|
|
p[5] *= a;
|
|
return *this;
|
|
}
|
|
|
|
ID_INLINE idVec6& idVec6::operator/=(const float a) {
|
|
float inva;
|
|
|
|
assert(a != 0.0f);
|
|
inva = 1.0f / a;
|
|
p[0] *= inva;
|
|
p[1] *= inva;
|
|
p[2] *= inva;
|
|
p[3] *= inva;
|
|
p[4] *= inva;
|
|
p[5] *= inva;
|
|
return *this;
|
|
}
|
|
|
|
ID_INLINE idVec6& idVec6::operator+=(const idVec6& a) {
|
|
p[0] += a[0];
|
|
p[1] += a[1];
|
|
p[2] += a[2];
|
|
p[3] += a[3];
|
|
p[4] += a[4];
|
|
p[5] += a[5];
|
|
return *this;
|
|
}
|
|
|
|
ID_INLINE idVec6& idVec6::operator-=(const idVec6& a) {
|
|
p[0] -= a[0];
|
|
p[1] -= a[1];
|
|
p[2] -= a[2];
|
|
p[3] -= a[3];
|
|
p[4] -= a[4];
|
|
p[5] -= a[5];
|
|
return *this;
|
|
}
|
|
|
|
ID_INLINE idVec6 operator*(const float a, const idVec6 b) {
|
|
return b * a;
|
|
}
|
|
|
|
ID_INLINE bool idVec6::Compare(const idVec6& a) const {
|
|
return ((p[0] == a[0]) && (p[1] == a[1]) && (p[2] == a[2]) &&
|
|
(p[3] == a[3]) && (p[4] == a[4]) && (p[5] == a[5]));
|
|
}
|
|
|
|
ID_INLINE bool idVec6::Compare(const idVec6& a, const float epsilon) const {
|
|
if (idMath::Fabs(p[0] - a[0]) > epsilon) {
|
|
return false;
|
|
}
|
|
|
|
if (idMath::Fabs(p[1] - a[1]) > epsilon) {
|
|
return false;
|
|
}
|
|
|
|
if (idMath::Fabs(p[2] - a[2]) > epsilon) {
|
|
return false;
|
|
}
|
|
|
|
if (idMath::Fabs(p[3] - a[3]) > epsilon) {
|
|
return false;
|
|
}
|
|
|
|
if (idMath::Fabs(p[4] - a[4]) > epsilon) {
|
|
return false;
|
|
}
|
|
|
|
if (idMath::Fabs(p[5] - a[5]) > epsilon) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
ID_INLINE bool idVec6::operator==(const idVec6& a) const {
|
|
return Compare(a);
|
|
}
|
|
|
|
ID_INLINE bool idVec6::operator!=(const idVec6& a) const {
|
|
return !Compare(a);
|
|
}
|
|
|
|
ID_INLINE void idVec6::Set(const float a1, const float a2, const float a3, const float a4, const float a5, const float a6) {
|
|
p[0] = a1;
|
|
p[1] = a2;
|
|
p[2] = a3;
|
|
p[3] = a4;
|
|
p[4] = a5;
|
|
p[5] = a6;
|
|
}
|
|
|
|
ID_INLINE void idVec6::Zero(void) {
|
|
p[0] = p[1] = p[2] = p[3] = p[4] = p[5] = 0.0f;
|
|
}
|
|
|
|
ID_INLINE float idVec6::Length(void) const {
|
|
return (float)idMath::Sqrt(p[0] * p[0] + p[1] * p[1] + p[2] * p[2] + p[3] * p[3] + p[4] * p[4] + p[5] * p[5]);
|
|
}
|
|
|
|
ID_INLINE float idVec6::LengthSqr(void) const {
|
|
return (p[0] * p[0] + p[1] * p[1] + p[2] * p[2] + p[3] * p[3] + p[4] * p[4] + p[5] * p[5]);
|
|
}
|
|
|
|
ID_INLINE float idVec6::Normalize(void) {
|
|
float sqrLength, invLength;
|
|
|
|
sqrLength = p[0] * p[0] + p[1] * p[1] + p[2] * p[2] + p[3] * p[3] + p[4] * p[4] + p[5] * p[5];
|
|
invLength = idMath::InvSqrt(sqrLength);
|
|
p[0] *= invLength;
|
|
p[1] *= invLength;
|
|
p[2] *= invLength;
|
|
p[3] *= invLength;
|
|
p[4] *= invLength;
|
|
p[5] *= invLength;
|
|
return invLength * sqrLength;
|
|
}
|
|
|
|
ID_INLINE float idVec6::NormalizeFast(void) {
|
|
float sqrLength, invLength;
|
|
|
|
sqrLength = p[0] * p[0] + p[1] * p[1] + p[2] * p[2] + p[3] * p[3] + p[4] * p[4] + p[5] * p[5];
|
|
invLength = idMath::RSqrt(sqrLength);
|
|
p[0] *= invLength;
|
|
p[1] *= invLength;
|
|
p[2] *= invLength;
|
|
p[3] *= invLength;
|
|
p[4] *= invLength;
|
|
p[5] *= invLength;
|
|
return invLength * sqrLength;
|
|
}
|
|
|
|
ID_INLINE int idVec6::GetDimension(void) const {
|
|
return 6;
|
|
}
|
|
|
|
ID_INLINE const idVec3& idVec6::SubVec3(int index) const {
|
|
return *reinterpret_cast<const idVec3*>(p + index * 3);
|
|
}
|
|
|
|
ID_INLINE idVec3& idVec6::SubVec3(int index) {
|
|
return *reinterpret_cast<idVec3*>(p + index * 3);
|
|
}
|
|
|
|
ID_INLINE const float* idVec6::ToFloatPtr(void) const {
|
|
return p;
|
|
}
|
|
|
|
ID_INLINE float* idVec6::ToFloatPtr(void) {
|
|
return p;
|
|
}
|
|
|
|
|
|
//===============================================================
|
|
//
|
|
// idVecX - arbitrary sized vector
|
|
//
|
|
// The vector lives on 16 byte aligned and 16 byte padded memory.
|
|
//
|
|
// NOTE: due to the temporary memory pool idVecX cannot be used by multiple threads
|
|
//
|
|
//===============================================================
|
|
|
|
#define VECX_MAX_TEMP 1024
|
|
#define VECX_QUAD( x ) ( ( ( ( x ) + 3 ) & ~3 ) * sizeof( float ) )
|
|
#define VECX_CLEAREND() int s = size; while( s < ( ( s + 3) & ~3 ) ) { p[s++] = 0.0f; }
|
|
#define VECX_ALLOCA( n ) ( (float *) _alloca16( VECX_QUAD( n ) ) )
|
|
#define VECX_SIMD
|
|
|
|
#ifdef QUAKE4
|
|
#ifdef _XENON
|
|
#undef VECX_SIMD
|
|
#endif
|
|
#endif
|
|
|
|
class idVecX {
|
|
friend class idMatX;
|
|
|
|
public:
|
|
idVecX(void);
|
|
explicit idVecX(int length);
|
|
explicit idVecX(int length, float* data);
|
|
~idVecX(void);
|
|
|
|
float operator[](const int index) const;
|
|
float& operator[](const int index);
|
|
idVecX operator-() const;
|
|
idVecX& operator=(const idVecX& a);
|
|
idVecX operator*(const float a) const;
|
|
idVecX operator/(const float a) const;
|
|
float operator*(const idVecX& a) const;
|
|
idVecX operator-(const idVecX& a) const;
|
|
idVecX operator+(const idVecX& a) const;
|
|
idVecX& operator*=(const float a);
|
|
idVecX& operator/=(const float a);
|
|
idVecX& operator+=(const idVecX& a);
|
|
idVecX& operator-=(const idVecX& a);
|
|
|
|
friend idVecX operator*(const float a, const idVecX b);
|
|
|
|
bool Compare(const idVecX& a) const; // exact compare, no epsilon
|
|
bool Compare(const idVecX& a, const float epsilon) const; // compare with epsilon
|
|
bool operator==(const idVecX& a) const; // exact compare, no epsilon
|
|
bool operator!=(const idVecX& a) const; // exact compare, no epsilon
|
|
|
|
void SetSize(int size);
|
|
void ChangeSize(int size, bool makeZero = false);
|
|
int GetSize(void) const { return size; }
|
|
void SetData(int length, float* data);
|
|
void Zero(void);
|
|
void Zero(int length);
|
|
void Random(int seed, float l = 0.0f, float u = 1.0f);
|
|
void Random(int length, int seed, float l = 0.0f, float u = 1.0f);
|
|
void Negate(void);
|
|
void Clamp(float min, float max);
|
|
idVecX& SwapElements(int e1, int e2);
|
|
|
|
float Length(void) const;
|
|
float LengthSqr(void) const;
|
|
idVecX Normalize(void) const;
|
|
float NormalizeSelf(void);
|
|
|
|
int GetDimension(void) const;
|
|
|
|
const idVec3& SubVec3(int index) const;
|
|
idVec3& SubVec3(int index);
|
|
const idVec6& SubVec6(int index) const;
|
|
idVec6& SubVec6(int index);
|
|
const float* ToFloatPtr(void) const;
|
|
float* ToFloatPtr(void);
|
|
const char* ToString(int precision = 2) const;
|
|
|
|
private:
|
|
int size; // size of the vector
|
|
int alloced; // if -1 p points to data set with SetData
|
|
float* p; // memory the vector is stored
|
|
|
|
#ifdef QUAKE4
|
|
ALIGN16(static float tempPtr[VECX_MAX_TEMP]); // used to store intermediate results
|
|
#else
|
|
static float temp[VECX_MAX_TEMP + 4]; // used to store intermediate results
|
|
static float* tempPtr; // pointer to 16 byte aligned temporary memory
|
|
#endif
|
|
static int tempIndex; // index into memory pool, wraps around
|
|
|
|
private:
|
|
void SetTempSize(int size);
|
|
};
|
|
|
|
|
|
ID_INLINE idVecX::idVecX(void) {
|
|
size = alloced = 0;
|
|
p = NULL;
|
|
}
|
|
|
|
ID_INLINE idVecX::idVecX(int length) {
|
|
size = alloced = 0;
|
|
p = NULL;
|
|
SetSize(length);
|
|
}
|
|
|
|
ID_INLINE idVecX::idVecX(int length, float* data) {
|
|
size = alloced = 0;
|
|
p = NULL;
|
|
SetData(length, data);
|
|
}
|
|
|
|
ID_INLINE idVecX::~idVecX(void) {
|
|
// if not temp memory
|
|
if (p && (p < idVecX::tempPtr || p >= idVecX::tempPtr + VECX_MAX_TEMP) && alloced != -1) {
|
|
Mem_Free16(p);
|
|
}
|
|
}
|
|
|
|
ID_INLINE float idVecX::operator[](const int index) const {
|
|
assert(index >= 0 && index < size);
|
|
return p[index];
|
|
}
|
|
|
|
ID_INLINE float& idVecX::operator[](const int index) {
|
|
assert(index >= 0 && index < size);
|
|
return p[index];
|
|
}
|
|
|
|
ID_INLINE idVecX idVecX::operator-() const {
|
|
int i;
|
|
idVecX m;
|
|
|
|
m.SetTempSize(size);
|
|
for (i = 0; i < size; i++) {
|
|
m.p[i] = -p[i];
|
|
}
|
|
return m;
|
|
}
|
|
|
|
ID_INLINE idVecX& idVecX::operator=(const idVecX& a) {
|
|
SetSize(a.size);
|
|
#ifdef VECX_SIMD
|
|
SIMDProcessor->Copy16(p, a.p, a.size);
|
|
#else
|
|
memcpy(p, a.p, a.size * sizeof(float));
|
|
#endif
|
|
idVecX::tempIndex = 0;
|
|
return *this;
|
|
}
|
|
|
|
ID_INLINE idVecX idVecX::operator+(const idVecX& a) const {
|
|
idVecX m;
|
|
|
|
assert(size == a.size);
|
|
m.SetTempSize(size);
|
|
#ifdef VECX_SIMD
|
|
SIMDProcessor->Add16(m.p, p, a.p, size);
|
|
#else
|
|
int i;
|
|
for (i = 0; i < size; i++) {
|
|
m.p[i] = p[i] + a.p[i];
|
|
}
|
|
#endif
|
|
return m;
|
|
}
|
|
|
|
ID_INLINE idVecX idVecX::operator-(const idVecX& a) const {
|
|
idVecX m;
|
|
|
|
assert(size == a.size);
|
|
m.SetTempSize(size);
|
|
#ifdef VECX_SIMD
|
|
SIMDProcessor->Sub16(m.p, p, a.p, size);
|
|
#else
|
|
int i;
|
|
for (i = 0; i < size; i++) {
|
|
m.p[i] = p[i] - a.p[i];
|
|
}
|
|
#endif
|
|
return m;
|
|
}
|
|
|
|
ID_INLINE idVecX& idVecX::operator+=(const idVecX& a) {
|
|
assert(size == a.size);
|
|
#ifdef VECX_SIMD
|
|
SIMDProcessor->AddAssign16(p, a.p, size);
|
|
#else
|
|
int i;
|
|
for (i = 0; i < size; i++) {
|
|
p[i] += a.p[i];
|
|
}
|
|
#endif
|
|
idVecX::tempIndex = 0;
|
|
return *this;
|
|
}
|
|
|
|
ID_INLINE idVecX& idVecX::operator-=(const idVecX& a) {
|
|
assert(size == a.size);
|
|
#ifdef VECX_SIMD
|
|
SIMDProcessor->SubAssign16(p, a.p, size);
|
|
#else
|
|
int i;
|
|
for (i = 0; i < size; i++) {
|
|
p[i] -= a.p[i];
|
|
}
|
|
#endif
|
|
idVecX::tempIndex = 0;
|
|
return *this;
|
|
}
|
|
|
|
ID_INLINE idVecX idVecX::operator*(const float a) const {
|
|
idVecX m;
|
|
|
|
m.SetTempSize(size);
|
|
#ifdef VECX_SIMD
|
|
SIMDProcessor->Mul16(m.p, p, a, size);
|
|
#else
|
|
int i;
|
|
for (i = 0; i < size; i++) {
|
|
m.p[i] = p[i] * a;
|
|
}
|
|
#endif
|
|
return m;
|
|
}
|
|
|
|
ID_INLINE idVecX& idVecX::operator*=(const float a) {
|
|
#ifdef VECX_SIMD
|
|
SIMDProcessor->MulAssign16(p, a, size);
|
|
#else
|
|
int i;
|
|
for (i = 0; i < size; i++) {
|
|
p[i] *= a;
|
|
}
|
|
#endif
|
|
return *this;
|
|
}
|
|
|
|
ID_INLINE idVecX idVecX::operator/(const float a) const {
|
|
assert(a != 0.0f);
|
|
return (*this) * (1.0f / a);
|
|
}
|
|
|
|
ID_INLINE idVecX& idVecX::operator/=(const float a) {
|
|
assert(a != 0.0f);
|
|
(*this) *= (1.0f / a);
|
|
return *this;
|
|
}
|
|
|
|
ID_INLINE idVecX operator*(const float a, const idVecX b) {
|
|
return b * a;
|
|
}
|
|
|
|
ID_INLINE float idVecX::operator*(const idVecX& a) const {
|
|
int i;
|
|
float sum = 0.0f;
|
|
|
|
assert(size == a.size);
|
|
for (i = 0; i < size; i++) {
|
|
sum += p[i] * a.p[i];
|
|
}
|
|
return sum;
|
|
}
|
|
|
|
ID_INLINE bool idVecX::Compare(const idVecX& a) const {
|
|
int i;
|
|
|
|
assert(size == a.size);
|
|
for (i = 0; i < size; i++) {
|
|
if (p[i] != a.p[i]) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
ID_INLINE bool idVecX::Compare(const idVecX& a, const float epsilon) const {
|
|
int i;
|
|
|
|
assert(size == a.size);
|
|
for (i = 0; i < size; i++) {
|
|
if (idMath::Fabs(p[i] - a.p[i]) > epsilon) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
ID_INLINE bool idVecX::operator==(const idVecX& a) const {
|
|
return Compare(a);
|
|
}
|
|
|
|
ID_INLINE bool idVecX::operator!=(const idVecX& a) const {
|
|
return !Compare(a);
|
|
}
|
|
|
|
ID_INLINE void idVecX::SetSize(int newSize) {
|
|
int alloc = (newSize + 3) & ~3;
|
|
if (alloc > alloced && alloced != -1) {
|
|
if (p) {
|
|
Mem_Free16(p);
|
|
}
|
|
#ifdef QUAKE4
|
|
p = (float*)Mem_Alloc16(alloc * sizeof(float));
|
|
#else
|
|
p = (float*)Mem_Alloc16(alloc * sizeof(float));
|
|
#endif
|
|
alloced = alloc;
|
|
}
|
|
size = newSize;
|
|
VECX_CLEAREND();
|
|
}
|
|
|
|
ID_INLINE void idVecX::ChangeSize(int newSize, bool makeZero) {
|
|
int alloc = (newSize + 3) & ~3;
|
|
if (alloc > alloced && alloced != -1) {
|
|
float* oldVec = p;
|
|
#ifdef QUAKE4
|
|
p = (float*)Mem_Alloc16(alloc * sizeof(float));
|
|
#else
|
|
p = (float*)Mem_Alloc16(alloc * sizeof(float));
|
|
#endif
|
|
alloced = alloc;
|
|
if (oldVec) {
|
|
for (int i = 0; i < size; i++) {
|
|
p[i] = oldVec[i];
|
|
}
|
|
Mem_Free16(oldVec);
|
|
}
|
|
if (makeZero) {
|
|
// zero any new elements
|
|
for (int i = size; i < newSize; i++) {
|
|
p[i] = 0.0f;
|
|
}
|
|
}
|
|
}
|
|
size = newSize;
|
|
VECX_CLEAREND();
|
|
}
|
|
|
|
ID_INLINE void idVecX::SetTempSize(int newSize) {
|
|
|
|
size = newSize;
|
|
alloced = (newSize + 3) & ~3;
|
|
assert(alloced < VECX_MAX_TEMP);
|
|
if (idVecX::tempIndex + alloced > VECX_MAX_TEMP) {
|
|
idVecX::tempIndex = 0;
|
|
}
|
|
p = idVecX::tempPtr + idVecX::tempIndex;
|
|
idVecX::tempIndex += alloced;
|
|
VECX_CLEAREND();
|
|
}
|
|
|
|
ID_INLINE void idVecX::SetData(int length, float* data) {
|
|
if (p && (p < idVecX::tempPtr || p >= idVecX::tempPtr + VECX_MAX_TEMP) && alloced != -1) {
|
|
Mem_Free16(p);
|
|
}
|
|
assert((((int)data) & 15) == 0); // data must be 16 byte aligned
|
|
p = data;
|
|
size = length;
|
|
alloced = -1;
|
|
VECX_CLEAREND();
|
|
}
|
|
|
|
ID_INLINE void idVecX::Zero(void) {
|
|
#ifdef VECX_SIMD
|
|
SIMDProcessor->Zero16(p, size);
|
|
#else
|
|
memset(p, 0, size * sizeof(float));
|
|
#endif
|
|
}
|
|
|
|
ID_INLINE void idVecX::Zero(int length) {
|
|
SetSize(length);
|
|
#ifdef VECX_SIMD
|
|
SIMDProcessor->Zero16(p, length);
|
|
#else
|
|
memset(p, 0, size * sizeof(float));
|
|
#endif
|
|
}
|
|
|
|
ID_INLINE void idVecX::Random(int seed, float l, float u) {
|
|
int i;
|
|
float c;
|
|
idRandom rnd(seed);
|
|
|
|
c = u - l;
|
|
for (i = 0; i < size; i++) {
|
|
p[i] = l + rnd.RandomFloat() * c;
|
|
}
|
|
}
|
|
|
|
ID_INLINE void idVecX::Random(int length, int seed, float l, float u) {
|
|
int i;
|
|
float c;
|
|
idRandom rnd(seed);
|
|
|
|
SetSize(length);
|
|
c = u - l;
|
|
for (i = 0; i < size; i++) {
|
|
p[i] = l + rnd.RandomFloat() * c;
|
|
}
|
|
}
|
|
|
|
ID_INLINE void idVecX::Negate(void) {
|
|
#ifdef VECX_SIMD
|
|
SIMDProcessor->Negate16(p, size);
|
|
#else
|
|
int i;
|
|
for (i = 0; i < size; i++) {
|
|
p[i] = -p[i];
|
|
}
|
|
#endif
|
|
}
|
|
|
|
ID_INLINE void idVecX::Clamp(float min, float max) {
|
|
int i;
|
|
for (i = 0; i < size; i++) {
|
|
if (p[i] < min) {
|
|
p[i] = min;
|
|
}
|
|
else if (p[i] > max) {
|
|
p[i] = max;
|
|
}
|
|
}
|
|
}
|
|
|
|
ID_INLINE idVecX& idVecX::SwapElements(int e1, int e2) {
|
|
float tmp;
|
|
tmp = p[e1];
|
|
p[e1] = p[e2];
|
|
p[e2] = tmp;
|
|
return *this;
|
|
}
|
|
|
|
ID_INLINE float idVecX::Length(void) const {
|
|
int i;
|
|
float sum = 0.0f;
|
|
|
|
for (i = 0; i < size; i++) {
|
|
sum += p[i] * p[i];
|
|
}
|
|
return idMath::Sqrt(sum);
|
|
}
|
|
|
|
ID_INLINE float idVecX::LengthSqr(void) const {
|
|
int i;
|
|
float sum = 0.0f;
|
|
|
|
for (i = 0; i < size; i++) {
|
|
sum += p[i] * p[i];
|
|
}
|
|
return sum;
|
|
}
|
|
|
|
ID_INLINE idVecX idVecX::Normalize(void) const {
|
|
int i;
|
|
idVecX m;
|
|
float invSqrt, sum = 0.0f;
|
|
|
|
m.SetTempSize(size);
|
|
for (i = 0; i < size; i++) {
|
|
sum += p[i] * p[i];
|
|
}
|
|
invSqrt = idMath::InvSqrt(sum);
|
|
for (i = 0; i < size; i++) {
|
|
m.p[i] = p[i] * invSqrt;
|
|
}
|
|
return m;
|
|
}
|
|
|
|
ID_INLINE float idVecX::NormalizeSelf(void) {
|
|
float invSqrt, sum = 0.0f;
|
|
int i;
|
|
for (i = 0; i < size; i++) {
|
|
sum += p[i] * p[i];
|
|
}
|
|
invSqrt = idMath::InvSqrt(sum);
|
|
for (i = 0; i < size; i++) {
|
|
p[i] *= invSqrt;
|
|
}
|
|
return invSqrt * sum;
|
|
}
|
|
|
|
ID_INLINE int idVecX::GetDimension(void) const {
|
|
return size;
|
|
}
|
|
|
|
ID_INLINE idVec3& idVecX::SubVec3(int index) {
|
|
assert(index >= 0 && index * 3 + 3 <= size);
|
|
return *reinterpret_cast<idVec3*>(p + index * 3);
|
|
}
|
|
|
|
ID_INLINE const idVec3& idVecX::SubVec3(int index) const {
|
|
assert(index >= 0 && index * 3 + 3 <= size);
|
|
return *reinterpret_cast<const idVec3*>(p + index * 3);
|
|
}
|
|
|
|
ID_INLINE idVec6& idVecX::SubVec6(int index) {
|
|
assert(index >= 0 && index * 6 + 6 <= size);
|
|
return *reinterpret_cast<idVec6*>(p + index * 6);
|
|
}
|
|
|
|
ID_INLINE const idVec6& idVecX::SubVec6(int index) const {
|
|
assert(index >= 0 && index * 6 + 6 <= size);
|
|
return *reinterpret_cast<const idVec6*>(p + index * 6);
|
|
}
|
|
|
|
ID_INLINE const float* idVecX::ToFloatPtr(void) const {
|
|
return p;
|
|
}
|
|
|
|
ID_INLINE float* idVecX::ToFloatPtr(void) {
|
|
return p;
|
|
}
|
|
|
|
|
|
//===============================================================
|
|
//
|
|
// idPolar3
|
|
//
|
|
//===============================================================
|
|
|
|
class idPolar3 {
|
|
public:
|
|
float radius, theta, phi;
|
|
|
|
idPolar3(void);
|
|
explicit idPolar3(const float radius, const float theta, const float phi);
|
|
|
|
void Set(const float radius, const float theta, const float phi);
|
|
|
|
float operator[](const int index) const;
|
|
float& operator[](const int index);
|
|
idPolar3 operator-() const;
|
|
idPolar3& operator=(const idPolar3& a);
|
|
|
|
idVec3 ToVec3(void) const;
|
|
};
|
|
|
|
ID_INLINE idPolar3::idPolar3(void) {
|
|
}
|
|
|
|
ID_INLINE idPolar3::idPolar3(const float radius, const float theta, const float phi) {
|
|
assert(radius > 0);
|
|
this->radius = radius;
|
|
this->theta = theta;
|
|
this->phi = phi;
|
|
}
|
|
|
|
ID_INLINE void idPolar3::Set(const float radius, const float theta, const float phi) {
|
|
assert(radius > 0);
|
|
this->radius = radius;
|
|
this->theta = theta;
|
|
this->phi = phi;
|
|
}
|
|
|
|
ID_INLINE float idPolar3::operator[](const int index) const {
|
|
return (&radius)[index];
|
|
}
|
|
|
|
ID_INLINE float& idPolar3::operator[](const int index) {
|
|
return (&radius)[index];
|
|
}
|
|
|
|
ID_INLINE idPolar3 idPolar3::operator-() const {
|
|
return idPolar3(radius, -theta, -phi);
|
|
}
|
|
|
|
ID_INLINE idPolar3& idPolar3::operator=(const idPolar3& a) {
|
|
radius = a.radius;
|
|
theta = a.theta;
|
|
phi = a.phi;
|
|
return *this;
|
|
}
|
|
|
|
ID_INLINE idVec3 idPolar3::ToVec3(void) const {
|
|
float sp, cp, st, ct;
|
|
idMath::SinCos(phi, sp, cp);
|
|
idMath::SinCos(theta, st, ct);
|
|
return idVec3(cp * radius * ct, cp * radius * st, radius * sp);
|
|
}
|
|
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
Old 3D vector macros, should no longer be used.
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
#define DotProduct( a, b) ((a)[0]*(b)[0]+(a)[1]*(b)[1]+(a)[2]*(b)[2])
|
|
#define VectorSubtract( a, b, c ) ((c)[0]=(a)[0]-(b)[0],(c)[1]=(a)[1]-(b)[1],(c)[2]=(a)[2]-(b)[2])
|
|
#define VectorAdd( a, b, c ) ((c)[0]=(a)[0]+(b)[0],(c)[1]=(a)[1]+(b)[1],(c)[2]=(a)[2]+(b)[2])
|
|
#define VectorScale( v, s, o ) ((o)[0]=(v)[0]*(s),(o)[1]=(v)[1]*(s),(o)[2]=(v)[2]*(s))
|
|
#define VectorMA( v, s, b, o ) ((o)[0]=(v)[0]+(b)[0]*(s),(o)[1]=(v)[1]+(b)[1]*(s),(o)[2]=(v)[2]+(b)[2]*(s))
|
|
#define VectorCopy( a, b ) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2])
|
|
|
|
|
|
#endif /* !__MATH_VECTOR_H__ */
|