#include "MLRHeaders.hpp"

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

#if !defined(MLR_MLRSPRITECLOUD_HPP)
	#include <MLR\MLRSpriteCloud.hpp>
#endif

extern DWORD gShowClippedPolys;

//#############################################################################
//####################    MLRSpriteCloud    ##########################
//#############################################################################

MLRSpriteCloud::ClassData*
	MLRSpriteCloud::DefaultData = NULL;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MLRSpriteCloud::InitializeClass()
{
	Verify(!DefaultData);
	Verify(gos_GetCurrentHeap() == StaticHeap);
	DefaultData =
		new ClassData(
			MLRSpriteCloudClassID,
			"MidLevelRenderer::MLRSpriteCloud",
			MLRPointCloud::DefaultData
		);
	Register_Object(DefaultData);
}

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

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MLRSpriteCloud::MLRSpriteCloud(int nr) :
	MLRPointCloud(nr)
{
	Verify(gos_GetCurrentHeap() == EffectHeap);
	usedNrOfVertices = NULL;

	Check_Pointer(this);
	
	drawMode = SortData::TriList;
}

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

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void 
	MLRSpriteCloud::SetData
	(
		const int *count,
		const Stuff::Point3D *point_data,
		const Stuff::RGBAColor *color_data,
		const Stuff::Scalar *scale_data,
		const Vector2DScalar *uv_data	// only 4, regardless count !
	)
{
	Check_Pointer(this);

	usedNrOfVertices = count;

	points = point_data;
	colors = color_data;
	scales = scale_data;
	texCoords = uv_data;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void 
	MLRSpriteCloud::Draw (DrawEffectInformation *dInfo, GOSVertexPool *allVerticesToDraw, MLRSorter *sorter)
{
	Check_Object(this);

#ifdef LAB_ONLY
	if(Limits::Max_Number_Vertices_Per_Frame < allVerticesToDraw->GetLast() + *usedNrOfVertices * 4)
	{
		SPEWALWAYS((0, "Not drawing MLRSpriteCloud. Too many vertices! Raid a bug to Art!"));
		return;
	}
#endif

	worldToEffect.Invert(*dInfo->effectToWorld);

	Transform(*usedNrOfVertices, 1);

	if( Clip(dInfo->clippingFlags, allVerticesToDraw, false ) )
	{
		sorter->AddEffect(this, dInfo->state);
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
	MLRSpriteCloud::Draw (ToBeDrawnPrimitive *tbdp, MLRSorter *sorter)
{
	Check_Object(this);

	effectToClipMatrix = tbdp->shapeToClipMatrix;
	Transform(*usedNrOfVertices, 1);

	int index = -1;
	if( Clip(tbdp->clippingFlags, tbdp->allVerticesToDraw, true ) )
	{
		sorter->AddEffect(this, tbdp->state, index);
	}
	return index;
}

static MLRClippingState theAnd, theOr, theTest;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int 
	MLRSpriteCloud::Clip(MLRClippingState clippingFlags, GOSVertexPool *vt, bool db)
{
	//--------------------------------------
	// See if we don't have to draw anything
	//--------------------------------------
	//
	int i;
	numGOSVertices = 0;

	if(usedNrOfVertices <= 0)
	{
		return 0;
	}

	Check_Object(vt);
	gos_vertices = vt->GetActualVertexPool(db);

	Stuff::Vector4D *v4d = transformedCoords->GetData();

	Vector4D tempVertex;
	for(i=0;i<*usedNrOfVertices;i++,v4d++)
	{
		if(IsOn(i) == false)
		{
			continue;
		}

		if(clippingFlags.GetClippingState() != 0)
		{
			if( clippingFlags.IsFarClipped() && v4d->w < v4d->z)
			{
				continue;
			}

			if( clippingFlags.IsNearClipped() && v4d->z < 0.0f)
			{
				continue;
			}

			if( clippingFlags.IsRightClipped() && v4d->x < 0.0f)
			{
				continue;
			}

			if( clippingFlags.IsLeftClipped() && v4d->w < v4d->x)
			{
				continue;
			}

			if( clippingFlags.IsBottomClipped() && v4d->y < 0.0f)
			{
				continue;
			}

			if(clippingFlags.IsTopClipped() && v4d->w < v4d->y)
			{
				continue;
			}
		}

		tempVertex.w = 1.0f/v4d->w;

		tempVertex.x = v4d->x * tempVertex.w;
		tempVertex.y = v4d->y * tempVertex.w;
		tempVertex.z = v4d->z * tempVertex.w;

		tempVertex.x = tempVertex.x*ViewportScalars::MulX + ViewportScalars::AddX;
		tempVertex.y = tempVertex.y*ViewportScalars::MulY + ViewportScalars::AddY;

		if( tempVertex.x + scales[i] >= Environment.screenWidth )
		{
			continue;
		}

		if( tempVertex.x < scales[i])
		{
			continue;
		}

		if( tempVertex.y + scales[i] >= Environment.screenHeight )
		{
			continue;
		}

		if( tempVertex.y < scales[i])
		{
			continue;
		}

		DWORD color; 

#ifdef I_SAY_YES_TO_COLOR
	#ifdef I_SAY_YES_TO_DWORD_COLOR
		color = colors!=NULL ? colors[i] : paintMeColorDW;
	#else	//	I_SAY_YES_TO_DWORD_COLOR
		color = GOSCopyColor(colors!=NULL ? (&colors[i]) : (&paintMeColorF) );
	#endif	//	I_SAY_YES_TO_DWORD_COLOR
#else	//	I_SAY_YES_TO_COLOR
		color = paintMeColorDW;
#endif	//	I_SAY_YES_TO_COLOR

		Scalar s = scales[i];
		gos_vertices[numGOSVertices].x = tempVertex.x - s;
		gos_vertices[numGOSVertices].y = tempVertex.y - s;
		gos_vertices[numGOSVertices].z = tempVertex.z;
		gos_vertices[numGOSVertices].rhw = tempVertex.w;
		gos_vertices[numGOSVertices].argb = color;
		*((BYTE *)&gos_vertices[numGOSVertices].frgb + 3) = 0xff;
		gos_vertices[numGOSVertices].u = texCoords[0][0];
		gos_vertices[numGOSVertices].v = texCoords[0][1];
		numGOSVertices++;

		gos_vertices[numGOSVertices].x = tempVertex.x - s;
		gos_vertices[numGOSVertices].y = tempVertex.y + s;
		gos_vertices[numGOSVertices].z = tempVertex.z;
		gos_vertices[numGOSVertices].rhw = tempVertex.w;
		gos_vertices[numGOSVertices].argb = color;
		*((BYTE *)&gos_vertices[numGOSVertices].frgb + 3) = 0xff;
		gos_vertices[numGOSVertices].u = texCoords[1][0];
		gos_vertices[numGOSVertices].v = texCoords[1][1];
		numGOSVertices++;

		gos_vertices[numGOSVertices].x = tempVertex.x + s;
		gos_vertices[numGOSVertices].y = tempVertex.y + s;
		gos_vertices[numGOSVertices].z = tempVertex.z;
		gos_vertices[numGOSVertices].rhw = tempVertex.w;
		gos_vertices[numGOSVertices].argb = color;
		*((BYTE *)&gos_vertices[numGOSVertices].frgb + 3) = 0xff;
		gos_vertices[numGOSVertices].u = texCoords[2][0];
		gos_vertices[numGOSVertices].v = texCoords[2][1];
		numGOSVertices++;


		gos_vertices[numGOSVertices].x = tempVertex.x - s;
		gos_vertices[numGOSVertices].y = tempVertex.y - s;
		gos_vertices[numGOSVertices].z = tempVertex.z;
		gos_vertices[numGOSVertices].rhw = tempVertex.w;
		gos_vertices[numGOSVertices].argb = color;
		*((BYTE *)&gos_vertices[numGOSVertices].frgb + 3) = 0xff;
		gos_vertices[numGOSVertices].u = texCoords[0][0];
		gos_vertices[numGOSVertices].v = texCoords[0][1];
		numGOSVertices++;

		gos_vertices[numGOSVertices].x = tempVertex.x + s;
		gos_vertices[numGOSVertices].y = tempVertex.y + s;
		gos_vertices[numGOSVertices].z = tempVertex.z;
		gos_vertices[numGOSVertices].rhw = tempVertex.w;
		gos_vertices[numGOSVertices].argb = color;
		*((BYTE *)&gos_vertices[numGOSVertices].frgb + 3) = 0xff;
		gos_vertices[numGOSVertices].u = texCoords[2][0];
		gos_vertices[numGOSVertices].v = texCoords[2][1];
		numGOSVertices++;

		gos_vertices[numGOSVertices].x = tempVertex.x + s;
		gos_vertices[numGOSVertices].y = tempVertex.y - s;
		gos_vertices[numGOSVertices].z = tempVertex.z;
		gos_vertices[numGOSVertices].rhw = tempVertex.w;
		gos_vertices[numGOSVertices].argb = color;
		*((BYTE *)&gos_vertices[numGOSVertices].frgb + 3) = 0xff;
		gos_vertices[numGOSVertices].u = texCoords[3][0];
		gos_vertices[numGOSVertices].v = texCoords[3][1];
		numGOSVertices++;
	}
	if(db==false)
	{
		vt->Increase(numGOSVertices);
	}

	visible = numGOSVertices ? 1 : 0;

	return visible;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void 
	MLRSpriteCloud::TestInstance() const
{
	if (usedNrOfVertices)
	{
		Verify(*usedNrOfVertices >= 0);
		Verify(*usedNrOfVertices <= maxNrOf);
	}
}

