Skip to content
Snippets Groups Projects
Mat4.cpp 6.67 KiB
Newer Older
Postea's avatar
Postea committed
#include "Mat4.h"

Yoel's avatar
Yoel committed
#define _USE_MATH_DEFINES

#include <math.h>

Postea's avatar
Postea committed
namespace util {
Yoel's avatar
Yoel committed
// Constructor
Mat4::Mat4(std::array<float, 16> arr) : arr(arr){};
Mat4::Mat4() : arr(identity().arr){};
// Operator
float Mat4::operator[](std::array<int, 2> i) const {
	return arr[4 * i[0] + i[1]];
Yoel's avatar
Yoel committed
float& Mat4::operator[](std::array<int, 2> i) {
	return arr[4 * i[0] + i[1]];
Yoel's avatar
Yoel committed
Mat4 Mat4::operator*(const Mat4& rhs) const {
	Mat4 n;
	for (int c = 0; c != 4; c++) {
		for (int r = 0; r != 4; r++) {
			float v = 0;
			for (int k = 0; k != 4; k++) v += arr[4 * k + r] * rhs[{c, k}];
			n[{c, r}] = v;
		}
	}
	return n;
Yoel's avatar
Yoel committed
bool Mat4::operator==(const Mat4& rhs) const {
	return arr == rhs.arr;
Yoel's avatar
Yoel committed
bool Mat4::operator!=(const Mat4& rhs) const {
	return !(*this == rhs);
Yoel's avatar
Yoel committed
// Methods
Mat4 Mat4::transpose() const {
	Mat4 x;
	for (int c = 0; c != 4; c++) {
		for (int r = 0; r != 4; r++) {
			x[{c, r}] = arr[4 * r + c];
		}
	}
	return x;
Yoel's avatar
Yoel committed
Vec3 Mat4::transformDir(Vec3 v) const {
	Mat4 mat(*this);
	const float x =
	    mat[{0, 0}] * v[0] + mat[{0, 1}] * v[1] + mat[{0, 2}] * v[2];
	const float y =
	    mat[{1, 0}] * v[0] + mat[{1, 1}] * v[1] + mat[{1, 2}] * v[2];
	const float z =
	    mat[{2, 0}] * v[0] + mat[{2, 1}] * v[1] + mat[{2, 2}] * v[2];
	return Vec3(x, y, z);
Yoel's avatar
Yoel committed
Vec3 Mat4::transformPoint(Vec3 v) const {
	Mat4 mat(*this);
	float x = mat[{0, 0}] * v[0] + mat[{0, 1}] * v[1] + mat[{0, 2}] * v[2] +
	          mat[{0, 3}];
	float y = mat[{1, 0}] * v[0] + mat[{1, 1}] * v[1] + mat[{1, 2}] * v[2] +
	          mat[{1, 3}];
	float z = mat[{2, 0}] * v[0] + mat[{2, 1}] * v[1] + mat[{2, 2}] * v[2] +
	          mat[{2, 3}];
	return Vec3(x, y, z);
Yoel's avatar
Yoel committed
Vec3 Mat4::position() const {
	Mat4 mat(*this);
	return Vec3(mat[{0, 3}], mat[{1, 3}], mat[{2, 3}]);
Yoel's avatar
Yoel committed
Mat4 Mat4::invertFull() const {
	Mat4 ret;
	std::array<float, 16> mat(arr);
	std::array<float, 16> dst(ret.arr);
	std::array<float, 12> tmp;
Postea's avatar
Postea committed

Yoel's avatar
Yoel committed
	/* temparray for pairs */
	std::array<float, 16> src;
Postea's avatar
Postea committed

Yoel's avatar
Yoel committed
	/* array of transpose source matrix */
	float det;
Postea's avatar
Postea committed

Yoel's avatar
Yoel committed
	/* determinant */
	/*
	 * transpose matrix
	 */
	for (int i = 0; i < 4; i++) {
		src[i] = mat[i * 4];
		src[i + 4] = mat[i * 4 + 1];
		src[i + 8] = mat[i * 4 + 2];
		src[i + 12] = mat[i * 4 + 3];
	}
Postea's avatar
Postea committed

Yoel's avatar
Yoel committed
	/* calculate pairs for first 8 elements (cofactors) */
	tmp[0] = src[10] * src[15];
	tmp[1] = src[11] * src[14];
	tmp[2] = src[9] * src[15];
	tmp[3] = src[11] * src[13];
	tmp[4] = src[9] * src[14];
	tmp[5] = src[10] * src[13];
	tmp[6] = src[8] * src[15];
	tmp[7] = src[11] * src[12];
	tmp[8] = src[8] * src[14];
	tmp[9] = src[10] * src[12];
	tmp[10] = src[8] * src[13];
	tmp[11] = src[9] * src[12];
Postea's avatar
Postea committed

Yoel's avatar
Yoel committed
	/* calculate first 8 elements (cofactors) */
	dst[0] = tmp[0] * src[5] + tmp[3] * src[6] + tmp[4] * src[7];
	dst[0] -= tmp[1] * src[5] + tmp[2] * src[6] + tmp[5] * src[7];
	dst[1] = tmp[1] * src[4] + tmp[6] * src[6] + tmp[9] * src[7];
	dst[1] -= tmp[0] * src[4] + tmp[7] * src[6] + tmp[8] * src[7];
	dst[2] = tmp[2] * src[4] + tmp[7] * src[5] + tmp[10] * src[7];
	dst[2] -= tmp[3] * src[4] + tmp[6] * src[5] + tmp[11] * src[7];
	dst[3] = tmp[5] * src[4] + tmp[8] * src[5] + tmp[11] * src[6];
	dst[3] -= tmp[4] * src[4] + tmp[9] * src[5] + tmp[10] * src[6];
	dst[4] = tmp[1] * src[1] + tmp[2] * src[2] + tmp[5] * src[3];
	dst[4] -= tmp[0] * src[1] + tmp[3] * src[2] + tmp[4] * src[3];
	dst[5] = tmp[0] * src[0] + tmp[7] * src[2] + tmp[8] * src[3];
	dst[5] -= tmp[1] * src[0] + tmp[6] * src[2] + tmp[9] * src[3];
	dst[6] = tmp[3] * src[0] + tmp[6] * src[1] + tmp[11] * src[3];
	dst[6] -= tmp[2] * src[0] + tmp[7] * src[1] + tmp[10] * src[3];
	dst[7] = tmp[4] * src[0] + tmp[9] * src[1] + tmp[10] * src[2];
	dst[7] -= tmp[5] * src[0] + tmp[8] * src[1] + tmp[11] * src[2];
Postea's avatar
Postea committed

Yoel's avatar
Yoel committed
	/* calculate pairs for second 8 elements (cofactors) */
	tmp[0] = src[2] * src[7];
	tmp[1] = src[3] * src[6];
	tmp[2] = src[1] * src[7];
	tmp[3] = src[3] * src[5];
	tmp[4] = src[1] * src[6];
	tmp[5] = src[2] * src[5];
	tmp[6] = src[0] * src[7];
	tmp[7] = src[3] * src[4];
	tmp[8] = src[0] * src[6];
	tmp[9] = src[2] * src[4];
	tmp[10] = src[0] * src[5];
	tmp[11] = src[1] * src[4];
Postea's avatar
Postea committed

Yoel's avatar
Yoel committed
	/* calculate second 8 elements (cofactors) */
	dst[8] = tmp[0] * src[13] + tmp[3] * src[14] + tmp[4] * src[15];
	dst[8] -= tmp[1] * src[13] + tmp[2] * src[14] + tmp[5] * src[15];
	dst[9] = tmp[1] * src[12] + tmp[6] * src[14] + tmp[9] * src[15];
	dst[9] -= tmp[0] * src[12] + tmp[7] * src[14] + tmp[8] * src[15];
	dst[10] = tmp[2] * src[12] + tmp[7] * src[13] + tmp[10] * src[15];
	dst[10] -= tmp[3] * src[12] + tmp[6] * src[13] + tmp[11] * src[15];
	dst[11] = tmp[5] * src[12] + tmp[8] * src[13] + tmp[11] * src[14];
	dst[11] -= tmp[4] * src[12] + tmp[9] * src[13] + tmp[10] * src[14];
	dst[12] = tmp[2] * src[10] + tmp[5] * src[11] + tmp[1] * src[9];
	dst[12] -= tmp[4] * src[11] + tmp[0] * src[9] + tmp[3] * src[10];
	dst[13] = tmp[8] * src[11] + tmp[0] * src[8] + tmp[7] * src[10];
	dst[13] -= tmp[6] * src[10] + tmp[9] * src[11] + tmp[1] * src[8];
	dst[14] = tmp[6] * src[9] + tmp[11] * src[11] + tmp[3] * src[8];
	dst[14] -= tmp[10] * src[11] + tmp[2] * src[8] + tmp[7] * src[9];
	dst[15] = tmp[10] * src[10] + tmp[4] * src[8] + tmp[9] * src[9];
	dst[15] -= tmp[8] * src[9] + tmp[11] * src[10] + tmp[5] * src[8];
Postea's avatar
Postea committed

Yoel's avatar
Yoel committed
	/* calculate determinant */
	det = src[0] * dst[0] + src[1] * dst[1] + src[2] * dst[2] + src[3] * dst[3];
Postea's avatar
Postea committed

Yoel's avatar
Yoel committed
	/* calculate matrix inverse */
	det = 1 / det;
Postea's avatar
Postea committed

Yoel's avatar
Yoel committed
	for (int j = 0; j < 16; j++) {
		dst[j] *= det;
	}
Postea's avatar
Postea committed

Yoel's avatar
Yoel committed
	Mat4 retu(dst);
Postea's avatar
Postea committed

Yoel's avatar
Yoel committed
	return retu;
Yoel's avatar
Yoel committed
// Static
Mat4 translate(Vec3 xyz) {
	Mat4 matrix;
	matrix[{0, 3}] = xyz[0];
	matrix[{1, 3}] = xyz[1];
	matrix[{2, 3}] = xyz[2];
	return matrix;
Yoel's avatar
Yoel committed
Mat4 rotate(Vec3 axis, float angle) {
	Mat4 matrix;
	float rad = (angle / 180) * M_PI;
	float cosa = cos(rad);
	float sina = sin(rad);
	float l = sqrt(axis[0] * axis[0] + axis[1] * axis[1] + axis[2] * axis[2]);
	float rx = axis[0] / l;
	float ry = axis[1] / l;
	float rz = axis[2] / l;
	float icosa = 1 - cosa;
	{
		matrix[{0, 0}] = (icosa * rx * rx + cosa);
		matrix[{1, 0}] = (icosa * rx * ry + rz * sina);
		matrix[{2, 0}] = (icosa * rx * rz - ry * sina);
	}
	{
		matrix[{0, 1}] = (icosa * rx * ry - rz * sina);
		matrix[{1, 1}] = (icosa * ry * ry + cosa);
		matrix[{2, 1}] = (icosa * ry * rz + rx * sina);
	}
	{
		matrix[{0, 2}] = (icosa * rx * rz + ry * sina);
		matrix[{1, 2}] = (icosa * ry * rz - rx * sina);
		matrix[{2, 2}] = (icosa * rz * rz + cosa);
	}
	return matrix;
Yoel's avatar
Yoel committed
Mat4 scale(Vec3 xyz) {
	Mat4 matrix;
	matrix[{0, 0}] = xyz[0];
	matrix[{1, 1}] = xyz[1];
	matrix[{2, 2}] = xyz[2];
	return matrix;
Yoel's avatar
Yoel committed
Mat4 identity() {
	return Mat4({1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1});
Yoel's avatar
Yoel committed
// Out
std::ostream& operator<<(std::ostream& os, const Mat4& rhs) {
	for (int c = 0; c < 4; c++) {
		os << "(";
		for (int r = 0; r < 4; r++) {
			os << rhs[{c, r}];
			if (r != 3) {
				os << ",";
			}
		}
		os << ")" << std::endl;
	}
	return os;
Yoel's avatar
Yoel committed
}  // namespace util