///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// ZObject Class
///
///		- Object Class
///		- Manage the Object properties which have  a mesh !! 
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////



#ifndef __ZOOOBJECT_H__
#define __ZOOOBJECT_H__


#include	"..\Basic\ZooStd.h"
#include	"..\Scene Graph\ZooNodeGraph.h"
#include	"..\Datas\ZooMesh.h"
#include	"..\Scene Graph\ZooCamera.h"


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// ZObject Class
///
///		- Classe des objets
///		- Setting de la PRS et du mesh (referencés)
///		- Bounding box (rectangulaire)
///		- méthodes d'affichage dans différents modes
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

class ZObject : public ZNodeGraph
{
protected:

	// Current mesh
	ZMesh				*currentMesh;							// mesh of the object

	// Son Skelete


	// Single-mesh
	ZMesh				*mesh;

	// Multi-meshes
	bool				multiMeshes;
	ZArray<ZMesh*>		meshList;
	ZArray<float>		rangeSQR;								// stockage des ranges en ordre décroissant

public:

	// Transformed datas
	vector<ZVector3>	VertsTransf;						// array of transformated coordinates of the vertices
	vector<ZVector3>	FaceNormTransf;						// array of transformated coordinates of the vertices
	vector<ZVector3>	VertNormTransf;						// array of transformated coordinates of the vertices

	bool		normalsTransformed;

	// Flags
	bool		visible;									// flag de visibilite pour le test de culling avec le view frustrum

	bool		clickable;


		bool		isAvatar ;

	

	


	///////////////////////////////////////////////////////////////////////////
	/// Constructor & Destructor											///
	///////////////////////////////////////////////////////////////////////////
	ZObject(int s3d);
	~ZObject();


	bool IsMultiMeshes();
	void setFlagMulti(bool multi);

	///////////////////////////////////////////////////////////////////////////
	/// Set the MESH of the object											///
	///////////////////////////////////////////////////////////////////////////
	void SetMesh(ZMesh *newMesh);
	void AddMeshInList(ZMesh *newMesh, float range2);
	void CleanMeshList();

	int	 GetNumberMeshes();
	void ChooseGoodMesh(float range2);

	///////////////////////////////////////////////////////////////////////////
	/// Get the MESH of the object											///
	///////////////////////////////////////////////////////////////////////////
	ZMesh*				GetMesh();					// get the current mesh
	ZArray<ZMesh*>*		GetMeshList();				// get the meshes list
	ZArray<float>*		GetRangeSQRList();



	///////////////////////////////////////////////////////////////////////////////////////
	///			RENDERING FUNCTION - DYSPLAY LISTS										///
	///////////////////////////////////////////////////////////////////////////////////////

	///////////////////////////////////////////////////////////////////////////
	/// Creation of the displays lists for each PASS						///
	///////////////////////////////////////////////////////////////////////////


	void RenderBOX(const ZVector3 &color, float lineWidth);


	///////////////////////////////////////////////////////////////////////////////////////
	///			RENDERING FUNCTION - DIRECT RENDERING									///
	///////////////////////////////////////////////////////////////////////////////////////

	///////////////////////////////////////////////////////////////////////////
	/// Direct rendering for non-static object (CLASSIC mode)				///
	///////////////////////////////////////////////////////////////////////////
	void RenderPass1Classic();
	void RenderPass2Classic();
	void RenderPassLightMapClassic();
	void RenderPass3Classic();
	void RenderPass4Classic();

	void RenderWired(float lineWidth);
	void ShaderPass() ;


	///////////////////////////////////////////////////////////////////////////////////////
	///			GLOBAL FUNCTIONS OF RENDERING											///
	///////////////////////////////////////////////////////////////////////////////////////

	///////////////////////////////////////////////////////////////////////////
	/// Global function for rendering										///
	///////////////////////////////////////////////////////////////////////////
	void RenderPass1();
	void RenderPass2();
	void RenderPassLightMap();
	void RenderPass3();
	void RenderPass4();

	void RenderAsParticle(const ZMatrix &matx);


	///////////////////////////////////////////////////////////////////////////////////////
	///			FUNCTIONS FOR OBJECT MODIFICATION										///
	///////////////////////////////////////////////////////////////////////////////////////

	///////////////////////////////////////////////////////////////////////////
	/// Transform the vertices with his matrix (in PRS)						///
	///////////////////////////////////////////////////////////////////////////
	void TransformAllVerts();
	void TransformNormals();
};


///////////////////////////////////////////////////////////////////////////
///		GetMesh															///
///////////////////////////////////////////////////////////////////////////
inline ZMesh* ZObject::GetMesh()
{
	return currentMesh;
}


inline ZArray<ZMesh*>*  ZObject::GetMeshList()
{
	return &meshList;
}


inline ZArray<float>*  ZObject::GetRangeSQRList()
{
	return &rangeSQR;
}


///////////////////////////////////////////////////////////////////////////
///		SetMesh															///
///////////////////////////////////////////////////////////////////////////
inline void ZObject::SetMesh(ZMesh *newMesh)
{
	if(multiMeshes==true)		return;

	if(mesh)
	{
		mesh->DecRef();
		VertsTransf.resize(0);
	}

	mesh = newMesh;
	currentMesh = mesh;

	if(mesh)
	{
		mesh->IncRef();
		VertsTransf.resize(mesh->NbVerts);
	}
}


///////////////////////////////////////////////////////////////////////////
///		SetMesh															///
///////////////////////////////////////////////////////////////////////////
inline bool ZObject::IsMultiMeshes()
{
	return multiMeshes;
}


///////////////////////////////////////////////////////////////////////////
///		setFlagMulti													///
///////////////////////////////////////////////////////////////////////////
inline void ZObject::setFlagMulti(bool multi)
{
	if(multi==multiMeshes)		return;

	if(multi==true)
	{
		SetMesh(NULL);
		multiMeshes = true;
		return;
	}

	if(multi==false)
	{
		CleanMeshList();

		multiMeshes = false;
		SetMesh(NULL);
		return;
	}
}


///////////////////////////////////////////////////////////////////////////
///		setFlagMulti													///
///////////////////////////////////////////////////////////////////////////
inline int ZObject::GetNumberMeshes()
{
	return rangeSQR.Size();
}


///////////////////////////////////////////////////////////////////////////
///		setFlagMulti													///
///////////////////////////////////////////////////////////////////////////
inline void ZObject::ChooseGoodMesh(float range2)
{
	if(multiMeshes==false)
	{
		currentMesh = mesh;
		return;
	}

	int		tabSize = rangeSQR.Size();

	for(int i=0; (i<tabSize) && (rangeSQR[i]>range2); i++);

	i--;

	if(i>=0)
	{
		if(i==tabSize)		currentMesh = meshList[tabSize-1];
		else				currentMesh = meshList[i];
	}
	else
	{
		currentMesh = NULL;
	}
}


///////////////////////////////////////////////////////////////////////////
///		RenderPass1														///
///////////////////////////////////////////////////////////////////////////
inline void ZObject::RenderPass1()
{
	
	if( (currentMesh->dependency==true) || (currentMesh->displayListCreate==false) )
	{
		glLoadIdentity();
		RenderPass1Classic();

	}
	else
	{
	
		glLoadMatrixf(worldMat.matxArray);		// load the world Matrix
		currentMesh->CallDisplayList1();

	}
	
}


///////////////////////////////////////////////////////////////////////////
///		RenderPass2														///
///////////////////////////////////////////////////////////////////////////
inline void ZObject::RenderPass2()
{
	if( (currentMesh->dependency==true) || (currentMesh->displayListCreate==false) )
	{
		glLoadIdentity();
		RenderPass2Classic();

	}
	else
	{
	
		glLoadMatrixf(worldMat.matxArray);		// load the world Matrix
		currentMesh->CallDisplayList2();

	}
}


///////////////////////////////////////////////////////////////////////////
///		RenderPassLightMap														///
///////////////////////////////////////////////////////////////////////////
inline void ZObject::RenderPassLightMap()
{
	
	
	if( (currentMesh->dependency==true) || (currentMesh->displayListCreate==false) )
	{
	
		glLoadIdentity();
		RenderPassLightMapClassic();
		
	}
	else
	{
	
	
		glLoadMatrixf(worldMat.matxArray);		// load the world Matrix
		currentMesh->CallDisplayListLightMap();	
	}
	

}

///////////////////////////////////////////////////////////////////////////
///		RenderPass3														///
///////////////////////////////////////////////////////////////////////////
inline void ZObject::RenderPass3()
{
	if( (currentMesh->dependency==true) || (currentMesh->displayListCreate==false) )
	{
		glLoadIdentity();
		RenderPass3Classic();
	}
	else
	{
		glLoadMatrixf(worldMat.matxArray);		// load the world Matrix
		currentMesh->CallDisplayList3();
	}
}


///////////////////////////////////////////////////////////////////////////
///		RenderPass4														///
///////////////////////////////////////////////////////////////////////////
inline void ZObject::RenderPass4()
{
	if( (currentMesh->dependency==true) || (currentMesh->displayListCreate==false) )
	{
		glLoadIdentity();
		RenderPass4Classic();
	}
	else
	{
		glLoadMatrixf(worldMat.matxArray);		// load the world Matrix
		currentMesh->CallDisplayList4();
	}
}


///////////////////////////////////////////////////////////////////////////
///		RenderAsParticle														///
///////////////////////////////////////////////////////////////////////////
inline void ZObject::RenderAsParticle(const ZMatrix &matx)
{
	if( (currentMesh->dependency==true) || (currentMesh->displayListCreate==false) )
	{
		// No render for the particles defined by a dynamic object
	}
	else
	{
		glLoadMatrixf(matx.matxArray);		// load the world Matrix
		currentMesh->CallDisplayList1();
	}
}


#endif