CSC3223_Graphics_For_Games_Software_Rasteriser / SoftwareRasteriser / Matrix4.h
Matrix4.h
Raw
/******************************************************************************
Class:Matrix4
Implements:
Author:Rich Davison	<richard.davison4@newcastle.ac.uk>
Description:VERY simple 4 by 4 matrix class. Students are encouraged to modify
this as necessary! Overloading the [] operator to allow access to the values
array in a neater way might be a good start, as the floats that make the matrix
up are currently public.
-_-_-_-_-_-_-_,------,
_-_-_-_-_-_-_-|   /\_/\   NYANYANYAN
-_-_-_-_-_-_-~|__( ^ .^) /
_-_-_-_-_-_-_-""  ""
*/ /////////////////////////////////////////////////////////////////////////////
#pragma once

#include <iostream>
#include "common.h"
#include "Vector3.h"
#include "Vector4.h"

class Vector3;

class Matrix4
{
public:
  Matrix4(void);
  Matrix4(float elements[16]);
  ~Matrix4(void);

  float values[16];

  // Set all matrix values to zero
  void ToZero();
  // Sets matrix to identity matrix (1.0 down the diagonal)
  void ToIdentity();

  // Gets the OpenGL position vector (floats 12,13, and 14)
  Vector3 GetPositionVector() const;
  // Sets the OpenGL position vector (floats 12,13, and 14)
  void SetPositionVector(const Vector3 in);

  // Gets the scale vector (floats 1,5, and 10)
  Vector3 GetScalingVector() const;
  // Sets the scale vector (floats 1,5, and 10)
  void SetScalingVector(const Vector3 &in);

  // Creates a rotation matrix that rotates by 'degrees' around the 'axis'
  // Analogous to glRotatef
  static Matrix4 Rotation(float degrees, const Vector3 &axis);

  // Creates a scaling matrix (puts the 'scale' vector down the diagonal)
  // Analogous to glScalef
  static Matrix4 Scale(const Vector3 &scale);

  // Creates a translation matrix (identity, with 'translation' vector at
  // floats 12, 13, and 14. Analogous to glTranslatef
  static Matrix4 Translation(const Vector3 &translation);

  // Creates a perspective matrix, with 'znear' and 'zfar' as the near and
  // far planes, using 'aspect' and 'fov' as the aspect ratio and vertical
  // field of vision, respectively.
  static Matrix4 Perspective(float znear, float zfar, float aspect, float fov);

  // Creates an orthographic matrix with 'znear' and 'zfar' as the near and
  // far planes, and so on. Descriptive variable names are a good thing!
  static Matrix4 Orthographic(float znear, float zfar, float right, float left, float top,
                              float bottom);

  // Builds a view matrix suitable for sending straight to the vertex shader.
  // Puts the camera at 'from', with 'lookingAt' centered on the screen, with
  //'up' as the...up axis (pointing towards the top of the screen)
  static Matrix4 BuildViewMatrix(const Vector3 &from, const Vector3 &lookingAt,
                                 const Vector3 up = Vector3(0, 1, 0));

  Matrix4 Inverse();

  Matrix4 GetTransposedRotation()
  {
    Matrix4 temp;

    temp.values[1] = values[4];
    temp.values[4] = values[1];
    temp.values[2] = values[8];
    temp.values[8] = values[2];
    temp.values[6] = values[9];
    temp.values[9] = values[6];

    return temp;
  }

  void SetRow(unsigned int row, const Vector4 &val)
  {
    if (row < 3)
    {
      int start = 4 * row;

      values[start += 4] = val.x;
      values[start += 4] = val.y;
      values[start += 4] = val.z;
      values[start += 4] = val.w;
    }
  }

  void SetColumn(unsigned int column, const Vector4 &val)
  {
    if (column < 3)
    {
      memcpy(&values[4 * column], &val, sizeof(Vector4));
    }
  }

  Vector4 GetRow(unsigned int row)
  {
    Vector4 out(0, 0, 0, 1);
    if (row < 3)
    {
      int start = 4 * row;

      out.x = values[start += 4];
      out.y = values[start += 4];
      out.z = values[start += 4];
      out.w = values[start += 4];
    }
    return out;
  }

  Vector4 GetColumn(unsigned int column)
  {
    Vector4 out(0, 0, 0, 1);

    if (column < 3)
    {
      memcpy(&out, &values[4 * column], sizeof(Vector4));
    }

    return out;
  }

  // Multiplies 'this' matrix by matrix 'a'. Performs the multiplication in 'OpenGL' order (ie,
  // backwards)
  inline Matrix4 operator*(const Matrix4 &b) const
  {
    Matrix4 out;
    for (unsigned int col = 0; col < 4; ++col)
    {
      for (unsigned int row = 0; row < 4; ++row)
      {
        int current = row + (col * 4);
        out.values[row + (col * 4)] = 0.0f;
        for (unsigned int i = 0; i < 4; ++i)
        {
          out.values[row + (col * 4)] += this->values[row + (i * 4)] * b.values[(col * 4) + i];
        }
      }
    }
    return out;
  }

  inline Vector3 operator*(const Vector3 &v) const
  {
    Vector3 vec;

    float temp;

    vec.x = v.x * values[0] + v.y * values[4] + v.z * values[8] + values[12];
    vec.y = v.x * values[1] + v.y * values[5] + v.z * values[9] + values[13];
    vec.z = v.x * values[2] + v.y * values[6] + v.z * values[10] + values[14];

    temp = v.x * values[3] + v.y * values[7] + v.z * values[11] + values[15];

    vec.x = vec.x / temp;
    vec.y = vec.y / temp;
    vec.z = vec.z / temp;

    return vec;
  };

  inline Vector4 operator*(const Vector4 &v) const
  {
    return Vector4(v.x * values[0] + v.y * values[4] + v.z * values[8] + v.w * values[12],
                   v.x * values[1] + v.y * values[5] + v.z * values[9] + v.w * values[13],
                   v.x * values[2] + v.y * values[6] + v.z * values[10] + v.w * values[14],
                   v.x * values[3] + v.y * values[7] + v.z * values[11] + v.w * values[15]);
  };

  // Handy string output for the matrix. Can get a bit messy, but better than nothing!
  inline friend std::ostream &operator<<(std::ostream &o, const Matrix4 &m)
  {
    o << "Mat4(";
    o << "\t" << m.values[0] << "," << m.values[1] << "," << m.values[2] << "," << m.values[3]
      << std::endl;
    o << "\t\t" << m.values[4] << "," << m.values[5] << "," << m.values[6] << "," << m.values[7]
      << std::endl;
    o << "\t\t" << m.values[8] << "," << m.values[9] << "," << m.values[10] << "," << m.values[11]
      << std::endl;
    o << "\t\t" << m.values[12] << "," << m.values[13] << "," << m.values[14] << "," << m.values[15]
      << " )" << std::endl;
    return o;
  }
};