#include "MLRHeaders.hpp"
#include "MLR\MLRFootstep.hpp"

MLRFootStep *MLRFootStep::Instance = NULL;

MLRFootStep::ClassData*
	MLRFootStep::DefaultData = NULL;

//#############################################################################
//############################    MLRFootStep    ##############################
//#############################################################################

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

	Instance = NULL;
}

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

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MLRFootStep::MLRFootStep(MemoryStream *stream):
	RegisteredClass(DefaultData)
{
	STOP(("Not implemented"));
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MLRFootStep::MLRFootStep(int nrOfActiveFootSteps):
	RegisteredClass(DefaultData), theFootSteps(nrOfActiveFootSteps)
{
	firstStep = 0;
	lastStep = 0;

	SetFadeOut(150.0f, 200.0f);

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MLRFootStep::~MLRFootStep()
{
	for(int i=0;i<theFootSteps.GetLength();i++)
	{
		if(theFootSteps[i].shape != NULL)
		{
			theFootSteps[i].shape->DetachReference();
			theFootSteps[i].shape = NULL;
		}
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
FootStepInfo*
	MLRFootStep::AddAStep(MLRShape *shape, Point3D& loc)
{
	if(theFootSteps[lastStep].shape != NULL)
	{
		theFootSteps[lastStep].shape->DetachReference();
	}

	int ret = lastStep;
	theFootSteps[lastStep].shape = shape;
	theFootSteps[lastStep].location = loc;
	lastStep++;

	if(lastStep==theFootSteps.GetLength())
	{
		lastStep = 0;
	}
	if(lastStep==firstStep)
	{
		firstStep++;

		if(firstStep==theFootSteps.GetLength())
		{
			firstStep = 0;
		}
	}
	return &theFootSteps[ret];
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void 
	MLRFootStep::Draw(MLRClipper *theClipper, const LinearMatrix4D& eye)
{
	Check_Object(this);
	Check_Object(theClipper);
	Check_Object(&eye);

	if(firstStep == lastStep || ShowSteps()==false)
	{
		return;
	}

	int eighthOfLen, sevenEightOfLen, len = theFootSteps.GetLength();
	eighthOfLen = len>>3;
	sevenEightOfLen = len - eighthOfLen;

	Scalar oneOverEighthOfLen = 1.0f/(len>>3);

	int flip = firstStep > lastStep ? 1 : 0;

	DrawShapeInformation drawShapeInfo;
	LinearMatrix4D matrix;

	matrix = LinearMatrix4D::Identity;

	RGBAColor fade;

	fade = RGBAColor::White;

	drawShapeInfo.activeLights = NULL;
	drawShapeInfo.clippingFlags = 0x3f;
	drawShapeInfo.nrOfActiveLights = 0;
	drawShapeInfo.shapeToWorld = &matrix;
	drawShapeInfo.worldToShape = &matrix;

	int index = firstStep;
	int numberOfActiveSteps = lastStep-firstStep+len*flip;
	Scalar fadeFactor0, fadeFactor1;

	UnitVector3D forward;
	eye.GetLocalForwardInWorld(&forward);

	Point3D eyeLocation;
	eyeLocation = eye;

	Vector3D stepToEye;

	for(int i=0;i<numberOfActiveSteps;i++,index++)
	{
		if(index==len)
		{
			index = 0;
		}

		stepToEye.Subtract(theFootSteps[index].location, eyeLocation);

		fadeFactor0	= stepToEye*forward;

		if(fadeFactor0<0.0f || fadeFactor0>fadeOutEnd)
		{
			continue;
		}
		if(fadeFactor0 > fadeOutStart)
		{
			fadeFactor0 = 1.0f - oneOverFadeOut*(fadeFactor0-fadeOutStart);
		}
		else
		{
			fadeFactor0 = 1.0f;
		}

		int howFar = sevenEightOfLen-numberOfActiveSteps+i;
		if(howFar > 0)
		{
			fadeFactor1 = 1.0f;
		}
		else
		{
			fadeFactor1 = 1.0f + oneOverEighthOfLen*howFar;
		}

		fade.alpha = fadeFactor0<fadeFactor1 ? fadeFactor0 : fadeFactor1;

		drawShapeInfo.paintMeColor = &fade;
		drawShapeInfo.shape = theFootSteps[index].shape;
		theClipper->DrawShape(&drawShapeInfo);
	}
}
