
/******************************************************************************************
	CRTest PS   (c) 1999-2001 ISL

	overlays.c:			Debug graphics, sprites, etc
******************************************************************************************/

#include "global.h"
#include "map_draw.h"
#include "maths.h"
#include "overlays.h"
#include "collide.h"
#include "platform.h"
#include "main.h"
#include "debris.h"
#include "custom.h"
//#include "text_ids.h"

void transformVertexListA(VERT *vertPtr, long numVerts, long *transformedVerts, long *transformedDepths);

#undef NULL
#define NULL 0

USHORT overlaySolidAlphaClut = 0;
USHORT overlayAlphaClut = 0;
USHORT overlayAlphaClut256 = 0;
extern unsigned short textureAddCLUT256(unsigned short *palette);
char overlay_debug_message_text[80];
int overlay_debug_messagetime = 0;

#define DARK_EGG		// subrtactive egg rather than additive
#define OUTSIDE_EGG		// egg seethrough, outside masked

// Used to be 200 * 8, but that caused GPU ov's
#define DEBUG_OVERLAY_SUBDIV_SIZE (200 * 16)

typedef struct
{
	short x;
	short y;
}XYSHORT;
#define OFFLEFT		1
#define OFFRIGHT	2
#define OFFUP		4
#define OFFDOWN		8
#define OFFFRONT	16
#define OFFBACK		32
extern GsRVIEW2	mycamera;

void overlayShowDebugLine(VECTOR *v1, VECTOR *v2, unsigned int bgr, int flags)
{
	VERT tempvert[2];
	XYSHORT *xy;
	int i;
	int depth;
	ULONG check,totalchecks;


	gte_SetRotMatrix(&GsWSMATRIX);
	gte_SetTransMatrix(&GsWSMATRIX);
	tempvert[0].vx = v1->vx - mycamera.vpx;
	tempvert[0].vy = v1->vy - mycamera.vpy;
	tempvert[0].vz = v1->vz - mycamera.vpz;
	tempvert[1].vx = v2->vx - mycamera.vpx;
	tempvert[1].vy = v2->vy - mycamera.vpy;
	tempvert[1].vz = v2->vz - mycamera.vpz;

	(ULONG*)xy=transformedVertices;
	transformVertexListA(tempvert, 2, transformedVertices, transformedDepths);
	totalchecks=0xffff;

	depth = 0;
	for(i=0; i<2; i++)
	{
		check=0;
		if(xy[i].x<-256)check|=OFFLEFT;
		if(xy[i].x>256 )check|=OFFRIGHT;
		if(xy[i].y<-128)check|=OFFUP;
		if(xy[i].y>128 )check|=OFFDOWN;
	  	if(transformedDepths[i]<=0)
		{
			check|=OFFFRONT;
		}

//	  	if(transformedDepths[i]>16032)check|=OFFBACK;
		totalchecks&=check;
		depth += transformedDepths[i];
	}
	if(totalchecks != 0)
		return;

	if(flags & DEBUGPOLY_SUBDIV)
	{
		VECTOR diff;
		int m;
		SUBVECTOR(&diff,v1,v2);
		m = Magnitude(&diff);
		if(m > DEBUG_OVERLAY_SUBDIV_SIZE)
		{
			VECTOR v1b;
			VECTOR v2b;
			v1b = *v1;
			v2b.vx = (v1->vx + v2->vx) / 2;
			v2b.vy = (v1->vy + v2->vy) / 2;
			v2b.vz = (v1->vz + v2->vz) / 2;
			overlayShowDebugLine(&v1b, &v2b, bgr, flags);
			v1b = *v2;
			overlayShowDebugLine(&v1b, &v2b, bgr, flags);
			return;
		}
	}


	if(!(flags & DEBUGPOLY_USEDEPTH))
	{
		depth = 10;
	}
	else
	{
		depth /= 2;
		depth >>= (3+2);
		depth -= 15;
		if (depth < 0) depth = 0;
		if (depth > 1023) depth = 1023;
	}

	{
		LINE_F2 *line;
		BEGINPRIM(line, LINE_F2);
		*(u_long *)&line->x0 = *(u_long *)&transformedVertices[0];
		*(u_long *)&line->x1 = *(u_long *)&transformedVertices[1];
		setRGB0(line, (bgr >> 16) & 255, (bgr >> 8) & 255, (bgr) & 255);
		setLineF2(line);
		ENDPRIM(line, depth, LINE_F2);
	}
}

// Draw a semitrans poly over the background scenery.
// Optional border white.
// Large polygons can be shown subdivided if required.
void overlayShowDebugPolygon(VECTOR *worldvecs, int n_verts, unsigned int bgr, int flags)
{
	VERT tempvert[12];
	int i;
	XYSHORT *xy;
	ULONG check,totalchecks;
	long	clipflag;
	int depth;
	int edgecheck;

	return;//MIKEY


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

	for(i = 0; i < n_verts; i++)
	{
		int temp;
		temp = worldvecs[i].vx - mycamera.vpx;
		if( temp > 0x7fff || temp < -0x7fff)
			return;
		tempvert[i].vx = temp;

		temp = worldvecs[i].vy - mycamera.vpy;
		if( temp > 0x7fff || temp < -0x7fff)
			return;
		tempvert[i].vy = temp;

		temp = worldvecs[i].vz - mycamera.vpz;
		if( temp > 0x7fff || temp < -0x7fff)
			return;
		tempvert[i].vz = temp;

	}

	(ULONG*)xy=transformedVertices;
	transformVertexListA(tempvert, n_verts, transformedVertices, transformedDepths);
	totalchecks=0xffff;

	depth = 0;
	for(i=0; i<n_verts; i++)
	{
		check=0;
		if(xy[i].x<-256)check|=OFFLEFT;
		if(xy[i].x>256 )check|=OFFRIGHT;
		if(xy[i].y<-128)check|=OFFUP;
		if(xy[i].y>128 )check|=OFFDOWN;
	  	if(transformedDepths[i]<=0)
		{
			check|=OFFFRONT;
		}

//	  	if(transformedDepths[i]>16032)check|=OFFBACK;
		totalchecks&=check;
		depth += transformedDepths[i];
	}
	if(totalchecks != 0)
		return;

// Subdivision, because some of these collision boxes are bloody huge...

	if(flags & DEBUGPOLY_SUBDIV)
	{
		int minx,maxx,miny,maxy,minz,maxz;
		int maxdim;
		int e;
		minx = maxx = worldvecs[0].vx;
		miny = maxy = worldvecs[0].vy;
		minz = maxz = worldvecs[0].vz;
		for(i = 1; i < n_verts; i++)
		{
			if(worldvecs[i].vx > maxx) maxx = worldvecs[i].vx;
			if(worldvecs[i].vy > maxy) maxy = worldvecs[i].vy;
			if(worldvecs[i].vz > maxz) maxz = worldvecs[i].vz;
			if(worldvecs[i].vx < minx) minx = worldvecs[i].vx;
			if(worldvecs[i].vy < miny) miny = worldvecs[i].vy;
			if(worldvecs[i].vz < minz) minz = worldvecs[i].vz;
		}
		maxdim = maxx-minx;
		if(maxy-miny > maxdim) maxdim = maxy-miny;
		if(maxz-minz > maxdim) maxdim = maxz-minz;

		if(maxdim > DEBUG_OVERLAY_SUBDIV_SIZE)
		{
			VECTOR newvecs[4];
			int newflags;

			edgecheck = DEBUGPOLY_NOTEDGE0;

			for(e = 0; e < n_verts; e++)
			{
				newvecs[0].vx = (minx + maxx) / 2;
				newvecs[0].vy = (miny + maxy) / 2;
				newvecs[0].vz = (minz + maxz) / 2;

				newvecs[1].vx = (worldvecs[e].vx + worldvecs[(e+1)%n_verts].vx) / 2;
				newvecs[1].vy = (worldvecs[e].vy + worldvecs[(e+1)%n_verts].vy) / 2;
				newvecs[1].vz = (worldvecs[e].vz + worldvecs[(e+1)%n_verts].vz) / 2;

				newvecs[2] = worldvecs[(e+1)%n_verts];

				newvecs[3].vx = (worldvecs[(e+1)%n_verts].vx + worldvecs[(e+2)%n_verts].vx) / 2;
				newvecs[3].vy = (worldvecs[(e+1)%n_verts].vy + worldvecs[(e+2)%n_verts].vy) / 2;
				newvecs[3].vz = (worldvecs[(e+1)%n_verts].vz + worldvecs[(e+2)%n_verts].vz) / 2;


				newflags = flags & ~(0x0f00);	// mask off the edge checks
				newflags |= DEBUGPOLY_NOTEDGE0;
				newflags |= DEBUGPOLY_NOTEDGE3;
				if((flags & edgecheck))
				{
					newflags |= DEBUGPOLY_NOTEDGE1;
				}
				edgecheck = edgecheck * 2;
				if(e == n_verts-1)
					edgecheck = DEBUGPOLY_NOTEDGE0;
				if((flags & edgecheck))
				{
					newflags |= DEBUGPOLY_NOTEDGE2;
				}

				overlayShowDebugPolygon(newvecs, 4, bgr, newflags);
			}
			return;
		}

	}


// Okay, let's plot the thing...

	if(!(flags & DEBUGPOLY_USEDEPTH))
	{
		depth = 10;
	}
	else
	{
		depth /= n_verts;
		depth >>= (3+2);
		depth -= 15;
		if (depth < 0) depth = 0;
		if (depth > 1023) depth = 1023;
	}

	gte_ldsxy3(transformedVertices[0],transformedVertices[1],transformedVertices[2]);
	gte_nclip();
	gte_stopz(&clipflag);

	if((clipflag < 0) || flags & DEBUGPOLY_DUBSIDED)
	{
		if(!(flags & DEBUGPOLY_NOBORDER))
		{

			edgecheck = DEBUGPOLY_NOTEDGE0;
			for(i = 0; i < n_verts; i++)
			{
				LINE_F2 *line;
				BEGINPRIM(line, LINE_F2);
				*(u_long *)&line->x0 = *(u_long *)&transformedVertices[i];
				*(u_long *)&line->x1 = *(u_long *)&transformedVertices[(i+1)%n_verts];
				if(!(flags & edgecheck))
					setRGB0(line, 255,255,255);
				else
					setRGB0(line, (bgr >> 16) & 255, (bgr >> 8) & 255, (bgr) & 255);
				setLineF2(line);
				ENDPRIM(line, depth, LINE_F2);
				edgecheck = edgecheck*2;
			}
			{
			}
		}


		for(i = 0; i < n_verts-2; i++)
		{
			POLY_F3			*siF3;
			BEGINPRIM(siF3, POLY_F3);

			*(u_long *)  (&siF3->x0) = *(u_long *) (&transformedVertices[0]);
			*(u_long *)  (&siF3->x1) = *(u_long *) (&transformedVertices[i+1]);
			*(u_long *)  (&siF3->x2) = *(u_long *) (&transformedVertices[i+2]);
			*(u_long *)  (&siF3->r0) = *(u_long *) (&bgr);

			setPolyF3(siF3);
			siF3->code |= 2;
			ENDPRIM(siF3, depth, POLY_F3);
		}
		{
		}
	}
}

void overlayShowBigBox(int xl, int xh, int yl, int yh, int zl, int zh, unsigned int bgr)
{
	VECTOR corners[4];
	int f;
	int p;
	int v;
	static int lookups[] =
		{0,1,3,2,
		 5,4,6,7,
		 5,7,3,1,
		 4,5,1,0,
		 6,4,0,2,
		 7,6,2,3
		};
	for(f=0;f<6;f++)
	{
		for(p = 0; p < 4; p++)
		{
			v = lookups[f*4+p];

			corners[p].vx=(v&1)?xl:xh;
			corners[p].vy=(v&2)?yl:yh;
			corners[p].vz=(v&4)?zl:zh;
		}
		overlayShowDebugPolygon(corners, 4, bgr, DEBUGPOLY_SUBDIV | DEBUGPOLY_USEDEPTH);
	}
}

void overlayShowSphere(int x, int y, int z, int radius, unsigned int bgr)
{
	VECTOR vecs[12];
	int i;
	for(i = 0; i < 12; i++)
	{
		vecs[i].vx = x + ((radius * rsin(i*4096/12)) >>12);
		vecs[i].vy = y + ((radius * rcos(i*4096/12)) >>12);
		vecs[i].vz = z;
	}
	overlayShowDebugPolygon(&vecs[0],12,bgr,DEBUGPOLY_DUBSIDED);
	for(i = 0; i < 12; i++)
	{
		vecs[i].vz = vecs[i].vx - x + z;
		vecs[i].vx = x;
	}
	overlayShowDebugPolygon(&vecs[0],12,bgr,DEBUGPOLY_DUBSIDED);
	for(i = 0; i < 12; i++)
	{
		vecs[i].vx = vecs[i].vy - y + x;
		vecs[i].vy = y;
	}
	overlayShowDebugPolygon(&vecs[0],12,bgr,DEBUGPOLY_DUBSIDED);

}

void overlayShowCollBox(COLLBOX *box, VECTOR *cumPos)
{
	switch(box->flags&TYPEPART)
	{
		case BOX:
			overlayShowBigBox(

				cumPos->vx + ((box->pX)>>9),
				cumPos->vx + ((box->pX + box->sX)>>9),
				cumPos->vy + ((box->pY + box->sY)>>9),
				cumPos->vy + ((box->pY)>>9),
				cumPos->vz + ((box->pZ)>>9),
				cumPos->vz + ((box->pZ + box->sZ)>>9),
				0x00ff00
				);
			break;
		case RAMP:
		{
/*
			overlayShowBigBox(

				cumPos->vx + ((box->pX)>>9),
				cumPos->vx + ((box->pX + box->sX)>>9),
				cumPos->vy + ((box->pY + box->sY)>>9),
				cumPos->vy + ((box->pY)>>9),
				cumPos->vz + ((box->pZ)>>9),
				cumPos->vz + ((box->pZ + box->sZ)>>9),
				0xffff00
				);
*/
			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;
			VECTOR pBBox[20];

			xl = (box->pX) >> 9;
			yl = (box->pY) >> 9;
			zl = (box->pZ) >> 9;

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

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

			pM=(ULONG *)(box->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>>9)+xl;
				pBBox[f].vy=(pV[f].vy>>9)+yl;
				pBBox[f].vz=(pV[f].vz>>9)+zl;
			}


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

				verts[0] = pBBox[vert2];
				verts[1] = pBBox[vert1];
				verts[2] = pBBox[vert0];
				overlayShowDebugPolygon(&verts[0], 3, 0xffff00, DEBUGPOLY_SUBDIV | DEBUGPOLY_USEDEPTH);

			}

			break;
		}
		default:
			break;
	}
}



// ---- True Alpha Sprites ----
void overlayGrabAlphaCluts()
{
	USHORT *temp;
	int i;

	temp = MALLOC(256 * sizeof(USHORT));
	temp[0] = 0x8000;

	for(i = 1; i < 256; i++)
	{
		temp[i] = 0x4210;	//rgb = 127
	}

	if(!overlayAlphaClut)
	{
		overlayAlphaClut = textureAddCLUT16(&temp[0]);
		overlayAlphaClut256 = textureAddCLUT256(&temp[0]);
	}

	temp[0] = 0x4210;
	overlaySolidAlphaClut = textureAddCLUT16(&temp[0]);
	FREE(temp);
}





int overlaySpriteRot(TextureType *spr, int x, int y, int depth, unsigned long colour, short rot)
{
	return overlaySprite(spr, x, y, depth, colour);
}

int overlaySprite(TextureType *spr, int x, int y, int depth, unsigned long colour)
{
	POLY_FT4 *si;
	int alp,ox,oy,w,h;

	ox=x;
	oy=y;

	y*=1.875;

	x+=256;
	y+=240;
	
	x*=1.25;

	if(depth<0)//dodgy check - but will work for now - spots the control buttons as they don't need scaling
	{
		depth*=-1;
		w = ((spr->u1 - spr->u0));
		h = ((spr->v2 - spr->v0));
	}
	else
	{
		w = ((spr->u1 - spr->u0)*1.25);
		h = ((spr->v2 - spr->v0)*1.875);
	}
	//alp = (colour>>24) & 0xff;

	BEGINPRIM(si, POLY_FT4);

	si->x0 = si->x2 = x;
	si->x1 = si->x3 = x + w;
	si->y0 = si->y1 = y;
	si->y2 = si->y3 = y + h;

	if(spr->tpage==192)
	{
		setUV4(si, 0,0, 96,0, 0,60, 96,60);
	}
	else
		setUV4(si, spr->u0, spr->v0, spr->u1, spr->v1, spr->u2, spr->v2, spr->u3, spr->v3);
	*(ULONG*)&si->r0 = (colour & 0xffffff);
	si->code = GPU_COM_TF4;
	si->tag=0;
	si->tpage=spr->tpage;

	ENDPRIM(si, depth, POLY_FT4);
		
   	if((spr->flags & (NSPLIT)))
	{
		overlaySprite(&DCKtextureList[spr->tpage+1],ox + (spr->u1 - spr->u0),oy,depth,colour);
	}

// If it's got vertical splitting, skip past the ones we just did with the above
// (Doschop only marks v-splitting on the first sprite of each row)
   	if((spr->flags & (NVSPLIT)))
	{
		while(spr->flags & (NSPLIT))
			spr=&DCKtextureList[spr->tpage+1];
//			spr++;

		overlaySprite(&DCKtextureList[spr->tpage+1],ox,oy+(spr->v2 - spr->v0),depth,colour);
	}	   
  
	return 1;
}

// BP: Show a sprite flipped about the Y axis (so we don't need 2 sprites for objects facing the opposite direction)
// TBD: fix it to work with splitted sprites (draw the last part of the splitted sprite first, then the first part last...)
int overlaySpriteFlipped(TextureType *spr, int x, int y, int depth, unsigned long colour)
{
	POLY_FT4 *si;
	int alp;
	y*=1.875;

	x+=256;
	y+=240;
	
	x*=1.25;
	
	BEGINPRIM(si, POLY_FT4);

	si->x0 = si->x2 = x+ ((spr->u1 - spr->u0)*1.25);
	si->x1 = si->x3 = x;
	si->y0 = si->y1 = y;
	si->y2 = si->y3 = y + ((spr->v2 - spr->v0)*1.875);

	alp = (colour>>24) & 0xff;

// Grrr. The new libs don't allow the sprite's (u/v/tpage/clut) to be copied across as longs.

	*(ULONG *)(&si->u0) = ((unsigned long)*(USHORT *)&spr->u0)
		                  | (((unsigned long)(spr->clut)) <<16);
	*(ULONG *)(&si->u2) = ((unsigned long)*(USHORT *)&spr->u2);
	*(ULONG *)(&si->u3) = ((unsigned long)*(USHORT *)&spr->u3);

	*(ULONG *)(&si->u1) = ((unsigned long)*(USHORT *)&spr->u1)
						  | (((unsigned long)(spr->tpage)) <<16);
//						  | ((SEMITRANS_ADD-1) << (16+5));
	*(ULONG*)&si->r0 = (colour & 0xffffff) | ((GPU_COM_TF4)<<24);
	setlen(si, 9);

	ENDPRIM(si, depth, POLY_FT4);
	return 1;
}


int overlaySpriteScaled(TextureType *spr, int x, int y, int depth, unsigned long colour, int xscale, int yscale)
{
	POLY_FT4 *si;
	int alp;

	
	BEGINPRIM(si, POLY_FT4);

// u,v = doschop offsets
//	u=(spr->u*scaleX)/4096;
//	v=(spr->v*sprctrl.scaley)/4096;

	si->x0 = si->x2 = x;
	si->x1 = si->x3 = x + (spr->w * xscale / 256);
	si->y0 = si->y1 = y;
	si->y2 = si->y3 = y + (spr->h * yscale / 256);

	alp = (colour>>24) & 0xff;

// Grrr. The new libs don't allow the sprite's (u/v/tpage/clut) to be copied across as longs.

	*(ULONG *)(&si->u0) = ((unsigned long)*(USHORT *)&spr->u0)
		                  | (((unsigned long)(spr->clut)) <<16);
	*(ULONG *)(&si->u2) = ((unsigned long)*(USHORT *)&spr->u2);
	*(ULONG *)(&si->u3) = ((unsigned long)*(USHORT *)&spr->u3);

	*(ULONG *)(&si->u1) = ((unsigned long)*(USHORT *)&spr->u1)
						  | (((unsigned long)(spr->tpage)) <<16);
//						  | ((SEMITRANS_ADD-1) << (16+5));
	*(ULONG*)&si->r0 = (colour & 0xffffff) | ((GPU_COM_TF4)<<24);
	setlen(si, 9);

	ENDPRIM(si, depth, POLY_FT4);

   	if((spr->flags & (NSPLIT)))
	{
		overlaySpriteScaled(spr+1,x + (spr->w * xscale / 256),y,depth,colour,xscale,yscale);
	}

// If it's got vertical splitting, skip past the ones we just did with the above
// (Doschop only marks v-splitting on the first sprite of each row)
   	if((spr->flags & (NVSPLIT)))
	{
		while(spr->flags & (NSPLIT))
			spr++;

		overlaySpriteScaled(spr+1,x,y+(spr->h * yscale / 256),depth,colour,xscale,yscale);
	}

	return 1;
}


////////////////////////////////////////////////////////////////////////////////////////////////
int overlaySpriteRotate(TextureType *spr, int x, int y, int xoff, int yoff, int depth, int rot,unsigned long colour)
{
	POLY_FT4 *si;
	int alp;

	int	x0,y0,x1,y1,x2,y2,x3,y3,tempx,tempy,sin,cos;


	BEGINPRIM(si, POLY_FT4);
	alp = (colour>>24) & 0xff;

	x0=x1= -yoff;
	x2=x3=x0 + spr->h;

	y0=y2= -xoff;
	y1=y3=y0 + spr->w;

	sin=rsin(rot);
	cos=rcos(rot);

	tempx=((sin*x0)+(cos*y0))/4096;
	tempy=((cos*x0)-(sin*y0))/4096;
	x0=tempx;
	y0=tempy;

	tempx=((sin*x1)+(cos*y1))/4096;
	tempy=((cos*x1)-(sin*y1))/4096;
	x1=tempx;
	y1=tempy;

	tempx=((sin*x2)+(cos*y2))/4096;
	tempy=((cos*x2)-(sin*y2))/4096;
	x2=tempx;
	y2=tempy;

	tempx=((sin*x3)+(cos*y3))/4096;
	tempy=((cos*x3)-(sin*y3))/4096;
	x3=tempx;
	y3=tempy;

	si->x0=x + x0;
	si->y0=y + y0;
	si->x1=x + x1;
	si->y1=y + y1;
	si->x2=x + x2;
	si->y2=y + y2;
	si->x3=x + x3;
	si->y3=y + y3;

	*(ULONG *)(&si->u0) = ((unsigned long)*(USHORT *)&spr->u0)
		                  | (((unsigned long)(spr->clut)) <<16);
	*(ULONG *)(&si->u2) = ((unsigned long)*(USHORT *)&spr->u2);
	*(ULONG *)(&si->u3) = ((unsigned long)*(USHORT *)&spr->u3);

	*(ULONG *)(&si->u1) = ((unsigned long)*(USHORT *)&spr->u1)
						  | (((unsigned long)(spr->tpage)) <<16);

	*(ULONG*)&si->r0 = (colour & 0xffffff) | ((GPU_COM_TF4)<<24);
	setlen(si, 9);

	ENDPRIM(si, depth, POLY_FT4);


   	if((spr->flags & (NSPLIT)))
	{
		overlaySpriteRotate(spr+1,x + spr->w,y, xoff, yoff, depth,rot,colour);
	}

   	if((spr->flags & (NVSPLIT)))
	{
		while(spr->flags & (NSPLIT))
			spr++;
		overlaySpriteRotate(spr+1,x + spr->w,y, xoff, yoff, depth,rot,colour);
	}
	return 1;
}




////////////////////////////////////////////////////////////////////////////////////////////////


// High byte of colour is used for the alpha mask, Low byte is the additive, with 128 being normal, remember.
// (So for smooth alpha, use "(0...255)<<24, and (0...128)* 0x10101 )
int overlayAlphaSprite(TextureType *spr, int x, int y, int depth, unsigned long colour)
{
	POLY_FT4 *si;
	int alp;

//	if(!(colour & 0xff000000))
	if(!(colour))	// you can still request additive with no backdrop removal
		return 0;
	if((colour & 0xff000000) == 0xff000000)
	{
		return overlaySprite(spr,x,y,depth,colour);
	}

	y*=1.875;

	x+=256;
	y+=240;
	
	x*=1.25;


	BEGINPRIM(si, POLY_FT4);

// u,v = doschop offsets
//	u=(spr->u*scaleX)/4096;
//	v=(spr->v*sprctrl.scaley)/4096;

	si->x0 = si->x2 = x;
	si->x1 = si->x3 = x + ((spr->u1 - spr->u0)*1.25);
	si->y0 = si->y1 = y;                      
	si->y2 = si->y3 = y + ((spr->v2 - spr->v0)*1.875);

	alp = (colour>>24) & 0xff;

// Grrr. The new libs don't allow the sprite's (u/v/tpage/clut) to be copied across as longs.

	*(ULONG *)(&si->u0) = ((unsigned long)*(USHORT *)&spr->u0)
		                  | (((unsigned long)(spr->clut)) <<16);
	*(ULONG *)(&si->u2) = ((unsigned long)*(USHORT *)&spr->u2);
	*(ULONG *)(&si->u3) = ((unsigned long)*(USHORT *)&spr->u3);

	*(ULONG *)(&si->u1) = ((unsigned long)*(USHORT *)&spr->u1)
						  | (((unsigned long)(spr->tpage)) <<16)
						  | ((SEMITRANS_ADD-1) << (16+5));
	*(ULONG*)&si->r0 = (colour & 0xffffff) | ((GPU_COM_TF4+2)<<24);

	setlen(si, 9);	// don't do "setPolyFT4", because we just did the "gpu_com", and orr-ed in the transparancy

	si[1] = si[0];
	
	si->tag=SEMITRANS_ADD;
	si->code = GPU_COM_TF4;
	si->tpage = spr->tpage;

	ENDPRIM(si, depth, POLY_FT4);

// Alpha-channel transparancy

	BEGINPRIM(si, POLY_FT4);

//////////////////////added this, we probably won't remember doing dc styley
	si->x0 = si->x2 = x;
	si->x1 = si->x3 = x + spr->w;
	si->y0 = si->y1 = y;
	si->y2 = si->y3 = y + spr->h;

	alp = (colour>>24) & 0xff;

// Grrr. The new libs don't allow the sprite's (u/v/tpage/clut) to be copied across as longs.

	*(ULONG *)(&si->u0) = ((unsigned long)*(USHORT *)&spr->u0)
		                  | (((unsigned long)(spr->clut)) <<16);
	*(ULONG *)(&si->u2) = ((unsigned long)*(USHORT *)&spr->u2);
	*(ULONG *)(&si->u3) = ((unsigned long)*(USHORT *)&spr->u3);

	*(ULONG *)(&si->u1) = ((unsigned long)*(USHORT *)&spr->u1)
						  | (((unsigned long)(spr->tpage)) <<16)
						  | ((SEMITRANS_ADD-1) << (16+5));
	*(ULONG*)&si->r0 = (colour & 0xffffff) | ((GPU_COM_TF4+2)<<24);

	setlen(si, 9);	// don't do "setPolyFT4", because we just did the "gpu_com", and orr-ed in the transparancy
//////////////////////

	if(si->tpage & (1 << 7))
	{
		si->clut = overlayAlphaClut256;
	}
	else
	{
		si->clut = overlayAlphaClut;
	}
	si->tpage = (spr->tpage) ;//| ((SEMITRANS_SUB-1) << 5);

	si->r0=alp;
	si->g0=alp;
	si->b0=alp;

	si->tag=SEMITRANS_SUB;
	si->code = GPU_COM_TF4;

	
	ENDPRIM(si, (depth), POLY_FT4);

   	if((spr->flags & (NSPLIT)))
	{
		overlayAlphaSprite(spr+1,x+spr->w,y,depth,colour);
	}
// If it's got vertical splitting, skip past the ones we just did with the above
// (Doschop only marks v-splitting on the first sprite of each row)
   	if((spr->flags & (NVSPLIT)))
	{
		while(spr->flags & (NSPLIT))
			spr++;

		overlayAlphaSprite(spr+1,x,y+spr->h,depth,colour);
	}

	return 1;
}



int overlayTranspSprite(TextureType *spr, int x, int y, int depth, unsigned long colour)
{
	POLY_FT4 *si;
	int alp,ox,oy;

	ox=x;
	oy=y;

	y*=1.875;

	x+=256;
	y+=240;
	
	x*=1.25;

	BEGINPRIM(si, POLY_FT4);

// u,v = doschop offsets
//	u=(spr->u*scaleX)/4096;
//	v=(spr->v*sprctrl.scaley)/4096;

	si->x0 = si->x2 = x;
	si->x1 = si->x3 = x + ((spr->u1 - spr->u0)*1.25);
	si->y0 = si->y1 = y;                      
	si->y2 = si->y3 = y + ((spr->v2 - spr->v0)*1.875);

	alp = (colour>>24) & 0xff;

// Grrr. The new libs don't allow the sprite's (u/v/tpage/clut) to be copied across as longs.

	*(ULONG *)(&si->u0) = ((unsigned long)*(USHORT *)&spr->u0)
		                  | (((unsigned long)(spr->clut)) <<16);
	*(ULONG *)(&si->u2) = ((unsigned long)*(USHORT *)&spr->u2);
	*(ULONG *)(&si->u3) = ((unsigned long)*(USHORT *)&spr->u3);

	*(ULONG *)(&si->u1) = ((unsigned long)*(USHORT *)&spr->u1)
						  | (((unsigned long)(spr->tpage)) <<16);
//						  | ((SEMITRANS_ADD-1) << (16+5));
	*(ULONG*)&si->r0 = (colour & 0xffffff) | ((GPU_COM_TF4)<<24);
	setlen(si, 9);

	si->tag=SEMITRANS_SEMI;

	ENDPRIM(si, depth, POLY_FT4);
		
   	if((spr->flags & (NSPLIT)))
	{
		overlayTranspSprite(&DCKtextureList[spr->tpage+1],ox + spr->w,oy,depth,colour);
	}

// If it's got vertical splitting, skip past the ones we just did with the above
// (Doschop only marks v-splitting on the first sprite of each row)
   	if((spr->flags & (NVSPLIT)))
	{
		while(spr->flags & (NSPLIT))
			spr=&DCKtextureList[spr->tpage+1];
//			spr++;



		overlayTranspSprite(&DCKtextureList[spr->tpage+1],ox,oy+spr->h,depth,colour);
	}	   
  
	return 1;
}



// ---- Debug Collision Viewer ----

void overlayShowPlatformCollision()
{
	PLATFORMWORK *platform;
	COLLBOX *box;
	int i;

	for(platform = platform_list; platform; platform = platform->next)
	{
		box = platform->def->coll_bounds.pBoxes;
		for(i=0; i<platform->def->coll_bounds.nCollBoxes; i++)
		{
			overlayShowCollBox(box, &platform->oldPos);	//cumPos);
			box++;
		}
	}
}

extern void *tempFile;
void overlayShowMapCollision()
{
	int i;
	COLLBOX *box;
	static VECTOR zerovec = {0,0,0};

	box = ADD2POINTER(tempFile,4);
	for(i = 0; i < numCollBoxes; i++)
	{
		overlayShowCollBox(box, &zerovec);
		box++;
	}
}

int overlay_show_collision = 0;

void overlayShowCollision()
{
#ifdef DEBUG
	switch(overlay_show_collision)
	{
	case DEBUG_OVERLAY_LEVEL_COLLISION:
		overlayShowMapCollision();
		return;
	case DEBUG_OVERLAY_PLATFORM_COLLISION:
		overlayShowPlatformCollision();
		return;
	}
#endif
}


void overlayPreviewOverlay()
{
	static TextureType *blitz = NULL;




#if PREVIEW_VERSION==1
	if(!blitz)
		blitz = textureFindInAllBanks("BLITZOVERLAY");


//fontPrintCentred(f,x,y,str,r,g,b)
	fontPrintCentred(font, 0,64, "\034Chicken Run\034 Development Preview", 128,128,128);
	fontPrintCentred(font, 0,64+10, "Team Manta, Blitz Games", 0,128,128);
//	fontPrint(font, -70,64+20, "14-Feb-2000", 128,128,0);
	fontPrintCentred(font, 0,64+20, VERSIONSTR, 128,128,0);

	if(blitz)
		overlayAlphaSprite(blitz, -230, 54, 0, 0x20ffffff);


#endif
}





void overlayFilledRectangle(int x, int y, int w, int h, unsigned int bgr)
{
	POLY_F4 *si4;
	float tx, ty, tw, th;

	tx = 320.0f + (((float) x) * 1.25f);
	ty = 240.0f + (((float) y) * 1.875f);

	tw = (((float) w) * 1.25f);
	th = (((float) h) * 1.875f);

	x = tx; y = ty; w = tw; h = th;


	BEGINPRIM(si4, POLY_F4);
	si4->r0 = (bgr & 0xff);
	si4->g0 = ((bgr >> 8) & 0xff);
	si4->b0 = ((bgr >> 16) & 0xff);

	si4->x0 = si4->x2 = x;
	si4->x1 = si4->x3 = x+w;

	si4->y0 = si4->y1 = y;
	si4->y2 = si4->y3 = y+h;

	setPolyF4(si4);
	ENDPRIM(si4, 0, POLY_F4);
}

void overlayLine(int x1,int y1, int x2, int y2, unsigned int bgr)
{
	LINE_F2	*line;

	BEGINPRIM(line, LINE_F2);
	line->x0 = x1;
	line->y0 = y1;
	line->x1 = x2;
	line->y1 = y2;
	line->r0 = (bgr & 0xff);
	line->g0 = ((bgr >> 8) & 0xff);
	line->b0 = ((bgr >> 16) & 0xff);
	setLineF2(line);
	ENDPRIM(line, 0, LINE_F2);
}

void overlayOutlineRectangle(int x1,int y1, int w, int h, unsigned int bgr)
{
	overlayLine(x1,y1,x1+w,y1,bgr);
	overlayLine(x1,y1,x1,y1+h,bgr);

	overlayLine(x1+w,y1,x1+w,y1+h,bgr);
	overlayLine(x1,y1+h,x1+w,y1+h,bgr);
}


// =================== Animating Texture Management ======================

// Call at the start of a cd-loading session...
int overlayLoadingDisplay = 0;

void overlayLoadingBegin(int effect)
{
#ifndef _WINDOWS
	RECT rect;
#else
	RECTPS rect;
#endif
	int x,y;
	displayPageType *otherDisplayPage;

	UsrSetVsyncFunc((void (*)(void))overlayLoadingVsync);//dcOverlayCallback);
	overlayLoadingDisplay = 1;
	return; 


	
// If, for whatever the reason, the fadeout was already happening, leave it happening
// (If we load really quickly and then immediately die, for instance?)
	if(overlayLoadingDisplay)
		return;


	otherDisplayPage = (currentDisplayPage==displayPage)?(&displayPage[1]):(&displayPage[0]);


//	textureShowVRAM(PALMODE);

// Ensure both screens have the same data


	rect.x = 0;
	rect.y = currentDisplayPage->drawenv.clip.y;
	rect.w = 512;
	rect.h = 256;
	DrawSync(0);

	x = 0;
	y = otherDisplayPage->drawenv.clip.y;

	printf("clips are %d %d\n",rect.y,y);
	
	DrawSync(0);
 //	MoveImage(&rect,x,y);
	DrawSync(0);



	overlayLoadingDisplay = 1;

// Don't CLS
	displayPage[0].drawenv.isbg = displayPage[1].drawenv.isbg = 0;
	PutDrawEnv(&otherDisplayPage->drawenv);


//	textureShowVRAM(PALMODE);

}

#define OVL_LOAD_MAX 4096
// Call from the vsync callback during a loading session

#define OVL_ANGSTEP (4096/32)
#define OVL_MID (4096/4)
// note - this is every frame, not every two
void overlayLoadingVsync()
{
	int i;
	int i2;
	int r;

	if(!overlayLoadingDisplay)
		return;
	if(overlayLoadingDisplay >= OVL_LOAD_MAX)
		return;

	overlayLoadingDisplay+=OVL_LOAD_MAX/100;

	kmBeginScene(&kmSystemConfig);
	kmBeginPass(&vertexBufferDesc);


	currentDisplayPage = (currentDisplayPage==displayPage)?(&displayPage[1]):(&displayPage[0]);
	ClearOTagR(currentDisplayPage->ot, 1024);
	currentDisplayPage->primPtr = currentDisplayPage->primBuffer;


// On the last *two* frames of fadeout (coz of flipping), draw over the ickle black dot
	if(overlayLoadingDisplay >= OVL_LOAD_MAX - OVL_LOAD_MAX/100)
	{
		POLY_F4 *f4;


		BEGINPRIM(f4, POLY_F4);
		setPolyF4(f4);

		f4->x0 = -256;
		f4->y0 = -128;
		f4->x1 = 256;
		f4->y1 = -128;

		f4->x2 = -256;
		f4->x3 = 256;

		f4->y2 = 128;
		f4->y3 = 128;

  #ifdef DARK_EGG
		setRGB0(f4, 0x00,0x00,0);
  #else
		setRGB0(f4, 0xff,0xff,0xff);
  #endif
		f4->tag = SEMITRANS_NONE;
		f4->code = 0x28;
		f4->y0*=1.875; f4->y1*=1.875; f4->y2*=1.875; f4->y3*=1.875;
		f4->x0+=256; f4->x1+=256; f4->x2+=256; f4->x3+=256;
		f4->y0+=240; f4->y1+=240; f4->y2+=240; f4->y3+=240;
		f4->x0*=1.25; f4->x1*=1.25; f4->x2*=1.25; f4->x3*=1.25;
		ENDPRIM(f4, 0, POLY_F4);
	}
	else
	{




// radius of the screen is 286
#ifdef OUTSIDE_EGG
	r = (OVL_LOAD_MAX - overlayLoadingDisplay) * 300/ OVL_LOAD_MAX;
#else
	r = overlayLoadingDisplay * 300/ OVL_LOAD_MAX;
#endif

	for(i = 0; i < 4096; i+=OVL_ANGSTEP)
	{
		POLY_G4 *g4;
#ifdef OUTSIDE_EGG
		POLY_F4 *f4;
#else
		POLY_F3 *f3;
#endif
		int s,c;

		i2 = i + OVL_ANGSTEP;

//the border should be a gouraud fade, really...
		BEGINPRIM(g4, POLY_G4);
		setPolyG4(g4);


// Maths for the points. Possibly this should be a table, or grabbed from a model, or something
// But for now... Let's do some sums

		g4->x0= (r * rsin(i )) >> 12;
		g4->x1= (r * rsin(i2)) >> 12;

		g4->x0 = g4->x0 * 380/320;
		g4->x1 = g4->x1 * 380/320;

		if(i < 1024 || i >= 1024 * 3)
		{
			g4->y0= ((r * OVL_MID) >>12)  + ((   ((r * (4096-OVL_MID)) >>12)   * rcos(i )) >> 12);
		}
		else
		{
			g4->y0= ((r * OVL_MID) >>12)  + ((   ((r * (4096+OVL_MID)) >> 12)  * rcos(i )) >> 12);
		}

		if(i2 < 1024 || i2 >= 1024 * 3)
		{
			g4->y1= ((r * OVL_MID) >>12)  + ((   ((r * (4096-OVL_MID)) >> 12)  * rcos(i2)) >> 12);
		}
		else
		{
			g4->y1= ((r * OVL_MID) >>12)  + ((   ((r * (4096+OVL_MID)) >> 12)  * rcos(i2)) >> 12);
		}

// End of maths, beginning of plotting...

		g4->x2 = g4->x0 * 24/16;
		g4->y2 = g4->y0 * 24/16;
		g4->x3 = g4->x1 * 24/16;
		g4->y3 = g4->y1 * 24/16;
#ifdef OUTSIDE_EGG
		setRGB0(g4, 0,0,0);
		setRGB1(g4, 0,0,0);
		setRGB2(g4, 255,255,255);
		setRGB3(g4, 255,255,255);
#else
		setRGB0(g4, 255,255,255);
		setRGB1(g4, 255,255,255);
		setRGB2(g4, 0,0,0);
		setRGB3(g4, 0,0,0);
#endif
  		g4->code = 0x28;
		g4->tag = SEMITRANS_SEMI;
		g4->y0*=1.875; g4->y1*=1.875; g4->y2*=1.875; g4->y3*=1.875;
		g4->x0+=256; g4->x1+=256; g4->x2+=256; g4->x3+=256;
		g4->y0+=240; g4->y1+=240; g4->y2+=240; g4->y3+=240;
		g4->x0*=1.25; g4->x1*=1.25; g4->x2*=1.25; g4->x3*=1.25;
		ENDPRIM(g4, 0, POLY_G4);
//		g4->code = g4->code | 2;


		
#ifdef OUTSIDE_EGG

		BEGINPRIM(f4, POLY_F4);
		setPolyF4(f4);

		f4->x0 = g4->x2;
		f4->y0 = g4->y2;
		f4->x1 = g4->x3;
		f4->y1 = g4->y3;

		f4->x2 = (300 * rsin(i )) >> 12;
		f4->x3 = (300 * rsin(i2)) >> 12;

		f4->y2 = (300 * rcos(i )) >> 12;
		f4->y3 = (300 * rcos(i2)) >> 12;


  #ifdef DARK_EGG
		setRGB0(f4, 0x00,0x00,0);
  #else
		setRGB0(f4, 0xff,0xff,0xff);
  #endif

		f4->y0*=1.875; f4->y1*=1.875; f4->y2*=1.875; f4->y3*=1.875;
		f4->x0+=256; f4->x1+=256; f4->x2+=256; f4->x3+=256;
		f4->y0+=240; f4->y1+=240; f4->y2+=240; f4->y3+=240;
		f4->x0*=1.25; f4->x1*=1.25; f4->x2*=1.25; f4->x3*=1.25;
		f4->code = 0x28;
		f4->tag = SEMITRANS_NONE;

		ENDPRIM(f4, 0, POLY_F4);

#else
		BEGINPRIM(f3, POLY_F3);
		setPolyF3(f3);

		f3->x0 = g4->x0;
		f3->y0 = g4->y0;
		f3->x1 = g4->x1;
		f3->y1 = g4->y1;

		f3->x2 = 0;
		f3->y2 = 0;



  #ifdef DARK_EGG
		setRGB0(f3, 0,0,0);
  #else
		setRGB0(f3, 0xff,0xff,0xff);
  #endif

		f3->y0*=1.875; f3->y1*=1.875; f3->y2*=1.875; 
		f3->x0+=256; f3->x1+=256; f3->x2+=256; 
		f3->y0+=240; f3->y1+=240; f3->y2+=240; 
		f3->x0*=1.25; f3->x1*=1.25; f3->x2*=1.25; 
		si->tag = SEMITRANS_NONE;
		si->code = 0x20;

		ENDPRIM(f3, 0, POLY_F3);
#endif



	}






	{
 //		DR_TPAGE *tp;
 //		BEGINPRIM(tp, DR_TPAGE);
#ifdef DARK_EGG
 //		setDrawTPage(tp,1,1,((SEMITRANS_SUB-1)<<5));
#else
 //		setDrawTPage(tp,1,1,((SEMITRANS_ADD-1)<<5));
#endif


 //		ENDPRIM(tp,0,DR_TPAGE);
	}


	}

		kmEndPass(&vertexBufferDesc);
				
		kmRender(KM_RENDER_FLIP);
		kmEndScene(&kmSystemConfig);



//	DrawSync(0);
//	PutDispEnv(&currentDisplayPage->dispenv);
//	PutDrawEnv(&currentDisplayPage->drawenv);
//	DrawOTag(currentDisplayPage->ot+(1024-1));
}


// Call at the end of a loading session
// (Essentially, it needs to wait for the fadeout to finish if we had a really fast load!)
void overlayLoadingEnd()
{
// re-enable CLS
	if(!overlayLoadingDisplay)
		return;

	while(overlayLoadingDisplay < OVL_LOAD_MAX)
	{
//		printf("wait %d\n",overlayLoadingDisplay);
		VSync(1);
	}
//	displayPage[0].drawenv.isbg = displayPage[1].drawenv.isbg = 1;

#ifdef DARK_EGG
	overlayStartOverlay(10, 0, 0);
#else
	overlayStartOverlay(10, 0, 0xffffff);
#endif

	overlayLoadingDisplay = 0;
}






void overlayScreenAdd(int b, int g, int r, int transp)
{
	{
		POLY_F4 *f4;
		BEGINPRIM(f4, POLY_F4);
		setPolyF4(f4);
		f4->x0=f4->x2=-320;
		f4->x1=f4->x3=320;
		f4->y0=f4->y1=-128;
		f4->y2=f4->y3=128;
		setRGB0(f4, r,g,b);
		ENDPRIM(f4, 0, POLY_F4);
		f4->code = f4->code | 2;
	}

	{
  //		DR_TPAGE *tp;
   //		BEGINPRIM(tp, DR_TPAGE);
	//	setDrawTPage(tp,1,1,((transp-1)<<5));
	 //	ENDPRIM(tp,0,DR_TPAGE);
	}
}


int overlayOVduration  = 0;
int overlayOVdurationW  = 0;
int overlayOVtimer  = 0;
int overlayOVcolour = 0;

void overlayStartOverlay(int timer, int whitetime, int colour)
{
	overlayOVduration = timer;
	overlayOVdurationW = whitetime;
	overlayOVtimer    = timer;
	overlayOVcolour   = colour;
}

void overlayDraw()
{
	int r,g,b;
	int len;

	if(overlay_debug_messagetime)
	{
		fontPrintCentred(font,0,100,&overlay_debug_message_text[0],20,100,180);
			overlay_debug_messagetime--;
	}


	if(!overlayOVtimer)
		return;



	if(!overlayOVcolour)
	{
		r = 0xff;
		g = 0xff;
		b = 0xff;

		len = overlayOVduration;	// - overlayOVdurationW;
		if(!len)
			len = 1;
		r = r * overlayOVtimer/len;
		g = g * overlayOVtimer/len;
		b = b * overlayOVtimer/len;
		overlayScreenAdd( (r) , (g) , (b), SEMITRANS_SUB);
	}
	else
	{
		r = (overlayOVcolour>>16) & 0xff;
		g = (overlayOVcolour>>8 ) & 0xff;
		b = (overlayOVcolour    ) & 0xff;

		if(overlayOVtimer > overlayOVduration - overlayOVdurationW)
		{
			int now;
			len = overlayOVdurationW;
			if(!len) len = 1;
			r = 255 - r;
			g = 255 - g;
			b = 255 - b;
			now = overlayOVduration - overlayOVtimer;
			r = r * now/len;
			g = g * now/len;
			b = b * now/len;

			r = 255 - r;
			g = 255 - g;
			b = 255 - b;
		}
		else
		{
			len = overlayOVduration - overlayOVdurationW;
			if(!len)
				len = 1;
			r = r * overlayOVtimer/len;
			g = g * overlayOVtimer/len;
			b = b * overlayOVtimer/len;
		}
		overlayScreenAdd( (r) , (g) , (b), SEMITRANS_ADD);
	}

	overlayOVtimer--;
}





// =================== Extra font stuff ======================


void fontCentredMultiLine(psFont *font, int x, int y, int width, char *text, unsigned char r, unsigned char g, unsigned char b)
{
	char temp[500];
	char *work;
	int numLines;
	int loop;

	numLines = fontFitToWidth(font, width, text, temp);
	work = temp;
	for(loop=0; loop<numLines; loop++)
	{
		fontPrintCentred(font,x,y,work,r,g,b);

// It's assumed that multi-line text will all be using the same, reasonably small, font.
// "12" is right for the Action-Man font - tbd: Change once we've got a proper chicken run one.
		y += 12;

		work += strlen(work)+1;
	}
}





void fontPrintMultiLineBoxSetDepth(psFont *font, int x, int y, int width, char *text, unsigned char r, unsigned char g, unsigned char b, int depth)
{
	fontSetPrintDepth(depth);
	fontPrintMultiLineBox(font, x, y, width, text, r, g, b);
	fontSetPrintDepth(0);
}


#define MULTI_LINE_BOX_MARGIN			26
#define MULTI_LINE_SPACING				18
#define MULTI_LINE_BOX_TOP_MARGIN		20
#define MULTI_LINE_BOX_BOTTOM_MARGIN	12
// For text at end of subgames..	rgb refers to alpha box in this case text is white.
//  x, y refer to centre of box
////////////////////////////////////////////////////////////////////////////////////////

void fontPrintMultiLineBox(psFont *font, int x, int y, int width, char *text, unsigned char r, unsigned char g, unsigned char b)
{

	char temp[256];
	char *work;
	int numLines, actualLines;
	int loop;
	int xText, yText;


	
	numLines = crFontFitToWidth(font, width, text, temp);
	actualLines = numLines*2;
	work = temp;

	xText = x-width/2;
	
	y -= (numLines*MULTI_LINE_SPACING  +MULTI_LINE_BOX_TOP_MARGIN + MULTI_LINE_BOX_BOTTOM_MARGIN)/2;
	yText = y;


	for(loop=0; loop<numLines; loop++)
	{
		fontPrintCentred(font,x,yText,work,128, 128, 128);
		//fontPrint(font,xText,yText,work,128, 128, 128);

// It's assumed that multi-line text will all be using the same, reasonably small, font.
// "12" is right for the Action-Man font - tbd: Change once we've got a proper chicken run one.
		if(strlen(work) == 0)
		{
			yText += (MULTI_LINE_SPACING/2);
			actualLines--;
		}
		else
			yText += MULTI_LINE_SPACING;

		work += strlen(work)+1;
	}
	overlayAlphaBox(xText - MULTI_LINE_BOX_MARGIN, y - MULTI_LINE_BOX_TOP_MARGIN, width + MULTI_LINE_BOX_MARGIN*2, (actualLines*MULTI_LINE_SPACING)/2  +MULTI_LINE_BOX_TOP_MARGIN + MULTI_LINE_BOX_BOTTOM_MARGIN, b, g, r);

}


/**************************************************************************
	FUNCTION:	fontFitToWidth()
	PURPOSE:	Wrap string to width into buffer (takes into account '\n' and "\n")
	PARAMETERS:	font ptr, width, string, buffer
	RETURNS:	Number of lines
**************************************************************************/

int crFontFitToWidth(psFont *font, int width, char *text, char *buffer)
{
	char	buf[256], *bufPtr, *outPtr = buffer;
	int		pixLen, lines = 0;

	memset(buf, 0, sizeof(buf));
	bufPtr = buf;
	while(1)
	{
		if (*text>=' ')
			*bufPtr++ = *text;
		pixLen = fontExtentW(font, buf);
		if ((pixLen>width)||(*text=='\0')||(*text=='\n')||((*text=='\\')&&(*(text+1) == 'n')))
		{
			if (pixLen>width)
			{
				while(*bufPtr!=' ')
				{
					bufPtr--;
					text--;
				}
				text++;
			}
			if((*text=='\\')&&(*(text+1) == 'n'))
			{
				text++;
				bufPtr--;
			}
			
			*bufPtr = '\0';
			strcpy(outPtr, buf);
			outPtr += strlen(buf)+1;
			lines++;
			bufPtr = buf;
			memset(buf, 0, sizeof(buf));
			if (*text=='\0')
				break;

		
		}
		text++;
	}
	return lines;
}










// e0 e8 ec f2 f9		// aeiou\
// c0 c8 cc d2 d9		// AEIOU\
// e1 e9 ed d3 fa fd	// aeiouy/
// c1 c9 cd d3 da dd	// AAIOUY/
// e2 ea ee f3 fb		// aeiou^
// -20-
// c2 ca ce d4 db		// AEIOU^
// e3 f1 f5				// ano~
// c3 d1 d5				// ANO~
// e4 eb ef f6 fc ff	// aeiouy"
// -20-
// c4 cb cf d6 dc		// AEIOU"
// e5 c5				// aA  o
// e6 c6				// ae AE
// e7 c7				// c, C,
// F0 D0				// d D
// F8 D8				/  oO/
// bf a1 df 22			// ?! sp B ger


// no: f4, f7, fe. No df











unsigned char fontUpperTable[256] =
{
//	 0    1    2    3    4    5    6    7    8    9    a    b    c    d    e    f
	0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,	//  0.. (ctrl)
	0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,	// 16.. (ctrl)
	0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,	// 32.. (" "...)
	0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,	// 48.. (" "...)
	0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,	// 64.. ("@A"...)
	0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,	// 80.. ("P"...)

	0x60,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,	// 96.. ("'a"...)
	0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x7b,0x7c,0x7d,0x7e,0x7f,	// 112.. ("p"...)
// (half way. Now for the accents)
	0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,	// 128..
	0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,	//
	0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,	//
	0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,	//
	0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,	// upper case
	0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
	0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,	// lower case. Whole line
	0xd0,0xd1,0xd2,0xd3,0xf4,0xd5,0xd6,0xf7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xfe,0xdf		//  No f4,f7,fe
};

char fontUppered[100];
char *fontUpper(char *text)
{
	int i;
	char *ps,*pd;

	if (!text)
		return "NULL";


	ps = text;
	pd = &fontUppered[0];

	for( ;*ps!=0; ps++,pd++)
	{
		*pd = fontUpperTable[(int)(*ps)];
	}
	*pd = 0;
	return &fontUppered[0];
}


// Message overlaid top-centre of screen
void overlayDebugMessage(char *msg, int time)
{
#ifdef DEBUG
	strcpy(&overlay_debug_message_text[0],msg);
	overlay_debug_messagetime = time;
#endif
}

// Message overlaid top-centre of screen
void overlayBurnDebugMessage(char *msg, int time)
{
#if defined DEBUG || defined EIDOS_DEBUG_STUFF
	strcpy(&overlay_debug_message_text[0],msg);
	overlay_debug_messagetime = time;
#endif
}


// =================== Animating Texture Management ======================
#define VRAM_STARTX			512
#define VRAM_PAGECOLS		8
#define VRAM_PAGEROWS		2
#define VRAM_PAGES			16
#define VRAM_PAGEW			32
#define VRAM_PAGEH			32
#define VRAM_SETX(X)		(X)
#define VRAM_SETY(Y)		((Y)*VRAM_PAGEW)
#define VRAM_SETXY(X,Y)		((X)+((Y)*VRAM_PAGEW))
#define VRAM_SETPAGE(P)		((P)<<16)
#define VRAM_GETX(HND)		((HND) & (VRAM_PAGEW-1))
#define VRAM_GETY(HND)		(((HND)/VRAM_PAGEW) & (VRAM_PAGEW-1))
#define VRAM_GETXY(HND)		((HND) & 0xffff)
#define VRAM_GETPAGE(HND)	((HND)>>16)
#define VRAM_CALCVRAMX(HND)	(512+((VRAM_GETPAGE(HND)%(VRAM_PAGECOLS))*64)+(VRAM_GETX(HND)*2))
#define VRAM_CALCVRAMY(HND)	(((VRAM_GETPAGE(HND)/(VRAM_PAGECOLS))*256)+(VRAM_GETY(HND)*8))

TEXANIM *texanim_list = NULL;

void texanimInit()
{
	texanim_list = NULL;
}

/*
clut = tex->clut
	for(pal=0; pal<VRAM_PALETTES; pal++)
   	{
   		if ((VRAMpalBlock[pal]) && (clut==VRAMpalCLUT[pal]))
   		{
			sprintf(str, "Palette #%d (used %dx)", pal, VRAMpalBlock[pal]);
   			fontPrint(font, -230,y+13, str, 128,128,128);
			break;
		}
	}
*/

// As soon as main.c & global.h are free, we need to bung the "rqd" in there
#ifndef VRAM_PALETTES
	#define VRAM_PALETTES CLUT_16S_REQUIRED
#endif

extern unsigned short	*VRAMpalBlock;
extern unsigned short	*VRAMpalCLUT;
extern int				*VRAMpalHandle;
extern unsigned long	*VRAMpalCRC;


unsigned short textureDuplicateCLUT16(int original)	//,unsigned short *palette)
{
	int				pal,col,newhnd, r,g,b;
	int oldhnd;
#ifndef _WINDOWS
	RECT rect;
#else
	RECTPS rect;
	int palsused=0;
#endif
	int x,y;
	unsigned long	palCRC;

//	palCRC = utilBlockCRC((char *)palette, (2 * 16));

// We need to insist on a new one, rather than checking against the existing set
	for(pal=0; pal<VRAM_PALETTES; pal++)					// Search for new palette slot
	{
		if (VRAMpalBlock[pal]==0)
		{
			VRAMpalBlock[pal] = 1;
			newhnd = VRAMpalHandle[pal/32];
			if (((pal & 31)==0) && (newhnd==0))				// Is new area needed?
			{
				newhnd = VRAMpalHandle[pal/32] = textureVRAMalloc(32,1);
			}
			oldhnd = VRAMpalHandle[original/32];

// rect is source, xy is dest
			rect.x = VRAM_CALCVRAMX(oldhnd)+16*(pal & 3);		// Copy up the palette
			rect.y = VRAM_CALCVRAMY(oldhnd)+((pal/4) & 7);
			rect.w = 16;
			rect.h = 1;
			DrawSync(0);

//			LoadImage(&rect, (unsigned long *)palette);
			x = VRAM_CALCVRAMX(newhnd)+16*(pal & 3);
			y = VRAM_CALCVRAMY(newhnd)+((pal/4) & 7);
 //			MoveImage(&rect,x,y);

			DrawSync(0);

			VRAMpalCRC[pal] = VRAMpalCRC[original];	// keep checksum of this palette
			VRAMpalCLUT[pal] = getClut(x,y);

#ifdef _DEBUG
			palsused++;
			//printf("Palette added: Currently used: %d\n", palsused);
#endif
			return VRAMpalCLUT[pal];
		}
	}
	printf("\nduplicatetexture: No more 16-colour palettes");
	return NULL;
}




void texanimLinkBFF(TEXANIMLIST *list)
{
	TEXANIM *anim;
	TextureType *tmap;
	int i;
	int sameclut;

	anim = ADD2POINTER(list,12);
	while(anim)
	{
		if(anim->header.next)
			anim->header.next = ADD2POINTER(anim->header.next, (int)list);

		anim->header.target = textureFindCRCInAllBanks((int)anim->header.target);
		if(!anim->header.target)
		{
			DB("AnimTexture Target not found\n");
		}
		ASSERT(anim->header.target);


		for(i = 0; i < anim->header.n_frames; i++)
		{
			anim->frames[i].tmap = textureFindCRCInAllBanks((int)anim->frames[i].tmap);
			if(!anim->frames[i].tmap)
				DB("AnimTexture Source not found\n");
			ASSERT(anim->frames[i].tmap);
		}


// Ensure that the target texture (possibly with the addition of *all* the source textures)
// are the only ones referring to the target palette
		sameclut = anim->header.target->clut;
		for(i = 0; i < anim->header.n_frames; i++)
		{
			if(anim->frames[i].tmap->clut != anim->header.target->clut)
				sameclut = -1;
		}

		for(i=0; i<VRAM_PALETTES; i++)
   		{
   			if ((VRAMpalBlock[i]) && (anim->header.target->clut==VRAMpalCLUT[i]))
   			{
/*
				printf("Found the target clut. It has %d references\n",VRAMpalBlock[i]);
				if(sameclut!=-1)
				{
					printf("The texanim shares a common clut. We want references to = %d\n",anim->header.n_frames+1);
				}
				else
				{
					printf("The texanim has varied cluts. We want references to = 1\n");
				}
*/

// If the palette's only used once, it'll be by the target, and life is cushtie.
// If the palette's common across the animation, and the palette's refcount is the same as the soure+target count,
// then life is also lovely.
				if( (sameclut != -1 && VRAMpalBlock[i] != anim->header.n_frames+1)
					||
					(sameclut == -1 && VRAMpalBlock[i] != 1)
				  )
				{
//					printf("We need to create a unique CLUT for this texanim\n");
// We need to give the target texture a brand new clut
// We also need to decrease the refcount of the original (It won't be decreasing from 1. That, after all, is the point of all this)
					anim->header.target->clut = textureDuplicateCLUT16(i);
					VRAMpalBlock[i]--;

				}
/*
				else
				{
					printf("Texanim already has a unique CLUT. Hurrah!\n");
				}
*/
				break;
			}
		}

		anim = anim->header.next;
	}
	texanim_list = ADD2POINTER(list,12);
}

// somewhat akin to andy's textureSetAnimation
void texanimDraw()
{
	TEXANIM *anim;
	DR_MOVE *siMove;
#ifndef _WINDOWS
	RECT moveRect;
#else
	RECTPS moveRect;
#endif
	TextureType *src;
	TextureType *dest;
	int i;

	for(anim = texanim_list; anim; anim = anim->header.next)
	{
		if(anim->header.n_frames == 1)
		{
			src = anim->frames[0].tmap;
		}
		else
		{
			for(i = 0; i < anim->header.n_frames-1; i++)
			{
				if(anim->frames[i].end_time > anim->header.current_time)
				{
					break;
				}
			}
//			printf("frame = %d\n",i);
			src = anim->frames[i].tmap;
		}
		dest = anim->header.target;


		if(src->clut != dest->clut)
		{
			moveRect.x = (src->clut & 0x3f) << 4;
			moveRect.y = src->clut >> 6;
			moveRect.w = 16;
			moveRect.h = 1;
  //			BEGINPRIM(siMove, DR_MOVE);
  //			SetDrawMove(siMove, &moveRect, (dest->clut & 0x3f) << 4,dest->clut >> 6);
  //			ENDPRIM(siMove, 1023, DR_MOVE);
		}

		moveRect.x = VRAM_CALCVRAMX(src->handle);
		moveRect.y = VRAM_CALCVRAMY(src->handle);
		if(anim->header.n_frames == 1)
		{
			moveRect.y += anim->header.current_time >> 12;	// Scroll y
		}

		moveRect.w = (dest->w + 3) / 4;
		moveRect.h = dest->h;

		// check for 256 colour mode
		if(dest->tpage & (1 << 7))
			moveRect.w *= 2;

		// copy bit of vram
  //		BEGINPRIM(siMove, DR_MOVE);
  //		SetDrawMove(siMove, &moveRect, (VRAM_CALCVRAMX(dest->handle)),(VRAM_CALCVRAMY(dest->handle)));
  //		ENDPRIM(siMove, 1023, DR_MOVE);
	}
}

// Just update the speeds & things
void texanimCycle()
{
	TEXANIM *anim;

#ifdef DEBUG
	if(padData.debounce[4] & PAD_CROSS)
		overlay_show_collision = (overlay_show_collision + 1) % N_DEBUG_OVERLAYS;
#endif

	for(anim = texanim_list; anim; anim = anim->header.next)
	{
		if(anim->header.n_frames == 1)
		{
// For whatever reason, these things look nicer if they scroll downwards for +ve speeds
			anim->header.current_time -= anim->header.current_speed;
//			printf("anim t = %d, s= %d\n",anim->header.current_time>>12,anim->header.current_speed);
			if(anim->header.target)
			{
				while(anim->header.current_time < 0)
				{
//					printf("+h %d\n",anim->header.target->h);
					anim->header.current_time += (anim->header.target->h<<12);
				}
				while(anim->header.current_time >= (anim->header.target->h << 12))
				{
//					printf("-h %d\n",anim->header.target->h);
					anim->header.current_time -= (anim->header.target->h<<12);
				}
			}
		}
		else
		{
			anim->header.current_time += anim->header.current_speed;
//			printf("anim t = %d. s=%d\n",anim->header.current_time>>12,anim->header.current_speed);

			while(anim->header.current_time < 0)
			{
//				printf("+t %d\n",anim->header.duration);
				anim->header.current_time += anim->header.duration;
			}
			while(anim->header.current_time >= anim->header.duration)
			{
//				printf("-t %d\n",anim->header.duration);
				anim->header.current_time -= anim->header.duration;
			}
		}
	}
}
TEXANIM *texanimFind(int tag)
{
	TEXANIM *anim;
	for(anim = texanim_list; anim; anim = anim->header.next)
	{
		if(anim->header.tag == tag)
			return anim;
	}
	return NULL;
}
void texanimSetSpeed(TEXANIM *anim, int speed)
{
	anim->header.current_speed = speed;
//	printf("anim %d, speed %d\n",anim->header.tag,anim->header.current_speed);
}



// Create a 2nd copy of a texture in Vram.
// Don't register it with "allbanks" or anything link that...
// "tex" should be mallocced already, but not filled in
void texanimDuplicateTexture(TextureType *src, TextureType *tex)
{
	int srchandle;
	int desthandle;
#ifndef _WINDOWS
	RECT srcrect;
#else
	RECTPS srcrect;
#endif

	int dtpage;
	int uMax,vMax;
	int ww,hh;
	int destx,desty;


	*tex = *src;
	ww = (src->w+7)/8;
	hh = (src->h+7)/8;

	if(src->flags & NEIGHTBIT)
		ww*=2;

	desthandle = textureVRAMalloc(ww,hh);

	destx = VRAM_CALCVRAMX(desthandle);
	desty = VRAM_CALCVRAMY(desthandle);

	srcrect.x = VRAM_CALCVRAMX(src->handle);
	srcrect.y = VRAM_CALCVRAMY(src->handle);
	srcrect.w = (src->w+3)/4;
	srcrect.h = src->h;

	if(src->flags & NEIGHTBIT)
		srcrect.w *= 2;	

	DrawSync(0);
  //	MoveImage(&srcrect,destx,desty);

	tex->tpage = getTPage(
		((src->flags & NEIGHTBIT) ? 1 : 0),
		0, destx, desty);

	tex->x = VRAM_GETX(desthandle)*8;

	if(src->flags & NEIGHTBIT)
		tex->x = tex->x / 2;

	tex->y = desty;

	uMax = tex->x + src->w - 1;
	if (uMax > 255)
		uMax = 255;
	vMax = tex->y + src->h - 1;
	if (vMax > 255)
		vMax = 255;



	tex->u0 = tex->x;
	tex->v0 = tex->y;
	tex->u1 = uMax;
	tex->v1 = tex->y;
	tex->u2 = tex->x;
	tex->v2 = vMax;
	tex->u3 = uMax;
	tex->v3 = vMax;
	tex->handle = desthandle;
	tex->imageCRC = 0;

}

extern void direct2FindTextureInstances(PSIMODEL *model,TEXINSTANCE *instance,TextureType *src);


// We have a PSI model which needs to have different instances with
// different texture animations on each one.
TEXINSTANCE *texanimSetupInstanceModel(PSIMODEL *model, int textureCrc, int new_texture)
{
	TextureType *src;
	TEXINSTANCE *dest;

	if(*(int *)model != BFF_PSI1_ID)
	{
		DB("texinstancemodel not a PSI1\n");
		return NULL;
	}
// Part I, create a copy of the texture...

	src = textureFindCRCInAllBanks(textureCrc);
	if(!src)
	{
		DB("texinstancemodel texture not found\n");
		return NULL;
	}

	dest = MALLOC(sizeof(TEXINSTANCE));
	if(new_texture)
	{
	 //	texanimDuplicateTexture(src,&dest->tex);
			dest->tex = *src;	
	}
	else
	{
		dest->tex = *src;
	}

	dest->n_pointers = 0;
	direct2FindTextureInstances(model,dest,src);


	return dest;
}

void texanimInstanceModel(TEXINSTANCE *instance)
{
	int i;
	for(i = 0; i < instance->n_pointers; i++)
	{
		*instance->pointers[i] = instance->values[i];
	}
}







TextureBankType *textureTidyBank(TextureBankType *bank)
{
//	return textureReallocTextureBank(bank);


 	TextureBankType	*newBank;
	int numTextures;
	int loop;
	int mallocSize;

	//MIKEY
	return bank;

}



TextureBankType *textureLoadInOneGo(char *filename)
{
	TextureBankType *bank;

	bank = textureLoadBank(filename);
//	textureDownloadBank(bank);
//	textureDestroyBank(bank);
#ifndef _WINDOWS
//	bank = textureTidyBank(bank);
#endif
	return bank;
}


psFont *fontTidy(psFont * font)
{
	TextureType *tex;
	int size;

	size = sizeof(TextureType)*font->numchars;
	tex = MALLOC(size);
	FMEMCPY(tex,font->txPtr,size);
	FREE(font->txPtr);
	font->txPtr = tex;
	return font;
}

////////////////////////////////////////////////////////////////////////////////////////
void overlayAlphaPoly(TextureType *spr,VECTOR *worldvecs, int n_verts, unsigned int bgr, int flags)
{

	VERT tempvert[12];
	int i;
	XYSHORT *xy;
	ULONG check,totalchecks;
	long	clipflag;
	int depth;
	int edgecheck;
	int alp;
	int trans;


	if(flags & ALPHA_POLY_ST_SUB)
	{
		trans = SEMITRANS_SUB;
	}
	else
	{
		trans = SEMITRANS_ADD;
	}

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

	for(i = 0; i < n_verts; i++)
	{
		tempvert[i].vx = worldvecs[i].vx - mycamera.vpx;
		tempvert[i].vy = worldvecs[i].vy - mycamera.vpy;
		tempvert[i].vz = worldvecs[i].vz - mycamera.vpz;
	}

	(ULONG*)xy=transformedVertices;
	transformVertexListA(tempvert, n_verts, transformedVertices, transformedDepths);
	totalchecks=0xffff;

	depth = 0;
	for(i=0; i<n_verts; i++)
	{
		check=0;
		if(xy[i].x<0)check|=OFFLEFT;
		if(xy[i].x>640 )check|=OFFRIGHT;
		if(xy[i].y<0)check|=OFFUP;
		if(xy[i].y>480 )check|=OFFDOWN;
	  	if(transformedDepths[i]<=0)
		{
			check|=OFFFRONT;
		}

//	  	if(transformedDepths[i]>16032)check|=OFFBACK;
		totalchecks&=check;
		depth += transformedDepths[i];
	}
	if(totalchecks != 0)
		return;

	depth /= n_verts;
	depth+=50;
//	depth >>= (3+2);
	//depth -= 15;
	if (depth < 0) depth = 0;
//	if (depth > 1023) depth = 1023;

	gte_ldsxy3(transformedVertices[0],transformedVertices[1],transformedVertices[2]);
	gte_nclip();
	gte_stopz(&clipflag);

	//if((clipflag < 0) || flags & DEBUGPOLY_DUBSIDED)
	if (clipflag < 0)
	{
//		for(i = 0; i < n_verts-2; i++)
//		{
			POLY_FT4			*siFT4;





			BEGINPRIM(siFT4, POLY_FT4);





			*(u_long *)  (&siFT4->x0) = *(u_long *) (&transformedVertices[0]);
			*(u_long *)  (&siFT4->x1) = *(u_long *) (&transformedVertices[1]);
			*(u_long *)  (&siFT4->x2) = *(u_long *) (&transformedVertices[2]);
			*(u_long *)  (&siFT4->x3) = *(u_long *) (&transformedVertices[3]);



			*(ULONG *)(&siFT4->u0) = ((unsigned long)*(USHORT *)&spr->u0)
				                  | (((unsigned long)(spr->clut)) <<16);
			*(ULONG *)(&siFT4->u2) = ((unsigned long)*(USHORT *)&spr->u2);
			*(ULONG *)(&siFT4->u3) = ((unsigned long)*(USHORT *)&spr->u3);

			*(ULONG *)(&siFT4->u1) = ((unsigned long)*(USHORT *)&spr->u1)
								  | (((unsigned long)(spr->tpage)) <<16)
								  | ((trans-1) << (16+5));

			*(ULONG*)&siFT4->r0 = (bgr & 0xffffff) | ((GPU_COM_TF4+2)<<24);

			setPolyFT4(siFT4);
			siFT4->code = GPU_COM_TF4;//|= 2;
			siFT4->tag = trans;
			siFT4->tpage = spr->tpage;

		//	siFT4[1] = siFT4[0];
			ENDPRIM(siFT4, depth, POLY_FT4);


			alp = (bgr>>24) & 0xff;
			BEGINPRIM(siFT4, POLY_FT4);

			//can't copy this happily//////////////////////////
			*(u_long *)  (&siFT4->x0) = *(u_long *) (&transformedVertices[0]);
			*(u_long *)  (&siFT4->x1) = *(u_long *) (&transformedVertices[1]);
			*(u_long *)  (&siFT4->x2) = *(u_long *) (&transformedVertices[2]);
			*(u_long *)  (&siFT4->x3) = *(u_long *) (&transformedVertices[3]);
			*(ULONG *)(&siFT4->u0) = ((unsigned long)*(USHORT *)&spr->u0)
				                  | (((unsigned long)(spr->clut)) <<16);
			*(ULONG *)(&siFT4->u2) = ((unsigned long)*(USHORT *)&spr->u2);
			*(ULONG *)(&siFT4->u3) = ((unsigned long)*(USHORT *)&spr->u3);

			*(ULONG *)(&siFT4->u1) = ((unsigned long)*(USHORT *)&spr->u1)
								  | (((unsigned long)(spr->tpage)) <<16)
								  | ((trans-1) << (16+5));
			*(ULONG*)&siFT4->r0 = (bgr & 0xffffff) | ((GPU_COM_TF4+2)<<24);
			setPolyFT4(siFT4);
			siFT4->code = GPU_COM_TF4;//|= 2;
			siFT4->tpage = spr->tpage;
			siFT4[1] = siFT4[0];
			////////////////////////////////////////////////////

			if(siFT4->tpage & (1 << 7))
			{
				siFT4->clut = overlayAlphaClut256;
			}
			else
			{
				siFT4->clut = overlayAlphaClut;
			}

//			siFT4->tpage = (spr->tpage) | ((SEMITRANS_SUB-1) << 5);
			siFT4->tag = SEMITRANS_SUB;

			siFT4->r0=alp;
			siFT4->g0=alp;
			siFT4->b0=alp;
//			setPolyFT4(siFT4);
			ENDPRIM(siFT4, (depth), POLY_FT4);




//		}

/*		{
			DR_TPAGE *si;
			BEGINPRIM(si, DR_TPAGE);
			SetDrawTPage(si,1,1,((SEMITRANS_SEMI-1)<<5));	// this is a macro, anyway
			ENDPRIM(si, depth, DR_TPAGE);
		}
*/	}
}


////////////////////////////////////////////////////////////////////////////////////////



void overlayAlphaBox(int x, int y, int w, int h, int b, int g, int r)
{
float tx, ty, tw, th;

	tx = 320.0f + (((float)x) * (640.0f / 512.0f));
	tw = (((float)w) * (640.0f / 512.0f));

	ty = 240.0f + (((float)y) * 1.875);
	th = (((float)h) * 1.875);

	x = tx; y = ty; w = tw; h = th;

	{
		POLY_F4 *f4;
		BEGINPRIM(f4, POLY_F4);
		setPolyF4(f4);
		f4->x0=f4->x2= x;
		f4->x1=f4->x3= x + w;
		f4->y0=f4->y1= y;
		f4->y2=f4->y3= y + h;
		setRGB0(f4, r,g,b);

//		f4->code = f4->code | 2;		
		f4->tag = SEMITRANS_SUB;
		ENDPRIM(f4, 2, POLY_F4);

	}

	{
	//	DR_TPAGE *tp;
	//	BEGINPRIM(tp, DR_TPAGE);
	//	setDrawTPage(tp,1,1,((SEMITRANS_SUB-1)<<5));
	// 	ENDPRIM(tp, 2,DR_TPAGE);
	}
}




