#pragma once #define _USE_MATH_DEFINES #include struct Vector2 { union { struct { float X; float Y; }; float data[2]; }; /** * Constructors. */ inline Vector2(); inline Vector2(float data[]); inline Vector2(float value); inline Vector2(float x, float y); /** * Constants for common vectors. */ static inline Vector2 Zero(); static inline Vector2 One(); static inline Vector2 Right(); static inline Vector2 Left(); static inline Vector2 Up(); static inline Vector2 Down(); //=====𝗦𝗥𝗖==𝗝𝗢𝗜𝗡==𝗧𝗘𝗟𝗘𝗚𝗥𝗔𝗠=@𝗚𝗞𝗣𝗙𝗥𝗘𝗘𝗛𝗔𝗖𝗞𝗦===@GKPHACK===V=2.4==// static inline float Angle(Vector2 a, Vector2 b); /** * Returns a vector with its magnitude clamped to maxLength. * @param vector: The target vector. * @param maxLength: The maximum length of the return vector. * @return: A new vector. */ static inline Vector2 ClampMagnitude(Vector2 vector, float maxLength); /** * Returns the component of a in the direction of b (scalar projection). * @param a: The target vector. * @param b: The vector being compared against. * @return: A scalar value. */ static inline float Component(Vector2 a, Vector2 b); /** * Returns the distance between a and b. * @param a: The first point. * @param b: The second point. * @return: A scalar value. */ static inline float Distance(Vector2 a, Vector2 b); /** * Returns the dot product of two vectors. * @param lhs: The left side of the multiplication. * @param rhs: The right side of the multiplication. * @return: A scalar value. */ static inline float Dot(Vector2 lhs, Vector2 rhs); /** * Converts a polar representation of a vector into cartesian * coordinates. * @param rad: The magnitude of the vector. * @param theta: The angle from the X axis. * @return: A new vector. */ static inline Vector2 FromPolar(float rad, float theta); /** * Returns a vector linearly interpolated between a and b, moving along * a straight line. The vector is clamped to never go beyond the end points. * @param a: The starting point. * @param b: The ending point. * @param t: The interpolation value [0-1]. * @return: A new vector. */ static inline Vector2 Lerp(Vector2 a, Vector2 b, float t); /** * Returns a vector linearly interpolated between a and b, moving along * a straight line. * @param a: The starting point. * @param b: The ending point. * @param t: The interpolation value [0-1] (no actual bounds). * @return: A new vector. */ static inline Vector2 LerpUnclamped(Vector2 a, Vector2 b, float t); /** * Returns the magnitude of a vector. * @param v: The vector in question. * @return: A scalar value. */ static inline float Magnitude(Vector2 v); /** * Returns a vector made from the largest components of two other vectors. * @param a: The first vector. * @param b: The second vector. * @return: A new vector. */ static inline Vector2 Max(Vector2 a, Vector2 b); /** * Returns a vector made from the smallest components of two other vectors. * @param a: The first vector. * @param b: The second vector. * @return: A new vector. */ static inline Vector2 Min(Vector2 a, Vector2 b); /** * Returns a vector "maxDistanceDelta" units closer to the target. This * interpolation is in a straight line, and will not overshoot. * @param current: The current position. * @param target: The destination position. * @param maxDistanceDelta: The maximum distance to move. * @return: A new vector. */ static inline Vector2 MoveTowards(Vector2 current, Vector2 target, float maxDistanceDelta); /** * Returns a new vector with magnitude of one. * @param v: The vector in question. * @return: A new vector. */ static inline Vector2 Normalized(Vector2 v); /** * Creates a new coordinate system out of the two vectors. * Normalizes "normal" and normalizes "tangent" and makes it orthogonal to * "normal".. * @param normal: A reference to the first axis vector. * @param tangent: A reference to the second axis vector. */ static inline void OrthoNormalize(Vector2 &normal, Vector2 &tangent); /** * Returns the vector projection of a onto b. * @param a: The target vector. * @param b: The vector being projected onto. * @return: A new vector. */ static inline Vector2 Project(Vector2 a, Vector2 b); /** * Returns a vector reflected about the provided line. * This behaves as if there is a plane with the line as its normal, and the * vector comes in and bounces off this plane. * @param vector: The vector traveling inward at the imaginary plane. * @param line: The line about which to reflect. * @return: A new vector pointing outward from the imaginary plane. */ static inline Vector2 Reflect(Vector2 vector, Vector2 line); /** * Returns the vector rejection of a on b. * @param a: The target vector. * @param b: The vector being projected onto. * @return: A new vector. */ static inline Vector2 Reject(Vector2 a, Vector2 b); /** * Rotates vector "current" towards vector "target" by "maxRadiansDelta". * This treats the vectors as directions and will linearly interpolate * between their magnitudes by "maxMagnitudeDelta". This function does not * overshoot. If a negative delta is supplied, it will rotate away from * "target" until it is pointing the opposite direction, but will not * overshoot that either. * @param current: The starting direction. * @param target: The destination direction. * @param maxRadiansDelta: The maximum number of radians to rotate. * @param maxMagnitudeDelta: The maximum delta for magnitude interpolation. * @return: A new vector. */ static inline Vector2 RotateTowards(Vector2 current, Vector2 target, float maxRadiansDelta, float maxMagnitudeDelta); /** * Multiplies two vectors component-wise. * @param a: The lhs of the multiplication. * @param b: The rhs of the multiplication. * @return: A new vector. */ static inline Vector2 Scale(Vector2 a, Vector2 b); /** * Returns a vector rotated towards b from a by the percent t. * Since interpolation is done spherically, the vector moves at a constant * angular velocity. This rotation is clamped to 0 <= t <= 1. * @param a: The starting direction. * @param b: The ending direction. * @param t: The interpolation value [0-1]. */ static inline Vector2 Slerp(Vector2 a, Vector2 b, float t); /** * Returns a vector rotated towards b from a by the percent t. * Since interpolation is done spherically, the vector moves at a constant * angular velocity. This rotation is unclamped. * @param a: The starting direction. * @param b: The ending direction. * @param t: The interpolation value [0-1]. */ static inline Vector2 SlerpUnclamped(Vector2 a, Vector2 b, float t); /** * Returns the squared magnitude of a vector. * This is useful when comparing relative lengths, where the exact length * is not important, and much time can be saved by not calculating the * square root. * @param v: The vector in question. * @return: A scalar value. */ static inline float SqrMagnitude(Vector2 v); /** * Calculates the polar coordinate space representation of a vector. * @param vector: The vector to convert. * @param rad: The magnitude of the vector. * @param theta: The angle from the X axis. */ static inline void ToPolar(Vector2 vector, float &rad, float &theta); /** * Operator overloading. */ inline struct Vector2& operator+=(const float rhs); inline struct Vector2& operator-=(const float rhs); inline struct Vector2& operator*=(const float rhs); inline struct Vector2& operator/=(const float rhs); inline struct Vector2& operator+=(const Vector2 rhs); inline struct Vector2& operator-=(const Vector2 rhs); }; inline Vector2 operator-(Vector2 rhs); inline Vector2 operator+(Vector2 lhs, const float rhs); inline Vector2 operator-(Vector2 lhs, const float rhs); inline Vector2 operator*(Vector2 lhs, const float rhs); inline Vector2 operator/(Vector2 lhs, const float rhs); inline Vector2 operator+(const float lhs, Vector2 rhs); inline Vector2 operator-(const float lhs, Vector2 rhs); inline Vector2 operator*(const float lhs, Vector2 rhs); inline Vector2 operator/(const float lhs, Vector2 rhs); inline Vector2 operator+(Vector2 lhs, const Vector2 rhs); inline Vector2 operator-(Vector2 lhs, const Vector2 rhs); inline bool operator==(const Vector2 lhs, const Vector2 rhs); inline bool operator!=(const Vector2 lhs, const Vector2 rhs); /******************************************************************************* * Implementation */ Vector2::Vector2() : X(0), Y(0) {} Vector2::Vector2(float data[]) : X(data[0]), Y(data[1]) {} Vector2::Vector2(float value) : X(value), Y(value) {} Vector2::Vector2(float x, float y) : X(x), Y(y) {} Vector2 Vector2::Zero() { return Vector2(0, 0); } Vector2 Vector2::One() { return Vector2(1, 1); } Vector2 Vector2::Right() { return Vector2(1, 0); } Vector2 Vector2::Left() { return Vector2(-1, 0); } Vector2 Vector2::Up() { return Vector2(0, 1); } Vector2 Vector2::Down() { return Vector2(0, -1); } float Vector2::Angle(Vector2 a, Vector2 b) { float v = Dot(a, b) / (Magnitude(a) * Magnitude(b)); v = fmax(v, -1.0); v = fmin(v, 1.0); return acos(v); } Vector2 Vector2::ClampMagnitude(Vector2 vector, float maxLength) { float length = Magnitude(vector); if (length > maxLength) vector *= maxLength / length; return vector; } float Vector2::Component(Vector2 a, Vector2 b) { return Dot(a, b) / Magnitude(b); } float Vector2::Distance(Vector2 a, Vector2 b) { return Vector2::Magnitude(a - b); } float Vector2::Dot(Vector2 lhs, Vector2 rhs) { return lhs.X * rhs.X + lhs.Y * rhs.Y; } Vector2 Vector2::FromPolar(float rad, float theta) { Vector2 v; v.X = rad * cos(theta); v.Y = rad * sin(theta); return v; } Vector2 Vector2::Lerp(Vector2 a, Vector2 b, float t) { if (t < 0) return a; else if (t > 1) return b; return LerpUnclamped(a, b, t); } Vector2 Vector2::LerpUnclamped(Vector2 a, Vector2 b, float t) { return (b - a) * t + a; } float Vector2::Magnitude(Vector2 v) { return sqrt(SqrMagnitude(v)); } Vector2 Vector2::Max(Vector2 a, Vector2 b) { float x = a.X > b.X ? a.X : b.X; float y = a.Y > b.Y ? a.Y : b.Y; return Vector2(x, y); } Vector2 Vector2::Min(Vector2 a, Vector2 b) { float x = a.X > b.X ? b.X : a.X; float y = a.Y > b.Y ? b.Y : a.Y; return Vector2(x, y); } Vector2 Vector2::MoveTowards(Vector2 current, Vector2 target, float maxDistanceDelta) { Vector2 d = target - current; float m = Magnitude(d); if (m < maxDistanceDelta || m == 0) return target; return current + (d * maxDistanceDelta / m); } Vector2 Vector2::Normalized(Vector2 v) { float mag = Magnitude(v); if (mag == 0) return Vector2::Zero(); return v / mag; } void Vector2::OrthoNormalize(Vector2 &normal, Vector2 &tangent) { normal = Normalized(normal); tangent = Reject(tangent, normal); tangent = Normalized(tangent); } Vector2 Vector2::Project(Vector2 a, Vector2 b) { float m = Magnitude(b); return Dot(a, b) / (m * m) * b; } Vector2 Vector2::Reflect(Vector2 vector, Vector2 planeNormal) { return vector - 2 * Project(vector, planeNormal); } Vector2 Vector2::Reject(Vector2 a, Vector2 b) { return a - Project(a, b); } Vector2 Vector2::RotateTowards(Vector2 current, Vector2 target, float maxRadiansDelta, float maxMagnitudeDelta) { float magCur = Magnitude(current); float magTar = Magnitude(target); float newMag = magCur + maxMagnitudeDelta * ((magTar > magCur) - (magCur > magTar)); newMag = fmin(newMag, fmax(magCur, magTar)); newMag = fmax(newMag, fmin(magCur, magTar)); float totalAngle = Angle(current, target) - maxRadiansDelta; if (totalAngle <= 0) return Normalized(target) * newMag; else if (totalAngle >= M_PI) return Normalized(-target) * newMag; float axis = current.X * target.Y - current.Y * target.X; axis = axis / fabs(axis); if (!(1 - fabs(axis) < 0.00001)) axis = 1; current = Normalized(current); Vector2 newVector = current * cos(maxRadiansDelta) + Vector2(-current.Y, current.X) * sin(maxRadiansDelta) * axis; return newVector * newMag; } Vector2 Vector2::Scale(Vector2 a, Vector2 b) { return Vector2(a.X * b.X, a.Y * b.Y); } Vector2 Vector2::Slerp(Vector2 a, Vector2 b, float t) { if (t < 0) return a; else if (t > 1) return b; return SlerpUnclamped(a, b, t); } Vector2 Vector2::SlerpUnclamped(Vector2 a, Vector2 b, float t) { float magA = Magnitude(a); float magB = Magnitude(b); a /= magA; b /= magB; float dot = Dot(a, b); dot = fmax(dot, -1.0); dot = fmin(dot, 1.0); float theta = acos(dot) * t; Vector2 relativeVec = Normalized(b - a * dot); Vector2 newVec = a * cos(theta) + relativeVec * sin(theta); return newVec * (magA + (magB - magA) * t); } float Vector2::SqrMagnitude(Vector2 v) { return v.X * v.X + v.Y * v.Y; } void Vector2::ToPolar(Vector2 vector, float &rad, float &theta) { rad = Magnitude(vector); theta = atan2(vector.Y, vector.X); } struct Vector2& Vector2::operator+=(const float rhs) { X += rhs; Y += rhs; return *this; } struct Vector2& Vector2::operator-=(const float rhs) { X -= rhs; Y -= rhs; return *this; } struct Vector2& Vector2::operator*=(const float rhs) { X *= rhs; Y *= rhs; return *this; } struct Vector2& Vector2::operator/=(const float rhs) { X /= rhs; Y /= rhs; return *this; } struct Vector2& Vector2::operator+=(const Vector2 rhs) { X += rhs.X; Y += rhs.Y; return *this; } struct Vector2& Vector2::operator-=(const Vector2 rhs) { X -= rhs.X; Y -= rhs.Y; return *this; } Vector2 operator-(Vector2 rhs) { return rhs * -1; } Vector2 operator+(Vector2 lhs, const float rhs) { return lhs += rhs; } Vector2 operator-(Vector2 lhs, const float rhs) { return lhs -= rhs; } Vector2 operator*(Vector2 lhs, const float rhs) { return lhs *= rhs; } Vector2 operator/(Vector2 lhs, const float rhs) { return lhs /= rhs; } Vector2 operator+(const float lhs, Vector2 rhs) { return rhs += lhs; } Vector2 operator-(const float lhs, Vector2 rhs) { return rhs -= lhs; } Vector2 operator*(const float lhs, Vector2 rhs) { return rhs *= lhs; } Vector2 operator/(const float lhs, Vector2 rhs) { return rhs /= lhs; } Vector2 operator+(Vector2 lhs, const Vector2 rhs) { return lhs += rhs; } Vector2 operator-(Vector2 lhs, const Vector2 rhs) { return lhs -= rhs; } bool operator==(const Vector2 lhs, const Vector2 rhs) { return lhs.X == rhs.X && lhs.Y == rhs.Y; } bool operator!=(const Vector2 lhs, const Vector2 rhs) { return !(lhs == rhs); }