#if !defined(MLR_TERRAIN_HEIGHTFIELD_HPP)
	#define MLR_TERRAIN_HEIGHTFIELD_HPP

	#include <MLR\MLR_I_DeT_PMesh.hpp>
//	#include <Proxies\ProxyHeaders.hpp>

	#include "terra\terra.hpp"

	class CFinalBitmapWnd;
	class CProgressDlg;

	extern CFinalBitmapWnd *Wnd2D;

	struct ToDrawTriangle
	{
		Point3D v[3];

		Point3D center;
		Scalar	area;

		void	SetPoint(int idx,float x,float y,float z);
		void	GetSurfaceAreaAndCentroid();

		Point3D	&GetV0() { return v[0]; }
		Point3D	&GetV1() { return v[1]; }
		Point3D	&GetV2() { return v[2]; }
	};
	
	struct HeightFieldFileHeader {
		int signature;
		int version;
		unsigned int totalSizeOfFile;
		Scalar minX, maxX;
		Scalar minZ, maxZ;
		long vertexCountX;
		long vertexCountZ;
	};

	class MLRHeightField {
	public:
		MLRHeightField();

		~MLRHeightField();
		
		void
      			TestInstance() const
					{}
		
		int GetFullPolyCount() {return (X-1)*(Z-1)*2; }
		int GetOptPolyCount() {return OptPolyCount; }


		ElementRenderer::GroupElement*
			GetGroup()
					{ return terrainGroup; }
		
		Scalar
			GetXinM()
					{ return (X-1) * dX; }
		
		Scalar
			GetZinM()
					{ return (Z-1) * dZ; }
		
		int
			GetX()
					{ return X; }
		
		int
			GetZ()
					{ return Z; }
		
		Stuff::Scalar
			GetXScale()
					{ return dX; }
		
		Stuff::Scalar
			GetZScale()
					{ return dZ; }
		
		Stuff::Scalar
			GetYScale()
					{ return dY; }
	
		Scalar
			GetHeight(int, int);
		
		Scalar
			GetHeight(Scalar, Scalar);

		Stuff::ExtentBox
			GetExtents();
			
		bool
			SaveHeightFieldInformations(MString& file_name);

		int
			GetNrOfIZs()
				{ return nrOfIZs; };

		void
			SetOffset(Stuff::Scalar offset)
				{ Offset = offset; };

		void
			SetDetailTextureInfo(
				const char *name,
				Scalar xOff, Scalar zOff,
				Scalar xFac, Scalar zFac,
				MidLevelRenderer::MLRState::AlphaMode alphaMode
			) 
			{
				detailInfo.name = name;
				detailInfo.xOff = xOff;
				detailInfo.zOff = zOff;
				detailInfo.xFac = xFac;
				detailInfo.zFac = zFac;
				detailInfo.alphaMode = alphaMode;
			}

		bool
			SetMegaTexture(
				int nrOfLevels,
				const char *mega_base_name
			);

		void
			OptimizeHField(int mode=0, int depth=0, int binSize=64);
		
		Stuff::Scalar 
			GetOffset()
				{ return Offset; };

		bool
			IsFullDisplayed()
		{
			return 	(terrainGroup->FindElement(fullTerrainGroup->GetName())!=NULL);
		} 

		bool
			IsOptDisplayed() 
		{
			return 	(terrainGroup->FindElement(simpleTerrainGroup->GetName())!=NULL);
		} 
		
		void
			DisplayFull(bool bl);
		void
			DisplayOpt(bool bl); 

		ElementRenderer::GroupElement *
			GetFullTerrain() { Check_Pointer(this); return fullTerrainGroup; }
		ElementRenderer::ListElement *
			GetOptTerrain() { Check_Pointer(this); return simpleTerrainGroup; }

	protected:
		void
			MakeTerrainFromField();

		void
			Blur2D();

		bool
			CreateMesh(
				ListElement *parent,
				int index,
				DynamicArrayOf<ToDrawTriangle*>& tdtrilist,
				Stuff::ExtentBox*,
				MidLevelRenderer::MLRState *state = NULL
			);

		bool
			BinSort(
				ListElement *parent,
				int index,
				DynamicArrayOf<ToDrawTriangle*>& tdtrilist,
				int binSize,
				CProgressDlg *pdlg,
				Stuff::ExtentBox*,
				MidLevelRenderer::MLRState *state = NULL
			);

		void
			MLRHeightField::DescentToUnderMountain(
				int depth,
				ElementRenderer::ListElement *group,
				Point3D *points,
				unsigned char *onOffPoints,
				int numOfTriangles,
				int maxNumOfTrianglesPerMesh,
				Scalar x0,
				Scalar z0,
				Scalar x1,
				Scalar z1,
				int tileX,
				int tileZ,
				const char *texRoot
			);

		// X, Z number of points, the length of the terrain would be (X-1)*dX
		int X, Z, visHeight;
		Stuff::Scalar dX, dY, dZ;
		int OptPolyCount;
		Stuff::DynamicArrayOf<float> field;
		
		int side, meshX, meshZ;
		ElementRenderer::GroupElement *terrainGroup;
		ElementRenderer::GroupElement *fullTerrainGroup;
		ElementRenderer::ListElement *simpleTerrainGroup;
		Stuff::DynamicArrayOf<MidLevelRenderer::MLRShape*> terrain;
		
		MidLevelRenderer::MLRState state0, state1;

		MidLevelRenderer::DetailTextureInfo detailInfo;

		int
			nrOfIZs;

	private:
		Stuff::Scalar Offset;
	};
#endif
