/* ----------------------------------------------------------------------------- GSFramework Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. ----------------------------------------------------------------------------- */ #ifndef __NVECTOR__ #define __NVECTOR__ #include "math/nmath.h" #include "alloc/ialloc.h" namespace GS { class Matrix3; class Matrix4; namespace NML { class File; class Tag; } /*! @short Vector 2d template class. @author Emmanuel Julien (ejulien@gsworks.fr) */ template struct tVector2 { NPLACEMENT_NEW(Vector) T x, y; inline bool operator == (const tVector2 &b) const { return (x == b.x) && (y == b.y); } inline bool operator != (const tVector2 &b) const { return (x != b.x) || (y != b.y); } inline void operator += (const tVector2 &b) { x += b.x; y += b.y; } inline void operator += (const float k) { x += k; y += k; } inline void operator -= (const tVector2 &b) { x -= b.x; y -= b.y; } inline void operator -= (const float k) { x -= k; y -= k; } inline void operator *= (const tVector2 &b) { x *= b.x; y *= b.y; } inline void operator *= (const float k) { x *= k; y *= k; } inline void operator /= (const tVector2 &b) { x /= b.x; y /= b.y; } inline void operator /= (const float k) { x /= k; y /= k; } inline tVector2 operator + (const tVector2 &b) const { return tVector2 (x + b.x, y + b.y); } inline tVector2 operator + (const T v) const { return tVector2 (x + v, y + v); } inline tVector2 operator - (const tVector2 &b) const { return tVector2 (x - b.x, y - b.y); } inline tVector2 operator - (const T v) const { return tVector2 (x - v, y - v); } inline tVector2 operator * (const tVector2 &b) const { return tVector2 (x * b.x, y * b.y); } inline tVector2 operator * (const T v) const { return tVector2 (x * v, y * v); } inline tVector2 operator / (const tVector2 &b) const { return tVector2 (x / b.x, y / b.y); } inline tVector2 operator / (const T v) const { return tVector2 (x / v, y / v); } tVector2 operator * (const Matrix3 &m) const; /// Squared vector length. inline float Len2() const { return (float)(x * x + y * y); } /// Vector length. inline float Len() const { return Math::Sqrt((float)(x * x + y * y)); } /// Normalize this vector. inline void Normalize() { float l = Len(); if (l) { float k = 1.f / l; x *= k; y *= k; } } /// Normalize vector. inline tVector2 Normalized() const { float k = 1.f / Len(); return tVector2 (x * k, y * k); } /// Reversed vector. inline tVector2 Reversed() const { return tVector2 (-x, -y); } /// Vector squared distance. static float Dist2(const tVector2 &a, const tVector2 &b) { return ((b.x - a.x) * (b.x - a.x) + (b.y - a.y) * (b.y - a.y)); } /// Vector distance. static float Dist(const tVector2 &a, const tVector2 &b) { return Math::Sqrt((float)((b.x - a.x) * (b.x - a.x) + (b.y - a.y) * (b.y - a.y))); } /// Set vector 2D components. inline void Set(const T a, const T b) { x = a; y = b; } tVector2 (T a, T b) { Set(a, b); } tVector2 () { Set(0, 0); } }; typedef tVector2 Vector2; /*! @short 4-Component vector @author Emmanuel Julien (ejulien@gsworks.fr) */ struct Vector4 { NPLACEMENT_NEW(Vector) float x, y, z, w; inline bool operator == (const Vector4 &b) const { return Math::TestEqual(x, b.x) && Math::TestEqual(y, b.y) && Math::TestEqual(z, b.z); } inline bool operator != (const Vector4 &b) const { return !Math::TestEqual(x, b.x) || !Math::TestEqual(y, b.y) || !Math::TestEqual(z, b.z); } inline void operator += (const Vector4 &b) { x += b.x; y += b.y; z += b.z; }; inline void operator += (const float k) { x += k; y += k; z += k; }; inline void operator -= (const Vector4 &b) { x -= b.x; y -= b.y; z -= b.z; }; inline void operator -= (const float k) { x -= k; y -= k; z -= k; }; inline void operator *= (const Vector4 &b) { x *= b.x; y *= b.y; z *= b.z; }; inline void operator *= (const float k) { x *= k; y *= k; z *= k; }; inline void operator /= (const Vector4 &b) { x /= b.x; y /= b.y; z /= b.z; }; inline void operator /= (const float k) { float k_ = k ? 1 / k : 0; x *= k_; y *= k_; z *= k_; }; inline Vector4 operator + (const Vector4 &b) const { return Vector4(x + b.x, y + b.y, z + b.z); } inline Vector4 operator + (const float v) const { return Vector4(x + v, y + v, z + v); } inline Vector4 operator - (const Vector4 &b) const { return Vector4(x - b.x, y - b.y, z - b.z); } inline Vector4 operator - (const float v) const { return Vector4(x - v, y - v, z - v); } inline Vector4 operator * (const Vector4 &b) const { return Vector4(x * b.x, y * b.y, z * b.z); } inline Vector4 operator * (const float v) const { return Vector4(x * v, y * v, z * v); } inline Vector4 operator / (const Vector4 &b) const { return Vector4(x / b.x, y / b.y, z / b.z); } inline Vector4 operator / (const float v) const { float i = v ? 1 / v : 0; return Vector4(x * i, y * i, z * i); } inline float operator [] (size_t n) const { return (&x)[n]; } inline float &operator [] (size_t n) { return (&x)[n]; } inline Vector4 SafeDivided(const Vector4 &b) const { return Vector4(b.x ? x / b.x : 0, b.y ? y / b.y : 0, b.z ? z / b.z : 0); } /// Set vector components. inline void Set(float x_, float y_, float z_, float w_) { x = x_; y = y_; z = z_; w = w_; } inline void Set(float x_ = 0.f, float y_ = 0.f, float z_ = 0.f) // Used to provide script overload. { x = x_; y = y_; z = z_; w = 1.0f; } inline void Set(Vector4 &v) { x = v.x; y = v.y; z = v.z; w = v.w; } /// Dot product. inline float Dot(const Vector4 &b) const { return x * b.x + y * b.y + z * b.z; } /// Cross product. inline Vector4 Cross(const Vector4 &b) const { return Vector4(y * b.z - z * b.y, z * b.x - x * b.z, x * b.y - y * b.x); } void operator *= (const Matrix4 &); Vector4 operator * (const Matrix4 &) const; void operator *= (const Matrix3 &); Vector4 operator * (const Matrix3 &) const; /// Reverse this vector. inline void Reverse() { x = -x; y = -y; z = -z; } /// Inverse vector. inline void Inverse() { x = x ? 1.f / x : 0; y = y ? 1.f / y : 0; z = z ? 1.f / z : 0; } /// Normalize this vector. inline void Normalize() { float l = Len(); if (l) { float k = 1.f / l; x *= k; y *= k; z *= k; } } /// Normalize vector. inline Vector4 Normalized() const { float l = Len(); float k = l ? 1.f / l : 1.f; return Vector4(x * k, y * k, z * k); } /// Clamp vector components to [min;max]. Vector4 Clamped(float min, float max) const; /// Clamp vector components to [min;max]. Vector4 Clamped(const Vector4 &min, const Vector4 &max) const; /// Clamp vector magnitude to [min;max]. Vector4 ClampedMagnitude(float min, float max) const; /// Return the opposite vector to this vector. inline Vector4 Reversed() const { return Vector4(-x, -y, -z); } /// Return the inverse vector to this vector. inline Vector4 Inversed() const { return Vector4(1.f / x, 1.f / y, 1.f / z); } /// Absolute vector. Vector4 Abs() const; /// Sign vector. inline Vector4 Sign() const { return Vector4(x < 0.f ? -1.f : 1.f, y < 0.f ? -1.f : 1.f, z < 0.f ? -1.f : 1.f); } /// Maximum of two vectors. static Vector4 Maximum(const Vector4 &a, const Vector4 &b) { return Vector4(a.x > b.x ? a.x : b.x, a.y > b.y ? a.y : b.y, a.z > b.z ? a.z : b.z); } /// Minimum of two vectors. static Vector4 Minimum(const Vector4 &a, const Vector4 &b) { return Vector4(a.x < b.x ? a.x : b.x, a.y < b.y ? a.y : b.y, a.z < b.z ? a.z : b.z); } /*! @short Reflect vector. @note Vector must be normalized. */ inline Vector4 Reflected(const Vector4 &n) const { Vector4 rv = Reversed(); return n * (2.f * rv.Dot(n)) - rv; } /*! @short Refract vector. @note Vector must be normalized. */ inline Vector4 Refracted(const Vector4 &n, float kin = 1, float kout = 1) const { const float k = kin / kout; return (*this) * k + n * (k - 1.f); } /// Squared vector length. inline float Len2() const { return (float)(x * x + y * y + z * z); } /// Vector length. inline float Len() const { return Math::Sqrt((float)(x * x + y * y + z * z)); } /// Hash vector. int Hash() const; Vector4 Floor() const; Vector4 Ceil() const; /*! @short Return a random vector. @note w component is not randomized but set to 1. */ static Vector4 Random(float min = -1, float max = 1); /// Vector squared distance. static float Dist2(const Vector4 &a, const Vector4 &b) { return ((b.x - a.x) * (b.x - a.x) + (b.y - a.y) * (b.y - a.y) + (b.z - a.z) * (b.z - a.z)); } /// Vector distance. static float Dist(const Vector4 &a, const Vector4 &b) { return Math::Sqrt((float)((b.x - a.x) * (b.x - a.x) + (b.y - a.y) * (b.y - a.y) + (b.z - a.z) * (b.z - a.z))); } /*! @short Vector base to Euler. @note base convention u = {0,0,1}, v = {1,0,0}, second axis is optional. */ static void BaseToEuler(Vector4 &euler, Vector4 &u, Vector4 *v = NULL); /*! @short Return a vector which is facing a given direction. Returns a copy of this vector if it is already facing the given direction or the opposite of this vector otherwise. */ Vector4 FaceForward(Vector4 &dir); NML::Tag *AsMetaTag(const char *id, bool full_dump = false) const; bool FromMetaTag(NML::Tag &tag); Vector4(float a, float b, float c, float d = 1) : x(a), y(b), z(c), w(d) {} Vector4(const tVector2 &v2) : x(v2.x), y(v2.y), z(1), w(1) {} Vector4(const tVector2 &v2) : x(float(v2.x)), y(float(v2.y)), z(1), w(1) {} Vector4() {} }; } // GS #define Vec3Set(v, a, b, c) { (v).x = a; (v).y = b; (v).z = c; } #define Vec3Len2(v) ((v).x * (v).x + (v).y * (v).y + (v).z * (v).z) #define Vec3Len(v) Math::Sqrt((float)Vec3Len2(v)) #define Vec3Add(r, a, b) { (r).x = (a).x + (b).x; (r).y = (a).y + (b).y; (r).z = (a).z + (b).z; } #define Vec3AddConst(r, a, k) { (r).x = (a).x + k; (r).y = (a).y + k; (r).z = (a).z + k; } #define Vec3Sub(r, a, b) { (r).x = (a).x - (b).x; (r).y = (a).y - (b).y; (r).z = (a).z - (b).z; } #define Vec3SubConst(r, a, k) { (r).x = (a).x - k; (r).y = (a).y - k; (r).z = (a).z - k; } #define Vec3Mul(r, a, b) { (r).x = (a).x * (b).x; (r).y = (a).y * (b).y; (r).z = (a).z * (b).z; } #define Vec3MulConst(r, a, k) { float _k = k; (r).x = (a).x * _k; (r).y = (a).y * _k; (r).z = (a).z * _k; } #define Vec3Div(r, a, b) { (r).x = (a).x / (b).x; (r).y = (a).y / (b).y; (r).z = (a).z / (b).z; } #define Vec3DivConst(r, a, k) { float ik = 1.f / k; (r).x = (a).x * ik; (r).y = (a).y * ik; (r).z = (a).z * ik; } #define Vec3Inc(r, a) { (r).x += (a).x; (r).y += (a).y; (r).z += (a).z; } #define Vec3IncConst(r, k) { (r).x += k; (r).y += k; (r).z += k; } #define Vec3Dec(r, a) { (r).x -= (a).x; (r).y -= (a).y; (r).z -= (a).z; } #define Vec3DecConst(r, k) { (r).x -= k; (r).y -= k; (r).z -= k; } #define Vec3Scale(r, a) { (r).x *= (a).x; (r).y *= (a).y; (r).z *= (a).z; } #define Vec3ScaleConst(r, k) { float _k = k; (r).x *= _k; (r).y *= _k; (r).z *= _k; } #define Vec3Shrink(r, a) { (r).x /= (a).x; (r).y /= (a).y; (r).z /= (a).z; } #define Vec3ShrinkConst(r, k) { float ik = 1.f / k; (r).x *= ik; (r).y *= ik; (r).z *= ik; } #define Vec3Dot(a, b) ((a).x * (b).x + (a).y * (b).y + (a).z * (b).z) #define Vec3Cross(r, a, b) {\ (r).x = (a).y * (b).z - (a).z * (b).y;\ (r).y = (a).z * (b).x - (a).x * (b).z;\ (r).z = (a).x * (b).y - (a).y * (b).x;\ } #define Vec3Clamp(v, a, b) {\ if ((v).x < a) (v).x = a; else if ((v).x > b) (v).x = b;\ if ((v).x < a) (v).x = a; else if ((v).x > b) (v).x = b;\ if ((v).x < a) (v).x = a; else if ((v).x > b) (v).x = b;\ } #define Vec3ClampMag(v, m) {\ const float m2 = (m) * (m);\ const float l2 = Vec3Len2(v);\ if (l2 > m2)\ {\ const float k = Math::Sqrt((float)(m2 / l2));\ Vec3ScaleConst(v, k);\ }\ } #endif // __NVECTOR__