#if !defined(HFSLIMMZ0P3_HPP)
	#define HFSLIMMZ0P3_HPP

	#include "ImageLib\image.h"
	#include "terra\terra.hpp"

	struct ToDrawTriangle
	{
		Point3D v[3];

		Point3D center;
		Scalar	area;
		Plane plane;

		ToDrawTriangle():
			plane(
				Normal3D::Down,
				0.0f
			)
				{}

		void	SetPoint(int idx,float x,float y,float z);
		void	GetSurfaceAreaAndCentroid();
		bool	IntersectTriangle(ToDrawTriangle*);

		Point3D	&GetV0() { return v[0]; }
		Point3D	&GetV1() { return v[1]; }
		Point3D	&GetV2() { return v[2]; }
	};
	
	class HFSlimMZ0p3 {
	public:
		HFSlimMZ0p3();

		~HFSlimMZ0p3();

		void
			FillFromImage(Image &image, int smooth=3);	

		void
   			TestInstance() const
				{}
	
		void
			SetScale (Stuff::Scalar xs, Stuff::Scalar ys, Stuff::Scalar zs)
				{ Check_Object(this); dX = xs; dY = ys; dZ = zs; }

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

		void 
			SetBorderPixels(int bp)
				{ borderPixelFun = bp/256.0f; }

		int GetOptPolyCount() {return OptPolyCount; }

		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
			GetX(int x)
				{ return x*dX; }
		
		Scalar
			GetZ(int z)
					{ return z*dZ; }

		Scalar
			GetX(Scalar x)
				{ return x; }
		
		Scalar
			GetZ(Scalar z)
					{ return z; }

		Scalar
			GetHeight(int, int);
		
		Stuff::ExtentBox
			GetExtents();

		void
			GetZoneDimensions(int *xd, int *zd)
				{ *xd = xDim; *zd = zDim; }

		Stuff::DynamicArrayOf<ElementRenderer::GridElement*>*
			GetTerrainArray()
				{ return &simpleTerrainGroup; }

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

		bool
			SetMegaTexture(
				int nrOfLevels,
				int bucketSize,
				const char *megaBaseName
			);

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

		void
			SetAllDepth(int d)
				{ maxAllDepth = d; }

		void
			SetOffset(Stuff::Scalar xo, Stuff::Scalar zo)
				{ Check_Object(this); xOffset = xo; zOffset = zo; }

	protected:
		void
			Blur2D(int);

		bool
			CreateMesh(
				MLR_Terrain2*,
				DynamicArrayOf<ToDrawTriangle*>& tdtrilist,
				Stuff::ExtentBox*
			);

		bool
			BuildTile(
				MLR_Terrain2*,
				DynamicArrayOf<unsigned char>& onOffPoints,
				int maxNumOfTrianglesPerMesh,
				Scalar xMin,
				Scalar zMin,
				Scalar xMax,
				Scalar zMax
			);

		DynamicArrayOf<ToDrawTriangle*> toSortTriangles;
		DynamicArrayOf<ToDrawTriangle>  tdtrilist;

		// 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;

		Stuff::DynamicArrayOf<ElementRenderer::GridElement*> simpleTerrainGroup;

		Stuff::DynamicArrayOf<MidLevelRenderer::MLRShape*> terrain;
		
		MidLevelRenderer::MLRState state0, state1;

		MidLevelRenderer::DetailTextureInfo detailInfo;

		Scalar borderPixelFun;
		unsigned char maxAllDepth;
		Stuff::Scalar xOffset, zOffset;

		int
			xDim, zDim;

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