Parallax Corrected Cubemaps/matrixinvert.h

From Valve Developer Community
Jump to: navigation, search

From Jason Yu-Tseh Chi's "Calculation of matrix inverse in C/C++"

Modified to work with Valve's matrix_3x4_t

//========= Copyright Jason Yu-Tseh Chi, All rights reserved. ============//
//
// Purpose: 
//
//=============================================================================//

#include "mathlib/mathlib.h"

//-----------------------------------------------------------------------------
// Purpose: Calculate the cofactor of element (row, col)
//-----------------------------------------------------------------------------
int GetMatrixMinor( float **src, float **dest, int row, int col, int order )
{
	// Indicate which col and row is being copied to dest
	int colCount = 0, rowCount = 0;

	for ( int i = 0; i < order; i++ )
	{
		if ( i != row )
		{
			colCount = 0;
			for ( int j = 0; j < order; j++ )
			{
				// When j is not the element
				if ( j != col )
				{
					dest[rowCount][colCount] = src[i][j];
					colCount++;
				}
			}
			rowCount++;
		}
	}

	return 1;
}

//-----------------------------------------------------------------------------
// Purpose: Calculate the determinant recursively
//-----------------------------------------------------------------------------
double CalcMatrixDeterminant( float **mat, int order )
{
	// Order must be >= 0
	// Stop the recursion when matrix is a single element
	if ( order == 1 )
		return mat[0][0];

	// The determinant value
	float det = 0;

	// Allocate the cofactor matrix
	float **minor;
	minor = new float *[order - 1];
	for ( int i = 0; i < order - 1; i++ )
		minor[i] = new float[order - 1];

	for ( int i = 0; i < order; i++ )
	{
		// Get minor of element (0, i)
		GetMatrixMinor( mat, minor, 0, i, order );
		// The recusion is here!

		det += (i % 2 == 1 ? -1.0 : 1.0) * mat[0][i] * CalcMatrixDeterminant( minor, order - 1 );
		//det += pow( -1.0, i ) * mat[0][i] * CalcMatrixDeterminant( minor,order - 1 );
	}

	// Release memory
	for ( int i = 0; i < order - 1; i++ )
		delete[] minor[i];
	delete[] minor;

	return det;
}

//-----------------------------------------------------------------------------
// Purpose: Matrix inversion
//-----------------------------------------------------------------------------
void MatrixInversion( matrix3x4_t &in, matrix3x4_t &out )
{
	float **A;
	A = new float *[4];
	for ( int i = 0; i < 4; i++ )
		A[i] = new float[4];
	int order = 4;

	// Load in into A
	for ( int i = 0; i < 3; i++ )
	{
		for ( int j = 0; j < 4; j++ )
		{
			A[i][j] = in[i][j];
		}
	}
	A[3][0] = A[3][1] = A[3][2] = 0;
	A[3][3] = 1;

	// Get the determinant of a
	double det = 1.0 / CalcMatrixDeterminant( (float **)A, order );

	// Memory allocation
	float *temp = new float[(order - 1) * (order - 1)];
	float **minor = new float *[order - 1];
	for ( int i = 0; i < order - 1; i++ )
		minor[i] = temp + (i * (order - 1));

	for ( int j = 0; j < order; j++ )
	{
		for ( int i = 0; i<order; i++ )
		{
			// Get the co-factor (matrix) of A(j, i)
			GetMatrixMinor( (float **)A, minor, j, i, order );
			out[i][j] = det * CalcMatrixDeterminant( minor, order - 1 );
			if ( (i + j) % 2 == 1 )
				out[i][j] = -out[i][j];
		}
	}

	// Release memory
	for ( int i = 0; i < 4; i++ )
		delete A[i];
	delete A;
	//delete[] minor[0];
	delete[] temp;
	delete[] minor;
}