#include "MLRHeaders.hpp"

#if !defined(MLR_MLRCLIPTRICK_HPP)
	#include <MLR\MLRClipTrick.hpp>
#endif

//#############################################################################
//###########################    MLRLightMap    ###############################
//#############################################################################

MLRLightMap::ClassData*
	MLRLightMap::DefaultData = NULL;
Stuff::MemoryStream
	*MLRLightMap::stream;
bool
	MLRLightMap::full;
GOSVertexPool*
	MLRLightMap::vertexPool;


int	MLRLightMap::currentVertex, MLRLightMap::currentIndex;

DynamicArrayOf<Stuff::Point3D>	*MLRLightMap::coords;	// Base address of coordinate list 
DynamicArrayOf<Vector2DScalar>	*MLRLightMap::texCoords;	// Base address of texture coordinate list 
DynamicArrayOf<BYTE>			*MLRLightMap::index;	// List of color indexes 
DynamicArrayOf<ColorType>		*MLRLightMap::colors;	// Base address of color list 

int MLRLightMap::currentCTMesh;
DynamicArrayOf<MLR_I_C_TMesh*>	*MLRLightMap::ctmeshs;







DynamicArrayOf<Stuff::Vector4D>
	*transformedCoords, *clipExtraCoords;
DynamicArrayOf<RGBAColor>
	*clipExtraColors;
DynamicArrayOf<Vector2DScalar>
	*clipExtraTexCoords;
DynamicArrayOf<MLRClippingState>
	*clippingStates;
ClipPolygon2
	*MLRLightMap::clipBuffer;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MLRLightMap::InitializeClass()
{
	Verify(!DefaultData);
	Verify(gos_GetCurrentHeap() == StaticHeap);
	DefaultData =
		new ClassData(
			MLRLightMapClassID,
			"MidLevelRenderer::MLRLightMap",
			RegisteredClass::DefaultData
		);
	Register_Object(DefaultData);

	BYTE *ptr = new BYTE [Limits::Max_Size_Of_LightMap_MemoryStream];
	Register_Pointer(ptr);

	stream = new MemoryStream(ptr, Limits::Max_Size_Of_LightMap_MemoryStream);
	Register_Object(stream);

	coords = new DynamicArrayOf<Point3D> (Limits::Max_Number_Vertices_Per_Mesh);
	Register_Object(coords);

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

	index = new DynamicArrayOf<BYTE> (Limits::Max_Size_Of_Index_Buffer);
	Register_Object(index);

	colors = new DynamicArrayOf<ColorType> (Limits::Max_Number_Vertices_Per_Mesh);
	Register_Object(colors);

	ctmeshs = new DynamicArrayOf<MLR_I_C_TMesh*> (32);

	for(int i=0;i<32;i++)
	{
		(*ctmeshs)[i] = new MLR_I_C_TMesh;
	}


	transformedCoords = new DynamicArrayOf<Stuff::Vector4D> (Limits::Max_Number_Vertices_Per_Polygon);
	Register_Object(transformedCoords);
	clipExtraCoords = new DynamicArrayOf<Stuff::Vector4D> (2*Limits::Max_Number_Vertices_Per_Polygon);
	Register_Object(clipExtraCoords);
	clipExtraColors = new DynamicArrayOf<RGBAColor> (2*Limits::Max_Number_Vertices_Per_Polygon);
	Register_Object(clipExtraColors);
	clipExtraTexCoords = new DynamicArrayOf<Vector2DScalar> (2*Limits::Max_Number_Vertices_Per_Polygon);
	Register_Object(clipExtraTexCoords);
	clippingStates = new DynamicArrayOf<MLRClippingState> (Limits::Max_Number_Vertices_Per_Polygon);
	Register_Object(clippingStates);

	clipBuffer = new ClipPolygon2 [2];
	Register_Pointer(clipBuffer);

	clipBuffer[0].Init(Limits::Max_Number_Of_Multitextures);
	clipBuffer[1].Init(Limits::Max_Number_Of_Multitextures);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MLRLightMap::TerminateClass()
{
	clipBuffer[1].Destroy();
	clipBuffer[0].Destroy();
	Unregister_Pointer(clipBuffer);
	delete [] clipBuffer;

	Unregister_Object(transformedCoords);
	delete transformedCoords;
	Unregister_Object(clipExtraCoords);
	delete clipExtraCoords;
	Unregister_Object(clipExtraColors);
	delete clipExtraColors;
	Unregister_Object(clipExtraTexCoords);
	delete clipExtraTexCoords;
	Unregister_Object(clippingStates);
	delete clippingStates;


	Unregister_Object(coords);
	delete coords;

	Unregister_Object(texCoords);
	delete texCoords;

	Unregister_Object(index);
	delete index;

	Unregister_Object(colors);
	delete colors;

	int i;

	for(i=0;i<ctmeshs->GetLength();i++)
	{
		(*ctmeshs)[i]->DetachReference();
	}

	Unregister_Object(ctmeshs);
	delete ctmeshs;

	stream->Rewind();
	BYTE *ptr = (BYTE *)stream->GetPointer();

	Unregister_Object(stream);
	delete stream;
	stream = NULL;

	Unregister_Pointer(ptr);
	delete [] ptr;

	Unregister_Object(DefaultData);
	delete DefaultData;
	DefaultData = NULL;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MLRLightMap::MLRLightMap(MLRTexture *tex) :
	RegisteredClass(DefaultData)
{
	Verify(gos_GetCurrentHeap() == LightsHeap);

	referenceCount = 0;

	state.SetTextureHandle(tex->GetTextureHandle());
	state.SetRenderDeltaMask(MLRState::TextureMask);

//	state.SetFogData(0xffffffff, 0.0f, 1.0f, 100.0f);
#ifdef OLDFOG
	state.SetFogMode(MLRState::DisableFogMode);
#else
	state.SetFogMode(0);
#endif

	state.SetZBufferCompareOn();
	state.SetZBufferWriteOff();
	state.SetBackFaceOn();
	state.SetAlphaMode(MLRState::OneOneMode);
	state.SetBumpMapOff();

	state.SetFilterMode(MLRState::BiLinearFilterMode);
	state.SetTextureWrapMode(MLRState::TextureClamp);

	full = false;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MLRLightMap::~MLRLightMap()
{
	Check_Object(this);
	Check_Object(stream);

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MLRLightMap::SetDrawData
		(
			GOSVertexPool *vp,
			Stuff::Matrix4D *mat,
			MLRClippingState& clippingState,
			MLRStateBase& _state
		)
{
	vertexPool = vp;

	stream->Rewind();
	full = false;

	Check_Object(mat);
	*stream << (int)Matrix4D;
	*stream << reinterpret_cast<int>(mat);

	*stream << (int)ClippingState;
	clippingState.Save(stream);

	*stream << (int)MasterRenderState;

	*stream << _state.GetRenderStateFlags() << _state.GetProcessStateFlags();

	stream->AdvanceToDwordBoundary();

	Reset();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MLRLightMap::TestInstance()
{
	Verify(IsDerivedFrom(DefaultData));
	Check_Object(stream);
}

void
	MLRLightMap::Reset()
{
	currentVertex = 0;
	currentIndex = 0;
}

bool
	MLRLightMap::IsFull(int howMuchMore)
{
	return (howMuchMore > (coords->GetLength() - currentVertex));
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MLRLightMap::DrawLightMaps(MLRSorter *sorter, bool db)
{
	Check_Object(stream);

	void *ptr, *end = stream->GetPointer();

	Stuff::Matrix4D *currentMatrix=NULL;
	MLRClippingState currentClippingState;
	
	MLRState currentState, masterState;

	int pointerValue;
	Check_Object(vertexPool);

	int msd;

	stream->Rewind();

	ptr = stream->GetPointer();
	currentCTMesh = 0;

	while(ptr < end)
	{
		*stream >> msd;

		switch(msd)
		{
			case Matrix4D:
				*stream >> pointerValue;
				currentMatrix = reinterpret_cast<Stuff::Matrix4D*>(pointerValue);
				Check_Object(currentMatrix);
			break;
			case ClippingState:
				currentClippingState.Load(stream);
			break;
			case MasterRenderState:
			{
				DWORD render_state, process_state;

				*stream >> render_state >> process_state;

				stream->AdvanceToDwordBoundary();

				masterState.SetRenderStateFlags(render_state);
				masterState.SetProcessStateFlags(process_state);
			}
			break;
			case CTMesh:
			{
				MLRState lightmapState;
				lightmapState.Load(stream, Current_MLR_Version);
				stream->AdvanceToDwordBoundary();

				int startVertex, vertexCount, startIndex, indexCount;
				*stream >> startVertex >> vertexCount;
				*stream >> startIndex >> indexCount;

				if(vertexCount>0 && indexCount>0)
				{
					(*ctmeshs)[currentCTMesh]->SetCoordData(&(*coords)[startVertex], vertexCount);
					(*ctmeshs)[currentCTMesh]->SetTexCoordData(&(*texCoords)[startVertex], vertexCount);
					(*ctmeshs)[currentCTMesh]->SetColorData(&(*colors)[startVertex], vertexCount);

					(*ctmeshs)[currentCTMesh]->SetIndexData(&(*index)[startIndex], indexCount);

					(*ctmeshs)[currentCTMesh]->SetSubprimitiveLengths(NULL, (int)(indexCount*0.33333333333333333333333333333334f), false);

					(*ctmeshs)[currentCTMesh]->SetReferenceState(lightmapState);
					(*ctmeshs)[currentCTMesh]->CombineStates(masterState);

					currentCTMesh++;

					if(currentCTMesh>=ctmeshs->GetLength())
					{
						ctmeshs->SetLength(2*ctmeshs->GetLength());
					}
				}
			}
			break;
			default:
				STOP(("Corrupted light map stream !!"));
			break;
		}
		ptr = stream->GetPointer();
	}

	for(int i=0;i<currentCTMesh;i++)
	{
		(*ctmeshs)[i]->InitializeDrawPrimitive(1, 1);
		(*ctmeshs)[i]->FindVisibleVertices();

		if(currentClippingState.GetClippingState() != 0)
		{
			(*ctmeshs)[i]->TransformAndClip(
					currentMatrix,
					currentClippingState,
					vertexPool,
					NULL,
#if COLOR_AS_DWORD>0
					paintMeColorDW,
#else
					GOSCopyColor(&paintMeColorF),
#endif
					true
			);
		}
		else
		{
			(*ctmeshs)[i]->TransformNoClip(
				currentMatrix,
				vertexPool,
				NULL,
#if COLOR_AS_DWORD>0
				paintMeColorDW,
#else
				GOSCopyColor(&paintMeColorF),
#endif
				true
			);
		}

		if((*ctmeshs)[i]->GetVisible())
		{
			sorter->DrawPrimitive((*ctmeshs)[i], 0);
		}
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MLR_I_C_TMesh*
	MLRLightMap::CreateLightMapMesh()
{
	Check_Object(stream);

	gos_PushCurrentHeap(LightsHeap);
	MLR_I_C_TMesh *ctmesh = NULL;
	
	void *ptr, *end = stream->GetPointer();

	MLRClippingState currentClippingState;
	
	MLRState currentState, masterState;

//	int stride;

	int i;
//	Stuff::Point3D *coords = NULL;
//	Stuff::RGBAColor color;
//	Stuff::RGBAColor *colors = NULL;
//	Vector2DScalar *texCoords = NULL;

	int msd;
	MemoryStreamData type;

	stream->Rewind();

	ptr = stream->GetPointer();

	int startVertex = -1, vertexCount = -1, startIndex = -1, indexCount = -1;

	while(ptr < end)
	{
		*stream >> msd;

		type = static_cast<MemoryStreamData>(msd);

		switch(msd)
		{
			case Matrix4D:
				//	not this time
				*stream >> i;
			break;
			case ClippingState:
				//	not this time
				*stream >> i;
			break;
			case MasterRenderState:
				//	not this time
				masterState.Load(stream, Current_MLR_Version);
			break;
			case CTMesh:
			{
				MLRState lightmapState;
				lightmapState.Load(stream, Current_MLR_Version);
				stream->AdvanceToDwordBoundary();

				int tstartVertex, tvertexCount, tstartIndex, tindexCount;
				*stream >> tstartVertex >> tvertexCount;
				*stream >> tstartIndex >> tindexCount;

				if(vertexCount>0 && indexCount>0)
				{
					if(ctmesh == NULL)
					{
						ctmesh = new MLR_I_C_TMesh;

						startVertex = tstartVertex;
						vertexCount = tvertexCount;
						startIndex = tstartIndex;
						indexCount = tindexCount;

						ctmesh->SetReferenceState(lightmapState);
					}
					else
					{
						if(lightmapState == ctmesh->GetReferenceState())
						{
							vertexCount += tvertexCount;
							indexCount += tindexCount;
						}
						else
						{
							ctmesh->CombineStates(masterState);

							if(ctmesh->dataStore == NULL)
							{
								ctmesh->dataStore = new DataStorage;
							}
							ctmesh->dataStore->coords.AssignData(&(*coords)[startVertex], vertexCount);
							ctmesh->SetCoordData(ctmesh->dataStore->coords.GetData(), vertexCount);

							ctmesh->dataStore->texCoords.AssignData(&(*texCoords)[startVertex], vertexCount);
							ctmesh->SetTexCoordData(ctmesh->dataStore->texCoords.GetData(), vertexCount);

							ctmesh->dataStore->colors.AssignData(&(*colors)[startVertex], vertexCount);
							ctmesh->SetColorData(ctmesh->dataStore->colors.GetData(), vertexCount);

							ctmesh->dataStore->index.AssignData(&(*index)[startVertex], indexCount);
							ctmesh->SetIndexData(ctmesh->dataStore->index.GetData(), indexCount);

							ctmesh->SetSubprimitiveLengths(NULL, (int)(indexCount*0.33333333333333333333333333333334f), false);

							return ctmesh;
						}
					}
				}
			}
			break;
/*
			case LightMapRenderState:
			{
				MLRState state; 
				state.Load(stream, Current_MLR_Version);

				if(numGOSVertices && (state != currentState))
				{
					if(ctmesh!=NULL)
					{
						ctmesh->SetSubprimitiveLengths(NULL, numGOSVertices/3);

						ctmesh->FlashClipCoords(numGOSVertices);
						ctmesh->FlashClipTexCoords(numGOSVertices);
						ctmesh->FlashClipColors(numGOSVertices);
						ctmesh->SetReferenceState(currentState);

						ctmesh->TheIndexer(numGOSVertices);

						ctmesh->FindFacePlanes();
					}
				}
				currentState = state;
			}
			break;
			case Polygon:
			{
				if(ctmesh == NULL)
				{
					ctmesh = new MLR_I_C_TMesh;
					numGOSVertices = 0;
				}
				*stream >> stride;
				Verify(stride==3);

				*stream >> color;

#if COLOR_AS_DWORD
				DWORD argb = 0xffffffff;
				argb = GOSCopyColor(&color);
#endif

				coords = (Stuff::Point3D *)stream->GetPointer();
				stream->AdvancePointer(stride*sizeof(Stuff::Point3D));
				texCoords = (Vector2DScalar *)stream->GetPointer();
				stream->AdvancePointer(stride*sizeof(Vector2DScalar));

				for(i=0;i<stride;i++,numGOSVertices++)
				{
					ctmesh->SetClipCoord(coords[i], numGOSVertices);
					ctmesh->SetClipTexCoord(texCoords[i], numGOSVertices);
#if COLOR_AS_DWORD
					ctmesh->SetClipColor(argb, numGOSVertices);
#else
					ctmesh->SetClipColor(color, numGOSVertices);
#endif
				}
			}
			break;
			case PolygonWithColor:
			{
				if(ctmesh == NULL)
				{
					ctmesh = new MLR_I_C_TMesh;
					numGOSVertices = 0;
				}

				*stream >> stride;
				Verify(stride<=Limits::Max_Number_Vertices_Per_Polygon);

				coords = (Stuff::Point3D *)stream->GetPointer();
				stream->AdvancePointer(stride*sizeof(Stuff::Point3D));
				
				colors = (Stuff::RGBAColor *)stream->GetPointer();
				stream->AdvancePointer(stride*sizeof(Stuff::RGBAColor));

				texCoords = (Vector2DScalar *)stream->GetPointer();
				stream->AdvancePointer(stride*sizeof(Vector2DScalar));


				for(i=0;i<stride;i++,numGOSVertices++)
				{
					ctmesh->SetClipCoord(coords[i], numGOSVertices);
					ctmesh->SetClipTexCoord(texCoords[i], numGOSVertices);
#if COLOR_AS_DWORD
					DWORD argb = GOSCopyColor(&colors[i]);
					ctmesh->SetClipColor(argb, numGOSVertices);
#else
					ctmesh->SetClipColor(colors[i], numGOSVertices);
#endif
				}
			}
			break;
*/
			default:
				STOP(("Corrupted light map stream !!"));
			break;
		}
		ptr = stream->GetPointer();
	}

	if(vertexCount>0 && indexCount>0 && ctmesh!=NULL)
	{
		ctmesh->CombineStates(masterState);

		if(ctmesh->dataStore == NULL)
		{
			ctmesh->dataStore = new DataStorage;
		}
		ctmesh->dataStore->coords.AssignData(&(*coords)[startVertex], vertexCount);
		ctmesh->SetCoordData(ctmesh->dataStore->coords.GetData(), vertexCount);

		ctmesh->dataStore->texCoords.AssignData(&(*texCoords)[startVertex], vertexCount);
		ctmesh->SetTexCoordData(ctmesh->dataStore->texCoords.GetData(), vertexCount);

		ctmesh->dataStore->colors.AssignData(&(*colors)[startVertex], vertexCount);
		ctmesh->SetColorData(ctmesh->dataStore->colors.GetData(), vertexCount);

		ctmesh->dataStore->index.AssignData(&(*index)[startVertex], indexCount);
		ctmesh->SetIndexData(ctmesh->dataStore->index.GetData(), indexCount);

		ctmesh->SetSubprimitiveLengths(NULL, (int)(indexCount*0.33333333333333333333333333333334f), false);
	}
	gos_PopCurrentHeap();

	return ctmesh;
}