#pragma once #include namespace Scop { template constexpr Vec4::Vec4(T X, T Y, T Z, T W) : x(X), y(Y), z(Z), w(W) {} template constexpr Vec4::Vec4(T X, T Y, const Vec2& vec) : x(X), y(Y), z(vec.x), w(vec.y) {} template constexpr Vec4::Vec4(T X, const Vec2& vec, T W) : x(X), y(vec.x), z(vec.y), w(W) {} template constexpr Vec4::Vec4(T X, const Vec3& vec) : x(X), y(vec.x), z(vec.y), w(vec.z) {} template constexpr Vec4::Vec4(T scale) : x(scale), y(scale), z(scale), w(scale) {} template constexpr Vec4::Vec4(const Vec2& vec, T Z, T W) : x(vec.x), y(vec.y), z(Z), w(W) {} template constexpr Vec4::Vec4(const Vec3& vec, T W) : x(vec.x), y(vec.y), z(vec.z), w(W) {} template template constexpr Vec4::Vec4(const Vec4& vec) : x(static_cast(vec.x)), y(static_cast(vec.y)), z(static_cast(vec.z)), w(static_cast(vec.w)) {} template T Vec4::AbsDotProduct(const Vec4& vec) const { return std::abs(x * vec.x) + std::abs(y * vec.y) + std::abs(z * vec.z) + std::abs(w * vec.w); } template constexpr bool Vec4::ApproxEqual(const Vec4& vec, T maxDifference) const { return NumberEquals(x, vec.x, maxDifference) && NumberEquals(y, vec.y, maxDifference) && NumberEquals(z, vec.z, maxDifference) && NumberEquals(w, vec.w, maxDifference); } template constexpr T Vec4::DotProduct(const Vec4& vec) const { return x*vec.x + y*vec.y + z*vec.z + w*vec.w; } template Vec4 Vec4::GetNormal(T* length) const { Vec4 vec(*this); vec.Normalize(length); return vec; } template constexpr Vec4& Vec4::Maximize(const Vec4& vec) { if (vec.x > x) x = vec.x; if (vec.y > y) y = vec.y; if (vec.z > z) z = vec.z; if (vec.w > w) w = vec.w; return *this; } template constexpr Vec4& Vec4::Minimize(const Vec4& vec) { if (vec.x < x) x = vec.x; if (vec.y < y) y = vec.y; if (vec.z < z) z = vec.z; if (vec.w < w) w = vec.w; return *this; } template Vec4& Vec4::Normalize(T* length) { T invLength = T(1.0) / w; x *= invLength; y *= invLength; z *= invLength; if (length) *length = w; w = T(1.0); return *this; } template std::string Vec4::ToString() const { std::ostringstream ss; ss << *this; return ss.str(); } template constexpr T& Vec4::operator[](std::size_t i) { Scop::Assert(i < 4, "index out of range"); return *(&x + i); } template constexpr const T& Vec4::operator[](std::size_t i) const { Scop::Assert(i < 4, "index out of range"); return *(&x + i); } template constexpr const Vec4& Vec4::operator+() const { return *this; } template constexpr Vec4 Vec4::operator-() const { return Vec4(-x, -y, -z, -w); } template constexpr Vec4 Vec4::operator+(const Vec4& vec) const { return Vec4(x + vec.x, y + vec.y, z + vec.z, w + vec.w); } template constexpr Vec4 Vec4::operator-(const Vec4& vec) const { return Vec4(x - vec.x, y - vec.y, z - vec.z, w - vec.w); } template constexpr Vec4 Vec4::operator*(const Vec4& vec) const { return Vec4(x * vec.x, y * vec.y, z * vec.z, w * vec.w); } template constexpr Vec4 Vec4::operator*(T scale) const { return Vec4(x * scale, y * scale, z * scale, w * scale); } template constexpr Vec4 Vec4::operator/(const Vec4& vec) const { return Vec4(x / vec.x, y / vec.y, z / vec.z, w / vec.w); } template constexpr Vec4 Vec4::operator/(T scale) const { return Vec4(x / scale, y / scale, z / scale, w / scale); } template constexpr Vec4 Vec4::operator%(const Vec4& vec) const { return Vec4(Mod(x, vec.x), Mod(y, vec.y), Mod(z, vec.z), Mod(w, vec.w)); } template constexpr Vec4 Vec4::operator%(T mod) const { return Vec4(Mod(x, mod), Mod(y, mod), Mod(z, mod), Mod(z, mod)); } template constexpr Vec4& Vec4::operator+=(const Vec4& vec) { x += vec.x; y += vec.y; z += vec.z; w += vec.w; return *this; } template constexpr Vec4& Vec4::operator-=(const Vec4& vec) { x -= vec.x; y -= vec.y; z -= vec.z; w -= vec.w; return *this; } template constexpr Vec4& Vec4::operator*=(const Vec4& vec) { x *= vec.x; y *= vec.y; z *= vec.z; w *= vec.w; return *this; } template constexpr Vec4& Vec4::operator*=(T scale) { x *= scale; y *= scale; z *= scale; w *= scale; return *this; } template constexpr Vec4& Vec4::operator/=(const Vec4& vec) { x /= vec.x; y /= vec.y; z /= vec.z; w /= vec.w; return *this; } template constexpr Vec4& Vec4::operator/=(T scale) { x /= scale; y /= scale; z /= scale; w /= scale; return *this; } template constexpr Vec4& Vec4::operator%=(const Vec4& vec) { x = Mod(x, vec.x); y = Mod(y, vec.y); z = Mod(z, vec.z); w = Mod(w, vec.w); return *this; } template constexpr Vec4& Vec4::operator%=(T mod) { x = Mod(x, mod); y = Mod(y, mod); z = Mod(z, mod); w = Mod(w, mod); return *this; } template constexpr bool Vec4::operator==(const Vec4& vec) const { return x == vec.x && y == vec.y && z == vec.z && w == vec.w; } template constexpr bool Vec4::operator!=(const Vec4& vec) const { return !operator==(vec); } template constexpr bool Vec4::operator<(const Vec4& vec) const { if (x != vec.x) return x < vec.x; if (y != vec.y) return y < vec.y; if (z != vec.z) return z < vec.z; return w < vec.w; } template constexpr bool Vec4::operator<=(const Vec4& vec) const { if (x != vec.x) return x < vec.x; if (y != vec.y) return y < vec.y; if (z != vec.z) return z < vec.z; return w <= vec.w; } template constexpr bool Vec4::operator>(const Vec4& vec) const { if (x != vec.x) return x > vec.x; if (y != vec.y) return y > vec.y; if (z != vec.z) return z > vec.z; return w > vec.w; } template constexpr bool Vec4::operator>=(const Vec4& vec) const { if (x != vec.x) return x > vec.x; if (y != vec.y) return y > vec.y; if (z != vec.z) return z > vec.z; return w >= vec.w; } template constexpr Vec4 Vec4::Apply(T(*func)(T), const Vec4& vec) { return Vec4(func(vec.x), func(vec.y), func(vec.z), func(vec.w)); } template constexpr bool Vec4::ApproxEqual(const Vec4& lhs, const Vec4& rhs, T maxDifference) { return lhs.ApproxEqual(rhs, maxDifference); } template constexpr T Vec4::DotProduct(const Vec4& vec1, const Vec4& vec2) { return vec1.DotProduct(vec2); } template Vec4 Vec4::Normalize(const Vec4& vec) { return vec.GetNormal(); } template constexpr Vec4 Vec4::UnitX() { return Vec4(1, 0, 0, 1); } template constexpr Vec4 Vec4::UnitY() { return Vec4(0, 1, 0, 1); } template constexpr Vec4 Vec4::UnitZ() { return Vec4(0, 0, 1, 1); } template constexpr Vec4 Vec4::Zero() { return Vec4(0, 0, 0, 1); } template std::ostream& operator<<(std::ostream& out, const Vec4& vec) { return out << "Vec4(" << vec.x << ", " << vec.y << ", " << vec.z << ", " << vec.w << ')'; } template constexpr Vec4 operator*(T scale, const Vec4& vec) { return Vec4(scale * vec.x, scale * vec.y, scale * vec.z, scale * vec.w); } template constexpr Vec4 operator/(T scale, const Vec4& vec) { return Vec4(scale / vec.x, scale / vec.y, scale / vec.z, scale / vec.w); } template constexpr Vec4 operator%(T mod, const Vec4& vec) { return Vec4(Mod(mod, vec.x), Mod(mod, vec.y), Mod(mod, vec.z), Mod(mod, vec.w)); } }