356 lines
No EOL
11 KiB
C++
Executable file
356 lines
No EOL
11 KiB
C++
Executable file
/*
|
|
Crafter®.Math
|
|
Copyright (C) 2026 Catcrafts®
|
|
catcrafts.net
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Lesser General Public
|
|
License version 3.0 as published by the Free Software Foundation;
|
|
|
|
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
|
|
*/
|
|
|
|
export module Crafter.Math:Vector;
|
|
import std;
|
|
|
|
namespace Crafter {
|
|
template <typename T, std::uint32_t Len, std::uint32_t Aligment>
|
|
struct __attribute__((packed)) VectorBase {
|
|
T v[Aligment];
|
|
};
|
|
|
|
template <typename T, std::uint32_t Aligment>
|
|
struct __attribute__((packed)) VectorBase<T, 1, Aligment> {
|
|
union {
|
|
T v[Aligment];
|
|
T x;
|
|
};
|
|
};
|
|
|
|
template <typename T, std::uint32_t Aligment>
|
|
struct __attribute__((packed)) VectorBase<T, 2, Aligment> {
|
|
union {
|
|
T v[Aligment];
|
|
struct __attribute__((packed)) {
|
|
T x, y;
|
|
};
|
|
};
|
|
constexpr VectorBase<T, 2, Aligment>(float x, float y): x(x), y(y) {
|
|
|
|
}
|
|
constexpr VectorBase<T, 2, Aligment>() = default;
|
|
};
|
|
|
|
template <typename T, std::uint32_t Aligment>
|
|
struct __attribute__((packed)) VectorBase<T, 3, Aligment> {
|
|
union {
|
|
T v[Aligment];
|
|
struct __attribute__((packed)) {
|
|
T x, y, z;
|
|
};
|
|
};
|
|
constexpr VectorBase<T, 3, Aligment>(float x, float y, float z): x(x), y(y), z(z) {
|
|
|
|
}
|
|
constexpr VectorBase<T, 3, Aligment>() = default;
|
|
};
|
|
|
|
template <typename T, std::uint32_t Aligment>
|
|
struct __attribute__((packed)) VectorBase<T, 4, Aligment> {
|
|
union {
|
|
T v[Aligment];
|
|
struct __attribute__((packed)) {
|
|
T x, y, z, w;
|
|
};
|
|
};
|
|
constexpr VectorBase<T, 4, Aligment>(float x, float y, float z, float w): x(x), y(y), z(z), w(w) {
|
|
|
|
}
|
|
constexpr VectorBase<T, 4, Aligment>() = default;
|
|
};
|
|
|
|
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;
|
|
};
|
|
};
|
|
constexpr VectorBase<T, 2, 0>(float x, float y): x(x), y(y) {
|
|
|
|
}
|
|
constexpr VectorBase<T, 2, 0>() = default;
|
|
};
|
|
|
|
template <typename T>
|
|
struct VectorBase<T, 3, 0> {
|
|
union {
|
|
T v[3];
|
|
struct {
|
|
T x, y, z;
|
|
};
|
|
};
|
|
constexpr VectorBase<T, 3, 0>(float x, float y, float z): x(x), y(y), z(z) {
|
|
|
|
}
|
|
constexpr VectorBase<T, 3, 0>() = default;
|
|
};
|
|
|
|
template <typename T>
|
|
struct VectorBase<T, 4, 0> {
|
|
union {
|
|
T v[4];
|
|
struct {
|
|
T x, y, z, w;
|
|
};
|
|
};
|
|
constexpr VectorBase<T, 4, 0>(float x, float y, float z, float w): x(x), y(y), z(z), w(w) {
|
|
|
|
}
|
|
constexpr VectorBase<T, 4, 0>() = default;
|
|
};
|
|
|
|
export template <typename T, std::uint32_t Len, std::uint32_t Aligment>
|
|
class Vector : public VectorBase<T, Len, Aligment> {
|
|
public:
|
|
constexpr 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) {
|
|
|
|
}
|
|
constexpr Vector(float x, float y, float z) requires(std::same_as<T, float> && Len == 3) : VectorBase<T, Len, Aligment>(x, y, z) {
|
|
|
|
}
|
|
constexpr Vector(float x, float y) requires(std::same_as<T, float> && Len == 2) : VectorBase<T, Len, Aligment>(x, y) {
|
|
|
|
}
|
|
constexpr Vector() = default;
|
|
|
|
template <std::uint32_t Blen, std::uint32_t BAlignment>
|
|
constexpr Vector<T, Len, Aligment> operator+(Vector<T, Blen, BAlignment> b) const {
|
|
Vector<T, Len, Aligment> resultVector;
|
|
for(std::uint32_t i = 0; i < std::min(Len, Blen); i++) {
|
|
resultVector.v[i] = this->v[i]+b.v[i];
|
|
}
|
|
return resultVector;
|
|
}
|
|
template <std::uint32_t Blen, std::uint32_t BAlignment>
|
|
constexpr Vector<T, Len, Aligment> operator-(Vector<T, Blen, BAlignment> b) const {
|
|
Vector<T, Len, Aligment> resultVector;
|
|
for(std::uint32_t i = 0; i < std::min(Len, Blen); i++) {
|
|
resultVector.v[i] = this->v[i]-b.v[i];
|
|
}
|
|
return resultVector;
|
|
}
|
|
constexpr Vector<T, Len, Aligment> operator-(){
|
|
Vector<T, Len, Aligment> resultVector;
|
|
for(std::uint32_t i = 0; i < Len; i++) {
|
|
resultVector.v[i] = -this->v[i];
|
|
}
|
|
return resultVector;
|
|
}
|
|
template <std::uint32_t Blen, std::uint32_t BAlignment>
|
|
constexpr Vector<T, Len, Aligment> operator*(Vector<T, Blen, BAlignment> b) const {
|
|
Vector<T, Len, Aligment> resultVector;
|
|
for(std::uint32_t i = 0; i < std::min(Len, Blen); i++) {
|
|
resultVector.v[i] = this->v[i]*b.v[i];
|
|
}
|
|
return resultVector;
|
|
}
|
|
template <std::uint32_t Blen, std::uint32_t BAlignment>
|
|
constexpr Vector<T, Len, Aligment> operator/(Vector<T, Blen, BAlignment> b) const {
|
|
Vector<T, Len, Aligment> resultVector;
|
|
for(std::uint32_t i = 0; i < std::min(Len, Blen); i++) {
|
|
resultVector.v[i] = this->v[i]/b.v[i];
|
|
}
|
|
return resultVector;
|
|
}
|
|
template <std::uint32_t Blen, std::uint32_t BAlignment>
|
|
constexpr void operator+=(Vector<T, Blen, BAlignment> b){
|
|
for(std::uint32_t i = 0; i < std::min(Len, Blen); i++) {
|
|
this->v[i]+=b.v[i];
|
|
}
|
|
}
|
|
template <std::uint32_t Blen, std::uint32_t BAlignment>
|
|
constexpr void operator-=(Vector<T, Blen, BAlignment> b){
|
|
for(std::uint32_t i = 0; i < std::min(Len, Blen); i++) {
|
|
this->v[i]-=b.v[i];
|
|
}
|
|
}
|
|
template <std::uint32_t Blen, std::uint32_t BAlignment>
|
|
constexpr void operator*=(Vector<T, Blen, BAlignment> b){
|
|
for(std::uint32_t i = 0; i < std::min(Len, Blen); i++) {
|
|
this->v[i]*=b.v[i];
|
|
}
|
|
}
|
|
template <std::uint32_t Blen, std::uint32_t BAlignment>
|
|
constexpr void operator/=(Vector<T, Blen, BAlignment> b){
|
|
for(std::uint32_t i = 0; i < std::min(Len, Blen); i++) {
|
|
this->v[i]/=b.v[i];
|
|
}
|
|
}
|
|
|
|
template <typename BT>
|
|
constexpr Vector<T, Len, Aligment> operator+(BT b) const {
|
|
Vector<T, Len, Aligment> resultVector;
|
|
for(std::uint32_t i = 0; i < Len; i++) {
|
|
resultVector.v[i] = this->v[i] + b;
|
|
}
|
|
return resultVector;
|
|
}
|
|
template <typename BT>
|
|
constexpr Vector<T, Len, Aligment> operator-(BT b) const {
|
|
Vector<T, Len, Aligment> resultVector;
|
|
for(std::uint32_t i = 0; i < Len; i++) {
|
|
resultVector.v[i] = this->v[i] - b;
|
|
}
|
|
return resultVector;
|
|
}
|
|
template <typename BT>
|
|
constexpr Vector<T, Len, Aligment> operator*(BT b) const {
|
|
Vector<T, Len, Aligment> resultVector;
|
|
for(std::uint32_t i = 0; i < Len; i++) {
|
|
resultVector.v[i] = this->v[i] * b;
|
|
}
|
|
return resultVector;
|
|
}
|
|
template <typename BT>
|
|
constexpr Vector<T, Len, Aligment> operator/(BT b) const {
|
|
Vector<T, Len, Aligment> resultVector;
|
|
for(std::uint32_t i = 0; i < Len; i++) {
|
|
resultVector.v[i] = this->v[i] / b;
|
|
}
|
|
return resultVector;
|
|
}
|
|
template <typename BT>
|
|
constexpr void operator+=(BT b){
|
|
for(std::uint32_t i = 0; i < Len; i++) {
|
|
this->v[i] += b;
|
|
}
|
|
}
|
|
template <typename BT>
|
|
constexpr void operator-=(BT b){
|
|
for(std::uint32_t i = 0; i < Len; i++) {
|
|
this->v[i] -= b;
|
|
}
|
|
}
|
|
template <typename BT>
|
|
constexpr void operator*=(BT b){
|
|
for(std::uint32_t i = 0; i < Len; i++) {
|
|
this->v[i] *= b;
|
|
}
|
|
}
|
|
template <typename BT>
|
|
constexpr void operator/=(BT b){
|
|
for(std::uint32_t i = 0; i < Len; i++) {
|
|
this->v[i] /= b;
|
|
}
|
|
}
|
|
template <std::uint32_t BAlignment>
|
|
operator Vector<T, Len, BAlignment>() const {
|
|
Vector<T, Len, BAlignment> returnVector;
|
|
for(std::uint32_t i = 0; i < Len; i++) {
|
|
returnVector.v[i] = this->v[i];
|
|
}
|
|
return returnVector;
|
|
}
|
|
|
|
constexpr void Normalize() {
|
|
float fLength = Length();
|
|
|
|
if (fLength > 0) {
|
|
fLength = 1.0f / fLength;
|
|
}
|
|
|
|
for(std::uint32_t i = 0; i < Len; i++) {
|
|
this->v[i] *= fLength;
|
|
}
|
|
}
|
|
|
|
constexpr void Invert() {
|
|
for(std::uint32_t i = 0; i < Len; i++) {
|
|
this->v[i] = -this->v[i];
|
|
}
|
|
}
|
|
|
|
constexpr float Length() const {
|
|
float Result = LengthSq();
|
|
return std::sqrtf(Result);
|
|
}
|
|
|
|
constexpr float LengthSq() const {
|
|
return Dot(*this, *this);
|
|
}
|
|
|
|
template <typename AT, std::uint32_t Alen, std::uint32_t AAlignment, typename BT, std::uint32_t Blen, std::uint32_t BAlignment>
|
|
constexpr static Vector<T, Len, Aligment> Cross(Vector<AT, Alen, AAlignment> a, Vector<BT, Blen, BAlignment> b) requires(Len == 3 && Alen >= 3 && Blen >= 3) {
|
|
return Vector<T, Len, Aligment>(
|
|
(a.v[1] * b.v[2]) - (a.v[2] * b.v[1]),
|
|
(a.v[2] * b.v[0]) - (a.v[0] * b.v[2]),
|
|
(a.v[0] * b.v[1]) - (a.v[1] * b.v[0])
|
|
);
|
|
}
|
|
|
|
template <typename AT, std::uint32_t Alen, std::uint32_t AAlignment, typename BT, std::uint32_t Blen, std::uint32_t BAlignment>
|
|
constexpr static float Dot(Vector<AT, Alen, AAlignment> a, Vector<BT, Blen, BAlignment> b) requires(Alen >= Len && Blen >= Len) {
|
|
float accumulate = a.v[0] * b.v[0];
|
|
for(std::uint32_t i = 1; i < Len; i++) {
|
|
accumulate += a.v[i] * b.v[i];
|
|
}
|
|
return accumulate;
|
|
}
|
|
};
|
|
}
|
|
|
|
|
|
template <typename T, std::uint32_t Aligment>
|
|
struct std::formatter<Crafter::Vector<T, 2, Aligment>> : std::formatter<std::string> {
|
|
auto format(const Crafter::Vector<T, 2, Aligment>& obj, format_context& ctx) const {
|
|
return std::formatter<std::string>::format(std::format("{{{}, {}}}",
|
|
obj.x, obj.y
|
|
), ctx);
|
|
}
|
|
};
|
|
|
|
template <typename T, std::uint32_t Aligment>
|
|
struct std::formatter<Crafter::Vector<T, 3, Aligment>> : std::formatter<std::string> {
|
|
auto format(const Crafter::Vector<T, 3, Aligment>& obj, format_context& ctx) const {
|
|
return std::formatter<std::string>::format(std::format("{{{}, {}, {}}}",
|
|
obj.x, obj.y, obj.z
|
|
), ctx);
|
|
}
|
|
};
|
|
|
|
template <typename T, std::uint32_t Aligment>
|
|
struct std::formatter<Crafter::Vector<T, 4, Aligment>> : std::formatter<std::string> {
|
|
auto format(const Crafter::Vector<T, 4, Aligment>& obj, format_context& ctx) const {
|
|
return std::formatter<std::string>::format(std::format("{{{}, {}, {}, {}}}",
|
|
obj.x, obj.y, obj.z, obj.w
|
|
), ctx);
|
|
}
|
|
};
|
|
|
|
|
|
template <typename T, std::uint32_t Len, std::uint32_t Aligment, typename BT>
|
|
constexpr Crafter::Vector<T, Len, Aligment> operator*(BT b, const Crafter::Vector<T, Len, Aligment>& v) {
|
|
return v * b;
|
|
} |