#include "MLRHeaders.hpp"

extern DWORD gEnableLightMaps, gEnableFancyWater;

//#############################################################################
//## MLRTerrain with no color no lighting w/ detail texture, uv's from xyz  ###
//#############################################################################

DynamicArrayOf<Vector2DScalar>
	*MLR_Water::detailTexCoords;

MLR_Water::ClassData*
	MLR_Water::DefaultData = NULL;

Stuff::UnitVector3D
	MLR_Water::sunLight;

Stuff::Scalar
	MLR_Water::specMult;

Stuff::Scalar
	MLR_Water::specCutoff;

int
	MLR_Water::specPow;

BYTE
	MLR_Water::lookUpSpecular[256];

extern DynamicArrayOf<Vector2DScalar> *lightMapUVs;
extern DynamicArrayOf<Scalar> *lightMapSqFalloffs;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MLR_Water::InitializeClass()
{
	Verify(!DefaultData);
	Verify(gos_GetCurrentHeap() == StaticHeap);
	DefaultData =
		new ClassData(
			MLR_WaterClassID,
			"MidLevelRenderer::MLR_Water",
			MLR_I_C_DeT_TMesh::DefaultData,
			(MLRPrimitiveBase::Factory)&Make
		);
	Register_Object(DefaultData);

	Vector3D sl(1.0f, -1.0f, -1.0f);

	sl.Normalize(sl);

	sunLight = sl;
	specMult = 345.0f;
	specPow = 5;
	specCutoff = 0.5f;

	detailTexCoords = new DynamicArrayOf<Vector2DScalar> (Limits::Max_Number_Vertices_Per_Mesh);
	Register_Object(detailTexCoords);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MLR_Water::TerminateClass()
{
	Unregister_Object(DefaultData);
	delete DefaultData;
	DefaultData = NULL;

	Unregister_Object(detailTexCoords);
	delete detailTexCoords;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MLR_Water::SetSpecularValues(Stuff::Scalar fac, int _pow, Scalar cutOff	)
{
	specMult = fac;
	specPow = _pow;
	specCutoff = cutOff;

	Scalar oneOver255 = 1.0f/255.0f;

	for(int i=0;i<256;i++)
	{
		Scalar sval = static_cast<Scalar>(255.5f * specMult * pow(i*oneOver255, specPow));
		
		if(sval>255.0f)
		{
			lookUpSpecular[i] = 0xff;
		}
		else
		{
			lookUpSpecular[i] = Truncate_Float_To_Byte(sval);
		}
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MLR_Water::MLR_Water(
	ClassData *class_data,
	MemoryStream *stream,
	int version
):
	MLR_I_C_DeT_TMesh(class_data, stream, version)
{
	Check_Pointer(this);
	Check_Pointer(stream);

	referenceState.SetLightingMode(MLRState::LightMapLightingMode);
	referenceState.SetSpecularOn();

	facePlanes.SetLength(0);

	if (!dataStore)
		dataStore = new DataStorage;
	Check_Pointer(dataStore);

	if (!colors.GetLength())
	{
		#if COLOR_AS_DWORD
			dataStore->colors.AssignValue(0xFFFFFFFF, coords.GetLength());
		#else
			dataStore->colors.AssignValue(RGBAColor::White, coords.GetLength());
		#endif
		colors.AssignData(dataStore->colors.GetData(), dataStore->colors.GetLength());
	}
	Verify(colors.GetData() == dataStore->colors.GetData());
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MLR_Water::MLR_Water(ClassData *class_data):
	MLR_I_C_DeT_TMesh(class_data)
{
	Check_Pointer(this);

	facePlanes.SetLength(0);

	if (!dataStore)
		dataStore = new DataStorage;
	Check_Pointer(dataStore);

	if (!colors.GetLength())
	{
		#if COLOR_AS_DWORD
			dataStore->colors.AssignValue(0xFFFFFFFF, coords.GetLength());
		#else
			dataStore->colors.AssignValue(RGBAColor::White, coords.GetLength());
		#endif
		colors.AssignData(dataStore->colors.GetData(), dataStore->colors.GetLength());
	}
	Verify(colors.GetData() == dataStore->colors.GetData());
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MLR_Water::~MLR_Water()
{
	Check_Object(this);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MLR_Water*
	MLR_Water::Make(
		MemoryStream *stream,
		int version
	)
{
	Check_Object(stream);

	gos_PushCurrentHeap(PrimitiveHeap);
	MLR_Water *water = new MLR_Water(DefaultData, stream, version);
	gos_PopCurrentHeap();

	return water;
}


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MLR_Water::Save(MemoryStream *stream)
{
	Check_Object(this);
	Check_Object(stream);

	MLR_I_C_DeT_TMesh::Save(stream);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MLR_Water::TestInstance() const
{
	Verify(IsDerivedFrom(DefaultData));
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
	MLR_Water::FindBackFace(const Point3D& u, const Normal3D& n)
{
	Check_Object(this);

	MLR_RENDER("Backface::MLR_Water");
	Start_Timer(Find_Backface_Time);

	BYTE *iPtr;

	if(numOfTriangles <= 0)
	{
		visible = 0;
		Stop_Timer(Find_Backface_Time);

		return 0;
	}

	if(gEnableFancyWater==0)
	{
		FindVisibleVertices();

		channelUse &= ~(1<<SpecularRedChannel);

		referenceState.SetSpecularOff();

		Stop_Timer(Find_Backface_Time);

		return 1;
	}

	ColorType *cols = dataStore->colors.GetData();
	int len = dataStore->colors.GetLength();
	DWORD new_color = paintMeColorDW;

	for(int i=0;i<len;i++)
	{
		Vector3D v;

		v.Subtract(u, coords[i]);
		v.NormalizeApproximate(v);

		Scalar a = 1.2f - 2.5f*v.y;

		if(a < 0.6f)
		{
			a = 0.6f;
		}

#if COLOR_AS_DWORD
		a *= 255.0f;

		if(a>=255.0f)
		{
			*((BYTE *)&new_color + 3) = 0xff;
		}
		else
		{
			*((BYTE *)&new_color + 3) = Truncate_Float_To_Byte(a);
		}

		cols[i] = new_color;
#else
//			SPEW(("micgaert", "%f", v.y/v.GetApproximateLength()));
		cols[i] = paintMeColorF;
		cols[i].alpha = a;
#endif
	
		v.y=0.0f;		


	/*
		Vector3D reflect_vect(0.0f,1.0f,0.0f), rev_sun;
		rev_sun.Negate(sunLight);

		reflect_vect.Multiply(reflect_vect,2*rev_sun.y);
		reflect_vect.Subtract(reflect_vect, rev_sun);

		reflect_vect.Normalize(reflect_vect);

		Scalar sval = reflect_vect*v;
	*/
	
		Scalar sval = sunLight*v;

	
		if(sval<specCutoff)
		{
			(*extraChannels[2*SpecularRedChannel])[i] = 0;
		}
		else
		{
			(*extraChannels[2*SpecularRedChannel])[i] = lookUpSpecular[Truncate_Float_To_Byte(255.5f*sval)];
		}
	}
		
	referenceState.SetSpecularOn();
	channelUse |= 1<<SpecularRedChannel;

	iPtr = testList->GetData();
	memset(iPtr, 1, numOfTriangles);

	visible = 1;

	FindVisibleVertices();

//	passes = 1;

	Stop_Timer(Find_Backface_Time);

	return 1;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MLR_Water::Copy(
		MLR_I_C_TMesh *prim,
		MLRState detailState,
		Stuff::Scalar xOff,
		Stuff::Scalar yOff,
		Stuff::Scalar xFac,
		Stuff::Scalar yFac
	)
{
	MLR_I_C_DeT_TMesh::Copy(prim, detailState, xOff, yOff, xFac, yFac);
	facePlanes.SetLength(0);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
	MLR_Water::Copy(MLR_I_C_DeT_PMesh *prim)
{
	bool b = MLR_I_C_DeT_TMesh::Copy(prim);
	facePlanes.SetLength(0);

	return b;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/*
int
	MLR_Water::GetNumPasses()
{
	Check_Object(this);

	return 2;
}
*/

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
#define I_SAY_YES_TO_DETAIL_TEXTURES
#define I_SAY_YES_TO_WATER
#define I_SAY_YES_TO_COLOR

#undef I_SAY_YES_TO_TERRAIN2
#undef I_SAY_YES_TO_DUAL_TEXTURES
#undef I_SAY_YES_TO_TERRAIN
#undef I_SAY_YES_TO_LIGHTING

#define CLASSNAME MLR_Water
#define CLASSNAMENOCOLOR MLR_I_DeT_TMesh

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//	This include contains follwing functions:
//	void MLR_Water::TransformNoClip(Matrix4D*, GOSVertexPool*);
//	int MLR_Water::Clip(MLRClippingState, GOSVertexPool*);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

#include <MLR\MLRTriangleClipping.hpp>

#undef I_SAY_YES_TO_DETAIL_TEXTURES
#undef I_SAY_YES_TO_WATER
#undef I_SAY_YES_TO_COLOR

#undef CLASSNAME
#undef CLASSNAMENOCOLOR

extern RGBAColor errorColor;
extern bool
	CheckForBigTriangles(DynamicArrayOf<Vector2DScalar> *lightMapUVs, int stride);

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MLR_Water::LightMapLighting(MLRLight *light)
{
	MLRLightMap *lightMap = light->GetLightMap();
	if((!lightMap) || !gEnableLightMaps || lightMap->IsFull()==true)
	{
		return;
	}

	int i, j, k, len = numOfTriangles;
	LinearMatrix4D matrix = LinearMatrix4D::Identity;
	Point3D lightPosInShape, hitPoint;
	UnitVector3D up, left, forward;
	bool lm;
	Scalar falloff = 1.0f, distance;

	Scalar waterHeight = coords[0].z;

	BYTE addedVertices = 0;
	BYTE addedIndicies = 0;

	int tooBig = 0;
	Scalar bigUV = MLRState::GetMaxUV();

	switch(light->GetLightType())
	{
		case MLRLight::PointLight:
		{
			Check_Object(lightMap);

			light->GetInShapePosition(lightPosInShape);

			Scalar n, f;
			Cast_Object(MLRPointLight*, light)->GetFalloffDistance(n, f);

			Scalar One_Over_Falloff = 1.0f/f;

			for(i=0,j=0,k=0;i<len;i++,j += 3)
			{
				if((*testList)[i] == 0)
				{
					continue;
				}

				f = lightPosInShape.z - waterHeight;
				
				lm = false;

				tooBig = 0;
				for(k=0;k<3;k++)
				{
					Vector3D vec(coords[index[k+j]]);
					vec-=lightPosInShape;

					(*lightMapUVs)[k][0] = vec.x * One_Over_Falloff;
					(*lightMapUVs)[k][1] = vec.z * One_Over_Falloff;

					falloff = 1.0f;

					if(
						(*lightMapUVs)[k][0] >= -0.5f && (*lightMapUVs)[k][0] <= 0.5f &&
						(*lightMapUVs)[k][1] >= -0.5f && (*lightMapUVs)[k][1] <= 0.5f

					) 
					{
						lm = true;
					}
					if(
						bigUV > 0.0f &&
						(
							(*lightMapUVs)[k][0] < -bigUV || (*lightMapUVs)[k][0] > bigUV ||
							(*lightMapUVs)[k][1] < -bigUV || (*lightMapUVs)[k][1] > bigUV
						)
					) 
					{
						tooBig++;
					}
				}

				if(tooBig==0 && (lm == true || CheckForBigTriangles(lightMapUVs, 3) == true))
				{
#if 0
					Vector3D vec(coords[index[j]]);
					SPEW(("micgaert", "\nvertex1 = %f,%f,%f", vec.x, vec.y, vec.z));
					vec = coords[index[j+1]];
					SPEW(("micgaert", "vertex2 = %f,%f,%f", vec.x, vec.y, vec.z));
					vec = coords[index[j+2]];
					SPEW(("micgaert", "vertex3 = %f,%f,%f", vec.x, vec.y, vec.z));
					vec = Vector3D(0.0f, 1.0f, 0.0f);
					SPEW(("micgaert", "normal = %f,%f,%f", vec.x, vec.y, vec.z));
					SPEW(("micgaert", "forward = %f,%f,%f", forward.x, forward.y, forward.z));
					SPEW(("micgaert", "distance = %f", f));
					SPEW(("micgaert", "light = %f,%f,%f", lightPosInShape.x, lightPosInShape.y, lightPosInShape.z));
					SPEW(("micgaert", "projection = %f,%f,%f", hitPoint.x, hitPoint.y, hitPoint.z));
#endif

					Scalar sq_falloff
						= falloff*falloff*light->GetIntensity();
					
					RGBAColor color;
					light->GetColor(color);

					color.red *= sq_falloff;
					color.green *= sq_falloff;
					color.blue *= sq_falloff;
					color.alpha = 1.0f;

					for(k=0;k<3;k++)
					{
						(*lightMapUVs)[k][0] += 0.5f;
						(*lightMapUVs)[k][1] += 0.5f;

						if(
							lightMap->AddIndex(addedIndicies++, addedVertices)==false ||
#if COLOR_AS_DWORD
							lightMap->AddVertex(addedVertices++, coords[index[k+j]], (*lightMapUVs)[k], GOSCopyColor(&color))==false
#else	//	COLOR_AS_DWORD
							lightMap->AddVertex(addedVertices++, coords[index[k+j]], (*lightMapUVs)[k], color)==false
#endif	//	COLOR_AS_DWORD
						)
						{
							return;
						}

						if(addedIndicies >= 252 && addedVertices > 0)
						{
							lightMap->AddMesh(referenceState.GetPriority()+1, addedVertices, addedIndicies);
							addedIndicies = 0;
							addedVertices = 0;
						}
					}
				}
			}
		}
		break;
		case MLRLight::SpotLight:
		{
			int behindCount = 0, falloffCount = 0;

			Check_Object(lightMap);

			light->GetInShapePosition(matrix);
			lightPosInShape = matrix;

			Scalar tanSpeadAngle = Cast_Object(MLRSpotLight*, light)->GetTanSpreadAngle();

#ifndef TOP_DOWN_ONLY
			matrix.GetLocalLeftInWorld(&left);
			matrix.GetLocalUpInWorld(&up);
			matrix.GetLocalForwardInWorld(&forward);
#else
			forward = UnitVector3D(0.0f, -1.0f, 0.0);
			up = UnitVector3D(1.0f, 0.0f, 0.0);
			left = UnitVector3D(0.0f, 0.0f, 1.0);
#endif

			Verify(Small_Enough(up*left));

			for(i=0,j=0,k=0;i<len;i++,j += 3)
			{
				behindCount = 0;
				falloffCount = 0;

				if((*testList)[i] == 0)
				{
					continue;
				}

				lm = false;

				if(!facePlanes[i].IsSeenBy(lightPosInShape))
				{
					continue;
				}

#if SPEW_AWAY
				Scalar maxX, maxZ;
				Scalar minX, minZ;

				minX = maxX = coords[index[j]].x;
				minZ = maxZ = coords[index[j]].z;

				if(minX>coords[index[j+1]].x)
				{
					minX = coords[index[j+1]].x;
				}
				if(minX>coords[index[j+2]].x)
				{
					minX = coords[index[j+2]].x;
				}
				if(minZ>coords[index[j+1]].z)
				{
					minZ = coords[index[j+1]].z;
				}
				if(minX>coords[index[j+2]].z)
				{
					minZ = coords[index[j+2]].z;
				}
				if(maxX<coords[index[j+1]].x)
				{
					maxX = coords[index[j+1]].x;
				}
				if(maxX<coords[index[j+2]].x)
				{
					maxX = coords[index[j+2]].x;
				}
				if(maxZ<coords[index[j+1]].z)
				{
					maxZ = coords[index[j+1]].z;
				}
				if(maxX<coords[index[j+2]].z)
				{
					maxZ = coords[index[j+2]].z;
				}

				if(lightPosInShape.x > minX && lightPosInShape.x < maxX && lightPosInShape.z > minZ && lightPosInShape.z < maxZ)
				{
					SPEW(("micgaert", "On Target !!"));
				}
#endif

				tooBig = 0;
				for(k=0;k<3;k++)
				{
					Vector3D vec;
					Scalar oneOver;

					vec.Subtract(coords[index[k+j]], lightPosInShape);

#ifndef TOP_DOWN_ONLY
					distance = (vec*forward);
#else
					distance = -vec.y;
#endif

#if SPEW_AWAY
					SPEW(("micgaert", "vertex%d = %f,%f,%f", k, coords[index[k+j]].x, coords[index[k+j]].y, coords[index[k+j]].z));
					SPEW(("micgaert", "distance = %f", distance));
#endif
					if(distance > SMALL)
					{
						if(Cast_Object(MLRInfiniteLightWithFalloff*, light)->GetFalloff(distance, falloff) == false)
						{
							falloffCount++;
						}
						(*lightMapSqFalloffs)[k] = falloff*falloff*light->GetIntensity();

						oneOver
#if 0
							= 1.0f/(2.0f*distance*tanSpeadAngle);
#else
							= OneOverApproximate(2.0f*distance*tanSpeadAngle);
#endif
					}
					else
					{
						behindCount++;
						oneOver = 1.0f/50.0f;
						(*lightMapSqFalloffs)[k] = 0.0f;
#if SPEW_AWAY
						SPEW(("micgaert", "Behind"));
#endif
					}

#ifndef TOP_DOWN_ONLY
					(*lightMapUVs)[k][0] = (left*vec) * oneOver;
					(*lightMapUVs)[k][1] = -(up*vec) * oneOver;
#else
					(*lightMapUVs)[k][0] = vec.x * oneOver;
					(*lightMapUVs)[k][1] = -vec.z * oneOver;
#endif

#if SPEW_AWAY
					SPEW(("micgaert", "uv%d = %f,%f", k, (*lightMapUVs)[k][0], (*lightMapUVs)[k][1]));
#endif
					if(
						(*lightMapUVs)[k][0] >= -0.5f && (*lightMapUVs)[k][0] <= 0.5f &&
						(*lightMapUVs)[k][1] >= -0.5f && (*lightMapUVs)[k][1] <= 0.5f

					) 
					{
						lm = true;
					}
					if(
						bigUV > 0.0f &&
						(
							(*lightMapUVs)[k][0] < -bigUV || (*lightMapUVs)[k][0] > bigUV ||
							(*lightMapUVs)[k][1] < -bigUV || (*lightMapUVs)[k][1] > bigUV
						)

					) 
					{
						tooBig++;
					}
				}
#if 1
				if(	
					tooBig == 0 
					&& behindCount < 3  
					&& falloffCount < 3 
 					&& ((lm == true)	|| CheckForBigTriangles(lightMapUVs, 3) == true)
				)
				{
					for(k=0;k<3;k++)
					{
						RGBAColor color;

						color.red = (*lightMapSqFalloffs)[k];
						color.green = (*lightMapSqFalloffs)[k];
						color.blue = (*lightMapSqFalloffs)[k];
						color.alpha = 1.0f;

						(*lightMapUVs)[k][0] += 0.5f;
						(*lightMapUVs)[k][1] += 0.5f;

						if(
							lightMap->AddIndex(addedIndicies++, addedVertices)==false ||
#if COLOR_AS_DWORD
							lightMap->AddVertex(addedVertices++, coords[index[k+j]], (*lightMapUVs)[k], GOSCopyColor(&color))==false
#else	//	COLOR_AS_DWORD
							lightMap->AddVertex(addedVertices++, coords[index[k+j]], (*lightMapUVs)[k], color)==false
#endif	//	COLOR_AS_DWORD
						)
						{
							return;
						}

						if(addedIndicies >= 252 && addedVertices > 0)
						{
							lightMap->AddMesh(referenceState.GetPriority()+1, addedVertices, addedIndicies);
							addedIndicies = 0;
							addedVertices = 0;
						}
					}
	#if SPEW_AWAY
					SPEW(("micgaert", "See the Light !"));
	#endif
				}
	#if SPEW_AWAY
				Vector3D vec = facePlanes[i].normal;
				SPEW(("micgaert", "normal = %f,%f,%f", vec.x, vec.y, vec.z));
				SPEW(("micgaert", "forward = %f,%f,%f", forward.x, forward.y, forward.z));
				SPEW(("micgaert", "left = %f,%f,%f", left.x, left.y, left.z));
				SPEW(("micgaert", "up = %f,%f,%f", up.x, up.y, up.z));
				SPEW(("micgaert", "light = %f,%f,%f\n", lightPosInShape.x, lightPosInShape.y, lightPosInShape.z));
	#endif
#else
				if(tooBig != 0)
				{
					lightMap->SetPolygonMarker(1);
					lightMap->AddUShort(3);

					for(k=0;k<3;k++)
					{
						lightMap->AddCoord(coords[index[k+j]]);
					}
					for(k=0;k<3;k++)
					{
						lightMap->AddColor(RGBAColor(0.0f, 0.0f, 0.5f, 1.0f));
					}
					for(k=0;k<3;k++)
					{
						lightMap->AddUVs(0.5f, 0.5f);
		//				DEBUG_STREAM << k << " " << lightMapUVs[k][0] << " " << lightMapUVs[k][0] << "\n";
					}
				} 
				else if(behindCount != 0)
				{
					lightMap->SetPolygonMarker(1);
					lightMap->AddUShort(3);

					for(k=0;k<3;k++)
					{
						lightMap->AddCoord(coords[index[k+j]]);
					}
					for(k=0;k<3;k++)
					{
						lightMap->AddColor(RGBAColor(0.5f, 0.0f, 0.0f, 1.0f));
					}
					for(k=0;k<3;k++)
					{
						lightMap->AddUVs(0.5f, 0.5f);
		//				DEBUG_STREAM << k << " " << lightMapUVs[k][0] << " " << lightMapUVs[k][0] << "\n";
					}
				} 
				else	if(behindCount == 0 && (lm == true || CheckForBigTriangles(&lightMapUVs, 3) == true) )
				{
					lightMap->SetPolygonMarker(1);
					lightMap->AddUShort(3);

					for(k=0;k<3;k++)
					{
						lightMap->AddCoord(coords[index[k+j]]);
					}
					for(k=0;k<3;k++)
					{
						lightMap->AddColor(lightMapSqFalloffs[k], lightMapSqFalloffs[k], lightMapSqFalloffs[k], 1.0f);
					}
					for(k=0;k<3;k++)
					{
						lightMap->AddUVs(lightMapUVs[k][0]+0.5f, lightMapUVs[k][1]+0.5f);
		//				DEBUG_STREAM << k << " " << lightMapUVs[k][0] << " " << lightMapUVs[k][0] << "\n";
					}

				}
				else if(CheckForBigTriangles(&lightMapUVs, 3) == false)
				{
					lightMap->SetPolygonMarker(1);
					lightMap->AddUShort(3);

					for(k=0;k<3;k++)
					{
						lightMap->AddCoord(coords[index[k+j]]);
					}
					for(k=0;k<3;k++)
					{
						lightMap->AddColor(errorColor);
					}
					for(k=0;k<3;k++)
					{
						lightMap->AddUVs(0.5f, 0.5f);
		//				DEBUG_STREAM << k << " " << lightMapUVs[k][0] << " " << lightMapUVs[k][0] << "\n";
					}
				}
#endif
			}
		}
		break;
#define TOP_DOWN_ONLY
		case MLRLight::ProjectLight:
		{
			MLRProjectLight *pLight = Cast_Object(MLRProjectLight*, light);
			
			light->GetInShapePosition(lightPosInShape);


			Scalar n, f;
			pLight->GetFalloffDistance(n, f);

			Scalar ray_distance = light->GetIntensity();

			UnitVector3D dir, rot;
			light->GetInShapeDirection(dir);

			lightPosInShape.AddScaled(lightPosInShape, dir, ray_distance);

			rot = dir;
			rot.y = 0.0f;

			rot.Normalize(rot);

			if(ray_distance <= SMALL)
			{
				break;
			}
//			Scalar One_Over_Falloff = 1.0f/(3.0f*f);
			Scalar oneOverRadius = 0.5f / (pLight->GetTanSpreadAngle() * ray_distance);
			
			if(pLight->GetFalloff(ray_distance, falloff))
			{
				for(i=0,j=0,k=0;i<len;i++,j += 3)
				{
					if((*testList)[i] == 0)
					{
						continue;
					}

					if(dir.y>0.0f)
					{
						continue;
					}

					lm = false;

					tooBig = 0;
					for(k=0;k<3;k++)
					{
						Vector3D vec(coords[index[k+j]]);
						vec-=lightPosInShape;

						Scalar u, v;
						u = vec.x * oneOverRadius;
						v = vec.z * oneOverRadius;
						(*lightMapUVs)[k][0] = u*rot.z - v*rot.x;
						(*lightMapUVs)[k][1] = v*rot.z + u*rot.x;


						if(
							(*lightMapUVs)[k][0] >= -0.5f && (*lightMapUVs)[k][0] <= 0.5f &&
							(*lightMapUVs)[k][1] >= -0.25f && (*lightMapUVs)[k][1] <= 0.75f

						) 
						{
							lm = true;
						}
						if(
							bigUV > 0.0f &&
							(
								(*lightMapUVs)[k][0] < -bigUV || (*lightMapUVs)[k][0] > bigUV ||
								(*lightMapUVs)[k][1] < -bigUV || (*lightMapUVs)[k][1] > bigUV
							)
						) 
						{
							tooBig++;
						}
					}

					if(tooBig==0 && (lm == true || CheckForBigTriangles(lightMapUVs, 3) == true))
					{
	#if 0
						Vector3D vec(coords[index[j]]);
						SPEW(("micgaert", "\nvertex1 = %f,%f,%f", vec.x, vec.y, vec.z));
						vec = coords[index[j+1]];
						SPEW(("micgaert", "vertex2 = %f,%f,%f", vec.x, vec.y, vec.z));
						vec = coords[index[j+2]];
						SPEW(("micgaert", "vertex3 = %f,%f,%f", vec.x, vec.y, vec.z));
						vec = facePlanes[i].normal;
						SPEW(("micgaert", "normal = %f,%f,%f", vec.x, vec.y, vec.z));
						SPEW(("micgaert", "forward = %f,%f,%f", forward.x, forward.y, forward.z));
						SPEW(("micgaert", "distance = %f", f));
						SPEW(("micgaert", "light = %f,%f,%f", lightPosInShape.x, lightPosInShape.y, lightPosInShape.z));
						SPEW(("micgaert", "projection = %f,%f,%f", hitPoint.x, hitPoint.y, hitPoint.z));
	#endif

						Scalar sq_falloff
							= falloff*falloff;	//*light->GetIntensity();

						RGBAColor color;
						light->GetColor(color);

						color.red *= sq_falloff;
						color.green *= sq_falloff;
						color.blue *= sq_falloff;
						color.alpha = 1.0f;

						for(k=0;k<3;k++)
						{
							(*lightMapUVs)[k][0] += 0.5f;
							(*lightMapUVs)[k][1] += 0.25f;

							if(
								lightMap->AddIndex(addedIndicies++, addedVertices)==false ||
#if COLOR_AS_DWORD
								lightMap->AddVertex(addedVertices++, coords[index[k+j]], (*lightMapUVs)[k], GOSCopyColor(&color))==false
#else	//	COLOR_AS_DWORD
								lightMap->AddVertex(addedVertices++, coords[index[k+j]], (*lightMapUVs)[k], color)==false
#endif	//	COLOR_AS_DWORD
							)
							{
								return;
							}

							if(addedIndicies >= 252 && addedVertices > 0)
							{
								lightMap->AddMesh(referenceState.GetPriority()+1, addedVertices, addedIndicies);
								addedIndicies = 0;
								addedVertices = 0;
							}
						}

					}
				}
			}
		}
		break;
		case MLRLight::ShadowLight:
		break;
		default:
			STOP(("MLR_Water::LightMapLighting: What you want me to do ?"));
		break;
	}

	if(addedIndicies && addedVertices)
	{
		lightMap->AddMesh(referenceState.GetPriority()+1, addedVertices, addedIndicies);
	}
}



void
	MLR_Water::FindFacePlanes()
{
	Check_Object(this); 

	int i, j, numPrimitives = GetNumPrimitives();
	Vector3D v;

	Verify(index.GetLength() > 0);

	for(i=0,j=0;i<numPrimitives;++i,j+=3)
	{
		facePlanes[i].BuildPlane(
			coords[index[j]],
			coords[index[j+1]],
			coords[index[j+2]]
		);

		;
	}
}

