#include "standard.h"
#include "global.h"
#include "winmain.h"
#include "..\3dsystem\3d_gen.h"


#include "..\game\room.h"
#include "..\game\draw.h"
#include "..\game\effect2.h"
#include "..\game\lara.h"
#include "drawprimitive.h"


extern "C" int CurrentRoom;
extern int SqrTable[1024];
extern unsigned int RColorTable[33][33][33];
extern unsigned int GColorTable[33][33][33];
extern unsigned int BColorTable[33][33][33];




/*
typedef struct phd_vbuf {
		float	xv;
		float	yv;
		float	zv;
		float	ooz;
		float	xs;
		float	ys;
		sint32  z;
		sint8	clip;
		uint8	fog;
		sint16	g;
		uint16	u,v;
		int		dynamic;
}PHD_VBUF;
*/


#ifdef GAMEDEBUG
	int RoomVerts;
	int ObjVerts;
#endif


float ZTable[DPQ_END*2];

void InitZTable()
{
	int z = 0;
	for(int n=0;n<DPQ_END;n++)
	{
		ZTable[(n*2)+0] = float(f_persp/float(z<<14));		
		ZTable[(n*2)+1] = float(f_persp/float(z<<14))*f_oneopersp;		
		z++;
	}
}


float m00,m01,m02,m03;
float m10,m11,m12,m13;
float m20,m21,m22,m23;


inline void MatrixToFloat(sint32* mptr)
{
	m00 = float(mptr[M00]);
	m01 = float(mptr[M01]);
	m02 = float(mptr[M02]);
	m03 = float(mptr[M03]);

	m10 = float(mptr[M10]);
	m11 = float(mptr[M11]);
	m12 = float(mptr[M12]);
	m13 = float(mptr[M13]);

	m20 = float(mptr[M20]);
	m21 = float(mptr[M21]);
	m22 = float(mptr[M22]);
	m23 = float(mptr[M23]);
}


sint16	*calc_object_vertices( sint16 *objptr )
{
	PHD_VBUF 	*dest;
	sint32		*mptr;
	float		zv;
	int			numvert;
	sint8		clipflag, totclip;
	float f_mid_sort;
	int z;
	float lz;
	double fconv;

	f_mid_sort = App.lpZBuffer ? 0.0f : (float)(mid_sort<<W2V_SHIFT+8);
	
	mptr = phd_mxptr;
	dest = vbuf;
	totclip = -1;
	objptr++;

	MatrixToFloat(mptr);

	for(numvert = (int)*(objptr++);numvert>0;numvert--,dest++,objptr+=3)
	{
		dest->xv = m00 * float(objptr[0]) + m01 * float(objptr[1]) + m02 * float(objptr[2]) + m03;
		dest->yv = m10 * float(objptr[0]) + m11 * float(objptr[1]) + m12 * float(objptr[2]) + m13;
		 	  zv = m20 * float(objptr[0]) + m21 * float(objptr[1]) + m22 * float(objptr[2]) + m23;

		dest->z = z = FTOL(zv);

		if (z >= phd_znear)
		{
			if (z >= phd_zfar)
			{
				dest->zv = f_zfar;		
			
				zv = f_persp / zv;
				dest->xs = dest->xv * zv + f_centerx;
				dest->ys = dest->yv * zv + f_centery;
				dest->ooz=zv*f_oneopersp;
			}
			else
			{	
				dest->zv = zv+f_mid_sort;
				lz = ZTable[((z>>14)<<1)+0];
				dest->ooz = ZTable[((z>>14)<<1)+1];

				dest->xs  = dest->xv * lz + f_centerx;
				dest->ys  = dest->yv * lz + f_centery;
			}

			clipflag = 0;
			
			if ( dest->xs < phd_leftfloat )
				clipflag++;
			else if ( dest->xs > phd_rightfloat )
				clipflag += 2;
			if ( dest->ys < phd_topfloat )
				clipflag += 4;
			else if ( dest->ys > phd_bottomfloat )
				clipflag += 8;
		
		}
		else
		{
			dest->zv = zv;
			clipflag = -128;				//  flag we need Z-clipping
		}
		
		dest->clip = clipflag;
		totclip &= clipflag;

	#ifdef GAMEDEBUG
		ObjVerts++;
	#endif

	}
	
	if (totclip)
		return (NULL);
	
	return(objptr);       				// return current objptr.
}




sint16	*calc_roomvert( sint16 *sobjptr, int far_clip )
{
	PHD_VBUF 	*dest;
	sint32		*mptr;
	int			numvert;
	sint8		clipflag;
	int n;
	float		zv;
	sint32 z;
	int dist;
	unsigned long mod;
	int x1,y1,z1;
	unsigned int r,g,b;	
	ROOM_INFO *this_room;
	double fconv;

	this_room = &room[CurrentRoom];

	mptr = phd_mxptr;

	float f_mid_sort;

	f_mid_sort = App.lpZBuffer ? 0.0f : (float)(mid_sort<<W2V_SHIFT+8);

	// Setup Ptrs And Vert Cnts
	sint16 *objptr;

	int nRoomVerts = (int)*(sobjptr++);
	
	objptr = sobjptr;
	dest   = vbuf;
		
	// Do Transformations
	
	MatrixToFloat(mptr);

	for(numvert=nRoomVerts;numvert>0;numvert--,dest++,objptr+=6)
	{
		dest->g  = objptr[5];

		dest->xv = m00 * float(objptr[0]) + m01 * float(objptr[1]) + m02 * float(objptr[2]) + m03;
		dest->yv = m10 * float(objptr[0]) + m11 * float(objptr[1]) + m12 * float(objptr[2]) + m13;
		 	  zv = m20 * float(objptr[0]) + m21 * float(objptr[1]) + m22 * float(objptr[2]) + m23;

		dest->zv = zv;
		
		z = FTOL(zv);		
	

		if (zv>=f_znear)
		{
			clipflag = 0;

			dest->zv += f_mid_sort;
			zv = f_persp/zv;

			if (zv<=DPQ_E) 	
			{
				dest->ooz	= zv*f_oneopersp;
			}
			else
			{
				clipflag    = far_clip;								
				dest->zv	= f_zfar;	
				dest->ooz	= f_oneozfar; 
			}
			dest->xs =  dest->xv * zv + f_centerx;
			dest->ys =  dest->yv * zv + f_centery;


			r = dest->g&0x7c00;
			g = dest->g&0x03e0;
			b = dest->g&0x001f;

			for(n=0;n<number_dynamics;n++)
			{
				if(dynamics[n].on)
				{
					x1 = (dynamics[n].x - (objptr[0]+this_room->x))>>7;
		            y1 = (dynamics[n].y - (objptr[1]+this_room->y))>>7;
					z1 = (dynamics[n].z - (objptr[2]+this_room->z))>>7;

					mod = (x1*x1)+(y1*y1)+(z1*z1);
				
					if(mod < 1024)					
					{
						dist = SqrTable[mod];

						int falloff;
						falloff = dynamics[n].falloff>>8;

						if(dist < falloff)
						{
							r += RColorTable[falloff][dist][dynamics[n].r];
							g += GColorTable[falloff][dist][dynamics[n].g];
							b += BColorTable[falloff][dist][dynamics[n].b];
						}
					}
				}
			}
		
			if(r>0x7c00) r = 0x7c00;
			if(g>0x03e0) g = 0x03e0;
			if(b>0x001f) b = 0x001f;
			
			dest->g = r|g|b;
		
			int off;

			off = ((objptr[0]+this_room->x)>>6) +
				  ((objptr[1]+this_room->y)>>6) +
				  ((objptr[2]+this_room->z)>>7);
			
			off = off&0xfc;
			
		
			if(objptr[4]&(1<<13))
			{
				dest->yv += float(WaterTable[this_room->MeshEffect][((WaterTable[this_room->MeshEffect][off&63].random+(wibble>>2))&63)].choppy<<W2V_SHIFT);
				
				int r,g,b;
				int shade;
			
				r = ((dest->g>>10)&0x1f);
				g = ((dest->g>>5)&0x1f);
				b = ((dest->g)&0x1f);
			
				shade = -WaterTable[this_room->MeshEffect][((WaterTable[this_room->MeshEffect][off&63].random+(wibble>>2))&63)].choppy>>4;

				r += shade;
				g += shade;
				b += shade;
				
				if(r>0x1f) r = 0x1f;
				if(g>0x1f) g = 0x1f;
				if(b>0x1f) b = 0x1f;
				
				if(r<0) r = 0;
				if(g<0) g = 0;
				if(b<0) b = 0;

				dest->g = r<<10|g<<5|b;
			}

				
			if(objptr[4]&(1<<14))
			{			
				int r,g,b;
				int shade;
			
				r = ((dest->g>>10)&0x1f);
				g = ((dest->g>>5)&0x1f);
				b = ((dest->g)&0x1f);
				
				shade = WaterTable[this_room->MeshEffect][((WaterTable[this_room->MeshEffect][off&63].random+(wibble>>2))&63)].shimmer;
				shade +=WaterTable[this_room->MeshEffect][((WaterTable[this_room->MeshEffect][off&63].random+(wibble>>2))&63)].abs;
	
				r += shade;
				g += shade;
				b += shade;
			
				if(r>0x1f) r = 0x1f;
				if(g>0x1f) g = 0x1f;
				if(b>0x1f) b = 0x1f;
				if(r<0) r = 0;
				if(g<0) g = 0;
				if(b<0) b = 0;
				dest->g = r<<10|g<<5|b;
			}
							
			if (water_effect && objptr[4]>=0)
				dest->ys += wibble_table[(FTOL(dest->xs) + wibble>>3) & (WIBBLE_SIZE-1)];
			
			if(dest->xs<phd_leftfloat)
				clipflag++;
			else if(dest->xs>phd_rightfloat)
				clipflag += 2;

			if(dest->ys<phd_topfloat)
				clipflag += 4;
			else if(dest->ys>phd_bottomfloat)
				clipflag += 8;
			
			dest->clip = clipflag;          
			
		}
		else
			dest->clip = -128;				// flag we need Z-clipping
	


		// Apply Depth Q
	
		if (z>DPQ_S)
		{
			int r,g,b;
			int v;
			r = ((dest->g>>10)&0x1f)<<3;
			g = ((dest->g>>5)&0x1f)<<3;
			b = (dest->g&0x1f)<<3;
						
			v = 2048-((z - DPQ_S)>>16);	

			r *= v;
			g *= v;
			b *= v;
			
			r >>= 14;
			g >>= 14;
			b >>= 14;
			
			if(r<0) r= 0;	
			if(g<0) g= 0;	
			if(b<0) b= 0;	

			dest->g = r<<10|g<<5|b;
		}



#ifdef GAMEDEBUG
		RoomVerts++;
#endif
	
	}

	return(objptr);       				// return current objptr.
}
