gm_matrix.dll, enhanced VMatrix functionality

I reached a point where I need to mess with matrices a little more than we were able to, so I started writing this module in order to throw it at garry and tell him to add it.

THIS DOES ONLY WORK FOR GM13, I’M NOT GONNA COMPILE FOR GM12!

List of functions:



VMatrix/Vector __add(VMatrix lhs, VMatrix/Vector rhs)
boolean __eq(VMatrix lhs, VMatrix rhs)
VMatrix __mul(VMatrix lhs, VMatrix rhs)
VMatrix __sub(VMatrix lhs, VMatrix rhs)
VMatrix __unm(VMatrix mat)
string __tostring(VMatrix mat)//Format: "[%.5f,	%.5f,	%.5f,	%.5f]
[%.5f,	%.5f,	%.5f,	%.5f]
[%.5f,	%.5f,	%.5f,	%.5f]
[%.5f,	%.5f,	%.5f,	%.5f]", 

VMatrix:Inverse()
VMatrix VMatrix:GetInverse()

boolean VMatrix:IsRotationMatrix()

boolean VMatrix:IsIdentity()
VMatrix:Identity()

VMatrix:Transpose()
VMatrix VMatrix:GetTranspose()
Vector VMatrix:GetForward()
Vector VMatrix:GetLeft()
Vector VMatrix:GetUp()

VMatrix:SetForward(Vector forw)
VMatrix:SetLeft(Vector left)
VMatrix:SetUp(Vector up)

VMatrix:Set(VMatrix source)--copy value from argument to self
VMatrix VMatrix:Copy()--returns a copy

VMatrix:SetField(int row, int column, double value)
double VMatrix:GetField(int row, int column)

table VMatrix:ToTable()--returns 2 dimensional table, see sample
VMatrix:FromTable(table)


Testcode:
[lua]

require(“matrix”)
local m1 = Matrix()
local m2 = Matrix()
m1:Translate(Vector(1, 2, 3))
m2:Translate(Vector(10, 20, 30))
MsgN("Addition:
", m1+m2)
MsgN("Multiplication:
", m1*m2)
MsgN("Subtraction:
", m1-m2)
MsgN("Equal:
", m1 == m2)
MsgN("Negation:
", -m1)

m1:SetField(1, 1, 23.3)
MsgN("G/SetField:
", m1:GetField(1, 1))

m1:SetForward(Vector(1, 2, 3))
MsgN("G/SetForward:
", m1:GetForward())
m1:SetLeft(Vector(10, 20, 30))
MsgN("G/SetLeft:
", m1:GetLeft())
m1:SetUp(Vector(100, 200, 300))
MsgN("G/SetUp:
", m1:GetUp())

m1:Set(m2)
MsgN("Set:
", m1)

MsgN("Copy:
", m1:Copy())

Msg("From/To Table:
")
m1:FromTable(–broken
{
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12},
{13, 14, 15, 16}
}
)
PrintTable(m1:ToTable())
[/lua]

[del]mat:FromTable is currently broken due to lack of functionality of garrys new interface.[/del] works now

Binary Download

Source(Using BlackOps wrapper):



#include "ILuaModuleManager.h"
#include "mathlib\vmatrix.h"
#include "mathlib\vector.h"

GMOD_MODULE( Open, Close );

ILuaInterface* gLua = NULL;

ILuaObject* vectorMeta,* matrixMeta;

LUA_FUNCTION( lMatrix__add ) {
	gLua->CheckType(1, Type::MATRIX);
	gLua->CheckType(2, Type::MATRIX);
	VMatrix* lhs = (VMatrix*)gLua->GetUserData(1);
	VMatrix* rhs = (VMatrix*)gLua->GetUserData(2);
	VMatrix* result = new VMatrix(*lhs+*rhs);
	gLua->PushUserData(matrixMeta, result);
	return 1;
}

LUA_FUNCTION( lMatrix__mul ) {
	gLua->CheckType(1, Type::MATRIX);
	int type = gLua->GetType(2);
	switch(type) {
		case Type::VECTOR: {
			VMatrix* lhs = (VMatrix*)gLua->GetUserData(1);
			Vector* rhs = (Vector*)gLua->GetUserData(2);
			Vector* result = new Vector(*lhs**rhs);
			gLua->PushUserData(vectorMeta, result);
			return 1;
		}
		case Type::MATRIX: {
			VMatrix* lhs = (VMatrix*)gLua->GetUserData(1);
			VMatrix* rhs = (VMatrix*)gLua->GetUserData(2);
			VMatrix* result = new VMatrix(*lhs**rhs);
			gLua->PushUserData(matrixMeta, result);
			return 1;
		}
	}
	char err[80];
	sprintf(err, "Invalid object to #2, (Vector or Matrix expected got %s)", gLua->GetTypeName(type));
	gLua->Error(err);
	return 0;
}

LUA_FUNCTION( lMatrix__sub ) {
	gLua->CheckType(1, Type::MATRIX);
	gLua->CheckType(2, Type::MATRIX);
	VMatrix* lhs = (VMatrix*)gLua->GetUserData(1);
	VMatrix* rhs = (VMatrix*)gLua->GetUserData(2);
	VMatrix* result = new VMatrix(*lhs-*rhs);
	gLua->PushUserData(matrixMeta, result);
	return 1;
}

LUA_FUNCTION( lMatrix__eq ) {
	gLua->CheckType(1, Type::MATRIX);
	if(gLua->GetType(2) == Type::MATRIX) {
		VMatrix* lhs = (VMatrix*)gLua->GetUserData(1);
		VMatrix* rhs = (VMatrix*)gLua->GetUserData(2);
		gLua->Push(*lhs == *rhs);
		return 1;
	}
	gLua->Push(false);
	return 1;
}

LUA_FUNCTION( lMatrix__unm ) {
	gLua->CheckType(1, Type::MATRIX);
	VMatrix* lhs = (VMatrix*)gLua->GetUserData(1);
	VMatrix* result = new VMatrix(-*lhs);
	gLua->PushUserData(matrixMeta, result);
	return 1;
}

LUA_FUNCTION( lMatrix__tostring ) {
	gLua->CheckType(1, Type::MATRIX);
	VMatrix* mat = (VMatrix*)gLua->GetUserData(1);
	vec_t(*vec_tMat)[4] = mat->m;
	char ret[256];
	sprintf(
		ret, 
		"[%.5f,	%.5f,	%.5f,	%.5f]
[%.5f,	%.5f,	%.5f,	%.5f]
[%.5f,	%.5f,	%.5f,	%.5f]
[%.5f,	%.5f,	%.5f,	%.5f]", 
		vec_tMat[0][0],
		vec_tMat[0][1],
		vec_tMat[0][2],
		vec_tMat[0][3],

		vec_tMat[1][0],
		vec_tMat[1][1],
		vec_tMat[1][2],
		vec_tMat[1][3],

		vec_tMat[2][0],
		vec_tMat[2][1],
		vec_tMat[2][2],
		vec_tMat[2][3],

		vec_tMat[3][0],
		vec_tMat[3][1],
		vec_tMat[3][2],
		vec_tMat[3][3]
	);
	gLua->Push(ret);
	return 1;
}

LUA_FUNCTION( lMatrixInverse ) {
	gLua->CheckType(1, Type::MATRIX);
	VMatrix* temp = ((VMatrix*)(gLua->GetUserData(1)));
	gLua->Push(temp->InverseGeneral(*temp));
	return 1;
}

LUA_FUNCTION( lMatrixGetInverse ) {
	gLua->CheckType(1, Type::MATRIX);
	VMatrix* retMat = new VMatrix();
	if(!((VMatrix*)(gLua->GetUserData(1)))->InverseGeneral(*retMat)) {
		gLua->PushNil();
		return 1;
	}
	gLua->PushUserData(matrixMeta, retMat);
	return 1;
}

LUA_FUNCTION( lMatrixIsRotationMatrix ) {
	gLua->CheckType(1, Type::MATRIX);
	((VMatrix*)(gLua->GetUserData(1)))->IsRotationMatrix();
	return 0;
}

LUA_FUNCTION( lMatrixIsIdentity ) {
	gLua->CheckType(1, Type::MATRIX);
	gLua->Push(((VMatrix*)(gLua->GetUserData(1)))->IsIdentity());
	return 1;
}

LUA_FUNCTION( lMatrixIdentity ) {
	gLua->CheckType(1, Type::MATRIX);
	((VMatrix*)(gLua->GetUserData(1)))->Identity();
	return 0;
}

LUA_FUNCTION( lMatrixTranspose ) {
	gLua->CheckType(1, Type::MATRIX);
	VMatrix* temp = ((VMatrix*)(gLua->GetUserData(1)));
	MatrixTranspose(*temp, *temp);
	return 0;
}

LUA_FUNCTION( lMatrixGetTranspose ) {
	gLua->CheckType(1, Type::MATRIX);
	VMatrix* retMat = new VMatrix();
	MatrixTranspose(*((VMatrix*)(gLua->GetUserData(1))), *retMat);
	gLua->PushUserData(matrixMeta, retMat);
	return 1;
}

LUA_FUNCTION( lMatrixGetField ) {
	gLua->CheckType(1, Type::MATRIX);
	gLua->CheckType(2, Type::NUMBER);
	gLua->CheckType(3, Type::NUMBER);
	int row = gLua->GetInteger(2);
	if(row > 4 || row < 1)
		gLua->Error("Invalid row");
	int col = gLua->GetInteger(3);
	if(col > 4 || col < 1)
		gLua->Error("Invalid column");
	VMatrix* mat = (VMatrix*)gLua->GetUserData(1);
	gLua->Push(mat->m[row][col]);
	return 1;
}

LUA_FUNCTION( lMatrixSetField ) {
	gLua->CheckType(1, Type::MATRIX);
	gLua->CheckType(2, Type::NUMBER);
	gLua->CheckType(3, Type::NUMBER);
	gLua->CheckType(4, Type::NUMBER);

	int row = gLua->GetInteger(2);
	if(row > 4 || row < 1)
		gLua->Error("Invalid row");
	int col = gLua->GetInteger(3);
	if(col > 4 || col < 1)
		gLua->Error("Invalid column");
	VMatrix* mat = (VMatrix*)gLua->GetUserData(1);
	mat->m[row][col] = gLua->GetFloat(4);
	return 0;
}

#define createMatGetDir(dir)\
LUA_FUNCTION( lMatrixGet##dir ) {\
	gLua->CheckType(1, Type::MATRIX);\
	Vector* retVec = new Vector(((VMatrix*)gLua->GetUserData(1))->Get##dir ());\
	gLua->PushUserData(vectorMeta, retVec);\
	return 1;\
}
createMatGetDir(Forward);
createMatGetDir(Left);
createMatGetDir(Up);

#define createMatSetDir(dir)\
LUA_FUNCTION( lMatrixSet ## dir ) {\
	gLua->CheckType(1, Type::MATRIX);\
	gLua->CheckType(2, Type::VECTOR);\
	VMatrix* mat = (VMatrix*)gLua->GetUserData(1);\
	Vector* vec = (Vector*)gLua->GetUserData(2);\
	mat->Set##dir(*vec);\
	return 0;\
}
createMatSetDir(Forward);
createMatSetDir(Left);
createMatSetDir(Up);

LUA_FUNCTION( lMatrixSet ) {
	gLua->CheckType(1, Type::MATRIX);
	gLua->CheckType(2, Type::MATRIX);
	MatrixCopy(*((VMatrix*)gLua->GetUserData(2)), *((VMatrix*)gLua->GetUserData(1)));
	return 0;
}

LUA_FUNCTION( lMatrixCopy ) {
	gLua->CheckType(1, Type::MATRIX);
	gLua->PushUserData(matrixMeta, new VMatrix(*((VMatrix*)gLua->GetUserData(1))));
	return 1;
}

LUA_FUNCTION( lMatrixToTable ) {
	gLua->CheckType(1, Type::MATRIX);
	VMatrix* mat = (VMatrix*)gLua->GetUserData(1);
	vec_t(*vec_tMat)[4] = mat->m;
	ILuaObject* retTable = gLua->GetNewTable();
	ILuaObject* subTable;
	for(int i = 1;5>i;i++) {
		subTable = gLua->GetNewTable();
			subTable->SetMember(1, vec_tMat[i-1][0]);
			subTable->SetMember(2, vec_tMat[i-1][1]);
			subTable->SetMember(3, vec_tMat[i-1][2]);
			subTable->SetMember(4, vec_tMat[i-1][3]);
		retTable->SetMember(i, subTable);
		subTable->UnReference();
	}
	retTable->Push();
	retTable->UnReference();
	return 1;
}

LUA_FUNCTION( lMatrixFromTable ) {
	gLua->CheckType(1, Type::MATRIX);
	gLua->CheckType(2, Type::TABLE);
	VMatrix* mat = (VMatrix*)gLua->GetUserData(1);
	vec_t(*vec_tMat)[4] = mat->m;
	ILuaObject* inputTable = gLua->GetObject(2);
	ILuaObject* subTable;
	ILuaObject* subTableMember;
	int k;
	for(int i = 1;5>i;i++) {
		subTable = inputTable->GetMember(i);
		if(!subTable)
			gLua->Error("Subtable is missing!");
		if(!subTable->isTable())
			gLua->Error("Main table member not table!");
		for(k = 1;5>k;k++) {
			if(!(subTableMember = subTable->GetMember(k)))
				gLua->Error("Subtable member not set!");
			if(!subTableMember->isNumber())
				gLua->Error("Subtable member not number!");
			vec_tMat[i-1][k-1] = subTableMember->GetDouble();
		}
	}
	return 0;
}

int Open( lua_State *L ) {
	gLua = Lua();
	if(!gLua)
		printf("UNABLE TO OBTAIN ILuaInterface.");

	vectorMeta = gLua->GetMetaTable("Vector", Type::VECTOR);

	matrixMeta = gLua->GetMetaTable("VMatrix", Type::MATRIX);
		matrixMeta->SetMember("__add", lMatrix__add);
		matrixMeta->SetMember("__eq", lMatrix__eq);
		matrixMeta->SetMember("__mul", lMatrix__mul);
		matrixMeta->SetMember("__sub", lMatrix__sub);
		matrixMeta->SetMember("__unm", lMatrix__unm);
		matrixMeta->SetMember("__tostring", lMatrix__tostring);

		matrixMeta->SetMember("Inverse", lMatrixInverse);
		matrixMeta->SetMember("GetInverse", lMatrixGetInverse);

		matrixMeta->SetMember("IsRotationMatrix", lMatrixIsRotationMatrix);

		matrixMeta->SetMember("IsIdentity", lMatrixIsIdentity);
		matrixMeta->SetMember("Identity", lMatrixIdentity);

		matrixMeta->SetMember("Transpose", lMatrixTranspose);
		matrixMeta->SetMember("GetTranspose", lMatrixGetTranspose);

		matrixMeta->SetMember("GetForward", lMatrixGetForward);
		matrixMeta->SetMember("GetLeft", lMatrixGetLeft);
		matrixMeta->SetMember("GetUp", lMatrixGetUp);

		matrixMeta->SetMember("SetForward", lMatrixSetForward);
		matrixMeta->SetMember("SetLeft", lMatrixSetLeft);
		matrixMeta->SetMember("SetUp", lMatrixSetUp);

		matrixMeta->SetMember("Set", lMatrixSet);
		matrixMeta->SetMember("Copy", lMatrixCopy);

		matrixMeta->SetMember("SetField", lMatrixSetField);
		matrixMeta->SetMember("GetField", lMatrixGetField);

		matrixMeta->SetMember("ToTable", lMatrixToTable);
		matrixMeta->SetMember("FromTable", lMatrixFromTable);

		matrixMeta->SetMember("__index", matrixMeta);
	return 0;
}

int Close(lua_State *L)
{
	vectorMeta->UnReference();
	matrixMeta->UnReference();
	return 0;
}


They work perfect for me? Also useful

All numbers with more than 2 digits wrap into the line for me.

That happens sometimes, not every time. (to me, at least)

Updated, FromTable works now.

Updated.

Added:

Inverse
GetInverse

IsRotationMaMatrix

IsIdentity
Identity

Transpose
GetTranspose

See OP for more info.

[editline]18th September 2012[/editline]

Also changed source code container to code tags, garry broken code highlighter is pissing me off.

Another update, Ralle mentioned I manually created errors instead of type checking, hell know why I did that.