void ShadowProject(v3 &p, bool n);

struct SIMPLEBUFFER
{
	int vf;	
	int curv,curi;
	WORD *ibptr;
	SIMPLEVERT *vbptr;
	int primtype;

	void Reset()
	{
		curv=curi=0;
	}

	void Flush(bool reset=true, bool shadow=false)
	{
		if (curi>MAXTRIS || curv>MAXTRIS) Draw(reset,shadow);
	}

	void Draw(bool reset = true, bool shadow = false)
	{
		d3ddev->SetVertexShader(SIMPLEFVF);
		int np=3;
		if (primtype==D3DPT_LINELIST) np=2;
#ifndef UV2
		if (shadow)
		{
			d3ddev->SetTextureStageState(1,D3DTSS_COLORARG1,D3DTA_CURRENT);
			d3ddev->SetTextureStageState(1,D3DTSS_COLORARG2,D3DTA_TEXTURE);
			d3ddev->SetTextureStageState(1,D3DTSS_COLOROP,D3DTOP_SELECTARG1);

			d3ddev->SetTextureStageState(1,D3DTSS_ALPHAARG1,D3DTA_CURRENT);		
			d3ddev->SetTextureStageState(1,D3DTSS_ALPHAOP,D3DTOP_SELECTARG1);
		}
		else
		{
			d3ddev->SetTextureStageState(1,D3DTSS_COLOROP,D3DTOP_DISABLE);
			d3ddev->SetTextureStageState(1,D3DTSS_ALPHAOP,D3DTOP_DISABLE);
		}
#endif
		if (shadow)
		{
			d3ddev->SetTextureStageState(2,D3DTSS_COLORARG1,D3DTA_CURRENT);
			d3ddev->SetTextureStageState(2,D3DTSS_COLORARG2,D3DTA_TEXTURE);
			d3ddev->SetTextureStageState(2,D3DTSS_COLOROP,D3DTOP_MODULATE);

			d3ddev->SetTextureStageState(2,D3DTSS_ALPHAARG1,D3DTA_CURRENT);		
			d3ddev->SetTextureStageState(2,D3DTSS_ALPHAOP,D3DTOP_SELECTARG1);
		}
		else
		{
			d3ddev->SetTextureStageState(2,D3DTSS_COLOROP,D3DTOP_DISABLE);
			d3ddev->SetTextureStageState(2,D3DTSS_ALPHAOP,D3DTOP_DISABLE);
		}
			
		if (curi) d3ddev->DrawIndexedPrimitiveUP((D3DPRIMITIVETYPE)primtype,0,curv,curi/np,ibptr,D3DFMT_INDEX16,vbptr,sizeof(SIMPLEVERT));
		if (reset) Reset();
#ifndef UV2
		d3ddev->SetTextureStageState(1,D3DTSS_COLOROP,D3DTOP_DISABLE);
		d3ddev->SetTextureStageState(1,D3DTSS_ALPHAOP,D3DTOP_DISABLE);
#endif
		d3ddev->SetTextureStageState(2,D3DTSS_COLOROP,D3DTOP_DISABLE);
		d3ddev->SetTextureStageState(2,D3DTSS_ALPHAOP,D3DTOP_DISABLE);
	}

	int AddTri(int a, int b, int c)
	{
		ASSERT(curi+3<MAXTRIS*3);
		ibptr[curi++]=a;
		ibptr[curi++]=b;
		ibptr[curi++]=c;
		return curi-3;
	}

	int AddLine(int a, int b)
	{
		ASSERT(curi+2<MAXTRIS*3);
		ibptr[curi++]=a;
		ibptr[curi++]=b;			
		return curi-2;
	}

	int AddQuad(int a, int b, int c, int d)
	{
		ASSERT(curi+6<MAXTRIS*3);
		ibptr[curi++]=a;
		ibptr[curi++]=b;
		ibptr[curi++]=c;
		ibptr[curi++]=c;
		ibptr[curi++]=d;
		ibptr[curi++]=a;
		return curi-6;
	}

	int AddVertexFog(v3 p, unsigned int col, float u=0, float v=0, float u2=0, float v2=0)
	{
		ASSERT(curv+1<MAXTRIS*3);
		
#ifdef RHW
		if (Surface::curtarget->isbackbuf)
		{
			p.x+=jitterx / Surface::curtarget->w;
			p.y+=jittery / Surface::curtarget->h;
		}
		
		p.x*=Surface::curtarget->w ; // d3dpp.BackBufferWidth;
		p.y*=Surface::curtarget->h ; // d3dpp.BackBufferHeight;
		
		vbptr[curv].p=p;
		vbptr[curv].rhw=1-p.z;

#else
		vbptr[curv].p=p;
		float d=(Length(p*cammat)-40.f)/200.f;
		d=bound(0,1-d,1);
		col=(col&0xffffff) + (unsigned int((col>>24)*d)<<24);
#endif
		vbptr[curv].col=col;
		vbptr[curv].u=u;
		vbptr[curv].v=v;
#ifdef UV2
		vbptr[curv].u2=u2;
		vbptr[curv].v2=v2;
#else
#ifndef RHW
		vbptr[curv].u2=0;
		vbptr[curv].v2=0;
#endif		
#endif
#ifndef RHW
		ShadowProject(p,true);
		vbptr[curv].u3=p.x;
		vbptr[curv].v3=p.y;
#endif

		return curv++;
	}

	int AddVertex(v3 p, unsigned int col, float u=0, float v=0, float u2=0, float v2=0)
	{
		ASSERT(curv+1<MAXTRIS*3);
		
#ifdef RHW
		p.x*=Surface::curtarget->w ; // d3dpp.BackBufferWidth;
		p.y*=Surface::curtarget->h ; // d3dpp.BackBufferHeight;
		
		vbptr[curv].p=p;
		vbptr[curv].rhw=1-p.z;

#else
		vbptr[curv].p=p;		
#endif
		vbptr[curv].col=col;
		vbptr[curv].u=u;
		vbptr[curv].v=v;
#ifdef UV2
		vbptr[curv].u2=u2;
		vbptr[curv].v2=v2;
#else
#ifndef RHW
		vbptr[curv].u2=0;
		vbptr[curv].v2=0;
#endif
#endif
#ifndef RHW
		ShadowProject(p,true);
		vbptr[curv].u3=p.x;
		vbptr[curv].v3=p.y;
#endif
		return curv++;
	}

	void AddBlob(v3 p, int col, float size=1.f, float angle = 0.f, float u1=0, float v1=0, float u2=1, float v2=1, float u4=0.5f, float v4=0.5f, float u5=0.5f, float v5=0.5f)
	{
		v3 xx,yy;						
		float ss,cc;
		cc=cos(angle);
		ss=sin(angle);
		
#ifndef RHW
		v3 _x = *((v3*)blobmat.m44[0]);
		v3 _y = *((v3*)blobmat.m44[1]);
		xx = _x*cc + _y*ss;
		yy = _y*cc - _x*ss;		
#else
		
		xx = v3(cc,ss,0);
		yy = v3(-ss,cc,0);
#endif
		xx*=size;
		yy*=size;
		AddQuad(
			AddVertex(p-xx-yy,col,u1,v1,u4,v4),
			AddVertex(p+xx-yy,col,u2,v1,u5,v4),
			AddVertex(p+xx+yy,col,u2,v2,u5,v5),
			AddVertex(p-xx+yy,col,u1,v2,u4,v5)
			);
	}

	void AddRandomBlob(v3 p, int col, float size=1.f, float u1=0, float v1=0, float u2=1, float v2=1)
	{
		v3 xx,yy;						
#ifndef RHW
		xx = *((v3*)blobmat.m44[0]);
		yy = *((v3*)blobmat.m44[1]);
#else
		xx = v3(1,0,0);
		yy = v3(0,1,0);
#endif
		xx*=size;
		yy*=size;
		AddQuad(
			AddVertex(p+xx*GaussRandom()+yy*GaussRandom(),col,u1,v1),
			AddVertex(p+xx*GaussRandom()+yy*GaussRandom(),col,u2,v1),
			AddVertex(p+xx*GaussRandom()+yy*GaussRandom(),col,u2,v2),
			AddVertex(p+xx*GaussRandom()+yy*GaussRandom(),col,u1,v2)				
			);
	}
	
	SIMPLEBUFFER(int pt = D3DPT_TRIANGLELIST)
	{
		primtype= pt;
		vbptr=new SIMPLEVERT[MAXTRIS*3];
		ibptr=new WORD[MAXTRIS*3];
		Reset();
	}



	virtual ~SIMPLEBUFFER()
	{			
		delete [] vbptr;
		delete [] ibptr;
	}

};

#undef RHW
#undef SIMPLEBUFFER
#undef SIMPLEVERT
#undef SIMPLEFVF