CSC3223_Graphics_For_Games_Software_Rasteriser / SoftwareRasteriser / Matrix4.cpp
Matrix4.cpp
Raw
#include "Matrix4.h"

Matrix4::Matrix4(void)
{
  ToIdentity();
}

Matrix4::Matrix4(float elements[16])
{
  memcpy(this->values, elements, 16 * sizeof(float));
}

Matrix4::~Matrix4(void)
{
  ToIdentity();
}

void Matrix4::ToIdentity()
{
  ToZero();
  values[0] = 1.0f;
  values[5] = 1.0f;
  values[10] = 1.0f;
  values[15] = 1.0f;
}

void Matrix4::ToZero()
{
  for (int i = 0; i < 16; i++)
  {
    values[i] = 0.0f;
  }
}

Vector3 Matrix4::GetPositionVector() const
{
  return Vector3(values[12], values[13], values[14]);
}

void Matrix4::SetPositionVector(const Vector3 in)
{
  values[12] = in.x;
  values[13] = in.y;
  values[14] = in.z;
}

Vector3 Matrix4::GetScalingVector() const
{
  return Vector3(values[0], values[5], values[10]);
}

void Matrix4::SetScalingVector(const Vector3 &in)
{
  values[0] = in.x;
  values[5] = in.y;
  values[10] = in.z;
}

Matrix4 Matrix4::Perspective(float znear, float zfar, float aspect, float fov)
{
  Matrix4 m;

  const float f = 1.0f / tan(fov * PI_OVER_360);
  float negDepth = znear - zfar;

  m.values[0] = f / aspect;
  m.values[5] = f;
  m.values[10] = (zfar + znear) / negDepth;
  m.values[11] = -1.0f;
  m.values[14] = 2.0f * (znear * zfar) / negDepth;
  m.values[15] = 0.0f;

  return m;
}

// http://www.opengl.org/sdk/docs/man/xhtml/glOrtho.xml
Matrix4 Matrix4::Orthographic(float znear, float zfar, float right, float left, float top,
                              float bottom)
{
  Matrix4 m;

  m.values[0] = 2.0f / (right - left);
  m.values[5] = 2.0f / (top - bottom);
  m.values[10] = -2.0f / (zfar - znear);

  m.values[12] = -(right + left) / (right - left);
  m.values[13] = -(top + bottom) / (top - bottom);
  m.values[14] = -(zfar + znear) / (zfar - znear);
  m.values[15] = 1.0f;

  return m;
}

Matrix4 Matrix4::BuildViewMatrix(const Vector3 &from, const Vector3 &lookingAt,
                                 const Vector3 up /*= Vector3(1,0,0)*/)
{
  Matrix4 r;
  r.SetPositionVector(Vector3(-from.x, -from.y, -from.z));

  Matrix4 m;

  Vector3 f = (lookingAt - from);
  f.Normalise();

  Vector3 s = Vector3::Cross(f, up);
  Vector3 u = Vector3::Cross(s, f);

  m.values[0] = s.x;
  m.values[4] = s.y;
  m.values[8] = s.z;

  m.values[1] = u.x;
  m.values[5] = u.y;
  m.values[9] = u.z;

  m.values[2] = -f.x;
  m.values[6] = -f.y;
  m.values[10] = -f.z;

  return m * r;
}

Matrix4 Matrix4::Rotation(float degrees, const Vector3 &inaxis)
{
  Matrix4 m;

  Vector3 axis = inaxis;

  axis.Normalise();

  float c = cos((float)DegToRad(degrees));
  float s = sin((float)DegToRad(degrees));

  m.values[0] = (axis.x * axis.x) * (1.0f - c) + c;
  m.values[1] = (axis.y * axis.x) * (1.0f - c) + (axis.z * s);
  m.values[2] = (axis.z * axis.x) * (1.0f - c) - (axis.y * s);

  m.values[4] = (axis.x * axis.y) * (1.0f - c) - (axis.z * s);
  m.values[5] = (axis.y * axis.y) * (1.0f - c) + c;
  m.values[6] = (axis.z * axis.y) * (1.0f - c) + (axis.x * s);

  m.values[8] = (axis.x * axis.z) * (1.0f - c) + (axis.y * s);
  m.values[9] = (axis.y * axis.z) * (1.0f - c) - (axis.x * s);
  m.values[10] = (axis.z * axis.z) * (1.0f - c) + c;

  return m;
}

Matrix4 Matrix4::Scale(const Vector3 &scale)
{
  Matrix4 m;

  m.values[0] = scale.x;
  m.values[5] = scale.y;
  m.values[10] = scale.z;

  return m;
}

Matrix4 Matrix4::Translation(const Vector3 &translation)
{
  Matrix4 m;

  m.values[12] = translation.x;
  m.values[13] = translation.y;
  m.values[14] = translation.z;

  return m;
}
// Yoinked from the Open Source Doom 3 release - all credit goes to id software!
Matrix4 Matrix4::Inverse()
{
  float det, invDet;

  Matrix4 mat = *this;

  mat.values[0];

  // 2x2 sub-determinants required to calculate 4x4 determinant
  float det2_01_01 = mat.values[0] * mat.values[5] - mat.values[1] * mat.values[4];
  float det2_01_02 = mat.values[0] * mat.values[6] - mat.values[2] * mat.values[4];
  float det2_01_03 = mat.values[0] * mat.values[7] - mat.values[3] * mat.values[4];
  float det2_01_12 = mat.values[1] * mat.values[6] - mat.values[2] * mat.values[5];
  float det2_01_13 = mat.values[1] * mat.values[7] - mat.values[3] * mat.values[5];
  float det2_01_23 = mat.values[2] * mat.values[7] - mat.values[3] * mat.values[6];

  // 3x3 sub-determinants required to calculate 4x4 determinant
  float det3_201_012 =
      mat.values[8] * det2_01_12 - mat.values[9] * det2_01_02 + mat.values[10] * det2_01_01;
  float det3_201_013 =
      mat.values[8] * det2_01_13 - mat.values[9] * det2_01_03 + mat.values[11] * det2_01_01;
  float det3_201_023 =
      mat.values[8] * det2_01_23 - mat.values[10] * det2_01_03 + mat.values[11] * det2_01_02;
  float det3_201_123 =
      mat.values[9] * det2_01_23 - mat.values[10] * det2_01_13 + mat.values[11] * det2_01_12;

  det = (-det3_201_123 * mat.values[12] + det3_201_023 * mat.values[13] -
         det3_201_013 * mat.values[14] + det3_201_012 * mat.values[15]);

  invDet = 1.0f / det;

  // remaining 2x2 sub-determinants
  float det2_03_01 = mat.values[0] * mat.values[13] - mat.values[1] * mat.values[12];
  float det2_03_02 = mat.values[0] * mat.values[14] - mat.values[2] * mat.values[12];
  float det2_03_03 = mat.values[0] * mat.values[15] - mat.values[3] * mat.values[12];
  float det2_03_12 = mat.values[1] * mat.values[14] - mat.values[2] * mat.values[13];
  float det2_03_13 = mat.values[1] * mat.values[15] - mat.values[3] * mat.values[13];
  float det2_03_23 = mat.values[2] * mat.values[15] - mat.values[3] * mat.values[14];

  float det2_13_01 = mat.values[4] * mat.values[13] - mat.values[5] * mat.values[12];
  float det2_13_02 = mat.values[4] * mat.values[14] - mat.values[6] * mat.values[12];
  float det2_13_03 = mat.values[4] * mat.values[15] - mat.values[7] * mat.values[12];
  float det2_13_12 = mat.values[5] * mat.values[14] - mat.values[6] * mat.values[13];
  float det2_13_13 = mat.values[5] * mat.values[15] - mat.values[7] * mat.values[13];
  float det2_13_23 = mat.values[6] * mat.values[15] - mat.values[7] * mat.values[14];

  // remaining 3x3 sub-determinants
  float det3_203_012 =
      mat.values[8] * det2_03_12 - mat.values[9] * det2_03_02 + mat.values[10] * det2_03_01;
  float det3_203_013 =
      mat.values[8] * det2_03_13 - mat.values[9] * det2_03_03 + mat.values[11] * det2_03_01;
  float det3_203_023 =
      mat.values[8] * det2_03_23 - mat.values[10] * det2_03_03 + mat.values[11] * det2_03_02;
  float det3_203_123 =
      mat.values[9] * det2_03_23 - mat.values[10] * det2_03_13 + mat.values[11] * det2_03_12;

  float det3_213_012 =
      mat.values[8] * det2_13_12 - mat.values[9] * det2_13_02 + mat.values[10] * det2_13_01;
  float det3_213_013 =
      mat.values[8] * det2_13_13 - mat.values[9] * det2_13_03 + mat.values[11] * det2_13_01;
  float det3_213_023 =
      mat.values[8] * det2_13_23 - mat.values[10] * det2_13_03 + mat.values[11] * det2_13_02;
  float det3_213_123 =
      mat.values[9] * det2_13_23 - mat.values[10] * det2_13_13 + mat.values[11] * det2_13_12;

  float det3_301_012 =
      mat.values[12] * det2_01_12 - mat.values[13] * det2_01_02 + mat.values[14] * det2_01_01;
  float det3_301_013 =
      mat.values[12] * det2_01_13 - mat.values[13] * det2_01_03 + mat.values[15] * det2_01_01;
  float det3_301_023 =
      mat.values[12] * det2_01_23 - mat.values[14] * det2_01_03 + mat.values[15] * det2_01_02;
  float det3_301_123 =
      mat.values[13] * det2_01_23 - mat.values[14] * det2_01_13 + mat.values[15] * det2_01_12;

  mat.values[0] = -det3_213_123 * invDet;
  mat.values[4] = +det3_213_023 * invDet;
  mat.values[8] = -det3_213_013 * invDet;
  mat.values[12] = +det3_213_012 * invDet;

  mat.values[1] = +det3_203_123 * invDet;
  mat.values[5] = -det3_203_023 * invDet;
  mat.values[9] = +det3_203_013 * invDet;
  mat.values[13] = -det3_203_012 * invDet;

  mat.values[2] = +det3_301_123 * invDet;
  mat.values[6] = -det3_301_023 * invDet;
  mat.values[10] = +det3_301_013 * invDet;
  mat.values[14] = -det3_301_012 * invDet;

  mat.values[3] = -det3_201_123 * invDet;
  mat.values[7] = +det3_201_023 * invDet;
  mat.values[11] = -det3_201_013 * invDet;
  mat.values[15] = +det3_201_012 * invDet;

  return mat;
}