#include <sys\types.h>
#include <libgte.h>
#include <libgpu.h>
#include <gtemac.h>
#include <inline_c.h>
#include "typedefs.h"
#include "3d_gen.h"
#include "maths.h"
#include "..\game\objects.h"
#include "..\game\items.h"
#include "..\game\effects.h"
#include "..\game\effect2.h"
#include "..\game\control.h"

#include "../spec_psx/psxinput.h"	//## Remove if no input check required.
#include "..\game\input.h"         //##
#include "..\game\box.h"         	//##
#include "..\game\lara.h"         	//##

#define	X	0
#define	Y	1
#define	Z	2
#define	XYZ	3

#define	CLIPEXTRA	256

extern void	GetJointAbsPosition( ITEM_INFO *item, PHD_VECTOR *vec, int joint );

extern WORD rcossin_tbl[];

short	BatMesh[5][3]	= 	{	{ -48<<2, 0,  -12<<2	},	//
							{ -48<<2, 0,   12<<2	},   // Body.
							{  24<<2, 0,    0	},   //
							{ -36<<2, 0, -48<<2	},	// Left wing.
							{ -36<<2, 0,  48<<2	}	// Right wing.
						};

uchar	BatLinks[9]	= 	{	0<<1, 1<<1, 2<<1,	//
							3<<1, 0<<1, 2<<1, 	// Face links.
							1<<1, 4<<1, 2<<1, 	//
						};

uchar	SplashLinks[8*4] = {	8<<1,  9<<1,  0<<1, 1<<1,
							9<<1,  10<<1, 1<<1, 2<<1,
							10<<1, 11<<1, 2<<1, 3<<1,
							11<<1, 12<<1, 3<<1, 4<<1,
							12<<1, 13<<1, 4<<1, 5<<1,
							13<<1, 14<<1, 5<<1, 6<<1,
							14<<1, 15<<1, 6<<1, 7<<1,
							15<<1, 8<<1,  7<<1, 0<<1	};	// Table of which points make up which faces.

static BITE_INFO NodeOffsets[16] = 	{
									{ 	0,340,64, 7	},			// SPN_PILOTFLAME
									{ 	0,0,-96, 10	},			// SPN_WINGMUTEPARTICLES
									{ 	16,48,320, 13	},   		// SPN_PUNKFLAME
									{ 	0,-256,0, 5	},			// SPN_PENDULUMFLAME
									{ 	0,64,0, 10	},			// SPN_TONYHANDLFLAME
									{ 	0,64,0, 13	},			// SPN_TONYHANDRFLAME
									{ 	-32,-16,-192, 13  	},		// SPN_CLAMUTEPLASMA
									{ 	-64,410,0, 20  	},		// SPN_WILLBOSSLPLASMA
									{ 	64,410,0, 23  	},			// SPN_WILLBOSSRPLASMA
									{ 	-160,-8,16, 5  	},		// SPN_CLEANER5
									{ 	-160,-8,16, 9  	},		// SPN_CLEANER9
									{ 	-160,-8,16, 13  	},		// SPN_CLEANER13
							};

void S_DrawSparks()
{
	long		lp;
	long		w,h,x1,x2,x3,x4,y1,y2,y3,y4,z1;

	SPARKS	*sptr;
	FX_INFO 	*fx;
	ITEM_INFO	*item;
	TILE 	*polytile;
	POLY_FT4 	*polyft4;
	PSXSPRITESTRUCT* pSpriteInfo;

	short		*scrxy;	// X,Y
	long			*scrz;	// Z
	short		*TempMesh;

	mPushMatrix();
	mTranslateAbsXYZ(lara_item->pos.x_pos,lara_item->pos.y_pos,lara_item->pos.z_pos);

	scrxy = (short *) 0x1f800000;	// Set pointer to scratch pad.
	scrz = (long *) 0x1f800100;	// Set pointer to scratch pad.
	TempMesh = (short *) 0x1f800200;	// Set pointer to scratch pad.

	sptr = &spark[0];

	for (lp=0;lp<MAX_SPARKS;lp++)
	{
		if (db.polyptr >= db.polybuf_limit)
		{
			mPopMatrix();
			return;
		}

		if (sptr->On == 0)
		{
			sptr++;
			continue;
		}

		if (sptr->Flags & SP_FX)
		{
			fx = &effects[sptr->FxObj];
			if (sptr->Flags & SP_USEFXOBJPOS)
			{
				x1 = fx->pos.x_pos;
				y1 = fx->pos.y_pos;
				z1 = fx->pos.z_pos;

			}
			else
			{
				x1 = fx->pos.x_pos+sptr->x;
				y1 = fx->pos.y_pos+sptr->y;
				z1 = fx->pos.z_pos+sptr->z;

				if ((fx->object_number == EXTRAFX1 || fx->object_number == EXTRAFX2 || fx->object_number == EXTRAFX5) && fx->flag1 >= 1 && ((sptr->sLife - sptr->Life) > (GetRandomDraw()&3)+8))
				{
				 	sptr->x = x1;
				 	sptr->y = y1;
				 	sptr->z = z1;
				 	sptr->Flags &= ~SP_FX;
				}
			}
		}
		else if (sptr->Flags & SP_ITEM)
		{
			item = &items[sptr->FxObj];
			if (sptr->Flags & SP_USEFXOBJPOS)
			{
				x1 = item->pos.x_pos;
				y1 = item->pos.y_pos;
				z1 = item->pos.z_pos;
			}
			else if (sptr->Flags & SP_NODEATTATCH)
			{
				PHD_VECTOR	pos1;

				pos1.x = NodeOffsets[sptr->NodeNumber].x;
				pos1.y = NodeOffsets[sptr->NodeNumber].y;
				pos1.z = NodeOffsets[sptr->NodeNumber].z;
				if (sptr->NodeNumber == SPN_WINGMUTEPARTICLES)
				{
					pos1.x += sptr->x;
					pos1.y += sptr->y;
					pos1.z += sptr->z;
					GetJointAbsPosition( item, &pos1, NodeOffsets[sptr->NodeNumber].mesh_num );
					x1 = pos1.x;
					y1 = pos1.y;
					z1 = pos1.z;
				}
				else
				{
					GetJointAbsPosition( item, &pos1, NodeOffsets[sptr->NodeNumber].mesh_num );
					x1 = pos1.x + sptr->x;
					y1 = pos1.y + sptr->y;
					z1 = pos1.z + sptr->z;
				}

				if (	sptr->NodeNumber >= SPN_PUNKFLAME)	// Let go at some point?
				{
					long	cutoff;

					if (sptr->NodeNumber == SPN_PENDULUMFLAME)	// Later than the others.
						cutoff = (GetRandomDraw()&3)+12;
					else
						cutoff = (GetRandomDraw()&3)+8;

					if ((sptr->sLife - sptr->Life) > cutoff)
					{
						sptr->x = x1;
						sptr->y = y1;
						sptr->z = z1;
						sptr->Flags &= ~(SP_ITEM|SP_NODEATTATCH);
					}
				}
			}
			else
			{
				x1 = item->pos.x_pos+sptr->x;
				y1 = item->pos.y_pos+sptr->y;
				z1 = item->pos.z_pos+sptr->z;
			}
		}
		else
		{
			x1 = sptr->x;
			y1 = sptr->y;
			z1 = sptr->z;
		}

		x1 -= lara_item->pos.x_pos;
		y1 -= lara_item->pos.y_pos;
		z1 -= lara_item->pos.z_pos;

		if (	x1 < -20480 || x1 > 20480 ||
			y1 < -20480 || y1 > 20480 ||
			z1 < -20480 || z1 > 20480)
		{
			sptr->On = 0;
			sptr++;
			continue;
		}

		TempMesh[X] = x1;
		TempMesh[Y] = y1;
		TempMesh[Z] = z1;

		gte_ldv0(TempMesh);
		gte_rtps();
		gte_stsxy(scrxy);
		gte_stsz(scrz);

/*		if (sptr->Flags & SP_RICOCHET)
		{
			polyf3 = (POLY_F3 *) db.polyptr;

			mCalcPoint(sptr->x-(sptr->Xvel>>3),sptr->y-(sptr->Yvel>>3),sptr->z-(sptr->Zvel>>3),&result[0]);
			ProjectPCoord(result[X],result[Y],result[Z],&scr[1][0],MY_PSX_W>>1,MY_PSX_H>>1,phd_persp);
			mCalcPoint(sptr->x-(sptr->Xvel>>5),sptr->y-(sptr->Yvel>>5)+sptr->Height,sptr->z-(sptr->Zvel>>5),&result[0]);
			ProjectPCoord(result[X],result[Y],result[Z],&scr[2][0],MY_PSX_W>>1,MY_PSX_H>>1,phd_persp);

			if ( (scr[0][Z] < 32 || scr[0][Z] >= 0x5000) ||
				(scr[1][Z] < 32 || scr[1][Z] >= 0x5000) ||
				(scr[2][Z] < 32 || scr[2][Z] >= 0x5000) ||
				(scr[0][X] < 0  && scr[1][X] < 0 && scr[2][X] < 0) ||
				(scr[0][X] >= MY_PSX_W  && scr[1][X] >= MY_PSX_W && scr[2][X] >= MY_PSX_W) ||
				(scr[0][Y] < 0  && scr[1][Y] < 0 && scr[2][Y] < 0) ||
				(scr[0][Y] >= MY_PSX_H  && scr[1][Y] >= MY_PSX_H && scr[2][Y] >= MY_PSX_H))
			{
				sptr++;
				continue;
			}

			setlen(polyf3, 4);		// F3
			if (sptr->TransType)
				setcode(polyf3, 0x22);
			else
				setcode(polyf3, 0x20);
			if (scr[0][Z] > 0x4000)
			{
				unsigned long	tr,tg,tb;
				tr = (sptr->R * (0x5000-scr[0][Z])) >> 12;
				tg = (sptr->G * (0x5000-scr[0][Z])) >> 12;
				tb = (sptr->B * (0x5000-scr[0][Z])) >> 12;
				setRGB0(polyf3,tr,tg,tb);
			}
			else
				setRGB0(polyf3,sptr->R,sptr->G,sptr->B);
			setXY3(polyf3,scr[0][X],scr[0][Y],scr[1][X],scr[1][Y],scr[2][X],scr[2][Y]);
			MyaddPrim( db.ot,scr[0][Z]>>3,polyf3 );
			db.polyptr += sizeof(POLY_F3);
			if (sptr->TransType)
			{
				setDrawTPage((DR_TPAGE *)db.polyptr, 0, 1, getTPage(0, sptr->TransType-1, 0, 0));
				MyaddPrim( db.ot,scr[0][Z]>>3,(DR_TPAGE *)db.polyptr);
				db.polyptr += sizeof(DR_TPAGE);
			}
		}
		else if (sptr->Flags & SP_DEF)*/

		if (sptr->Flags & SP_DEF)
		{
			if (*scrz < 256 || *scrz >= 0x5000)
			{
				if (*scrz >= 0x5000)	// Out of range, turn it off.
					sptr->On = 0;
				sptr++;
				continue;
			}

			if (sptr->Flags & SP_SCALE)
			{
				long	minw=4;
				if ((sptr->Flags & SP_NODEATTATCH) && sptr->NodeNumber == SPN_PILOTFLAME)
					minw = 2;
				w = ((sptr->Width*phd_persp)<<sptr->Scalar)/(*scrz);
				h = ((sptr->Height*phd_persp)<<sptr->Scalar)/(*scrz);
				if (w > (sptr->Width<<sptr->Scalar))
					w = (sptr->Width<<sptr->Scalar);
				else if (w < minw)
					w = minw;
				if (h > (sptr->Height<<sptr->Scalar))
					h = (sptr->Height<<sptr->Scalar);
				else if (h < minw)
					h = minw;
			}
			else
			{
				w = sptr->Width;
				h = sptr->Height;
			}

			if ( (scrxy[X]+(w>>1) < 0) ||
				(scrxy[X]-(w>>1) >= MY_PSX_W) ||
				(scrxy[Y]+(h>>1) < 0) ||
				(scrxy[Y]-(h>>1) >= MY_PSX_H))
			{
				sptr++;
				continue;
			}

			polyft4 = (POLY_FT4 *) db.polyptr;

			if (sptr->Flags & SP_ROTATE)
			{
				long	sin,cos;
				long sinx1,sinx2,siny1,siny2;
				long	cosx1,cosx2,cosy1,cosy2;

				sin = ((short)rcossin_tbl[sptr->RotAng<<1]);
				cos = ((short)rcossin_tbl[(sptr->RotAng<<1)+1]);
				sinx1 = ((-w>>1)*sin)>>12;
				sinx2 = ((w>>1)*sin)>>12;
				siny1 = ((-h>>1)*sin)>>12;
				siny2 = ((h>>1)*sin)>>12;
				cosx1 = ((-w>>1)*cos)>>12;
				cosx2 = ((w>>1)*cos)>>12;
				cosy1 = ((-h>>1)*cos)>>12;
				cosy2 = ((h>>1)*cos)>>12;

				x1 = sinx1-cosy1+scrxy[X];
				x2 = sinx2-cosy1+scrxy[X];
				x3 = sinx2-cosy2+scrxy[X];
				x4 = sinx1-cosy2+scrxy[X];
				y1 = cosx1+siny1+scrxy[Y];
				y2 = cosx2+siny1+scrxy[Y];
				y3 = cosx2+siny2+scrxy[Y];
				y4 = cosx1+siny2+scrxy[Y];

				setXY4(polyft4,x1,y1,x2,y2,x4,y4,x3,y3);
			}
			else
			{
				x1 = scrxy[X]-(w>>1);
				x2 = scrxy[X]+(w>>1);
				y1 = scrxy[Y]-(h>>1);
				y2 = scrxy[Y]+(h>>1);
				setXY4(polyft4,x1,y1,x2,y1,x1,y2,x2,y2);
			}

			pSpriteInfo=psxspriteinfo+sptr->Def;
			setlen(polyft4, 9);		// POLY_FT4
			if (sptr->TransType)
				setcode(polyft4, 0x2e);	// 2e
			else
				setcode(polyft4, 0x2c);

			if (*scrz > 0x3000)
			{
				unsigned long	tr,tg,tb;
				tr = (sptr->R * (0x5000-(*scrz))) >> 13;
				tg = (sptr->G * (0x5000-(*scrz))) >> 13;
				tb = (sptr->B * (0x5000-(*scrz))) >> 13;
				setRGB0(polyft4,tr,tg,tb);
			}
			else
				setRGB0(polyft4,sptr->R,sptr->G,sptr->B);

			x1 = pSpriteInfo->u1;
			x2 = pSpriteInfo->u2;
			y1 = pSpriteInfo->v1;
			y2 = pSpriteInfo->v2;

			setUV4(polyft4,x1,y1,x2,y1,x1,y2,x2,y2);
			if (sptr->TransType)
				polyft4->tpage = (pSpriteInfo->tpage & (~96)) | ((sptr->TransType-1)<<5);
			else
				polyft4->tpage = pSpriteInfo->tpage;
			polyft4->clut = pSpriteInfo->clut;

			MyaddPrim( db.ot,(*scrz)>>3,polyft4 );
			db.polyptr += sizeof(POLY_FT4);
		}
		else
		{
			if ((*scrz) < 256 || (*scrz) >= 0x5000)
			{
				if ((*scrz) >= 0x5000)
					sptr->On = 0;
				sptr++;
				continue;
			}

			polytile = (TILE *) db.polyptr;

			if (sptr->Flags & SP_SCALE)
			{
				w = ((sptr->Width*phd_persp)<<sptr->Scalar)/(*scrz);
				h = ((sptr->Height*phd_persp)<<sptr->Scalar)/(*scrz);
				if (w > (sptr->Width<<sptr->Scalar))
					w = (sptr->Width<<sptr->Scalar);
				else if (w < 1)
					w = 1;
				if (h > (sptr->Height<<sptr->Scalar))
					h = (sptr->Height<<sptr->Scalar);
				else if (h < 1)
					h = 1;
			}
			else
			{
				w = sptr->Width;
				h = sptr->Height;
			}

			if (	(scrxy[X]+(w>>1) < 0) ||
				(scrxy[X]-(w>>1) >= MY_PSX_W) ||
				(scrxy[Y]+(h>>1) < 0) ||
				(scrxy[Y]-(h>>1) >= MY_PSX_H))
			{
				sptr++;
				continue;
			}

			setlen(polytile, 3);		// tile
			if (sptr->TransType)
				setcode(polytile, 0x62);
			else
				setcode(polytile, 0x60);
			if ((*scrz) > 0x3000)
			{
				unsigned long	tr,tg,tb;
				tr = (sptr->R * (0x5000-(*scrz))) >> 13;
				tg = (sptr->G * (0x5000-(*scrz))) >> 13;
				tb = (sptr->B * (0x5000-(*scrz))) >> 13;
				setRGB0(polytile,tr,tg,tb);
			}
			else
				setRGB0(polytile,sptr->R,sptr->G,sptr->B);
			setXY0(polytile,scrxy[X]-(w>>1),scrxy[Y]-(h>>1));
			setWH(polytile,w,h);
			MyaddPrim( db.ot,(*scrz)>>3,polytile );
			db.polyptr += sizeof(TILE);
			if (sptr->TransType)
			{
				if (db.polyptr >= db.polybuf_limit)
				{
					mPopMatrix();
					return;
				}
				setDrawTPage((DR_TPAGE *)db.polyptr, 0, 1, getTPage(0, sptr->TransType-1, 0, 0));
				MyaddPrim( db.ot,(*scrz)>>3,(DR_TPAGE *)db.polyptr);
				db.polyptr += sizeof(DR_TPAGE);
			}
		}
		sptr++;
	}

	mPopMatrix();
}


void S_DrawSplashes()
{
	SPLASH_STRUCT	*sptr;
	RIPPLE_STRUCT	*rptr;
	PSXSPRITESTRUCT* pSpriteInfo;
	POLY_GT4		*gt4;
	POLY_FT4 		*ft4;
//	long			*result;
//	long			*scrpoints;	// X,Y,Z.
	uchar		*pptr;
	long			lp,vlp,olp;
	long			linkadd;
	long			u1,u2,v1,v2;
	long			x1,x2,x3,x4,y1,y2,y3,y4,otz,z1,z2,z3,z4;

	short		*scrxy;	// X,Y
	long			*scrz;	// Z
	short		*TempMesh;

	TempMesh = (short *) 0x1f800300;	// Set pointer to scratch pad.

	sptr = &splashes[0];

	for (lp=0;lp<MAX_SPLASHES;lp++)
	{
		SPLASH_VERTS	*svptr;

		if ((sptr->flags & SPL_ON) == 0)
		{
			sptr++;
			continue;
		}

		svptr = &sptr->sv[0];

		mPushMatrix();
//		SetRotMatrix((MATRIX*) Matrix);
//		SetTransMatrix((MATRIX*) Matrix);
//		mTranslateXYZ(sptr->x, sptr->y, sptr->z);
		mTranslateAbsXYZ(sptr->x, sptr->y, sptr->z);

		scrxy = (short *) 0x1f800000;	// Set pointer to scratch pad.
		scrz = (long *) 0x1f800100;	// Set pointer to scratch pad.

		for (vlp=0;vlp<48;vlp++)
		{
			TempMesh[X] = (svptr->wx>>4);
			TempMesh[Y] = svptr->wy;
			TempMesh[Z] = (svptr->wz>>4);

			gte_ldv0(TempMesh);
			gte_rtps();
			svptr++;
			gte_stsxy(scrxy);
			gte_stsz(scrz);

			scrxy+=2;
			scrz+=2;
		}

		mPopMatrix();

		scrxy = (short *) 0x1f800000;	// Set pointer to beginning of scratch pad.
		scrz = (long *) 0x1f800100;	// Set pointer to scratch pad.
		gt4=(POLY_GT4*)db.polyptr;

		for (olp=0;olp<3;olp++)
		{
			if (sptr->flags & SPL_KAYAK_SPLASH)
			{
				if (olp == 2 || (olp == 0 && (sptr->flags & SPL_RIPPLEINNER)) || (olp == 1 && (sptr->flags & SPL_RIPPLEMIDDLE)))
					continue;
			}

			if (olp == 2 || (olp == 0 && (sptr->flags & SPL_RIPPLEINNER)) || (olp == 1 && (sptr->flags & SPL_RIPPLEMIDDLE)))
				pSpriteInfo=psxspriteinfo+objects[EXPLOSION1].mesh_index+4+((wibble>>4)&3);
			else
				pSpriteInfo=psxspriteinfo+objects[EXPLOSION1].mesh_index+8;

			u1 = pSpriteInfo->u1;
			u2 = pSpriteInfo->u2;
			v1 = pSpriteInfo->v1;
			v2 = pSpriteInfo->v2;

			pptr = &SplashLinks[0];
			linkadd = olp<<5;

			for (vlp=0;vlp<8;vlp++)
			{
				if ((char *)gt4 >= db.polybuf_limit)
				{
					db.polyptr = (char *)gt4;
					return;
				}

				x1 = scrxy[(*pptr)+linkadd];
				y1 = scrxy[(*pptr)+1+linkadd];
				z1 = scrz[(*pptr++)+linkadd];
				x2 = scrxy[(*pptr)+linkadd];
				y2 = scrxy[(*pptr)+1+linkadd];
				z2 = scrz[(*pptr++)+linkadd];
				x3 = scrxy[(*pptr)+linkadd];
				y3 = scrxy[(*pptr)+1+linkadd];
				z3 = scrz[(*pptr++)+linkadd];
				x4 = scrxy[(*pptr)+linkadd];
				y4 = scrxy[(*pptr)+1+linkadd];
				z4 = scrz[(*pptr++)+linkadd];

				otz = (z1+z2+z3+z4)>>2;

				if ( (otz < 256 || otz >= 0x5000) ||
					(z1 < 256 || z2 < 256 || z3 < 256 || z4 < 256) ||
					(x1 < 0 && x2 < 0 && x3 < 0 && x4 < 0) ||
					(x1 >= MY_PSX_W && x2 >= MY_PSX_W && x3 >= MY_PSX_W && x4 >= MY_PSX_W) ||
					(y1 < 0 && y2 < 0 && y3 < 0 && y4 < 0) ||
					(y1 >= MY_PSX_H && y2 >= MY_PSX_H && y3 >= MY_PSX_H && y4 >= MY_PSX_H))
				{
					continue;
				}

				setlen(gt4, 12);
				setcode(gt4, (sptr->flags & SPL_TRANS) ? 0x3e : 0x3c);
				setXY4(gt4,x1,y1,x2,y2,x3,y3,x4,y4);
				setUV4(gt4,u1,v1,u2,v1,u1,v2,u2,v2);
				gt4->r0 = gt4->g0 = gt4->b0 = gt4->r1 = gt4->g1 = gt4->b1 = (sptr->life);
				gt4->r2 = gt4->g2 = gt4->b2 = gt4->r3 = gt4->g3 = gt4->b3 = (sptr->life)-(sptr->life>>2);
				gt4->clut = pSpriteInfo->clut;
				gt4->tpage = (pSpriteInfo->tpage & (~96)) | (1<<5);	// Set colour addition.
				MyaddPrim( db.ot,otz>>3, gt4 );
				gt4++;
			}
		}
		db.polyptr = (uchar *) gt4;
		sptr++;
	}

	ft4 = (POLY_FT4 *) db.polyptr;

	rptr = &ripples[0];
	for (lp=0;lp<MAX_RIPPLES;lp++)
	{
		if ((char *)ft4 >= db.polybuf_limit)
		{
			db.polyptr = (char *)ft4;
			return;
		}

		if (rptr->flags & SPL_ON)
		{
			long	size = rptr->size<<2;

			scrxy = (short *) 0x1f800000;	// Set pointer to beginning of scratch pad.
			scrz = (long *) 0x1f800100;	// Set pointer to scratch pad.

			mPushMatrix();
//			SetRotMatrix((MATRIX*) Matrix);
//			SetTransMatrix((MATRIX*) Matrix);
//			mTranslateXYZ(rptr->x, rptr->y, rptr->z);
			mTranslateAbsXYZ(rptr->x, rptr->y, rptr->z);

			TempMesh[X] = -size;
			TempMesh[Y] = 0;
			TempMesh[Z] = -size;

			gte_ldv0(TempMesh);
			gte_rtps();
			TempMesh[X] = size;
			gte_stsxy(scrxy);
			gte_stsz(scrz);

			gte_ldv0(TempMesh);
			gte_rtps();
			scrxy+=2;
			scrz++;
			TempMesh[X] = -size;
			TempMesh[Z] = size;
			gte_stsxy(scrxy);
			gte_stsz(scrz);

			gte_ldv0(TempMesh);
			gte_rtps();
			scrxy+=2;
			scrz++;
			TempMesh[X] = size;
			gte_stsxy(scrxy);
			gte_stsz(scrz);

			gte_ldv0(TempMesh);
			gte_rtps();
			scrxy+=2;
			scrz++;
			gte_stsxy(scrxy);
			gte_stsz(scrz);

			mPopMatrix();

			scrxy -= 6;	// Reset pointer to beginning of screen XYs.
			scrz -= 3;	// Reset pointer to beginning of screen Zs.

			x1 = *scrxy++;
			y1 = *scrxy++;
			z1 = *scrz++;
			x2 = *scrxy++;
			y2 = *scrxy++;
			z2 = *scrz++;
			x3 = *scrxy++;
			y3 = *scrxy++;
			z3 = *scrz++;
			x4 = *scrxy++;
			y4 = *scrxy;
			z4 = *scrz;

			otz = (z1+z2+z3+z4)>>2;

			if ( (otz < 256 || otz >= 0x5000) ||
				(z1 < 256|| z2 < 256 || z3 < 256 || z4 < 256) ||
				(x1 < 0 && x2 < 0 && x3 < 0 && x4 < 0) ||
				(x1 >= MY_PSX_W && x2 >= MY_PSX_W && x3 >= MY_PSX_W && x4 >= MY_PSX_W) ||
				(y1 < 0 && y2 < 0 && y3 < 0 && y4 < 0) ||
				(y1 >= MY_PSX_H && y2 >= MY_PSX_H && y3 >= MY_PSX_H && y4 >= MY_PSX_H))
			{
				rptr++;
				continue;
			}

			setlen(ft4, 9);
			setcode(ft4, (rptr->flags & SPL_TRANS) ? 0x2e : 0x2c);
			setXY4(ft4,x1,y1,x2,y2,x3,y3,x4,y4);

			if (rptr->flags & SPL_BLOOD)
				pSpriteInfo=psxspriteinfo+objects[EXPLOSION1].mesh_index;		// Get ripple texture.
			else
				pSpriteInfo=psxspriteinfo+objects[EXPLOSION1].mesh_index+9;		// Get ripple texture.

			u1 = pSpriteInfo->u1;
			u2 = pSpriteInfo->u2;
			v1 = pSpriteInfo->v1;
			v2 = pSpriteInfo->v2;

			setUV4(ft4,u1,v1,u2,v1,u1,v2,u2,v2);

			if (rptr->flags & SPL_MORETRANS)
			{
				if (rptr->flags & SPL_BLOOD)
				{
#ifdef GERMAN
					if (rptr->init)
						setRGB0(ft4,rptr->init>>2,0,rptr->init>>1);
					else
						setRGB0(ft4,rptr->life>>2,0,rptr->life>>1);
#else
					if (rptr->init)
						setRGB0(ft4,rptr->init>>1,0,rptr->init>>4);
					else
						setRGB0(ft4,rptr->life>>1,0,rptr->life>>4);
#endif
				}
				else
				{
					if (rptr->init)
						setRGB0(ft4,rptr->init,rptr->init,rptr->init);
					else
						setRGB0(ft4,rptr->life,rptr->life,rptr->life);
				}
			}
			else
			{
				if (rptr->init)
					setRGB0(ft4,rptr->init<<1,rptr->init<<1,rptr->init<<1);
				else
					setRGB0(ft4,rptr->life<<1,rptr->life<<1,rptr->life<<1);
			}
			ft4->clut = pSpriteInfo->clut;
			ft4->tpage = (pSpriteInfo->tpage & (~96)) | (1<<5);	// Set colour addition.
			MyaddPrim( db.ot,otz>>3, ft4 );
			ft4++;
		}
		rptr++;
	}

	db.polyptr = (uchar *) ft4;

}

void S_DrawBat()
{
	PSXSPRITESTRUCT *pSpriteInfo;
	POLY_FT3		*ft3;
	BAT_STRUCT	*bptr;
	short		*scrxy;	// X,Y
	long			*scrz;	// Z
	uchar		*pptr;
	short		*TempMesh;
	long			lp,vlp;
	long			u1,u2,v1,v2;
	long			x1,x2,x3,y1,y2,y3,z1,z2,z3,otz;

	scrxy = (short *) 0x1f800000;	// Set pointer to scratch pad.
	scrz = (long *) 0x1f800100;	// Set pointer to scratch pad.
	TempMesh = (short *) 0x1f800200;	// Set pointer to scratch pad.

	ft3=(POLY_FT3*)db.polyptr;

	bptr = &bats[0];
	for (lp=0;lp<MAX_BATS;lp++)
	{
		if (bptr->flags & B_ON)
		{
			mPushMatrix();
//			SetRotMatrix((MATRIX*) Matrix);
//			SetTransMatrix((MATRIX*) Matrix);
//			mTranslateXYZ(bptr->x, bptr->y, bptr->z);
			mTranslateAbsXYZ(bptr->x, bptr->y, bptr->z);
			mRotY(bptr->angle<<4);
//			SetRotMatrix((MATRIX*) Matrix);	// ???
//			SetTransMatrix((MATRIX*) Matrix);  // ???

			for (vlp=0;vlp<5;vlp++)
			{
				TempMesh[X] = BatMesh[vlp][X];
				if (vlp >= 3)
					TempMesh[Y] = BatMesh[vlp][Y] - 512 + ((rcossin_tbl[bptr->WingYoff<<7])>>4);
				else
					TempMesh[Y] = BatMesh[vlp][Y] - 512 + ((rcossin_tbl[((bptr->WingYoff+32)&63)<<7])>>8);
				TempMesh[Z] = BatMesh[vlp][Z];

				gte_ldv0(TempMesh);
				gte_rtps();
				gte_stsxy(scrxy);
				gte_stsz(scrz);
				scrxy+=2;
				scrz+=2;
			}

			mPopMatrix();

			scrxy = (short *) 0x1f800000;	// Set pointer to scratch pad.
			scrz = (long *) 0x1f800100;	// Set pointer to scratch pad.

			pSpriteInfo=psxspriteinfo+objects[EXPLOSION1].mesh_index+12;

			u1 = pSpriteInfo->u1;
			u2 = pSpriteInfo->u2;
			v1 = pSpriteInfo->v1;
			v2 = pSpriteInfo->v2;

			pptr = &BatLinks[0];

			for (vlp=0;vlp<3;vlp++)
			{
				if ((char *)ft3 >= db.polybuf_limit)
				{
					db.polyptr = (char *)ft3;
					return;
				}

				x1 = scrxy[(*pptr)];
				y1 = scrxy[(*pptr)+1];
				z1 = scrz[(*pptr++)];
				x2 = scrxy[(*pptr)];
				y2 = scrxy[(*pptr)+1];
				z2 = scrz[(*pptr++)];
				x3 = scrxy[(*pptr)];
				y3 = scrxy[(*pptr)+1];
				z3 = scrz[(*pptr++)];

				otz = (z1+z2+z3)/3;

				if ( (otz < 32 || otz >= 0x5000) ||
					(z1 < 32 || z2 < 32 || z3 < 32 ) ||
					(x1 < 0 && x2 < 0 && x3 < 0 ) ||
					(x1 >= MY_PSX_W && x2 >= MY_PSX_W && x3 >= MY_PSX_W ) ||
					(y1 < 0 && y2 < 0 && y3 < 0 ) ||
					(y1 >= MY_PSX_H && y2 >= MY_PSX_H && y3 >= MY_PSX_H ))
				{
					continue;
				}

				setPolyFT3(ft3);
				setXY3(ft3,x1,y1,x2,y2,x3,y3);

				if (!vlp)
					setUV3(ft3,u1,v1+1,u2-1,v2,u1,v2);
				else if (vlp==1)
					setUV3(ft3,u2,v1,u1,v1,u2,v2);
				else
					setUV3(ft3,u1,v1,u2,v1,u2,v2);

				setRGB0(ft3,192,128,80);
				//setRGB0(ft3,255,255,255);
				ft3->clut = pSpriteInfo->clut;
				ft3->tpage = pSpriteInfo->tpage;
				MyaddPrim( db.ot,otz>>3, ft3 );
				ft3++;
			}
		}
		bptr++;
	}

	db.polyptr = (uchar *) ft3;
}

void	S_DrawDarts( ITEM_INFO *item )
{
	LINE_G2 	*lineg2;
	long		x, y, z, speed;
	short  	*scrxy;	// X,Y
	long	  	*scrz;	// Z
	short  	*TempMesh;

	if (db.polyptr >= db.polybuf_limit)
		return;

	mPushMatrix();
//	SetRotMatrix((MATRIX*) Matrix);
//	SetTransMatrix((MATRIX*) Matrix);
//	mTranslateXYZ(item->pos.x_pos,item->pos.y_pos,item->pos.z_pos);
	mTranslateAbsXYZ(item->pos.x_pos,item->pos.y_pos,item->pos.z_pos);

	scrxy = (short *) 0x1f800000;	// Set pointer to scratch pad.
	scrz = (long *) 0x1f800100;	// Set pointer to scratch pad.
	TempMesh = (short *) 0x1f800200;	// Set pointer to scratch pad.

	TempMesh[0] = TempMesh[1] = TempMesh[2] = x = z = 0;
	gte_ldv0(TempMesh);
	gte_rtps();
	gte_stsxy(scrxy);
	gte_stsz(scrz);
	scrxy+=2;
	scrz++;

	speed = (-96 * phd_cos(item->pos.x_rot)) >> W2V_SHIFT;
	z = (speed * phd_cos(item->pos.y_rot)) >> W2V_SHIFT;
	x = (speed * phd_sin(item->pos.y_rot)) >> W2V_SHIFT;
	y = ((96 * phd_sin(item->pos.x_rot)) >> W2V_SHIFT);

	TempMesh[0] = x;
	TempMesh[1] = y;
	TempMesh[2] = z;
	gte_ldv0(TempMesh);
	gte_rtps();
	gte_stsxy(scrxy);
	gte_stsz(scrz);
	scrxy-=2;
	scrz--;

	if (	scrz[0] > 0x5000 || scrz[0] < 256 ||
		scrz[1] > 0x5000 || scrz[1] < 256 ||
		scrxy[0] < -32    || scrxy[2] < -32 ||
		scrxy[0] > 512+32 || scrxy[2] > 512+32 ||
		scrxy[1] < -64    || scrxy[3] < -64 ||
		scrxy[1] > 256+64 || scrxy[3] > 256+64)
	{
		mPopMatrix();
		return;
	}

	lineg2 = (LINE_G2 *)db.polyptr;
	setlen(lineg2, 4);
	setcode(lineg2, 0x50);
	setRGB1(lineg2,120,60,20);
	setRGB0(lineg2,0,0,0);
	setXY2(lineg2,scrxy[0],scrxy[1],scrxy[2],scrxy[3]);
	MyaddPrim(db.ot, scrz[0]>>3, lineg2);
	lineg2++;
	db.polyptr = (char *)lineg2;

	mPopMatrix();
}

#if	0

unsigned char BoxesDrawn[2048];

void	S_DrawAIBoxes()
{
	LINE_G2 *lineg2;
	long	result[XYZ];
	long	result2[XYZ];
	long	result3[XYZ];
	long	result4[XYZ];
	long	lp, distance;
	long	x, y, z, radius;
	long	screencoords[XYZ];
	long screencoords2[XYZ];
	long screencoords3[XYZ];
	long screencoords4[XYZ];
	long dir, angle, roomno;
	long	wx,wy,wz,boxno;
	BOX_INFO *box;
	FLOOR_INFO *floor;
	ROOM_INFO *r;

	SetRotMatrix((MATRIX*) Matrix);
	SetTransMatrix((MATRIX*) Matrix);

	for (x=0;x<2048;x++)
		BoxesDrawn[x]=0;

	r = &room[lara_item->room_number];

	for (y=1;y<r->y_size-1;y++)
	{
		for (x=1;x<r->x_size-1;x++)
		{
			if (BoxesDrawn[r->floor[x+(y*r->x_size)].box] == 0)
			{
				boxno = r->floor[x+(y*r->x_size)].box;
				box = &boxes[boxno];
				BoxesDrawn[boxno] = 1;

				wz = (box->left*1024);
				wy = box->height;
				wx = (box->top*1024);
				mCalcPoint(wx, wy, wz, &result[0]);
				ProjectPCoord(result[X],result[Y],result[Z],screencoords,MY_PSX_W>>1,MY_PSX_H>>1,phd_persp);

				wz = (box->right*1024);
				wy = box->height;
				wx = (box->top*1024);
				mCalcPoint(wx, wy, wz, &result2[0]);
				ProjectPCoord(result2[X],result2[Y],result2[Z],screencoords2,MY_PSX_W>>1,MY_PSX_H>>1,phd_persp);

				wz = (box->right*1024);
				wy = box->height;
				wx = (box->bottom*1024);
				mCalcPoint(wx, wy, wz, &result3[0]);
				ProjectPCoord(result3[X],result3[Y],result3[Z],screencoords3,MY_PSX_W>>1,MY_PSX_H>>1,phd_persp);

				wz = (box->left*1024);
				wy = box->height;
				wx = (box->bottom*1024);
				mCalcPoint(wx, wy, wz, &result4[0]);
				ProjectPCoord(result4[X],result4[Y],result4[Z],screencoords4,MY_PSX_W>>1,MY_PSX_H>>1,phd_persp);

				lineg2 = (LINE_G2 *)db.polyptr;

				if (result[Z] > 32 && result2[Z] > 32 &&
					(screencoords[X]  > -CLIPEXTRA && screencoords[X]  < 512+CLIPEXTRA) &&
					(screencoords2[X] > -CLIPEXTRA && screencoords2[X] < 512+CLIPEXTRA) &&
					(screencoords[Y]  > -CLIPEXTRA && screencoords[Y]  < 256+CLIPEXTRA) &&
					(screencoords2[Y] > -CLIPEXTRA && screencoords2[Y] < 256+CLIPEXTRA))
				{
					setlen(lineg2, 4);
					setcode(lineg2, 0x50);
					setRGB1(lineg2,0,255,0);
					setRGB0(lineg2,255,0,0);
					setXY2(lineg2,screencoords[X],screencoords[Y],screencoords2[X],screencoords2[Y]);
					MyaddPrim(db.ot, 64, lineg2);
					lineg2++;
				}

				if (result3[Z] > 32 && result2[Z] > 32 &&
					(screencoords3[X] > -CLIPEXTRA && screencoords3[X] < 512+CLIPEXTRA) &&
					(screencoords2[X] > -CLIPEXTRA && screencoords2[X] < 512+CLIPEXTRA) &&
					(screencoords3[Y] > -CLIPEXTRA && screencoords3[Y] < 256+CLIPEXTRA) &&
					(screencoords2[Y] > -CLIPEXTRA && screencoords2[Y] < 256+CLIPEXTRA))
				{
					setlen(lineg2, 4);
					setcode(lineg2, 0x50);
					setRGB1(lineg2,0,255,0);
					setRGB0(lineg2,255,0,0);
					setXY2(lineg2,screencoords2[X],screencoords2[Y],screencoords3[X],screencoords3[Y]);
					MyaddPrim(db.ot, 64, lineg2);
					lineg2++;
				}

				if (result3[Z] > 32 && result4[Z] > 32 &&
					(screencoords3[X] > -CLIPEXTRA && screencoords3[X] < 512+CLIPEXTRA) &&
					(screencoords4[X] > -CLIPEXTRA && screencoords4[X] < 512+CLIPEXTRA) &&
					(screencoords3[Y] > -CLIPEXTRA && screencoords3[Y] < 256+CLIPEXTRA) &&
					(screencoords4[Y] > -CLIPEXTRA && screencoords4[Y] < 256+CLIPEXTRA))
				{
					setlen(lineg2, 4);
					setcode(lineg2, 0x50);
					setRGB1(lineg2,0,255,0);
					setRGB0(lineg2,255,0,0);
					setXY2(lineg2,screencoords3[X],screencoords3[Y],screencoords4[X],screencoords4[Y]);
					MyaddPrim(db.ot, 64, lineg2);
					lineg2++;
				}

				if (result[Z] > 32 && result4[Z] > 32 &&
					(screencoords[X]  > -CLIPEXTRA && screencoords[X]  < 512+CLIPEXTRA) &&
					(screencoords4[X] > -CLIPEXTRA && screencoords4[X] < 512+CLIPEXTRA) &&
					(screencoords[Y]  > -CLIPEXTRA && screencoords[Y]  < 256+CLIPEXTRA) &&
					(screencoords4[Y] > -CLIPEXTRA && screencoords4[Y] < 256+CLIPEXTRA))
				{
					setlen(lineg2, 4);
					setcode(lineg2, 0x50);
					setRGB1(lineg2,0,255,0);
					setRGB0(lineg2,255,0,0);
					setXY2(lineg2,screencoords[X],screencoords[Y],screencoords4[X],screencoords4[Y]);
					MyaddPrim(db.ot, 64, lineg2);
					lineg2++;
				}

				db.polyptr = (char *)lineg2;
			}
		}
	}

}

#endif
