#include "main.h"
#include <string.h>

#include <islpsi.h>
#include <psitypes.h>

#include "bff_load.h"
#include "map_draw.h"
#include "maths.h"
#include "debris.h"

UBYTE			globalPause =0;

#define GETX(n)( ((SHORTXY *)( (int)(tfv) +(n) ))->x )
#define GETY(n)( ((SHORTXY *)( (int)(tfv) +(n) ))->y )
#define GETV(n)(  *(u_long *)( (int)(tfv) +(n) ) )
#define GETD(n)(  *(u_long *)( (int)(tfd) +(n) ) )

#define GETN(n)( ((VERT *)( (int)(tfn) +(n<<1) )) )
#define GETN2(n)( ((VERT *)( (int)(tfn) +(n) )) )



#define MIN_MAP_DEPTH 10



#define MAX_MAPOBJECT_DIMENSION 1050
// This ends up being somewhere around the 700->800 mark
#define MAX_MAP_DEPTH_UPPER_LIMIT (( 32768 - MAX_MAPOBJECT_DIMENSION * 8) >> 5)

#define MAX_MAP_DEPTH max_map_ot_depth
#define MAX_MAP_DEPTH_CLIPCHECK 1023




UBYTE loadedInventory;
SHORT invFirstTex;
SHORT invLastTex;
int	  depthBump;
UBYTE globalDeathOn;

float preGsh1;
float preGsh2;

enum{
	INV_NONE,
	INV_ACT1,
	INV_ACT2,
	INV_ACT4,
	INV_FIRST,
};


void emptyInit()
{
	depthBump	  = 0;
	globalDeathOn = 0;
}

void zpCheck(char *str)
{
}

int MoveImage(RECT *rect, int x, int y)
{
}

void memoryShowStats()
{
}
 
void memoryShow()
{
}

void main_EnsureOverlay(int empty)
{
}
 
int emptyPrintf(char* format, ...)
{
}

void fontSetPrintDepth(int depth)
{
}

void dcOverlayCallback()
{

}

void dcSetVertexBuffer()
{
	memcpy(dwDataPtr, tmpVertexBuffer, 2*1024*1024);
}

void dcGrabVertexBuffer()
{
	memcpy(tmpVertexBuffer, dwDataPtr, 2*1024*1024);
}
				 

void dcSetInventory(char *level)
{
	UBYTE newInv;
	int i;

	invFirstTex = originalTexCount;

	if(strcmp(level,"none")==0)//this called to initialise it
	{
		newInv=INV_FIRST;
		loadedInventory=INV_NONE;
	}
	else
	if(strcmp(level,"A1_DOGCHASE")==0 ||
	   strcmp(level,"A2_CATAPULT")==0 ||
	   strcmp(level,"A2_SEESAW")==0	  ||
	   strcmp(level,"A2_FIREWORKS")==0)
	{
		newInv=INV_NONE;
	}
	else
	if(strncmp(level,"A1_",3)==0)
	{
		newInv=INV_ACT1;
	}
	else
	if(strncmp(level,"A2_",3)==0)
	{
		newInv=INV_ACT2;
	}

	else
	if(strncmp(level,"A3_",3)==0)
	{
		newInv=INV_ACT4;
	}

	if(newInv==loadedInventory && newInv!=INV_FIRST)return;

	//empty old inventory
	if(loadedInventory!=INV_NONE)
	{
		for(i=invFirstTex; i<DCKnumTextures; i++)
		{
			kmFreeTexture(DCKtextureList[i].surfacePtr);
		}
		DCKnumTextures=invFirstTex;
	}

	invFirstTex=DCKnumTextures;

	if(newInv==INV_NONE)
	{
	}
	else
	if(newInv==INV_ACT1)
	{
		textureLoadBank("INVENTORY\\INVENT1.SPT");
	}
	if(newInv==INV_ACT2)
	{
		textureLoadBank("INVENTORY\\INVENT2.SPT");
	}
	if(newInv==INV_ACT4)
	{
		textureLoadBank("INVENTORY\\INVENT4.SPT");
	}

	loadedInventory = newInv;
	originalTexCount = DCKnumTextures;
}

int cardFormat()
{
}

void dcCleanTexStream()
{
	int i;

	for(i=afterRoomTexCount; i<DCKnumTextures; i++)
	{
		kmFreeTexture(DCKtextureList[i].surfacePtr);
	}
	DCKnumTextures=afterRoomTexCount;
}

void transformVertexListA_ZeroCam(long *p)
{
int i;
VERT tmp, *verts;
long *tfv, *tfd;

	verts	= (VERT *) p[0];		// Pointer to the source vertices
	i		= p[1];					// The number of verts to be transformed
	tfv		= (long*) p[2];			// Pointer to the transformedVerts array
	tfd		= (long*) p[3];			// Pointer to the transformedDepths array

	while(i--)
	{
		tmp.vx		= verts->vx + p[4];		// Adjust for the mesh instance-camera position
		tmp.vy		= verts->vy + p[5];		//
		tmp.vz		= verts->vz + p[6];		//
		verts++;

		gte_ldv0((&tmp));					// Load the vert into the gte

		gte_rtps();							// Do transform and projection
		gte_stsxy(tfv);						// Store the screen xy in tfv list
		tfv++;								//
		gte_stsz(tfd);						// Store the Z depth in the tfd list
		tfd++;								//
	} 
} 

//mainly for dog, so we can sort infront on deth fade
void direct2PsiDrawFlattenedPrimitivesDC(PSIMODEL *model, long *tfv,long *tfd)
{
	PACKET*		packet ;//= currentDisplayPage->primPtr;
	long clipflag,count=0,i;
	register D2M_TMD_P_GT4I	*opcd;
	register long			t1;
	register long			t2;
	VERT 					*tfn = transformedNormals;
	UBYTE					done=0;

	int primsleft;
	DIRECT2MESH *d2m;

	d2m = (DIRECT2MESH *)(&model->pad[0]);

// ------ Gouraud Textured Tris -------
// Keep optimal, coz ginger and the dogs are "all gt3"
#define si ((POLY_GT3*)packet)
#define op ((D2M_TMD_P_GT3I*)opcd)
	op = d2m->gt3s;
	for(primsleft = d2m->n_gt3s; primsleft != 0; primsleft--, op++)
	{
		gte_ldsxy3(GETV(op->v0), GETV(op->v1), GETV(op->v2));		// Load 1st three vertices
		gte_nclip();
		gte_stopz(&clipflag);
			
		if ((clipflag < 0))
		{
			gte_ldsz3(GETD(op->v0),GETD(op->v1),GETD(op->v2));

			BEGINPRIM(si, POLY_GT3);

			t1 = *(u_long *) (&op->tu0);
			gte_stsxy3_gt3(si);	// 3 swc2's
			t2 = *(u_long *) (&op->tu1);
			gte_ldv3(GETN2(op->n0), GETN2(op->n1), GETN2(op->n2));

			*(u_long *)  (&si->u0) = t1;
			*(u_long *)  (&si->u1) = t2;

			gte_nct();

			t1 = *(u_long *) (&op->tu2);
			*(u_long *)  (&si->u2) = t1;

			gte_strgb3(&si->r0, &si->r1, &si->r2);

			si->tag=SEMITRANS_NONE;
			if(si->code&2)
			{
  				si->tag=SEMITRANS_ADD;
			}
			si->code  = GPU_COM_TG3;

			si->tpage = op->tpage;
			//not a bad approximation
//		 	ENDPRIMA(si,GETD(op->v0)/1700,GETD(op->v2)/1700,GETD(op->v1)/1700,0,POLY_GT3);
			if(globalDeathOn)globalDeathOn++;//so we can spot the polys !not! to push back
			ENDPRIMA(si,GETD(op->v0),GETD(op->v2),GETD(op->v1),0,POLY_GT3);
			if(globalDeathOn)globalDeathOn--;
		}
	}
			  
#undef op
#undef si
}


//chickens+dogs+etc...
void direct2PsiDrawInsertionPrimitivesDC(PSIMODEL *model, long *tfv,long *tfd)
{
	PACKET*		packet ;//= currentDisplayPage->primPtr;
	long clipflag;
	register D2M_TMD_P_GT4I	*opcd;
	register long			t1;
	register long			t2;
	VERT 					*tfn = transformedNormals;

	static int bump=-400;

	int primsleft;
	DIRECT2MESH *d2m;

	d2m = (DIRECT2MESH *)(&model->pad[0]);

// ------ Gouraud Textured Tris -------
// Keep optimal, coz ginger and the dogs are "all gt3"
#define si ((POLY_GT3*)packet)
#define op ((D2M_TMD_P_GT3I*)opcd)
	op = d2m->gt3s;
	for(primsleft = d2m->n_gt3s; primsleft != 0; primsleft--, op++)
	{
		gte_ldsxy3(GETV(op->v0), GETV(op->v1), GETV(op->v2));		// Load 1st three vertices
		gte_nclip();
		gte_stopz(&clipflag);
			
		if ((clipflag < 0))
		{
			gte_ldsz3(GETD(op->v0),GETD(op->v1),GETD(op->v2));

			BEGINPRIM(si, POLY_GT3);

			t1 = *(u_long *) (&op->tu0);
			gte_stsxy3_gt3(si);	// 3 swc2's
			t2 = *(u_long *) (&op->tu1);
			gte_ldv3(GETN2(op->n0), GETN2(op->n1), GETN2(op->n2));

			*(u_long *)  (&si->u0) = t1;
			*(u_long *)  (&si->u1) = t2;

			gte_nct();

			t1 = *(u_long *) (&op->tu2);
			*(u_long *)  (&si->u2) = t1;

			gte_strgb3(&si->r0, &si->r1, &si->r2);

			si->tag=SEMITRANS_NONE;
			if(si->code&2)
			{
  				si->tag=SEMITRANS_ADD;
			}
			si->code  = GPU_COM_TG3;

			si->tpage = op->tpage;

			ENDPRIMA(si,GETD(op->v0)+bump,GETD(op->v2)+bump,GETD(op->v1)+bump,0,POLY_GT3);
		}
	}
			  
#undef op
#undef si

// ------ Gouraud Textured Quads -------
// (I've not checked the optimisation of this one so thoroughly - FW)

#define si ((POLY_GT4*)packet)
#define op opcd
	op = d2m->gt4s;
	for(primsleft = d2m->n_gt4s; primsleft != 0; primsleft--, op++)
	{
		gte_ldsxy3(GETV(op->v0), GETV(op->v1), GETV(op->v2));		// Load 1st three vertices

		gte_nclip();	// takes 8 cycles
		gte_stopz(&clipflag);
				
		if ((clipflag < 0))
		{
			gte_ldsz4(GETD(op->v0),GETD(op->v1),GETD(op->v2),GETD(op->v3));
			BEGINPRIM(si, POLY_GT4);

			t1 = *(u_long *) (&op->tu0);
			t2 = *(u_long *) (&op->tu1);
			*(u_long *)  (&si->u0) = t1;
			*(u_long *)  (&si->u1) = t2;
				
			gte_stsxy3_gt4(si);

			t1 = *(u_long *) (&op->tu2);
			t2 = *(u_long *) (&op->tu3);
			gte_ldv3(GETN2(op->n0), GETN2(op->n1), GETN2(op->n2));
			*(u_long *)  (&si->u2) = t1;
			*(u_long *)  (&si->u3) = t2;
									
			t1 = *(u_long *) (&GETV(op->v3));
//					gte_nct();
			gte_nct_b();			
			gte_strgb3(&si->r0, &si->r1, &si->r2);
			*(u_long *)  (&si->x3) = t1;

			gte_ldv0(GETN2(op->n3));
			gte_ncs();			// NormalColorCol

			gte_strgb(&si->r3);
			//si->code = GPU_COM_TG4;	//op->cd;
			si->tag=SEMITRANS_NONE;
			if(si->code&2)
			{
  				si->tag=SEMITRANS_ADD;
			}
			si->code  = GPU_COM_TG4;

			si->tpage=op->tpage;
			ENDPRIMA(si,GETD(op->v0),GETD(op->v2),GETD(op->v1),GETD(op->v3),POLY_GT4);
		}
	}
#undef op
#undef si

}

//scenics
void direct2PsiDrawInsertionPrimitivesPrelitDepthCheckDC(PSIMODEL *model, long *tfv,long *tfd)
{
	PACKET*					packet;
	long clipflag;
	long deep=10;//MIKEY = tmp value;
	register D2M_TMD_P_GT4I	*opcd;

	register long			t1;
	register long			t2;
	VERT 					*tfn = transformedNormals;

	int primsleft;
	DIRECT2MESH *d2m;

	d2m = (DIRECT2MESH *)(&model->pad[0]);


// ------ Gouraud Textured Tris -------
// Keep optimal, coz ginger and the dogs are "all gt3"
#define si ((POLY_GT3*)packet)
#define op ((D2M_TMD_P_GT3I*)opcd)
			  
	op = d2m->gt3s;
	for(primsleft = d2m->n_gt3s; primsleft != 0; primsleft--, op++)
	{
		gte_ldsxy3(GETV(op->v0), GETV(op->v1), GETV(op->v2));		// Load 1st three vertices

		gte_nclip();	// takes 8 cycles

		gte_stopz(&clipflag);
  		if ((clipflag < 0))
		{
			BEGINPRIM(si,POLY_GT3);
			t1 = *(u_long *) (&op->tu0);
			gte_stsxy3_gt3(si);	// 3 swc2's
			t2 = *(u_long *) (&op->tu1);
			*(u_long *)  (&si->u0) = t1;
			*(u_long *)  (&si->u1) = t2;

			t1 = *(u_long *) (&op->r0);
			t2 = *(u_long *) (&op->r1);
			*(u_long *)  (&si->r0) = t1;
			*(u_long *)  (&si->r1) = t2;

			t1 = *(u_long *) (&op->tu2);
			t2 = *(u_long *) (&op->r2);
			*(u_long *)  (&si->u2) = t1;
			*(u_long *)  (&si->r2) = t2;


			si->tag=SEMITRANS_NONE;
			if(si->code&2)
			{
  				si->tag=SEMITRANS_ADD;
			}
			si->code  = GPU_COM_TG3;

			si->tpage = op->tpage;
			ENDPRIMA(si,GETD(op->v0),GETD(op->v2),GETD(op->v1),0,POLY_GT3);
		}
	}
		
#undef op
#undef si

// ------ Gouraud Textured Quads -------
// (I've not checked the optimisation of this one so thoroughly - FW)

#define si ((POLY_GT4*)packet)
#define op opcd
	op = d2m->gt4s;
	for(primsleft = d2m->n_gt4s; primsleft != 0; primsleft--, op++)
	{
		gte_ldsxy3(GETV(op->v0), GETV(op->v1), GETV(op->v2));		// Load 1st three vertices

		gte_nclip();	// takes 8 cycles

		gte_stopz(&clipflag);
		if ((clipflag < 0))
		{
			BEGINPRIM(si,POLY_GT4);

			t1 = *(u_long *) (&op->tu0);
			t2 = *(u_long *) (&op->tu1);
			*(u_long *)  (&si->u0) = t1;
			*(u_long *)  (&si->u1) = t2;

			t1 = *(u_long *) (&op->r0);
			t2 = *(u_long *) (&op->r1);
			*(u_long *)  (&si->r0) = t1;
			*(u_long *)  (&si->r1) = t2;

			t1 = *(u_long *) (&op->r2);
			t2 = *(u_long *) (&op->r3);
			*(u_long *)  (&si->r2) = t1;
			*(u_long *)  (&si->r3) = t2;

			gte_stsxy3_gt4(si);

			t1 = *(u_long *) (&op->tu2);
			t2 = *(u_long *) (&op->tu3);
			*(u_long *)  (&si->u2) = t1;
			*(u_long *)  (&si->u3) = t2;
									
			t1 = *(u_long *) (&GETV(op->v3));
			*(u_long *)  (&si->x3) = t1;

			si->tag=SEMITRANS_NONE;
			if(si->code&2)
			{
  				si->tag=SEMITRANS_ADD;
			}
			si->code  = GPU_COM_TG4;

			si->tpage = op->tpage;
			ENDPRIMA(si,GETD(op->v0),GETD(op->v2),GETD(op->v1),GETD(op->v3),POLY_GT4);
		}
	}
#undef op
#undef si
}

void direct2PsiFixupPrimsDC(PSIMODEL *psiModel)
{
	TextureType *sprt;
	int p,a,tp;
	char *primitive;
	UBYTE s;

	//int ix; //temp

	DIRECT2MESH *d2m;

	d2m = (DIRECT2MESH *)(&psiModel->pad[0]);

// Gouraud Textured Tris
	for(p = 0; p < d2m->n_gt3s; p++)
	{
		sprt = PageTexture( d2m->gt3s[p].clut ); 
		tp = sprt->tpage;


		d2m->gt3s[p].code = GPU_COM_TG3;
		if (d2m->gt3s[p].tpage) 
		{
			d2m->gt3s[p].cd |= 2;
			d2m->gt3s[p].code |= 2;
		}
		d2m->gt3s[p].tpage =tp;//MIKEY|= sprt->tpage;
		d2m->gt3s[p].clut = 0;//MIKEYsprt->clut;

		d2m->gt3s[p].in=(sizeof(D2M_TMD_P_GT3I)/4)-1;	//ilen
		d2m->gt3s[p].out=0x9; 						//olen   

		d2m->gt3s[p].v0 *= 4;	// Hmmm. This lot should be at the PC end
		d2m->gt3s[p].v1 *= 4;
		d2m->gt3s[p].v2 *= 4;

		d2m->gt3s[p].n0 = d2m->gt3s[p].v0 * 2;
		d2m->gt3s[p].n1 = d2m->gt3s[p].v1 * 2;
		d2m->gt3s[p].n2 = d2m->gt3s[p].v2 * 2;



	}
// Gouraud Textured Quads
	for(p = 0; p < d2m->n_gt4s; p++)
	{

		sprt = PageTexture( d2m->gt4s[p].clut ); // clut= texture index number
		tp = sprt->tpage;//tp = (u_short)FindTextureN((char*)&currentTextureList[d2m->gt3s[p].clut]);
		
		d2m->gt4s[p].code = GPU_COM_TG4;

		if (d2m->gt4s[p].tpage) 
		{
			d2m->gt4s[p].cd |= 2;
			d2m->gt4s[p].code |= 2;
		}

		d2m->gt4s[p].tpage =tp;//MIKEY|= sprt->tpage;
		d2m->gt4s[p].clut = 0;//MIKEYsprt->clut;

		d2m->gt4s[p].in=(sizeof(D2M_TMD_P_GT4I)/4)-1;	//ilen
		d2m->gt4s[p].out=0xc; 						//olen   

		d2m->gt4s[p].v0 *= 4;
		d2m->gt4s[p].v1 *= 4;
		d2m->gt4s[p].v2 *= 4;
		d2m->gt4s[p].v3 *= 4;

		d2m->gt4s[p].n0 = d2m->gt4s[p].v0 * 2;
		d2m->gt4s[p].n1 = d2m->gt4s[p].v1 * 2;
		d2m->gt4s[p].n2 = d2m->gt4s[p].v2 * 2;
		d2m->gt4s[p].n3 = d2m->gt4s[p].v3 * 2;
	}					
}

void MapDraw_DrawFMA_Mesh3DC(WORLD_MESH_INSTANCE *instance, int depthscaler)
{
	u_long t1;	// I've re-jigged the code, so "depth" is re-usable, & shares register with t1
	u_long t2;


	PACKET * packet;
	char *opcd;
	long *tfv;
	long *tfd;

	FMA_MESH_HEADER *mesh = instance->mesh;
	int h,w;
	TextureType *tex;

// These macris are for an optimisation that requires all our vertex numbers to be multiplied by four,
// which means they're byte offsets into the tfv/tfd table rather than int-array indices
// Essentially
// tfv[n] and tfd[n], where tfv/tfd are arrays of ints, have now been replaced by these macros,
// where "n" is pre-shifted at PC map-compile time. Thus saving a shift instruction per vertex per polygon.
//#define GETX(n)( ((SHORTXY *)( (int)(tfv) +(n) ))->x )
//#define GETY(n)( ((SHORTXY *)( (int)(tfv) +(n) ))->y )
//#define GETV(n)(  *(u_long *)( (int)(tfv) +(n) ) )
//#define GETD(n)(  *(u_long *)( (int)(tfd) +(n) ) )

// "depth" is forced to be a CPU register so we can use the fast gte macro
// (Also note, it's shared with a temporary variable "t1")
	long clipflag;
	long depth;
	int i;

	int min_depth = MIN_MAP_DEPTH - instance->sort_depth;
	int max_depth = MAX_MAP_DEPTH - instance->sort_depth;
	if(min_depth < 1)//200)//was 1
	{
		min_depth = 1;//200;//was 1
	}

	if(max_depth > 1024-instance->sort_depth)
		max_depth = 1024-instance->sort_depth;


	tfv = transformedVertices;
	tfd = transformedDepths;
						  
	{
		long p[9];
		p[0] = (int)mesh->verts;	// 0
		p[1] = mesh->n_verts;		// 4
		p[2] = (int)tfv;			// 8
		p[3] = (int)tfd;			// 12
		p[4] = instance->posx - mycamera.vpx;	// 16
		p[5] = instance->posy - mycamera.vpy;	// 20
		p[6] = instance->posz - mycamera.vpz;	// 24
		transformVertexListA_ZeroCam(&p[0]);
	}						
//  	if(depthscaler)
//	{
  	for(i = 0; i < mesh->n_verts; i++)
  	   	tfd[i] = tfd[i] +=depthBump;//>> depthscaler;
//	}

// The MapDraw stores a count+list of quads and one of tris,
// rather than checking a "type" element for every polygon.
// (coz it only has those two types. No transparent. No double sided. No nothing)

#define si ((POLY_GT4*)packet)
#define op ((FMA_GT4 *)opcd)

	op = mesh->gt4s;

	for(i = mesh->n_gt4s; i != 0; i--,op++)
	{
		gte_ldsz4(GETD(op->vert0),GETD(op->vert1),GETD(op->vert2),GETD(op->vert3));
   		gte_avsz4();
		gte_stotz(&depth);
		if(depth > min_depth)// && depth < max_depth)
		{
// Load 1st three vertices for a backface cull check
// (Yes, this check is better when placed after the offscreen one - Checked on PA)
			gte_ldsxy3(GETV(op->vert0), GETV(op->vert1), GETV(op->vert2));
			gte_nclip();
			gte_stopz(&clipflag);

			if (clipflag<0)
			{
			 	BEGINPRIM(si,POLY_GT4);

				t1 = *(u_long *) (&op->u0);
				t2 = *(u_long *) (&op->u1);
				*(u_long *)  (&si->u0) = t1;
				*(u_long *)  (&si->u1) = t2;
				gte_stsxy3_gt4(si);	// The first 3 x's & y's are already in the gte, so we may as well use 'em
				t1 = *(u_long *) (&op->u2);
				t2 = *(u_long *) (&op->u3);
				*(u_long *)  (&si->u2) = t1;
				*(u_long *)  (&si->u3) = t2;
				*(u_long *)  (&si->x3) = *(u_long *) (&GETV(op->vert3));
				t1 = *(u_long *) (&op->r0);
				t2 = *(u_long *) (&op->r1);
				*(u_long *)  (&si->r0) = t1;
				*(u_long *)  (&si->r1) = t2;
				t1 = *(u_long *) (&op->r2);
				t2 = *(u_long *) (&op->r3);
				*(u_long *)  (&si->r2) = t1;
				*(u_long *)  (&si->r3) = t2;

				if(si->x0<0 && si->x1<0 && si->x2<0 && si->x3<0)continue;
				if(si->y0<0 && si->y1<0 && si->y2<0 && si->y3<0)continue;
				if(si->x0>640 && si->x1>640 && si->x2>640 && si->x3>640)continue;
				if(si->y0>480 && si->y1>480 && si->y2>480 && si->y3>480)continue;

  				si->tag=SEMITRANS_NONE;
				if(si->code&2)
				{
	  				si->tag=SEMITRANS_ADD;
				}
				si->code=GPU_COM_TG4;
							
				ENDPRIMA(si,GETD(op->vert0),GETD(op->vert2),GETD(op->vert1),GETD(op->vert3), POLY_GT4);
			}
		}
	}

#undef si
#undef op

// That's the quads done, now let's do the triangles...

#define si ((POLY_GT3*)packet)
#define op ((FMA_GT3 *)opcd)
	   					 
	op = mesh->gt3s;
	for(i = mesh->n_gt3s; i != 0; i--,op++)
	{
// Get average Z of the polygon & use as a depth pointer
		gte_ldsz3(GETD(op->vert0),GETD(op->vert1),GETD(op->vert2));
   		gte_avsz3();
		gte_stotz(&depth);

  //		if(depth > min_depth && depth < max_depth)
		if(depth > min_depth)// && depth < max_depth)
		{
// Load 1st three vertices for a backface cull
			gte_ldsxy3(GETV(op->vert0), GETV(op->vert1), GETV(op->vert2));
			gte_nclip();
			gte_stopz(&clipflag);
			if(clipflag < 0)
			{
				BEGINPRIM(si,POLY_GT3);
				t1 = *(u_long *) (&op->u0);
				t2 = *(u_long *) (&op->u1);
				*(u_long *)  (&si->u0) = t1;
				*(u_long *)  (&si->u1) = t2;
				gte_stsxy3_gt3(si);
				t1 = *(u_long *) (&op->u2);
				t2 = *(u_long *) (&op->r0);
				*(u_long *)  (&si->u2) = t1;
				*(u_long *)  (&si->r0) = t2;
				t1 = *(u_long *) (&op->r1);
				t2 = *(u_long *) (&op->r2);
				*(u_long *)  (&si->r1) = t1;
				*(u_long *)  (&si->r2) = t2;

				if(si->x0<0 && si->x1<0 && si->x2<0)continue;
				if(si->y0<0 && si->y1<0 && si->y2<0)continue;
				if(si->x0>640 && si->x1>640 && si->x2>640)continue;
				if(si->y0>480 && si->y1>480 && si->y2>480)continue;
						
  				si->tag=SEMITRANS_NONE;
				if(si->code&2)
				{
	  				si->tag=SEMITRANS_ADD;
				}
				si->code  = GPU_COM_TG3;
				ENDPRIMA(si,GETD(op->vert0),GETD(op->vert2),GETD(op->vert1),0, POLY_GT3);
			}
		}
	}
	   					   
#undef si
#undef op

// New & improved landscape models can now have built-in skies...

#define si ((POLY_G4*)packet)
#define op ((FMA_G4 *)opcd)
		   			   
	op = mesh->g4s;

	for(i = mesh->n_g4s; i != 0; i--,op++)
	{
		gte_ldsz4(GETD(op->vert0),GETD(op->vert1),GETD(op->vert2),GETD(op->vert3));
   		gte_avsz4();
		gte_stotz(&depth);

 //		if(depth > min_depth && depth < max_depth)
		if(depth > min_depth)// && depth < max_depth)
		{
	// For sky models, backface cull is still necessary.
	// (coz of polys behind you)
	// depth is always right at the back

			gte_ldsxy3(GETV(op->vert0), GETV(op->vert1), GETV(op->vert2));

			gte_nclip();
			gte_stopz(&clipflag);
			if (clipflag<0)
			{
		// Put the polygon into the OT (Note that we re-use "depth" as one of the "t" variables)
  				BEGINPRIM(si,POLY_G4);
				// Copy the polygon data over into the OT

				t1 = *(u_long *) (&op->r0);
				t2 = *(u_long *) (&op->r1);
				*(u_long *)  (&si->r0) = t1;
				*(u_long *)  (&si->r1) = t2;
				gte_stsxy3_g4(si);	// The first 3 x's & y's are already in the gte, so we may as well use 'em
				t1 = *(u_long *) (&op->r2);
				t2 = *(u_long *) (&op->r3);
				*(u_long *)  (&si->r2) = t1;
				*(u_long *)  (&si->r3) = t2;
				*(u_long *)  (&si->x3) = *(u_long *) (&GETV(op->vert3));
					  
	  			si->tag=SEMITRANS_NONE;
				if(si->code&2)
				{
	  				si->tag=SEMITRANS_ADD;
				}
				si->code  = GPU_COM_G4;
					

   				ENDPRIMA(si,GETD(op->vert0),GETD(op->vert2),GETD(op->vert1),GETD(op->vert3), POLY_G4);
			}
		}
	}
	  	  	 		 
#undef si
#undef op
			   	
// That's the quads done, now let's do the triangles...

#define si ((POLY_G3*)packet)
#define op ((FMA_G3 *)opcd)

	op = mesh->g3s;
	for(i = mesh->n_g3s; i != 0; i--,op++)
	{
		gte_ldsz3(GETD(op->vert0),GETD(op->vert1),GETD(op->vert2));
   		gte_avsz3();
		gte_stotz(&depth);

 //		if(depth > min_depth && depth < max_depth)
		if(depth > min_depth)// && depth < max_depth)
		{
			gte_ldsxy3(GETV(op->vert0), GETV(op->vert1), GETV(op->vert2));
			gte_nclip();
			gte_stopz(&clipflag);

			if (clipflag<0)
			{
		// Put the polygon into the OT (Note that we re-use "depth" as one of the "t" variables)
  				BEGINPRIM(si, POLY_G3);
				// Copy the polygon data over into the OT
				t2 = *(u_long *) (&op->r0);
				*(u_long *)  (&si->r0) = t2;
				gte_stsxy3_g3(si);
				t1 = *(u_long *) (&op->r1);
				t2 = *(u_long *) (&op->r2);
				*(u_long *)  (&si->r1) = t1;
				*(u_long *)  (&si->r2) = t2;
				
	  			si->tag=SEMITRANS_NONE;
				if(si->code&2)
				{
	  				si->tag=SEMITRANS_ADD;
				}
				si->code  = GPU_COM_G3;

				ENDPRIMA(si,GETD(op->vert0),GETD(op->vert2),GETD(op->vert1),0, POLY_G3);
			}
		}
	}
	  	  	 		 
#undef si
#undef op
}

void MapDraw_DrawSkyMeshDC(FMA_SKYMESH_HEADER *mesh)
{  
// Note - t1 & t2 are shared with other variables
	u_long t1;
	u_long t2;
	PACKET * packet;
	char *opcd;
	long *tfv = transformedVertices;
	long *tfd = transformedDepths;

#define GETV(n)(  *(u_long *)( (int)(tfv) +(n) ) )
#define GETD(n)(  *(u_long *)( (int)(tfd) +(n) ) )
	unsigned long *ot = currentDisplayPage->ot + 1023;	// right at the back of the OT...

	int i;
	long clipflag;

	transformVertexListA(mesh->verts, mesh->n_verts, tfv, tfd);

#define si ((POLY_G4*)packet)
#define op ((FMA_G4 *)opcd)
		 
	op = mesh->g4s;

	for(i = mesh->n_g4s; i != 0; i--,op++)
	{
// For sky models, backface cull is still necessary.
// (coz of polys behind you)
// depth is always right at the back

		gte_ldsxy3(GETV(op->vert0), GETV(op->vert1), GETV(op->vert2));

		gte_nclip();
		gte_stopz(&clipflag);
		if (clipflag<0)
		{
	// Put the polygon into the OT (Note that we re-use "depth" as one of the "t" variables)
			BEGINPRIM(si,POLY_G4);
	// Copy the polygon data over into the OT

			t1 = *(u_long *) (&op->r0);
			t2 = *(u_long *) (&op->r1);
			*(u_long *)  (&si->r0) = t1;
			*(u_long *)  (&si->r1) = t2;
			gte_stsxy3_g4(si);	// The first 3 x's & y's are already in the gte, so we may as well use 'em
			t1 = *(u_long *) (&op->r2);
			t2 = *(u_long *) (&op->r3);
			*(u_long *)  (&si->r2) = t1;
			*(u_long *)  (&si->r3) = t2;
			*(u_long *)  (&si->x3) = *(u_long *) (&GETV(op->vert3));

	 		si->r0 = op->r0;   si->g0 = op->g0;  si->b0 = op->b0;
	 		si->r1 = op->r1;   si->g1 = op->g1;  si->b1 = op->b1;
	 		si->r2 = op->r2;   si->g2 = op->g2;  si->b2 = op->b2;
	 		si->r3 = op->r3;   si->g3 = op->g3;  si->b3 = op->b3;
			si->tag = SEMITRANS_NONE;
			si->code = 0x38;//cant remember the define

			ENDPRIM(si,GETD(op->vert0),POLY_G4);
		}
	}
		   
#undef si
#undef op

// That's the quads done, now let's do the triangles...

#define si ((POLY_G3*)packet)
#define op ((FMA_G3 *)opcd)
	   
	op = mesh->g3s;
	for(i = mesh->n_g3s; i != 0; i--,op++)
	{
// Optimisation - X & Y at the same time
		gte_ldsxy3(GETV(op->vert0), GETV(op->vert1), GETV(op->vert2));
		gte_nclip();
		gte_stopz(&clipflag);

  		if (clipflag<0)
		{

	// Put the polygon into the OT (Note that we re-use "depth" as one of the "t" variables)
			BEGINPRIM(si,POLY_G3);
	// Copy the polygon data over into the OT
			t2 = *(u_long *) (&op->r0);
			*(u_long *)  (&si->r0) = t2;
			gte_stsxy3_g3(si);
			t1 = *(u_long *) (&op->r1);
			t2 = *(u_long *) (&op->r2);
			*(u_long *)  (&si->r1) = t1;
			*(u_long *)  (&si->r2) = t2;
			ENDPRIM(si,GETD(op->vert0),POLY_G3);
		}
	}

#undef si
#undef op
}
