EHS/include/ehs/Mat4.h
2024-07-27 18:51:19 -07:00

429 lines
8.5 KiB
C++

#pragma once
#include "EHS.h"
#include "Math.h"
#include "Mat3.h"
#include "Vec4.h"
#include "Vec3.h"
namespace ehs
{
template <typename T = float>
class Mat4
{
private:
friend class GpuUniform;
T data[16];
public:
Mat4()
{
for (UInt_8 i = 0; i < 16; ++i)
data[i] = 0;
}
explicit Mat4(const T* data)
{
for (UInt_8 i = 0; i < 16; ++i)
this->data[i] = data[i];
}
template<typename C>
Mat4(const Mat3<C>& mat)
{
for (UInt_8 i = 0; i < 9; ++i)
{
UInt_8 row = i / 3;
UInt_8 column = i % 3;
UInt_8 dst = row * 4 + column;
data[dst] = (T)mat[i];
}
data[3] = 0;
data[7] = 0;
data[11] = 0;
data[12] = 0;
data[13] = 0;
data[14] = 0;
data[15] = 1;
}
template<typename C>
Mat4(const Mat4<C>& mat)
{
for (UInt_8 i = 0; i < 16; ++i)
data[i] = (T)mat.data[i];
}
template<typename C>
Mat4<T>& operator=(const Mat4<C>& mat)
{
if (this == &mat)
return *this;
for (UInt_8 i = 0; i < 16; ++i)
data[i] = (T)mat.data[i];
return *this;
}
Vec4<T> operator*(Vec4<T> vec) const
{
Vec4<T> result;
result.x = vec.x * data[0] + vec.y * data[4] + vec.z * data[8] + vec.w * data[12];
result.y = vec.x * data[1] + vec.y * data[5] + vec.z * data[9] + vec.w * data[13];
result.z = vec.x * data[2] + vec.y * data[6] + vec.z * data[10] + vec.w * data[14];
result.w = vec.x * data[3] + vec.y * data[7] + vec.z * data[11] + vec.w * data[15];
return result;
}
Mat4<T>& operator*=(const T scalar)
{
for (UInt_8 i = 0; i < 16; ++i)
data[i] *= scalar;
return *this;
}
Mat4<T> operator*(const T scalar) const
{
Mat4<T> result;
for (UInt_8 i = 0; i < 16; ++i)
result.data[i] = data[i] * scalar;
return result;
}
Mat4<T>& operator*=(const Mat4<T>& mat)
{
Mat4 transposed = GetTranspose();
for (UInt_8 i = 0; i < 16; i++)
{
UInt_8 row = i / 4 * 4;
UInt_8 column = i % 4 * 4;
data[i] += transposed.data[column] * mat.data[row];
data[i] += transposed.data[column + 1] * mat.data[row + 1];
data[i] += transposed.data[column + 2] * mat.data[row + 2];
data[i] += transposed.data[column + 3] * mat.data[row + 3];
}
return *this;
}
Mat4<T> operator*(const Mat4<T>& mat) const
{
Mat4 transposed = GetTranspose();
Mat4<T> result;
for (UInt_8 i = 0; i < 16; i++)
{
UInt_8 row = i / 4 * 4;
UInt_8 column = i % 4 * 4;
result.data[i] += transposed.data[column] * mat.data[row];
result.data[i] += transposed.data[column + 1] * mat.data[row + 1];
result.data[i] += transposed.data[column + 2] * mat.data[row + 2];
result.data[i] += transposed.data[column + 3] * mat.data[row + 3];
}
return result;
}
operator const T*() const
{
return data;
}
operator T*()
{
return data;
}
Vec3<T> GetRight() const
{
return Vec3<T>(data[0], data[4], data[8]);
}
Vec3<T> GetUp() const
{
return Vec3<T>(data[1], data[5], data[9]);
}
Vec3<T> GetForward() const
{
return Vec3<T>(data[2], data[6], data[10]);
}
Mat4<T> GetTranspose() const
{
Mat4<T> result;
for (UInt_8 i = 0; i < 16; ++i)
result.data[i] = data[i % 4 * 4 + i / 4];
return result;
}
void Transpose()
{
Mat4<T> old = *this;
for (UInt_8 i = 0; i < 16; ++i)
data[i] = old.data[4 * (i % 4) + i / 4];
}
Mat3<T> Cut(const UInt_8 row, const UInt_8 column) const
{
Mat3<T> result;
UInt_8 index = 0;
for (UInt_8 r = 0; r < 4; ++r)
{
for (UInt_8 c = 0; c < 4; ++c)
{
if (r == row || c == column)
continue;
result[index++] = data[4 * r + c];
}
}
return result;
}
Mat4<T> GetMinor() const
{
Mat4<T> result;
for (UInt_8 r = 0; r < 4; ++r)
for (UInt_8 c = 0; c < 4; ++c)
result.data[4 * r + c] = Cut(r, c).GetDeterminant();
return result;
}
void Minor()
{
Mat4<T> old = *this;
for (UInt_8 r = 0; r < 4; ++r)
for (UInt_8 c = 0; c < 4; ++c)
data[4 * r + c] = old.Cut(r, c).GetDeterminant();
}
Mat4<T> GetCofactor() const
{
Mat4<T> minor = GetMinor();
Mat4<T> result;
for (UInt_8 r = 0; r < 4; ++r)
{
for (UInt_8 c = 0; c < 4; ++c)
{
UInt_8 i = 4 * c + r;
result.data[i] = minor.data[i] * Math::Pow<T>(-1, r + c);
}
}
return result;
}
void Cofactor()
{
Mat4<T> minor = GetMinor();
for (UInt_8 r = 0; r < 4; ++r)
{
for (UInt_8 c = 0; c < 4; ++c)
{
UInt_8 i = 4 * c + r;
data[i] = minor.data[i] * Math::Pow<T>(-1, r + c);
}
}
}
T GetDeterminant() const
{
Mat4<T> cofactor = GetCofactor();
T result = 0;
for (UInt_8 c = 0; c < 4; ++c)
result += data[c] * cofactor[c];
return result;
}
Mat4<T> GetAdjugate() const
{
return GetCofactor().GetTranspose();
}
void Adjugate()
{
Cofactor();
Transpose();
}
Mat4<T> GetInverse() const
{
T det = GetDeterminant();
if (Math::ComCmp(det, 0))
return {};
return GetAdjugate() * (1 / det);
}
void Inverse()
{
T det = GetDeterminant();
if (Math::ComCmp(det, 0))
return;
Adjugate();
operator*=(1 / det);
}
static Mat4<T> Identity()
{
Mat4<T> result;
result.data[0] = 1;
result.data[5] = 1;
result.data[10] = 1;
result.data[15] = 1;
return result;
}
static Mat4<T> Scale(const Vec3<T>& scale)
{
Mat4<T> result;
result.data[0] = scale.x;
result.data[5] = scale.y;
result.data[10] = scale.z;
result.data[15] = 1;
return result;
}
static Mat4<T> Translate(const Vec3<T>& pos)
{
Mat4<T> result = Identity();
result.data[12] = pos.x;
result.data[13] = pos.y;
result.data[14] = pos.z;
return result;
}
static Mat4<T> PitchRotate(const T angle)
{
T radians = Math::Rads(angle);
Mat4<T> result;
result.data[0] = 1;
result.data[5] = Math::Cos(radians);
result.data[6] = Math::Sin(radians);
result.data[9] = -Math::Sin(radians);
result.data[10] = Math::Cos(radians);
result.data[15] = 1;
return result;
}
static Mat4<T> YawRotate(const T angle)
{
T radians = Math::Rads<T>(angle);
Mat4<T> result;
result.data[0] = Math::Cos<T>(radians);
result.data[2] = -Math::Sin<T>(radians);
result.data[5] = 1;
result.data[8] = Math::Sin<T>(radians);
result.data[10] = Math::Cos<T>(radians);
result.data[15] = 1;
return result;
}
static Mat4<T> RollRotate(const T angle)
{
T radians = Math::Rads<T>(angle);
Mat4<T> result;
result.data[0] = Math::Cos(radians);
result.data[1] = Math::Sin(radians);
result.data[4] = -Math::Sin(radians);
result.data[5] = Math::Cos(radians);
result.data[10] = 1;
result.data[15] = 1;
return result;
}
static Mat4<T> Rotate(const Vec3<T>& vec)
{
return YawRotate(vec.y) * RollRotate(vec.z) * PitchRotate(vec.x);
}
static Mat4<T> RH_Perspective(const T fov, const T aspect, const T zNear, const T zFar)
{
const T tanHalfFovy = Math::Tan<T>(Math::Rads(fov) / 2.0f);
Mat4<T> result;
result[0] = 1.0f / (aspect * tanHalfFovy);
result[5] = -1.0f / tanHalfFovy;
result[10] = zFar / (zFar - zNear);
result[14] = -(zFar * zNear) / (zFar - zNear);
return result;
}
static Mat4<T> LH_Perspective(const T fov, const T aspect, const T zNear, const T zFar)
{
const T tanHalfFovy = Math::Tan<T>(Math::Rads(fov) / 2.0f);
Mat4<T> result;
result[0] = 1.0f / (aspect * tanHalfFovy);
result[5] = -1.0f / tanHalfFovy;
result[10] = zFar / (zFar - zNear);
result[11] = 1.0f;
result[14] = -(zFar * zNear) / (zFar - zNear);
result[15] = 0.0f;
return result;
}
static Mat4<T> LH_Orthographic(const T left, const T right, const T top, const T bottom, const T zNear, const T zFar)
{
Mat4<T> result;
result[0] = 2.0f / (right - left); // 0,0 entry
result[5] = 2.0f / (bottom - top); // 1,1 entry
result[10] = 1.0f / (zFar - zNear); // 2,2 entry
result[12] = -(right + left) / (right - left); // 3,0 entry
result[13] = -(bottom + top) / (bottom - top); // 3,1 entry
result[14] = -zNear / (zFar - zNear); // 3,2 entry
result[15] = 1.0f; // 3,3 entry
return result;
/*
Mat4<T> result;
result.data[0] = 2 / (right - left);
result.data[5] = 2 / (top - bottom);
result.data[10] = 1 / (zFar - zNear);
result.data[12] = (left + right) / (left - right);
result.data[13] = (top + bottom) / (bottom - top);
result.data[14] = zNear / (zNear - zFar);
result.data[15] = 1;
return result;
*/
}
};
template class EHS_LIB_IO Mat4<float>;
template class EHS_LIB_IO Mat4<double>;
typedef Mat4<float> Mat4_f;
typedef Mat4<double> Mat4_d;
}