made vec templates.
This commit is contained in:
@@ -6,17 +6,18 @@
|
||||
#include <string>
|
||||
#include <ostream>
|
||||
|
||||
template<typename T>
|
||||
class Vec3 {
|
||||
public:
|
||||
float x, y, z;
|
||||
T x, y, z;
|
||||
|
||||
Vec3() : x(0), y(0), z(0) {}
|
||||
Vec3(float x, float y, float z) : x(x), y(y), z(z) {}
|
||||
Vec3(float scalar) : x(scalar), y(scalar), z(scalar) {}
|
||||
Vec3(T x, T y, T z) : x(x), y(y), z(z) {}
|
||||
Vec3(T scalar) : x(scalar), y(scalar), z(scalar) {}
|
||||
|
||||
Vec3(const class Vec2& vec2, float z = 0.0f);
|
||||
Vec3(const class Vec2& vec2, T z = 0);
|
||||
|
||||
Vec3& move(const Vec3 newpos) {
|
||||
Vec3& move(const Vec3& newpos) {
|
||||
x = newpos.x;
|
||||
y = newpos.y;
|
||||
z = newpos.z;
|
||||
@@ -40,11 +41,11 @@ public:
|
||||
return Vec3(x / other.x, y / other.y, z / other.z);
|
||||
}
|
||||
|
||||
Vec3 operator+(float scalar) const {
|
||||
Vec3 operator+(T scalar) const {
|
||||
return Vec3(x + scalar, y + scalar, z + scalar);
|
||||
}
|
||||
|
||||
Vec3 operator-(float scalar) const {
|
||||
Vec3 operator-(T scalar) const {
|
||||
return Vec3(x - scalar, y - scalar, z - scalar);
|
||||
}
|
||||
|
||||
@@ -52,15 +53,15 @@ public:
|
||||
return Vec3(-x, -y, -z);
|
||||
}
|
||||
|
||||
Vec3 operator*(float scalar) const {
|
||||
Vec3 operator*(T scalar) const {
|
||||
return Vec3(x * scalar, y * scalar, z * scalar);
|
||||
}
|
||||
|
||||
Vec3 operator/(float scalar) const {
|
||||
Vec3 operator/(T scalar) const {
|
||||
return Vec3(x / scalar, y / scalar, z / scalar);
|
||||
}
|
||||
|
||||
Vec3& operator=(float scalar) {
|
||||
Vec3& operator=(T scalar) {
|
||||
x = y = z = scalar;
|
||||
return *this;
|
||||
}
|
||||
@@ -93,28 +94,28 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
Vec3& operator+=(float scalar) {
|
||||
Vec3& operator+=(T scalar) {
|
||||
x += scalar;
|
||||
y += scalar;
|
||||
z += scalar;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Vec3& operator-=(float scalar) {
|
||||
Vec3& operator-=(T scalar) {
|
||||
x -= scalar;
|
||||
y -= scalar;
|
||||
z -= scalar;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Vec3& operator*=(float scalar) {
|
||||
Vec3& operator*=(T scalar) {
|
||||
x *= scalar;
|
||||
y *= scalar;
|
||||
z *= scalar;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Vec3& operator/=(float scalar) {
|
||||
Vec3& operator/=(T scalar) {
|
||||
x /= scalar;
|
||||
y /= scalar;
|
||||
z /= scalar;
|
||||
@@ -125,7 +126,7 @@ public:
|
||||
return x * other.x + y * other.y + z * other.z;
|
||||
}
|
||||
|
||||
Vec3 cross(const Vec3& other) const {
|
||||
Vec3& cross(const Vec3& other) const {
|
||||
return Vec3(
|
||||
y * other.z - z * other.y,
|
||||
z * other.x - x * other.z,
|
||||
@@ -133,25 +134,25 @@ public:
|
||||
);
|
||||
}
|
||||
|
||||
float length() const {
|
||||
return std::sqrt(x * x + y * y + z * z);
|
||||
T length() const {
|
||||
return static_cast<T>(std::sqrt(static_cast<double>(x * x + y * y + z * z)));
|
||||
}
|
||||
|
||||
float lengthSquared() const {
|
||||
T lengthSquared() const {
|
||||
return x * x + y * y + z * z;
|
||||
}
|
||||
|
||||
float distance(const Vec3& other) const {
|
||||
T distance(const Vec3& other) const {
|
||||
return (*this - other).length();
|
||||
}
|
||||
|
||||
float distanceSquared(const Vec3& other) const {
|
||||
T distanceSquared(const Vec3& other) const {
|
||||
Vec3 diff = *this - other;
|
||||
return diff.x * diff.x + diff.y * diff.y + diff.z * diff.z;
|
||||
}
|
||||
|
||||
Vec3 normalized() const {
|
||||
float len = length();
|
||||
T len = length();
|
||||
if (len > 0) {
|
||||
return *this / len;
|
||||
}
|
||||
@@ -222,7 +223,7 @@ public:
|
||||
);
|
||||
}
|
||||
|
||||
Vec3 clamp(float minVal, float maxVal) const {
|
||||
Vec3 clamp(T minVal, T maxVal) const {
|
||||
return Vec3(
|
||||
std::clamp(x, minVal, maxVal),
|
||||
std::clamp(y, minVal, maxVal),
|
||||
@@ -240,19 +241,19 @@ public:
|
||||
std::abs(z - other.z) < epsilon;
|
||||
}
|
||||
|
||||
friend Vec3 operator+(float scalar, const Vec3& vec) {
|
||||
friend Vec3 operator+(T scalar, const Vec3& vec) {
|
||||
return Vec3(scalar + vec.x, scalar + vec.y, scalar + vec.z);
|
||||
}
|
||||
|
||||
friend Vec3 operator-(float scalar, const Vec3& vec) {
|
||||
friend Vec3 operator-(T scalar, const Vec3& vec) {
|
||||
return Vec3(scalar - vec.x, scalar - vec.y, scalar - vec.z);
|
||||
}
|
||||
|
||||
friend Vec3 operator*(float scalar, const Vec3& vec) {
|
||||
friend Vec3 operator*(T scalar, const Vec3& vec) {
|
||||
return Vec3(scalar * vec.x, scalar * vec.y, scalar * vec.z);
|
||||
}
|
||||
|
||||
friend Vec3 operator/(float scalar, const Vec3& vec) {
|
||||
friend Vec3 operator/(T scalar, const Vec3& vec) {
|
||||
return Vec3(scalar / vec.x, scalar / vec.y, scalar / vec.z);
|
||||
}
|
||||
|
||||
@@ -260,17 +261,17 @@ public:
|
||||
return *this - 2.0f * this->dot(normal) * normal;
|
||||
}
|
||||
|
||||
Vec3 lerp(const Vec3& other, float t) const {
|
||||
Vec3 lerp(const Vec3& other, T t) const {
|
||||
t = std::clamp(t, 0.0f, 1.0f);
|
||||
return *this + (other - *this) * t;
|
||||
}
|
||||
|
||||
Vec3 slerp(const Vec3& other, float t) const {
|
||||
Vec3 slerp(const Vec3& other, T t) const {
|
||||
t = std::clamp(t, 0.0f, 1.0f);
|
||||
float dot = this->dot(other);
|
||||
T dot = this->dot(other);
|
||||
dot = std::clamp(dot, -1.0f, 1.0f);
|
||||
|
||||
float theta = std::acos(dot) * t;
|
||||
T theta = std::acos(dot) * t;
|
||||
Vec3 relative = other - *this * dot;
|
||||
relative = relative.normalized();
|
||||
|
||||
@@ -326,11 +327,11 @@ public:
|
||||
return direction.angleTo(other);
|
||||
}
|
||||
|
||||
float& operator[](int index) {
|
||||
T& operator[](int index) {
|
||||
return (&x)[index];
|
||||
}
|
||||
|
||||
const float& operator[](int index) const {
|
||||
const T& operator[](int index) const {
|
||||
return (&x)[index];
|
||||
}
|
||||
|
||||
@@ -345,16 +346,22 @@ public:
|
||||
};
|
||||
};
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os, const Vec3& vec) {
|
||||
using Vec3f = Vec3<float>;
|
||||
using Vec3d = Vec3<double>;
|
||||
using Vec3i = Vec3<int>;
|
||||
using Vec3ui8 = Vec3<uint8_t>;
|
||||
|
||||
template<typename T>
|
||||
inline std::ostream& operator<<(std::ostream& os, const Vec3<T>& vec) {
|
||||
os << vec.toString();
|
||||
return os;
|
||||
}
|
||||
|
||||
namespace std {
|
||||
template<>
|
||||
struct hash<Vec3> {
|
||||
size_t operator()(const Vec3& v) const {
|
||||
return hash<float>()(v.x) ^ (hash<float>()(v.y) << 1) ^ (hash<float>()(v.z) << 2);
|
||||
template<typename T>
|
||||
struct hash<Vec3<T>> {
|
||||
size_t operator()(const Vec3<T>& v) const {
|
||||
return hash<T>()(v.x) ^ (hash<T>()(v.y) << 1) ^ (hash<T>()(v.z) << 2);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -8,24 +8,25 @@
|
||||
#include <ostream>
|
||||
#include <cstdint>
|
||||
|
||||
template<typename T>
|
||||
class Vec4 {
|
||||
public:
|
||||
union {
|
||||
struct { float x, y, z, w; };
|
||||
struct { float r, g, b, a; };
|
||||
struct { float s, t, p, q; }; // For texture coordinates
|
||||
struct { T x, y, z, w; };
|
||||
struct { T r, g, b, a; };
|
||||
struct { T s, t, p, q; }; // For texture coordinates
|
||||
};
|
||||
|
||||
// Constructors
|
||||
Vec4() : x(0), y(0), z(0), w(0) {}
|
||||
Vec4(float x, float y, float z, float w) : x(x), y(y), z(z), w(w) {}
|
||||
Vec4(float scalar) : x(scalar), y(scalar), z(scalar), w(scalar) {}
|
||||
Vec4(T x, T y, T z, T w) : x(x), y(y), z(z), w(w) {}
|
||||
Vec4(T scalar) : x(scalar), y(scalar), z(scalar), w(scalar) {}
|
||||
|
||||
Vec4(const Vec3& rgb, float w = 1.0f) : x(rgb.x), y(rgb.y), z(rgb.z), w(w) {}
|
||||
static Vec4 RGB(float r, float g, float b, float a = 1.0f) { return Vec4(r, g, b, a); }
|
||||
static Vec4 RGBA(float r, float g, float b, float a) { return Vec4(r, g, b, a); }
|
||||
Vec4(const Vec3<T>& rgb, T w = 1) : x(rgb.x), y(rgb.y), z(rgb.z), w(w) {}
|
||||
static Vec4 RGB(T r, T g, T b, T a = 1) { return Vec4(r, g, b, a); }
|
||||
static Vec4 RGBA(T r, T g, T b, T a) { return Vec4(r, g, b, a); }
|
||||
|
||||
Vec4& recolor(const Vec4 newColor) {
|
||||
Vec4& recolor(const Vec4& newColor) {
|
||||
r = newColor.r;
|
||||
g = newColor.g;
|
||||
b = newColor.b;
|
||||
@@ -34,7 +35,7 @@ public:
|
||||
}
|
||||
|
||||
Vec4 average(const Vec4& other) const {
|
||||
return Vec4((x+other.x)/2,(y+other.y)/2,(z+other.z)/2,(w+other.w)/2);
|
||||
return Vec4((x + other.x) / 2, (y + other.y) / 2, (z + other.z) / 2, (w + other.w) / 2);
|
||||
}
|
||||
|
||||
Vec4 operator+(const Vec4& other) const {
|
||||
@@ -53,11 +54,11 @@ public:
|
||||
return Vec4(x / other.x, y / other.y, z / other.z, w / other.w);
|
||||
}
|
||||
|
||||
Vec4 operator+(float scalar) const {
|
||||
Vec4 operator+(T scalar) const {
|
||||
return Vec4(x + scalar, y + scalar, z + scalar, w + scalar);
|
||||
}
|
||||
|
||||
Vec4 operator-(float scalar) const {
|
||||
Vec4 operator-(T scalar) const {
|
||||
return Vec4(x - scalar, y - scalar, z - scalar, w - scalar);
|
||||
}
|
||||
|
||||
@@ -65,15 +66,15 @@ public:
|
||||
return Vec4(-x, -y, -z, -w);
|
||||
}
|
||||
|
||||
Vec4 operator*(float scalar) const {
|
||||
Vec4 operator*(T scalar) const {
|
||||
return Vec4(x * scalar, y * scalar, z * scalar, w * scalar);
|
||||
}
|
||||
|
||||
Vec4 operator/(float scalar) const {
|
||||
Vec4 operator/(T scalar) const {
|
||||
return Vec4(x / scalar, y / scalar, z / scalar, w / scalar);
|
||||
}
|
||||
|
||||
Vec4& operator=(float scalar) {
|
||||
Vec4& operator=(T scalar) {
|
||||
x = y = z = w = scalar;
|
||||
return *this;
|
||||
}
|
||||
@@ -110,7 +111,7 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
Vec4& operator+=(float scalar) {
|
||||
Vec4& operator+=(T scalar) {
|
||||
x += scalar;
|
||||
y += scalar;
|
||||
z += scalar;
|
||||
@@ -118,7 +119,7 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
Vec4& operator-=(float scalar) {
|
||||
Vec4& operator-=(T scalar) {
|
||||
x -= scalar;
|
||||
y -= scalar;
|
||||
z -= scalar;
|
||||
@@ -126,7 +127,7 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
Vec4& operator*=(float scalar) {
|
||||
Vec4& operator*=(T scalar) {
|
||||
x *= scalar;
|
||||
y *= scalar;
|
||||
z *= scalar;
|
||||
@@ -134,7 +135,7 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
Vec4& operator/=(float scalar) {
|
||||
Vec4& operator/=(T scalar) {
|
||||
x /= scalar;
|
||||
y /= scalar;
|
||||
z /= scalar;
|
||||
@@ -142,50 +143,50 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
float dot(const Vec4& other) const {
|
||||
T dot(const Vec4& other) const {
|
||||
return x * other.x + y * other.y + z * other.z + w * other.w;
|
||||
}
|
||||
|
||||
// 4D cross product (returns vector perpendicular to 3 given vectors in 4D space)
|
||||
Vec4 cross(const Vec4& v1, const Vec4& v2, const Vec4& v3) const {
|
||||
float a = v1.y * (v2.z * v3.w - v2.w * v3.z) -
|
||||
v1.z * (v2.y * v3.w - v2.w * v3.y) +
|
||||
v1.w * (v2.y * v3.z - v2.z * v3.y);
|
||||
T a = v1.y * (v2.z * v3.w - v2.w * v3.z) -
|
||||
v1.z * (v2.y * v3.w - v2.w * v3.y) +
|
||||
v1.w * (v2.y * v3.z - v2.z * v3.y);
|
||||
|
||||
float b = -v1.x * (v2.z * v3.w - v2.w * v3.z) +
|
||||
v1.z * (v2.x * v3.w - v2.w * v3.x) -
|
||||
v1.w * (v2.x * v3.z - v2.z * v3.x);
|
||||
T b = -v1.x * (v2.z * v3.w - v2.w * v3.z) +
|
||||
v1.z * (v2.x * v3.w - v2.w * v3.x) -
|
||||
v1.w * (v2.x * v3.z - v2.z * v3.x);
|
||||
|
||||
float c = v1.x * (v2.y * v3.w - v2.w * v3.y) -
|
||||
v1.y * (v2.x * v3.w - v2.w * v3.x) +
|
||||
v1.w * (v2.x * v3.y - v2.y * v3.x);
|
||||
T c = v1.x * (v2.y * v3.w - v2.w * v3.y) -
|
||||
v1.y * (v2.x * v3.w - v2.w * v3.x) +
|
||||
v1.w * (v2.x * v3.y - v2.y * v3.x);
|
||||
|
||||
float d = -v1.x * (v2.y * v3.z - v2.z * v3.y) +
|
||||
v1.y * (v2.x * v3.z - v2.z * v3.x) -
|
||||
v1.z * (v2.x * v3.y - v2.y * v3.x);
|
||||
T d = -v1.x * (v2.y * v3.z - v2.z * v3.y) +
|
||||
v1.y * (v2.x * v3.z - v2.z * v3.x) -
|
||||
v1.z * (v2.x * v3.y - v2.y * v3.x);
|
||||
|
||||
return Vec4(a, b, c, d);
|
||||
}
|
||||
|
||||
float length() const {
|
||||
return std::sqrt(x * x + y * y + z * z + w * w);
|
||||
T length() const {
|
||||
return static_cast<T>(std::sqrt(static_cast<double>(x * x + y * y + z * z + w * w)));
|
||||
}
|
||||
|
||||
float lengthSquared() const {
|
||||
T lengthSquared() const {
|
||||
return x * x + y * y + z * z + w * w;
|
||||
}
|
||||
|
||||
float distance(const Vec4& other) const {
|
||||
T distance(const Vec4& other) const {
|
||||
return (*this - other).length();
|
||||
}
|
||||
|
||||
float distanceSquared(const Vec4& other) const {
|
||||
T distanceSquared(const Vec4& other) const {
|
||||
Vec4 diff = *this - other;
|
||||
return diff.x * diff.x + diff.y * diff.y + diff.z * diff.z + diff.w * diff.w;
|
||||
}
|
||||
|
||||
Vec4 normalized() const {
|
||||
float len = length();
|
||||
T len = length();
|
||||
if (len > 0) {
|
||||
return *this / len;
|
||||
}
|
||||
@@ -194,8 +195,8 @@ public:
|
||||
|
||||
// Homogeneous normalization (divide by w)
|
||||
Vec4 homogenized() const {
|
||||
if (w != 0.0f) {
|
||||
return Vec4(x / w, y / w, z / w, 1.0f);
|
||||
if (w != 0) {
|
||||
return Vec4(x / w, y / w, z / w, 1);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
@@ -203,36 +204,45 @@ public:
|
||||
// Clamp values between 0 and 1
|
||||
Vec4 clamped() const {
|
||||
return Vec4(
|
||||
std::clamp(r, 0.0f, 1.0f),
|
||||
std::clamp(g, 0.0f, 1.0f),
|
||||
std::clamp(b, 0.0f, 1.0f),
|
||||
std::clamp(a, 0.0f, 1.0f)
|
||||
std::clamp(r, static_cast<T>(0), static_cast<T>(1)),
|
||||
std::clamp(g, static_cast<T>(0), static_cast<T>(1)),
|
||||
std::clamp(b, static_cast<T>(0), static_cast<T>(1)),
|
||||
std::clamp(a, static_cast<T>(0), static_cast<T>(1))
|
||||
);
|
||||
}
|
||||
|
||||
// Convert to Vec3 (ignoring alpha)
|
||||
Vec3 toVec3() const {
|
||||
return Vec3(r, g, b);
|
||||
Vec3<T> toVec3() const {
|
||||
return Vec3<T>(r, g, b);
|
||||
}
|
||||
|
||||
// Convert to 8-bit color values
|
||||
void toUint8(uint8_t& red, uint8_t& green, uint8_t& blue, uint8_t& alpha) const {
|
||||
red = static_cast<uint8_t>(std::clamp(r, 0.0f, 1.0f) * 255);
|
||||
green = static_cast<uint8_t>(std::clamp(g, 0.0f, 1.0f) * 255);
|
||||
blue = static_cast<uint8_t>(std::clamp(b, 0.0f, 1.0f) * 255);
|
||||
alpha = static_cast<uint8_t>(std::clamp(a, 0.0f, 1.0f) * 255);
|
||||
template<typename U = T>
|
||||
typename std::enable_if<std::is_floating_point<U>::value>::type
|
||||
toUint8(uint8_t& red, uint8_t& green, uint8_t& blue, uint8_t& alpha) const {
|
||||
red = static_cast<uint8_t>(std::clamp(r, static_cast<T>(0), static_cast<T>(1)) * 255);
|
||||
green = static_cast<uint8_t>(std::clamp(g, static_cast<T>(0), static_cast<T>(1)) * 255);
|
||||
blue = static_cast<uint8_t>(std::clamp(b, static_cast<T>(0), static_cast<T>(1)) * 255);
|
||||
alpha = static_cast<uint8_t>(std::clamp(a, static_cast<T>(0), static_cast<T>(1)) * 255);
|
||||
}
|
||||
|
||||
void toUint8(uint8_t& red, uint8_t& green, uint8_t& blue) const {
|
||||
red = static_cast<uint8_t>(std::clamp(r, 0.0f, 1.0f) * 255);
|
||||
green = static_cast<uint8_t>(std::clamp(g, 0.0f, 1.0f) * 255);
|
||||
blue = static_cast<uint8_t>(std::clamp(b, 0.0f, 1.0f) * 255);
|
||||
template<typename U = T>
|
||||
typename std::enable_if<std::is_floating_point<U>::value>::type
|
||||
toUint8(uint8_t& red, uint8_t& green, uint8_t& blue) const {
|
||||
red = static_cast<uint8_t>(std::clamp(r, static_cast<T>(0), static_cast<T>(1)) * 255);
|
||||
green = static_cast<uint8_t>(std::clamp(g, static_cast<T>(0), static_cast<T>(1)) * 255);
|
||||
blue = static_cast<uint8_t>(std::clamp(b, static_cast<T>(0), static_cast<T>(1)) * 255);
|
||||
}
|
||||
|
||||
// Get XYZ components as Vec3
|
||||
class Vec3 xyz() const;
|
||||
Vec3<T> xyz() const {
|
||||
return Vec3<T>(x, y, z);
|
||||
}
|
||||
|
||||
// Get RGB components as Vec3
|
||||
class Vec3 rgb() const;
|
||||
Vec3<T> rgb() const {
|
||||
return Vec3<T>(r, g, b);
|
||||
}
|
||||
|
||||
bool operator==(const Vec4& other) const {
|
||||
return x == other.x && y == other.y && z == other.z && w == other.w;
|
||||
@@ -296,7 +306,7 @@ public:
|
||||
std::max(z, other.z), std::max(w, other.w));
|
||||
}
|
||||
|
||||
Vec4 clamp(float minVal, float maxVal) const {
|
||||
Vec4 clamp(T minVal, T maxVal) const {
|
||||
return Vec4(
|
||||
std::clamp(x, minVal, maxVal),
|
||||
std::clamp(y, minVal, maxVal),
|
||||
@@ -315,54 +325,58 @@ public:
|
||||
);
|
||||
}
|
||||
|
||||
bool isZero(float epsilon = 1e-10f) const {
|
||||
bool isZero(T epsilon = static_cast<T>(1e-10)) const {
|
||||
return std::abs(x) < epsilon && std::abs(y) < epsilon &&
|
||||
std::abs(z) < epsilon && std::abs(w) < epsilon;
|
||||
}
|
||||
|
||||
bool equals(const Vec4& other, float epsilon = 1e-10f) const {
|
||||
bool equals(const Vec4& other, T epsilon = static_cast<T>(1e-10)) const {
|
||||
return std::abs(x - other.x) < epsilon &&
|
||||
std::abs(y - other.y) < epsilon &&
|
||||
std::abs(z - other.z) < epsilon &&
|
||||
std::abs(w - other.w) < epsilon;
|
||||
}
|
||||
|
||||
friend Vec4 operator+(float scalar, const Vec4& vec) {
|
||||
friend Vec4 operator+(T scalar, const Vec4& vec) {
|
||||
return Vec4(scalar + vec.x, scalar + vec.y, scalar + vec.z, scalar + vec.w);
|
||||
}
|
||||
|
||||
friend Vec4 operator-(float scalar, const Vec4& vec) {
|
||||
friend Vec4 operator-(T scalar, const Vec4& vec) {
|
||||
return Vec4(scalar - vec.x, scalar - vec.y, scalar - vec.z, scalar - vec.w);
|
||||
}
|
||||
|
||||
friend Vec4 operator*(float scalar, const Vec4& vec) {
|
||||
friend Vec4 operator*(T scalar, const Vec4& vec) {
|
||||
return Vec4(scalar * vec.x, scalar * vec.y, scalar * vec.z, scalar * vec.w);
|
||||
}
|
||||
|
||||
friend Vec4 operator/(float scalar, const Vec4& vec) {
|
||||
friend Vec4 operator/(T scalar, const Vec4& vec) {
|
||||
return Vec4(scalar / vec.x, scalar / vec.y, scalar / vec.z, scalar / vec.w);
|
||||
}
|
||||
|
||||
Vec4 lerp(const Vec4& other, float t) const {
|
||||
t = std::clamp(t, 0.0f, 1.0f);
|
||||
Vec4 lerp(const Vec4& other, T t) const {
|
||||
t = std::clamp(t, static_cast<T>(0), static_cast<T>(1));
|
||||
return *this + (other - *this) * t;
|
||||
}
|
||||
|
||||
// Convert to grayscale using standard RGB weights
|
||||
float grayscale() const {
|
||||
return r * 0.299f + g * 0.587f + b * 0.114f;
|
||||
// Convert to grayscale using standard RGB weights (only valid for float/double)
|
||||
template<typename U = T>
|
||||
typename std::enable_if<std::is_floating_point<U>::value, T>::type grayscale() const {
|
||||
return r * static_cast<T>(0.299) + g * static_cast<T>(0.587) + b * static_cast<T>(0.114);
|
||||
}
|
||||
|
||||
// Color inversion (1.0 - color)
|
||||
Vec4 inverted() const {
|
||||
return Vec4(1.0f - r, 1.0f - g, 1.0f - b, a);
|
||||
// Color inversion (1.0 - color) (only valid for float/double)
|
||||
template<typename U = T>
|
||||
typename std::enable_if<std::is_floating_point<U>::value, Vec4>::type
|
||||
inverted() const {
|
||||
return Vec4(static_cast<T>(1) - r, static_cast<T>(1) - g,
|
||||
static_cast<T>(1) - b, a);
|
||||
}
|
||||
|
||||
float& operator[](int index) {
|
||||
T& operator[](int index) {
|
||||
return (&x)[index];
|
||||
}
|
||||
|
||||
const float& operator[](int index) const {
|
||||
const T& operator[](int index) const {
|
||||
return (&x)[index];
|
||||
}
|
||||
|
||||
@@ -371,29 +385,40 @@ public:
|
||||
std::to_string(z) + ", " + std::to_string(w) + ")";
|
||||
}
|
||||
|
||||
std::string toColorString() const {
|
||||
template<typename U = T>
|
||||
typename std::enable_if<std::is_floating_point<U>::value, std::string>::type
|
||||
toColorString() const {
|
||||
return "RGBA(" + std::to_string(r) + ", " + std::to_string(g) + ", " +
|
||||
std::to_string(b) + ", " + std::to_string(a) + ")";
|
||||
}
|
||||
|
||||
struct Hash {
|
||||
std::size_t operator()(const Vec4& v) const {
|
||||
return std::hash<float>()(v.x) ^ (std::hash<float>()(v.y) << 1) ^ (std::hash<float>()(v.z) << 2) ^ (std::hash<float>()(v.w) << 3);
|
||||
return std::hash<T>()(v.x) ^ (std::hash<T>()(v.y) << 1) ^
|
||||
(std::hash<T>()(v.z) << 2) ^ (std::hash<T>()(v.w) << 3);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os, const Vec4& vec) {
|
||||
// Type aliases for common use cases
|
||||
using Vec4f = Vec4<float>;
|
||||
using Vec4d = Vec4<double>;
|
||||
using Vec4i = Vec4<int>;
|
||||
using Vec4u = Vec4<unsigned int>;
|
||||
using Vec4ui8 = Vec4<uint8_t>;
|
||||
|
||||
template<typename T>
|
||||
inline std::ostream& operator<<(std::ostream& os, const Vec4<T>& vec) {
|
||||
os << vec.toString();
|
||||
return os;
|
||||
}
|
||||
|
||||
namespace std {
|
||||
template<>
|
||||
struct hash<Vec4> {
|
||||
size_t operator()(const Vec4& v) const {
|
||||
return hash<float>()(v.x) ^ (hash<float>()(v.y) << 1) ^
|
||||
(hash<float>()(v.z) << 2) ^ (hash<float>()(v.w) << 3);
|
||||
template<typename T>
|
||||
struct hash<Vec4<T>> {
|
||||
size_t operator()(const Vec4<T>& v) const {
|
||||
return hash<T>()(v.x) ^ (hash<T>()(v.y) << 1) ^
|
||||
(hash<T>()(v.z) << 2) ^ (hash<T>()(v.w) << 3);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user