#pragma once

#include "dllinterface.h"
#include "..\Utilities\list.h"
#include <d3dx9.h>
#include "bound.h"

class Camera;

//a node can have 3 states of visibility
enum DXFUNCTIONS_API QT_VISIBLETYPE {QTVT_NONE=0,QTVT_FULL,QTVT_PARTLY};

struct DXFUNCTIONS_API QuadtreeNode
{
	WORD x,y;
	WORD size;
	WORD level;
	AABB box;
	DXVector3 points[8];
	QT_VISIBLETYPE visible; //says if block is visible
	QuadtreeNode* childs[4]; //the childs of this block

	void SetPoints(DXVector3 minv,DXVector3 maxv)
	{
		box.SetVolume(minv, maxv);
		//fill points
		points[0]= DXVector3(minv.x,minv.y,minv.z);
		points[1]= DXVector3(minv.x,minv.y,maxv.z);
		points[2]= DXVector3(minv.x,maxv.y,minv.z);
		points[3]= DXVector3(minv.x,maxv.y,maxv.z);
		points[4]= DXVector3(maxv.x,minv.y,minv.z);
		points[5]= DXVector3(maxv.x,minv.y,maxv.z);
		points[6]= DXVector3(maxv.x,maxv.y,minv.z);
		points[7]= DXVector3(maxv.x,maxv.y,maxv.z);
	}
};

class DXFUNCTIONS_API Quadtree
{
	DWORD m_yl,m_xl; //size of the field
	DWORD m_Levels; //number of levels
	DWORD m_Quadsize;//size of the top quad (power of 2)
	QuadtreeNode *m_Root; //the root node

	QuadtreeNode **m_Leaves;
	//0 = left, 1 = right, 2 = top, 3 = bottom
	DXVector3 m_CullNormals[6];
	DXVector3 m_FrustumPoints[8];
	DXVector3 m_CamPos;
	float		m_FarPlane;

	ViewFrustum		m_Frustum;

	void InitChild(DWORD ind,QuadtreeNode*parent);
	void CheckNode(QuadtreeNode* const node);
	inline bool PointVisible(const DXVector3 &p,const int i) const
	{
		DXVector3 cp;

		if(i<5)
			cp = p - m_CamPos;
		else  
			cp = p - m_CamPos + m_CullNormals[5] * m_FarPlane;

		if(D3DXVec3Dot((D3DXVECTOR3*)(m_CullNormals+i), cp) < 0.f)
			return false;
		else
			return true;
	}

	void SumChildNodes(QuadtreeNode* const node);

public:
	//constructor creates a quadtree with this size
	Quadtree(DWORD xl, DWORD yl);
	//destructor deletes all nodes
	~Quadtree(void);

	//to fill the vector values
	QuadtreeNode* GetRoot(void)const{return m_Root;} 

	//returns the leaf with the specific ind
	QuadtreeNode* GetLeaf(const DWORD level,const DWORD x,const DWORD y);

	//some additional info about the quadtree
	DWORD GetLevels(void)const{return m_Levels;}
	DWORD GetQuadsize(void)const{return m_Quadsize;}
	DWORD GetXL(void)const{return m_xl;}
	DWORD GetYL(void)const{return m_yl;}

	void UpdatePoints(void){SumChildNodes(m_Root);}

	//updates the 'bool visible' value
	void CalcVisible(const Camera& cam);
	void CalcVisible(const OBS& obs);
	void CalcVisible(const OBB& obb);

	void SetNodeVT(QuadtreeNode* const node,const QT_VISIBLETYPE vt);
};
