#include "pch.h"
Matrix g_matIdentity;
class InitializeTransform {
public:
InitializeTransform()
{
g_matIdentity.SetIdentity();
}
} initialize;
const Matrix& Matrix::GetIdentity()
{
return g_matIdentity;
}
Matrix::Matrix(const Matrix2& mat2) :
m_type(TransformUnknown)
{
m_m[0][0] = mat2[0][0]; m_m[0][1] = mat2[0][1]; m_m[0][2] = 0; m_m[0][3] = mat2[0][2];
m_m[1][0] = mat2[1][0]; m_m[1][1] = mat2[1][1]; m_m[1][2] = 0; m_m[1][3] = mat2[1][2];
m_m[2][0] = 0; m_m[2][1] = 0; m_m[2][2] = 1; m_m[2][3] = 0;
m_m[3][0] = mat2[2][0]; m_m[3][1] = mat2[2][1]; m_m[3][2] = 0; m_m[3][3] = mat2[2][2];
}
Matrix::Matrix(
float v00, float v01, float v02, float v03,
float v10, float v11, float v12, float v13,
float v20, float v21, float v22, float v23,
float v30, float v31, float v32, float v33
) :
m_type(TransformUnknown)
{
m_m[0][0] = v00; m_m[0][1] = v01; m_m[0][2] = v02; m_m[0][3] = v03;
m_m[1][0] = v10; m_m[1][1] = v11; m_m[1][2] = v12; m_m[1][3] = v13;
m_m[2][0] = v20; m_m[2][1] = v21; m_m[2][2] = v22; m_m[2][3] = v23;
m_m[3][0] = v30; m_m[3][1] = v31; m_m[3][2] = v32; m_m[3][3] = v33;
}
Matrix::Matrix(
const Orientation& o,
const Vector& p,
float s
) :
m_type(TransformUnknown)
{
m_m[0][0] = o.m_r[0][0] * s; m_m[0][1] = o.m_r[1][0] * s; m_m[0][2] = o.m_r[2][0] * s; m_m[0][3] = p.x;
m_m[1][0] = o.m_r[0][1] * s; m_m[1][1] = o.m_r[1][1] * s; m_m[1][2] = o.m_r[2][1] * s; m_m[1][3] = p.y;
m_m[2][0] = o.m_r[0][2] * s; m_m[2][1] = o.m_r[1][2] * s; m_m[2][2] = o.m_r[2][2] * s; m_m[2][3] = p.z;
m_m[3][0] = 0.0; m_m[3][1] = 0.0; m_m[3][2] = 0.0; m_m[3][3] = 1.0f;
}
float Matrix::GetScale() const
{
return Vector(m_m[0][0], m_m[1][0], m_m[2][0]).Length();
}
Vector Matrix::GetTranslate() const
{
return Vector(m_m[0][3], m_m[1][3], m_m[2][3]);
}
float Determinant( float m00, float m01, float m02, float m03,
float m10, float m11, float m12, float m13,
float m20, float m21, float m22, float m23,
float m30, float m31, float m32, float m33
) {
return
m00 * Determinant3(
m11, m12, m13,
m21, m22, m23,
m31, m32, m33
)
+ m10 * Determinant3(
m21, m22, m23,
m31, m32, m33,
m01, m02, m03
)
+ m20 * Determinant3(
m31, m32, m33,
m01, m02, m03,
m11, m12, m13
)
+ m30 * Determinant3(
m01, m02, m03,
m11, m12, m13,
m21, m22, m23
);
}
float Determinant(const float m[4][4], int startRow, int startCol, int size);
float Determinant(const float m[4][4], int size)
{
if (size == 2) {
return m[0][0] * m[1][1] - m[0][1] * m[1][0];
} else {
float sum = 0;
for(int index = 0; index < size; index++) {
int nextIndex = index == size ? 0 : index + 1;
sum += m[index][0] * Determinant(m, nextIndex, 1, size);
}
return sum;
}
}
float Determinant(const float m[4][4], int startRow, int startCol, int size)
{
float mm[4][4];
for (int row = 0; row < size - 1; row++) {
for (int col = 0; col < size - 1; col++) {
int fromRow = startRow + row; if (fromRow >= size) fromRow -= size;
int fromCol = startCol + col; if (fromCol >= size) fromCol -= size;
mm[row][col] = m[fromRow][fromCol];
}
}
return Determinant(mm, size - 1);
}
TransformType Matrix::GetType() const
{
if (m_type == TransformUnknown) {
((Matrix*)this)->CalcType();
}
return m_type;
}
void Matrix::InvalidateType()
{
m_type = TransformUnknown;
}
void Matrix::CalcType()
{
m_type = TransformIdentity;
if (m_m[3][0] != 0 || m_m[3][1] != 0 || m_m[3][2] != 0 || m_m[3][3] != 1) {
m_type |= TransformPerspective;
}
if (
m_m[0][1] != 0 || m_m[0][2] != 0 ||
m_m[1][0] != 0 || m_m[1][2] != 0 ||
m_m[2][0] != 0 || m_m[2][1] != 0
) {
m_type |= TransformRotate;
}
if (m_m[0][0] != 1 || m_m[1][1] != 1 || m_m[2][2] != 1) {
m_type |= TransformScale;
}
if (m_m[0][3] != 0 || m_m[1][3] != 0 || m_m[2][3] != 0) {
m_type |= TransformTranslate;
}
}
Matrix& Matrix::SetIdentity()
{
m_m[0][0] = 1; m_m[0][1] = 0; m_m[0][2] = 0; m_m[0][3] = 0;
m_m[1][0] = 0; m_m[1][1] = 1; m_m[1][2] = 0; m_m[1][3] = 0;
m_m[2][0] = 0; m_m[2][1] = 0; m_m[2][2] = 1; m_m[2][3] = 0;
m_m[3][0] = 0; m_m[3][1] = 0; m_m[3][2] = 0; m_m[3][3] = 1;
m_type = TransformIdentity;
return *this;
}
void Matrix::Set(int row, int col, float value)
{
ZAssert(row >= 0 && row <= 3 && col >= 0 && col <= 3);
m_m[row][col] = value;
m_type = TransformUnknown;
}
Matrix& Matrix::SetScale(float scale)
{
SetIdentity();
m_m[0][0] = scale;
m_m[1][1] = scale;
m_m[2][2] = scale;
m_type = TransformScale;
return *this;
}
Matrix& Matrix::Scale(float scale)
{
m_m[0][0] *= scale; m_m[0][1] *= scale; m_m[0][2] *= scale; m_m[0][3] *= scale;
m_m[1][0] *= scale; m_m[1][1] *= scale; m_m[1][2] *= scale; m_m[1][3] *= scale;
m_m[2][0] *= scale; m_m[2][1] *= scale; m_m[2][2] *= scale; m_m[2][3] *= scale;
m_type |= TransformScale;
return *this;
}
Matrix& Matrix::PreScale(float scale)
{
m_m[0][0] *= scale; m_m[0][1] *= scale; m_m[0][2] *= scale;
m_m[1][0] *= scale; m_m[1][1] *= scale; m_m[1][2] *= scale;
m_m[2][0] *= scale; m_m[2][1] *= scale; m_m[2][2] *= scale;
m_m[3][0] *= scale; m_m[3][1] *= scale; m_m[3][2] *= scale;
m_type |= TransformScale;
return *this;
}
Matrix& Matrix::SetScale(const Vector& vec)
{
SetIdentity();
m_m[0][0] = vec.X();
m_m[1][1] = vec.Y();
m_m[2][2] = vec.Z();
m_type = TransformScale;
return *this;
}
Matrix& Matrix::Scale(const Vector& vec)
{
m_m[0][0] *= vec.X(); m_m[0][1] *= vec.X(); m_m[0][2] *= vec.X(); m_m[0][3] *= vec.X();
m_m[1][0] *= vec.Y(); m_m[1][1] *= vec.Y(); m_m[1][2] *= vec.Y(); m_m[1][3] *= vec.Y();
m_m[2][0] *= vec.Z(); m_m[2][1] *= vec.Z(); m_m[2][2] *= vec.Z(); m_m[2][3] *= vec.Z();
m_type |= TransformScale;
return *this;
}
Matrix& Matrix::PreScale(const Vector& vec)
{
m_m[0][0] *= vec.X(); m_m[0][1] *= vec.Y(); m_m[0][2] *= vec.Z();
m_m[1][0] *= vec.X(); m_m[1][1] *= vec.Y(); m_m[1][2] *= vec.Z();
m_m[2][0] *= vec.X(); m_m[2][1] *= vec.Y(); m_m[2][2] *= vec.Z();
m_m[3][0] *= vec.X(); m_m[3][1] *= vec.Y(); m_m[3][2] *= vec.Z();
m_type |= TransformScale;
return *this;
}
Matrix& Matrix::SetTranslate(const Vector& vec)
{
SetIdentity();
m_m[0][3] = vec.X();
m_m[1][3] = vec.Y();
m_m[2][3] = vec.Z();
m_type = TransformTranslate;
return *this;
}
Matrix& Matrix::Translate(const Vector& vec)
{
float x = vec.X();
float y = vec.Y();
float z = vec.Z();
m_m[0][0] = m_m[0][0] + x * m_m[3][0];
m_m[0][1] = m_m[0][1] + x * m_m[3][1];
m_m[0][2] = m_m[0][2] + x * m_m[3][2];
m_m[0][3] = m_m[0][3] + x * m_m[3][3];
m_m[1][0] = m_m[1][0] + y * m_m[3][0];
m_m[1][1] = m_m[1][1] + y * m_m[3][1];
m_m[1][2] = m_m[1][2] + y * m_m[3][2];
m_m[1][3] = m_m[1][3] + y * m_m[3][3];
m_m[2][0] = m_m[2][0] + z * m_m[3][0];
m_m[2][1] = m_m[2][1] + z * m_m[3][1];
m_m[2][2] = m_m[2][2] + z * m_m[3][2];
m_m[2][3] = m_m[2][3] + z * m_m[3][3];
m_type |= TransformTranslate;
return *this;
}
Matrix& Matrix::PreTranslate(const Vector& vec)
{
m_m[0][3] += m_m[0][0] * vec.X() + m_m[0][1] * vec.Y() + m_m[0][2] * vec.Z();
m_m[1][3] += m_m[1][0] * vec.X() + m_m[1][1] * vec.Y() + m_m[1][2] * vec.Z();
m_m[2][3] += m_m[2][0] * vec.X() + m_m[2][1] * vec.Y() + m_m[2][2] * vec.Z();
m_m[3][3] += m_m[3][0] * vec.X() + m_m[3][1] * vec.Y() + m_m[3][2] * vec.Z();
m_type |= TransformTranslate;
return *this;
}
Matrix& Matrix::SetRotateX(float angle)
{
SetIdentity();
float c = cos(angle);
float s = sin(angle);
m_m[1][1] = c; m_m[1][2] = -s;
m_m[2][1] = s; m_m[2][2] = c;
m_type = TransformRotate;
return *this;
}
Matrix& Matrix::SetRotateY(float angle)
{
SetIdentity();
float c = cos(angle);
float s = sin(angle);
m_m[2][2] = c; m_m[2][0] = -s;
m_m[0][2] = s; m_m[0][0] = c;
m_type = TransformRotate;
return *this;
}
Matrix& Matrix::SetRotateZ(float angle)
{
SetIdentity();
float c = cos(angle);
float s = sin(angle);
m_m[0][0] = c; m_m[0][1] = -s;
m_m[1][0] = s; m_m[1][1] = c;
m_type = TransformRotate;
return *this;
}
Matrix& Matrix::SetRotate(const Vector& vec, float angle)
{
if (vec.Y() == 0 && vec.Z() == 0) {
return SetRotateX(angle * sign(vec.X()));
} else if (vec.X() == 0 && vec.Z() == 0) {
return SetRotateY(angle * sign(vec.Y()));
} else if (vec.X() == 0 && vec.Y() == 0) {
return SetRotateZ(angle * sign(vec.Z()));
} else {
Vector vecUnit = vec.Normalize();
float x = vecUnit.X();
float y = vecUnit.Y();
float z = vecUnit.Z();
float c = cos(angle);
float s = sin(angle);
float x2 = x * x;
float y2 = y * y;
float z2 = z * z;
float xy = x * y * (1 - c);
float yz = y * z * (1 - c);
float zx = z * x * (1 - c);
m_m[0][0] = x2 + c * (1 - x2); m_m[0][1] = xy - z * s; m_m[0][2] = zx + y * s; m_m[0][3] = 0;
m_m[1][0] = xy + z * s; m_m[1][1] = y2 + c * (1 - y2); m_m[1][2] = yz - x * s; m_m[1][3] = 0;
m_m[2][0] = zx - y * s; m_m[2][1] = yz + x * s; m_m[2][2] = z2 + c * (1 - z2); m_m[2][3] = 0;
m_m[3][0] = 0; m_m[3][1] = 0; m_m[3][2] = 0; m_m[3][3] = 1;
}
m_type = TransformRotate;
return *this;
}
Matrix& Matrix::Rotate(const Vector& vec, float angle)
{
Matrix m;
m.SetRotate(vec, angle);
Multiply(m);
return *this;
}
Matrix& Matrix::PreRotate(const Vector& vec, float angle)
{
Matrix m;
m.SetRotate(vec, angle);
PreMultiply(m);
return *this;
}
Matrix& Matrix::SetLookAtFrom(const Vector& vecAt, const Vector& vecFrom, const Vector& vecUp)
{
Vector vecZAxis = (vecFrom - vecAt).Normalize();
if (vecZAxis == vecUp) {
SetIdentity();
m_m[0][3] = vecFrom.X();
m_m[1][3] = vecFrom.Y();
m_m[2][3] = vecFrom.Z();
} else {
Vector vecXAxis = CrossProduct(vecUp, vecZAxis).Normalize();
Vector vecYAxis = CrossProduct(vecZAxis, vecXAxis);
m_m[0][0] = vecXAxis.X();
m_m[0][1] = vecYAxis.X();
m_m[0][2] = vecZAxis.X();
m_m[0][3] = vecFrom.X();
m_m[1][0] = vecXAxis.Y();
m_m[1][1] = vecYAxis.Y();
m_m[1][2] = vecZAxis.Y();
m_m[1][3] = vecFrom.Y();
m_m[2][0] = vecXAxis.Z();
m_m[2][1] = vecYAxis.Z();
m_m[2][2] = vecZAxis.Z();
m_m[2][3] = vecFrom.Z();
m_m[3][0] = 0;
m_m[3][1] = 0;
m_m[3][2] = 0;
m_m[3][3] = 1;
m_type = TransformRotate | TransformTranslate;
}
return *this;
}
Matrix& Matrix::LookAtFrom(const Vector& vecAt, const Vector& vecFrom, const Vector& vecUp)
{
Matrix m;
m.SetLookAtFrom(vecAt, vecFrom, vecUp);
Multiply(m);
return *this;
}
Matrix& Matrix::PreLookAtFrom(const Vector& vecAt, const Vector& vecFrom, const Vector& vecUp)
{
Matrix m;
m.SetLookAtFrom(vecAt, vecFrom, vecUp);
PreMultiply(m);
return *this;
}
Matrix& Matrix::SetMultiply(const Matrix& m1, const Matrix& m2)
{
for (int row = 0; row < 4; row++) {
for (int col = 0; col < 4; col++) {
m_m[row][col] =
m1.m_m[0][col] * m2.m_m[row][0]
+ m1.m_m[1][col] * m2.m_m[row][1]
+ m1.m_m[2][col] * m2.m_m[row][2]
+ m1.m_m[3][col] * m2.m_m[row][3];
}
}
m_type = m1.GetType() | m2.GetType();
return *this;
}
Matrix& Matrix::Multiply(const Matrix& m2)
{
Matrix m1(*this);
SetMultiply(m1, m2);
return *this;
}
Matrix& Matrix::PreMultiply(const Matrix& m1)
{
Matrix m2(*this);
SetMultiply(m1, m2);
return *this;
}
Matrix& Matrix::SetInverse(const Matrix& mStart)
{
const int size = 4;
bool bSwap = false;
Matrix m(mStart);
SetIdentity();
for (int row = 0; row < size; row++) {
float max = abs(m.m_m[row][row]);
int rowMax = row;
for (int rowIndex = row + 1; rowIndex < size; rowIndex++) {
if (abs(m.m_m[rowIndex][row]) > max) {
max = abs(m.m_m[rowIndex][row]);
rowMax = rowIndex;
}
}
if (rowMax != row) {
bSwap = true;
for (int col = 0; col < size; col++) {
swap(m.m_m[row][col], m.m_m[rowMax][col]);
swap( m_m[row][col], m_m[rowMax][col]);
}
}
float scale = m.m_m[row][row];
if (scale != 1.0f) {
float rscale = 1.0f / scale;
int col;
m.m_m[row][row] = 1;
for (col = row + 1; col < size; col++) {
m.m_m[row][col] *= rscale;
}
if (bSwap) {
for (col = 0; col < size; col++) {
m_m[row][col] *= rscale;
}
} else {
m_m[row][row] = rscale;
for (col = 0; col < row; col++) {
m_m[row][col] *= rscale;
}
}
}
for (int row2 = 0; row2 < size; row2++) {
if (row2 != row) {
float scale = m.m_m[row2][row];
if (scale != 0) {
int col;
m.m_m[row2][row] = 0;
for (col = row + 1; col < size; col++) {
m.m_m[row2][col] -= scale * m.m_m[row][col];
}
if (bSwap) {
for (col = 0; col < size; col++) {
m_m[row2][col] -= scale * m_m[row][col];
}
} else {
for (col = 0; col <= row; col++) {
m_m[row2][col] -= scale * m_m[row][col];
}
}
}
}
}
}
m_type = TransformUnknown;
return *this;
}
Matrix& Matrix::Inverse()
{
Matrix mat(*this);
SetInverse(mat);
return *this;
}
Matrix& Matrix::SetTranspose(const Matrix& m)
{
for (int row = 0; row < 4; row++) {
for (int col = 0; col < 4; col++) {
m_m[row][col] = m.m_m[col][row];
}
}
return *this;
}
Matrix& Matrix::Transpose()
{
for (int row = 0; row < 3; row++) {
for (int col = row + 1; col < 4; col++) {
float value = m_m[row][col];
m_m[row][col] = m_m[col][row];
m_m[col][row] = value;
}
}
return *this;
}
bool operator==(const Matrix& m1, const Matrix& m2)
{
for (int row = 0; row < 3; row++) {
for (int col = row + 1; col < 4; col++) {
if (m1.m_m[row][col] != m2.m_m[row][col]) {
return false;
}
}
}
return true;
}
bool operator!=(const Matrix& m1, const Matrix& m2)
{
for (int row = 0; row < 3; row++) {
for (int col = row + 1; col < 4; col++) {
if (m1.m_m[row][col] == m2.m_m[row][col]) {
return false;
}
}
}
return true;
}
Matrix operator*(const Matrix& m1, const Matrix& m2)
{
Matrix m(m1);
m.Multiply(m2);
return m;
}
Point Matrix::Transform(const Point& point) const
{
float x = ((m_m[0][0] * point.X()) + (m_m[0][1] * point.Y()) + m_m[0][3]);
float y = ((m_m[1][0] * point.X()) + (m_m[1][1] * point.Y()) + m_m[1][3]);
Point p(x, y);
return p;
}
HVector Matrix::Transform(const HVector& vec) const
{
float x = vec.X();
float y = vec.Y();
float z = vec.Z();
float w = vec.W();
return
HVector(
m_m[0][0] * x + m_m[0][1] * y + m_m[0][2] * z + m_m[0][3] * w,
m_m[1][0] * x + m_m[1][1] * y + m_m[1][2] * z + m_m[1][3] * w,
m_m[2][0] * x + m_m[2][1] * y + m_m[2][2] * z + m_m[2][3] * w,
m_m[3][0] * x + m_m[3][1] * y + m_m[3][2] * z + m_m[3][3] * w
);
}
Vector Matrix::Transform(const Vector& vec) const
{
float x = vec.X();
float y = vec.Y();
float z = vec.Z();
return
Vector(
m_m[0][0] * x + m_m[0][1] * y + m_m[0][2] * z + m_m[0][3],
m_m[1][0] * x + m_m[1][1] * y + m_m[1][2] * z + m_m[1][3],
m_m[2][0] * x + m_m[2][1] * y + m_m[2][2] * z + m_m[2][3]
);
}
Vector Matrix::TransformDirection(const Vector& vec) const
{
float x = vec.X();
float y = vec.Y();
float z = vec.Z();
return
Vector(
m_m[0][0] * x + m_m[0][1] * y + m_m[0][2] * z,
m_m[1][0] * x + m_m[1][1] * y + m_m[1][2] * z,
m_m[2][0] * x + m_m[2][1] * y + m_m[2][2] * z
);
}
void Matrix::Transform(const TVector<Point>& vSource, TVector<Point>& vDest) const
{
int count = vSource.GetCount();
vDest.SetCount(count);
for (int index = 0; index < count; index++) {
float x = vSource[index].X();
float y = vSource[index].Y();
vDest.Set(
index,
Point(
m_m[0][0] * x + m_m[0][1] * y + m_m[0][3],
m_m[1][0] * x + m_m[1][1] * y + m_m[1][3]
)
);
}
}
void Matrix::Transform(const TVector<HVector>& vSource, TVector<HVector>& vDest) const
{
int count = vSource.GetCount();
vDest.SetCount(count);
for (int index = 0; index < count; index++) {
float x = vSource[index].X();
float y = vSource[index].Y();
float z = vSource[index].Z();
vDest.Set(
index,
HVector(
m_m[0][0] * x + m_m[0][1] * y + m_m[0][2] * z + m_m[0][3],
m_m[1][0] * x + m_m[1][1] * y + m_m[1][2] * z + m_m[1][3],
m_m[2][0] * x + m_m[2][1] * y + m_m[2][2] * z + m_m[2][3]
)
);
}
}
void Matrix::Transform(const TVector<Vector>& vSource, TVector<Vector>& vDest) const
{
int count = vSource.GetCount();
vDest.SetCount(count);
for (int index = 0; index < count; index++) {
float x = vSource[index].X();
float y = vSource[index].Y();
float z = vSource[index].Z();
vDest.Set(
index,
Vector(
m_m[0][0] * x + m_m[0][1] * y + m_m[0][2] * z + m_m[0][3],
m_m[1][0] * x + m_m[1][1] * y + m_m[1][2] * z + m_m[1][3],
m_m[2][0] * x + m_m[2][1] * y + m_m[2][2] * z + m_m[2][3]
)
);
}
}