//-----------------------------------------------------------------------------
//                           PS2 Shell System Core
//
// shellVU0Math header file
//
// $Workfile: shellVU0Math.h $
// $Author: Ygoh $
// $Date: 20/02/04 15:01 $
// $Revision: 18 $
//
// Copyright (c) 2002-3 Sony Computer Entertainment Europe.
// All Rights Reserved.
//
//-----------------------------------------------------------------------------

#ifndef _SHELL_VU0MATH_H_
#define _SHELL_VU0MATH_H_

#include <math.h>

#ifdef __cplusplus
extern "C" {
#endif


//-----------------------------------------------------------------------------
// T Y P E D E F S
//-----------------------------------------------------------------------------

typedef union _ShellVector
{
	float v[4];
	u_long128 u;
} ShellVector;

typedef union _ShellMatrix
{
	float m[4][4];
	ShellVector v[4];
} ShellMatrix;

// VU0 Micro Code Control
// Current code address hidden in VI27 (CMSAR0)

typedef enum
{
	SHELLVU0MATH_MICROCODE_NONE		= 0,
	SHELLVU0MATH_MICROCODE_DEFAULT	= 1,
	SHELLVU0MATH_MICROCODE_USER		= 0x4000
} EShellVU0MathMicrocodeType;

//-----------------------------------------------------------------------------
// P R O T O T Y P E S
//-----------------------------------------------------------------------------

// VU0 Microcode Implementations (external)

extern unsigned int MicroUpload0[] __attribute__((section(".vudata")));
extern void VU0BBoxSetup(void) __attribute__ ((section(".vutext")));
extern void VU0BBoxEntry(void) __attribute__ ((section(".vutext")));
extern void PortalExtents(void) __attribute__ ((section(".vutext")));
extern void VU0MathMatrixMultiply1(void) __attribute__ ((section(".vutext")));
extern void VU0MathMatrixMultiply2(void) __attribute__ ((section(".vutext")));
extern void VU0MathRotateX(void)		__attribute__((section(".vutext")));
extern void VU0MathRotateY(void)		__attribute__((section(".vutext")));
extern void VU0MathRotateZ(void)		__attribute__((section(".vutext")));


//-----------------------------------------------------------------------------
// shellVU0MathUploadCode()
// Description: Uploads microcode to VU0 if not already installed
// Parameters:  type - Type of code to be uploaded
//              code - Pointer to DMA chain to upload microcode
// Notes:
//-----------------------------------------------------------------------------
static inline void shellVU0MathUploadCode(EShellVU0MathMicrocodeType type, ShellDmaTag *code)
{
	EShellVU0MathMicrocodeType currentType;
	asm("CFC2 %0, $vi27" : "=r"(currentType));
	if(type && currentType != type) {
		shellDmaSetChannelOptions(SHELLDMA_CHANNEL_VIF0,1,1,0,0,0,0);
		shellDmaStartChain(SHELLDMA_CHANNEL_VIF0,code);
		shellDmaSync(SHELLDMA_CHANNEL_VIF0,0);
	}
	asm("CTC2 %0, $vi27" : : "r"(type));
}

//-----------------------------------------------------------------------------
// shellVU0MathMatrixLoad0()
// Description: Loads a matrix into matrix 0
// Parameters: mat - Matrix to load into matrix 0
// Notes: 
//-----------------------------------------------------------------------------
static inline void shellVU0MathMatrixLoad0(ShellMatrix *mat)
{
	asm("
		lqc2	vf1,0x00(%0)
		lqc2	vf2,0x10(%0)
		lqc2	vf3,0x20(%0)
		lqc2	vf4,0x30(%0)
	": :"r"(mat));
}

//-----------------------------------------------------------------------------
// shellVU0MathMatrixStore0()
// Description: Stores the matrix from matrix 0
// Parameters: mat - Matrix into which to store matrix 0 
// Notes: 
//-----------------------------------------------------------------------------
static inline void shellVU0MathMatrixStore0(ShellMatrix *mat)
{
	asm("
		sqc2	vf1,0x00(%0)
		sqc2	vf2,0x10(%0)
		sqc2	vf3,0x20(%0)
		sqc2	vf4,0x30(%0)
	": :"r"(mat));
}

//-----------------------------------------------------------------------------
// shellVU0MathMatrixLoad1()
// Description: Loads a matrix into matrix 1
// Parameters: mat - Matrix to load into matrix 1
// Notes: 
//-----------------------------------------------------------------------------
static inline void shellVU0MathMatrixLoad1(ShellMatrix *mat)
{
	asm("
		lqc2	vf5,0x00(%0)
		lqc2	vf6,0x10(%0)
		lqc2	vf7,0x20(%0)
		lqc2	vf8,0x30(%0)
	": :"r"(mat));
}

//-----------------------------------------------------------------------------
// shellVU0MathMatrixStore1()
// Description: Stores the matrix from matrix 1
// Parameters: mat - Matrix into which to store matrix 1
// Notes: 
//-----------------------------------------------------------------------------
static inline void shellVU0MathMatrixStore1(ShellMatrix *mat)
{
	asm("
		sqc2	vf5,0x00(%0)
		sqc2	vf6,0x10(%0)
		sqc2	vf7,0x20(%0)
		sqc2	vf8,0x30(%0)
	": :"r"(mat));
}

//-----------------------------------------------------------------------------
// shellVU0MathMatrixLoad2()
// Description: Loads a matrix into matrix 2
// Parameters: mat - Matrix to load into matrix 2
// Notes: 
//-----------------------------------------------------------------------------
static inline void shellVU0MathMatrixLoad2(ShellMatrix *mat)
{
	asm("
		lqc2	vf28,0x00(%0)
		lqc2	vf29,0x10(%0)
		lqc2	vf30,0x20(%0)
		lqc2	vf31,0x30(%0)
	": :"r"(mat));
}

//-----------------------------------------------------------------------------
// shellVU0MathMatrixStore2()
// Description: Stores the matrix from matrix 2
// Parameters: mat - Matrix into which to store Matrix 2
// Notes: 
//-----------------------------------------------------------------------------
static inline void shellVU0MathMatrixStore2(ShellMatrix *mat)
{
	asm("
		sqc2	vf28,0x00(%0)
		sqc2	vf29,0x10(%0)
		sqc2	vf30,0x20(%0)
		sqc2	vf31,0x30(%0)
	": :"r"(mat));
}

//-----------------------------------------------------------------------------
// shellVU0MathMatrixMultiply1()
// Description: Macro mode multiplication of matrix 0 and matrix 1 to matrix 1
// Notes: 
//-----------------------------------------------------------------------------
static inline void shellVU0MathMatrixMultiply1()
{
	asm("
		vmulax	ACC,vf1,vf5
		vmadday	ACC,vf2,vf5
		vmaddaz	ACC,vf3,vf5
		vmaddw	vf5,vf4,vf5
		vmulax	ACC,vf1,vf6
		vmadday	ACC,vf2,vf6
		vmaddaz	ACC,vf3,vf6
		vmaddw	vf6,vf4,vf6
		vmulax	ACC,vf1,vf7
		vmadday	ACC,vf2,vf7
		vmaddaz	ACC,vf3,vf7
		vmaddw	vf7,vf4,vf7
		vmulax	ACC,vf1,vf8
		vmadday	ACC,vf2,vf8
		vmaddaz	ACC,vf3,vf8
		vmaddw	vf8,vf4,vf8
	");
}

//-----------------------------------------------------------------------------
// shellVU0MathMatrixMultiply2()
// Description: Macro mode multiplication of matrix 0 and matrix 1 to matrix 2
// Notes: 
//-----------------------------------------------------------------------------
static inline void shellVU0MathMatrixMultiply2()
{
	asm("
		vmulax	ACC,vf1,vf5
		vmadday	ACC,vf2,vf5
		vmaddaz	ACC,vf3,vf5
		vmaddw	vf28,vf4,vf5
		vmulax	ACC,vf1,vf6
		vmadday	ACC,vf2,vf6
		vmaddaz	ACC,vf3,vf6
		vmaddw	vf29,vf4,vf6
		vmulax	ACC,vf1,vf7
		vmadday	ACC,vf2,vf7
		vmaddaz	ACC,vf3,vf7
		vmaddw	vf30,vf4,vf7
		vmulax	ACC,vf1,vf8
		vmadday	ACC,vf2,vf8
		vmaddaz	ACC,vf3,vf8
		vmaddw	vf31,vf4,vf8
	");
}

//-----------------------------------------------------------------------------
// shellVU0MathMatrixMultiply1Micro()
// Description: Microcode implementation of shellVU0MathMatrixMultiply1()
// Notes:
//-----------------------------------------------------------------------------
static inline void shellVU0MathMatrixMultiply1Micro()
{
	shellVU0MathUploadCode(SHELLVU0MATH_MICROCODE_DEFAULT, (ShellDmaTag*)MicroUpload0);
	asm("vcallms VU0MathMatrixMultiply1");
}

//-----------------------------------------------------------------------------
// shellVU0MathMatrixMultiply2Micro()
// Description: Microcode implementation of shellVU0MathMatrixMultiply2()
// Notes:
//-----------------------------------------------------------------------------
static inline void shellVU0MathMatrixMultiply2Micro()
{
	shellVU0MathUploadCode(SHELLVU0MATH_MICROCODE_DEFAULT, (ShellDmaTag*)MicroUpload0);
	asm("vcallms VU0MathMatrixMultiply2");
}

//-----------------------------------------------------------------------------
// shellVU0MathMulVector()
// Description: Element-wise multiplies two vectors together
// Parameters: v0 - Address of output vector
//             v1 - Address of input vector 1
//             v2 - Address of input vector 2
// Notes: 
//-----------------------------------------------------------------------------
static inline void shellVU0MathMulVector(ShellVector *v0, ShellVector *v1, ShellVector *v2)
{
	asm ("
	lqc2    vf9,0x0(%1)
	lqc2    vf18,0x0(%2)
	vmul.xyzw	vf9,vf9,vf18
	sqc2    vf9,0x0(%0)
	": : "r" (v0) , "r" (v1), "r" (v2));
}

//-----------------------------------------------------------------------------
// shellVU0MathApplyMatrix0()
// Description: Applies the matrix in matrix 0 to a vector
// Parameters: out - Address of the output vector 
//             in  - Address of the input vector
// Notes: 
//-----------------------------------------------------------------------------
static inline void shellVU0MathApplyMatrix0(ShellVector *out, ShellVector *in)
{
	asm("
		lqc2 vf9, 0x0(%1)
		vmulax ACC,vf1,vf9
		vmadday ACC,vf2,vf9
		vmaddaz ACC,vf3,vf9
		vmaddw vf9,vf4,vf9
		sqc2 $vf9, 0x0(%0)
		": : "r"(out), "r"(in));
}

//-----------------------------------------------------------------------------
// shellVU0MathTransposeMatrix()
// Description: Transposes an affine matrix
// Parameters: out - Address of output matrix
//             in - Address of input matrix
// Notes: This function avoids using VU0 in order that it can run in parallel
//        with micro code
//-----------------------------------------------------------------------------
static inline void shellVU0MathTransposeMatrix(ShellMatrix *out, ShellMatrix *in)
{
	asm __volatile__("
	lq $8,0x0000(%1)
	lq $9,0x0010(%1)
	lq $10,0x0020(%1)
	lq $11,0x0030(%1)

	pextlw     $12,$9,$8
	pextuw     $13,$9,$8
	pextlw     $14,$11,$10
	pextuw     $15,$11,$10

	pcpyld     $8,$14,$12

	sq $8,0x0000(%0)
	pcpyud     $9,$12,$14

	sq $9,0x0010(%0)
	pcpyld     $10,$15,$13

	sq $10,0x0020(%0)
	pcpyud     $11,$13,$15
	
	sq $11,0x0030(%0)
	": : "r" (out) , "r" (in) : "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15");
}

//-----------------------------------------------------------------------------
// shellVU0MathInvertMatrix()
// Description: Inverts a matrix
// Parameters: mat - Address of matrix to invert
// Notes: This function avoids using VU0 in order that it can run in parallel
//        with micro code
//-----------------------------------------------------------------------------
static inline void shellVU0MathInvertMatrix(ShellMatrix *mat)
{
ShellMatrix tempMatrix;
	asm __volatile__("
.set noreorder
	qmfc2.ni $8, $vf28
	
	qmfc2.ni $9, $vf29
	
	sqc2		$vf31, 0x30(%1)
	pextlw     $12,$9,$8
	
	qmfc2.ni $10, $vf30

	pextuw     $13,$9,$8
	pextlw     $14,$0,$10
	pcpyld     $11,$14,$12

	pcpyud     $9,$12,$14
	sq			$11, 0x00(%1)
	
	pextuw     $15,$0,$10
	sq			 $9, 0x10(%1)

	pcpyld     $10,$15,$13
	sq			$10, 0x20(%1)

	# Load translation vector
	lwc1 $f8,  0x30(%1)
	lwc1 $f9,  0x34(%1)
	lwc1 $f10, 0x38(%1)
	
	# Load column 1
	lwc1 $f5, 0x00(%1)
	lwc1 $f6, 0x10(%1)
	lwc1 $f7, 0x20(%1)
	mula.s  $f5, $f8
	madda.s $f6, $f9
	madd.s  $f11, $f7, $f10
	neg.s $f11, $f11
	swc1 $f11, 0x30(%1)
	
	# Load column 2
	lwc1 $f5, 0x04(%1)
	lwc1 $f6, 0x14(%1)
	lwc1 $f7, 0x24(%1)
	mula.s  $f5, $f8
	madda.s $f6, $f9
	madd.s  $f11, $f7, $f10
	neg.s $f11, $f11
	swc1 $f11, 0x34(%1)

	# Load column 3
	lwc1 $f5, 0x08(%1)
	lwc1 $f6, 0x18(%1)
	lwc1 $f7, 0x28(%1)
	mula.s  $f5, $f8
	madda.s $f6, $f9
	madd.s  $f11, $f7, $f10
	neg.s $f11, $f11
	swc1 $f11, 0x38(%1)
	
	lq			$11, 0x00(%1)
	lq			 $9, 0x10(%1)
	lq			$10, 0x20(%1)
	lq			 $8, 0x30(%1)
	sq			$11, 0x00(%0)
	sq			 $9, 0x10(%0)
	sq			$10, 0x20(%0)
	sq			 $8, 0x30(%0)
.set reorder
	": : "r" (mat), "r"(&tempMatrix) :"$8","$9","$10","$11", "$12","$13","$14","$15",
	"$f5", "$f6", "$f7", "$f8", "$f9", "$f10", "$f11");
}

//-----------------------------------------------------------------------------
// shellVU0MathMatrixSetPerspective()
// Description: Sets a matrix to the perspective matrix
// Parameters: mat		- Address of matrix to output
//             fovy		- Field of view in degrees
//             near		- Distance to near plane
//             far		- Distance to far plane
//             aspect	- Aspect ratio
//             xmin		- Minimum projected X value in clip space
//             ymin		- Minimum projected Y value in clip space
//             xmax		- Maximum projected X value in clip space
//             ymax		- Maximum projected Y value in clip space
//	Notes:
//	Frustum matrix
//			[	2n/(r-l)		0				(r+l)/(r-l)		0			]
//		F =	[	0				2n/(t-b)		(t+b)/(t-b)		0			]
//			[	0				0				(f+n)/(f-n)		2nf/(f-n)	]
//			[	0				0				-1				0			]
//
//	Perspective matrix
//		t-b =	2*n*tan(fovy/2)
//		dy  =	1/tan(fovy/2)
//		dx  =	dy/aspect
//
//			[	dy/aspect		0				0				0					]
//		P =	[	0				dy				0				0					]
//			[	0				0				(zf+zn)/(zf-zn)	2*zn*zf/(zf-zn)		]
//			[	0				0				-1				0					]
//
//	"Clipping" matrix
//			[	2/(xmax-xmin)	0				0				(xmax+xmin)/(xmin-xmax)	]
//		C =	[	0				2/(ymax-ymin)	0				(ymax+ymin)/(ymin-ymax)	]
//			[	0				0				2/(zmax-zmin)	(zmax+zmin)/(zmin-zmax)	]
//			[	0				0				0				1						]
//
//	Resulting matrix (R = C*P)
//		in our casee,
//			2/(zmax-zmin)			=	1
//			(zmax+zmin)/(zmin-zmax)	=	0
//			f > n > 0
//
//			[	2*dy/aspect*(xmax-xmin)	0					(xmax+xmin)/(xmax-xmin)		0			]
//		R =	[	0						2*dy/(ymax-ymin)	(ymax+ymin)/(ymax-ymin)		0			]
//			[	0						0					(f+n)/(f-n)					2nf/(f-n)	]
//			[	0						0					-1							0			]
//
//	-2nf/(f-n) =	n * [1 + (f+n)/(f-n)]
//-----------------------------------------------------------------------------
static inline void	shellVU0MathMatrixSetPerspective(	ShellMatrix*	mat,
														float			fovy,
														float			near,		// DISTANCE(>0)
														float			far,		// DISTANCE(>near>0)
														float			aspect,
														float			xmin,
														float			xmax,
														float			ymin,
														float			ymax )
{
	register float	dy;
	dy =			2.0f / tanf(fovy *((float)(M_PI/ 180.0)));				// 2.0f / (fovy/2)

	// Clear matrix to 0
	asm __volatile__
	(
		"
		sq		$0, 0x00(%0)
		sq		$0, 0x10(%0)
		sq		$0, 0x20(%0)
		sq		$0, 0x30(%0)
		"
		:
		:
		"r" (mat->m)
	);

	mat->m[0][0] =	dy / ((xmax-xmin) * aspect);
	mat->m[1][1] =	dy /  (ymax-ymin);
	mat->m[2][0] =	(xmax+xmin) / (xmax-xmin);
	mat->m[2][1] =	(ymax+ymin) / (ymax-ymin);
	mat->m[2][2] =	(far +near) / (far -near);								// near(z=+1) ; far(z=-1)
	mat->m[2][3] =	-1.0f;
	mat->m[3][2] =	near * (1.0f + mat->m[2][2]);							// near(z=+1) ; far(z=-1)	2.0f*near*far/(near-far)
}


//-----------------------------------------------------------------------------
// shellVU0MathMatrixSetIdentity()
// Description: Sets a matrix to the identity matrix
// Parameters: mat - Address of matrix to be set to identity
// Notes: 
//-----------------------------------------------------------------------------
static inline void shellVU0MathMatrixSetIdentity(ShellMatrix *mat)
{
	asm("
		sqc2	vf0,0x30(%0)
		vmr32	vf09,vf0
		sqc2	vf09,0x20(%0)	
		vmr32	vf09,vf09
		sqc2	vf09,0x10(%0)	
		vmr32	vf09,vf09
		sqc2	vf09,0x00(%0)	
	": :"r"(mat));
}

//-----------------------------------------------------------------------------
// shellVU0MathMatrixZero()
// Description: Zeros out a matrix
// Parameters: mat - Address of matrix to be zero'd
//-----------------------------------------------------------------------------
static inline void shellVU0MathMatrixZero(ShellMatrix *mat)
{
	asm("
		sq	$0,0x00(%0)
		sq	$0,0x10(%0)
		sq	$0,0x20(%0)
		sq	$0,0x30(%0)
	": :"r"(mat));
}

//-----------------------------------------------------------------------------
// shellVU0MathVectorSet()
// Description: Sets a vector
// Parameters: v0 - Address of vector to be set
//			   x,y,z,w - vector component values
//-----------------------------------------------------------------------------
static inline void shellVU0MathVectorSet(ShellVector *v0, float x, float y, float z, float w)
{
	u_long128 temp0, temp1;
	asm("pcpyld %0,%1,%2" : "=r"(temp0) : "r"(y), "r"(x) );
    asm("pcpyld %0,%1,%2" : "=r"(temp1) : "r"(w), "r"(z) );
    asm("ppacw %0,%1,%2" : "=r"(v0->u) : "r"(temp1), "r"(temp0) );
}

//-----------------------------------------------------------------------------
// shellVU0MathRotXMatrix0()
// Description: microcode to generate rotation in matrix0
// Parameters: angle in radians
//-----------------------------------------------------------------------------
static inline void shellVU0MathRotXMatrix0(float angle)
{
	shellVU0MathUploadCode(SHELLVU0MATH_MICROCODE_DEFAULT, (ShellDmaTag *) MicroUpload0);
	asm ("
		qmtc2.i %0,vf15
		vcallms VU0MathRotateX
	" : : "r"( angle ) );
}

//-----------------------------------------------------------------------------
// shellVU0MathRotYMatrix0()
// Description: microcode to generate rotation in matrix0
// Parameters: angle in radians
//-----------------------------------------------------------------------------
static inline void shellVU0MathRotYMatrix0(float angle)
{
	shellVU0MathUploadCode(SHELLVU0MATH_MICROCODE_DEFAULT, (ShellDmaTag *) MicroUpload0);
	asm ("
		qmtc2.i %0,vf15
		vcallms VU0MathRotateY
	" : : "r"( angle ) );
}

//-----------------------------------------------------------------------------
// shellVU0MathRotZMatrix0()
// Description: microcode to generate rotation in matrix0
// Parameters: angle in radians
//-----------------------------------------------------------------------------
static inline void shellVU0MathRotZMatrix0(float angle)
{
	shellVU0MathUploadCode(SHELLVU0MATH_MICROCODE_DEFAULT, (ShellDmaTag *) MicroUpload0);
	asm ("
		qmtc2.i %0,vf15
		vcallms VU0MathRotateZ
	" : : "r"( angle ) );
}

//-----------------------------------------------------------------------------
// shellVU0MathMatrixLoad1i()
// Description: Loads a matrix into matrix 1 with 'interlock' 
//				waits for current vu0 microcode to finish
// Parameters: mat - Matrix to load into matrix 1
//-----------------------------------------------------------------------------
static inline void shellVU0MathMatrixLoad1i(ShellMatrix *mat)
{
	asm("
		vnop
		lqc2	vf5,0x00(%0)
		lqc2	vf6,0x10(%0)
		lqc2	vf7,0x20(%0)
		lqc2	vf8,0x30(%0)
	": :"r"(mat));
}

//-----------------------------------------------------------------------------
// shellVU0MathMatrixStore1i()
// Description: Stores the matrix from matrix 1 with 'interlock'
//				waits for current vu0 microcode to finish
// Parameters: mat - Matrix into which to store matrix 1
//-----------------------------------------------------------------------------
static inline void shellVU0MathMatrixStore1i(ShellMatrix *mat)
{
	asm("
		vnop
		sqc2	vf5,0x00(%0)
		sqc2	vf6,0x10(%0)
		sqc2	vf7,0x20(%0)
		sqc2	vf8,0x30(%0)
	": :"r"(mat));
}

//-----------------------------------------------------------------------------
// shellVU0MathTranslateMatrix1()
// Description: adds vector translation into matrix1
// Parameters: v0 - Address of input vector 
//-----------------------------------------------------------------------------
static inline void shellVU0MathTranslateMatrix1(ShellVector* v0)
{
	asm("
		lqc2 vf9, 0x0(%0)
		vadd.xyz vf8,vf8,vf9
	": : "r" (v0) );
}

//-----------------------------------------------------------------------------
// shellVU0MathCalculatePortalExtents()
// Description: Obtain the screen space extents of a portal's bounding box
// Parameters: bounds - Array of two vectors with minimum and maximum bounds
// Notes:	Overwrites matrix 1
//-----------------------------------------------------------------------------
static inline void shellVU0MathCalculatePortalExtents(ShellVector *bounds)
{
	shellVU0MathUploadCode(SHELLVU0MATH_MICROCODE_DEFAULT, (ShellDmaTag *) MicroUpload0);
	asm __volatile__ ("
		LQC2	vf5, 0x00(%0)
		LQC2	vf6, 0x10(%0)
		VCALLMS PortalExtents
	": : "r"(bounds));
}

//-----------------------------------------------------------------------------
// shellVU0MathGetPortalExtents()
// Description: Retrieve the result of shellVU0MathCalculatePortalExtents
// Parameters: exents[0]: minimum x and y, extents[1]: maximum x and y
// Notes:	Overwrites matrix 1
//-----------------------------------------------------------------------------
static inline void shellVU0MathGetPortalExtents(ShellVector extents[2])
{
	asm __volatile__ ("
		vNOP
		sqc2		vf05, 0x00(%0)
		sqc2		vf06, 0x10(%0)
	": : "r" (extents));
}

//-----------------------------------------------------------------------------
// shellVU0MathBBoxSetup()
// Description: Initialise bounding box test using matrix 2
// Notes:
//-----------------------------------------------------------------------------
static inline void shellVU0MathBBoxSetup()
{
	shellVU0MathUploadCode(SHELLVU0MATH_MICROCODE_DEFAULT, (ShellDmaTag *) MicroUpload0);
	asm("vcallms VU0BBoxSetup");
}

//-----------------------------------------------------------------------------
// shellVU0MathBBoxTest()
// Description: Applies the bounding box test
// Parameters: bounds - Array of two vectors with minimum and maximum bounds
// Returns:    The outcome of the test
//             0 = No clipping required
//             1 = Clipping required
//             Other = Not visible
// Notes: shellVU0MathBBoxSetup() must be called first
//		  Overwrites matrix 1
//-----------------------------------------------------------------------------
static inline int shellVU0MathBBoxTest(ShellVector *bounds)
{
	int outcode;
	shellVU0MathUploadCode(SHELLVU0MATH_MICROCODE_DEFAULT, (ShellDmaTag *) MicroUpload0);
	asm("
			lqc2	vf5, 0x0(%1)
			lqc2	vf6, 0x10(%1)		
			vcallms VU0BBoxEntry
			vnop
			cfc2.i	%0,$vi1
	":"=r"(outcode):"r"(bounds));
	return outcode;
}

#ifdef __cplusplus
}
#endif

#endif // _SHELLCORE_VU0MATH_H_
