429 lines
8.5 KiB
C++
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;
|
|
} |