Skip to main content
edited title
Link
Ethan Bierlein
  • 15.9k
  • 4
  • 60
  • 146

4x4 Matrixmatrix implementation in C++

Source Link
Ethan Bierlein
  • 15.9k
  • 4
  • 60
  • 146

4x4 Matrix implementation in C++

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.