/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///
///		FICHIER :	ZooWorld.h
///
///		NATURE	:	Defines the world of the scene, the contain of a 3D scene for displaying 
///					It manages all the Object of the scene and the hierarchy of the scene
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


#ifndef __ZOOWORLD_H__
#define __ZOOWORLD_H__


#include	"..\Basic\ZooStd.h"

#include	"..\Scene Graph\ZooObject.h"
#include	"..\Scene Graph\ZooLight.h"
#include	"..\Scene Graph\ZooCamera.h"
#include	"..\Scene Graph\ZooShell.h"
#include	"..\Scene Graph\ZooColl.h"
#include	"..\Scene Graph\ZooSprite.h"
#include	"..\Scene Graph\ZooAnim.h"
#include	"..\Scene Graph\ZooParticle.h"
#include	"..\Scene Graph\ZooSound.h"
#include	"..\Scene Graph\ZooBone.h"
#include	"..\Scene Graph\ZooSkelet.h"

#include	"..\Basic\ZooScene.h"


float GetTimePassed(DWORD *lastTime);



//$BLG
///////////////////////////////////////////////////////////////////////////////
// ZBLG_ObjSpr Class
/////////////////////////////////////////////////////////////////////////////// 
class ZBLG_ObjSpr : public ZNodeGraph
{
  public:
	ZObject*  blg_objspr_obj;
	ZSprite*  blg_objspr_spr;

	// Constructor& Destructor
	ZBLG_ObjSpr(int s3d);
	~ZBLG_ObjSpr();
};


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// ZFaceProj Class
///
///		- Classe des faces transparentes
///		- stockage en liste chainée pour le tri en Z
///		- champs nécessaire pour l'affichage : données sur la face, et sur les vertices correspondants
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct ZFaceProj
{
	ZFace		*face;							// face correspondant à ce polygone

	ZVector3	vert3D[3];						// coordonnées des 3 vertices, déjà transformées (tirées de VertTransf dans ZObject)
	float		Zproj[3];						// coordonnées Z des trois vertices projetés à l'écran
	
	ZVector3	*colorVerts[3];					// couleurs des vertices

	ZVector3	normales[3];					// normales aux vertices
	ZVector3	normFace;

	float		Zmin;

	int			type;							// 0 = objet	;	1 = particule	;	2 = sprite

	ZVector4	pclColor;

	ZSprite		*sprite;
};


struct ZVertSOFT
{
	float		posX;
	int			posY;
	float		posZ;

	float		u, v;

	float		light;
};


struct ZFaceSOFT
{
	ZFaceSOFT	*next;
	ZFaceSOFT	*prev;

	ZVertSOFT	vert[4];
	
	ZFace		*face;							// face correspondant à ce polygone

	int			Npoints;

	int			ymin, ymax;

	short		pointG, pointD;


	float		xg, zg, dxg, dzg;
	float		xd, zd, dxd, dzd;

	float		ug, vg, dug, dvg;
	float		ud, vd, dud, dvd;

	float		lgtg, dlgtg;
	float		lgtd, dlgtd;


	bool		active;


	//$LB
	int         color24;
	bool		transp;
	//$LB
	unsigned char* table24;

	//$LB
	OBJBITMAP_BUFFER bitmap24;
	int			width;
	int			height;

	void		*render;
};


#include	"ZooSoft.h"


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// ZWorld Class
///
///		- Classe du World
///		- listes globales et linéaires des objets, lights et cameras (parcours rapide)
///		- liste des polygones transparents du monde
///		- methodes de creation de liste et de gestion globale du monde
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

class ZWorld : public ZNode
{

protected:

	///////////////////////////////////////////////////////////////////////////
	/// createNodeListsRecurs()												///
	///////////////////////////////////////////////////////////////////////////
	void createNodeListsRecurs(ZNode *node);


public:

	ZArray<ZObject*>	objList;
	ZArray<ZLight*>		lghList;
	ZArray<ZCamera*>	camList;
	ZArray<ZShell*>		shlList;
	ZArray<ZEmitter*>	pclList;
	ZArray<ZSound*>		sndList;
	ZArray<ZSprite*>	sprList;
	ZArray<ZBone*>		boneList;
	ZArray<ZSkelet*>	sklList;
	ZArray<ZAnim*>		aniList;


	vector<int>			tempQuickSort;

	vector<ZFaceProj>	transpList;
	vector<ZFaceProj*>	transpListSorted;

	vector<ZFaceSOFT>	SOFTList;
	vector<ZFaceSOFT*>	SOFTListSorted;
	ZFaceSOFT			*base;

	ZVector3 			defaultLightDir;		// spécifique au mode SOFT

	ZScene				*scene3D;

	///////////////////////////////////////////////////////////////////////////
	/// Constructor	& Destructor											///
	///////////////////////////////////////////////////////////////////////////
	ZWorld(ZScene *scene);
	~ZWorld();


	///////////////////////////////////////////////////////////////////////////
	/// Free the entire world												///
	///////////////////////////////////////////////////////////////////////////
	void FreeWorld();


	///////////////////////////////////////////////////////////////////////////
	/// createNodeLists()													///
	///////////////////////////////////////////////////////////////////////////
	void createNodeLists(ZNode* baseNode);


  //$BLG
  //Added in v4.6a2
  //Removed in v4.6a3: Brought more problems than solutions, especially with ColorLights.
  ///////////////////////////////////////////////////////////////////////////
  // BLG_GetAmbientLight()
  ///////////////////////////////////////////////////////////////////////////
  //float BLG_GetAmbientLight();


	///////////////////////////////////////////////////////////////////////////
	/// PutLightSettings()													///
	///////////////////////////////////////////////////////////////////////////
	void PutLightSettings(const ZMatrix &matCam);


	///////////////////////////////////////////////////////////////////////////
	/// UpdateSounds()														///
	///////////////////////////////////////////////////////////////////////////
	void UpdateSounds(ZSound *listener);


	void ViewFrustrumCull(ZCamera *curCam, float tailleX, float tailleY, bool ortho);


	///////////////////////////////////////////////////////////////////////////
	/// RenderObjectPass1 & RenderObjectPass2								///
	///////////////////////////////////////////////////////////////////////////
	void RenderObjectPass1();
	void RenderObjectPass2();
	void RenderObjectPass3();
	void RenderObjectPass4();
	void RenderObjectPassLightMap();
	
	void RenderObjectPassTransp(ZCamera *curCam);

	void RenderParticles(const ZVector3 &RealAngleCam, const ZMatrix &RealMatCam, const ZMatrix &matCam);
	void RenderAdditiveParticles(const ZVector3 &RealAngleCam, const ZMatrix &matCam);
	void RenderSpritesPASS1(float camRotationZ);
	void RenderSpritesPASS2(float camRotationZ);
	void RenderSpritesPASS3(float camRotationZ);


	///////////////////////////////////////////////////////////////////////////
	/// RenderObjectWire													///
	///////////////////////////////////////////////////////////////////////////
	void RenderObjectWired(float lineWidth);


	///////////////////////////////////////////////////////////////////////////
	/// ShaderObjectPass													///
	///////////////////////////////////////////////////////////////////////////
	void ShaderObjectPass();

	///////////////////////////////////////////////////////////////////////////
	/// ComputeMatrices()													///
	///////////////////////////////////////////////////////////////////////////
	void RecursComputeMatrices(ZNodeGraph* activeCam, ZNodeGraph*  baseNode, const ZMatrix &refMat, float refScale, bool rangeOK);
	void ComputeMatrices(ZNodeGraph* activeCam, ZNodeGraph*  baseNode, const ZMatrix &refMat, float refScale, bool rangeOK);


	///////////////////////////////////////////////////////////////////////////
	/// TransformVertices()													///
	///////////////////////////////////////////////////////////////////////////
	void TransformVertices();
	void ComputeNormals(bool accel);


	///////////////////////////////////////////////////////////////////////////
	/// SelectionTest()														///
	///////////////////////////////////////////////////////////////////////////
	//$BLG
	//void SelectionTest(ZMatrix &camMat, const ZVector3 &orig, const ZVector3 &ray, float* dist, float distMin, float* u, float* v, float* z, ZObject**	result, int* faceNb);
	void SelectionTest(ZMatrix &camMat, const ZVector3 &orig, const ZVector3 &ray, float* dist, float distMin, float* u, float* v, float* z, ZBLG_ObjSpr*	result, int* faceNb, float blg_ActiveCamRotZ);


	void SelectFaces(ZCamera *curCam, bool wired, bool ortho);
	
	void RenderSOFT(ZCamera *cam, RenderBuffer *buffer, int fond24, bool clear);
	void RenderSOFT_Wired(ZCamera *cam, RenderBuffer *buffer, int fond24, bool clear);

	void RenderlineSOFT(RenderBuffer *rendBuf, ZCamera *cam, int yscan, int traceHeight);
	void ComputeLightTarget(const ZMatrix &matCam);
	float Calclight(ZVector3 *pos, ZVector3 *norm);

	void UpdateFace(ZFaceSOFT *face, int ytab);

	//	void DetectCollision();
};


///////////////////////////////////////////////////////////////////////////////////////////////
///		RenderObjectPass1																	///
///////////////////////////////////////////////////////////////////////////////////////////////
inline void ZWorld::RenderObjectPass1()
{
	ZObject	*curObj;

	for(int i=0; i<objList.Size(); i++)
	{
		curObj = objList[i];

		if(curObj->visible && curObj->isAvatar == false)
		{
			curObj->RenderPass1();							// and finally render the object
		}
	}
}


///////////////////////////////////////////////////////////////////////////////////////////////
///		RenderObjectPass2																	///
///////////////////////////////////////////////////////////////////////////////////////////////
inline void ZWorld::RenderObjectPass2()
{
	ZObject	*curObj;
	
	for(int i=0; i<objList.Size(); i++)
	{
		curObj = objList[i];
		
		if(curObj->visible && curObj->isAvatar == false)
		{
			curObj->RenderPass2();							// and finally render the object
		}
	}
}


///////////////////////////////////////////////////////////////////////////////////////////////
///		RenderObjectPassLightMap																	///
///////////////////////////////////////////////////////////////////////////////////////////////
inline void ZWorld::RenderObjectPassLightMap()
{
	ZObject	*curObj;
	
	for(int i=0; i<objList.Size(); i++)
	{
		curObj = objList[i];
		
		if(curObj->visible && curObj->isAvatar == false)
		{
			curObj->RenderPassLightMap();							// and finally render the object
		}
	}
}

///////////////////////////////////////////////////////////////////////////////////////////////
///		RenderObjectPass3																	///
///////////////////////////////////////////////////////////////////////////////////////////////
inline void ZWorld::RenderObjectPass3()
{
	ZObject	*curObj;
	
	for(int i=0; i<objList.Size(); i++)
	{
		curObj = objList[i];
		
		if(curObj->visible && curObj->isAvatar == false)
		{
			curObj->RenderPass3();							// and finally render the object
		}
	}
}


///////////////////////////////////////////////////////////////////////////////////////////////
///		RenderObjectPass3																	///
///////////////////////////////////////////////////////////////////////////////////////////////
inline void ZWorld::RenderObjectPass4()
{
	ZObject	*curObj;
	
	for(int i=0; i<objList.Size(); i++)
	{
		curObj = objList[i];
		
		if(curObj->visible && curObj->isAvatar == false)
		{
			curObj->RenderPass4();							// and finally render the object
		}
	}
}


///////////////////////////////////////////////////////////////////////////////////////////////
///		RenderParticles																		///
///////////////////////////////////////////////////////////////////////////////////////////////
inline void ZWorld::RenderParticles(const ZVector3 &RealAngleCam, const ZMatrix &RealMatCam, const ZMatrix &matCam)
{
	ZEmitter	*curPcl;


	for(int i=0; i<pclList.Size(); i++)
	{
		curPcl	= pclList[i];
		curPcl->NextStep();

		if(curPcl->rangeOK)
			curPcl->Render(RealAngleCam, matCam);
	}
}


///////////////////////////////////////////////////////////////////////////////////////////////
///		RenderAdditiveParticles																///
///////////////////////////////////////////////////////////////////////////////////////////////
inline void ZWorld::RenderAdditiveParticles(const ZVector3 &RealAngleCam, const ZMatrix &matCam)
{
	ZEmitter	*curPcl;


	for(int i=0; i<pclList.Size(); i++)
	{
		curPcl	= pclList[i];

		if( curPcl->rangeOK && (curPcl->mask&PCL_ADDITIVE) )
			curPcl->RenderAdditive(RealAngleCam, matCam);
	}
}


///////////////////////////////////////////////////////////////////////////////////////////////
///		RenderObjectWired																	///
///////////////////////////////////////////////////////////////////////////////////////////////
inline void ZWorld::RenderObjectWired(float lineWidth)
{
	ZObject	*curObj;
	
	glLoadIdentity();

	for(int i=0; i<objList.Size(); i++)
	{
		curObj = objList[i];
		
		if(curObj->visible)
		{
			curObj->RenderWired(lineWidth);					// and finally render the object
		}
	}
}

///////////////////////////////////////////////////////////////////////////////////////////////
///		ShaderObjectPass																	///
///////////////////////////////////////////////////////////////////////////////////////////////
/* $MS : Modification for Optimisation of Skinning pass */
inline void ZWorld::ShaderObjectPass()
{
	ZObject	*curObj;

	glLoadIdentity();

	for(int i=0; i<objList.Size(); i++)
	{
		curObj = objList[i];

		if(curObj->visible && curObj->isAvatar == true )
		{
			
			//curObj->ShaderPass();							// and finally render the object
			// $MS : Place it outside the render loop to optimise
			curObj->GetMesh()->cgTexture    = cgGetNamedParameter(curObj->GetMesh()->cgFragmentProgram, "decal");
			ZMatrix mat ;
			mat = curObj->worldMat ;
			ZMatrix avamat ;
			avamat = curObj->GetPRS()->mat ;
			cgGLSetMatrixParameterfr(curObj->GetMesh()->ModelViewProj,mat.matxArray);
			mat.Inverse() ;
			cgGLSetMatrixParameterfr(curObj->GetMesh()->ModelViewInverseProj,mat.matxArray);
			cgGLSetMatrixParameterfr(curObj->GetMesh()->AvaViewProj,avamat.matxArray);
			cgGLSetStateMatrixParameter(curObj->GetMesh()->WorldViewProj, CG_GL_MODELVIEW_PROJECTION_MATRIX, CG_GL_MATRIX_IDENTITY);

			cgGLSetManageTextureParameters(curObj->GetMesh()->cgContext, CG_TRUE) ;
		   // On lance l'activation du programme Cg!
			cgGLEnableProfile(curObj->GetMesh()->cgVertexProfile);					// Enable Our Vertex Shader Profile
			// Bind Our Vertex Program To The Current State
			cgGLBindProgram(curObj->GetMesh()->cgVertexProgram);
		   // On lance l'activation du programme Cg!
			cgGLEnableProfile(curObj->GetMesh()->cgFragmentProfile);					// Enable Our Vertex Shader Profile
			// Bind Our Vertex Program To The Current State
			cgGLBindProgram(curObj->GetMesh()->cgFragmentProgram);
			curObj->GetMesh()->CallDisplayListSkinning() ;

			cgGLDisableProfile(curObj->GetMesh()->cgVertexProfile);
			cgGLDisableProfile(curObj->GetMesh()->cgFragmentProfile);
		}
	}
}
///////////////////////////////////////////////////////////////////////////////////////////////
///		ComputeLightTarget																	///
///////////////////////////////////////////////////////////////////////////////////////////////
inline void ZWorld::ComputeLightTarget(const ZMatrix &matCam)
{
	if(lghList.Size()==0)
	{
		defaultLightDir.SetCoord(matCam._13, matCam._23, matCam._33);
		defaultLightDir.Normalize();
	}
	else
	{
		for(int i=0; i<lghList.Size(); i++)
		{
			lghList[i]->target.SetCoord(lghList[i]->worldMat._13, lghList[i]->worldMat._23, lghList[i]->worldMat._33);
			lghList[i]->target.Normalize();
		}
	}
}


///////////////////////////////////////////////////////////////////////////
///		UpdateSounds													///
///////////////////////////////////////////////////////////////////////////
inline void ZWorld::UpdateSounds(ZSound *pZSound)
{
	if( !pZSound ) return ;

	ZSound	*curSound;

	for(int i=0; i<sndList.Size(); i++)
	{
		curSound = sndList[i];
		curSound->update( pZSound );
	}
}


bool TestObject(ZMatrix &camMat, ZObject* curObj, const ZVector3 &orig, const ZVector3 &ray, float* dist, float distMin, float* u, float* v, float* z, int* faceNb);
//$BLG
bool BLG_TestSprObject(ZSprite* curObj, const ZVector3 &orig, const ZVector3 &ray, float* dist, float distMin, float blg_ActiveCamRotZ);


#endif











