#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 "gpu.h"
#include "..\game\objects.h"
#include "..\game\items.h"
#include "..\game\anim.h"

#define UNIT_SHADOW_SHIFT 8

void S_DrawSprite(uint32 dwFlags,sint32 nX,sint32 nY,sint32 nZ,sint16 nSprite,sint16 nShade,sint16 nScale)
	{
	sint32 xv,yv,zv,otz;
	sint32 x1,y1,x2,y2;
	POLY_FT4* pFT4;
	PSXSPRITESTRUCT* pSpriteInfo;
	uint32 dwRGBC;

	if (db.polyptr>=db.polybuf_limit)
		return;
	if (dwFlags&SPRITE_ABS)
		{
		nX-=w2v_matrix[M03];
		nY-=w2v_matrix[M13];
		nZ-=w2v_matrix[M23];
		if (nX<-phd_viewdist || nX>phd_viewdist ||
			nY<-phd_viewdist || nY>phd_viewdist ||
			nZ<-phd_viewdist || nZ>phd_viewdist)
				return;
		zv=w2v_matrix[M20]*nX+w2v_matrix[M21]*nY+w2v_matrix[M22]*nZ;
		if (zv<phd_znear || zv>=phd_zfar)
			return;
		xv=w2v_matrix[M00]*nX+w2v_matrix[M01]*nY+w2v_matrix[M02]*nZ;
		yv=w2v_matrix[M10]*nX+w2v_matrix[M11]*nY+w2v_matrix[M12]*nZ;
		}
	else
		{
		if ((nX|nY|nZ)==0)
			{
			zv=phd_mxptr[M23];
			if (zv<phd_znear || zv>phd_zfar)
				return;
			xv=phd_mxptr[M03];
			yv=phd_mxptr[M13];
			}
		else
			{
			zv=phd_mxptr[M20]*nX+phd_mxptr[M21]*nY+phd_mxptr[M22]*nZ+phd_mxptr[M23];
			if (zv<phd_znear || zv>phd_zfar)
				return;
			xv=phd_mxptr[M00]*nX+phd_mxptr[M01]*nY+phd_mxptr[M02]*nZ+phd_mxptr[M03];
			yv=phd_mxptr[M10]*nX+phd_mxptr[M11]*nY+phd_mxptr[M12]*nZ+phd_mxptr[M13];
			}
		}
	otz=zv>>(W2V_SHIFT+2);
	zv/=phd_persp;

	pSpriteInfo=psxspriteinfo+nSprite;
	x1=pSpriteInfo->x1;
	y1=pSpriteInfo->y1;
	x2=pSpriteInfo->x2;
	y2=pSpriteInfo->y2;
	if (dwFlags&SPRITE_SCALE)
		{
		x1=(x1*nScale)<<(W2V_SHIFT-8);
		x2=(x2*nScale)<<(W2V_SHIFT-8);
		nScale-=(nScale>>2);

		y1=(y1*nScale)<<(W2V_SHIFT-8);
		y2=(y2*nScale)<<(W2V_SHIFT-8);
		}
	else
		{
		x1<<=W2V_SHIFT;
		y1<<=W2V_SHIFT;
		x2<<=W2V_SHIFT;
		y2<<=W2V_SHIFT;
		}
	x1=(sint32)((xv+x1)/zv+phd_centerx); if (x1>=phd_winwidth) return;
	y1=(sint32)((yv+y1)/zv+phd_centery); if (y1>=phd_winheight) return;
	x2=(sint32)((xv+x2)/zv+phd_centerx); if (x2<0) return;
	y2=(sint32)((yv+y2)/zv+phd_centery); if (y2<0) return;

	if (dwFlags&SPRITE_SHADE)
		{
		nShade=(0x1fff-nShade)>>5;
		if (otz>DPQ_START)
			nShade-=(otz-DPQ_START)>>5;
		if (nShade<0)
			nShade=0;
		if (nShade>255)
			nShade=255;
		if (dwFlags&SPRITE_TINT)
			{
			uint32 nR,nG,nB;

			nR=(dwFlags&0xff)*nShade; if (nR&0xffff0000) nR=255; else nR>>=8;
			nG=((dwFlags>>8)&0xff)*nShade; if (nG&0xffff0000) nG=255; else nG>>=8;
			nB=((dwFlags>>16)&0xff)*nShade; if (nB&0xffff0000) nB=255; else nB>>=8;
			dwRGBC=MAKE_RGB(nR,nG,nB);
			}
		else
			dwRGBC=MAKE_RGB(nShade,nShade,nShade);
		}
	else if (dwFlags&SPRITE_TINT)
		dwRGBC=dwFlags&0x00ffffff;
	else
		dwRGBC=0x808080;

	pFT4=(POLY_FT4*)db.polyptr;
	*((uint32*)pFT4)=0x09000000;
	*((uint32*)&pFT4->r0)=dwRGBC|0x2c000000|(dwFlags&SPRITE_SEMITRANS);
	*((uint32*)&pFT4->x0)=(x1&0xffff)|(y1<<16);
	*((uint32*)&pFT4->x1)=(x2&0xffff)|(y1<<16);
	*((uint32*)&pFT4->x2)=(x1&0xffff)|(y2<<16);
	*((uint32*)&pFT4->x3)=(x2&0xffff)|(y2<<16);
	*((uint32*)&pFT4->u0)=pSpriteInfo->u1|(pSpriteInfo->v1<<8)|(pSpriteInfo->clut<<16);
	*((uint32*)&pFT4->u1)=pSpriteInfo->u2|(pSpriteInfo->v1<<8)|((pSpriteInfo->tpage<<16)|((dwFlags&0x60000000)>>8));
	*((uint32*)&pFT4->u2)=pSpriteInfo->u1|(pSpriteInfo->v2<<8);
	*((uint32*)&pFT4->u3)=pSpriteInfo->u2|(pSpriteInfo->v2<<8);
	MyaddPrim(db.ot,otz>>OTRIGHT,pFT4);
	db.polyptr=(char*)(pFT4+1);
	}

/**************************************************************************************************
 *					Draw Objects Shadow On Screen !!!
 *************************************************************************************************/
void	S_PrintShadow( sint16 size, sint16 *bptr, ITEM_INFO *iptr, int underwater)
{
	POLY_FT4* p;
	int midx,addx;
	int midz,addz;
	uint32 otz,piss,flag;
	PSXSPRITESTRUCT* dptr;
	SVECTOR svec[4],* sptr;			// Vertices For Shadows

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

	phd_PushMatrix();
	phd_TranslateAbs(iptr->pos.x_pos,iptr->floor, iptr->pos.z_pos);
	if (*(phd_mxptr+M23)<=phd_znear || *(phd_mxptr+M23)>=phd_zfar)		// Return Now if shadow
		{																// Is Too Near OR Too Far
		phd_PopMatrix();
		return;
		}
	phd_RotY(iptr->pos.y_rot);
	DownLoadMatrix();
	phd_PopMatrix();

	midx=(*(bptr+0)+*(bptr+1))>>1;
	midz=(*(bptr+4)+*(bptr+5))>>1;
	addx=((*(bptr+1)-*(bptr+0))*size)>>(UNIT_SHADOW_SHIFT+1);
	addz=((*(bptr+5)-*(bptr+4))*size)>>(UNIT_SHADOW_SHIFT+1);

	sptr=svec;
	sptr->vx=midx-addx;
	sptr->vy=0;
	sptr->vz=midz+addz;
	++sptr;
	sptr->vx=midx+addx;
	sptr->vy=0;
	sptr->vz=midz+addz;
	++sptr;
	sptr->vx=midx+addx;
	sptr->vy=0;
	sptr->vz=midz-addz;
	++sptr;
	sptr->vx=midx-addx;
	sptr->vy=0;
	sptr->vz=midz-addz;

	p=(POLY_FT4*)db.polyptr;
	if (RotAverageNclip4(svec+0,svec+1,svec+3,svec+2,
						 (uint32*)&p->x0,(uint32*)&p->x1,(uint32*)&p->x2,(uint32*)&p->x3,
						 &piss,&otz,&flag)<=0)
		return;
	if ((flag&OBJ_FLAG_BITS) || otz>=(DPQ_END>>2))
		return;

	dptr=psxspriteinfo+objects[SHADOW].mesh_index;

	*((uint32*)p)=0x09000000;
	*((uint32*)&p->r0) = underwater ? 0x2e000080 : 0x2e000000;

	p->clut=dptr->clut;
	p->tpage=dptr->tpage;
	p->u0=dptr->u1;
	p->v0=dptr->v1;
	p->u1=dptr->u2;
	p->v1=dptr->v1;
	p->u2=dptr->u1;
	p->v2=dptr->v2;
	p->u3=dptr->u2;
	p->v3=dptr->v2;
	MyaddPrim(db.ot,(otz>>OTRIGHT),p);
	db.polyptr=(char*)(p+1);
}

