#if !defined(HFSLIMMZL_HPP)
	#define HFSLIMMZL_HPP

	#include <ElementRenderer\ElementRendererheaders.hpp>

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

	extern bool doWater;
	extern Scalar waterLevel;
	extern bool doBSP;

	struct DetailLevelInfo {
		unsigned short width, height;
		unsigned char *array;
	};

	struct TriangleStruct;

	struct TrianglePointAngleStruct {
		TriangleStruct *tri;
		float angle;
		int pos;
	};

	struct PointStruct {
		PointStruct() : myTri(12) { p = Point3D::Identity; connectedTo = 0; }
		Point3D p;

		int connectedTo;
		DynamicArrayOf<TrianglePointAngleStruct> myTri;

		void Add (TriangleStruct *ts, int pos);

		void CalculateAngles();

		bool
			CheckAngles(float, float);

		void
   			TestInstance() const;
	};

	struct TriangleStruct {
		static PointStruct *points;

		int v[3];

		Point3D center;
		Scalar	area;
		Plane plane;

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

		void	GetSurfaceAreaAndCentroid();
	//	bool	IntersectTriangle(TriangleStruct*);

		Point3D	&GetPoint(int i) { Verify(points!=NULL); return points[v[i]].p; }
	};


	class HFSlimMZL {
	public:
		HFSlimMZL();

		~HFSlimMZL();

		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);
		typedef Stuff::Scalar frameArray[8][4];

		bool
			CreateMesh(
				ListElement *parent,
				int index,
				int levDiff,
				DynamicArrayOf<TriangleStruct*>& tdtrilist,
				frameArray *frame,
				MidLevelRenderer::MLRState *state = NULL
			);
		bool
			BinSort(
				ListElement *parent,
				int index,
				int levDiff,
				DynamicArrayOf<TriangleStruct*>& tdtrilist,
				int binSize,
				frameArray *frame,
				MidLevelRenderer::MLRState *state = NULL
			);

		void
			BuildTile(
				DynamicArrayOf<TriangleStruct*>& tempTrianglesPtr,
				int index,
				int depth, int maxdepth,
				int numOfTriangles,
				DynamicArrayOf<unsigned char>& onOffPoints,
				int maxNumOfTrianglesPerMesh,
				Scalar xOffset,
				Scalar zOffset,
				Scalar xGrid,
				Scalar zGrid,
				int tileX,
				int tileZ
			);

		void
			CreateTile(
				ElementRenderer::ListElement *list,
				DynamicArrayOf<TriangleStruct*>& tempTrianglesPtr,
				int index,
				int depth, int maxdepth,
				int maxNumOfTrianglesPerMesh,
				Scalar xOffset,
				Scalar zOffset,
				Scalar xGrid,
				Scalar zGrid,
				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;

		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
