/****************************************************************************** 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; } };