Crafter.Math/interfaces/Crafter.Math-Vector.cppm

343 lines
9.9 KiB
Text
Raw Normal View History

2025-05-07 19:18:58 +02:00
/*
2026-01-29 20:19:20 +01:00
Crafter®.Math
Copyright (C) 2026 Catcrafts®
catcrafts.net
2025-05-07 19:18:58 +02:00
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
2026-01-29 20:19:20 +01:00
License version 3.0 as published by the Free Software Foundation;
2025-05-07 19:18:58 +02:00
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
2025-05-05 02:01:44 +02:00
export module Crafter.Math:Vector;
2026-01-29 20:19:20 +01:00
import std;
2025-05-05 02:01:44 +02:00
import :BasicTypes;
2025-05-07 19:18:58 +02:00
import :Misc;
2025-05-05 02:01:44 +02:00
namespace Crafter {
2026-02-05 01:18:05 +01:00
template <typename T, std::uint32_t Len, std::uint32_t Aligment>
struct __attribute__((packed)) VectorBase {
T v[Aligment];
2025-05-05 05:14:39 +02:00
};
2026-02-05 01:18:05 +01:00
template <typename T, std::uint32_t Aligment>
struct __attribute__((packed)) VectorBase<T, 1, Aligment> {
2025-05-05 05:14:39 +02:00
union {
2026-02-05 01:18:05 +01:00
T v[Aligment];
2025-05-05 05:14:39 +02:00
T x;
};
};
2026-02-05 01:18:05 +01:00
template <typename T, std::uint32_t Aligment>
struct __attribute__((packed)) VectorBase<T, 2, Aligment> {
2025-05-05 05:14:39 +02:00
union {
2026-02-05 01:18:05 +01:00
T v[Aligment];
struct __attribute__((packed)) {
2025-05-05 05:14:39 +02:00
T x, y;
};
};
2026-02-05 01:18:05 +01:00
VectorBase<T, 2, Aligment>(float x, float y): x(x), y(y) {
2025-05-07 19:18:58 +02:00
}
2026-02-05 01:18:05 +01:00
VectorBase<T, 2, Aligment>() = default;
2025-05-05 05:14:39 +02:00
};
2025-05-05 02:01:44 +02:00
2026-02-05 01:18:05 +01:00
template <typename T, std::uint32_t Aligment>
struct __attribute__((packed)) VectorBase<T, 3, Aligment> {
2025-05-05 05:14:39 +02:00
union {
2026-02-05 01:18:05 +01:00
T v[Aligment];
struct __attribute__((packed)) {
2025-05-05 05:14:39 +02:00
T x, y, z;
};
};
2026-02-05 01:18:05 +01:00
VectorBase<T, 3, Aligment>(float x, float y, float z): x(x), y(y), z(z) {
2025-05-05 05:14:39 +02:00
2025-05-05 02:01:44 +02:00
}
2026-02-05 01:18:05 +01:00
VectorBase<T, 3, Aligment>() = default;
2025-05-05 02:01:44 +02:00
};
2026-02-05 01:18:05 +01:00
template <typename T, std::uint32_t Aligment>
struct __attribute__((packed)) VectorBase<T, 4, Aligment> {
2025-05-05 05:14:39 +02:00
union {
2026-02-05 01:18:05 +01:00
T v[Aligment];
struct __attribute__((packed)) {
2025-05-05 05:14:39 +02:00
T x, y, z, w;
};
};
2026-02-05 01:18:05 +01:00
VectorBase<T, 4, Aligment>(float x, float y, float z, float w): x(x), y(y), z(z), w(w) {
2025-05-07 19:18:58 +02:00
}
2026-02-05 01:18:05 +01:00
VectorBase<T, 4, Aligment>() = default;
2025-05-05 05:14:39 +02:00
};
2026-02-05 01:57:32 +01:00
template <typename T, std::uint32_t Len>
struct VectorBase<T, Len, 0> {
T v[Len];
};
template <typename T>
struct VectorBase<T, 1, 0> {
union {
T v[1];
T x;
};
};
template <typename T>
struct VectorBase<T, 2, 0> {
union {
T v[2];
struct {
T x, y;
};
};
VectorBase<T, 2, 0>(float x, float y): x(x), y(y) {
}
VectorBase<T, 2, 0>() = default;
};
template <typename T>
struct VectorBase<T, 3, 0> {
union {
T v[3];
struct {
T x, y, z;
};
};
VectorBase<T, 3, 0>(float x, float y, float z): x(x), y(y), z(z) {
}
VectorBase<T, 3, 0>() = default;
};
template <typename T>
struct VectorBase<T, 4, 0> {
union {
T v[4];
struct {
T x, y, z, w;
};
};
VectorBase<T, 4, 0>(float x, float y, float z, float w): x(x), y(y), z(z), w(w) {
}
VectorBase<T, 4, 0>() = default;
};
2026-02-05 01:18:05 +01:00
export template <typename T, std::uint32_t Len, std::uint32_t Aligment>
class Vector : public VectorBase<T, Len, Aligment> {
2025-05-05 02:01:44 +02:00
public:
2026-02-05 01:18:05 +01:00
Vector(float x, float y, float z, float w ) requires(std::same_as<T, float> && Len == 4) : VectorBase<T, Len, Aligment>(x, y, z, w) {
2025-05-07 19:18:58 +02:00
}
2026-02-05 01:18:05 +01:00
Vector(float x, float y, float z) requires(std::same_as<T, float> && Len == 3) : VectorBase<T, Len, Aligment>(x, y, z) {
2025-05-07 19:18:58 +02:00
}
2026-02-05 01:18:05 +01:00
Vector(float x, float y) requires(std::same_as<T, float> && Len == 2) : VectorBase<T, Len, Aligment>(x, y) {
2025-05-07 19:18:58 +02:00
}
Vector() = default;
2026-02-05 01:18:05 +01:00
static Vector<T, Len, Aligment> QuaternionRotationRollPitchYaw(float Pitch, float Yaw, float Roll) requires(Len == 4) {
2025-05-07 19:18:58 +02:00
const float halfpitch = Pitch * 0.5f;
2026-01-29 20:19:20 +01:00
float cp = std::cosf(halfpitch);
float sp = std::sinf(halfpitch);
2025-05-07 19:18:58 +02:00
const float halfyaw = Yaw * 0.5f;
2026-01-29 20:19:20 +01:00
float cy = std::cosf(halfyaw);
float sy = std::sinf(halfyaw);
2025-05-07 19:18:58 +02:00
const float halfroll = Roll * 0.5f;
2026-01-29 20:19:20 +01:00
float cr = std::cosf(halfroll);
float sr = std::sinf(halfroll);
2025-05-07 19:18:58 +02:00
2026-02-05 01:18:05 +01:00
return Vector<T, Len, Aligment>(
2025-05-07 19:18:58 +02:00
cr * sp * cy + sr * cp * sy,
cr * cp * sy - sr * sp * cy,
sr * cp * cy - cr * sp * sy,
cr * cp * cy + sr * sp * sy
);
}
2026-02-05 01:51:31 +01:00
template <std::uint32_t Blen, std::uint32_t BAlignment>
Vector<T, Len, Aligment> operator+(Vector<T, Blen, BAlignment> b){
2026-02-05 01:18:05 +01:00
Vector<T, Len, Aligment> resultVector;
2026-01-29 20:19:20 +01:00
for(std::uint32_t i = 0; i < std::min(Len, Blen); i++) {
2025-05-07 19:18:58 +02:00
resultVector.v[i] = this->v[i]+b.v[i];
}
return resultVector;
}
2026-02-05 01:51:31 +01:00
template <std::uint32_t Blen, std::uint32_t BAlignment>
Vector<T, Len, Aligment> operator-(Vector<T, Blen, BAlignment> b){
2026-02-05 01:18:05 +01:00
Vector<T, Len, Aligment> resultVector;
2026-01-29 20:19:20 +01:00
for(std::uint32_t i = 0; i < std::min(Len, Blen); i++) {
2025-05-07 19:18:58 +02:00
resultVector.v[i] = this->v[i]-b.v[i];
}
return resultVector;
}
2026-02-05 01:18:05 +01:00
Vector<T, Len, Aligment> operator-(){
Vector<T, Len, Aligment> resultVector;
2026-01-29 20:19:20 +01:00
for(std::uint32_t i = 0; i < Len; i++) {
2025-05-07 19:18:58 +02:00
resultVector.v[i] = -this->v[i];
}
return resultVector;
}
2026-02-05 01:51:31 +01:00
template <std::uint32_t Blen, std::uint32_t BAlignment>
Vector<T, Len, Aligment> operator*(Vector<T, Blen, BAlignment> b){
2026-02-05 01:18:05 +01:00
Vector<T, Len, Aligment> resultVector;
2026-01-29 20:19:20 +01:00
for(std::uint32_t i = 0; i < std::min(Len, Blen); i++) {
2025-05-07 19:18:58 +02:00
resultVector.v[i] = this->v[i]*b.v[i];
}
return resultVector;
}
2026-02-05 01:51:31 +01:00
template <std::uint32_t Blen, std::uint32_t BAlignment>
Vector<T, Len, Aligment> operator/(Vector<T, Blen, BAlignment> b){
2026-02-05 01:18:05 +01:00
Vector<T, Len, Aligment> resultVector;
2026-01-29 20:19:20 +01:00
for(std::uint32_t i = 0; i < std::min(Len, Blen); i++) {
2025-05-07 19:18:58 +02:00
resultVector.v[i] = this->v[i]/b.v[i];
}
return resultVector;
}
2026-02-05 01:18:05 +01:00
Vector<T, Len, Aligment> Rotate(Vector<T, 4, Aligment> rotation) requires(Len == 3) {
Vector<T, 4, Aligment> q = rotation.QuaternionConjugate();
Vector<T, 4, Aligment> result = q.QuaternionMultiply(Vector<T, 4, Aligment>(this->x, this->y, this->z, 0));
return Vector<T, Len, Aligment>(result.x, result.y, result.z);
2025-05-07 19:18:58 +02:00
}
2026-02-05 01:18:05 +01:00
Vector<T, Len, Aligment> Normalize() requires(Len == 3) {
2025-05-07 19:18:58 +02:00
float fLength = Length();
// Prevent divide by zero
if (fLength > 0)
{
fLength = 1.0f / fLength;
}
2026-02-05 01:18:05 +01:00
return Vector<T, Len, Aligment>(this->v[0] * fLength, this->v[1] * fLength, this->v[2] * fLength);
2025-05-07 19:18:58 +02:00
}
2025-05-05 05:14:39 +02:00
2026-02-05 01:18:05 +01:00
Vector<T, Len, Aligment> Normalize() requires(Len == 4) {
2025-05-07 19:18:58 +02:00
float fLength = Length();
// Prevent divide by zero
if (fLength > 0)
{
fLength = 1.0f / fLength;
}
2026-02-05 01:18:05 +01:00
return Vector<T, Len, Aligment>(this->v[0] * fLength, this->v[1] * fLength, this->v[2] * fLength, this->v[3] * fLength);
2025-05-07 19:18:58 +02:00
}
float Length()
{
float Result = LengthSq();
2026-01-29 20:19:20 +01:00
return std::sqrtf(Result);
2025-05-07 19:18:58 +02:00
}
2026-02-05 01:18:05 +01:00
Vector<T, Len, Aligment> ReciprocalLength() requires(Len == 3) {
Vector<T, Len, Aligment> Result = LengthSq();
2025-05-07 19:18:58 +02:00
Result = ReciprocalSqrt(Result);
return Result;
}
2026-02-05 01:18:05 +01:00
Vector<T, Len, Aligment> ReciprocalSqrt() requires(Len == 3)
2025-05-07 19:18:58 +02:00
{
2026-02-05 01:18:05 +01:00
return Vector<T, Len, Aligment>(
2026-01-29 20:19:20 +01:00
1.f / std::sqrtf(this->v[0]),
1.f / std::sqrtf(this->v[1]),
1.f / std::sqrtf(this->v[2])
2025-05-07 19:18:58 +02:00
);
2025-05-05 05:14:39 +02:00
}
2025-05-07 19:18:58 +02:00
float LengthSq()
{
return Dot(*this);
}
2026-02-05 01:18:05 +01:00
float Dot(Vector<T, Len, Aligment> v2) requires(Len == 3)
2025-05-07 19:18:58 +02:00
{
return this->v[0] * v2.v[0] + this->v[1] * v2.v[1] + this->v[2] * v2.v[2];
}
2026-02-05 01:18:05 +01:00
float Dot(Vector<T, Len, Aligment> v2) requires(Len == 4)
2025-05-07 19:18:58 +02:00
{
return this->v[0] * v2.v[0] + this->v[1] * v2.v[1] + this->v[2] * v2.v[2] + this->v[3] * v2.v[3];
}
2026-02-05 01:18:05 +01:00
Vector<T, Len, Aligment> Cross(Vector<T, Len, Aligment> v2) requires(Len == 3) {
return Vector<T, Len, Aligment>(
2025-05-07 19:18:58 +02:00
(this->v[1] * v2.v[2]) - (this->v[2] * v2.v[1]),
(this->v[2] * v2.v[0]) - (this->v[0] * v2.v[2]),
(this->v[0] * v2.v[1]) - (this->v[1] * v2.v[0])
);
};
2026-02-05 01:18:05 +01:00
Vector<T, Len, Aligment> QuaternionConjugate() requires(Len == 4) {
return Vector<T, Len, Aligment>(
2025-05-07 19:18:58 +02:00
-this->x,
-this->y,
-this->z,
this->w
);
}
2026-02-05 01:18:05 +01:00
Vector<T, Len, Aligment> QuaternionMultiply(Vector<T, Len, Aligment> q2) requires(Len == 4) {
return Vector<T, Len, Aligment>(
2025-05-07 19:18:58 +02:00
(q2.v[3] * this->v[0]) + (q2.v[0] * this->v[3]) + (q2.v[1] * this->v[2]) - (q2.v[2] * this->v[1]),
(q2.v[3] * this->v[1]) - (q2.v[0] * this->v[2]) + (q2.v[1] * this->v[3]) + (q2.v[2] * this->v[0]),
(q2.v[3] * this->v[2]) + (q2.v[0] * this->v[1]) - (q2.v[1] * this->v[0]) + (q2.v[2] * this->v[3]),
(q2.v[3] * this->v[3]) - (q2.v[0] * this->v[0]) - (q2.v[1] * this->v[1]) - (q2.v[2] * this->v[2])
);
}
2026-02-05 01:18:05 +01:00
Vector<T, 4, Aligment> QuaternionRotationAxis(float angle) requires(Len == 3) {
Vector<T, 3, Aligment> Normal = Normalize();
2025-05-07 19:18:58 +02:00
return Normal.QuaternionRotationNormal(angle);
}
2026-02-05 01:18:05 +01:00
Vector<T, 4, Aligment> QuaternionRotationNormal(float angle) requires(Len == 3) {
Vector<T, 4, Aligment> N = Vector<T, 4, Aligment>(this->x, this->y, this->z, 1);
2025-05-07 19:18:58 +02:00
float SinV, CosV;
XMScalarSinCos(&SinV, &CosV, 0.5f * angle);
2026-02-05 01:18:05 +01:00
Vector<T, 4, Aligment> Scale = Vector<T, 4, Aligment>(SinV, SinV, SinV, CosV);
2025-05-07 19:18:58 +02:00
return N * Scale;
}
2026-02-05 01:18:05 +01:00
static Vector<T, 4, Aligment> NegativeMultiplySubtract(Vector<T, 4, Aligment> a, Vector<T, 4, Aligment> b, Vector<T, 4, Aligment> c) requires(Len == 4) {
return Vector<T, 4, Aligment>(
2026-01-29 20:19:20 +01:00
c.v[0] - (a.v[0] * b.v[0]),
c.v[1] - (a.v[1] * b.v[1]),
c.v[2] - (a.v[2] * b.v[2]),
c.v[3] - (a.v[3] * b.v[3])
);
}
2025-05-05 02:01:44 +02:00
};
2025-05-05 05:14:39 +02:00
}
2025-05-05 02:01:44 +02:00
2025-05-05 05:14:39 +02:00
template <>
2026-02-05 01:18:05 +01:00
struct std::formatter<Crafter::Vector<float, 3, 4>> : std::formatter<std::string> {
auto format(const Crafter::Vector<float, 3, 4>& obj, format_context& ctx) const {
2025-05-05 05:14:39 +02:00
return std::formatter<std::string>::format(std::format("{{{}, {}, {}}}",
obj.x, obj.y, obj.z
), ctx);
}
2026-02-05 01:18:05 +01:00
auto format(const Crafter::Vector<float, 4, 4>& obj, format_context& ctx) const {
return std::formatter<std::string>::format(std::format("{{{}, {}, {}, {}}}",
obj.x, obj.y, obj.z, obj.w
), ctx);
}
2025-05-05 05:14:39 +02:00
};