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

	lscape.c:		Landscape specific draw routines

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

#include "glover.h"

/*********************************************
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!!! (they've all been moved to 'variable.c') 
***********************************************/
//at 5:30 may10. This file was 20.4k. and 'all over the shop!'. will be split into a few 4k separate chunks.
#define FOGWATER YES

#define CLIPVERTSOLD


inline static  PACKET *divideQuad(TMD_PTYPE_TG4 *opTG4,long *transformedVerts, long *transformedDepths,PACKET *packet);
inline static  PACKET *divideTri(TMD_PTYPE_TG3 *opTG3,long *transformedVerts, long *transformedDepths,PACKET *packet);



#define SUBDIVISION
//#define SUBDIVIDEWATER
//#define SUBDIV_USEGTE


#define SUBDIV_TRANSPARENT


void	Get_Screenxy(VERT *v0,LONG *xy);

#define CHECKMAXDEPTH //if(depth>maxmapdepth) maxmapdepth=depth; // rem this whole line (before if), to remove check

#define DEPTHSHIFT	0
int DEPTHOFFS = 16;	/*added to each map face, to push it back slightly*/
#define MINMAPDEPTH	10 /*clips any depth less than this*/
#define MAXMAPDEPTH (MAXPOLYDEPTH-DEPTHOFFS-10) 

#define STOREMAPTILE ot=(GsOTA *)(PolyList->org+((DEPTHOFFS+depth) ));
/*************************************************************************************************************************/
/**********************************************************************************************/
/******  LANDSCAPE RENDERER  (FOGGED!)*****************************************************/
/**********************************************************************************************/
// ================================= Fogged Model ==============================================
// note the fog and the subdiv mustn't occur on within the same model...
// It's assumed that a model in the fogging zone will not also require subdivision
// (this, sadly, is not always the case, due to the size of landscape models...)

#define gte_stotz_cpu(r)\
asm(\
  "mfc2 %0, $7;"\
  :\
  : "r" (r)\
)


#define CONTPRIM {primPtr+=primSize;modctrl->PrimLeft--;continue;}
#define BREAKPRIM {primPtr+=primSize; break;}

static void renderFoggedLandscapeModel(long *transformedVerts, long *transformedDepths)	  //rou $1550 bytes
{
	// new ones by Chris
	union{
		TMD_PTYPE_GENERIC	*opGeneric;
		TMD_PTYPE_TG4		*opTG4;
		TMD_PTYPE_TG3		*opTG3;
		TMD_PTYPE_G4		*opG4;
		TMD_PTYPE_G3		*opG3;
		TMD_PTYPE_STG3		*opSTG3;	// Scrolling UVs, e.g. conveyors
		TMD_PTYPE_STG4		*opSTG4;
	}opu;


	union
	{
		PACKET*			packet;
		POLY_GT4		*siTG4;
		POLY_GT3		*siTG3;
		POLY_G4			*siG4;
		POLY_G3			*siG3;
		POLY_F4			*siF4;
		POLY_F3			*siF3;
	}siu;


//	ULONG fullcheck,check;
	VERT			*verttop;
	MODELCTRL 		*modctrl = &modelctrl;
	UBYTE			*primPtr;
	GsOTA			*ot;
	XYSHORT			*xy;
	signed char code;
	SPRITEX	*spr;
	register long depth asm("$16"); // force it to use CPU register
	long	clipflag;
	u_long	vert0;
	u_long	vert1;
	u_long	vert2;
	u_long	vert3;

	int		alpha0, alpha1, alpha2, alpha3;
	int		ralpha0, ralpha1, ralpha2, ralpha3;
	int primSize;

	int tFrame=(iframe/256)&15;

	siu.packet = GsOUT_PACKET_P;
	verttop = modctrl->VertTop;
	primPtr = (UBYTE *)modctrl->PrimTop;
	(ULONG*)xy=transformedVerts;
	depth=vert3=alpha3=0;  //just to stop warnings!!
	
	while(modctrl->PrimLeft)
	{
		// What I've done here is to cleverly (?) do back face culling and depth calculations BEFORE
		// we know what kind of polygon it is. This has two advantages. Firstly, back facing polygons
		// are rejected sooner, giving a small increase in speed, and second, the code is smaller and
		// easier to read since the aforementioned code is not duplicated time after time for each
		// polygon type.


		opu.opGeneric = (TMD_PTYPE_GENERIC *)primPtr;
		code=opu.opGeneric->primtype;

		primSize=opu.opGeneric->src_size;

		vert0 = opu.opGeneric->v0;
		vert1 = opu.opGeneric->v1;
		vert2 = opu.opGeneric->v2;

		ASSERT(vert0<MAXSEGMENTVERTS);
		ASSERT(vert1<MAXSEGMENTVERTS);
		ASSERT(vert2<MAXSEGMENTVERTS);

		gte_ldsxy3(transformedVerts[vert0],transformedVerts[vert1],transformedVerts[vert2]);
		gte_nclip();											// takes 8 cycles
		gte_stopz(&clipflag);

		if(!(code & PTYPENUMBER_DOUBLESIDED) && (clipflag >= 0)) // backface culling
			CONTPRIM;

		alpha0 = (int)transformedDepths[vert0];
		alpha1 = (int)transformedDepths[vert1];
		alpha2 = (int)transformedDepths[vert2];

		if((code&1)==PTYPE_TG4)
		{ // is a quadilateral
			vert3 = opu.opGeneric->v3;
			ASSERT(vert3<MAXSEGMENTVERTS);

			if((xy[vert0].x+256)&(xy[vert1].x+256)&(xy[vert2].x+256)&(xy[vert3].x+256)&512)
				CONTPRIM;

			if((xy[vert0].y+128)&(xy[vert1].y+128)&(xy[vert2].y+128)&(xy[vert3].y+128)&256)
				CONTPRIM;

			gte_ldsz4(transformedDepths[vert0],transformedDepths[vert1],transformedDepths[vert2],transformedDepths[vert3]);
   			gte_avsz4();											// Get Z depth value (5 cycles)

			alpha3 = (int)transformedDepths[vert3];
		}
		else
		{ // is a triangle

			ASSERT((code&1)==PTYPE_TG3);

			if((xy[vert0].x+256)&(xy[vert1].x+256)&(xy[vert2].x+256)&512)
				CONTPRIM;

			if((xy[vert0].y+128)&(xy[vert1].y+128)&(xy[vert2].y+128)&256)
				CONTPRIM;

			gte_ldsz3(transformedDepths[vert0],transformedDepths[vert1],transformedDepths[vert2]);
   			gte_avsz3();											// Get Z depth value (5 cycles)
		}

		gte_stotz_cpu(depth);										

		if(depth < MINMAPDEPTH)
			CONTPRIM;

		if(depth > MAXMAPDEPTH)
			depth=MAXMAPDEPTH;

   		STOREMAPTILE;
		INCPOLYSDRAWN;

		if((code&1)==PTYPE_TG4)
		{
			if(alpha0 > lscapeFogEndZ && alpha1 > lscapeFogEndZ && alpha2 > lscapeFogEndZ && alpha3 > lscapeFogEndZ)
			{
				if(alpha0 > lscapeFogFlatZ && alpha1 > lscapeFogFlatZ && alpha2 > lscapeFogFlatZ && alpha3 > lscapeFogFlatZ)
					CONTPRIM;

				*(u_long *)(&siu.siF4->r0) = *(u_long *)(&lscapeFogColour);	// which is set up to F4

				*(u_long *)  (&siu.siF4->x0) = *(u_long *) (&transformedVerts[vert0]);
				*(u_long *)  (&siu.siF4->x1) = *(u_long *) (&transformedVerts[vert1]);
				*(u_long *)  (&siu.siF4->x2) = *(u_long *) (&transformedVerts[vert2]);
				*(u_long *)  (&siu.siF4->x3) = *(u_long *) (&transformedVerts[vert3]);

				PUTPACKETINTABLE(siu.siF4, ot, POLYF4_LEN);
				siu.siF4++;
				CONTPRIM;
			}
		}
		else
		{
			if(alpha0 > lscapeFogEndZ && alpha1 > lscapeFogEndZ && alpha2 > lscapeFogEndZ)
			{
				if(alpha0 > lscapeFogFlatZ && alpha1 > lscapeFogFlatZ && alpha2 > lscapeFogFlatZ)
					CONTPRIM;

				*(u_long *)(&siu.siF3->r0) = *(u_long *)(&lscapeFogColour);	// which is set up to F4

				siu.siF3->code=GPU_COM_F3;
				*(u_long *)  (&siu.siF3->x0) = *(u_long *) (&transformedVerts[vert0]);
				*(u_long *)  (&siu.siF3->x1) = *(u_long *) (&transformedVerts[vert1]);
				*(u_long *)  (&siu.siF3->x2) = *(u_long *) (&transformedVerts[vert2]);

				PUTPACKETINTABLE(siu.siF3, ot, POLYF3_LEN);
				siu.siF3++;
				CONTPRIM;
			}
		}


		// there should be a near/far check before doing this bit...
		// "Alpha[]" is zero at the near boundary, 255 at the far.

		alpha0 = (( alpha0 - lscapeFogStartZ) << 8) >> lscapeFogSpanShift;
		alpha1 = (( alpha1 - lscapeFogStartZ) << 8) >> lscapeFogSpanShift;
		alpha2 = (( alpha2 - lscapeFogStartZ) << 8) >> lscapeFogSpanShift;

		if((code&1)==PTYPE_TG4)
			alpha3 = (( alpha3 - lscapeFogStartZ) << 8) >> lscapeFogSpanShift;


		if(code<0) // bit 7 set
			goto renderSpecial;

		code=code&1; // mask off all the crap

renderNormal:
		switch(code)
		{
		// note - Even with subdiv of transparencies, it still doesn't subdiv water, coz of tu/tv issues
		case PTYPE_TG4:
			ASSERT(primSize==sizeof(TMD_PTYPE_TG4));

			*(u_long *)  (&siu.siTG4->u0) = *(u_long *) (&opu.opTG4->tu0);	// Copy in texture coords
			*(u_long *)  (&siu.siTG4->u1) = *(u_long *) (&opu.opTG4->tu1);	// 6 cycles here
			*(u_long *)  (&siu.siTG4->u2) = *(u_long *) (&opu.opTG4->tu2);
			*(u_long *)  (&siu.siTG4->u3) = *(u_long *) (&opu.opTG4->tu3);

normalTG4afteruv:

			*(u_long *)  (&siu.siTG4->x3) = *(u_long *) (&transformedVerts[vert3]);
			gte_stsxy3_gt4(siu.siTG4);
			*(u_long *)  (&siu.siTG4->r0) = *(u_long *) (&opu.opTG4->r0);	// Copy in vertex colours (3 cycles)
			*(u_long *)  (&siu.siTG4->r1) = *(u_long *) (&opu.opTG4->r1);	// 3 cycles here
			*(u_long *)  (&siu.siTG4->r2) = *(u_long *) (&opu.opTG4->r2);
			*(u_long *)  (&siu.siTG4->r3) = *(u_long *) (&opu.opTG4->r3);

			if((alpha0 > 0) || (alpha1 > 0) || (alpha2 > 0) || (alpha3 > 0))
			{
				// Clamp the near & far ends of the fogging
				if(alpha0 < 0) alpha0 = 0;
				if(alpha0 > 255) alpha0 = 255;
				ralpha0 = 255 - alpha0;
	
				if(alpha1 < 0) alpha1 = 0;
				if(alpha1 > 255) alpha1 = 255;
				ralpha1 = 255 - alpha1;
	
				if(alpha2 < 0) alpha2 = 0;
				if(alpha2 > 255) alpha2 = 255;
				ralpha2 = 255 - alpha2;
	
				if(alpha3 < 0) alpha3 = 0;
				if(alpha3 > 255) alpha3 = 255;
				ralpha3 = 255 - alpha3;

				// fog the textured poly down to black in the distance
				// tbd - do this colour-scaling with the GTE
				// doesnt make any difference putting it as a long


				siu.siTG4->r0 = (((ULONG)siu.siTG4->r0) *ralpha0)>>8;
				siu.siTG4->g0 = (((ULONG)siu.siTG4->g0) *ralpha0)>>8;
				siu.siTG4->b0 = (((ULONG)siu.siTG4->b0) *ralpha0)>>8;

				siu.siTG4->r1 = (((ULONG)siu.siTG4->r1) *ralpha1)>>8;
				siu.siTG4->g1 = (((ULONG)siu.siTG4->g1) *ralpha1)>>8;
				siu.siTG4->b1 = (((ULONG)siu.siTG4->b1) *ralpha1)>>8;

				siu.siTG4->r2 = (((ULONG)siu.siTG4->r2) *ralpha2)>>8;
				siu.siTG4->g2 = (((ULONG)siu.siTG4->g2) *ralpha2)>>8;
				siu.siTG4->b2 = (((ULONG)siu.siTG4->b2) *ralpha2)>>8;

				siu.siTG4->r3 = (((ULONG)siu.siTG4->r3) *ralpha3)>>8;
				siu.siTG4->g3 = (((ULONG)siu.siTG4->g3) *ralpha3)>>8;
				siu.siTG4->b3 = (((ULONG)siu.siTG4->b3) *ralpha3)>>8;

				if(siu.siTG4->code & 2) // is it transparent?
				{
					PUTPACKETINTABLE(siu.siTG4, ot, POLYTG4_LEN);
		   			siu.siTG4++;
				}
				else
				{
					// If it's a normal texture, we need to plot a solid fog polygon, and then plot the
					// poly itself in additive.

// Because OT's are a linked list, the solid poly is added second
			   		siu.siTG4->code = GPU_COM_TG4|2;
		   			siu.siTG4->tpage = siu.siTG4->tpage | ((SEMITRANS_ADD-1) << 5);

					PUTPACKETINTABLE(siu.siTG4, ot, POLYTG4_LEN);
		   			siu.siTG4++;

					if(opu.opGeneric->flags & PMASK_COLOURKEY)
					{
						*(u_long *)  (&siu.siTG4->u0) = *(u_long *) (&opu.opTG4->tu0);	// Copy in texture coords
						*(u_long *)  (&siu.siTG4->u1) = *(u_long *) (&opu.opTG4->tu1);	// 6 cycles here
						*(u_long *)  (&siu.siTG4->u2) = *(u_long *) (&opu.opTG4->tu2);
						*(u_long *)  (&siu.siTG4->u3) = *(u_long *) (&opu.opTG4->tu3);


						siu.siTG4->r0 = ((int)lscapeFogColour.r *ralpha0 )>>8;
						siu.siTG4->g0 = ((int)lscapeFogColour.g *ralpha0 )>>8;
						siu.siTG4->b0 = ((int)lscapeFogColour.b *ralpha0 )>>8;

						siu.siTG4->r1 = ((int)lscapeFogColour.r *ralpha1 )>>8;
						siu.siTG4->g1 = ((int)lscapeFogColour.g *ralpha1 )>>8;
						siu.siTG4->b1 = ((int)lscapeFogColour.b *ralpha1 )>>8;

						siu.siTG4->r2 = ((int)lscapeFogColour.r *ralpha2 )>>8;
						siu.siTG4->g2 = ((int)lscapeFogColour.g *ralpha2 )>>8;
						siu.siTG4->b2 = ((int)lscapeFogColour.b *ralpha2 )>>8;
		
						siu.siTG4->r3 = ((int)lscapeFogColour.r *ralpha3 )>>8;
						siu.siTG4->g3 = ((int)lscapeFogColour.g *ralpha3 )>>8;
						siu.siTG4->b3 = ((int)lscapeFogColour.b *ralpha3 )>>8;

						*(u_long *)  (&siu.siTG4->x0) = *(u_long *) (&transformedVerts[vert0]);
						*(u_long *)  (&siu.siTG4->x1) = *(u_long *) (&transformedVerts[vert1]);
						*(u_long *)  (&siu.siTG4->x2) = *(u_long *) (&transformedVerts[vert2]);
						*(u_long *)  (&siu.siTG4->x3) = *(u_long *) (&transformedVerts[vert3]);

						siu.siTG4->code=GPU_COM_TG4|2;
		   				siu.siTG4->tpage = siu.siTG4->tpage | ((SEMITRANS_SUB-1) << 5);
						siu.siTG4->clut=overlayAlphaClut;

						PUTPACKETINTABLE(siu.siTG4, ot, POLYTG4_LEN);
						siu.siTG4++;
					}
					else
					{
// G4 is what we're going to add...
// Colours are (solid fog colour) at the back, and (black) at the front.
// Again, the colours need to be done with the GTE really
						siu.siG4->r0 = ((int)lscapeFogColour.r *alpha0 )>>8;
						siu.siG4->g0 = ((int)lscapeFogColour.g *alpha0 )>>8;
						siu.siG4->b0 = ((int)lscapeFogColour.b *alpha0 )>>8;

						siu.siG4->r1 = ((int)lscapeFogColour.r *alpha1 )>>8;
						siu.siG4->g1 = ((int)lscapeFogColour.g *alpha1 )>>8;
						siu.siG4->b1 = ((int)lscapeFogColour.b *alpha1 )>>8;

						siu.siG4->r2 = ((int)lscapeFogColour.r *alpha2 )>>8;
						siu.siG4->g2 = ((int)lscapeFogColour.g *alpha2 )>>8;
						siu.siG4->b2 = ((int)lscapeFogColour.b *alpha2 )>>8;
		
						siu.siG4->r3 = ((int)lscapeFogColour.r *alpha3 )>>8;
						siu.siG4->g3 = ((int)lscapeFogColour.g *alpha3 )>>8;
						siu.siG4->b3 = ((int)lscapeFogColour.b *alpha3 )>>8;

						*(u_long *)  (&siu.siG4->x0) = *(u_long *) (&transformedVerts[vert0]);
						*(u_long *)  (&siu.siG4->x1) = *(u_long *) (&transformedVerts[vert1]);
						*(u_long *)  (&siu.siG4->x2) = *(u_long *) (&transformedVerts[vert2]);
						*(u_long *)  (&siu.siG4->x3) = *(u_long *) (&transformedVerts[vert3]);

						siu.siG4->code=GPU_COM_G4;	// NO transparancy on this
						PUTPACKETINTABLE(siu.siG4, ot, POLYG4_LEN);
						siu.siG4++;
					}
				}
			}
			else
			{
				PUTPACKETINTABLE(siu.siTG4, ot, POLYTG4_LEN);
				siu.siTG4++;
			}

			BREAKPRIM;
 
		case PTYPE_TG3:
			ASSERT(primSize==sizeof(TMD_PTYPE_TG3));

		 	*(u_long *)  (&siu.siTG3->u0) = *(u_long *) (&opu.opTG3->tu0);	// Copy in texture coords
			*(u_long *)  (&siu.siTG3->u1) = *(u_long *) (&opu.opTG3->tu1);	// 6 cycles here
			*(u_long *)  (&siu.siTG3->u2) = *(u_long *) (&opu.opTG3->tu2);

normalTG3afteruv:

			gte_stsxy3_gt3(siu.siTG3);
			*(u_long *)  (&siu.siTG3->r0) = *(u_long *) (&opu.opTG3->r0);	// Copy in vertex colours (3 cycles)
			*(u_long *)  (&siu.siTG3->r1) = *(u_long *) (&opu.opTG3->r1);	// 3 cycles here
			*(u_long *)  (&siu.siTG3->r2) = *(u_long *) (&opu.opTG3->r2);

			if((alpha0 > 0) || (alpha1 > 0) || (alpha2 > 0))
			{
				// Clamp the near & far ends of the fogging
				if(alpha0 < 0) alpha0 = 0;
				if(alpha0 > 255) alpha0 = 255;

				ralpha0 = 255 - alpha0;
	
				if(alpha1 < 0) alpha1 = 0;
				if(alpha1 > 255) alpha1 = 255;
				ralpha1 = 255 - alpha1;
	
				if(alpha2 < 0) alpha2 = 0;
				if(alpha2 > 255) alpha2 = 255;
				ralpha2 = 255 - alpha2;
	
				// fog the textured poly down to black in the distance
				// tbd - do this colour-scaling with the GTE
				// doesnt make any difference putting it as a long

				siu.siTG3->r0 = (((ULONG)siu.siTG3->r0) *ralpha0)>>8;
				siu.siTG3->g0 = (((ULONG)siu.siTG3->g0) *ralpha0)>>8;
				siu.siTG3->b0 = (((ULONG)siu.siTG3->b0) *ralpha0)>>8;

				siu.siTG3->r1 = (((ULONG)siu.siTG3->r1) *ralpha1)>>8;
				siu.siTG3->g1 = (((ULONG)siu.siTG3->g1) *ralpha1)>>8;
				siu.siTG3->b1 = (((ULONG)siu.siTG3->b1) *ralpha1)>>8;

				siu.siTG3->r2 = (((ULONG)siu.siTG3->r2) *ralpha2)>>8;
				siu.siTG3->g2 = (((ULONG)siu.siTG3->g2) *ralpha2)>>8;
				siu.siTG3->b2 = (((ULONG)siu.siTG3->b2) *ralpha2)>>8;

				if(siu.siTG3->code & 2) // is it transparent?
				{
					PUTPACKETINTABLE(siu.siTG3, ot, POLYTG3_LEN);
		   			siu.siTG3++;
				}
				else
				{
					// If it's a normal texture, we need to plot a solid fog polygon, and then plot the poly itself in additive.
// Because OT's are a linked list, the solid poly is added second
		   			siu.siTG3->code = GPU_COM_TG3|2;
		   			siu.siTG3->tpage = siu.siTG3->tpage | ((SEMITRANS_ADD-1) << 5);

					PUTPACKETINTABLE(siu.siTG3, ot, POLYTG3_LEN);
	   				siu.siTG3++;

					if(opu.opGeneric->flags & PMASK_COLOURKEY)
					{
						*(u_long *)  (&siu.siTG3->u0) = *(u_long *) (&opu.opTG3->tu0);	// Copy in texture coords
						*(u_long *)  (&siu.siTG3->u1) = *(u_long *) (&opu.opTG3->tu1);	// 6 cycles here
						*(u_long *)  (&siu.siTG3->u2) = *(u_long *) (&opu.opTG3->tu2);


						siu.siTG3->r0 = ((int)lscapeFogColour.r *ralpha0 )>>8;
						siu.siTG3->g0 = ((int)lscapeFogColour.g *ralpha0 )>>8;
						siu.siTG3->b0 = ((int)lscapeFogColour.b *ralpha0 )>>8;

						siu.siTG3->r1 = ((int)lscapeFogColour.r *ralpha1 )>>8;
						siu.siTG3->g1 = ((int)lscapeFogColour.g *ralpha1 )>>8;
						siu.siTG3->b1 = ((int)lscapeFogColour.b *ralpha1 )>>8;

						siu.siTG3->r2 = ((int)lscapeFogColour.r *ralpha2 )>>8;
						siu.siTG3->g2 = ((int)lscapeFogColour.g *ralpha2 )>>8;
						siu.siTG3->b2 = ((int)lscapeFogColour.b *ralpha2 )>>8;
		
						*(u_long *)  (&siu.siTG3->x0) = *(u_long *) (&transformedVerts[vert0]);
						*(u_long *)  (&siu.siTG3->x1) = *(u_long *) (&transformedVerts[vert1]);
						*(u_long *)  (&siu.siTG3->x2) = *(u_long *) (&transformedVerts[vert2]);

						siu.siTG3->code=GPU_COM_TG3|2;
		   				siu.siTG3->tpage = siu.siTG3->tpage | ((SEMITRANS_SUB-1) << 5);
						siu.siTG3->clut=overlayAlphaClut;

						PUTPACKETINTABLE(siu.siTG3, ot, POLYTG3_LEN);
						siu.siTG3++;
					}
					else
					{
// G3 is what we're going to add...
// Colours are (solid fog colour) at the back, and (black) at the front.
// Again, the colours need to be done with the GTE really

						siu.siG3->r0 = ((int)lscapeFogColour.r *alpha0 )>>8;
						siu.siG3->g0 = ((int)lscapeFogColour.g *alpha0 )>>8;
						siu.siG3->b0 = ((int)lscapeFogColour.b *alpha0 )>>8;

						siu.siG3->r1 = ((int)lscapeFogColour.r *alpha1 )>>8;
						siu.siG3->g1 = ((int)lscapeFogColour.g *alpha1 )>>8;
						siu.siG3->b1 = ((int)lscapeFogColour.b *alpha1 )>>8;

						siu.siG3->r2 = ((int)lscapeFogColour.r *alpha2 )>>8;
						siu.siG3->g2 = ((int)lscapeFogColour.g *alpha2 )>>8;
						siu.siG3->b2 = ((int)lscapeFogColour.b *alpha2 )>>8;
		
						*(u_long *)  (&siu.siG3->x0) = *(u_long *) (&transformedVerts[vert0]);
						*(u_long *)  (&siu.siG3->x1) = *(u_long *) (&transformedVerts[vert1]);
						*(u_long *)  (&siu.siG3->x2) = *(u_long *) (&transformedVerts[vert2]);

						siu.siG3->code=GPU_COM_G3;	// NO transparancy on this
						PUTPACKETINTABLE(siu.siG3, ot, POLYG3_LEN);
						siu.siG3++;
					}
				}
			}
			else
			{
				PUTPACKETINTABLE(siu.siTG3, ot, POLYTG3_LEN);
				siu.siTG3++;
			}

			BREAKPRIM;

		default:
			DB("Unsupported LSCAPE poly type %d\n", code);
			modctrl->PrimLeft = 1;
			break;
		}

doneRenderSpecial:

		modctrl->PrimLeft--;
	}

	GsOUT_PACKET_P=siu.packet;
	return;

renderSpecial:
	// Do stuff like water, conveyor belts etc.
	// nb. transparent stuff doesn't need/want subdividing

	code=code&1; // mask off all the crap

	if(opu.opGeneric->flags==PMASK_TRANS)	// if it's trans only, we need just render a normal poly.
		goto renderNormal;

	if(opu.opGeneric->flags==PMASK_COLOURKEY)   // it's probably easiest to deal with this in the 'normal' code
		goto renderNormal;

//	DB("Rendering %d\n", opu.opGeneric->flags);

	if(opu.opGeneric->flags&PMASK_TEXANIM)	// an animating textured poly must be water or lava
	{
		if(code==PTYPE_TG4)
		{
			//if((opu.opSTG4->texPrg)>(opu.opSTG4->texFrames))
			//	opu.opSTG4->texPrg=0;

			//spr=(opu.opTG4->spr)+(opu.opSTG4->texPrg++);

			spr=(opu.opTG4->spr)+tFrame;

			*(ULONG *)(&siu.siTG4->u0)= ((*(USHORT *)(&spr->u0))+(*(USHORT *)(&opu.opTG4->tu0))) | (spr->clut<<16);
			*(ULONG *)(&siu.siTG4->u1)= ((*(USHORT *)(&spr->u0))+(*(USHORT *)(&opu.opTG4->tu1))) | (((opu.opTG4->tpage & 0x0060) | spr->tpage) <<16);	// preserve transp mode
			*(USHORT *)(&siu.siTG4->u2)=(*(USHORT *)(&spr->u0))+(*(USHORT *)(&opu.opTG4->tu2));
			*(USHORT *)(&siu.siTG4->u3)=(*(USHORT *)(&spr->u0))+(*(USHORT *)(&opu.opTG4->tu3));

			if(!(opu.opGeneric->flags & PMASK_TRANS))
				goto normalTG4afteruv;

			*(u_long *)  (&siu.siTG4->x3) = *(u_long *) (&transformedVerts[vert3]);
			gte_stsxy3_gt4(siu.siTG4);
			*(u_long *)  (&siu.siTG4->r0) = *(u_long *) (&opu.opTG4->r0);	// Copy in vertex colours (3 cycles)
			*(u_long *)  (&siu.siTG4->r1) = *(u_long *) (&opu.opTG4->r1);	// 3 cycles here
			*(u_long *)  (&siu.siTG4->r2) = *(u_long *) (&opu.opTG4->r2);
			*(u_long *)  (&siu.siTG4->r3) = *(u_long *) (&opu.opTG4->r3);

			if((alpha0 > 0) || (alpha1 > 0) || (alpha2 > 0) || (alpha3 > 0))
			{
				// Clamp the near & far ends of the fogging
				if(alpha0 < 0) alpha0 = 0;
				if(alpha0 > 255) alpha0 = 255;
				ralpha0 = 255 - alpha0;
	
				if(alpha1 < 0) alpha1 = 0;
				if(alpha1 > 255) alpha1 = 255;
				ralpha1 = 255 - alpha1;
	
				if(alpha2 < 0) alpha2 = 0;
				if(alpha2 > 255) alpha2 = 255;
				ralpha2 = 255 - alpha2;
	
				if(alpha3 < 0) alpha3 = 0;
				if(alpha3 > 255) alpha3 = 255;
				ralpha3 = 255 - alpha3;

				// fog the textured poly down to black in the distance
				// tbd - do this colour-scaling with the GTE
				// doesnt make any difference putting it as a long


				siu.siTG4->r0 = (((ULONG)siu.siTG4->r0) *ralpha0)>>8;
				siu.siTG4->g0 = (((ULONG)siu.siTG4->g0) *ralpha0)>>8;
				siu.siTG4->b0 = (((ULONG)siu.siTG4->b0) *ralpha0)>>8;

				siu.siTG4->r1 = (((ULONG)siu.siTG4->r1) *ralpha1)>>8;
				siu.siTG4->g1 = (((ULONG)siu.siTG4->g1) *ralpha1)>>8;
				siu.siTG4->b1 = (((ULONG)siu.siTG4->b1) *ralpha1)>>8;

				siu.siTG4->r2 = (((ULONG)siu.siTG4->r2) *ralpha2)>>8;
				siu.siTG4->g2 = (((ULONG)siu.siTG4->g2) *ralpha2)>>8;
				siu.siTG4->b2 = (((ULONG)siu.siTG4->b2) *ralpha2)>>8;

				siu.siTG4->r3 = (((ULONG)siu.siTG4->r3) *ralpha3)>>8;
				siu.siTG4->g3 = (((ULONG)siu.siTG4->g3) *ralpha3)>>8;
				siu.siTG4->b3 = (((ULONG)siu.siTG4->b3) *ralpha3)>>8;

				// we know it's transparent

				PUTPACKETINTABLE(siu.siTG4, ot, POLYTG4_LEN);
		   		siu.siTG4++;
			}
			else
			{
				PUTPACKETINTABLE(siu.siTG4, ot, POLYTG4_LEN);
				siu.siTG4++;
			}

		}
		else
		{
			//if(opu.opSTG3->texPrg>opu.opSTG3->texFrames)
			//	opu.opSTG3->texPrg=0;

			//spr=(opu.opTG3->spr)+opu.opSTG3->texPrg++;

			spr=(opu.opTG3->spr)+tFrame;

			*(ULONG *)(&siu.siTG3->u0)= ((*(USHORT *)(&spr->u0))+(*(USHORT *)(&opu.opTG3->tu0))) | (spr->clut<<16);
			*(ULONG *)(&siu.siTG3->u1)= ((*(USHORT *)(&spr->u0))+(*(USHORT *)(&opu.opTG3->tu1))) | (((opu.opTG3->tpage & 0x0060) | spr->tpage) <<16);	// preserve transp mode
			*(USHORT *)(&siu.siTG3->u2)=(*(USHORT *)(&spr->u0))+(*(USHORT *)(&opu.opTG3->tu2));

			if(!(opu.opGeneric->flags & PMASK_TRANS))
				goto normalTG3afteruv;

			gte_stsxy3_gt3(siu.siTG3);
			*(u_long *)  (&siu.siTG3->r0) = *(u_long *) (&opu.opTG3->r0);	// Copy in vertex colours (3 cycles)
			*(u_long *)  (&siu.siTG3->r1) = *(u_long *) (&opu.opTG3->r1);	// 3 cycles here
			*(u_long *)  (&siu.siTG3->r2) = *(u_long *) (&opu.opTG3->r2);

			if((alpha0 > 0) || (alpha1 > 0) || (alpha2 > 0))
			{
				// Clamp the near & far ends of the fogging
				if(alpha0 < 0) alpha0 = 0;
				if(alpha0 > 255) alpha0 = 255;
				ralpha0 = 255 - alpha0;
	
				if(alpha1 < 0) alpha1 = 0;
				if(alpha1 > 255) alpha1 = 255;
				ralpha1 = 255 - alpha1;
	
				if(alpha2 < 0) alpha2 = 0;
				if(alpha2 > 255) alpha2 = 255;
				ralpha2 = 255 - alpha2;
	
				// fog the textured poly down to black in the distance
				// tbd - do this colour-scaling with the GTE
				// doesnt make any difference putting it as a long

				siu.siTG3->r0 = (((ULONG)siu.siTG3->r0) *ralpha0)>>8;
				siu.siTG3->g0 = (((ULONG)siu.siTG3->g0) *ralpha0)>>8;
				siu.siTG3->b0 = (((ULONG)siu.siTG3->b0) *ralpha0)>>8;

				siu.siTG3->r1 = (((ULONG)siu.siTG3->r1) *ralpha1)>>8;
				siu.siTG3->g1 = (((ULONG)siu.siTG3->g1) *ralpha1)>>8;
				siu.siTG3->b1 = (((ULONG)siu.siTG3->b1) *ralpha1)>>8;

				siu.siTG3->r2 = (((ULONG)siu.siTG3->r2) *ralpha2)>>8;
				siu.siTG3->g2 = (((ULONG)siu.siTG3->g2) *ralpha2)>>8;
				siu.siTG3->b2 = (((ULONG)siu.siTG3->b2) *ralpha2)>>8;

				PUTPACKETINTABLE(siu.siTG3, ot, POLYTG3_LEN);
		   		siu.siTG3++;
			}
			else
			{
				PUTPACKETINTABLE(siu.siTG3, ot, POLYTG3_LEN);
				siu.siTG3++;
			}
		}

		primPtr+=primSize;
	}
	else
	{
		if(opu.opGeneric->flags&PMASK_UVANIM)
		{
			if(code==PTYPE_TG4)
			{
				//char uvFrame=(frame*(-opu.opSTG4->scrSpeed))&(opu.opSTG4->scrMask);
				char uvFrame=((iframe*(-opu.opSTG4->scrSpeed))/256)&(opu.opSTG4->scrMask);

				ASSERT(primSize==sizeof(TMD_PTYPE_STG4));

		 		*(u_long *)  (&siu.siTG4->u0) = *(u_long *) (&opu.opSTG4->tu0);	// Copy in texture coords
				*(u_long *)  (&siu.siTG4->u1) = *(u_long *) (&opu.opSTG4->tu1);	// 6 cycles here
				*(u_long *)  (&siu.siTG4->u2) = *(u_long *) (&opu.opSTG4->tu2);
				*(u_long *)  (&siu.siTG4->u3) = *(u_long *) (&opu.opSTG4->tu3);

				siu.siTG4->v0+=uvFrame;
				siu.siTG4->v1+=uvFrame;
				siu.siTG4->v2+=uvFrame;
				siu.siTG4->v3+=uvFrame;

				*(u_long *)  (&siu.siTG4->x3) = *(u_long *) (&transformedVerts[vert3]);
				gte_stsxy3_gt4(siu.siTG4);
				*(u_long *)  (&siu.siTG4->r0) = *(u_long *) (&opu.opSTG4->r0);	// Copy in vertex colours (3 cycles)
				*(u_long *)  (&siu.siTG4->r1) = *(u_long *) (&opu.opSTG4->r1);	// 3 cycles here
				*(u_long *)  (&siu.siTG4->r2) = *(u_long *) (&opu.opSTG4->r2);
				*(u_long *)  (&siu.siTG4->r3) = *(u_long *) (&opu.opSTG4->r3);
	
				PUTPACKETINTABLE(siu.siTG4, ot, POLYTG4_LEN);				// Add poly to list
				siu.siTG4++;
			}
			else
			{
				//char uvFrame=(frame*(-opu.opSTG3->scrSpeed))&(opu.opSTG3->scrMask);
				char uvFrame=((iframe*(-opu.opSTG3->scrSpeed))/256)&(opu.opSTG3->scrMask);

				ASSERT(primSize==sizeof(TMD_PTYPE_STG3));

				*(u_long *)  (&siu.siTG3->u0) = *(u_long *) (&opu.opTG3->tu0);	// Copy in texture coords	
				*(u_long *)  (&siu.siTG3->u1) = *(u_long *) (&opu.opTG3->tu1);	// 3 cycles here
				*(u_long *)  (&siu.siTG3->u2) = *(u_long *) (&opu.opTG3->tu2);

				siu.siTG3->v0+=uvFrame;
				siu.siTG3->v1+=uvFrame;
				siu.siTG3->v2+=uvFrame;

				gte_stsxy3_gt3(siu.siTG3);

				*(u_long *)  (&siu.siTG3->r0) = *(u_long *) (&opu.opTG3->r0);	// 6 cycles here
				*(u_long *)  (&siu.siTG3->r1) = *(u_long *) (&opu.opTG3->r1);	// 6 cycles here
				*(u_long *)  (&siu.siTG3->r2) = *(u_long *) (&opu.opTG3->r2);

				PUTPACKETINTABLE(siu.siTG3, ot, POLYTG3_LEN);				// Add poly to list
				siu.siTG3++;
			}

			primPtr+=primSize;
		}
		else
		{
			if(opu.opGeneric->flags==PMASK_COLOURKEY)
			{
				;
			}
		}
	}

	goto doneRenderSpecial;
}



/*******************************************************************************************/
void transformVertices(NEWMODEL *model,long *transformedVerts, long *transformedDepths)
{
//	int i,ctr;
	long numVerts;
	VERT *vertPtr;
	NEWOBJECT *world;

	world = &model->world;
	numVerts = world->meshdata->vern;

	ASSERT(numVerts<MAXSEGMENTVERTS);

	vertPtr = (VERT*)(world->meshdata->vertop);

	transformVertexListA(vertPtr, numVerts, transformedVerts, transformedDepths);
}

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

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


// draw the world as collision boxes
#ifdef SHOWCOLL

void lscapeDrawCuboid2(int xl, int xh, int yl, int yh, int zl, int zh, int colour)
{
	int v;
	ULONG check,totalchecks;
	XYSHORT			*xy;
//	int nClips=0;
	int f;
	int vert0,vert1,vert2,vert3;
	long	depth;
	GsOTA			*ot;
	int r,g,b;
	int c2,c3;
	long	clipflag;

	static int lookups[] =
		{0,1,2,3,
		 5,4,7,6,
		 5,7,1,3,
		 4,5,0,1,
		 6,4,2,0,
		 7,6,3,2
		};

	MATRIX *pMatrix = &GsWSMATRIX;
	POLY_G4			*siG4;


	(ULONG*)xy=transVerts;
	r = colour & 0xff;
	g = (colour>>8) & 0xff;
	b = (colour>>16) & 0xff;
	c2 = (r/2) | ((g/2)<<8) | ((b/2)<<16);
	c3 = (r/4) | ((g/4)<<8) | ((b/4)<<16);

	for(v=0; v<8; v++)
	{		// cunning way to build a bounding box
		pBBox[v].vx=(v&1)?xl:xh;
		pBBox[v].vy=(v&2)?yl:yh;
		pBBox[v].vz=(v&4)?zl:zh;
	}

	gte_SetRotMatrix(pMatrix);
	gte_SetTransMatrix(pMatrix);
	transformVertexList(pBBox, 9, transVerts, transDepths);
	totalchecks=0xffff;
	for(v=0; v<8; v++)
	{
		check=0;
		if(xy[v].x<-256)check|=OFFLEFT;
		if(xy[v].x>256 )check|=OFFRIGHT;
		if(xy[v].y<-128)check|=OFFUP;
		if(xy[v].y>128 )check|=OFFDOWN;
	  	if(transDepths[v]<=0)
		{
			check|=OFFFRONT;
			return;
		}
		if(transDepths[v]>lscapeFogEndZ)
			check |= OFFBACK;

	  	if(transDepths[v]>16032)check|=OFFBACK;
		totalchecks&=check;
	}

	if(totalchecks != 0)
		return;

	siG4 = (void *)GsOUT_PACKET_P;

	if(TOOMANYPOLYS(6*MAXPACKETSIZE,"<Lscapecolldraw>"))return;

	for(f = 0; f < 6; f++)
	{
		vert0 = lookups[f*4];
		vert1 = lookups[f*4+1];
		vert2 = lookups[f*4+2];
		vert3 = lookups[f*4+3];

	 	gte_ldsxy3(transVerts[vert0],transVerts[vert1],transVerts[vert2]);
		gte_nclip();
		if ((clipped[vert0]&clipped[vert1]&clipped[vert2]&clipped[vert3])!=0) break;

		gte_stopz(&clipflag);

		if((clipflag < 0))
		{
			gte_ldsz4(transDepths[vert0],transDepths[vert1],transDepths[vert2],transDepths[vert3]);
			*(u_long *)  (&siG4->x0) = *(u_long *) (&transVerts[vert0]);
			*(u_long *)  (&siG4->x1) = *(u_long *) (&transVerts[vert1]);
			*(u_long *)  (&siG4->x2) = *(u_long *) (&transVerts[vert2]);
			*(u_long *)  (&siG4->x3) = *(u_long *) (&transVerts[vert3]);
   			gte_avsz4_b();
			gte_stotz(&depth);										

			//depth/=2;	
			if (depth < MINMAPDEPTH)break;
			if (depth > MAXMAPDEPTH) depth=MAXMAPDEPTH;
   			STOREMAPTILE;
			INCPOLYSDRAWN;

//			gte_stsxy3_t4(siG4);
			*(u_long *)  (&siG4->r0) = *(u_long *) (&colour);	//&opu.opTG4->r0);
			*(u_long *)  (&siG4->r1) = *(u_long *) (&c2);	//&opu.opTG4->r1);
			*(u_long *)  (&siG4->r2) = *(u_long *) (&c2);	//&opu.opTG4->r2);
			*(u_long *)  (&siG4->r3) = *(u_long *) (&c3);	//&opu.opTG4->r3);

			siG4->code=GPU_COM_G4;

			PUTPACKETINTABLE(siG4, ot, POLYG4_LEN);

			siG4++;
		}
	}
	GsOUT_PACKET_P = (void *)siG4;
}

/*
typedef struct {
	u_long	tag;
	u_char	r0, g0, b0, code;
	short	x0, 	y0;
	u_char	r1, g1, b1, pad1;
	short	x1,	y1;
	u_char	r2, g2, b2, pad2;
	short	x2,	y2;
	u_char	r3, g3, b3, pad3;
	short	x3,	y3;
} POLY_G4;
*/

void lscapeDrawRamp(COLLBOX *pB, VECTOR *pPos, int colour)
{
//	int dx,dy,dz;
//	int xc,yc,zc;

//	int x,y,z;
	int xl,yl,zl;
	int xh,yh,zh;

	int v;
	ULONG check,totalchecks;
	XYSHORT			*xy;
	MATRIX *pMatrix = &GsWSMATRIX;

	int nFaces, nVerts, f;
	VECTOR *pV;
	ULONG *pM,*pF;
	int clipflag;
	int vert0, vert1, vert2;
	int depth;

	POLY_G3			*siG3;
	GsOTA			*ot;

	char r = colour & 0xff;
	char g = (colour>>8) & 0xff;
	char b = (colour>>16) & 0xff;
	int c2 = (r/2) | ((g/2)<<8) | ((b/2)<<16);


	xl = (pB->pX) >> 12;
	yl = (pB->pY) >> 12;
	zl = (pB->pZ) >> 12;

	if(pPos)
	{
		xl+=(pPos->vx)>>12;
		yl+=(pPos->vy)>>12;
		zl+=(pPos->vz)>>12;
	}

	xh = xl+((pB->sX) >> 12);
	yh = yl+((pB->sY) >> 12);
	zh = zl+((pB->sZ) >> 12);

	for(v=0; v<8; v++)
	{		// cunning way to build a bounding box
		pBBox[v].vx=(v&1)?xl:xh;
		pBBox[v].vy=(v&2)?yl:yh;
		pBBox[v].vz=(v&4)?zl:zh;
	}
	gte_SetRotMatrix(pMatrix);
	gte_SetTransMatrix(pMatrix);
	(ULONG*)xy=transVerts;
	transformVertexList(pBBox, 9, transVerts, transDepths);
	totalchecks=0xffff;
	for(v=0; v<8; v++)
	{
		check=0;
//		if(xy[v].x<-256)check|=OFFLEFT;
//		if(xy[v].x>256 )check|=OFFRIGHT;
//		if(xy[v].y<-128)check|=OFFUP;
//		if(xy[v].y>128 )check|=OFFDOWN;
	  	if(transDepths[v]<=0)
		{
			check|=OFFFRONT;
		}
		if(transDepths[v]>lscapeFogEndZ)
			check |= OFFBACK;

	  	if(transDepths[v]>16032)check|=OFFBACK;
		totalchecks&=check;
	}

	if(totalchecks != 0)
		return;

	siG3 = (void *)GsOUT_PACKET_P;

	// now actually draw the thing

	pM=(ULONG *)(pB->rampheader);

	if(!pM)
		return;

	nVerts=pM[0]&0xffff;
	nFaces=pM[0]>>16;
				  
	pF=(ULONG *)pM[1];
	pV=(VECTOR *)pM[2];

	for(f=0; f<nVerts; f++)
	{
		pBBox[f].vx=(pV[f].vx>>12)+xl;
		pBBox[f].vy=(pV[f].vy>>12)+yl;
		pBBox[f].vz=(pV[f].vz>>12)+zl;
	}

	transformVertexList(pBBox, 8, transVerts, transDepths);

	for(f=0; f<nFaces; f++)
	{
		vert0 = (pF[f]>>8)&0xf;
		vert1 = (pF[f]>>12)&0xf;
		vert2 = (pF[f]>>16)&0xf;

	 	gte_ldsxy3(transVerts[vert0],transVerts[vert1],transVerts[vert2]);
		gte_nclip();

		gte_stopz(&clipflag);

		//if((clipflag < 0))
		{
			gte_ldsz3(transDepths[vert0],transDepths[vert1],transDepths[vert2]);
			*(u_long *)  (&siG3->x0) = *(u_long *) (&transVerts[vert0]);
			*(u_long *)  (&siG3->x1) = *(u_long *) (&transVerts[vert1]);
			*(u_long *)  (&siG3->x2) = *(u_long *) (&transVerts[vert2]);
   			gte_avsz3_b();
			gte_stotz(&depth);										

			//depth/=2;	
			if (depth < MINMAPDEPTH)break;
			if (depth > MAXMAPDEPTH) depth=MAXMAPDEPTH;
   			STOREMAPTILE;
			INCPOLYSDRAWN;

//			gte_stsxy3_t4(siG4);
			*(u_long *)  (&siG3->r0) = *(u_long *) (&colour);	//&opu.opTG4->r0);
			*(u_long *)  (&siG3->r1) = *(u_long *) (&c2);	//&opu.opTG4->r1);
			*(u_long *)  (&siG3->r2) = *(u_long *) (&c2);	//&opu.opTG4->r2);

			siG3->code=GPU_COM_G3;

			PUTPACKETINTABLE(siG3, ot, POLYG3_LEN);

			siG3++;
		}
	}
	GsOUT_PACKET_P = (void *)siG3;

}

void lscapeDrawCuboid(int xl, int xh, int yl, int yh, int zl, int zh, int colour)
{
	int dx,dy,dz;
	int xc,yc,zc;

	int x,y,z;
	int xl1,yl1,zl1;
	int xh1,yh1,zh1;

	int v;
	ULONG check,totalchecks;
	XYSHORT			*xy;
	MATRIX *pMatrix = &GsWSMATRIX;

	xl = xl >> 12;
	yl = yl >> 12;
	zl = zl >> 12;

	xh = xh >> 12;
	yh = yh >> 12;
	zh = zh >> 12;

	for(v=0; v<8; v++)
	{		// cunning way to build a bounding box
		pBBox[v].vx=(v&1)?xl:xh;
		pBBox[v].vy=(v&2)?yl:yh;
		pBBox[v].vz=(v&4)?zl:zh;
	}

	gte_SetRotMatrix(pMatrix);
	gte_SetTransMatrix(pMatrix);
	(ULONG*)xy=transVerts;
	transformVertexList(pBBox, 9, transVerts, transDepths);
	totalchecks=0xffff;
	for(v=0; v<8; v++)
	{
		check=0;
//		if(xy[v].x<-256)check|=OFFLEFT;
//		if(xy[v].x>256 )check|=OFFRIGHT;
//		if(xy[v].y<-128)check|=OFFUP;
//		if(xy[v].y>128 )check|=OFFDOWN;
	  	if(transDepths[v]<=0)
		{
			check|=OFFFRONT;
		}
		if(transDepths[v]>lscapeFogEndZ)
			check |= OFFBACK;

	  	if(transDepths[v]>16032)check|=OFFBACK;
		totalchecks&=check;
	}

	if(totalchecks != 0)
		return;

	dx = xh-xl;
	dy = yh-yl;
	dz = zh-zl;

	xc = 1;
	yc = 1;
	zc = 1;

	if(dx < 0 || dy < 0 || dz < 0)
		return;

	xc = (dx / 200) + 1;
	yc = (dy / 200) + 1;
	zc = (dz / 200) + 1;


	for(x = 0; x < xc; x++)
	for(y = 0; y < yc; y++)
	for(z = 0; z < zc; z++)
	{
		xl1 = xl + (xh-xl) * x / xc;
		xh1 = xl + (xh-xl) * (x+1) / xc;

		yl1 = yl + (yh-yl) * y / yc;
		yh1 = yl + (yh-yl) * (y+1) / yc;

		zl1 = zl + (zh-zl) * z / zc;
		zh1 = zl + (zh-zl) * (z+1) / zc;

		lscapeDrawCuboid2(xl1, xh1, yl1, yh1, zl1, zh1, colour);
	}
}
/*************************************************************************************/
void lscapeDrawCollBox(COLLBOX *pB, DYNCOLLBOX *pD)
{
	int x1=pB->pX;
	int y1=pB->pY+pB->sY;
	int z1=pB->pZ;
	int x2=pB->pX+pB->sX;
	int y2=pB->pY;
	int z2=pB->pZ+pB->sZ;

	if(pD)
	{
		x1+=(pD->cumPos.vx);
		y1+=(pD->cumPos.vy);
		z1+=(pD->cumPos.vz);
		x2+=(pD->cumPos.vx);
		y2+=(pD->cumPos.vy);
		z2+=(pD->cumPos.vz);
	}

	if((pB->flags&TYPEPART)==BOX)
	{
		lscapeDrawCuboid(x1,x2,y1,y2,z1,z2, 0x00808080);

//			pB->pX,       pB->pX+pB->sX,
//			pB->pY+pB->sY,pB->pY,
//			pB->pZ,       pB->pZ+pB->sZ,
//			0x00808080);
	}
	else if ( (pB->flags&TYPEPART)==RAMP )
	{
		if(pD)
			lscapeDrawRamp(pB, &(pD->cumPos), 0x00ffff00);
		else
			lscapeDrawRamp(pB, NULL, 0x00ffff00);

		//lscapeDrawCuboid(x1,x2,y1,y2,z1,z2, 0x00ffff00);

//			pB->pX,       pB->pX+pB->sX,
//			pB->pY+pB->sY,pB->pY,
//			pB->pZ,       pB->pZ+pB->sZ,
//			0x00ffff00);

	}
	else if ( ((pB->flags&TYPEPART)==CYLINDER_X) || ((pB->flags&TYPEPART)==CYLINDER_Y) || ((pB->flags&TYPEPART)==CYLINDER_Z) )
	{
		lscapeDrawCuboid(x1,x2,y1,y2,z1,z2, 0x0000ffff);

//			pB->pX,       pB->pX+pB->sX,
//			pB->pY+pB->sY,pB->pY,
//			pB->pZ,       pB->pZ+pB->sZ,
//			0x0000ffff);
	}
	else if ( (pB->flags&TYPEPART)==SPHERE )
	{
		lscapeDrawCuboid(x1,x2,y1,y2,z1,z2, 0x00ff0000);

//			pB->pX,       pB->pX+pB->sX,
//			pB->pY+pB->sY,pB->pY,
//			pB->pZ,       pB->pZ+pB->sZ,
//			0x00ff0000);
	}
	else
	{
		printf(".");
	}

}
extern COLLBOX *pMeshColl;
extern int nMeshColl;

void lscapeDrawCollision()
{
//	DYNCOLLBOX *ptr;
	int i;

	for(i=0; i<nMeshColl; i++)
	{
		lscapeDrawCollBox(pMeshColl+i, NULL);
	}

}

#endif

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

int lscape_collbox_toggle = 0;
int lscape_just_one_model = -1;
int lscape_jom_ticker = 0;

void lscapeDrawAll(PSAWORLD *pW)
{
	ULONG i;
	NEWMODEL *pModel;
//	NEWMODEL *model;
//	NEWOBJECT	*world;

#if RELEASE == NO
#ifdef SHOWCOLL
	if(debounce[1] & PAD_CROSS)
		lscape_collbox_toggle = !lscape_collbox_toggle;
	if(lscape_collbox_toggle)
	{
		lscapeDrawCollision();
		return;
	}
#endif
#endif

	ASSERT(pW);
//	ASSERT(ppModels);
	 modelctrl.polysdrawn=0;

	//lscapeFogSpan = lscapeFogEndZ - lscapeFogStartZ;
	
	lscapeFogSpanShift=8;
	lscapeFogSpan=1<<lscapeFogSpanShift;

#if RELEASE == NO
	lscape_jom_ticker++;
	if((debounce[1] & PAD_RIGHT) || ((pad[1] & PAD_RIGHT) && lscape_jom_ticker > 5))
	{
		lscape_jom_ticker = 0;
		lscape_just_one_model++;
		if(lscape_just_one_model >= pW->nZones)
			lscape_just_one_model = 0;
	}
	else if((debounce[1] & PAD_LEFT) || ((pad[1] & PAD_LEFT) && lscape_jom_ticker > 5))
	{
		lscape_jom_ticker = 0;
		lscape_just_one_model--;
		if(lscape_just_one_model <0)
			lscape_just_one_model = pW->nZones-1;
	}
	else if(lscape_jom_ticker >= 30 * 10)
	{
		lscape_jom_ticker = 0;
		lscape_just_one_model = -1;
	}
	if(lscape_just_one_model >= 0)
	{
		char tempmess[8];
		SETRGBC(sprctrl.r,0,128,128,0);

		TEXTSETFONT(fontList[0]);

		SETRGBC(sprctrl.r1,0,0,128,TRUE);
	
		messctrl.justify=LEFTTEXT;
		sprintf(tempmess,"%d",lscape_just_one_model);
		TEXTPRINTAT(80,50,tempmess);

		if(pWld->pZones[lscape_just_one_model].tag)
		{
		sprintf(tempmess,"tag %d",pWld->pZones[lscape_just_one_model].tag);
		TEXTPRINTAT(88,60,tempmess);
		}


		if(pW->pZones[lscape_just_one_model].u.model)
		{
	 		pModel=pW->pZones[lscape_just_one_model].u.model;
			lscapeDrawClipped(pModel, &GsWSMATRIX, LSCAPE_DRAWMODEL);
		}
		return;
	}
#endif


	for(i=0; i<(pW->nZones); i++)
	{
		if(pW->pZones[i].u.model)
		{// check to see if bounding box is on the screen
	 		pModel=pW->pZones[i].u.model;

			lscapeSetTerrainDepthOffset(pW->pZones[i].terrain);
			lscapeDrawClipped(pModel, &GsWSMATRIX, LSCAPE_DRAWMODEL);
		}
	}
	DEPTHOFFS = 16*2;

//   	DB("polys drawn=%d \n",modelctrl.polysdrawn);

}

/*************************************************************************************************************************/
void transformVertexList(VERT *vertPtr, long numVerts, long *transformedVerts, long *transformedDepths)// rou $12c bytes
{
	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;
	XYSHORT			*xy;
	(ULONG*)xy=transformedVerts;

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

	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(&transformedVerts[vertLoop]);
		gte_stsz3c(&transformedDepths[vertLoop]);

#ifndef CLIPVERTSOLD
		UBYTE check=0;
		(long*)xy=transformedVerts;
		if(xy[vertLoop].x<-256)check=OFFLEFT;
		if(xy[vertLoop].x>256)check|=OFFRIGHT;
		if(xy[vertLoop].y<-128)check|=OFFUP;
		if(xy[vertLoop].y>128)check|=OFFDOWN;
		clipped[vertLoop]=check;
	 
		check=0;
		if(xy[vertLoop+1].x<-256)check=OFFLEFT;
		if(xy[vertLoop+1].x>256)check|=OFFRIGHT;
		if(xy[vertLoop+1].y<-128)check|=OFFUP;
		if(xy[vertLoop+1].y>128)check|=OFFDOWN;
		clipped[vertLoop+1]=check;

		check=0;
		if(xy[vertLoop+2].x<-256)check=OFFLEFT;
		if(xy[vertLoop+2].x>256)check|=OFFRIGHT;
		if(xy[vertLoop+2].y<-128)check|=OFFUP;
		if(xy[vertLoop+2].y>128)check|=OFFDOWN;
		clipped[vertLoop+2]=check;
#endif

	}
}
/************************************************************************************************/
/*************************************************************************************************************************/
void renderSkyModel(long *transformedVerts, long *transformedDepths)				   //rou $490 bytes
{
	VERT			*verttop;
	union{
		TMD_P_TG4A		*opTG4;
		TMD_P_TG3A		*opTG3;
		TMD_P_F4G		*opG4;
		TMD_P_F3G		*opG3;
	}opu;

	union
	{
		PACKET*			packet;
		POLY_GT4		*siTG4;
		POLY_GT3		*siTG3;
		POLY_G4			*siG4;
		POLY_G3			*siG3;
		POLY_F4			*siF4;
		POLY_F3			*siF3;
	}siu;

	MODELCTRL 		*modctrl = &modelctrl;
	UBYTE			*primPtr;
	GsOTA			*ot;
	XYSHORT			*xy;
	ULONG code;
	long	depth;
	long	clipflag;
	siu.packet = GsOUT_PACKET_P;
	verttop = modctrl->VertTop;
	primPtr = (UBYTE *)modctrl->PrimTop;
	(ULONG*)xy=transformedVerts;
	depth=MAXMAPDEPTH;

	while (modctrl->PrimLeft)
	{
		opu.opTG4 = (TMD_P_TG4A *)primPtr;
		code=opu.opTG4->cd & (0xff-2);
		switch(code)
		{
		case GPU_COM_G4:
			if ( (xy[opu.opG4->v0].x+256)&(xy[opu.opG4->v1].x+256)&(xy[opu.opG4->v2].x+256)&(xy[opu.opG4->v3].x+256)&512)goto lscapeDoneG4; //return (PACKET *)si;
			if ( (xy[opu.opG4->v0].y+128)&(xy[opu.opG4->v1].y+128)&(xy[opu.opG4->v2].y+128)&(xy[opu.opG4->v3].y+128)&256)goto lscapeDoneG4; //return (PACKET *)si;

			gte_ldsxy3(transformedVerts[opu.opG4->v0],transformedVerts[opu.opG4->v1],transformedVerts[opu.opG4->v2]);
	
			*(u_long *)  (&siu.siG4->x3) = *(u_long *) (&transformedVerts[opu.opG4->v3]);
	
			gte_nclip_b();										// (8 cycles)
		
			*(u_long *)  (&siu.siG4->r1) = *(u_long *) (&opu.opG4->r1);
			*(u_long *)  (&siu.siG4->r2) = *(u_long *) (&opu.opG4->r2);

			gte_stopz(&clipflag);								// (1 cycle)
		
			if((!(opu.opG4->dummy & 2)) && (clipflag >= 0))goto lscapeDoneG4;	// Backface culling
 
			gte_stsxy3_g4(siu.siG4);
			*(u_long *)  (&siu.siG4->r0) = *(u_long *) (&opu.opG4->r0);	// Copy in vertex colours
			*(u_long *)  (&siu.siG4->r3) = *(u_long *) (&opu.opG4->r3);
		   	STOREMAPTILE;
			INCPOLYSDRAWN;
 	
			PUTPACKETINTABLE(siu.siG4, ot, POLYG4_LEN);				// Add poly to list
			siu.siG4++;
lscapeDoneG4:
			primPtr += sizeof(TMD_P_F4G);
			break;
		case GPU_COM_G3:
			if ( (xy[opu.opG3->v0].x+256)&(xy[opu.opG3->v1].x+256)&(xy[opu.opG3->v2].x+256)&512)goto lscapeDoneG3;
			if ( (xy[opu.opG3->v0].y+128)&(xy[opu.opG3->v1].y+128)&(xy[opu.opG3->v2].y+128)&256)goto lscapeDoneG3;

			gte_ldsxy3(transformedVerts[opu.opG3->v0],transformedVerts[opu.opG3->v1],transformedVerts[opu.opG3->v2]);

			gte_nclip();										// (8 cycles)
	
			gte_stopz(&clipflag);								// (1 cycle)
		
			if((!(opu.opG3->dummy & 2)) && (clipflag >= 0))goto lscapeDoneG3;// Backface culling

			gte_stsxy3_g3(siu.siG3);
			*(u_long *)  (&siu.siG3->r0) = *(u_long *) (&opu.opG3->r0);	// Copy in vertex colours
			*(u_long *)  (&siu.siG3->r1) = *(u_long *) (&opu.opG3->r1);
			*(u_long *)  (&siu.siG3->r2) = *(u_long *) (&opu.opG3->r2);
		   	STOREMAPTILE;
			INCPOLYSDRAWN;
			PUTPACKETINTABLE(siu.siG3, ot, POLYG3_LEN);				// Add poly to list
			siu.siG3++;
lscapeDoneG3:
			primPtr += sizeof(TMD_P_F3G);
	 		break;
		default:
			debugPrintf("Unsupported SKY poly type %d\n", opu.opTG4->cd & (0xff-2));
			modctrl->PrimLeft = 1;
			break;
		}
		modctrl->PrimLeft--;
	}
	GsOUT_PACKET_P=siu.packet;
	return;
}
/*-------------------------------------*/
/*************************************************************************************************************************/


static void renderLandscapeModel(long *transformedVerts, long *transformedDepths)	  //rou $1550 bytes
{
	// new ones by Chris
	union{
		TMD_PTYPE_GENERIC	*opGeneric;
		TMD_PTYPE_TG4		*opTG4;
		TMD_PTYPE_TG3		*opTG3;
		TMD_PTYPE_G4		*opG4;
		TMD_PTYPE_G3		*opG3;
		TMD_PTYPE_STG3		*opSTG3;	// Scrolling UVs, e.g. conveyors
		TMD_PTYPE_STG4		*opSTG4;
	}opu;


	union
	{
		PACKET*			packet;
		POLY_GT4		*siTG4;
		POLY_GT3		*siTG3;
		POLY_G4			*siG4;
		POLY_G3			*siG3;
		POLY_F4			*siF4;
		POLY_F3			*siF3;
	}siu;

	VERT			*verttop;
	MODELCTRL 		*modctrl = &modelctrl;
	UBYTE			*primPtr;
	GsOTA			*ot;
	XYSHORT			*xy;
	signed char code;
	SPRITEX	*spr;
	register long depth asm("$16"); // force it to use CPU register
	long	clipflag;
	u_long	vert0;
	u_long	vert1;
	u_long	vert2;
	u_long	vert3;
	int primSize;
	int tFrame=(iframe/256)&15;
	
	depth=vert3=0;  //just to stop warnings!

	siu.packet = GsOUT_PACKET_P;
	verttop = modctrl->VertTop;
	primPtr = (UBYTE *)modctrl->PrimTop;
	(ULONG*)xy=transformedVerts;

	while(modctrl->PrimLeft)
	{
		// What I've done here is to cleverly (?) do back face culling and depth calculations BEFORE
		// we know what kind of polygon it is. This has two advantages. Firstly, back facing polygons
		// are rejected sooner, giving a small increase in speed, and second, the code is smaller and
		// easier to read since the aforementioned code is not duplicated time after time for each
		// polygon type.


		opu.opGeneric = (TMD_PTYPE_GENERIC *)primPtr;
		code=opu.opGeneric->primtype;

		primSize=opu.opGeneric->src_size;

		vert0 = opu.opGeneric->v0;
		vert1 = opu.opGeneric->v1;
		vert2 = opu.opGeneric->v2;

		ASSERT(vert0<MAXSEGMENTVERTS);
		ASSERT(vert1<MAXSEGMENTVERTS);
		ASSERT(vert2<MAXSEGMENTVERTS);

		gte_ldsxy3(transformedVerts[vert0],transformedVerts[vert1],transformedVerts[vert2]);
		gte_nclip();											// takes 8 cycles
		gte_stopz(&clipflag);

		if(!(code & PTYPENUMBER_DOUBLESIDED) && (clipflag >= 0)) // backface culling
			CONTPRIM;


		if((code&1)==PTYPE_TG4)
		{ // is a quadilateral
			vert3 = opu.opGeneric->v3;
			ASSERT(vert3<MAXSEGMENTVERTS);

			if((xy[vert0].x+256)&(xy[vert1].x+256)&(xy[vert2].x+256)&(xy[vert3].x+256)&512)
				CONTPRIM;

			if((xy[vert0].y+128)&(xy[vert1].y+128)&(xy[vert2].y+128)&(xy[vert3].y+128)&256)
				CONTPRIM;

			gte_ldsz4(transformedDepths[vert0],transformedDepths[vert1],transformedDepths[vert2],transformedDepths[vert3]);
   			gte_avsz4();											// Get Z depth value (5 cycles)
		}
		else
		{ // is a triangle

			ASSERT((code&1)==PTYPE_TG3);

			if((xy[vert0].x+256)&(xy[vert1].x+256)&(xy[vert2].x+256)&512)
				CONTPRIM;

			if((xy[vert0].y+128)&(xy[vert1].y+128)&(xy[vert2].y+128)&256)
				CONTPRIM;

			gte_ldsz3(transformedDepths[vert0],transformedDepths[vert1],transformedDepths[vert2]);
   			gte_avsz3();											// Get Z depth value (5 cycles)
		}

		gte_stotz_cpu(depth);										

		if(depth < MINMAPDEPTH)
			CONTPRIM;

		if(depth > MAXMAPDEPTH)
			depth=MAXMAPDEPTH;

   		STOREMAPTILE;
		INCPOLYSDRAWN;

		if(code<0) // bit 7 set
			goto renderSpecial;

		code=code&1; // mask off all the crap

		if((depth<(SubDivCtrl.otzDepth*2)) /*&& (level==HUB8)*/)
			goto renderSubdivided;

renderNormal:
		switch(code)
		{
		// note - Even with subdiv of transparencies, it still doesn't subdiv water, coz of tu/tv issues
		case PTYPE_TG4:
			ASSERT(primSize==sizeof(TMD_PTYPE_TG4));

		 	*(u_long *)  (&siu.siTG4->u0) = *(u_long *) (&opu.opTG4->tu0);	// Copy in texture coords
			*(u_long *)  (&siu.siTG4->u1) = *(u_long *) (&opu.opTG4->tu1);	// 6 cycles here
			*(u_long *)  (&siu.siTG4->u2) = *(u_long *) (&opu.opTG4->tu2);
			*(u_long *)  (&siu.siTG4->u3) = *(u_long *) (&opu.opTG4->tu3);

			*(u_long *)  (&siu.siTG4->x3) = *(u_long *) (&transformedVerts[vert3]);
			gte_stsxy3_gt4(siu.siTG4);
			*(u_long *)  (&siu.siTG4->r0) = *(u_long *) (&opu.opTG4->r0);	// Copy in vertex colours (3 cycles)
			*(u_long *)  (&siu.siTG4->r1) = *(u_long *) (&opu.opTG4->r1);	// 3 cycles here
			*(u_long *)  (&siu.siTG4->r2) = *(u_long *) (&opu.opTG4->r2);
			*(u_long *)  (&siu.siTG4->r3) = *(u_long *) (&opu.opTG4->r3);
	
			PUTPACKETINTABLE(siu.siTG4, ot, POLYTG4_LEN);				// Add poly to list
			siu.siTG4++;

			BREAKPRIM;
 
		case PTYPE_TG3:
			ASSERT(primSize==sizeof(TMD_PTYPE_TG3));

			*(u_long *)  (&siu.siTG3->u0) = *(u_long *) (&opu.opTG3->tu0);	// Copy in texture coords	
			*(u_long *)  (&siu.siTG3->u1) = *(u_long *) (&opu.opTG3->tu1);	// 3 cycles here
			*(u_long *)  (&siu.siTG3->u2) = *(u_long *) (&opu.opTG3->tu2);

			gte_stsxy3_gt3(siu.siTG3);

			*(u_long *)  (&siu.siTG3->r0) = *(u_long *) (&opu.opTG3->r0);	// 6 cycles here
			*(u_long *)  (&siu.siTG3->r1) = *(u_long *) (&opu.opTG3->r1);	// 6 cycles here
			*(u_long *)  (&siu.siTG3->r2) = *(u_long *) (&opu.opTG3->r2);

			PUTPACKETINTABLE(siu.siTG3, ot, POLYTG3_LEN);				// Add poly to list
			siu.siTG3++;

			BREAKPRIM;

		default:
			DB("Unsupported LSCAPE poly type %d\n", code);
			modctrl->PrimLeft = 1;
			break;
		}

doneRenderSpecial:
doneRenderSubdivided:

		modctrl->PrimLeft--;
	}

	GsOUT_PACKET_P=siu.packet;
	return;
/**********************/
renderSubdivided:
	// This bit handles the subdivision	which is done on polys close to the camera

		switch(code)
		{
		// note - Even with subdiv of transparencies, it still doesn't subdiv water, coz of tu/tv issues
		case PTYPE_TG4:
			divideFlag=FULLINSIDE;

			if(	(transformedDepths[vert0] > SubDivCtrl.zDepth) &&
				(transformedDepths[vert1] > SubDivCtrl.zDepth) &&
				(transformedDepths[vert2] > SubDivCtrl.zDepth) &&
				(transformedDepths[vert3] > SubDivCtrl.zDepth))
			{
				divideFlag=NOTINSIDE;
				goto renderNormal;
			}

				if(	(transformedDepths[vert0] > SubDivCtrl.zDepth) ||
					(transformedDepths[vert1] > SubDivCtrl.zDepth) ||
					(transformedDepths[vert2] > SubDivCtrl.zDepth) ||
					(transformedDepths[vert3] > SubDivCtrl.zDepth))
					divideFlag=PARTINSIDE;

				*(ULONG*)&rgbNew[0].r=(((opu.opTG4->r0+opu.opTG4->r1)/2))
									 |(((opu.opTG4->g0+opu.opTG4->g1)/2)<<8)
									 |(((opu.opTG4->b0+opu.opTG4->b1)/2)<<16);

				*(ULONG*)&rgbNew[1].r=(((opu.opTG4->r1+opu.opTG4->r3)/2))
									 |(((opu.opTG4->g1+opu.opTG4->g3)/2)<<8)
									 |(((opu.opTG4->b1+opu.opTG4->b3)/2)<<16);

				*(ULONG*)&rgbNew[2].r=(((opu.opTG4->r2+opu.opTG4->r3)/2))
									 |(((opu.opTG4->g2+opu.opTG4->g3)/2)<<8)
									 |(((opu.opTG4->b2+opu.opTG4->b3)/2)<<16);

				*(ULONG*)&rgbNew[3].r=(((opu.opTG4->r0+opu.opTG4->r2)/2))
									 |(((opu.opTG4->g0+opu.opTG4->g2)/2)<<8)
									 |(((opu.opTG4->b0+opu.opTG4->b2)/2)<<16);

				*(ULONG*)&rgbNew[4].r=(((opu.opTG4->r1+opu.opTG4->r2)/2))
									 |(((opu.opTG4->g1+opu.opTG4->g2)/2)<<8)
									 |(((opu.opTG4->b1+opu.opTG4->b2)/2)<<16);


				*(LONG*)&newVerts[4].vx=((USHORT)((verttop[vert0].vx+verttop[vert1].vx+verttop[vert2].vx+verttop[vert3].vx)/4))
  									|((USHORT)((verttop[vert0].vy+verttop[vert1].vy+verttop[vert2].vy+verttop[vert3].vy)/4)<<16);
				newVerts[4].vz=(verttop[vert0].vz+verttop[vert1].vz+verttop[vert2].vz+verttop[vert3].vz)/4;
	
				*(LONG*)&newVerts[0].vx=((USHORT)((verttop[vert0].vx+verttop[vert1].vx)/2))|((USHORT)((verttop[vert0].vy+verttop[vert1].vy)/2)<<16);
				newVerts[0].vz=(verttop[vert0].vz+verttop[vert1].vz)/2;

				*(LONG*)&newVerts[1].vx=((USHORT)((verttop[vert1].vx+verttop[vert3].vx)/2))|((USHORT)((verttop[vert1].vy+verttop[vert3].vy)/2)<<16);
				newVerts[1].vz=(verttop[vert1].vz+verttop[vert3].vz)/2;

				*(LONG*)&newVerts[2].vx=((USHORT)((verttop[vert2].vx+verttop[vert3].vx)/2))|((USHORT)((verttop[vert2].vy+verttop[vert3].vy)/2)<<16);
				newVerts[2].vz=(verttop[vert2].vz+verttop[vert3].vz)/2;

				*(LONG*)&newVerts[3].vx=((USHORT)((verttop[vert0].vx+verttop[vert2].vx)/2))|((USHORT)((verttop[vert0].vy+verttop[vert2].vy)/2)<<16);
			 	newVerts[3].vz=(verttop[vert0].vz+verttop[vert2].vz)/2;

  
				transformVertexList(&newVerts[0], 3, transSubVerts, transSubDepths);

   				*(ULONG *)(&uvStart[0].u)= *(ULONG *)(&opu.opTG4->tu0);
		   		*(ULONG *)(&uvStart[1].u)= *(ULONG *)(&opu.opTG4->tu1);
		   		*(ULONG *)(&uvStart[2].u)= *(ULONG *)(&opu.opTG4->tu2);
		   		*(ULONG *)(&uvStart[3].u)= *(ULONG *)(&opu.opTG4->tu3);

				*(ULONG*)&uv[0].u=(((opu.opTG4->tu0+opu.opTG4->tu1)/2))
								 |(((opu.opTG4->tv0+opu.opTG4->tv1)/2)<<8)
								 |(((opu.opTG4->tu1+opu.opTG4->tu3)/2)<<16)
								 |(((opu.opTG4->tv1+opu.opTG4->tv3)/2)<<24);
	
				*(ULONG*)&uv[2].u=((opu.opTG4->tu2+opu.opTG4->tu3)/2)
								 |(((opu.opTG4->tv2+opu.opTG4->tv3)/2)<<8)
								 |(((opu.opTG4->tu0+opu.opTG4->tu2)/2)<<16)
								 |(((opu.opTG4->tv0+opu.opTG4->tv2)/2)<<24);


				*(USHORT*)&uv[4].u=((opu.opTG4->tu0+opu.opTG4->tu1+opu.opTG4->tu2+opu.opTG4->tu3)/4)
									|(((opu.opTG4->tv0+opu.opTG4->tv1+opu.opTG4->tv2+opu.opTG4->tv3)/4)<<8);
  
				clut0=opu.opTG4->clut;
		 		tpage0=opu.opTG4->tpage;

				siu.packet=divideQuad(opu.opTG4,transformedVerts,transformedDepths,siu.packet);

			BREAKPRIM;
 
		case PTYPE_TG3:
			divideFlag=FULLINSIDE;

			if(	(transformedDepths[vert0] > SubDivCtrl.zDepth) &&
				(transformedDepths[vert1] > SubDivCtrl.zDepth) &&
				(transformedDepths[vert2] > SubDivCtrl.zDepth))
			{
				divideFlag=NOTINSIDE;
				goto renderNormal;
			}

			if(	(transformedDepths[vert0] > SubDivCtrl.zDepth) ||
				(transformedDepths[vert1] > SubDivCtrl.zDepth) ||
				(transformedDepths[vert2] > SubDivCtrl.zDepth))
	   			divideFlag=PARTINSIDE;


 				*(ULONG*)&rgbNew[0]=(((opu.opTG3->r0+opu.opTG3->r1)/2))
 									|(((opu.opTG3->g0+opu.opTG3->g1)/2)<<8)
 									|(((opu.opTG3->b0+opu.opTG3->b1)/2)<<16);
 	
 				*(ULONG*)&rgbNew[1]=(((opu.opTG3->r0+opu.opTG3->r2)/2))
 									|(((opu.opTG3->g0+opu.opTG3->g2)/2)<<8)
 									|(((opu.opTG3->b0+opu.opTG3->b2)/2)<<16);
				*(ULONG*)&rgbNew[2]=(((opu.opTG3->r1+opu.opTG3->r2)/2))
									|(((opu.opTG3->g1+opu.opTG3->g2)/2)<<8)
									|(((opu.opTG3->b1+opu.opTG3->b2)/2)<<16);


				*(LONG*)&newVerts[3].vx=((USHORT)((verttop[vert0].vx+verttop[vert1].vx+verttop[vert2].vx)*2)/3)
									   |((USHORT)(((verttop[vert0].vy+verttop[vert1].vy+verttop[vert2].vy)*2)/3)<<16);
		  		newVerts[3].vz=((verttop[vert0].vz+verttop[vert1].vz+verttop[vert2].vz)*2)/3;

				*(LONG*)&newVerts[0].vx=((USHORT)((verttop[vert0].vx+verttop[vert1].vx)/2))|((USHORT)((verttop[vert0].vy+verttop[vert1].vy)/2)<<16);
				newVerts[0].vz=(verttop[vert0].vz+verttop[vert1].vz)/2;
	
				*(LONG*)&newVerts[1].vx=((USHORT)((verttop[vert0].vx+verttop[vert2].vx)/2))|((USHORT)((verttop[vert0].vy+verttop[vert2].vy)/2)<<16);
				newVerts[1].vz=(verttop[vert0].vz+verttop[vert2].vz)/2;
		
				*(LONG*)&newVerts[2].vx=((USHORT)((verttop[vert1].vx+verttop[vert2].vx)/2))|((USHORT)((verttop[vert1].vy+verttop[vert2].vy)/2)<<16);
				newVerts[2].vz=(verttop[vert1].vz+verttop[vert2].vz)/2;

				transformVertexList(&newVerts[0], 3, transSubVerts, transSubDepths);

				*(ULONG *)(&uvStart[0].u)= *(ULONG *)(&opu.opTG3->tu0);
				*(ULONG *)(&uvStart[1].u)= *(ULONG *)(&opu.opTG3->tu1);
				*(ULONG *)(&uvStart[2].u)= *(ULONG *)(&opu.opTG3->tu2);

				*(ULONG*)&uv[0].u=((opu.opTG3->tu0+opu.opTG3->tu1)/2)
							 |(((opu.opTG3->tv0+opu.opTG3->tv1)/2)<<8)
							 |(((opu.opTG3->tu0+opu.opTG3->tu2)/2)<<16)
							 |(((opu.opTG3->tv0+opu.opTG3->tv2)/2)<<24);
		
				*(USHORT*)&uv[2].u=((opu.opTG3->tu1+opu.opTG3->tu2)/2)|(((opu.opTG3->tv1+opu.opTG3->tv2)/2)<<8);

				tpage0=opu.opTG3->tpage;
  				clut0=opu.opTG3->clut;
				siu.packet=divideTri(opu.opTG3,transformedVerts,transformedDepths,siu.packet);

			BREAKPRIM;


		default:
			DB("Unsupported LSCAPE poly type %d\n", code);
			modctrl->PrimLeft = 1;
			break;
		}

	goto doneRenderSubdivided;

renderSpecial:
	// Do stuff like water, conveyor belts etc.
	// nb. transparent stuff doesn't need/want subdividing

	code=code&1; // mask off all the crap

/*
	if((opu.opGeneric->flags & PMASK_COLOURKEY) && !(opu.opGeneric->flags & PMASK_TEXANIM))
		goto renderNormal;

	if(opu.opGeneric->flags==PMASK_TRANS)	// if it's trans only, we need just render a normal poly.
		goto renderNormal;
*/
	if(!(opu.opGeneric->flags & (PMASK_TEXANIM+PMASK_UVANIM)))	// if it's trans only, we need just render a normal poly.
		goto renderNormal;
//	DB("Rendering %d\n", opu.opGeneric->flags);

	if(opu.opGeneric->flags&PMASK_TEXANIM)	// an animating textured poly must be water or lava
	{
		if(code==PTYPE_TG4)
		{
			//if(opu.opSTG4->texPrg>opu.opSTG4->texFrames)
			//	opu.opSTG4->texPrg=0;

			//spr=(opu.opTG4->spr)+opu.opSTG4->texPrg++;

			spr=(opu.opTG4->spr)+tFrame;

			*(ULONG *)(&siu.siTG4->u0)= ((*(USHORT *)(&spr->u0))+(*(USHORT *)(&opu.opTG4->tu0))) | (spr->clut<<16);
			*(ULONG *)(&siu.siTG4->u1)= ((*(USHORT *)(&spr->u0))+(*(USHORT *)(&opu.opTG4->tu1))) | (((opu.opTG4->tpage & 0x0060) | spr->tpage) <<16);	// preserve transp mode
			*(USHORT *)(&siu.siTG4->u2)=(*(USHORT *)(&spr->u0))+(*(USHORT *)(&opu.opTG4->tu2));
			*(USHORT *)(&siu.siTG4->u3)=(*(USHORT *)(&spr->u0))+(*(USHORT *)(&opu.opTG4->tu3));

			gte_stsxy3_gt4(siu.siTG4);
			*(u_long *)  (&siu.siTG4->x3) = *(u_long *) (&transformedVerts[vert3]);
		
			*(u_long *)  (&siu.siTG4->r0) = *(u_long *) (&opu.opTG4->r0);	// Copy in vertex colours (3 cycles)
			*(u_long *)  (&siu.siTG4->r1) = *(u_long *) (&opu.opTG4->r1);	// 3 cycles here
			*(u_long *)  (&siu.siTG4->r2) = *(u_long *) (&opu.opTG4->r2);
			*(u_long *)  (&siu.siTG4->r3) = *(u_long *) (&opu.opTG4->r3);

			PUTPACKETINTABLE(siu.siTG4, ot, POLYTG4_LEN);				// Add poly to list
			siu.siTG4++;
		}
		else
		{
			//if(opu.opSTG3->texPrg>opu.opSTG3->texFrames)
			//	opu.opSTG3->texPrg=0;

			//spr=(opu.opTG3->spr)+opu.opSTG3->texPrg++;

			spr=(opu.opTG3->spr)+tFrame;

			*(ULONG *)(&siu.siTG3->u0)= ((*(USHORT *)(&spr->u0))+(*(USHORT *)(&opu.opTG3->tu0))) | (spr->clut<<16);
			*(ULONG *)(&siu.siTG4->u1)= ((*(USHORT *)(&spr->u0))+(*(USHORT *)(&opu.opTG4->tu1))) | (((opu.opTG4->tpage & 0x0060) | spr->tpage) <<16);	// preserve transp mode
			*(USHORT *)(&siu.siTG3->u2)=(*(USHORT *)(&spr->u0))+(*(USHORT *)(&opu.opTG3->tu2));

			gte_stsxy3_gt3(siu.siTG3);
		
			*(u_long *)  (&siu.siTG3->r0) = *(u_long *) (&opu.opTG3->r0);	// Copy in vertex colours (3 cycles)
			*(u_long *)  (&siu.siTG3->r1) = *(u_long *) (&opu.opTG3->r1);	// 3 cycles here
			*(u_long *)  (&siu.siTG3->r2) = *(u_long *) (&opu.opTG3->r2);

			PUTPACKETINTABLE(siu.siTG3, ot, POLYTG3_LEN);				// Add poly to list
			siu.siTG3++;
		}

		primPtr+=primSize;
	}
	else
	{
		if(opu.opGeneric->flags&PMASK_UVANIM)
		{
			if(code==PTYPE_TG4)
			{
				char uvFrame=((iframe*(-opu.opSTG4->scrSpeed))/256)&(opu.opSTG4->scrMask);

				ASSERT(primSize==sizeof(TMD_PTYPE_STG4));

		 		*(u_long *)  (&siu.siTG4->u0) = *(u_long *) (&opu.opSTG4->tu0);	// Copy in texture coords
				*(u_long *)  (&siu.siTG4->u1) = *(u_long *) (&opu.opSTG4->tu1);	// 6 cycles here
				*(u_long *)  (&siu.siTG4->u2) = *(u_long *) (&opu.opSTG4->tu2);
				*(u_long *)  (&siu.siTG4->u3) = *(u_long *) (&opu.opSTG4->tu3);

				siu.siTG4->v0+=uvFrame;
				siu.siTG4->v1+=uvFrame;
				siu.siTG4->v2+=uvFrame;
				siu.siTG4->v3+=uvFrame;

				*(u_long *)  (&siu.siTG4->x3) = *(u_long *) (&transformedVerts[vert3]);
				gte_stsxy3_gt4(siu.siTG4);
				*(u_long *)  (&siu.siTG4->r0) = *(u_long *) (&opu.opSTG4->r0);	// Copy in vertex colours (3 cycles)
				*(u_long *)  (&siu.siTG4->r1) = *(u_long *) (&opu.opSTG4->r1);	// 3 cycles here
				*(u_long *)  (&siu.siTG4->r2) = *(u_long *) (&opu.opSTG4->r2);
				*(u_long *)  (&siu.siTG4->r3) = *(u_long *) (&opu.opSTG4->r3);
	
				PUTPACKETINTABLE(siu.siTG4, ot, POLYTG4_LEN);				// Add poly to list
				siu.siTG4++;
			}
			else
			{
				char uvFrame=((iframe*(-opu.opSTG3->scrSpeed))/256)&(opu.opSTG3->scrMask);

				ASSERT(primSize==sizeof(TMD_PTYPE_STG3));

				//spr=opu.opTG3->spr;

				*(u_long *)  (&siu.siTG3->u0) = *(u_long *) (&opu.opTG3->tu0);	// Copy in texture coords	
				*(u_long *)  (&siu.siTG3->u1) = *(u_long *) (&opu.opTG3->tu1);	// 3 cycles here
				*(u_long *)  (&siu.siTG3->u2) = *(u_long *) (&opu.opTG3->tu2);

				siu.siTG3->v0+=uvFrame;
				siu.siTG3->v1+=uvFrame;
				siu.siTG3->v2+=uvFrame;

				gte_stsxy3_gt3(siu.siTG3);

				*(u_long *)  (&siu.siTG3->r0) = *(u_long *) (&opu.opTG3->r0);	// 6 cycles here
				*(u_long *)  (&siu.siTG3->r1) = *(u_long *) (&opu.opTG3->r1);	// 6 cycles here
				*(u_long *)  (&siu.siTG3->r2) = *(u_long *) (&opu.opTG3->r2);

				PUTPACKETINTABLE(siu.siTG3, ot, POLYTG3_LEN);				// Add poly to list
				siu.siTG3++;
			}

			primPtr+=primSize;
		}
	}

	goto doneRenderSpecial;
}


/**************************************************************************
	FUNCTION:	divideTri
	PURPOSE:	Subdivide triangles no cracking checks
	PARAMETERS:	
	RETURNS:	
**************************************************************************/

#define POLYBREAKDEPTHBODGE 40


inline static  PACKET *divideTri(TMD_PTYPE_TG3 *opTG3,long *transformedVerts, long *transformedDepths,PACKET *packet)
{
POLY_GT3		*siTG3;
GsOTA			*ot;
ULONG			depth;
XYSHORT			*xy;
int				deepest;

	(ULONG*)xy=transformedVerts;
	siTG3 = (POLY_GT3 *)packet;
//////////////////////////////////
	gte_ldsz3(transformedDepths[opTG3->v0],transSubDepths[0],transSubDepths[1]);
	*(USHORT *) (&siTG3->tpage)= *(USHORT *) (&tpage0);
	gte_avsz3_b();											// Get Z depth value (5 cycles)
	*(USHORT *) (&siTG3->clut) = *(USHORT *) (&clut0);

	gte_stotz(&depth);										// (1 cycle)
	deepest=depth;
	//	depth/=2;

	STOREMAPTILE;
	INCPOLYSDRAWN;

	*(u_long *)  (&siTG3->r0) = *(u_long *) (&opTG3->r0);
	*(u_long *)  (&siTG3->r1) = *(u_long *) (&rgbNew[0]);
	*(u_long *)  (&siTG3->r2) = *(u_long *) (&rgbNew[1]);

//	siTG3->code = opTG3->code;  //r0 above does the code

	*(u_long *) (&siTG3->x0) = *(u_long *) (&xy[opTG3->v0].x);
	*(u_long *) (&siTG3->x1) = *(u_long *) (&transSubVerts[0]);
	*(u_long *) (&siTG3->x2) = *(u_long *) (&transSubVerts[1]);

	*(USHORT *) (&siTG3->u0) = *(USHORT *) (&uvStart[0]);
	*(USHORT *) (&siTG3->u1) = *(USHORT *) (&uv[0]);
	*(USHORT *) (&siTG3->u2) = *(USHORT *) (&uv[1]);

	PUTPACKETINTABLE(siTG3, ot, POLYTG3_LEN);				// Add poly to list

	siTG3++;

//////////////////////////////////
	gte_ldsz3(transSubDepths[1],transSubDepths[2],transformedDepths[opTG3->v2]);	
	*(USHORT *) (&siTG3->tpage) = *(USHORT *) (&tpage0);
	gte_avsz3_b();											// Get Z depth value (5 cycles)

	*(USHORT *) (&siTG3->clut) = *(USHORT *) (&clut0);
	gte_stotz(&depth);										// (1 cycle)

	if(depth>deepest)
		deepest=depth;

	//	depth/=2;

	STOREMAPTILE;
	INCPOLYSDRAWN;

	*(u_long *) (&siTG3->r0) = *(u_long *) (&rgbNew[1]);
	*(u_long *) (&siTG3->r1) = *(u_long *) (&rgbNew[2]);
	*(u_long *) (&siTG3->r2) = *(u_long *) (&opTG3->r2);

	siTG3->code = opTG3->code;

	*(u_long *) (&siTG3->x0) = *(u_long *) (&transSubVerts[1]);
	*(u_long *) (&siTG3->x1) = *(u_long *) (&transSubVerts[2]);
	*(u_long *) (&siTG3->x2) = *(u_long *) (&xy[opTG3->v2].x);

	*(USHORT *) (&siTG3->u0) = *(USHORT *) (&uv[1]);
	*(USHORT *) (&siTG3->u1) = *(USHORT *) (&uv[2]);
	*(USHORT *) (&siTG3->u2) = *(USHORT *) (&uvStart[2]);

	PUTPACKETINTABLE(siTG3, ot, POLYTG3_LEN);				// Add poly to list
	siTG3++;

//////////////////////////////////
	gte_ldsz3(transSubDepths[0],transformedDepths[opTG3->v1],transSubDepths[2]);	
	*(USHORT *) (&siTG3->tpage) = *(USHORT *) (&tpage0);
	gte_avsz3_b();											// Get Z depth value (5 cycles)
	*(USHORT *) (&siTG3->clut) = *(USHORT *) (&clut0);

	gte_stotz(&depth);										// (1 cycle)

	if(depth>deepest)
		deepest=depth;

//	depth/=2;

	STOREMAPTILE;
	INCPOLYSDRAWN;

	*(u_long *) (&siTG3->r0) = *(u_long *) (&rgbNew[0]);
	*(u_long *) (&siTG3->r1) = *(u_long *) (&opTG3->r1);
	*(u_long *) (&siTG3->r2) = *(u_long *) (&rgbNew[2]);

	siTG3->code = opTG3->code;

	*(u_long *) (&siTG3->x0) = *(u_long *) (&transSubVerts[0]);
	*(u_long *) (&siTG3->x1) = *(u_long *) (&xy[opTG3->v1].x);
	*(u_long *) (&siTG3->x2) = *(u_long *) (&transSubVerts[2]);

	*(USHORT *) (&siTG3->u0) = *(USHORT *) (&uv[0]);
	*(USHORT *) (&siTG3->u1) = *(USHORT *) (&uvStart[1]);
	*(USHORT *) (&siTG3->u2) = *(USHORT *) (&uv[2]);

	PUTPACKETINTABLE(siTG3, ot, POLYTG3_LEN);				// Add poly to list
	siTG3++;

//////////////////////////////////
	gte_ldsz3(transSubDepths[0],transSubDepths[2],transSubDepths[1]);	
	*(USHORT *) (&siTG3->tpage) = *(USHORT *) (&tpage0);
	gte_avsz3_b();											// Get Z depth value (5 cycles)
	*(USHORT *) (&siTG3->clut) = *(USHORT *) (&clut0);

	gte_stotz(&depth);										// (1 cycle)

	if(depth>deepest)
		deepest=depth;

//	depth/=2;

	STOREMAPTILE;
	INCPOLYSDRAWN;

	*(u_long *) (&siTG3->r0) = *(u_long *) (&rgbNew[0]);
	*(u_long *) (&siTG3->r1) = *(u_long *) (&rgbNew[2]);
	*(u_long *) (&siTG3->r2) = *(u_long *) (&rgbNew[1]);

	siTG3->code = opTG3->code;

	*(u_long *) (&siTG3->x0) = *(u_long *) (&transSubVerts[0]);
	*(u_long *) (&siTG3->x1) = *(u_long *) (&transSubVerts[2]);
	*(u_long *) (&siTG3->x2) = *(u_long *) (&transSubVerts[1]);

	*(USHORT *) (&siTG3->u0) = *(USHORT *) (&uv[0]);
	*(USHORT *) (&siTG3->u1) = *(USHORT *) (&uv[2]);
	*(USHORT *) (&siTG3->u2) = *(USHORT *) (&uv[1]);

	PUTPACKETINTABLE(siTG3, ot, POLYTG3_LEN);				// Add poly to list
	siTG3++;
/****/
  	if (divideFlag==PARTINSIDE) //print the Un-subdivided poly underneath
	{

		//gte_ldsz3(transformedDepths[opTG3->v0],transformedDepths[opTG3->v1],transformedDepths[opTG3->v2]);
		*(USHORT *) (&siTG3->tpage)= *(USHORT *) (&tpage0);
		//gte_avsz3();											// Get Z depth value (5 cycles)
		*(USHORT *) (&siTG3->clut) = *(USHORT *) (&clut0);

		//gte_stotz(&depth);										// (1 cycle)
		//	depth/=2;
		//	depth+=POLYBREAKDEPTHBODGE;

		depth=deepest+1;	// plot the underneath poly at just deeper than the deepest of the subdivided ones
							// there's no need to do a GTE average of the points.

		STOREMAPTILE;
		INCPOLYSDRAWN;

		*(u_long *)  (&siTG3->r0) = *(u_long *) (&opTG3->r0);
		*(u_long *)  (&siTG3->r1) = *(u_long *) (&opTG3->r1);
		*(u_long *)  (&siTG3->r2) = *(u_long *) (&opTG3->r2);
	
   		//siTG3->code = opTG3->code; //r0 above does code

		*(u_long *) (&siTG3->x0) = *(u_long *) (&xy[opTG3->v0].x);
		*(u_long *) (&siTG3->x1) = *(u_long *) (&xy[opTG3->v1].x);
		*(u_long *) (&siTG3->x2) = *(u_long *) (&xy[opTG3->v2].x);

		*(USHORT *) (&siTG3->u0) = *(USHORT *) (&uvStart[0]);
		*(USHORT *) (&siTG3->u1) = *(USHORT *) (&uvStart[1]);
		*(USHORT *) (&siTG3->u2) = *(USHORT *) (&uvStart[2]);

		PUTPACKETINTABLE(siTG3, ot, POLYTG3_LEN);				// Add poly to list
		siTG3++;
  	}
	packet=(PACKET *)siTG3;
	return(packet);
/*******/
}

/**************************************************************************
	FUNCTION:	divideQuad
	PURPOSE:	Subdivide quads no cracking checks
	PARAMETERS:	
	RETURNS:	
**************************************************************************/

inline static  PACKET *divideQuad(TMD_PTYPE_TG4 *opTG4,long *transformedVerts, long *transformedDepths,PACKET *packet)
{
POLY_GT4		*siTG4;
GsOTA			*ot;
LONG			depth;
XYSHORT			*xy;
int				deepest;

	(ULONG*)xy=transformedVerts;
  	siTG4 = (POLY_GT4 *)packet;
/////////////////////////////////////////
	gte_ldsz4(transformedDepths[opTG4->v0],transSubDepths[0],transSubDepths[3],transSubDepths[4]);
	*(USHORT *)  (&siTG4->tpage) = *(USHORT *) (&tpage0);
   	gte_avsz4();		   // Get Z depth value (5 cycles)
	*(USHORT *)  (&siTG4->clut) = *(USHORT *) (&clut0);

	gte_stotz(&depth);
	deepest=depth;
//	depth/=2;	
	STOREMAPTILE;
	INCPOLYSDRAWN;

	*(u_long *)  (&siTG4->r0) = *(u_long *) (&opTG4->r0);
	*(u_long *)  (&siTG4->r1) = *(u_long *) (&rgbNew[0]);
	*(u_long *)  (&siTG4->r2) = *(u_long *) (&rgbNew[3]);
	*(u_long *)  (&siTG4->r3) = *(u_long *) (&rgbNew[4]);

//	siTG4->code = opTG4->code; //r0 above did the code

	*(u_long *) (&siTG4->x0) = *(u_long *) (&xy[opTG4->v0].x);
	*(u_long *) (&siTG4->x1) = *(u_long *) (&transSubVerts[0]);
	*(u_long *) (&siTG4->x2) = *(u_long *) (&transSubVerts[3]);
	*(u_long *) (&siTG4->x3) = *(u_long *) (&transSubVerts[4]);

	*(USHORT *)  (&siTG4->u0) = *(USHORT *) (&uvStart[0]);
	*(USHORT *)  (&siTG4->u1) = *(USHORT *) (&uv[0]);
	*(USHORT *)  (&siTG4->u2) = *(USHORT *) (&uv[3]);
	*(USHORT *)  (&siTG4->u3) = *(USHORT *) (&uv[4]);

	PUTPACKETINTABLE(siTG4, ot, POLYTG4_LEN);				// Add poly to list
	siTG4++;
/////////////////////////////////////////
	gte_ldsz4(transformedDepths[opTG4->v1],transSubDepths[4],transSubDepths[1],transSubDepths[0]);
	*(USHORT *)  (&siTG4->tpage) = *(USHORT *) (&tpage0);
   	gte_avsz4();			// Get Z depth value (5 cycles)
	*(USHORT *)  (&siTG4->clut) = *(USHORT *) (&clut0);

	gte_stotz(&depth);
	if(depth>deepest)
		deepest=depth;

//	depth/=2;

	STOREMAPTILE;
	INCPOLYSDRAWN;

	*(u_long *)  (&siTG4->r0) = *(u_long *) (&rgbNew[0]);
	*(u_long *)  (&siTG4->r1) = *(u_long *) (&opTG4->r1);
	*(u_long *)  (&siTG4->r2) = *(u_long *) (&rgbNew[4]);
	*(u_long *)  (&siTG4->r3) = *(u_long *) (&rgbNew[1]);

	siTG4->code = opTG4->code;

	*(u_long *) (&siTG4->x0) = *(u_long *) (&transSubVerts[0]);
	*(u_long *) (&siTG4->x1) = *(u_long *) (&xy[opTG4->v1].x);
	*(u_long *) (&siTG4->x2) = *(u_long *) (&transSubVerts[4]);
	*(u_long *) (&siTG4->x3) = *(u_long *) (&transSubVerts[1]);

	*(USHORT *)  (&siTG4->u0) = *(USHORT *) (&uv[0]);
	*(USHORT *)  (&siTG4->u1) = *(USHORT *) (&uvStart[1]);		
	*(USHORT *)  (&siTG4->u2) = *(USHORT *) (&uv[4]);
	*(USHORT *)  (&siTG4->u3) = *(USHORT *) (&uv[1]);

	PUTPACKETINTABLE(siTG4, ot, POLYTG4_LEN);				// Add poly to list
	siTG4++;

/////////////////////////////////////////
	gte_ldsz4(transformedDepths[opTG4->v2],transSubDepths[3],transSubDepths[4],transSubDepths[2]);
	*(USHORT *)  (&siTG4->tpage) = *(USHORT *) (&tpage0);
   	gte_avsz4();											// Get Z depth value (5 cycles)

	*(USHORT *)  (&siTG4->clut) = *(USHORT *) (&clut0);

	gte_stotz(&depth);
	if(depth>deepest)
		deepest=depth;

//	depth/=2;	

	STOREMAPTILE;
	INCPOLYSDRAWN;
 
	*(u_long *)  (&siTG4->r0) = *(u_long *) (&rgbNew[3]);
	*(u_long *)  (&siTG4->r1) = *(u_long *) (&rgbNew[4]);
	*(u_long *)  (&siTG4->r2) = *(u_long *) (&opTG4->r2);
	*(u_long *)  (&siTG4->r3) = *(u_long *) (&rgbNew[2]);

	siTG4->code = opTG4->code;

	*(u_long *) (&siTG4->x0) = *(u_long *) (&transSubVerts[3]);
	*(u_long *) (&siTG4->x1) = *(u_long *) (&transSubVerts[4]);
	*(u_long *) (&siTG4->x2) = *(u_long *) (&xy[opTG4->v2].x);
	*(u_long *) (&siTG4->x3) = *(u_long *) (&transSubVerts[2]);

	*(USHORT *)  (&siTG4->u0) = *(USHORT *) (&uv[3]);
	*(USHORT *)  (&siTG4->u1) = *(USHORT *) (&uv[4]);
	*(USHORT *)  (&siTG4->u2) = *(USHORT *) (&uvStart[2]);
	*(USHORT *)  (&siTG4->u3) = *(USHORT *) (&uv[2]);

	PUTPACKETINTABLE(siTG4, ot, POLYTG4_LEN);				// Add poly to list
	siTG4++;

/////////////////////////////////////////
	gte_ldsz4(transformedDepths[opTG4->v3],transSubDepths[4],transSubDepths[1],transSubDepths[2]);
	*(USHORT *)  (&siTG4->tpage) = *(USHORT *) (&tpage0);
   	gte_avsz4();											// Get Z depth value (5 cycles)
	*(USHORT *)  (&siTG4->clut) = *(USHORT *) (&clut0);

	gte_stotz(&depth);
	if(depth>deepest)
		deepest=depth;

//	depth/=2;	

	STOREMAPTILE;
	INCPOLYSDRAWN;

	*(u_long *)  (&siTG4->r0) = *(u_long *) (&rgbNew[4]);
	*(u_long *)  (&siTG4->r1) = *(u_long *) (&rgbNew[1]);
	*(u_long *)  (&siTG4->r2) = *(u_long *) (&rgbNew[2]);
	*(u_long *)  (&siTG4->r3) = *(u_long *) (&opTG4->r3);

	siTG4->code = opTG4->code;

	*(u_long *) (&siTG4->x0) = *(u_long *) (&transSubVerts[4]);
	*(u_long *) (&siTG4->x1) = *(u_long *) (&transSubVerts[1]);
	*(u_long *) (&siTG4->x2) = *(u_long *) (&transSubVerts[2]);
	*(u_long *) (&siTG4->x3) = *(u_long *) (&xy[opTG4->v3].x);

	*(USHORT *)  (&siTG4->u0) = *(USHORT *) (&uv[4]);
	*(USHORT *)  (&siTG4->u1) = *(USHORT *) (&uv[1]);
	*(USHORT *)  (&siTG4->u2) = *(USHORT *) (&uv[2]);
	*(USHORT *)  (&siTG4->u3) = *(USHORT *) (&uvStart[3]);

	PUTPACKETINTABLE(siTG4, ot, POLYTG4_LEN);				// Add poly to list
	siTG4++;
/////////////////////////////////////////

  	if (divideFlag==PARTINSIDE)	//print the un-subdivided poly behind
	{
//		gte_ldsz4(transformedDepths[opTG4->v0],transformedDepths[opTG4->v1],transformedDepths[opTG4->v2],transformedDepths[opTG4->v3]);
		*(USHORT *)  (&siTG4->tpage) = *(USHORT *) (&tpage0);
//	   	gte_avsz4();											// Get Z depth value (5 cycles)
		*(USHORT *)  (&siTG4->clut) = *(USHORT *) (&clut0);

//		gte_stotz(&depth);										
//		depth/=2;	
//		depth+=POLYBREAKDEPTHBODGE;

		depth=deepest+1;	// plot the underneath poly at just deeper than the deepest of the subdivided ones
							// there's no need to do a GTE average of the points.
		STOREMAPTILE;
		INCPOLYSDRAWN;

		*(u_long *)  (&siTG4->r0) = *(u_long *) (&opTG4->r0);
		*(u_long *)  (&siTG4->r1) = *(u_long *) (&opTG4->r1);
		*(u_long *)  (&siTG4->r2) = *(u_long *) (&opTG4->r2);
		*(u_long *)  (&siTG4->r3) = *(u_long *) (&opTG4->r3);

	//	siTG4->code = opTG4->code;   //r0 above does code

		*(u_long *) (&siTG4->x0) = *(u_long *) (&xy[opTG4->v0].x);
		*(u_long *) (&siTG4->x1) = *(u_long *) (&xy[opTG4->v1].x);
		*(u_long *) (&siTG4->x2) = *(u_long *) (&xy[opTG4->v2].x);
		*(u_long *) (&siTG4->x3) = *(u_long *) (&xy[opTG4->v3].x);

		*(USHORT *)  (&siTG4->u0) = *(USHORT *) (&uvStart[0]);
		*(USHORT *)  (&siTG4->u1) = *(USHORT *) (&uvStart[1]);
		*(USHORT *)  (&siTG4->u2) = *(USHORT *) (&uvStart[2]);
		*(USHORT *)  (&siTG4->u3) = *(USHORT *) (&uvStart[3]);

		PUTPACKETINTABLE(siTG4, ot, POLYTG4_LEN);				// Add poly to list
		siTG4++;
	
	}

	packet = (PACKET *)siTG4;
	return(packet);
}


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


void lscapeInit(void)
{
	transVerts=(long *)MALLOC(sizeof(long)*(MAXSEGMENTVERTS+10), "transVerts");
	transDepths=(long *)MALLOC(sizeof(long)*(MAXSEGMENTVERTS+10), "transDepths");

	//transSubVerts=(long *)MALLOC(sizeof(long)*10, "transSubVerts");
	//transSubDepths=(long *)MALLOC(sizeof(long)*10, "transSubDepths");

	transSubVerts=transVerts+MAXSEGMENTVERTS;
	transSubDepths=transDepths+MAXSEGMENTVERTS;

	SETSUBDIVDEPTH(SUBDIVISIONDEPTH);
}

/**************************************************************************
	FUNCTION:	lscapeDraw()
	PURPOSE:	Draw a landscape object (with proper depth sort)
	PARAMETERS:	Model structure
	RETURNS:	
**************************************************************************/

// Values for rotFlag:
//		LSCAPE_ROTATEMODEL
//		LSCAPE_DRAWMODEL

// Returns true if object was drawn, false if it was clipped
int lscapeDrawClipped(NEWMODEL *pModel, MATRIX *pMatrix, int rotFlag)
{
	ULONG check,totalchecks,subDivFlag;
	XYSHORT			*xy;
	int v;
	int nClips=0;
	int usefog;

	ASSERT(pMatrix);

	if(rotFlag & LSCAPE_ROTATEMODEL)
	{
		MATRIX		rotmat1;

		for(v=0; v<8; v++)
		{		// cunning way to build a bounding box
			pBBox[v].vx=(v&1)?pModel->world.meshdata->boundminx:pModel->world.meshdata->boundmaxx;
			pBBox[v].vy=(v&2)?pModel->world.meshdata->boundminy:pModel->world.meshdata->boundmaxy;
			pBBox[v].vz=(v&4)?pModel->world.meshdata->boundminz:pModel->world.meshdata->boundmaxz;
		}


		RotMatrixYXZ_gte(&pModel->world.rotate,&rotmat1);
		gte_MulMatrix0(&GsWSMATRIX,&rotmat1,&pModel->world.matrixscale);

		gte_SetRotMatrix(&GsWSMATRIX);
		gte_SetTransMatrix(&GsWSMATRIX);
		gte_ldlvl(&pModel->position);

//		modctrl->VertTop = (VERT*)(world->meshdata->vertop);
		
		gte_rtirtr();

//		(NORM*)modctrl->NormTop = world->meshdata->nortop;
//		modctrl->PrimTop = world->meshdata->primtop;
//		modctrl->PrimLeft = world->meshdata->primn;

		gte_stlvl(&pModel->world.matrixscale.t);

	   	gte_SetRotMatrix(&pModel->world.matrixscale);
	   	gte_SetTransMatrix(&pModel->world.matrixscale);

//		gte_ldlvl(&world->model.position);

	}
	else
	{
		for(v=0; v<8; v++)
		{		// cunning way to build a bounding box
			pBBox[v].vx=(v&1)?pModel->world.meshdata->boundminx:pModel->world.meshdata->boundmaxx;
			pBBox[v].vy=(v&2)?pModel->world.meshdata->boundminy:pModel->world.meshdata->boundmaxy;
			pBBox[v].vz=(v&4)?pModel->world.meshdata->boundminz:pModel->world.meshdata->boundmaxz;

			pBBox[v].vx+=pModel->position.vx;
			pBBox[v].vy+=pModel->position.vy;
			pBBox[v].vz+=pModel->position.vz;
		}

		gte_SetRotMatrix(pMatrix);
		gte_SetTransMatrix(pMatrix);
	}

	ASSERT(transVerts);
	ASSERT(transDepths);

	transformVertexList(pBBox, 9, transVerts, transDepths);

	(ULONG*)xy=transVerts;
	nClips=0;
	//printf("\n");
	totalchecks=0xffff;
	subDivFlag=0;
	usefog = 0;
	for(v=0; v<8; v++)
	{
		check=0;
		if(xy[v].x<-256)check|=OFFLEFT;
		if(xy[v].x>256 )check|=OFFRIGHT;
		if(xy[v].y<-128)check|=OFFUP;
		if(xy[v].y>128 )check|=OFFDOWN;
	  	if(transDepths[v]<=0)check|=OFFFRONT;
//	  	if(transDepths[v]>16032)check|=OFFBACK;

		if(transDepths[v]>lscapeFogFlatZ)
			check |= OFFBACK;
	  	if(transDepths[v]>lscapeFogStartZ)
			usefog = 1;

		//if(transDepths[v]<=SubDivCtrl.otzDepth)
		//	subDivFlag=modelctrl.subdivflag;

		totalchecks&=check;
	}

	if(totalchecks==0)
	{

#ifdef SUBDIVISION
		modelctrl.subdivide=subDivFlag;
#else
		modelctrl.subdivide=0;
#endif
		if(rotFlag & LSCAPE_DRAWMODEL)
		{
			if(rotFlag & LSCAPE_ROTATEMODEL)
				lscapeDrawRotate(pModel,usefog);//,usefog);
			else
				lscapeDraw(pModel,usefog);
		}

		return TRUE;
	}
 	else
	{
		return FALSE;
	}
}

/**************************************************************************
	FUNCTION:	lscapeDraw()
	PURPOSE:	Draw a landscape object (with proper depth sort)
	PARAMETERS:	Model structure
	RETURNS:	
**************************************************************************/

void lscapeDraw(NEWMODEL *model, int usefog)
{
	NEWOBJECT	*world;
	MODELCTRL	*modctrl=&modelctrl;
	ULONG		vertLoopTop;
	ULONG		numVerts;
	long *transformedVerts, *transformedDepths;

	gte_SetRotMatrix(&GsWSMATRIX);
	gte_SetTransMatrix(&GsWSMATRIX);

	world = &model->world;
	ASSERT(world);
	modctrl->VertTop = (VERT*)(world->meshdata->vertop);
	numVerts = world->meshdata->vern;

	vertLoopTop = numVerts + (3 - (numVerts % 3));
	
   	transformedVerts = transVerts;
   	transformedDepths = transDepths;

// fix for the end of fear3, where there's models with postition = (0,0,0) that manage to
// get horribly confused if run through this bit of transformation code
	if(model->position.vx != 0 || model->position.vy != 0 || model->position.vz != 0)
	{
		gte_ldlvl(&model->position);
//		gte_rtirtr_b();
		gte_rtirtr();
		world->matrixscale = GsWSMATRIX;
		gte_stlvl(&world->matrixscale.t);
   		gte_SetRotMatrix(&world->matrixscale);
   		gte_SetTransMatrix(&world->matrixscale);
	}

	(NORM *)modctrl->NormTop =world->meshdata->nortop;
	modctrl->PrimTop = world->meshdata->primtop;
	modctrl->PrimLeft = world->meshdata->primn;


// not used anywhere anyway
//	modelctrl.originX = model->position.vx;
//	modelctrl.originY = model->position.vy;
//	modelctrl.originZ = model->position.vz;


	if(TOOMANYPOLYS(modctrl->PrimLeft*MAXPACKETSIZE,"<Lscapedraw>"))return;

	transformVertices(model,transformedVerts,transformedDepths);
	if (model==pSky)
	{
		renderSkyModel(transformedVerts,transformedDepths);
	}
	else{
		if(usefog)	renderFoggedLandscapeModel(transformedVerts,transformedDepths);
		else  		renderLandscapeModel(transformedVerts,transformedDepths);
	}
}

/**************************************************************************
	FUNCTION:	lscapeDrawRotate()
	PURPOSE:	Draw a landscape object (with proper depth sort), can rotate
	PARAMETERS:	Model structure
	RETURNS:	
**************************************************************************/

void lscapeDrawRotate(NEWMODEL *model, int usefog)
{
	NEWOBJECT	*world;
	MODELCTRL	*modctrl=&modelctrl;
	MATRIX		rotmat1;
	ULONG		flat=NO;
	ULONG		numVerts, vertLoopTop;
	long *transformedVerts, *transformedDepths;

	world = &model->world;

	numVerts = world->meshdata->vern;

	vertLoopTop = numVerts + (3 - (numVerts % 3));
	
  	transformedVerts = transVerts;
	transformedDepths = transDepths;

	if(!flat)
	{
		RotMatrixYXZ_gte(&world->rotate,&rotmat1);
		gte_MulMatrix0(&GsWSMATRIX,&rotmat1,&world->matrixscale);
	}
	else
	{
		world->matrixscale=GsIDMATRIX;
	}

	gte_SetRotMatrix(&GsWSMATRIX);
	gte_SetTransMatrix(&GsWSMATRIX);
	gte_ldlvl(&model->position);

	modctrl->VertTop = (VERT*)(world->meshdata->vertop);
	
	gte_rtirtr_b();

	(NORM*)modctrl->NormTop = world->meshdata->nortop;
	modctrl->PrimTop = world->meshdata->primtop;
	modctrl->PrimLeft = world->meshdata->primn;

	gte_stlvl(&world->matrixscale.t);

   	gte_SetRotMatrix(&world->matrixscale);
   	gte_SetTransMatrix(&world->matrixscale);

	if(TOOMANYPOLYS(modctrl->PrimLeft*MAXPACKETSIZE,"<Lscapedrawrotate>"))return;

	transformVertices(model, transformedVerts, transformedDepths);
	if (model==pSky)
	{
		renderSkyModel(transformedVerts,transformedDepths);
	}
	else{
		if(usefog)	renderFoggedLandscapeModel(transformedVerts,transformedDepths);
		else  		renderLandscapeModel(transformedVerts,transformedDepths);
	}
}

/**************************************************************************
	FUNCTION:	lscapeDrawBoundPoly()
	PURPOSE:	highlights the collision polys
	PARAMETERS:	
	RETURNS:	
**************************************************************************/

void lscapeDrawBoundPoly(int numPoints, Point2DType *points, int height, uchar r,uchar g,uchar b)
{
	long screen;
	VERT v0,v1;
	ULONG loop;

	for(loop=0; loop < numPoints; loop++)
	{
		polyLine.r0=r;
		polyLine.b0=g;
		polyLine.g0=b;
		
		v0.vx=points[loop].x;
		v0.vy=height;		 
		v0.vz=points[loop].y;

		v1.vx=points[(loop+1)MOD numPoints].x;
		v1.vy=height;		 
		v1.vz=points[(loop+1)MOD numPoints].y;

	   	gte_SetRotMatrix(&GsWSMATRIX);
		gte_SetTransMatrix(&GsWSMATRIX);

		Get_Screenxy(&v0,&screen);
		polyLine.x0=(screen &0xffff);
		polyLine.y0=(screen>>16);

		Get_Screenxy(&v1,&screen);
		polyLine.x1=(screen &0xffff);
		polyLine.y1=(screen>>16);

//		polyDrawLine(1);			

		polyDrawLineClipped(polyLine.x0,polyLine.y0,polyLine.x1,polyLine.y1,r,g,b,1);

	}
}




void lscapeSetTerrainPlat(DYNCOLLBOX *plat, int terrain)
{
	int i;
	static int remaps[] =
	{
		0,			//	STONE,
		-1,			//	GRASS,
		C_ICE,			//	ICE,
		-1,				//	MUD,
		-1,				//	SAND,
		C_WATERY,		//	WATERY,
		C_LAVA,			//	LAVA,
		C_STICKY,		//	STICKY,
		-1,				//	SLIDY,
		C_SPIKE,				//	GOO,	-> spikes
		C_SNOW,			//	SNOW,
		C_SNOWANDICE,		//	ICYSNOW,
		-1,				//	FORCE_FIELD,
		C_MEGASTICKY,	//	STICKY2,		// new
		-1,				//	UNDERWATER,
	};


	if(terrain < 15 && remaps[terrain] != -1)
	{
		for(i = 0; i < plat->nCollBoxes; i++)
		{
	// preserve the "move" stuff
//			plat->pBoxes[i].flags = (plat->pBoxes[i].flags & MOVE) | remaps[terrain];

// oops. Preserve the move AND the box type, or else!
			plat->pBoxes[i].flags = (plat->pBoxes[i].flags & 0x1ff) | remaps[terrain];
		}
	}
}

void lscapeSetTerrainTag(int tag, int terrain)
{
	int i;

// terrain type -> collide data remap type lookup table
// note - THIS ONLY WORKS ON PLATFORMS, whereas the
// visible "water/underwater" thing also works on landscape


// Setting the visibility stuff on landscape objects
	if(pWld)
	{
		for(i = 0; i < pWld->nZones; i++)
		{
			if(pWld->pZones[i].tag == tag)
			{
	//			printf("terrain set to %d\n",terrain);
				pWld->pZones[i].terrain = terrain;
			}
		}
	}


// Setting the interaction info on platform objects
//	if(terrain < 15 && remaps[terrain] != -1)
	{
		DYNCOLLBOX *plat;

		loadlndFindPlatform(tag, NULL, &plat);
		if(plat)
		{
			lscapeSetTerrainPlat(plat, terrain);
			plat->pPlatDef->head.terrain=terrain;
		}
	}
}

/**************************************************************************
	FUNCTION:	lscapeDrawBoundPoly3D()
	PURPOSE:	highlights the collision polys
	PARAMETERS:	
	RETURNS:	
**************************************************************************/

void lscapeDrawBoundPoly3D(int numPoints, Point3DType *points, uchar r,uchar g,uchar b)
{
	long screen;
	VERT v0,v1;
	ULONG loop;
	long d0,d1;

	for(loop=0; loop < numPoints; loop++)
	{
		polyLine.r0=r;
		polyLine.b0=g;
		polyLine.g0=b;

		v0.vx=points[loop].x;
		v0.vy=points[loop].y;		 
		v0.vz=points[loop].z;

		v1.vx=points[(loop+1)MOD numPoints].x;
		v1.vy=points[(loop+1)MOD numPoints].y; 
		v1.vz=points[(loop+1)MOD numPoints].z;

	   	gte_SetRotMatrix(&GsWSMATRIX);
		gte_SetTransMatrix(&GsWSMATRIX);

		d0=Find_Screen_Depth(&v0);
		d1=Find_Screen_Depth(&v1);

		if(d0<0) continue;
		if(d1<0) continue;

		Get_Screenxy(&v0,&screen);	// do inline!
		polyLine.x0=(screen &0xffff);
		polyLine.y0=(screen>>16);

		Get_Screenxy(&v1,&screen);
		polyLine.x1=(screen &0xffff);
		polyLine.y1=(screen>>16);

//		polyDrawLine(1);			
		polyDrawLineClipped(polyLine.x0,polyLine.y0,polyLine.x1,polyLine.y1,r,g,b,((d0+d1)/2)-8);
	}
}


void lscapeSetTerrainDepthOffset(int terrain)
{
// tricksy judging of values ahoy...
// (with watery at 18...)
// 24 can't handle the end trough on at2, 26 can't cope with pi1,
// 32 not *quite*, 36 is touch & go at times
// 40 starts to show the floor on at2 through the water
// 38's ok there (though you can see the drains in the entry bit where you shouldn't)

	if(terrain == WATERY)	// watery
		DEPTHOFFS = 18*2;
	else if(terrain == UNDERWATER)
	{
		if(level == ATLANTIS3)
			DEPTHOFFS = 80*2;
		else
			DEPTHOFFS = 38*2;
	}
	else
		DEPTHOFFS = 16*2;

}

