/****************************************************************************************************

		SimpleTerrainFilter.cpp
		Copyright: (c) 2001 Eovia Corp. All rights reserved.

		Author:	Lionel
		Date:	10/5/2004

****************************************************************************************************/

#include "SimpleTerrainFilter.h"

const MCGUID TSimpleTerrainFilter::sClassId ( R_CLSID_SimpleTerrainFilter );


void Extension3DInit(IMCUnknown* utilities)
{
	// Perform your dll initialization here
}

void Extension3DCleanup()
{
	// Perform any nec clean-up here
}

TBasicUnknown* MakeCOMObject(const MCCLSID& classId)	// This method instanciate
{														// the object TSimpleTerrainFilter
	TBasicUnknown* res = NULL;

	if (classId == TSimpleTerrainFilter::sClassId) res = new TSimpleTerrainFilter;

	return res;
}



TSimpleTerrainFilter::TParameterMap::TParameterMap()
{
	fRadius	= 0.5f;
}


TSimpleTerrainFilter::TSimpleTerrainFilter()
{
}

TSimpleTerrainFilter::~TSimpleTerrainFilter()
{
}


MCCOMErr TSimpleTerrainFilter::QueryInterface(const MCIID &riid, void** ppvObj)
{
	if (MCIsEqualIID(riid, TSimpleTerrainFilter::sClassId))
	{
		TMCCountedGetHelper<TSimpleTerrainFilter> result(ppvObj);
		result = this;
		return MC_S_OK;
	}
	return TBasicTerrainFilter::QueryInterface(riid, ppvObj);
}

void* TSimpleTerrainFilter::GetExtensionDataBuffer()
{
	return &fParameterMap;
}

// ****************************************************************************
//								GetValue
// -Description:
//
//		Computes a coefficient factor for the height of a height field point
//
// -Parameters:
//
//		x, y:	coords between 0 and 1 of the height field point
//
// -Returns:
//		
//		the coefficient value that will be applied to modify the height.
//		in this simple case, we compute a conical crater.
//
real TSimpleTerrainFilter::GetValue(real x, real y)
{
	MCAssert(x >= 0 && x <= 1);
	MCAssert(y >= 0 && y <= 1);

	real value	= 1.0f;
	real radius = sqrt((x - 0.5)*(x - 0.5) + (y - 0.5)*(y - 0.5));
	real Rmax	= fParameterMap.fRadius / 2;

	if ((radius < Rmax) && (Rmax > 0.0f))
	{
		// the point (x,y) belongs to the disk centered at (0.5, 0.5) and whose radius is Rmax
		value = radius / Rmax;
	}

	return value;

}

// ****************************************************************************
//								Filter
// -Description:
//
//		Filter the height field
//
// -Parameters:
//
//		heightField:	array of real
//		heightBound:	height min and max of the terrain (must be updated
//						by this function if the height bounds changed)
//		size:			size of the array
//		cellSize:		size of a cell of the grid
//
void TSimpleTerrainFilter::Filter(TMCArray<real>& heightField, TVector2& heightBound,
							 const TIndex2& size, const TVector2& cellSize)
{	
	real maxHeight = -1e30f;
	real minHeight = 1e30f;

	int32 index = 0;

	MCAssert(size.x > 1 && size.y > 1);

	for (real y=0; y<size.y; y++)
	{
		for (real x=0; x<size.x; x++)
		{
			real height = heightField[index];
			height *= GetValue(x / size.x, y / size.y);

			if (height > maxHeight) maxHeight = height;
			if (height < minHeight) minHeight = height;

			heightField[index++] = height;
		}
	}

	heightBound[0] = minHeight;
	heightBound[1] = maxHeight;
}
