/************************************************************************************
	GLOVER PSX	(c) 1998-9 ISL

	poly.c:		Poly draw routines for general objects

************************************************************************************/

/*********************************************
This routine has now been CACHED ALIGNED! 
Therefore the beginning of the file starts
on a 4k boundry. It currently breaks somewhere in DrawBox.
Meaning that the whole of DrawPrimative remains in the cache. (very good!)
NB. No global variables can be set within this file!!! 
***********************************************/

#include "glover.h"

#define transformedVertices  transVerts

// Andy Sidwell and I (Chris Wilson) have re-written the following routine and a
// similar one in lscape.c in assembler, and is now 30% faster than the C version.

/*
void polyTransformVertices(long numVerts)
//transform a large number of 3D coords to 2D very quickly. Done in 3's
{
	register u_long   ur0     asm("$16");
	register u_long   ur1     asm("$17");
	register u_long   ur2     asm("$18");
	register u_long   ur3     asm("$19");
	register u_long   ur4     asm("$20");
	register u_long   ur5     asm("$21");
	
	register u_long vertLoop;
	register u_long vertLoopTop;
	VERT *vertPtr;

	vertLoopTop = numVerts + (3 - (numVerts % 3));

	vertPtr = (VERT*)modelctrl.VertTop;

	cpu_ldr(ur0,(u_long*)&vertPtr[0].vx);
	cpu_ldr(ur1,(u_long*)&vertPtr[0].vz);
	cpu_ldr(ur2,(u_long*)&vertPtr[1].vx);
	cpu_ldr(ur3,(u_long*)&vertPtr[1].vz);
	cpu_ldr(ur4,(u_long*)&vertPtr[2].vx);
	cpu_ldr(ur5,(u_long*)&vertPtr[2].vz);

	for(vertLoop = 0; vertLoop < vertLoopTop; vertLoop += 3)
	{
		cpu_gted0(ur0);
		cpu_gted1(ur1);
		cpu_gted2(ur2);
		cpu_gted3(ur3);
		cpu_gted4(ur4);
		cpu_gted5(ur5);

		gte_rtpt();

		cpu_ldr(ur0,(u_long*)&vertPtr[vertLoop + 3].vx);
		cpu_ldr(ur1,(u_long*)&vertPtr[vertLoop + 3].vz);
		cpu_ldr(ur2,(u_long*)&vertPtr[vertLoop + 4].vx);
		cpu_ldr(ur3,(u_long*)&vertPtr[vertLoop + 4].vz);
		cpu_ldr(ur4,(u_long*)&vertPtr[vertLoop + 5].vx);
		cpu_ldr(ur5,(u_long*)&vertPtr[vertLoop + 5].vz);

		gte_stsxy3c(&transformedVertices[vertLoop]);
	}

}
*/

/************************************************************************************/
// Primitive generation routines

inline PACKET *polyAddTG4(POLY_GT4 *si, VERT* vp, MODELCTRL *modctrl, GsOTA *ot);
inline PACKET *polyAddTG4T(POLY_GT4 *si, VERT* vp, MODELCTRL *modctrl, GsOTA *ot);
inline PACKET *polyAddTG3(POLY_GT3 *si, VERT* vp, MODELCTRL *modctrl, GsOTA *ot);
PACKET *polyAddTF4(POLY_FT4 *si, VERT* vp, MODELCTRL *modctrl, GsOTA *ot);
PACKET *polyAddTF3(POLY_FT3 *si, VERT* vp, MODELCTRL *modctrl, GsOTA *ot);
PACKET *polyAddF3(POLY_F3 *si, VERT* vp, MODELCTRL *modctrl, GsOTA *ot);
PACKET *polyAddG3(POLY_G3 *si, VERT* vp, MODELCTRL *modctrl, GsOTA *ot);
PACKET *polyAddF4(POLY_F4 *si, VERT* vp, MODELCTRL *modctrl, GsOTA *ot);
PACKET *polyAddG4(POLY_G4 *si, VERT* vp, MODELCTRL *modctrl, GsOTA *ot);
PACKET *polyAddTF4SPR(POLY_FT4 *si, VERT* vp, MODELCTRL *modctrl, GsOTA *ot);


/**************************************************************************
	FUNCTION:	polyDrawPrimitives()
	PURPOSE:	Add primitives to packet draw list
	PARAMETERS:	Ptr to order table entry
	RETURNS:	

NB. This has all been changed to inline CASE statements, by ANO 6/5/99.
    This is slightly less readable, but means that varibles are not 
    pushed and popped of the stack as it goes from 1 poly to the next.
	I've used defines, so the same registers get re-used.
NBB.   Changed to and Lite and UNlite routines, by ANO 4/8/99

**************************************************************************/

void polyDrawPrimitives(GsOTA *ot)	//Without lighting!
{
#define OPGT4 ((TMD_P_TG4A*)op) 
#define SIGT4 ((POLY_GT4*)packet)
#define OPGT3 ((TMD_P_TG3A*)op) 
#define SIGT3 ((POLY_GT3*)packet)
#define OPFT4 ((TMD_P_TF4A*)op) 
#define SIFT4 ((POLY_FT4*)packet)
#define OPFT3 ((TMD_P_TF3A*)op) 
#define SIFT3 ((POLY_FT3*)packet)
#define OPG4 ((TMD_P_F4G*)op) 
#define SIG4 ((POLY_G4*)packet)
#define OPG3 ((TMD_P_F3G*)op) 
#define SIG3 ((POLY_G3*)packet)
#define OPF4 ((TMD_P_F4*)op) 
#define SIF4 ((POLY_F4*)packet)
#define OPF3 ((TMD_P_F3*)op) 
#define SIF3 ((POLY_F3*)packet)
#define OPFT4S ((TMD_P_TF4A*)op) 
#define SIFT4S ((POLY_FT4*)packet)

	register PACKET*  	packet = GsOUT_PACKET_P;
	register TMD_P_TF4A	*op;
	register MODELCTRL	*modctrl = &modelctrl;
	long	 clipflag;
	register NORM *np=(NORM *)modctrl->NormTop;
	LONG	spritez;
	ULONG	width, height;
  	VERT* 	vp=modctrl->VertTop;                                             

	while(modctrl->PrimLeft)
	{
		op = (TMD_P_TF4A*)(modctrl->PrimTop+((*modctrl->SortPtr)&0xffffff));
		switch (op->cd & (0xff-2))
		{
		case GPU_COM_TG4: /*--------------------------------------------------------------------------------------*/
		   	  	gte_ldsxy3(transformedVertices[OPGT4->v0], transformedVertices[OPGT4->v1], transformedVertices[OPGT4->v2]);		// Load 1st three vertices
				modctrl->SortPtr++;
		
			 	gte_nclip_b();	// takes 8 cycles
				modctrl->PrimLeft--;
				gte_stopz(&clipflag);
		
				if ((!(OPGT4->dummy & 2)) && (clipflag >= 0)){{INCPOLYSCLIPPED;}break;}	// Back face culling
				 
				*(u_long *) (&SIGT4->r0) = *(u_long *) (&OPGT4->r0);		// 6 cycles here
	 			*(u_long *) (&SIGT4->r1) = *(u_long *) (&OPGT4->r1);
				*(u_long *) (&SIGT4->r2) = *(u_long *) (&OPGT4->r2);		// 6 cycles here
	 			*(u_long *) (&SIGT4->r3) = *(u_long *) (&OPGT4->r3);
		  
				gte_stsxy3_gt4(SIGT4);
				*(u_long *)  (&SIGT4->x3) = *(u_long *) (&transformedVertices[OPGT4->v3]);
		  
				SIGT4->code = OPGT4->code | modctrl->semitrans;
		
				*(u_long *)  (&SIGT4->u0) = *(u_long *) (&OPGT4->tu0);		// Texture coords
				*(u_long *)  (&SIGT4->u1) = *(u_long *) (&OPGT4->tu1);
				*(u_long *)  (&SIGT4->u2) = *(u_long *) (&OPGT4->tu2);
				*(u_long *)  (&SIGT4->u3) = *(u_long *) (&OPGT4->tu3);
		
				INCPOLYSDRAWN;
		 		PUTPACKETINTABLE(SIGT4,ot,POLYTG4_LEN);					// Put poly in table
				SIGT4++;
			break;
		case GPU_COM_TG3:   /*-------------------------------------------------------------------------------------------*/
		   		gte_ldsxy3(transformedVertices[OPGT3->v0], transformedVertices[OPGT3->v1], transformedVertices[OPGT3->v2]);		// Load 1st three vertices
				modctrl->SortPtr++;
				gte_nclip_b();	// takes 8 cycles
				modctrl->PrimLeft--;
				gte_stopz(&clipflag);
				
				if ((!(OPGT3->dummy & 2)) && (clipflag >= 0)){{INCPOLYSCLIPPED;}break;}	// Back face culling

	 			*(u_long *) (&SIGT3->r0) = *(u_long *) (&OPGT3->r0);		// 6 cycles here
	 			*(u_long *) (&SIGT3->r1) = *(u_long *) (&OPGT3->r1);
				*(u_long *) (&SIGT3->r2) = *(u_long *) (&OPGT3->r2);

				gte_stsxy3_gt3(SIGT3);

				SIGT3->code = OPGT3->code | modctrl->semitrans;

				*(u_long *)  (&SIGT3->u0) = *(u_long *) (&OPGT3->tu0);		// Texture coords
				*(u_long *)  (&SIGT3->u1) = *(u_long *) (&OPGT3->tu1);
				*(u_long *)  (&SIGT3->u2) = *(u_long *) (&OPGT3->tu2);

				INCPOLYSDRAWN;
		 		PUTPACKETINTABLE(SIGT3,ot,POLYTG3_LEN);					// Put poly in table
				SIGT3++;
	  		break;
		case GPU_COM_TF4:  /*-----------------------------------------------------------------------------------*/
				gte_ldsxy3(transformedVertices[OPFT4->v0], transformedVertices[OPFT4->v1], transformedVertices[OPFT4->v2]);		// Load 1st three vertices
		
				modctrl->SortPtr++;
		
				gte_nclip_b();	// takes 8 cycles
				modctrl->PrimLeft--;
				gte_stopz(&clipflag);

				*(u_long *) (&SIFT4->r0) = *(u_long *) (&OPFT4->r0);	// 9 cycles here
				*(u_long *)  (&SIFT4->u0) = *(u_long *) (&OPFT4->tu0);		// Texture coords
				*(u_long *)  (&SIFT4->u1) = *(u_long *) (&OPFT4->tu1);

				if ((!(OPFT4->dummy & 2)) && (clipflag >= 0)){{INCPOLYSCLIPPED;}break;}	// Back face culling

				gte_stsxy3_ft4(SIFT4);
		 
				SIFT4->code = OPFT4->code | modctrl->semitrans;

				*(u_long *)  (&SIFT4->x3) = *(u_long *) (&transformedVertices[OPFT4->v3]);
				*(u_long *)  (&SIFT4->u2) = *(u_long *) (&OPFT4->tu2);
				*(u_long *)  (&SIFT4->u3) = *(u_long *) (&OPFT4->tu3);
												
				INCPOLYSDRAWN;
		 		PUTPACKETINTABLE(SIFT4,ot,POLYTF4_LEN);					// Put poly in table
				SIFT4++;
		   	break;

		case GPU_COM_TF3: /*-----------------------------------------------------------------------------------*/
				gte_ldsxy3(transformedVertices[OPFT3->v0], transformedVertices[OPFT3->v1], transformedVertices[OPFT3->v2]);		// Load 1st three vertices
		
				modctrl->SortPtr++;
		
				gte_nclip_b();	// takes 8 cycles
				modctrl->PrimLeft--;
			  	gte_stopz(&clipflag);
				if ((!(OPFT3->dummy & 2)) && (clipflag >= 0)){{INCPOLYSCLIPPED;}break;}	// Back face culling

				*(u_long *) (&SIFT3->r0) = *(u_long *) (&OPFT3->r0);	// 9 cycles here
				*(u_long *) (&SIFT3->u0) = *(u_long *) (&OPFT3->tu0);		// Texture coords
				*(u_long *) (&SIFT3->u1) = *(u_long *) (&OPFT3->tu1);

				gte_stsxy3_ft3(SIFT3);
		 
				SIFT3->code = OPFT3->code | modctrl->semitrans;

				*(u_long *)  (&SIFT3->u2) = *(u_long *) (&OPFT3->tu2);
							
				INCPOLYSDRAWN;
		 		PUTPACKETINTABLE(SIFT3,ot,POLYTF3_LEN);					// Put poly in table
				SIFT3++;
			break;

	  		case GPU_COM_G4:   /*-----------------------------------------------------------------------------------*/
				gte_ldsxy3(transformedVertices[OPG4->v0], transformedVertices[OPG4->v1], transformedVertices[OPG4->v2]);		// Load 1st three vertices
		
				modctrl->SortPtr++;
	
				gte_nclip_b();	// takes 8 cycles
				modctrl->PrimLeft--;
				gte_stopz(&clipflag);
		
				if ((!(OPG4->dummy & 2)) && (clipflag >= 0)){{INCPOLYSCLIPPED;}continue;}	// Back face culling

				*(u_long *) (&SIG4->r0) = *(u_long *) (&OPG4->r0);		// 6 cycles here
	 			*(u_long *) (&SIG4->r1) = *(u_long *) (&OPG4->r1);
	 			*(u_long *) (&SIG4->r2) = *(u_long *) (&OPG4->r2);
	 			*(u_long *) (&SIG4->r3) = *(u_long *) (&OPG4->r3);

				gte_stsxy3_g4(SIG4);
			 
				SIG4->code = OPG4->code | modctrl->semitrans;

				*(u_long *)  (&SIG4->x3) = *(u_long *) (&transformedVertices[OPG4->v3]);
		
				INCPOLYSDRAWN;
		 		PUTPACKETINTABLE(SIG4,ot,POLYG4_LEN);					// Put poly in table
				SIG4++;

			break;
		case GPU_COM_G3:  /*-----------------------------------------------------------------------------------*/
				gte_ldsxy3(transformedVertices[OPG3->v0], transformedVertices[OPG3->v1], transformedVertices[OPG3->v2]);		// Load 1st three vertices
		
				modctrl->SortPtr++;
	
				gte_nclip_b();	// takes 8 cycles
				modctrl->PrimLeft--;
				gte_stopz(&clipflag);
		
				if ((!(OPG3->dummy & 2)) && (clipflag >= 0)){{INCPOLYSCLIPPED;}break;}	// Back face culling

				*(u_long *) (&SIG3->r0) = *(u_long *) (&OPG3->r0);	// 9 cycles here
	 			*(u_long *) (&SIG3->r1) = *(u_long *) (&OPG3->r1);
	 			*(u_long *) (&SIG3->r2) = *(u_long *) (&OPG3->r2);

				gte_stsxy3_g3(SIG3);

				SIG3->code = OPG3->code | modctrl->semitrans;
					
				INCPOLYSDRAWN;
		 		PUTPACKETINTABLE(SIG3,ot,POLYG3_LEN);					// Put poly in table
				SIG3++;
	 		break;
	 	case GPU_COM_F4:  /*-----------------------------------------------------------------------------------*/
				gte_ldsxy3(transformedVertices[OPF4->v0], transformedVertices[OPF4->v1], transformedVertices[OPF4->v2]);		// Load 1st three vertices
		
				modctrl->SortPtr++;
				gte_nclip_b();	// takes 8 cycles
				modctrl->PrimLeft--;
				gte_stopz(&clipflag);

				if ((!(OPF4->dummy & 2)) && (clipflag >= 0)){{INCPOLYSCLIPPED;}break;}	// Back face culling

			 	*(u_long *) (&SIF4->r0) = *(u_long *) (&OPF4->r0);	// 6 cycles here
				*(u_long *)  (&SIF4->x3) = *(u_long *) (&transformedVertices[OPF4->v3]);
 	 
				gte_stsxy3_f4(SIF4);
		 
				SIF4->code = OPF4->code | modctrl->semitrans;

				INCPOLYSDRAWN;
		 		PUTPACKETINTABLE(SIF4,ot,POLYF4_LEN);					// Put poly in table
				SIF4++;
	  	 	break;
  	 	case GPU_COM_F3:   /*-----------------------------------------------------------------------------------*/
				gte_ldsxy3(transformedVertices[OPF3->v0], transformedVertices[OPF3->v1], transformedVertices[OPF3->v2]);		// Load 1st three vertices
		
				modctrl->SortPtr++;
				gte_nclip_b();	// takes 8 cycles
		 		modctrl->PrimLeft--;
		 		gte_stopz(&clipflag);
		
				if ((!(OPF3->dummy & 2)) && (clipflag >= 0)){{INCPOLYSCLIPPED;}break;}	// Back face culling

		 		*(u_long *) (&SIF3->r0) = *(u_long *) (&OPF3->r0);	// 7 cycles here
				SIF3->code = OPF3->code | modctrl->semitrans;
 
				gte_stsxy3_f3(SIF3);
		
				INCPOLYSDRAWN;
		 		PUTPACKETINTABLE(SIF3,ot,POLYF3_LEN);					// Put poly in table
				SIF3++;
			break;
		case GPU_COM_TF4SPR: /*-----------------------------------------------------------------------------------*/
				gte_ldv0(&vp[OPFT4S->v0]);									// Load centre point
		
				modctrl->PrimLeft--;
		
				gte_rtps_b();												// Perspective transform

				modctrl->SortPtr++;

				// Fred - This is where we need to know the model's globalscale, so we need to add a pointer to MODELCTRL

				width  = ((int)vp[OPFT4S->v1].vx * modctrl->currentmodel->globalscale.vx) >> 10;	// should be 12, but isn't.
				height = ((int)vp[OPFT4S->v1].vy * modctrl->currentmodel->globalscale.vy) >> 10;

		 		*(u_long *) & SIFT4S->r0 = *(u_long *) & OPFT4S->r0;			// Texture coords / colors
				*(u_long *) & SIFT4S->u0 = *(u_long *) & OPFT4S->tu0;
				*(u_long *) & SIFT4S->u1 = *(u_long *) & OPFT4S->tu1;
				*(u_long *) & SIFT4S->u2 = *(u_long *) & OPFT4S->tu2;
				*(u_long *) & SIFT4S->u3 = *(u_long *) & OPFT4S->tu3;

				gte_stsxy(&SIFT4S->x0);		   
				gte_stsz(&spritez);

				spritez = 1+(spritez>>6);								// Calc poly size
		 	 	width = (LONG)(width*(5))/spritez;
		
				SIFT4S->x1 = SIFT4S->x3=SIFT4S->x0+width;
				SIFT4S->x0 = SIFT4S->x2=SIFT4S->x0-width;
		
		 	 	height = (LONG)(height*(3))/spritez;
		
				SIFT4S->y2 = SIFT4S->y3=SIFT4S->y0-height;
				SIFT4S->y0 = SIFT4S->y1=SIFT4S->y0+height;

				//DB("spritez = %d, width = %d, height = %d\n", spritez, width, height);

				INCPOLYSDRAWN;
				SIFT4S->code=GPU_COM_TF4|modctrl->semitrans;
	
		 		PUTPACKETINTABLE(SIFT4S, ot, POLYTF4_LEN);					// Put poly in table
				SIFT4S++;
		   	break;

		default:
  			modctrl->PrimLeft--;
 			modctrl->SortPtr++;
			break;
		}
	}
	GsOUT_PACKET_P = packet;
}

/**************************************************************************************************/
void polyDrawPrimitivesLite(GsOTA *ot)	//With lighting!
{
#define OPGT4 ((TMD_P_TG4A*)op) 
#define SIGT4 ((POLY_GT4*)packet)
#define OPGT3 ((TMD_P_TG3A*)op) 
#define SIGT3 ((POLY_GT3*)packet)
#define OPFT4 ((TMD_P_TF4A*)op) 
#define SIFT4 ((POLY_FT4*)packet)
#define OPFT3 ((TMD_P_TF3A*)op) 
#define SIFT3 ((POLY_FT3*)packet)
#define OPG4 ((TMD_P_F4G*)op) 
#define SIG4 ((POLY_G4*)packet)
#define OPG3 ((TMD_P_F3G*)op) 
#define SIG3 ((POLY_G3*)packet)
#define OPF4 ((TMD_P_F4*)op) 
#define SIF4 ((POLY_F4*)packet)
#define OPF3 ((TMD_P_F3*)op) 
#define SIF3 ((POLY_F3*)packet)
#define OPFT4S ((TMD_P_TF4A*)op) 
#define SIFT4S ((POLY_FT4*)packet)

	register PACKET*  	packet = GsOUT_PACKET_P;
	register TMD_P_TF4A	*op;
	register MODELCTRL	*modctrl = &modelctrl;
	long	 clipflag;
	register NORM *np=(NORM *)modctrl->NormTop;
	LONG	spritez;
	ULONG	width, height;
  	VERT* 	vp=modctrl->VertTop;                                             

	while(modctrl->PrimLeft)
	{
		op = (TMD_P_TF4A*)(modctrl->PrimTop+((*modctrl->SortPtr)&0xffffff));
		switch (op->cd & (0xff-2))
		{
		case GPU_COM_TG4: /*--------------------------------------------------------------------------------------*/
		   	  	gte_ldsxy3(transformedVertices[OPGT4->v0], transformedVertices[OPGT4->v1], transformedVertices[OPGT4->v2]);		// Load 1st three vertices
				modctrl->SortPtr++;
		
			 	gte_nclip_b();	// takes 8 cycles
				modctrl->PrimLeft--;
				gte_stopz(&clipflag);
		
				if ((!(OPGT4->dummy & 2)) && (clipflag >= 0)){{INCPOLYSCLIPPED;}break;}	// Back face culling
				 
				//lighting
				 	gte_ldrgb3(&OPGT4->r0, &OPGT4->r1, &OPGT4->r2);
				 	gte_ldv3(&np[OPGT4->n0], &np[OPGT4->n1], &np[OPGT4->n2]);
					gte_ncct();			// NormalColorCol3
					gte_strgb3(&SIGT4->r0, &SIGT4->r1, &SIGT4->r2);

					gte_ldv0(&np[OPGT4->n3]);
					gte_ldrgb(&OPGT4->r3);				//rgb register
					gte_nccs();			// NormalColorCol
					gte_strgb(&SIGT4->r3);
		  
				gte_stsxy3_gt4(SIGT4);
				*(u_long *)  (&SIGT4->x3) = *(u_long *) (&transformedVertices[OPGT4->v3]);
		  
				SIGT4->code = OPGT4->code | modctrl->semitrans;
		
				*(u_long *)  (&SIGT4->u0) = *(u_long *) (&OPGT4->tu0);		// Texture coords
				*(u_long *)  (&SIGT4->u1) = *(u_long *) (&OPGT4->tu1);
				*(u_long *)  (&SIGT4->u2) = *(u_long *) (&OPGT4->tu2);
				*(u_long *)  (&SIGT4->u3) = *(u_long *) (&OPGT4->tu3);
		
				INCPOLYSDRAWN;
		 		PUTPACKETINTABLE(SIGT4,ot,POLYTG4_LEN);					// Put poly in table
				SIGT4++;
			break;
		case GPU_COM_TG3:   /*-------------------------------------------------------------------------------------------*/
		   		gte_ldsxy3(transformedVertices[OPGT3->v0], transformedVertices[OPGT3->v1], transformedVertices[OPGT3->v2]);		// Load 1st three vertices
				modctrl->SortPtr++;
				gte_nclip_b();	// takes 8 cycles
				modctrl->PrimLeft--;
				gte_stopz(&clipflag);
				
				if ((!(OPGT3->dummy & 2)) && (clipflag >= 0)){{INCPOLYSCLIPPED;}break;}	// Back face culling

				//lighting
					gte_ldrgb3(&OPGT3->r0, &OPGT3->r1, &OPGT3->r2);
					gte_ldv3(&np[OPGT3->n0], &np[OPGT3->n1], &np[OPGT3->n2]);
					gte_ncct();			// NormalColorCol3
					gte_strgb3(&SIGT3->r0, &SIGT3->r1, &SIGT3->r2);

				gte_stsxy3_gt3(SIGT3);

				SIGT3->code = OPGT3->code | modctrl->semitrans;

				*(u_long *)  (&SIGT3->u0) = *(u_long *) (&OPGT3->tu0);		// Texture coords
				*(u_long *)  (&SIGT3->u1) = *(u_long *) (&OPGT3->tu1);
				*(u_long *)  (&SIGT3->u2) = *(u_long *) (&OPGT3->tu2);

				INCPOLYSDRAWN;
		 		PUTPACKETINTABLE(SIGT3,ot,POLYTG3_LEN);					// Put poly in table
				SIGT3++;
	  		break;
		case GPU_COM_TF4:  /*-----------------------------------------------------------------------------------*/
				gte_ldsxy3(transformedVertices[OPFT4->v0], transformedVertices[OPFT4->v1], transformedVertices[OPFT4->v2]);		// Load 1st three vertices
		
				modctrl->SortPtr++;
		
				gte_nclip_b();	// takes 8 cycles
				modctrl->PrimLeft--;
				gte_stopz(&clipflag);

				*(u_long *) (&SIFT4->r0) = *(u_long *) (&OPFT4->r0);	// 9 cycles here
				*(u_long *)  (&SIFT4->u0) = *(u_long *) (&OPFT4->tu0);		// Texture coords
				*(u_long *)  (&SIFT4->u1) = *(u_long *) (&OPFT4->tu1);

				if ((!(OPFT4->dummy & 2)) && (clipflag >= 0)){{INCPOLYSCLIPPED;}break;}	// Back face culling

				gte_stsxy3_ft4(SIFT4);
		 
				SIFT4->code = OPFT4->code | modctrl->semitrans;

				*(u_long *)  (&SIFT4->x3) = *(u_long *) (&transformedVertices[OPFT4->v3]);
				*(u_long *)  (&SIFT4->u2) = *(u_long *) (&OPFT4->tu2);
				*(u_long *)  (&SIFT4->u3) = *(u_long *) (&OPFT4->tu3);
												
				INCPOLYSDRAWN;
		 		PUTPACKETINTABLE(SIFT4,ot,POLYTF4_LEN);					// Put poly in table
				SIFT4++;
		   	break;

		case GPU_COM_TF3: /*-----------------------------------------------------------------------------------*/
				gte_ldsxy3(transformedVertices[OPFT3->v0], transformedVertices[OPFT3->v1], transformedVertices[OPFT3->v2]);		// Load 1st three vertices
		
				modctrl->SortPtr++;
		
				gte_nclip_b();	// takes 8 cycles
				modctrl->PrimLeft--;
			  	gte_stopz(&clipflag);
				if ((!(OPFT3->dummy & 2)) && (clipflag >= 0)){{INCPOLYSCLIPPED;}break;}	// Back face culling

				*(u_long *) (&SIFT3->r0) = *(u_long *) (&OPFT3->r0);	// 9 cycles here
				*(u_long *) (&SIFT3->u0) = *(u_long *) (&OPFT3->tu0);		// Texture coords
				*(u_long *) (&SIFT3->u1) = *(u_long *) (&OPFT3->tu1);

				gte_stsxy3_ft3(SIFT3);
		 
				SIFT3->code = OPFT3->code | modctrl->semitrans;

				*(u_long *)  (&SIFT3->u2) = *(u_long *) (&OPFT3->tu2);
							
				INCPOLYSDRAWN;
		 		PUTPACKETINTABLE(SIFT3,ot,POLYTF3_LEN);					// Put poly in table
				SIFT3++;
			break;

	  		case GPU_COM_G4:   /*-----------------------------------------------------------------------------------*/
				gte_ldsxy3(transformedVertices[OPG4->v0], transformedVertices[OPG4->v1], transformedVertices[OPG4->v2]);		// Load 1st three vertices
		
				modctrl->SortPtr++;
	
				gte_nclip_b();	// takes 8 cycles
				modctrl->PrimLeft--;
				gte_stopz(&clipflag);
		
				if ((!(OPG4->dummy & 2)) && (clipflag >= 0)){{INCPOLYSCLIPPED;}continue;}	// Back face culling

				//lighting
					gte_ldrgb3(&OPG4->r0, &OPG4->r1, &OPG4->r2);
					gte_ldv3(&np[OPG4->n0], &np[OPG4->n0], &np[OPG4->n0]);
					gte_ncct();			// NormalColorCol3
					gte_strgb3(&SIG4->r0, &SIG4->r1, &SIG4->r2);

					gte_ldrgb(&OPG4->r3);				//rgb register
					gte_ldv0(&np[OPG4->n0]);
					gte_nccs();			// NormalColorCol 
					gte_strgb(&SIG4->r3);

				gte_stsxy3_g4(SIG4);
			 
				SIG4->code = OPG4->code | modctrl->semitrans;

				*(u_long *)  (&SIG4->x3) = *(u_long *) (&transformedVertices[OPG4->v3]);
		
				INCPOLYSDRAWN;
		 		PUTPACKETINTABLE(SIG4,ot,POLYG4_LEN);					// Put poly in table
				SIG4++;

			break;
		case GPU_COM_G3:  /*-----------------------------------------------------------------------------------*/
				gte_ldsxy3(transformedVertices[OPG3->v0], transformedVertices[OPG3->v1], transformedVertices[OPG3->v2]);		// Load 1st three vertices
		
				modctrl->SortPtr++;
	
				gte_nclip_b();	// takes 8 cycles
				modctrl->PrimLeft--;
				gte_stopz(&clipflag);
		
				if ((!(OPG3->dummy & 2)) && (clipflag >= 0)){{INCPOLYSCLIPPED;}break;}	// Back face culling

				//lighting
					gte_ldrgb3(&OPG3->r0, &OPG3->r1, &OPG3->r2);
					gte_ldv3(&np[OPG3->n0], &np[OPG3->n0], &np[OPG3->n0]);
					gte_ncct();			// NormalColorCol3
					gte_strgb3(&SIG3->r0, &SIG3->r1, &SIG3->r2);

				gte_stsxy3_g3(SIG3);

				SIG3->code = OPG3->code | modctrl->semitrans;
					
				INCPOLYSDRAWN;
		 		PUTPACKETINTABLE(SIG3,ot,POLYG3_LEN);					// Put poly in table
				SIG3++;
	 		break;
	 	case GPU_COM_F4:  /*-----------------------------------------------------------------------------------*/
				gte_ldsxy3(transformedVertices[OPF4->v0], transformedVertices[OPF4->v1], transformedVertices[OPF4->v2]);		// Load 1st three vertices
		
				modctrl->SortPtr++;
				gte_nclip_b();	// takes 8 cycles
				modctrl->PrimLeft--;
				gte_stopz(&clipflag);

				if ((!(OPF4->dummy & 2)) && (clipflag >= 0)){{INCPOLYSCLIPPED;}break;}	// Back face culling

			 	*(u_long *) (&SIF4->r0) = *(u_long *) (&OPF4->r0);	// 6 cycles here
				*(u_long *)  (&SIF4->x3) = *(u_long *) (&transformedVertices[OPF4->v3]);
 	 
				gte_stsxy3_f4(SIF4);
		 
				SIF4->code = OPF4->code | modctrl->semitrans;

				INCPOLYSDRAWN;
		 		PUTPACKETINTABLE(SIF4,ot,POLYF4_LEN);					// Put poly in table
				SIF4++;
	  	 	break;
  	 	case GPU_COM_F3:   /*-----------------------------------------------------------------------------------*/
				gte_ldsxy3(transformedVertices[OPF3->v0], transformedVertices[OPF3->v1], transformedVertices[OPF3->v2]);		// Load 1st three vertices
		
				modctrl->SortPtr++;
				gte_nclip_b();	// takes 8 cycles
		 		modctrl->PrimLeft--;
		 		gte_stopz(&clipflag);
		
				if ((!(OPF3->dummy & 2)) && (clipflag >= 0)){{INCPOLYSCLIPPED;}break;}	// Back face culling

		 		*(u_long *) (&SIF3->r0) = *(u_long *) (&OPF3->r0);	// 7 cycles here
				SIF3->code = OPF3->code | modctrl->semitrans;
 
				gte_stsxy3_f3(SIF3);
		
				INCPOLYSDRAWN;
		 		PUTPACKETINTABLE(SIF3,ot,POLYF3_LEN);					// Put poly in table
				SIF3++;
			break;
		case GPU_COM_TF4SPR: /*-----------------------------------------------------------------------------------*/
				gte_ldv0(&vp[OPFT4S->v0]);									// Load centre point
		
				modctrl->PrimLeft--;
		
				gte_rtps_b();												// Perspective transform

				modctrl->SortPtr++;

				// Fred - This is where we need to know the model's globalscale, so we need to add a pointer to MODELCTRL

				width  = ((int)vp[OPFT4S->v1].vx * modctrl->currentmodel->globalscale.vx) >> 10;	// should be 12, but isn't.
				height = ((int)vp[OPFT4S->v1].vy * modctrl->currentmodel->globalscale.vy) >> 10;

		 		*(u_long *) & SIFT4S->r0 = *(u_long *) & OPFT4S->r0;			// Texture coords / colors
				*(u_long *) & SIFT4S->u0 = *(u_long *) & OPFT4S->tu0;
				*(u_long *) & SIFT4S->u1 = *(u_long *) & OPFT4S->tu1;
				*(u_long *) & SIFT4S->u2 = *(u_long *) & OPFT4S->tu2;
				*(u_long *) & SIFT4S->u3 = *(u_long *) & OPFT4S->tu3;

				gte_stsxy(&SIFT4S->x0);		   
				gte_stsz(&spritez);

				spritez = 1+(spritez>>6);								// Calc poly size
		 	 	width = (LONG)(width*(5))/spritez;
		
				SIFT4S->x1 = SIFT4S->x3=SIFT4S->x0+width;
				SIFT4S->x0 = SIFT4S->x2=SIFT4S->x0-width;
		
		 	 	height = (LONG)(height*(3))/spritez;
		
				SIFT4S->y2 = SIFT4S->y3=SIFT4S->y0-height;
				SIFT4S->y0 = SIFT4S->y1=SIFT4S->y0+height;

				//DB("spritez = %d, width = %d, height = %d\n", spritez, width, height);

				INCPOLYSDRAWN;
				SIFT4S->code=GPU_COM_TF4|modctrl->semitrans;
	
		 		PUTPACKETINTABLE(SIFT4S, ot, POLYTF4_LEN);					// Put poly in table
				SIFT4S++;
		   	break;

		default:
  			modctrl->PrimLeft--;
 			modctrl->SortPtr++;
			break;
		}
	}
	GsOUT_PACKET_P = packet;
}

/**************************************************************************************************/

void DrawBoxOutline(long x,long y,long w,long h,UBYTE r,UBYTE g, UBYTE b,UBYTE thickness,UBYTE pri)
{
	DrawBox(x,y,w,thickness,r,g,b,0,pri);
	DrawBox(x,y+h-thickness,w,thickness,r,g,b,0,pri);
	DrawBox(x+w-thickness,y,thickness,h,r,g,b,0,pri);
	DrawBox(x,y,thickness,h,r,g,b,0,pri);

}

void
DrawBox(SHORT x,SHORT y,SHORT w,SHORT h,UBYTE r,UBYTE g,UBYTE b,UBYTE semi,SHORT pri)
{

	POLY_F4 *si = (POLY_F4 *) GsOUT_PACKET_P; 
	GsOTA 	*otptr;
 
	//CurrentPolyList->polycnt--;
	if (TOOMANYPOLYS(5*MAXPACKETSIZE,"DrawBox"))
		return;
	if(w<=0 || h <= 0)
		return;

	otptr=(GsOTA*)(PolyList->org+((pri &MAXDEPTH)>>PolyList->shift));
	si->r0=r;
	si->g0=g;
	si->b0=b;
	if (semi>0)
		si->code=GPU_COM_F4+2;
	else		
		si->code=GPU_COM_F4;

	si->x0=si->x2=x;
	si->x1=si->x3=x+w;
	si->y0=si->y1=y;
	si->y2=si->y3=y+h;
 	PUTPACKETINTABLE(si,otptr,POLYF4_LEN);
	GsOUT_PACKET_P+=sizeof(POLY_F4);
	si++;

	if(semi)
	{
		DR_TPAGE *si = (DR_TPAGE *) GsOUT_PACKET_P;
		setDrawTPage(si,1,1,((semi-1)<<5));	// macro

		PUTPACKETINTABLE(si,otptr,DRTPAGE_LEN);
		GsOUT_PACKET_P+=sizeof(DR_TPAGE);
	}
}

void
Get_Screenxy(VERT *v0,LONG *xy){
 	gte_ldv0(v0);		//load vector
 	gte_rtps();        	//RotTransPers1
	gte_stsxy(xy);	 	//store
}
/***********************************************************************************************/
LONG Find_Screen_Depth(VERT *v0){
LONG zdepth;
		gte_ldv0(v0);			//load (x,y,z) coord
		gte_rtps();				//MACRO	// RotTransPers 
		gte_stszotz(&zdepth);		//store Z
return zdepth;
}

