/* =========================================================================== Copyright (C) 2015 the OpenMoHAA team This file is part of OpenMoHAA source code. OpenMoHAA 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 2 of the License, or (at your option) any later version. OpenMoHAA 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 OpenMoHAA source code; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA =========================================================================== */ // vector.h: C++ vector class. #pragma once #include #include #include "qcommon.h" //#define X 0 //#define Y 1 //#define Z 2 //#define W 3 #ifdef __Q_FABS__ # define VECTOR_FABS Q_fabs #else # define VECTOR_FABS fabs #endif static float vrsqrt(float number) { union { float f; int i; } t; float x2, y; const float threehalfs = 1.5F; x2 = number * 0.5F; t.f = number; t.i = 0x5f3759df - (t.i >> 1); // what the fuck? y = t.f; y = y * (threehalfs - (x2 * y * y)); // 1st iteration return y; } class Vector { public: float x; float y; float z; Vector(); Vector(const vec3_t src); Vector(const float x, const float y, const float z); explicit Vector(const char *text); operator float *(); operator const float *() const; float pitch(void) const; float yaw(void) const; float roll(void) const; float operator[](const int index) const; float & operator[](const int index); void copyTo(vec3_t vec) const; void setPitch(const float x); void setYaw(const float y); void setRoll(const float z); void setXYZ(const float x, const float y, const float z); const Vector & operator=(const Vector &a); const Vector & operator=(vec3_t a); const Vector & operator=(const char *a); friend Vector operator+(const Vector &a, const Vector &b); friend Vector operator+(vec3_t a, const Vector &b); friend Vector operator+(const Vector &a, vec3_t b); const Vector & operator+=(const Vector &a); const Vector & operator+=(vec3_t a); friend Vector operator-(const Vector &a, const Vector &b); friend Vector operator-(vec3_t a, const Vector &b); friend Vector operator-(const Vector &a, vec3_t b); const Vector & operator-=(const Vector &a); const Vector & operator-=(vec3_t a); friend Vector operator*(const Vector &a, const float b); friend Vector operator*(const float a, const Vector &b); friend float operator*(const Vector &a, const Vector &b); friend float operator*(vec3_t a, const Vector &b); friend float operator*(const Vector &a, vec3_t b); const Vector & operator*=(const float a); friend Vector operator/(const Vector &a, const float b); friend Vector operator/(const float a, const Vector &b); friend float operator/(const Vector &a, const Vector &b); friend float operator/(vec3_t a, const Vector &b); friend float operator/(const Vector &a, vec3_t b); const Vector & operator/=(const float a); friend int operator==(const Vector &a, const Vector &b); friend int operator==(vec3_t a, const Vector &b); friend int operator==(const Vector &a, vec3_t b); friend int operator!=(const Vector &a, const Vector &b); friend int operator!=(vec3_t a, const Vector &b); friend int operator!=(const Vector &a, vec3_t b); int FuzzyEqual(const Vector &b, const float epsilon) const; int FuzzyEqual(vec3_t b, const float epsilon) const; const Vector & CrossProduct(const Vector a, const Vector b); const Vector & CrossProduct(vec3_t a, const Vector b); const Vector & CrossProduct(const Vector a, vec3_t b); float length(void) const; float lengthfast(void) const; float lengthSquared(void) const; float lengthXY() const; float lengthXYSquared() const; float normalize(void); void normalizefast(void); void EulerNormalize(void); void EulerNormalize360(void); static Vector Clamp(const Vector &value, const Vector &min, const Vector &max); static void Clamp(Vector &value, const Vector &min, const Vector &max); static Vector Cross(const Vector &vector1, const Vector &vector2); static float Dot(const Vector &vector1, const Vector &vector2); static float Dot(vec3_t a, const Vector &b); static float Dot(const Vector &a, vec3_t b); static float Distance(const Vector &vector1, const Vector &vector2); static float DistanceSquared(const Vector &vector1, const Vector &vector2); static float DistanceXY(const Vector &vector1, const Vector &vector2); static Vector AnglesBetween(const Vector &vector1, const Vector &vector2); static float AngleBetween(const Vector &vector1, const Vector &vector2); static bool CloseEnough(const Vector &vector1, const Vector &vector2, const float epsilon = Vector::Epsilon()); static bool SmallEnough(const Vector &vector, const float epsilon = Vector::Epsilon()); static float Epsilon(void); static Vector& Identity(void); Vector operator-(void) const; friend Vector fabs(const Vector &a); float toYaw(void) const; float toPitch(void) const; Vector toAngles(void) const; Vector AnglesMod(void) const; void AngleVectors(Vector *forward, Vector *right = NULL, Vector *up = NULL) const; void AngleVectorsLeft(Vector *forward, Vector *right = NULL, Vector *up = NULL) const; friend Vector LerpVector(const Vector &w1, const Vector &w2, const float t); friend float MaxValue(const Vector &a); Vector GetRotatedX(float angle) const; void RotateX(double angle); Vector GetRotatedY(float angle) const; void RotateY(double angle); Vector GetRotatedZ(float angle) const; void RotateZ(float angle); void PackTo01(); Vector GetPackedTo01() const; }; static Vector vec_origin = Vector(0, 0, 0); static Vector vec_zero = Vector(0, 0, 0); static Vector g_vEyeDir = Vector(0, 0, 0); inline float Vector::pitch(void) const { return x; } inline float Vector::yaw(void) const { return y; } inline float Vector::roll(void) const { return z; } inline void Vector::setPitch(float pitch) { x = pitch; } inline void Vector::setYaw(float yaw) { y = yaw; } inline void Vector::setRoll(float roll) { z = roll; } inline void Vector::copyTo(vec3_t vec) const { vec[0] = x; vec[1] = y; vec[2] = z; } inline float Vector::operator[](const int index) const { assert((index >= 0) && (index < 3)); return (&x)[index]; } inline float& Vector::operator[](const int index) { assert((index >= 0) && (index < 3)); return (&x)[index]; } inline void Vector::setXYZ(const float new_x, const float new_y, const float new_z) { x = new_x; y = new_y; z = new_z; } inline Vector::Vector() : x(0) , y(0) , z(0) {} inline Vector::Vector(const vec3_t src) : x(src[0]) , y(src[1]) , z(src[2]) {} inline Vector::Vector(const float init_x, const float init_y, const float init_z) : x(init_x) , y(init_y) , z(init_z) {} inline Vector::Vector(const char *text) : x(0) , y(0) , z(0) { if (text) { if (text[0] == '"') { sscanf(text, "\"%f %f %f\"", &x, &y, &z); } else { sscanf(text, "%f %f %f", &x, &y, &z); } } } inline Vector::operator float *(void) { return &x; } inline Vector::operator const float *(void) const { return &x; } inline const Vector& Vector::operator=(const Vector& a) { x = a.x; y = a.y; z = a.z; return *this; } inline const Vector& Vector::operator=(vec3_t a) { x = a[0]; y = a[1]; z = a[2]; return *this; } inline const Vector& Vector::operator=(const char *a) { if (a) { if (a[0] == '"') { sscanf(a, "\"%f %f %f\"", &x, &y, &z); } else { sscanf(a, "%f %f %f", &x, &y, &z); } } return *this; } inline Vector operator+(const Vector& a, const Vector& b) { return Vector(a.x + b.x, a.y + b.y, a.z + b.z); } inline Vector operator+(vec3_t a, const Vector& b) { return Vector(a[0] + b.x, a[1] + b.y, a[2] + b.z); } inline Vector operator+(const Vector& a, vec3_t b) { return Vector(a.x + b[0], a.y + b[1], a.z + b[2]); } inline const Vector& Vector::operator+=(const Vector& a) { x += a.x; y += a.y; z += a.z; return *this; } inline const Vector& Vector::operator+=(vec3_t a) { x += a[0]; y += a[1]; z += a[2]; return *this; } inline Vector operator-(const Vector& a, const Vector& b) { return Vector(a.x - b.x, a.y - b.y, a.z - b.z); } inline Vector operator-(vec3_t a, const Vector& b) { return Vector(a[0] - b.x, a[1] - b.y, a[2] - b.z); } inline Vector operator-(const Vector& a, vec3_t b) { return Vector(a.x - b[0], a.y - b[1], a.z - b[2]); } inline const Vector& Vector::operator-=(const Vector& a) { x -= a.x; y -= a.y; z -= a.z; return *this; } inline const Vector& Vector::operator-=(vec3_t a) { x -= a[0]; y -= a[1]; z -= a[2]; return *this; } inline Vector operator*(const Vector& a, const float b) { return Vector(a.x * b, a.y * b, a.z * b); } inline Vector operator*(const float a, const Vector& b) { return b * a; } inline float operator*(const Vector& a, const Vector& b) { return (a.x * b.x) + (a.y * b.y) + (a.z * b.z); } inline float operator*(vec3_t a, const Vector& b) { return (a[0] * b.x) + (a[1] * b.y) + (a[2] * b.z); } inline float operator*(const Vector& a, vec3_t b) { return (a.x * b[0]) + (a.y * b[1]) + (a.z * b[2]); } inline const Vector& Vector::operator*=(const float a) { x *= a; y *= a; z *= a; return *this; } inline Vector operator/(const Vector& a, const float b) { return Vector(a.x / b, a.y / b, a.z / b); } inline Vector operator/(const float a, const Vector& b) { return b / a; } inline float operator/(const Vector& a, const Vector& b) { return (a.x / b.x) + (a.y / b.y) + (a.z / b.z); } inline float operator/(vec3_t a, const Vector& b) { return (a[0] / b.x) + (a[1] / b.y) + (a[2] / b.z); } inline float operator/(const Vector& a, vec3_t b) { return (a.x / b[0]) + (a.y / b[1]) + (a.z / b[2]); } inline const Vector& Vector::operator/=(const float a) { *this = *this / a; return *this; } inline int Vector::FuzzyEqual(const Vector& b, const float epsilon) const { return ((VECTOR_FABS(x - b.x) < epsilon) && (VECTOR_FABS(y - b.y) < epsilon) && (VECTOR_FABS(z - b.z) < epsilon)); } inline int Vector::FuzzyEqual(vec3_t b, const float epsilon) const { return ( (VECTOR_FABS(x - b[0]) < epsilon) && (VECTOR_FABS(y - b[1]) < epsilon) && (VECTOR_FABS(z - b[2]) < epsilon) ); } inline int operator==(const Vector& a, const Vector& b) { return ((a.x == b.x) && (a.y == b.y) && (a.z == b.z)); } inline int operator==(vec3_t a, const Vector& b) { return ((a[0] == b.x) && (a[1] == b.y) && (a[2] == b.z)); } inline int operator==(const Vector& a, vec3_t b) { return ((a.x == b[0]) && (a.y == b[1]) && (a.z == b[2])); } inline int operator!=(const Vector& a, const Vector& b) { return ((a.x != b.x) || (a.y != b.y) || (a.z != b.z)); } inline int operator!=(vec3_t a, const Vector& b) { return ((a[0] != b.x) || (a[1] != b.y) || (a[2] != b.z)); } inline int operator!=(const Vector& a, vec3_t b) { return ((a.x != b[0]) || (a.y != b[1]) || (a.z != b[2])); } inline const Vector& Vector::CrossProduct(const Vector a, const Vector 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; } inline const Vector& Vector::CrossProduct(vec3_t a, const Vector b) { x = (a[1] * b.z) - (a[2] * b.y); y = (a[2] * b.x) - (a[0] * b.z); z = (a[0] * b.y) - (a[1] * b.x); return *this; } inline const Vector& Vector::CrossProduct(const Vector a, vec3_t b) { x = (a.y * b[2]) - (a.z * b[1]); y = (a.z * b[0]) - (a.x * b[2]); z = (a.x * b[1]) - (a.y * b[0]); return *this; } inline Vector Vector::Clamp(const Vector& value, const Vector& minimum, const Vector& maximum) { Vector clamped(value); Vector::Clamp(clamped, minimum, maximum); return clamped; } inline void Vector::Clamp(Vector& value, const Vector& minimum, const Vector& maximum) { for (int i = 0; i < 3; i++) { Q_clamp(value[i], minimum[i], maximum[i]); } } inline Vector Vector::Cross(const Vector& vector1, const Vector& vector2) { const Vector result( (vector1.y * vector2.z) - (vector1.z * vector2.y), (vector1.z * vector2.x) - (vector1.x * vector2.z), (vector1.x * vector2.y) - (vector1.y * vector2.x) ); return result; } inline float Vector::Dot(const Vector& vector1, const Vector& vector2) { return vector1 * vector2; } inline float Vector::Dot(vec3_t vector1, const Vector& vector2) { return vector1 * vector2; } inline float Vector::Dot(const Vector& vector1, vec3_t vector2) { return vector1 * vector2; } //---------------------------------------------------------------- // Name: lengthSquared // Class: Vector // // Description: Returns squared length of the vector // // Parameters: None // // Returns: float - squared length //---------------------------------------------------------------- inline float Vector::lengthSquared(void) const { return (x * x) + (y * y) + (z * z); } inline float Vector::length(void) const { return sqrt(lengthSquared()); } inline float Vector::lengthfast(void) const { return vrsqrt(lengthSquared()); } //---------------------------------------------------------------- // Name: lengthXY // Class: Vector // // Description: Returns length of the vector (using only the x // and y components // // Parameters: None // // Returns: float - length of the vector in the xy plane //---------------------------------------------------------------- inline float Vector::lengthXY() const { return sqrt((x * x) + (y * y)); } //---------------------------------------------------------------- // Name: lengthXYSquared // Class: Vector // // Description: Returns length of the vector squared (using only the x // and y components // // Parameters: None // // Returns: float - squared length of the vector in the xy plane //---------------------------------------------------------------- inline float Vector::lengthXYSquared() const { return (x * x) + (y * y); } //---------------------------------------------------------------- // Name: normalize // Class: Vector // // Description: unitizes the vector // // Parameters: None // // Returns: float - length of the vector before the function //---------------------------------------------------------------- inline float Vector::normalize(void) { return VectorNormalize(*this); } //---------------------------------------------------------------- // Name: normalizefast // Class: Vector // // Description: fast version of normalize // // Parameters: None // // Returns: float - length of the vector before the function //---------------------------------------------------------------- inline void Vector::normalizefast(void) { float ilength; ilength = this->lengthfast(); x *= ilength; y *= ilength; z *= ilength; } //---------------------------------------------------------------- // Name: EulerNormalize // Class: Vector // // Description: forces each component of the vector into the // range (-180, +180) by adding or subtracting 360 // This is useful when the Vector is being used as // EulerAngles to represent a rotational offset // // Parameters: None // // Returns: None //---------------------------------------------------------------- inline void Vector::EulerNormalize(void) { x = AngleNormalize180(x); y = AngleNormalize180(y); z = AngleNormalize180(z); } //---------------------------------------------------------------- // Name: EulerNormalize360 // Class: Vector // // Description: forces each component of the vector into the // range (0, +360) by adding or subtracting 360 // This is useful when the Vector is being used as // EulerAngles to represent a rotational direction // // Parameters: None // // Returns: None //---------------------------------------------------------------- inline void Vector::EulerNormalize360(void) { x = AngleNormalize360(x); y = AngleNormalize360(y); z = AngleNormalize360(z); } //---------------------------------------------------------------- // Name: Epsilon // Class: Vector // // Description: returns a standard 'small' value for the class // // Parameters: None // // Returns: float - the epsilon constant for the class //---------------------------------------------------------------- inline float Vector::Epsilon(void) { return 0.000000001f; } //---------------------------------------------------------------- // Name: Identity // Class: Vector // // Description: returns the additive identity for the class // // Parameters: None // // Returns: Vector - the identity for the class //---------------------------------------------------------------- inline Vector& Vector::Identity(void) { return vec_zero; } //---------------------------------------------------------------- // Name: Distance // Class: Vector // // Description: returns the distance between two vectors // // Parameters: // Vector - first vector // Vector - second vector // // Returns: float - distance between the two vectors //---------------------------------------------------------------- inline float Vector::Distance(const Vector& vector1, const Vector& vector2) { return (vector1 - vector2).length(); } //---------------------------------------------------------------- // Name: DistanceSquared // Class: Vector // // Description: returns the squared distance between two vectors // // Parameters: // Vector - first vector // Vector - second vector // // Returns: float - distance between the two vectors squared //---------------------------------------------------------------- inline float Vector::DistanceSquared(const Vector& vector1, const Vector& vector2) { return (vector1 - vector2).lengthSquared(); } //---------------------------------------------------------------- // Name: DistanceXY // Class: Vector // // Description: returns the distance between two vectors in the // xy plane // // Parameters: // Vector - first vector // Vector - second vector // // Returns: float - distance between the two vectors in the // xy plane //---------------------------------------------------------------- inline float Vector::DistanceXY(const Vector& vector1, const Vector& vector2) { return (vector1 - vector2).lengthXY(); } inline Vector Vector::toAngles(void) const { float forward; float yaw, pitch; if ((x == 0.0f) && (y == 0.0f)) { yaw = 0.0f; if (z > 0.0f) { pitch = 90.0f; } else { pitch = 270.0f; } } else { yaw = atan2(y, x) * 180.0f / M_PI; if (yaw < 0.0f) { yaw += 360.0f; } forward = (float)sqrt(x * x + y * y); pitch = atan2(z, forward) * 180.0f / M_PI; if (pitch < 0.0f) { pitch += 360.0f; } } return Vector(-pitch, yaw, 0.0f); } //---------------------------------------------------------------- // Name: AnglesBetween // Class: Vector // // Description: returns the smaller of the angles formed by the // two vectors // // Parameters: // Vector - first vector // Vector - second vector // // Returns: Vector - angles between the vectors //---------------------------------------------------------------- inline Vector Vector::AnglesBetween(const Vector& vector1, const Vector& vector2) { Vector unitVector1(vector1); unitVector1.normalize(); Vector unitVector2(vector2); unitVector2.normalize(); Vector angles(unitVector1.toAngles() - unitVector2.toAngles()); angles.EulerNormalize(); return angles; } //---------------------------------------------------------------- // Name: AngleBetween // Class: Vector // // Description: returns the smaller of the angles formed by the // two vectors // // Parameters: // Vector - first vector // Vector - second vector // // Returns: float - angle between the vectors //---------------------------------------------------------------- inline float Vector::AngleBetween(const Vector& vector1, const Vector& vector2) { Vector unitVector1(vector1); unitVector1.normalize(); Vector unitVector2(vector2); unitVector2.normalize(); return acos(Vector::Dot(unitVector1, unitVector2)); } //---------------------------------------------------------------- // Name: CloseEnough // Class: Vector // // Description: tests to see if the two vectors are within // 'epsilon' of each other // // Parameters: // Vector - first vector // Vector - second vector // float - amount that each component of the // vectors can be apart // // Returns: bool - the result of the test for closeness //---------------------------------------------------------------- inline bool Vector::CloseEnough(const Vector& vector1, const Vector& vector2, const float epsilon) { return Distance(vector1, vector2) < epsilon; } //---------------------------------------------------------------- // Name: SmallEnough // Class: Vector // // Description: tests to see if the vectors are within // 'epsilon' of the origin // // Parameters: // Vector - vector // float - amount that each component of the // vectors can be from the origin // // Returns: bool - the result of the test for smallness //---------------------------------------------------------------- inline bool Vector::SmallEnough(const Vector& vector, const float epsilon) { return CloseEnough(vector, Vector::Identity(), epsilon); } inline Vector Vector::operator-() const { return Vector(-x, -y, -z); } inline Vector fabs(const Vector& a) { return Vector(VECTOR_FABS(a.x), VECTOR_FABS(a.y), VECTOR_FABS(a.z)); } inline float MaxValue(const Vector& a) { float maxy; float maxz; float max; max = VECTOR_FABS(a.x); maxy = VECTOR_FABS(a.y); maxz = VECTOR_FABS(a.z); if (maxy > max) { max = maxy; } if (maxz > max) { max = maxz; } return max; } inline float Vector::toYaw(void) const { float yaw; if ((y == 0.0f) && (x == 0.0f)) { yaw = 0.0f; } else { yaw = (float)((int)(atan2(y, x) * 180.0f / M_PI)); if (yaw < 0.0f) { yaw += 360.0f; } } return yaw; } inline float Vector::toPitch(void) const { float forward; float pitch; forward = (float)sqrt((x * x) + (y * y)); pitch = (float)((int)(atan2(z, forward) * 180 / M_PI)); if (pitch < 0.0f) { pitch += 360.0f; } return pitch; } inline Vector Vector::AnglesMod(void) const { return Vector(AngleMod(x), AngleMod(y), AngleMod(z)); } inline void Vector::AngleVectors(Vector *forward, Vector *right, Vector *up) const { float angle; static float sr, sp, sy, cr, cp, cy; // static to help MS compiler fp bugs angle = yaw() * (M_PI * 2.0f / 360.0f); sy = sin(angle); cy = cos(angle); angle = pitch() * (M_PI * 2.0f / 360.0f); sp = sin(angle); cp = cos(angle); angle = roll() * (M_PI * 2.0f / 360.0f); sr = sin(angle); cr = cos(angle); if (forward) { forward->setXYZ(cp * cy, cp * sy, -sp); } if (right) { right->setXYZ((-1 * sr * sp * cy) + (-1 * cr * -sy), (-1 * sr * sp * sy) + (-1 * cr * cy), -1 * sr * cp); } if (up) { up->setXYZ((cr * sp * cy) + (-sr * -sy), (cr * sp * sy) + (-sr * cy), cr * cp); } } inline void Vector::AngleVectorsLeft(Vector *forward, Vector *left, Vector *up) const { float angle; static float sr, sp, sy, cr, cp, cy; // static to help MS compiler fp bugs angle = yaw() * (M_PI * 2 / 360); sy = sin(angle); cy = cos(angle); angle = pitch() * (M_PI * 2 / 360); sp = sin(angle); cp = cos(angle); angle = roll() * (M_PI * 2 / 360); sr = sin(angle); cr = cos(angle); if (forward) { forward->setXYZ(cp * cy, cp * sy, -sp); } if (left) { left->setXYZ((sr * sp * cy) + (cr * -sy), (sr * sp * sy) + (cr * cy), sr * cp); } if (up) { up->setXYZ((cr * sp * cy) + (-sr * -sy), (cr * sp * sy) + (-sr * cy), cr * cp); } } #define LERP_DELTA 1e-6 inline Vector LerpVector(const Vector& vector1, const Vector& vector2, const float t) { float omega, cosom, sinom, scale0, scale1; Vector w1(vector1); Vector w2(vector2); w1.normalize(); w2.normalize(); cosom = w1 * w2; if ((1.0f - cosom) > LERP_DELTA) { omega = acos(cosom); sinom = sin(omega); scale0 = sin((1.0f - t) * omega) / sinom; scale1 = sin(t * omega) / sinom; } else { scale0 = 1.0f - t; scale1 = t; } return ((w1 * scale0) + (w2 * scale1)); } class Quat { public: float x; float y; float z; float w; Quat(); Quat(Vector angles); Quat(float scrMatrix[3][3]); Quat(const float x, const float y, const float z, const float w); float *vec4(void); float operator[](const int index) const; float & operator[](const int index); void set(const float x, const float y, const float z, const float w); const Quat& operator=(const Quat& a); friend Quat operator+(const Quat& a, const Quat& b); const Quat& operator+=(const Quat& a); friend Quat operator-(const Quat& a, const Quat& b); const Quat& operator-=(const Quat& a); friend Quat operator*(const Quat& a, const float b); friend Quat operator*(const float a, const Quat& b); const Quat& operator*=(const float a); friend int operator==(const Quat &a, const Quat &b); friend int operator!=(const Quat &a, const Quat &b); float length(void) const; float lengthSquared(void) const; const Quat& normalize(void); Quat operator-() const; Vector toAngles(void); }; inline Quat::Quat() : x(0) , y(0) , z(0) , w(0) {} inline Quat::Quat(Vector Angles) { EulerToQuat(Angles, this->vec4()); } inline Quat::Quat(float srcMatrix[3][3]) { MatToQuat(srcMatrix, this->vec4()); } inline Quat::Quat(const float init_x, const float init_y, const float init_z, const float init_w) : x(init_x) , y(init_y) , z(init_z) , w(init_w) {} inline float Quat::operator[](const int index) const { assert((index >= 0) && (index < 4)); return (&x)[index]; } inline float& Quat::operator[](const int index) { assert((index >= 0) && (index < 4)); return (&x)[index]; } inline float *Quat::vec4(void) { return &x; } inline void Quat::set(const float new_x, const float new_y, const float new_z, const float new_w) { x = new_x; y = new_y; z = new_z; w = new_w; } inline const Quat& Quat::operator=(const Quat& a) { x = a.x; y = a.y; z = a.z; w = a.w; return *this; } inline Quat operator+(const Quat& a, const Quat& b) { return Quat(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w); } inline const Quat& Quat::operator+=(const Quat& a) { *this = *this + a; return *this; } inline Quat operator-(const Quat& a, const Quat& b) { return Quat(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w); } inline const Quat& Quat::operator-=(const Quat& a) { *this = *this - a; return *this; } inline Quat operator*(const Quat& a, const float b) { return Quat(a.x * b, a.y * b, a.z * b, a.w * b); } inline Quat operator*(const float a, const Quat& b) { return b * a; } inline const Quat& Quat::operator*=(const float a) { *this = *this * a; return *this; } inline int operator==(const Quat& a, const Quat& b) { return ((a.x == b.x) && (a.y == b.y) && (a.z == b.z) && (a.w == b.w)); } inline int operator!=(const Quat& a, const Quat& b) { return (((a.x != b.x) || (a.y != b.y)) || ((a.z != b.z) && (a.w != b.w))); } inline float Quat::length(void) const { float length; length = (x * x) + (y * y) + (z * z) + (w * w); return sqrt(length); } inline const Quat& Quat::normalize(void) { float length, ilength; length = this->length(); if (length) { ilength = 1.0f / length; *this *= ilength; } return *this; } inline Quat Quat::operator-() const { return Quat(-x, -y, -z, -w); } inline Vector Quat::toAngles(void) { float m[3][3]; vec3_t angles; QuatToMat(this->vec4(), m); MatrixToEulerAngles(m, angles); return Vector(angles); } inline Vector Vector::GetRotatedX(float angle) const { if (angle == 0.0) { return (*this); } float sinAngle = (float)sin(M_PI * angle / 180); float cosAngle = (float)cos(M_PI * angle / 180); return Vector(x, y * cosAngle - z * sinAngle, y * sinAngle + z * cosAngle); } inline void Vector::RotateX(double angle) { (*this) = GetRotatedX(angle); } inline Vector Vector::GetRotatedY(float angle) const { if (angle == 0.0) { return (*this); } float sinAngle = (float)sin(M_PI * angle / 180); float cosAngle = (float)cos(M_PI * angle / 180); return Vector(x * cosAngle + z * sinAngle, y, -x * sinAngle + z * cosAngle); } inline void Vector::RotateY(double angle) { (*this) = GetRotatedY(angle); } inline Vector Vector::GetRotatedZ(float angle) const { if (angle == 0.0) { return (*this); } float sinAngle = (float)sin(M_PI * angle / 180); float cosAngle = (float)cos(M_PI * angle / 180); return Vector(x * cosAngle - y * sinAngle, x * sinAngle + y * cosAngle, z); } inline void Vector::RotateZ(float angle) { (*this) = GetRotatedZ(angle); } inline void Vector::PackTo01() { (*this) = GetPackedTo01(); } inline Vector Vector::GetPackedTo01() const { Vector temp(*this); temp.normalize(); temp = temp * 0.5f + Vector(0.5f, 0.5f, 0.5f); return temp; } #undef VECTOR_FABS