I've been doing some 3D graphics in OpenGL lately and I needed a way to work with 4x4 matrices. My implementation supports the following operations:
- Matrix-matrix addition.
- Matrix-matrix subtraction.
- Matrix-matrix multiplication.
- Transformation matrix creation.
- View matrix creation.
- Perspective projection matrix creation.
- Orthographic projection matrix creation.
matrix.h
#ifndef MATRIX_H_
#define MATRIX_H_
#define _USE_MATH_DEFINES
#include <cmath>
#include <math.h>
#include <Windows.h>
#include <gl/GL.h>
#include <gl/GLU.h>
#include <gl/glext.h>
#include <gl/wglext.h>
#include <gl/glcorearb.h>
#include <SOIL.h>
#include "SWOGLL.h"
#include "vector4.h"
struct Matrix4x4
{
GLfloat m_elements[16];
Matrix4x4();
Matrix4x4(GLfloat elements[]);
GLfloat* GetElementsPointer();
static Matrix4x4 CreateScale(Vector4 scale);
static Matrix4x4 CreateTranslation(Vector4 translation);
static Matrix4x4 CreateRotationX(GLfloat angle);
static Matrix4x4 CreateRotationY(GLfloat angle);
static Matrix4x4 CreateRotationZ(GLfloat angle);
static Matrix4x4 CreateView(Vector4 forward, Vector4 up, Vector4 right, Vector4 position);
static Matrix4x4 CreatePerspectiveProjection(GLfloat width, GLfloat height, GLfloat fov, GLfloat nearPlane, GLfloat farPlane);
static Matrix4x4 CreateOrthographicProjection(GLfloat left, GLfloat right, GLfloat top, GLfloat bottom, GLfloat farPlane, GLfloat nearPlane);
inline Matrix4x4& operator+=(const Matrix4x4& rhs)
{
for(int i = 0; i < 16; i++)
{
this->m_elements[i] += rhs.m_elements[i];
}
return *this;
}
inline Matrix4x4& operator-=(const Matrix4x4& rhs)
{
for(int i = 0; i < 16; i++)
{
this->m_elements[i] -= rhs.m_elements[i];
}
return *this;
}
inline Matrix4x4& operator*=(const Matrix4x4& rhs)
{
this->m_elements[0] = this->m_elements[0] * rhs.m_elements[0] + this->m_elements[1] * rhs.m_elements[4] + this->m_elements[2] * rhs.m_elements[8] + this->m_elements[3] * rhs.m_elements[12];
this->m_elements[1] = this->m_elements[0] * rhs.m_elements[1] + this->m_elements[1] * rhs.m_elements[5] + this->m_elements[2] * rhs.m_elements[9] + this->m_elements[3] * rhs.m_elements[13];
this->m_elements[2] = this->m_elements[0] * rhs.m_elements[2] + this->m_elements[1] * rhs.m_elements[6] + this->m_elements[2] * rhs.m_elements[10] + this->m_elements[3] * rhs.m_elements[14];
this->m_elements[3] = this->m_elements[0] * rhs.m_elements[3] + this->m_elements[1] * rhs.m_elements[7] + this->m_elements[2] * rhs.m_elements[11] + this->m_elements[3] * rhs.m_elements[15];
this->m_elements[4] = this->m_elements[4] * rhs.m_elements[0] + this->m_elements[5] * rhs.m_elements[4] + this->m_elements[6] * rhs.m_elements[8] + this->m_elements[7] * rhs.m_elements[12];
this->m_elements[5] = this->m_elements[4] * rhs.m_elements[1] + this->m_elements[5] * rhs.m_elements[5] + this->m_elements[6] * rhs.m_elements[9] + this->m_elements[7] * rhs.m_elements[13];
this->m_elements[6] = this->m_elements[4] * rhs.m_elements[2] + this->m_elements[5] * rhs.m_elements[6] + this->m_elements[6] * rhs.m_elements[10] + this->m_elements[7] * rhs.m_elements[14];
this->m_elements[7] = this->m_elements[4] * rhs.m_elements[3] + this->m_elements[5] * rhs.m_elements[7] + this->m_elements[6] * rhs.m_elements[11] + this->m_elements[7] * rhs.m_elements[15];
this->m_elements[8] = this->m_elements[8] * rhs.m_elements[0] + this->m_elements[9] * rhs.m_elements[4] + this->m_elements[10] * rhs.m_elements[8] + this->m_elements[11] * rhs.m_elements[12];
this->m_elements[9] = this->m_elements[8] * rhs.m_elements[1] + this->m_elements[9] * rhs.m_elements[5] + this->m_elements[10] * rhs.m_elements[9] + this->m_elements[11] * rhs.m_elements[13];
this->m_elements[10] = this->m_elements[8] * rhs.m_elements[2] + this->m_elements[9] * rhs.m_elements[6] + this->m_elements[10] * rhs.m_elements[10] + this->m_elements[11] * rhs.m_elements[14];
this->m_elements[11] = this->m_elements[8] * rhs.m_elements[3] + this->m_elements[9] * rhs.m_elements[7] + this->m_elements[10] * rhs.m_elements[11] + this->m_elements[11] * rhs.m_elements[15];
this->m_elements[12] = this->m_elements[12] * rhs.m_elements[0] + this->m_elements[13] * rhs.m_elements[4] + this->m_elements[14] * rhs.m_elements[8] + this->m_elements[15] * rhs.m_elements[12];
this->m_elements[13] = this->m_elements[12] * rhs.m_elements[1] + this->m_elements[13] * rhs.m_elements[5] + this->m_elements[14] * rhs.m_elements[9] + this->m_elements[15] * rhs.m_elements[13];
this->m_elements[14] = this->m_elements[12] * rhs.m_elements[2] + this->m_elements[13] * rhs.m_elements[6] + this->m_elements[14] * rhs.m_elements[10] + this->m_elements[15] * rhs.m_elements[14];
this->m_elements[15] = this->m_elements[12] * rhs.m_elements[3] + this->m_elements[13] * rhs.m_elements[7] + this->m_elements[14] * rhs.m_elements[11] + this->m_elements[15] * rhs.m_elements[15];
return *this;
}
inline Matrix4x4& operator*=(const GLfloat& rhs)
{
for(int i = 0; i < 16; i++)
{
this->m_elements[i] *= rhs;
}
return *this;
}
};
extern inline Matrix4x4 operator+(const Matrix4x4& lhs, const Matrix4x4& rhs);
extern inline Matrix4x4 operator-(const Matrix4x4& lhs, const Matrix4x4& rhs);
extern inline Matrix4x4 operator*(const Matrix4x4& lhs, const Matrix4x4& rhs);
extern inline Matrix4x4 operator*(const Matrix4x4& lhs, const GLfloat& rhs);
#endif
matrix.cpp
#include "matrix.h"
Matrix4x4::Matrix4x4()
{
memset(&this->m_elements, 0, sizeof(this->m_elements));
this->m_elements[0] = 1;
this->m_elements[5] = 1;
this->m_elements[10] = 1;
this->m_elements[15] = 1;
}
Matrix4x4::Matrix4x4(GLfloat elements[])
{
memset(&this->m_elements, 0, sizeof(this->m_elements));
for(int i = 0; i < 16; i++)
{
this->m_elements[i] = elements[i];
}
}
GLfloat* Matrix4x4::GetElementsPointer()
{
return this->m_elements;
}
Matrix4x4 Matrix4x4::CreateScale(Vector4 scale)
{
Matrix4x4 newMatrix = Matrix4x4();
newMatrix.m_elements[0] = scale.x;
newMatrix.m_elements[5] = scale.y;
newMatrix.m_elements[10] = scale.z;
return newMatrix;
}
Matrix4x4 Matrix4x4::CreateTranslation(Vector4 translation)
{
Matrix4x4 newMatrix = Matrix4x4();
newMatrix.m_elements[3] = translation.x;
newMatrix.m_elements[7] = translation.y;
newMatrix.m_elements[11] = translation.z;
return newMatrix;
}
Matrix4x4 Matrix4x4::CreateRotationX(GLfloat angle)
{
Matrix4x4 newMatrix = Matrix4x4();
newMatrix.m_elements[5] = std::cos(-angle);
newMatrix.m_elements[6] = -std::sin(-angle);
newMatrix.m_elements[9] = std::sin(-angle);
newMatrix.m_elements[10] = std::cos(-angle);
return newMatrix;
}
Matrix4x4 Matrix4x4::CreateRotationY(GLfloat angle)
{
Matrix4x4 newMatrix = Matrix4x4();
newMatrix.m_elements[0] = std::cos(-angle);
newMatrix.m_elements[2] = std::sin(-angle);
newMatrix.m_elements[8] = -std::sin(-angle);
newMatrix.m_elements[10] = std::cos(-angle);
return newMatrix;
}
Matrix4x4 Matrix4x4::CreateRotationZ(GLfloat angle)
{
Matrix4x4 newMatrix = Matrix4x4();
newMatrix.m_elements[0] = std::cos(-angle);
newMatrix.m_elements[1] = -std::sin(-angle);
newMatrix.m_elements[4] = std::sin(-angle);
newMatrix.m_elements[5] = std::cos(-angle);
return newMatrix;
}
Matrix4x4 Matrix4x4::CreateView(Vector4 forward, Vector4 up, Vector4 right, Vector4 position)
{
Matrix4x4 newMatrixOne = Matrix4x4();
newMatrixOne.m_elements[0] = right.x;
newMatrixOne.m_elements[1] = right.y;
newMatrixOne.m_elements[2] = right.z;
newMatrixOne.m_elements[4] = up.x;
newMatrixOne.m_elements[5] = up.y;
newMatrixOne.m_elements[6] = up.z;
newMatrixOne.m_elements[8] = forward.x;
newMatrixOne.m_elements[9] = forward.y;
newMatrixOne.m_elements[10] = forward.z;
Matrix4x4 newMatrixTwo = Matrix4x4();
newMatrixTwo.m_elements[3] = -position.x;
newMatrixTwo.m_elements[7] = -position.y;
newMatrixTwo.m_elements[11] = -position.z;
Matrix4x4 newMatrix = newMatrixOne * newMatrixTwo;
return newMatrix;
}
Matrix4x4 Matrix4x4::CreatePerspectiveProjection(GLfloat width, GLfloat height, GLfloat fov, GLfloat nearPlane, GLfloat farPlane)
{
Matrix4x4 newMatrix = Matrix4x4();
newMatrix.m_elements[0] = (1.0f / std::tan((fov * M_PI / 180.0f) / 2.0f)) / (width / height);
newMatrix.m_elements[5] = 1.0f / std::tan((fov * M_PI / 180.0f) / 2.0f);
newMatrix.m_elements[10] = (farPlane + nearPlane) / (nearPlane - farPlane);
newMatrix.m_elements[11] = (2.0f * farPlane * nearPlane) / (nearPlane - farPlane);
newMatrix.m_elements[14] = -1.0f;
return newMatrix;
}
Matrix4x4 Matrix4x4::CreateOrthographicProjection(GLfloat left, GLfloat right, GLfloat top, GLfloat bottom, GLfloat farPlane, GLfloat nearPlane)
{
Matrix4x4 newMatrix = Matrix4x4();
newMatrix.m_elements[0] = 2.0f / (right - left);
newMatrix.m_elements[3] = -((right + left) / (right - left));
newMatrix.m_elements[5] = 2.0f / (top - bottom);
newMatrix.m_elements[7] = -((top + bottom) / (top - bottom));
newMatrix.m_elements[10] = 2.0f / (farPlane - nearPlane);
newMatrix.m_elements[11] = -((farPlane + nearPlane) / (farPlane - nearPlane));
return newMatrix;
}
inline Matrix4x4 operator+(const Matrix4x4& lhs, const Matrix4x4& rhs)
{
Matrix4x4 newMatrix = Matrix4x4(lhs);
newMatrix += rhs;
return newMatrix;
}
inline Matrix4x4 operator-(const Matrix4x4& lhs, const Matrix4x4& rhs)
{
Matrix4x4 newMatrix = Matrix4x4(lhs);
newMatrix -= rhs;
return newMatrix;
}
inline Matrix4x4 operator*(const Matrix4x4& lhs, const Matrix4x4& rhs)
{
Matrix4x4 newMatrix = Matrix4x4(lhs);
newMatrix *= rhs;
return newMatrix;
}
inline Matrix4x4 operator*(const Matrix4x4& lhs, const GLfloat& rhs)
{
Matrix4x4 newMatrix = Matrix4x4(lhs);
newMatrix *= rhs;
return newMatrix;
}
What can I improve?
The header SWOGLL.h is my custom OpenGL loader, which can be found here: https://github.com/Ethan-Bierlein/SWOGLL. The header vector4.h is simply my implementation of a four-component vector.