//------------------------------------------------------------------------------------
// irr::core::matrix4 wrappers
//------------------------------------------------------------------------------------

extern "C" 
{

	matrix4* IrrCore_Matrix4_new(matrix4::eConstructor constructor = matrix4::EM4CONST_IDENTITY)
	{
		return new matrix4(constructor);
	}
	
	matrix4* IrrCore_Matrix4_newFromMatrix4(const matrix4& other,matrix4::eConstructor constructor = matrix4::EM4CONST_COPY)
	{
		return new matrix4(other,constructor);
	}

	void IrrCore_Matrix4_del(matrix4* del)
	{
		if (del)
			delete del;
			
		del=0;
	}
	
	// do not delete
	matrix4* IrrCore_Matrix4_makeIdentity(matrix4* matrix)
	{
		if (matrix)
			return &matrix->makeIdentity();
		else return 0;
	}
	
	bool IrrCore_Matrix4_isIdentity(matrix4* matrix)
	{
		bool lRetVal=false;
	
		if (matrix)
			lRetVal=matrix->isIdentity();
	
		return lRetVal;
	}
	
	// do not delete
	matrix4* IrrCore_Matrix4_setTranslation(matrix4* matrix,vector3df* translation)
	{
		if (matrix)
			return &matrix->setTranslation(*translation);
		else return 0;
	}
	
	vector3df* IrrCore_Matrix4_getTranslation(matrix4* matrix)
	{
		vector3df* pRetVal=0;
	
		if (matrix)
			pRetVal=new vector3df(matrix->getTranslation());
	
		return pRetVal;
	}
	
	// do not delete
	matrix4* IrrCore_Matrix4_setInverseTranslation(matrix4* matrix,vector3df* translation)
	{
		if (matrix)
			return &matrix->setInverseTranslation(*translation);
		else return 0;
	}
	
	// do not delete
	matrix4* IrrCore_Matrix4_setRotationRadians(matrix4* matrix,vector3df* rotation)
	{
		if (matrix)
			return &matrix->setRotationRadians(*rotation);
		else return 0;
	}
	
	// do not delete
	matrix4* IrrCore_Matrix4_setRotationDegrees(matrix4* matrix,vector3df* rotation)
	{
		if (matrix)
			return &matrix->setRotationDegrees(*rotation);
		else return 0;
	}
	
	vector3df* IrrCore_Matrix4_getRotationDegrees(matrix4* matrix)
	{
		vector3df* pRetVal=0;
	
		if (matrix)
			pRetVal=new vector3df(matrix->getRotationDegrees());
	
		return pRetVal;
	}
	
	// do not delete
	matrix4* IrrCore_Matrix4_setInverseRotationRadians(matrix4* matrix,vector3df* rotation)
	{
		if (matrix)
			return &matrix->setInverseRotationRadians(*rotation);
		else return 0;
	}
	
	// do not delete
	matrix4* IrrCore_Matrix4_setInverseRotationDegrees(matrix4* matrix,vector3df* rotation)
	{
		if (matrix)
			return &matrix->setInverseRotationDegrees(*rotation);
		else return 0;
	}
	
	// do not delete
	matrix4* IrrCore_Matrix4_setScale(matrix4* matrix,vector3df* scale)
	{
		if (matrix)
			return &matrix->setScale(*scale);
		else return 0;
	}
	
	// do not delete
	matrix4* IrrCore_Matrix4_setScaleFromFloat(matrix4* matrix,f32 scale)
	{
		if (matrix)
			return &matrix->setScale(scale);
		else return 0;
	}
	
	void IrrCore_Matrix4_inverseTranslateVect(matrix4* matrix,vector3df* vect)
	{
		if (matrix)
			matrix->inverseTranslateVect(*vect);
	}
	
	void IrrCore_Matrix4_inverseRotateVect(matrix4* matrix,vector3df* vect)
	{
		if (matrix)
			matrix->inverseRotateVect(*vect);
	}
	
	void IrrCore_Matrix4_rotateVect(matrix4* matrix,vector3df* vect)
	{
		if (matrix)
			matrix->rotateVect(*vect);
	}

	void IrrCore_Matrix4_rotateVectToVect(matrix4* matrix,vector3df* out,vector3df* in)
	{
		if (matrix)
			matrix->rotateVect(*out, *in);
	}

	//! An alternate transform vector method, writing into an array of 3 floats
	void IrrCore_Matrix4_rotateVectToFloatArray(matrix4* matrix,f32 *out,vector3df* in)
	{
		if (matrix)
			matrix->rotateVect(out, *in);
	}
	
	void IrrCore_Matrix4_transformVectIO(matrix4* matrix,vector3df* in,vector3df* out)
	{
		if (matrix)
			matrix->transformVect(*in,*out);
	}
	
	void IrrCore_Matrix4_transformVect(matrix4* matrix,vector3df* vect)
	{
		if (matrix)
			matrix->transformVect(*vect);
	}
	
	void IrrCore_Matrix4_transformVectArray(matrix4* matrix,f32 *out,vector3df* in)
	{
		if (matrix)
			matrix->transformVect(out,*in);
	}
	
	void IrrCore_Matrix4_translateVect(matrix4* matrix,vector3df* vect)
	{
		if (matrix)
			matrix->translateVect(*vect);
	}
	
	void IrrCore_Matrix4_transformPlaneIO(matrix4* matrix,plane3df* in,plane3df* out)
	{
		if (matrix)
			matrix->transformPlane(*in,*out);
	}
	
	void IrrCore_Matrix4_transformPlane(matrix4* matrix,plane3df* plane)
	{
		if (matrix)
			matrix->transformPlane(*plane);
	}
	
	void IrrCore_Matrix4_transformBox(matrix4* matrix,aabbox3d<f32>* box)
	{
		if (matrix)
			matrix->transformBox(*box);
	}
	
	void IrrCore_Matrix4_transformBoxEx(matrix4* matrix,aabbox3d<f32>* box)
	{
		if (matrix)
			matrix->transformBoxEx(*box);
	}
	
	void IrrCore_Matrix4_multiplyWith1x4Matrix(matrix4* matrix,f32* mat)
	{
		if (matrix)
			matrix->multiplyWith1x4Matrix(mat);
	}
	
	bool IrrCore_Matrix4_makeInverse(matrix4* matrix)
	{
		bool lRetVal=false;
	
		if (matrix)
			lRetVal=matrix->makeInverse();
	
		return lRetVal;
	}
	
	bool IrrCore_Matrix4_getInverse(matrix4* matrix,matrix4* out)
	{
		bool lRetVal=false;
	
		if (matrix)
			lRetVal=matrix->getInverse(*out);
	
		return lRetVal;
	}
	
	matrix4* IrrCore_Matrix4_interpolate(matrix4* matrix,matrix4* b,f32 time)
	{
		matrix4* pRetVal=0;
	
		if (matrix)
			pRetVal=new matrix4(matrix->interpolate(*b,time));
	
		return pRetVal;
	}
	
	// need to delete this pointer
	f32* IrrCore_Matrix4_pointer(matrix4* matrix)
	{
		if (matrix)
			return matrix->pointer();
	}
	
	matrix4* IrrCore_Matrix4_getTransposed(matrix4* matrix)
	{
		matrix4* pRetVal=0;
	
		if (matrix)
			pRetVal=new matrix4(matrix->getTransposed());
	
		return pRetVal;
	}
	
	// do not delete
	matrix4* IrrCore_Matrix4_buildProjectionMatrixPerspectiveFovRH(matrix4* matrix,f32 fieldOfViewRadians,f32 aspectRatio,f32 zNear,f32 zFar)
	{
		if (matrix)
			return &matrix->buildProjectionMatrixPerspectiveFovRH(fieldOfViewRadians,aspectRatio,zNear,zFar);
		else return 0;
	}
	
	// do not delete
	matrix4* IrrCore_Matrix4_buildProjectionMatrixPerspectiveFovLH(matrix4* matrix,f32 fieldOfViewRadians,f32 aspectRatio,f32 zNear,f32 zFar)
	{
		if (matrix)
			return &matrix->buildProjectionMatrixPerspectiveFovLH(fieldOfViewRadians,aspectRatio,zNear,zFar);
		else return 0;
	}
	
	// do not delete
	matrix4* IrrCore_Matrix4_buildProjectionMatrixPerspectiveRH(matrix4* matrix,f32 widthOfViewVolume,f32 heightOfViewVolume,f32 zNear,f32 zFar)
	{
		if (matrix)
			return &matrix->buildProjectionMatrixPerspectiveRH(widthOfViewVolume,heightOfViewVolume,zNear,zFar);
		else return 0;
	}
	
	// do not delete
	matrix4* IrrCore_Matrix4_buildProjectionMatrixPerspectiveLH(matrix4* matrix,f32 widthOfViewVolume,f32 heightOfViewVolume,f32 zNear,f32 zFar)
	{
		if (matrix)
			return &matrix->buildProjectionMatrixPerspectiveLH(widthOfViewVolume,heightOfViewVolume,zNear,zFar);
		else return 0;
	}
	
	// do not delete
	matrix4* IrrCore_Matrix4_buildProjectionMatrixOrthoLH(matrix4* matrix,f32 widthOfViewVolume,f32 heightOfViewVolume,f32 zNear,f32 zFar)
	{
		if (matrix)
			return &matrix->buildProjectionMatrixOrthoLH(widthOfViewVolume,heightOfViewVolume,zNear,zFar);
		else return 0;
	}
	
	// do not delete
	matrix4* IrrCore_Matrix4_buildProjectionMatrixOrthoRH(matrix4* matrix,f32 widthOfViewVolume,f32 heightOfViewVolume,f32 zNear,f32 zFar)
	{
		if (matrix)
			return &matrix->buildProjectionMatrixOrthoRH(widthOfViewVolume,heightOfViewVolume,zNear,zFar);
		else return 0;
	}
	
	// do not delete
	matrix4* IrrCore_Matrix4_buildCameraLookAtMatrixLH(matrix4* matrix,vector3df* position,vector3df* target,vector3df* upVector)
	{
		if (matrix)
			return &matrix->buildCameraLookAtMatrixLH(*position,*target,*upVector);
		else return 0;
	}
	
	// do not delete
	matrix4* IrrCore_Matrix4_buildCameraLookAtMatrixRH(matrix4* matrix,vector3df* position,vector3df* target,vector3df* upVector)
	{
		if (matrix)
			return &matrix->buildCameraLookAtMatrixRH(*position,*target,*upVector);
		else return 0;
	}
	
	// do not delete
	matrix4* IrrCore_Matrix4_buildShadowMatrix(matrix4* matrix,vector3df* light,plane3df* plane,f32 point = 1.0f)
	{
		if (matrix)
			return &matrix->buildShadowMatrix(*light,*plane,point);
		else return 0;
	}
	
	// do not delete
	matrix4* IrrCore_Matrix4_buildNDCToDCMatrix(matrix4* matrix,rect<s32>* area, f32 zScale)
	{
		if (matrix)
			return &matrix->buildNDCToDCMatrix(*area,zScale);
		else return 0;
	}
	
	f32 IrrCore_Matrix4_elementAt(matrix4* matrix,s32 row, s32 column)
	{
		f32 fRetVal=0.0f;
		
		if (matrix)
			fRetVal=(*matrix)(row,column);
		
		return fRetVal;
	}
	
	matrix4* IrrCore_Matrix4_Eq(matrix4* matrix,matrix4* other)
	{
		if (matrix) {
			*matrix = *other;
			return matrix;
		} else return 0;
	}
	
	bool IrrCore_Matrix4_EqEq(matrix4* matrix,matrix4* other)
	{
		bool lRetVal=false;
		if (matrix)
			lRetVal=(*matrix == *other);
		return lRetVal;
	}
	
	bool IrrCore_Matrix4_NotEq(matrix4* matrix,matrix4* other)
	{
		bool lRetVal=false;
		if (matrix)
			lRetVal=(*matrix != *other);
		return lRetVal;
	}
	
	matrix4* IrrCore_Matrix4_MultEq(matrix4* matrix,matrix4* other)
	{
		if (matrix) {
			*matrix *= *other;
			return matrix;
		} else return 0;
	}
	
	matrix4* IrrCore_Matrix4_Mult(matrix4* matrix,matrix4* other)
	{
		matrix4* pRetVal=0;
		if (matrix)
			pRetVal=new matrix4(*matrix * *other);
		return pRetVal;
	}
	
	// need to delete ptr
	vector3df* IrrCore_Matrix4_getScale(matrix4* matrix)
	{
		vector3df* pRetVal=0;
	
		if (matrix)
			pRetVal=new vector3df(matrix->getScale());
	
		return pRetVal;
	}
	
	f32* IrrCore_Matrix4_Idx(matrix4* matrix,u32 index)
	{
		if (matrix)
			return &(matrix->pointer()[index]);
		else return 0;
	}
	
	matrix4* IrrCore_Matrix4_EqScalar(matrix4* matrix,const f32 scalar)
	{
		if (matrix) {
			//*matrix = scalar;
			return matrix;
		} else return 0;
	}

	matrix4* IrrCore_Matrix4_MultEqScalar(matrix4* matrix,const f32 scalar)
	{
		if (matrix) {
			*matrix *= scalar;
			return matrix;
		} else return 0;
	}
	
	matrix4* IrrCore_Matrix4_MultScalar(matrix4* matrix,const f32 scalar)
	{
		matrix4* pRetVal=0;
		if (matrix)
			pRetVal=new matrix4(*matrix * scalar);
		return pRetVal;
	}	
	
	matrix4* IrrCore_Matrix4_PlusEq(matrix4* matrix,matrix4* other)
	{
		if (matrix) {
			*matrix += *other;
			return matrix;
		} else return 0;
	}
	
	matrix4* IrrCore_Matrix4_Plus(matrix4* matrix,matrix4* other)
	{
		matrix4* pRetVal=0;
		if (matrix)
			pRetVal=new matrix4(*matrix + *other);
		return pRetVal;
	}	

	matrix4* IrrCore_Matrix4_MinusEq(matrix4* matrix,matrix4* other)
	{
		if (matrix) {
			*matrix -= *other;
			return matrix;
		} else return 0;
	}
	
	matrix4* IrrCore_Matrix4_Minus(matrix4* matrix,matrix4* other)
	{
		matrix4* pRetVal=0;
		if (matrix)
			pRetVal=new matrix4(*matrix - *other);
		return pRetVal;
	}
	
	void IrrCore_Matrix4_setbyproduct_nocheck(matrix4* matrix,const matrix4& other_a,const matrix4& other_b)
	{
		if (matrix)
			matrix->setbyproduct_nocheck(other_a,other_b);
	}
	
	void IrrCore_Matrix4_setbyproduct(matrix4* matrix,const matrix4& other_a,const matrix4& other_b)
	{
		if (matrix)
			matrix->setbyproduct(other_a,other_b);
	}
	
	bool IrrCore_Matrix4_isIdentity_integer_base(matrix4* matrix)
	{
		if (matrix)
			return matrix->isIdentity_integer_base();
		else return false;
	}
	
	void IrrCore_Matrix4_rotateVectToOut(matrix4* matrix,f32 *out,const core::vector3df &in)
	{
		if (matrix)
			matrix->rotateVect(out,in);
	}
		
	bool IrrCore_Matrix4_getInversePrimitive(matrix4* matrix, matrix4& out)
	{
		if (matrix)
			return matrix->getInversePrimitive(out);
		else return false;
	}
	
	void IrrCore_Matrix4_getTransposedToDest(matrix4* matrix, matrix4& dest)
	{
		if (matrix)
			matrix->getTransposed(dest);
	}
	
	// do not delete
	matrix4* IrrCore_Matrix4_setTextureRotationCenter(matrix4* matrix, f32 rotateRad)
	{
		if (matrix)
			return &matrix->setTextureRotationCenter(rotateRad);
		else return 0;
	}
	
	// do not delete
	matrix4* IrrCore_Matrix4_setTextureTranslate(matrix4* matrix, f32 x, f32 y)
	{
		if (matrix)
			return &matrix->setTextureTranslate(x,y);
		else return 0;
	}
	
	// do not delete
	matrix4* IrrCore_Matrix4_setTextureScale(matrix4* matrix, f32 sx, f32 sy)
	{
		if (matrix)
			return &matrix->setTextureScale(sx,sy);
		else return 0;
	}
	
	// do not delete
	matrix4* IrrCore_Matrix4_setTextureScaleCenter(matrix4* matrix, f32 sx, f32 sy)
	{
		if (matrix)
			return &matrix->setTextureScaleCenter(sx,sy);
		else return 0;
	}
	
	// do not delete
	matrix4* IrrCore_Matrix4_buildTextureTransform(matrix4* matrix, f32 rotateRad,const core::vector2df &rotatecenter,const core::vector2df &translate,const core::vector2df &scale)
	{
		if (matrix)
			return &matrix->buildTextureTransform(rotateRad,rotatecenter,translate,scale);
		else return 0;
	}
	
	// do not delete
	matrix4* IrrCore_Matrix4_setM(matrix4* matrix,const f32* data)
	{
		if (matrix)
			return &matrix->setM(data);
		else return 0;
	}

	void IrrCore_Matrix4_setDefinitelyIdentityMatrix(matrix4* matrix,bool isDefinitelyIdentityMatrix)
	{
		if (matrix)
			matrix->setDefinitelyIdentityMatrix(isDefinitelyIdentityMatrix);
	}

	bool IrrCore_Matrix4_getDefinitelyIdentityMatrix(matrix4* matrix)
	{
		if (matrix)
			return matrix->getDefinitelyIdentityMatrix();
		else return false;
	}

	// do not delete
	matrix4* IrrCore_Matrix4_setTextureTranslateTransposed(matrix4* matrix, f32 x, f32 y)
	{
		if (matrix)
			return &matrix->setTextureTranslateTransposed(x, y);
		else return 0;
	}

	bool IrrCore_Matrix4_isOrthogonal(matrix4* matrix) {
		if (matrix)
			return matrix->isOrthogonal();
		else return false;
	}
	
	// must delete
	matrix4* IrrCore_Matrix4_buildRotateFromTo(matrix4* matrix, const core::vector3df& from, const core::vector3df& to) {
		if (matrix)
			return new matrix4(matrix->buildRotateFromTo(from, to));
		else return 0;
	}
	
	void IrrCore_Matrix4_setRotationCenter(matrix4* matrix, const core::vector3df& center, const core::vector3df& translate) {
		if (matrix)
			matrix->setRotationCenter(center, translate);
	}
	
	void IrrCore_Matrix4_buildAxisAlignedBillboard(	matrix4* matrix, 
									const core::vector3df& camPos,
									const core::vector3df& center,
									const core::vector3df& translation,
									const core::vector3df& axis,
									const core::vector3df& from
								) {
		if (matrix)
			matrix->buildAxisAlignedBillboard(camPos, center, translation, axis, from);
	}	
	
	bool IrrCore_Matrix4_equals(matrix4* matrix, const matrix4& other, const f32 tolerance=(f32)ROUNDING_ERROR_f64) 
	{
		if (matrix)
			return matrix->equals(other, tolerance);
		else return false;
	}
}