/*






*/


#include "standard.h"
#include "global.h"
#include "litesrc.h"
#include "..\game\effect2.h"
#include "..\game\lara.h"
#include "..\3dsystem\3d_gen.h"
#include "drawprimitive.h"



int smcr,smcg,smcb;
extern "C" int number_dynamics;
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];
extern "C" MESH_INFO* CurrentMesh;


sint32 LightPos[12];
sint32 LightCol[12];
PHD_VECTOR LPos[3];

enum{SUN,OMN,DYN};


/*

void ApplyMatrix(sint32* mptr,sint16* objptr,sint32& x,sint32& y,sint32& z)
{
	x = (mptr[M00] * objptr[0] + mptr[M01] * objptr[1] + mptr[M02] * objptr[2])>>W2V_SHIFT;
	y = (mptr[M10] * objptr[0] + mptr[M11] * objptr[1] + mptr[M12] * objptr[2])>>W2V_SHIFT;
	z = (mptr[M20] * objptr[0] + mptr[M21] * objptr[1] + mptr[M22] * objptr[2])>>W2V_SHIFT;
}

void ApplyTransposeMatrix(sint32* mptr,sint16* objptr,sint32& x,sint32& y,sint32& z)
{

	x = (mptr[M00] * objptr[0] + mptr[M10] * objptr[1] + mptr[M20] * objptr[2])>>W2V_SHIFT;
	y = (mptr[M01] * objptr[0] + mptr[M11] * objptr[1] + mptr[M21] * objptr[2])>>W2V_SHIFT;
	z = (mptr[M02] * objptr[0] + mptr[M12] * objptr[1] + mptr[M22] * objptr[2])>>W2V_SHIFT;
}

*/

inline void ApplyMatrix(sint32* mptr,PHD_VECTOR* objptr,sint32& x,sint32& y,sint32& z)
{
	x = (mptr[M00] * objptr->x + mptr[M01] * objptr->y + mptr[M02] * objptr->z)>>W2V_SHIFT;
	y = (mptr[M10] * objptr->x + mptr[M11] * objptr->y + mptr[M12] * objptr->z)>>W2V_SHIFT;
	z = (mptr[M20] * objptr->x + mptr[M21] * objptr->y + mptr[M22] * objptr->z)>>W2V_SHIFT;
}


inline void ApplyTransposeMatrix(sint32* mptr,PHD_VECTOR* objptr,sint32& x,sint32& y,sint32& z)
{
	x = (mptr[M00] * objptr->x + mptr[M10] * objptr->y + mptr[M20] * objptr->z)>>W2V_SHIFT;
	y = (mptr[M01] * objptr->x + mptr[M11] * objptr->y + mptr[M21] * objptr->z)>>W2V_SHIFT;
	z = (mptr[M02] * objptr->x + mptr[M12] * objptr->y + mptr[M22] * objptr->z)>>W2V_SHIFT;
}


sint16	*calc_vertice_light( sint16 *objptr,sint16 *objptr1)
{
	int			numvert;
	PHD_VBUF 	*dest;
	sint32		*mptr;
	int r,g,b;
	int shade;
	double fconv;

	dest = &vbuf[0];

	numvert = (int)*(objptr++);


	if(numvert>0)								
	{
		mptr = phd_mxptr;

		ApplyTransposeMatrix(mptr,&LPos[SUN],LightPos[M00],LightPos[M01],LightPos[M02]);
		ApplyTransposeMatrix(mptr,&LPos[OMN],LightPos[M10],LightPos[M11],LightPos[M12]);
		ApplyTransposeMatrix(mptr,&LPos[DYN],LightPos[M20],LightPos[M21],LightPos[M22]);
		
		for(;numvert>0;numvert--,dest++,objptr+=3)
		{
			sint32 sdot,odot,ddot;
			float v1,v2,v3;

			v1 = float(objptr[0]);
			v2 = float(objptr[1]);
			v3 = float(objptr[2]);

			float fsdot,fodot,fddot;
			
			fsdot = (v1*float(LightPos[M00]))+(v2*float(LightPos[M01]))+(v3*float(LightPos[M02]));

			sdot = FTOL(fsdot);
	
			fodot = (v1*float(LightPos[M10]))+(v2*float(LightPos[M11]))+(v3*float(LightPos[M12]));

			odot = FTOL(fodot);

			fddot = (v1*float(LightPos[M20]))+(v2*float(LightPos[M21]))+(v3*float(LightPos[M22]));
		
			ddot = FTOL(fddot);
			
//			sdot = (objptr[0]*LightPos[M00])+(objptr[1]*LightPos[M01])+(objptr[2]*LightPos[M02]);
//			odot = (objptr[0]*LightPos[M10])+(objptr[1]*LightPos[M11])+(objptr[2]*LightPos[M12]);
//			ddot = (objptr[0]*LightPos[M20])+(objptr[1]*LightPos[M21])+(objptr[2]*LightPos[M22]);


			sdot >>= 16;
			odot >>= 16;
			ddot >>= 16;

			if(sdot < 0) sdot = 0;
			if(odot < 0) odot = 0;
			if(ddot < 0) ddot = 0;
			 
			r = (smcr<<13)+(LightCol[M00]*sdot)+(LightCol[M01]*odot)+(LightCol[M02]*ddot);	
			g = (smcg<<13)+(LightCol[M10]*sdot)+(LightCol[M11]*odot)+(LightCol[M12]*ddot);
			b = (smcb<<13)+(LightCol[M20]*sdot)+(LightCol[M21]*odot)+(LightCol[M22]*ddot);
			
			r >>= 16+3;
			g >>= 16+3;
			b >>= 16+3;

			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;
			
			// Apply DepthQ

			if (dest->z > DPQ_S)
			{
				int v;
				r <<= 3;
				g <<= 3;
				b <<= 3;
				v = 2048-((dest->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;
		}
	}
	else if(numvert < 0)
	{
		// Skip Vertex Count on Vertex Data
		
		objptr1+=2;
		
		// Calculate Lighting For Static Mesh Objects
	
		for (;numvert<0;numvert++,dest++,objptr++,objptr1+=3)
		{
			// Get Static Mesh Light
			
			r = smcr;
			g = smcg;
			b = smcb;
			
			// Apply Tint
			
			shade = 8192-*(objptr);
			r *= shade;
			g *= shade;
			b *= shade;
			r >>= 13+3;
			g >>= 13+3;
			b >>= 13+3;
				
			// Apply Dynamic Lights

			if(number_dynamics > 0 && CurrentMesh != NULL)
			{
				int dx,dy,dz;
				int x1,y1,z1;
				int mod,dist;

				if(CurrentMesh->y_rot != 0)
				{
					phd_PushUnitMatrix();
					phd_RotY(CurrentMesh->y_rot);
					dx = phd_mxptr[M00] * objptr1[0] + phd_mxptr[M01] * objptr1[1] + phd_mxptr[M02] * objptr1[2];
					dz = phd_mxptr[M20] * objptr1[0] + phd_mxptr[M21] * objptr1[1] + phd_mxptr[M22] * objptr1[2];
					dx >>= 14;
					dz >>= 14;
					dx += CurrentMesh->x;
					dy  = objptr1[1]+CurrentMesh->y;
					dz += CurrentMesh->z;
					phd_PopMatrix();
				}
				else
				{
					dx = CurrentMesh->x + objptr1[0];
					dy = CurrentMesh->y + objptr1[1];
					dz = CurrentMesh->z + objptr1[2];
				}

				for(int n=0;n<number_dynamics;n++)
				{
					if(dynamics[n].on)
					{
						z1 = (dynamics[n].z - dz)>>7;
			
						mod = (z1*z1);
					
						if(mod < 1024)
						{
							x1 = (dynamics[n].x - dx)>>7;
	
							mod +=(x1*x1);

							if(mod < 1024)
							{
					            y1 = (dynamics[n].y - dy)>>7;
				
								mod += (y1*y1);

								if(mod < 1024)					
								{
									dist = SqrTable[mod];

									if(dist < dynamics[n].falloff>>8)
									{
										r += RColorTable[dynamics[n].falloff>>8][dist][dynamics[n].r]>>10;
										g += GColorTable[dynamics[n].falloff>>8][dist][dynamics[n].g]>>5;
										b += BColorTable[dynamics[n].falloff>>8][dist][dynamics[n].b];
									}
								}
							}	
						}
					}
				}
		
			}

			if(r > 0x1f) r = 0x1f;
			if(g > 0x1f) g = 0x1f;
			if(b > 0x1f) b = 0x1f;

			// Apply DepthQ

			if (dest->z > DPQ_S)
			{
				int v;
				r <<= 3;
				g <<= 3;
				b <<= 3;
				v = 2048-((dest->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;
			
		}
	}

	return(objptr);
}




void S_CalculateLight(sint32 x, sint32 y, sint32 z, sint16 room_number, ITEM_LIGHT *il)
{
	LIGHT_INFO *sl=NULL, sunlight;	// ptr to target sun colour, dummy bulb

	int i;
	ROOM_INFO *r;
	sint32 brightest;
	DYNAMIC *dl, *dl2=NULL;
	PHD_VECTOR ls, lc;
	LIGHT_INFO *light, *l=NULL;
	uint16 ambience;
	char sun;
	ITEM_LIGHT dummy;

	//*** ToDo : Sort This Out
	
	if (il == NULL)
	{
		il = &dummy;
		il->init = 0;
	}



	LightPos[M00] = LightPos[M01] = LightPos[M02] =
	LightPos[M10] = LightPos[M11] = LightPos[M12] =
	LightPos[M20] = LightPos[M21] = LightPos[M22] = 0;

	LightCol[M00] = LightCol[M01] = LightCol[M02] =
	LightCol[M10] = LightCol[M11] = LightCol[M12] =
	LightCol[M20] = LightCol[M21] = LightCol[M22] = 0;

	LPos[0].x = LPos[0].y = LPos[0].z = 0;
	LPos[1].x = LPos[1].y = LPos[1].z = 0;
	LPos[2].x = LPos[2].y = LPos[2].z = 0;

/* -------- determine brightest room light */

	sun = 0;
	brightest = -1;

	r = &room[room_number];

	ambience = (r->ambient >> 5) + 16;

	for ( i=r->num_lights,light=r->light ; i>0 ; i--,light++ )
	{
		sint32 distance, shade;

	/* -------- process sun bulb */

		if (light->type)
		{
			sun = 1;
			sl = light;
		}

	/* -------- process omni bulb */

		else
		{
			lc.x = light->x - x;
			lc.y = light->y - y;
			lc.z = light->z - z;

			distance = mSqrt(SQUARE(lc.x) + SQUARE(lc.y) + SQUARE(lc.z));

			if (distance > light->l.spot.falloff)
				continue;

			shade = 8191 - (((light->l.spot.intensity * distance) / light->l.spot.falloff));

//			shade = 8192-shade;

			ambience += (shade >> (5+3));

			if (shade > brightest)
			{
				brightest = shade;
				l = light;
				ls = lc;
			}
		}
	}


/* -------- interpolate sun bulb */

	if ((!sun) && (il->init & 1))
	{
		sunlight.l.sun.nx = il->sun.x;
		sunlight.l.sun.ny = il->sun.y;
		sunlight.l.sun.nz = il->sun.z;

		sunlight.r = sunlight.g = sunlight.b = r->ambient >> 5;

		sl = &sunlight;
		sun = 1;
	}

	if (sun)
	{
		if (il->init & 1)
		{
			il->sun.x += (sl->l.sun.nx - il->sun.x) >> 3;
			il->sun.y += (sl->l.sun.ny - il->sun.y) >> 3;
			il->sun.z += (sl->l.sun.nz - il->sun.z) >> 3;

			il->sunr += (sl->r - il->sunr) >> 3;
			il->sung += (sl->g - il->sung) >> 3;
			il->sunb += (sl->b - il->sunb) >> 3;
		}
		else
		{
			il->sun.x = sl->l.sun.nx;
			il->sun.y = sl->l.sun.ny;
			il->sun.z = sl->l.sun.nz;

			il->sunr = sl->r;
			il->sung = sl->g;
			il->sunb = sl->b;
			il->init |= 1;
		}

		LPos[0].x = il->sun.x; 
		LPos[0].y = il->sun.y;
		LPos[0].z = il->sun.z;

		LightCol[M00] = il->sunr << 4;
		LightCol[M10] = il->sung << 4;
		LightCol[M20] = il->sunb << 4;
	}

/* -------- interpolate omni bulb */

	if ((brightest == -1) && (il->init & 2))
	{
		ls.x	= il->bulb.x;
		ls.y	= il->bulb.y;
		ls.z	= il->bulb.z;

		sunlight.r = sunlight.g = sunlight.b = r->ambient >> 5;
		l = &sunlight;

		brightest = 8191;
	}

	if (brightest != -1)
	{
		phd_NormaliseVector(ls.x, ls.y, ls.z, (sint32 *)&ls);

		if (il->init & 2)
		{
			il->bulb.x += (ls.x - il->bulb.x) >> 3;
			il->bulb.y += (ls.y - il->bulb.y) >> 3;
			il->bulb.z += (ls.z - il->bulb.z) >> 3;

			il->bulbr += (((l->r * brightest) >> 13) - il->bulbr) >> 3;
			il->bulbg += (((l->g * brightest) >> 13) - il->bulbg) >> 3;
			il->bulbb += (((l->b * brightest) >> 13) - il->bulbb) >> 3;
		}
		else
		{
			il->bulb.x = ls.x;
			il->bulb.y = ls.y;
			il->bulb.z = ls.z;

			il->bulbr = (l->r * brightest) >> 13;
			il->bulbg = (l->g * brightest) >> 13;
			il->bulbb = (l->b * brightest) >> 13;
			il->init |= 2;
		}

		LPos[1].x = il->bulb.x >> 2;
		LPos[1].y = il->bulb.y >> 2;
		LPos[1].z = il->bulb.z >> 2;

		LightCol[M01] = il->bulbr << 4;
		LightCol[M11] = il->bulbg << 4;
		LightCol[M21] = il->bulbb << 4;
	}

/* -------- determine brightest dynamic light */

	brightest = -1;	// Reset brightest for dynamics.

	for (i=0, dl=dynamics; i<number_dynamics; i++, dl++)
	{
		sint32 distance, shade;

		lc.x = dl->x - x;
		lc.y = dl->y - y;
		lc.z = dl->z - z;

		if ((abs(lc.x) > 8192)
		||  (abs(lc.y) > 8192)
		||  (abs(lc.z) > 8192))
			continue;

		distance = mSqrt(SQUARE(lc.x) + SQUARE(lc.y) + SQUARE(lc.z));

		if (distance > (dl->falloff >> 1))
			continue;

		shade = 8191 - (((8191 * distance) / (dl->falloff >> 1)));
	
		ambience += (shade >> (5+2));

		if (shade > brightest)
		{
			brightest = shade;
			ls = lc;
			dl2 = dl;
		}
	}

	if (brightest != -1)
	{
		phd_NormaliseVector(ls.x, ls.y, ls.z, (sint32 *)&ls);
#if 1
		if (il->init & 4)
		{
			il->dynamic.x += (ls.x - il->dynamic.x) >> 1;
			il->dynamic.y += (ls.y - il->dynamic.y) >> 1;
			il->dynamic.z += (ls.z - il->dynamic.z) >> 1;

			il->dynamicr += (((dl2->r * brightest) >> (13-3)) - il->dynamicr) >> 1;
			il->dynamicg += (((dl2->g * brightest) >> (13-3)) - il->dynamicg) >> 1;
			il->dynamicb += (((dl2->b * brightest) >> (13-3)) - il->dynamicb) >> 1;
		}
		else
#endif
		{

		il->dynamic.x = ls.x;
		il->dynamic.y = ls.y;
		il->dynamic.z = ls.z;
		il->dynamicr = (dl2->r * brightest) >> (13-3);
		il->dynamicg = (dl2->g * brightest) >> (13-3);
		il->dynamicb = (dl2->b * brightest) >> (13-3);

		}



		LPos[2].x = il->dynamic.x >> 2;
		LPos[2].y = il->dynamic.y >> 2;
		LPos[2].z = il->dynamic.z >> 2;

		LightCol[M02] = il->dynamicr << 6;
		LightCol[M12] = il->dynamicg << 6;
		LightCol[M22] = il->dynamicb << 6;
	}

/* -------- determine ambience */

	if (ambience > 255)
		ambience = 255;

	if (il->init & 8)
		il->ambient += (ambience - il->ambient) >> 3;
	else
	{
		il->ambient = ambience;
		il->init |= 8;
	}

//	SetBackColor(il->ambient, il->ambient, il->ambient);

	smcr = il->ambient;
	smcg = il->ambient;
	smcb = il->ambient;

//	SetLightMatrices();


	LPos[0].x <<= 2;
	LPos[0].y <<= 2;
	LPos[0].z <<= 2;

	LPos[1].x <<= 2;
	LPos[1].y <<= 2;
	LPos[1].z <<= 2;

	LPos[2].x <<= 2;
	LPos[2].y <<= 2;
	LPos[2].z <<= 2;

	ApplyMatrix(w2v_matrix,&LPos[0],x,y,z);	
	
	LPos[0].x = x;
	LPos[0].y = y;
	LPos[0].z = z;

	ApplyMatrix(w2v_matrix,&LPos[1],x,y,z);	
	
	LPos[1].x = x;
	LPos[1].y = y;
	LPos[1].z = z;

	ApplyMatrix(w2v_matrix,&LPos[2],x,y,z);	

	LPos[2].x = x;
	LPos[2].y = y;
	LPos[2].z = z;

  
}


void S_CalculateStaticLight(sint16 adder)
{
	smcr = (adder & 0x1f) << 3;
	smcg = (adder & 0x3e0) >> 2;
	smcb = (adder & 0x7c00) >> 7;
}