
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///
///		FICHIER :	ZooWorld.cpp
///
///		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
///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#include	"..\Basic\ZooWorld.h"
#include "../scol/colors.h"

//$BLG
///////////////////////////////////////////////////////////////////////////////
// ZBLG_ObjSpr Class
/////////////////////////////////////////////////////////////////////////////// 
ZBLG_ObjSpr::ZBLG_ObjSpr(int s3d) : ZNodeGraph(s3d)
{
	blg_objspr_obj = NULL;
	blg_objspr_spr = NULL;
}
ZBLG_ObjSpr::~ZBLG_ObjSpr()
{
	blg_objspr_obj = NULL;
	blg_objspr_spr = NULL;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// 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
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

ZWorld::ZWorld(ZScene *scene) : ZNode()				
{
	type = WLD_TYPE_ID;

	scene3D = scene;

	transpList.resize(0);
}

ZWorld::~ZWorld()
{
	FreeWorld();
}

void DeleteRecursWorld(ZNode *firstNode)
{
	ZNode	*curNode, *nodeSon, *nodeNext;

	curNode = firstNode;

	while(curNode != NULL)
	{
		nodeSon  = curNode->son;
		nodeNext = curNode->next;

		delete curNode;

		// Test of recursion
		if(nodeSon!=NULL)			DeleteRecursWorld(nodeSon);
		curNode = nodeNext;
	}
}

///////////////////////////////////////////////////////////////////////////
/// Free the entire world												///
///////////////////////////////////////////////////////////////////////////
void ZWorld::FreeWorld()
{
	transpList.resize(0);

	DeleteRecursWorld(son);
	son = NULL;

	objList.Empty();
	lghList.Empty();
	camList.Empty();
	shlList.Empty();
	sndList.Empty();
	pclList.Empty();
	sprList.Empty();
	boneList.Empty() ;
	sklList.Empty() ;
	aniList.Empty() ;
}


///////////////////////////////////////////////////////////////////////////////////////////////
/// createNodeLists()																		///
///																							///
///		This function create all lists of nodes (same type)									///
///																							///
///////////////////////////////////////////////////////////////////////////////////////////////

void ZWorld::createNodeLists(ZNode* baseNode)
{
	objList.Clear();
	lghList.Clear();
	camList.Clear();
	shlList.Clear();
	sndList.Clear();
	pclList.Clear();
	sprList.Clear();
	boneList.Clear();
	sklList.Clear() ;
	aniList.Clear() ;

		 if (baseNode->type == OBJ_TYPE_ID)			objList.Add((ZObject*)baseNode);
	else if (baseNode->type == LGH_TYPE_ID)			lghList.Add((ZLight*) baseNode);
	else if (baseNode->type == CAM_TYPE_ID)			camList.Add((ZCamera*)baseNode);
	else if (baseNode->type == SHL_TYPE_ID)			shlList.Add((ZShell*) baseNode);
	else if (baseNode->type == SND_TYPE_ID)			sndList.Add((ZSound*) baseNode);
	else if (baseNode->type == PCL_TYPE_ID)			pclList.Add((ZEmitter*)  baseNode);
	else if (baseNode->type == SPR_TYPE_ID)			sprList.Add((ZSprite*)baseNode);
	else if (baseNode->type == BON_TYPE_ID)			boneList.Add((ZBone*)baseNode) ;
//	else if (baseNode->type == SKL_TYPE_ID)			sklList.Add((ZSkelet*)baseNode) ;
	else if (baseNode->type == ANI_TYPE_ID)			aniList.Add((ZAnim*)baseNode) ;

	// creation recursive des listes
	createNodeListsRecurs(baseNode);
}



///////////////////////////////////////////////////////////////////////////////////////////////
/// createNodeListsRecurs()																	///
///																							///
///		This recursive function create lists which contain all objects of same type			///
///																							///
///////////////////////////////////////////////////////////////////////////////////////////////

void ZWorld::createNodeListsRecurs(ZNode *node)
{
	ZNode*		curNode;

	curNode = node->son;

	while(curNode != NULL)
	{
			 if (curNode->type == OBJ_TYPE_ID)			objList.Add((ZObject*)curNode);
		else if (curNode->type == LGH_TYPE_ID)			lghList.Add((ZLight*) curNode);
		else if (curNode->type == CAM_TYPE_ID)			camList.Add((ZCamera*)curNode);
		else if (curNode->type == SHL_TYPE_ID)			shlList.Add((ZShell*) curNode);
		else if (curNode->type == SND_TYPE_ID)			sndList.Add((ZSound*) curNode);
		else if (curNode->type == PCL_TYPE_ID)			pclList.Add((ZEmitter*)  curNode);
		else if (curNode->type == SPR_TYPE_ID)			sprList.Add((ZSprite*)curNode);
		else if (curNode->type == BON_TYPE_ID)			boneList.Add((ZBone*)curNode) ;
	//	else if (curNode->type == SKL_TYPE_ID)			sklList.Add((ZSkelet*)curNode) ;
		else if (curNode->type == ANI_TYPE_ID)			aniList.Add((ZAnim*)curNode) ;


		// Test of recursion
		if( curNode->son != NULL )		createNodeListsRecurs(curNode);
		curNode = curNode->next;
	}
}





int TestViewObj(const ZMatrix &objMat, float fCosineX, float fSineX, float fCosineY, float fSineY, float Znear, float Zfar,
				float xmin, float xmax, float ymin, float ymax, float zmin, float zmax)
{
	ZMatrix		matPlan;
	ZVector3	coin0, coin1, coin2, coin3, coin4, coin5, coin6, coin7;
	bool		dehors;

	coin0.SetCoord(xmin, ymin, zmin);		coin0 *= objMat;
	coin1.SetCoord(xmax, ymin, zmin);		coin1 *= objMat;
	coin2.SetCoord(xmin, ymax, zmin);		coin2 *= objMat;
	coin3.SetCoord(xmax, ymax, zmin);		coin3 *= objMat;
	coin4.SetCoord(xmin, ymin, zmax);		coin4 *= objMat;
	coin5.SetCoord(xmax, ymin, zmax);		coin5 *= objMat;
	coin6.SetCoord(xmin, ymax, zmax);		coin6 *= objMat;
	coin7.SetCoord(xmax, ymax, zmax);		coin7 *= objMat;
	
	matPlan.IdentityMatrix();

	// Methode de détermination :
	// Test sur chacun des 6 plan de la pyramide tronquée de vision.
	// Chaque test suit le mode suivant -> calcul de la matrice de rotation du plan, calcul de la matrice de résultat,
	// et enfin test sur chaque point de l'OBB par le biais du calcul d'UNE seule coordonnée du point transformé et comparaison avec le plan.
	// Si un point est dedans, *dehors=false* et on passe à la suite.
	// Si les 8 points sont dehors, on stoppe => l'objet n'est pas visible.


	// ---------- PLAN 1 ---------- GAUCHE

	matPlan._11 = +fCosineX;
	matPlan._13 = -fSineX;
	matPlan._31 = +fSineX;
	matPlan._33 = +fCosineX;

	dehors = true;

	if(			   (matPlan._11*coin0.x + matPlan._12*coin0.y + matPlan._13*coin0.z + matPlan._14) > 0.0f  )	dehors = false;
	if( dehors && ((matPlan._11*coin1.x + matPlan._12*coin1.y + matPlan._13*coin1.z + matPlan._14) > 0.0f) )	dehors = false;
	if( dehors && ((matPlan._11*coin2.x + matPlan._12*coin2.y + matPlan._13*coin2.z + matPlan._14) > 0.0f) )	dehors = false;
	if( dehors && ((matPlan._11*coin3.x + matPlan._12*coin3.y + matPlan._13*coin3.z + matPlan._14) > 0.0f) )	dehors = false;
	if( dehors && ((matPlan._11*coin4.x + matPlan._12*coin4.y + matPlan._13*coin4.z + matPlan._14) > 0.0f) )	dehors = false;
	if( dehors && ((matPlan._11*coin5.x + matPlan._12*coin5.y + matPlan._13*coin5.z + matPlan._14) > 0.0f) )	dehors = false;
	if( dehors && ((matPlan._11*coin6.x + matPlan._12*coin6.y + matPlan._13*coin6.z + matPlan._14) > 0.0f) )	dehors = false;
	if( dehors && ((matPlan._11*coin7.x + matPlan._12*coin7.y + matPlan._13*coin7.z + matPlan._14) > 0.0f) )	dehors = false;

	if(dehors)		return 0;


	// ---------- PLAN 2 ---------- DROIT

	matPlan._13 = +fSineX;
	matPlan._31 = -fSineX;

	dehors = true;

	if(			   (matPlan._11*coin0.x + matPlan._12*coin0.y + matPlan._13*coin0.z + matPlan._14) < 0.0f  )	dehors = false;
	if( dehors && ((matPlan._11*coin1.x + matPlan._12*coin1.y + matPlan._13*coin1.z + matPlan._14) < 0.0f) )	dehors = false;
	if( dehors && ((matPlan._11*coin2.x + matPlan._12*coin2.y + matPlan._13*coin2.z + matPlan._14) < 0.0f) )	dehors = false;
	if( dehors && ((matPlan._11*coin3.x + matPlan._12*coin3.y + matPlan._13*coin3.z + matPlan._14) < 0.0f) )	dehors = false;
	if( dehors && ((matPlan._11*coin4.x + matPlan._12*coin4.y + matPlan._13*coin4.z + matPlan._14) < 0.0f) )	dehors = false;
	if( dehors && ((matPlan._11*coin5.x + matPlan._12*coin5.y + matPlan._13*coin5.z + matPlan._14) < 0.0f) )	dehors = false;
	if( dehors && ((matPlan._11*coin6.x + matPlan._12*coin6.y + matPlan._13*coin6.z + matPlan._14) < 0.0f) )	dehors = false;
	if( dehors && ((matPlan._11*coin7.x + matPlan._12*coin7.y + matPlan._13*coin7.z + matPlan._14) < 0.0f) )	dehors = false;

	if(dehors)		return 0;


	// ---------- PLAN 3 ---------- BAS

	matPlan.IdentityMatrix();
	matPlan._22 = +fCosineY;
	matPlan._23 = -fSineY;
	matPlan._32 = +fSineY;
	matPlan._33 = +fCosineY;

	dehors = true;

	if(			   (matPlan._21*coin0.x + matPlan._22*coin0.y + matPlan._23*coin0.z + matPlan._24) > 0.0f  )	dehors = false;
	if( dehors && ((matPlan._21*coin1.x + matPlan._22*coin1.y + matPlan._23*coin1.z + matPlan._24) > 0.0f) )	dehors = false;
	if( dehors && ((matPlan._21*coin2.x + matPlan._22*coin2.y + matPlan._23*coin2.z + matPlan._24) > 0.0f) )	dehors = false;
	if( dehors && ((matPlan._21*coin3.x + matPlan._22*coin3.y + matPlan._23*coin3.z + matPlan._24) > 0.0f) )	dehors = false;
	if( dehors && ((matPlan._21*coin4.x + matPlan._22*coin4.y + matPlan._23*coin4.z + matPlan._24) > 0.0f) )	dehors = false;
	if( dehors && ((matPlan._21*coin5.x + matPlan._22*coin5.y + matPlan._23*coin5.z + matPlan._24) > 0.0f) )	dehors = false;
	if( dehors && ((matPlan._21*coin6.x + matPlan._22*coin6.y + matPlan._23*coin6.z + matPlan._24) > 0.0f) )	dehors = false;
	if( dehors && ((matPlan._21*coin7.x + matPlan._22*coin7.y + matPlan._23*coin7.z + matPlan._24) > 0.0f) )	dehors = false;

	if(dehors)		return 0;


	// ---------- PLAN 4 ---------- HAUT

	matPlan._23 = +fSineY;
	matPlan._32 = -fSineY;

	dehors = true;

	if(			   (matPlan._21*coin0.x + matPlan._22*coin0.y + matPlan._23*coin0.z + matPlan._24) < 0.0f  )	dehors = false;
	if( dehors && ((matPlan._21*coin1.x + matPlan._22*coin1.y + matPlan._23*coin1.z + matPlan._24) < 0.0f) )	dehors = false;
	if( dehors && ((matPlan._21*coin2.x + matPlan._22*coin2.y + matPlan._23*coin2.z + matPlan._24) < 0.0f) )	dehors = false;
	if( dehors && ((matPlan._21*coin3.x + matPlan._22*coin3.y + matPlan._23*coin3.z + matPlan._24) < 0.0f) )	dehors = false;
	if( dehors && ((matPlan._21*coin4.x + matPlan._22*coin4.y + matPlan._23*coin4.z + matPlan._24) < 0.0f) )	dehors = false;
	if( dehors && ((matPlan._21*coin5.x + matPlan._22*coin5.y + matPlan._23*coin5.z + matPlan._24) < 0.0f) )	dehors = false;
	if( dehors && ((matPlan._21*coin6.x + matPlan._22*coin6.y + matPlan._23*coin6.z + matPlan._24) < 0.0f) )	dehors = false;
	if( dehors && ((matPlan._21*coin7.x + matPlan._22*coin7.y + matPlan._23*coin7.z + matPlan._24) < 0.0f) )	dehors = false;

	if(dehors)		return 0;


	// ---------- PLAN 5 ---------- FAR

	matPlan.IdentityMatrix();
	matPlan._34 = Zfar;

	dehors = true;

	if(			   (matPlan._31*coin0.x + matPlan._32*coin0.y + matPlan._33*coin0.z + matPlan._34) > 0.0f  )	dehors = false;
	if( dehors && ((matPlan._31*coin1.x + matPlan._32*coin1.y + matPlan._33*coin1.z + matPlan._34) > 0.0f) )	dehors = false;
	if( dehors && ((matPlan._31*coin2.x + matPlan._32*coin2.y + matPlan._33*coin2.z + matPlan._34) > 0.0f) )	dehors = false;
	if( dehors && ((matPlan._31*coin3.x + matPlan._32*coin3.y + matPlan._33*coin3.z + matPlan._34) > 0.0f) )	dehors = false;
	if( dehors && ((matPlan._31*coin4.x + matPlan._32*coin4.y + matPlan._33*coin4.z + matPlan._34) > 0.0f) )	dehors = false;
	if( dehors && ((matPlan._31*coin5.x + matPlan._32*coin5.y + matPlan._33*coin5.z + matPlan._34) > 0.0f) )	dehors = false;
	if( dehors && ((matPlan._31*coin6.x + matPlan._32*coin6.y + matPlan._33*coin6.z + matPlan._34) > 0.0f) )	dehors = false;
	if( dehors && ((matPlan._31*coin7.x + matPlan._32*coin7.y + matPlan._33*coin7.z + matPlan._34) > 0.0f) )	dehors = false;

	if(dehors)		return 0;


	// ---------- PLAN 6 ---------- NEAR

	matPlan._34 = Znear;

	dehors = true;

	if(			   (matPlan._31*coin0.x + matPlan._32*coin0.y + matPlan._33*coin0.z + matPlan._34) < 0.0f  )	dehors = false;
	if( dehors && ((matPlan._31*coin1.x + matPlan._32*coin1.y + matPlan._33*coin1.z + matPlan._34) < 0.0f) )	dehors = false;
	if( dehors && ((matPlan._31*coin2.x + matPlan._32*coin2.y + matPlan._33*coin2.z + matPlan._34) < 0.0f) )	dehors = false;
	if( dehors && ((matPlan._31*coin3.x + matPlan._32*coin3.y + matPlan._33*coin3.z + matPlan._34) < 0.0f) )	dehors = false;
	if( dehors && ((matPlan._31*coin4.x + matPlan._32*coin4.y + matPlan._33*coin4.z + matPlan._34) < 0.0f) )	dehors = false;
	if( dehors && ((matPlan._31*coin5.x + matPlan._32*coin5.y + matPlan._33*coin5.z + matPlan._34) < 0.0f) )	dehors = false;
	if( dehors && ((matPlan._31*coin6.x + matPlan._32*coin6.y + matPlan._33*coin6.z + matPlan._34) < 0.0f) )	dehors = false;
	if( dehors && ((matPlan._31*coin7.x + matPlan._32*coin7.y + matPlan._33*coin7.z + matPlan._34) < 0.0f) )	dehors = false;

	if(dehors)		return 0;


	// Si tout s'est bien passé, l'objet est visible !
	return 1;
}



void ZWorld::ViewFrustrumCull(ZCamera *curCam, float tailleX, float tailleY, bool ortho)
{
	if(ortho==false)
	{
		ZVector3	angl;

		float	fovY	 = curCam->fov * 0.0174532925f;
		float	fCosineY = (float) cos(fovY);
		float	fSineY	 = (float) sin(fovY);

		float	ftangeX	 = (fSineY / fCosineY) * (tailleX / tailleY);
		float	fCosineX = sqrt( 1.0f / (1.0f+ftangeX*ftangeX) );
		float	fSineX	 = ftangeX * fCosineX;

		float	znear	= curCam->Znear;
		float	zfar	= curCam->Zfar;

		ZObject		*curObj;
		ZMesh		*curMesh;

		for(int i=0; i<objList.Size(); i++)
		{
			curObj = objList[i];

			curObj->visible = true;

			if( curObj->rangeOK )
			{
				curObj->visible = true;
				curMesh = curObj->GetMesh();

				if(curMesh)
				{
					if(!TestViewObj(curObj->worldMat, fCosineX, fSineX, fCosineY, fSineY, znear, zfar, 
									curMesh->xmin, curMesh->xmax, 
									curMesh->ymin, curMesh->ymax, 
									curMesh->zmin, curMesh->zmax										))		curObj->visible = false;
				}
				else
					curObj->visible = false;
			}
			else
				curObj->visible = false;
		}
	}
	else
	{
		ZObject		*curObj;

		for(int i=0; i<objList.Size(); i++)
		{
			curObj = objList[i];

			if( curObj->rangeOK && curObj->GetMesh() )		curObj->visible = true;
			else											curObj->visible = false;
		}
	}
}



///////////////////////////////////////////////////////////////////////////////////////////////
/// RenderSpritesPASS1()																	///
///																							///
///		This function render one sequence of object on the screen							///
///																							///
///////////////////////////////////////////////////////////////////////////////////////////////

void ZWorld::RenderSpritesPASS1(float camRotationZ)
{
	ZTexture	*curTex, *lastTex;
	ZMaterial	*curMat;

	lastTex = NULL;

	ZSprite		*curSpr;

	float		halfW, halfH, scale;
	ZVector3	*pos;
	ZVector3	*color;
	ZUV			*texCoord;

	bool		curClampU, curClampV;

	curClampU = curClampV = true;
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);



	for(int kk=0; kk<sprList.Size(); kk++)
	{
		curSpr = sprList[kk];
		curMat = curSpr->GetMaterial();

		if( (curSpr->rangeOK) && (!curMat->IsOnMode(RENDER_TRANSP)) )
		{
			// Application de la matrice
			glLoadIdentity();

			pos   = &(curSpr->worldPos);
			scale = curSpr->worldScale;
			glTranslatef(pos->x, pos->y, pos->z);
			if(curSpr->CameraOriented)		glRotatef(-camRotationZ+curSpr->rotationZ, 0.0f, 0.0f, 1.0f);
			else							glRotatef(curSpr->rotationZ, 0.0f, 0.0f, 1.0f);
			glScalef(scale, scale, scale);

			// données du sprite
			curTex = curMat->GetTexture1();

			color	 = curSpr->vertColor1;
			texCoord = curSpr->UV1;

			halfW = curSpr->halfW;
			halfH = curSpr->halfH;

			// ------> TEXTURE <------
			if(curMat->IsOnMode(RENDER_TEXTURED) && curTex && curTex->activated)
			{
				glEnable(GL_TEXTURE_2D);

				if(curTex!=lastTex)
				{
					curTex->PutGLMultiparams0();
					glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS );
					glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE );
					glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE );

					if(curTex->A)				
					{	
						glEnable(GL_BLEND);		
						glEnable(GL_ALPHA_TEST);	
						glAlphaFunc(GL_GREATER, CONST_ALPHA_TEST);
					}
					else						{	glDisable(GL_BLEND);	glDisable(GL_ALPHA_TEST);	}
				}
				lastTex = curTex;

				if( curMat->IsOnMode(RENDER_ENVMAP) )
				{
					curClampU = curClampV = false;
					glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
					glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

					glShadeModel(GL_FLAT);

					glEnable(GL_TEXTURE_GEN_S);							// Enable Texture Coord Generation For S (NEW)
					glEnable(GL_TEXTURE_GEN_T);							// Enable Texture Coord Generation For T (NEW)
					
					glBegin(GL_QUADS);

						glColor3f(1.0f, 1.0f, 1.0f);
						glNormal3f(0.0f, 0.0f, 1.0f);

						// Vertex number 0
						glVertex3f(-halfW, -halfH, 0.0f);

						// Vertex number 3
						glVertex3f( halfW, -halfH, 0.0f);

						// Vertex number 2
						glVertex3f( halfW,  halfH, 0.0f);

						// Vertex number 1
						glVertex3f(-halfW,  halfH, 0.0f);

						glEnd();

					glDisable(GL_TEXTURE_GEN_S);							// Enable Texture Coord Generation For S (NEW)
					glDisable(GL_TEXTURE_GEN_T);							// Enable Texture Coord Generation For T (NEW)
				}
				else
				if( curMat->IsOnMode(RENDER_COLOR1) && curMat->IsOnMode(RENDER_COLOR_VERTEX) )
				{
					if(curSpr->clampU1 != curClampU)
					{
						curClampU = curSpr->clampU1;
						if(curClampU)	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
						else			glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
					}

					if(curSpr->clampV1 != curClampV)
					{
						curClampV = curSpr->clampV1;
						if(curClampV)	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
						else			glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
					}

					glShadeModel(GL_SMOOTH);

					glBegin(GL_QUADS);

						// Vertex number 0
						glColor3fv(color->vals);
						glMultiTexCoord2fvARB(GL_TEXTURE0_ARB,texCoord->vals);
						glVertex3f(-halfW, -halfH, 0.0f);
						texCoord++;
						color++;

						// Vertex number 3
						glColor3fv(color->vals);
						glMultiTexCoord2fvARB(GL_TEXTURE0_ARB,texCoord->vals);
						glVertex3f( halfW, -halfH, 0.0f);
						texCoord++;
						color++;

						// Vertex number 2
						glColor3fv(color->vals);
						glMultiTexCoord2fvARB(GL_TEXTURE0_ARB,texCoord->vals);
						glVertex3f( halfW,  halfH, 0.0f);
						texCoord++;
						color++;

						// Vertex number 1
						glColor3fv(color->vals);
						glMultiTexCoord2fvARB(GL_TEXTURE0_ARB,texCoord->vals);
						glVertex3f(-halfW,  halfH, 0.0f);

					glEnd();
				}
				else
				if( curMat->IsOnMode(RENDER_COLOR1) )
				{
					if(curSpr->clampU1 != curClampU)
					{
						curClampU = curSpr->clampU1;
						if(curClampU)	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
						else			glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
					}

					if(curSpr->clampV1 != curClampV)
					{
						curClampV = curSpr->clampV1;
						if(curClampV)	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
						else			glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
					}

					color = &(curMat->color1);
				
					glShadeModel(GL_FLAT);

					glBegin(GL_QUADS);
						
						glColor3fv(color->vals);

						// Vertex number 0
						glMultiTexCoord2fvARB(GL_TEXTURE0_ARB,texCoord->vals);
						glVertex3f(-halfW, -halfH, 0.0f);
						texCoord++;
						
						// Vertex number 3
						glMultiTexCoord2fvARB(GL_TEXTURE0_ARB,texCoord->vals);
						glVertex3f( halfW, -halfH, 0.0f);
						texCoord++;
						
						// Vertex number 2
						glMultiTexCoord2fvARB(GL_TEXTURE0_ARB,texCoord->vals);
						glVertex3f( halfW,  halfH, 0.0f);
						texCoord++;
						
						// Vertex number 1
						glMultiTexCoord2fvARB(GL_TEXTURE0_ARB,texCoord->vals);
						glVertex3f(-halfW,  halfH, 0.0f);
					
					glEnd();
				}
				else
				{
					if(curSpr->clampU1 != curClampU)
					{
						curClampU = curSpr->clampU1;
						if(curClampU)	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
						else			glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
					}

					if(curSpr->clampV1 != curClampV)
					{
						curClampV = curSpr->clampV1;
						if(curClampV)	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
						else			glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
					}

					glShadeModel(GL_FLAT);

					glBegin(GL_QUADS);
						
						glColor3f(1.0f, 1.0f, 1.0f);

						// Vertex number 0
						glMultiTexCoord2fvARB(GL_TEXTURE0_ARB,texCoord->vals);
						glVertex3f(-halfW, -halfH, 0.0f);
						texCoord++;

						// Vertex number 3
						glMultiTexCoord2fvARB(GL_TEXTURE0_ARB,texCoord->vals);
						glVertex3f( halfW, -halfH, 0.0f);
						texCoord++;

						// Vertex number 2
						glMultiTexCoord2fvARB(GL_TEXTURE0_ARB,texCoord->vals);
						glVertex3f( halfW,  halfH, 0.0f);
						texCoord++;

						// Vertex number 1
						glMultiTexCoord2fvARB(GL_TEXTURE0_ARB,texCoord->vals);
						glVertex3f(-halfW,  halfH, 0.0f);

					glEnd();
				}
			}
			else
			// ---> NO TEXTURE <---
			{
				glDisable(GL_TEXTURE_2D);
				
				// pour désactiver la couleur de transparence
				glDisable(GL_BLEND);	
				glDisable(GL_ALPHA_TEST);

				if( curMat->IsOnMode(RENDER_COLOR1) && curMat->IsOnMode(RENDER_COLOR_VERTEX) )
				{
					glShadeModel(GL_SMOOTH);

					glBegin(GL_QUADS);
						
						// Vertex number 0
						glColor3fv(color->vals);
						glVertex3f(-halfW, -halfH, 0.0f);
						color++;

						// Vertex number 3
						glColor3fv(color->vals);
						glVertex3f( halfW, -halfH, 0.0f);
						color++;
					
						// Vertex number 2
						glColor3fv(color->vals);
						glVertex3f( halfW,  halfH, 0.0f);
						color++;

						// Vertex number 1
						glColor3fv(color->vals);
						glVertex3f(-halfW,  halfH, 0.0f);

					glEnd();
				}
				else
				if( curMat->IsOnMode(RENDER_COLOR1) )
				{
					color = &(curMat->color1);
				
					glShadeModel(GL_FLAT);

					glBegin(GL_QUADS);
						
						glColor3fv(color->vals);

						// Vertex number 0
						glVertex3f(-halfW, -halfH, 0.0f);

						// Vertex number 3
						glVertex3f( halfW, -halfH, 0.0f);

						// Vertex number 2
						glVertex3f( halfW,  halfH, 0.0f);

						// Vertex number 1
						glVertex3f(-halfW,  halfH, 0.0f);

					glEnd();
				}
				else
				{
					color = &(curMat->color);
				
					glShadeModel(GL_FLAT);

					glBegin(GL_QUADS);
						
						glColor3fv(color->vals);

						// Vertex number 0
						glVertex3f(-halfW, -halfH, 0.0f);

						// Vertex number 3
						glVertex3f( halfW, -halfH, 0.0f);

						// Vertex number 2
						glVertex3f( halfW,  halfH, 0.0f);

						// Vertex number 1
						glVertex3f(-halfW,  halfH, 0.0f);
					
					glEnd();
				}
			}
		}
	}
}





///////////////////////////////////////////////////////////////////////////////////////////////
/// RenderSpritesPASS2()																	///
///																							///
///		This function render one sequence of object on the screen							///
///																							///
///////////////////////////////////////////////////////////////////////////////////////////////

void ZWorld::RenderSpritesPASS2(float camRotationZ)
{
	ZTexture	*curTex, *lastTex;
	ZMaterial	*curMat;

	lastTex = NULL;

	ZSprite		*curSpr;

	float		halfW, halfH, scale;
	ZVector3	*pos;
	ZVector3	*color;
	ZUV			*texCoord;
	float		alpha;

	bool		curClampU, curClampV;

	curClampU = curClampV = true;

	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);


	for(int kk=0; kk<sprList.Size(); kk++)
	{
		curSpr	= sprList[kk];
		curMat = curSpr->GetMaterial();

		if( (curSpr->rangeOK) && (!curMat->IsOnMode(RENDER_TRANSP)) )
		{
			// Application de la matrice
			glLoadIdentity();

			pos   = &(curSpr->worldPos);
			scale = curSpr->worldScale;
			glTranslatef(pos->x, pos->y, pos->z);
			if(curSpr->CameraOriented)		glRotatef(-camRotationZ+curSpr->rotationZ, 0.0f, 0.0f, 1.0f);
			else							glRotatef(curSpr->rotationZ, 0.0f, 0.0f, 1.0f);
			glScalef(scale, scale, scale);

			// données du sprite
			curTex = curMat->GetTexture2();
			alpha  = curMat->alpha;

			color	 = curSpr->vertColor2;
			texCoord = curSpr->UV2;

			halfW = curSpr->halfW;
			halfH = curSpr->halfH;

			// ------> TEXTURE <------
			if(curMat->IsOnMode(RENDER_TEXTURED_BIS) && curTex && curTex->activated)
			{
				glEnable(GL_TEXTURE_2D);

				if(curTex!=lastTex)
				{
					curTex->PutGLMultiparams0();
					glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS );
					glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE );
					glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE );
					if(curTex->A)				
					{	
						glEnable(GL_ALPHA_TEST);	
						glAlphaFunc(GL_NOTEQUAL, 0);	
					}
					else						{	glDisable(GL_ALPHA_TEST);	}
				}
				lastTex = curTex;

				if(curSpr->clampU2 != curClampU)
				{
					curClampU = curSpr->clampU2;
					if(curClampU)	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
					else			glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
				}

				if(curSpr->clampV2 != curClampV)
				{
					curClampV = curSpr->clampV2;
					if(curClampV)	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
					else			glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
				}


				if( curMat->IsOnMode(RENDER_COLOR2) && curMat->IsOnMode(RENDER_COLOR_VERTEX) )
				{
					glShadeModel(GL_SMOOTH);

					glBegin(GL_QUADS);

						// Vertex number 0
						glColor4f(color->x, color->y, color->z, alpha);
						glMultiTexCoord2fvARB(GL_TEXTURE0_ARB,texCoord->vals);
						glVertex3f(-halfW, -halfH, 0.0f);
						texCoord++;
						color++;

						// Vertex number 3
						glColor4f(color->x, color->y, color->z, alpha);
						glMultiTexCoord2fvARB(GL_TEXTURE0_ARB,texCoord->vals);
						glVertex3f( halfW, -halfH, 0.0f);
						texCoord++;
						color++;

						// Vertex number 2
						glColor4f(color->x, color->y, color->z, alpha);
						glMultiTexCoord2fvARB(GL_TEXTURE0_ARB,texCoord->vals);
						glVertex3f( halfW,  halfH, 0.0f);
						texCoord++;
						color++;

						// Vertex number 1
						glColor4f(color->x, color->y, color->z, alpha);
						glMultiTexCoord2fvARB(GL_TEXTURE0_ARB,texCoord->vals);
						glVertex3f(-halfW,  halfH, 0.0f);

					glEnd();
				}
				else
				if( curMat->IsOnMode(RENDER_COLOR2) )
				{
					color = &(curMat->color1);
				
					glShadeModel(GL_FLAT);

					glBegin(GL_QUADS);
						
						glColor4f(color->x, color->y, color->z, alpha);

						// Vertex number 0
						glMultiTexCoord2fvARB(GL_TEXTURE0_ARB,texCoord->vals);
						glVertex3f(-halfW, -halfH, 0.0f);
						texCoord++;

						// Vertex number 3
						glMultiTexCoord2fvARB(GL_TEXTURE0_ARB,texCoord->vals);
						glVertex3f( halfW, -halfH, 0.0f);
						texCoord++;
					
						// Vertex number 2
						glMultiTexCoord2fvARB(GL_TEXTURE0_ARB,texCoord->vals);
						glVertex3f( halfW,  halfH, 0.0f);
						texCoord++;

						// Vertex number 1
						glMultiTexCoord2fvARB(GL_TEXTURE0_ARB,texCoord->vals);
						glVertex3f(-halfW,  halfH, 0.0f);

					glEnd();
				}
				else
				{
					glShadeModel(GL_FLAT);

					glBegin(GL_QUADS);
						
						glColor4f(1.0f, 1.0f, 1.0f, alpha);

						// Vertex number 0
						glMultiTexCoord2fvARB(GL_TEXTURE0_ARB,texCoord->vals);
						glVertex3f(-halfW, -halfH, 0.0f);
						texCoord++;

						// Vertex number 3
						glMultiTexCoord2fvARB(GL_TEXTURE0_ARB,texCoord->vals);
						glVertex3f( halfW, -halfH, 0.0f);
						texCoord++;

						// Vertex number 2
						glMultiTexCoord2fvARB(GL_TEXTURE0_ARB,texCoord->vals);
						glVertex3f( halfW,  halfH, 0.0f);
						texCoord++;

						// Vertex number 1
						glMultiTexCoord2fvARB(GL_TEXTURE0_ARB,texCoord->vals);
						glVertex3f(-halfW,  halfH, 0.0f);

					glEnd();
				}
			}
		}
	}
}



///////////////////////////////////////////////////////////////////////////////////////////////
/// RenderSpritesPASS3()																	///
///																							///
///		This function render one sequence of object on the screen							///
///																							///
///////////////////////////////////////////////////////////////////////////////////////////////

void ZWorld::RenderSpritesPASS3(float camRotationZ)
{
	ZMaterial	*curMat;
	ZSprite		*curSpr;

	float		halfW, halfH, scale;
	ZVector3	*pos;


	glShadeModel(GL_FLAT);

	for(int kk=0; kk<sprList.Size(); kk++)
	{
		curSpr = sprList[kk];
		curMat = curSpr->GetMaterial();

		if( (curSpr->rangeOK) && (!curMat->IsOnMode(RENDER_TRANSP)) )
		{

			if(curMat->IsOnMode(RENDER_LIGHTED))
			{
				curMat->PutGLparams();

				// Application de la matrice
				glLoadIdentity();

				pos   = &(curSpr->worldPos);
				scale = curSpr->worldScale;
				glTranslatef(pos->x, pos->y, pos->z);
				if(curSpr->CameraOriented)		glRotatef(-camRotationZ+curSpr->rotationZ, 0.0f, 0.0f, 1.0f);
				else							glRotatef(curSpr->rotationZ, 0.0f, 0.0f, 1.0f);
				glScalef(scale, scale, scale);

				// données du sprite
				halfW = curSpr->halfW;
				halfH = curSpr->halfH;

				glBegin(GL_QUADS);

					glColor3f(1.0f, 1.0f, 1.0f);
					glNormal3f(0.0f, 0.0f, 1.0f);

					// Vertex number 0
					glVertex3f(-halfW, -halfH, 0.0f);

					// Vertex number 3
					glVertex3f( halfW, -halfH, 0.0f);

					// Vertex number 2
					glVertex3f( halfW,  halfH, 0.0f);

					// Vertex number 1
					glVertex3f(-halfW,  halfH, 0.0f);

				glEnd();
			}
		}
	}
}













// C est la taille maximale des sous-tableaux pour le Quick Sort
#define TailleTabMax 15

void QuickSortIterative(vector<ZFaceProj*> &liste, vector<int> &a) 
{
	int		gauche, droit, 
			g, d, n,
			taille_a = 0;


	if(n = liste.size())
	{
		a.resize(2*n);

		ZFaceProj	*mid;
		ZFaceProj	*tmp;

		// On empile les bornes du sous-tableau
		a[taille_a++] = 0;
		a[taille_a++] = n-1;

		while(taille_a)
		{
			// Tant que la pile n est pas vide
			d = droit  = a[--taille_a];
			g = gauche = a[--taille_a];

			// on depile deux bornes d un sous tableau
			if (droit-gauche > TailleTabMax)
			{
				// si celui-ci est de taille superieure a la taille fixee au debut, on applique le quicksort
				mid = liste[droit];

				do
				{
					for( ; liste[g]->Zmin > mid->Zmin; g++);

					while( (--d) && (liste[d]->Zmin < mid->Zmin) );

					if (g<d)
					{
						tmp = liste[g];
						liste[g] = liste[d];
						liste[d] = tmp;
					}
				}
				while(g<d);

				tmp = liste[g];
				liste[g] = liste[droit];
				liste[droit] = tmp;

				a[taille_a++] = gauche;
				a[taille_a++] = g-1;
				a[taille_a++] = g+1;
				a[taille_a++] = droit;
			}
			else
			// Sinon, on trie le sous tableau par insertion
			while (++g <= droit)
			{
				mid = liste[g];

				for(d=g-1; (d>=0) && (liste[d]->Zmin < mid->Zmin) && (d >= gauche); d--)			liste[d+1] = liste[d];

				liste[d+1] = mid;
			}
		}
	}
}






///////////////////////////////////////////////////////////////////////////////////////////////
/// MACRO de détermination d'un vertex partagé - Transp definition							///
///////////////////////////////////////////////////////////////////////////////////////////////
#define FIND_SHARED_VERTEX_Transp											\
	ref    = *vrtRef;														\
	pere   = curObj;														\
	nbVert = mesh->NbVerts;													\
	while(ref >= nbVert)													\
	{																		\
		ref -= nbVert;														\
		pere = (ZObject*) pere->father;										\
		nbVert = pere->GetMesh()->NbVerts;									\
	}




///////////////////////////////////////////////////////////////////////////////////////////////
/// RenderObjectPassTransp()																///
///																							///
///		This function render one sequence of object on the screen							///
///																							///
///////////////////////////////////////////////////////////////////////////////////////////////
void ZWorld::RenderObjectPassTransp(ZCamera *curCam)
{
	FaceList			*listeface;
	vector<ZVert>		*vert;
	vector<ZVector3>	*vertTransf;
	vector<ZVector3>	*normTransf;

	ZObject		*curObj;
	ZMesh		*mesh;

	ZMatrix		matx;

	ZFaceProj	*curFace;
	ZFace		*Realface;
	
	ZObject		*pere;
	int			ref, nbVert;

	int			nbTranspFaces = 0;
	int			curNbTransp	  = 0;

	// données matricielles pour la projection de Z
	int			matA = curCam->visionMatx._31;
	int			matB = curCam->visionMatx._32;
	int			matC = curCam->visionMatx._33;
	int			matD = curCam->visionMatx._34;
	ZVector3	*vertMoved;									// utilisé pour accélérer les calculs de Zproj

	float		*tempFloat;
	int			*vrtRef;
	ZVector3	*tempVecPos;
	ZVector3	*tempVecNorm;

	// -------------------------------------------------------
	// ----------		TRAITEMENT DES OBJETS		----------
	// -------------------------------------------------------

	for(int i=0; i<objList.Size(); i++)
	{
		curObj = objList[i];

		// Matrix for static-normales computing
		matx = curObj->worldMat;
		matx._14 = matx._24 = matx._34 = matx._41 = matx._42 = matx._43 = 0.0f;
		matx._44 = 1.0f;

		if(curObj->visible)
		{
			mesh		= curObj->GetMesh();
			listeface	= &(mesh->FacesTransp);
			vert		= &(mesh->Verts);
			vertTransf	= &(curObj->VertsTransf);
			normTransf	= &(curObj->VertNormTransf);

			// resize de la liste des faces transparentes, si besoin est..
			nbTranspFaces += listeface->size();
			if(transpList.size() < nbTranspFaces)		transpList.resize(nbTranspFaces);

			// Introduction des nouvelles faces transparentes
			for(int j=0; j < listeface->size(); j++)
			{
				curFace = &(transpList[curNbTransp]);
				curNbTransp++;

				curFace->face = Realface = (*listeface)[j];
				curFace->type = 0;

				if(mesh->dependency==true)
					curFace->normFace = Realface->Normal;				// normale déjà calculée
				else
					curFace->normFace = matx * Realface->Normal;		// normale que l'on calcule

				// Pointeurs d'acceleration
				tempVecPos  = curFace->vert3D;
				tempVecNorm = curFace->normales;

				if(Realface->dependency)
				{
					vrtRef = Realface->VertRef;

					// Vertex number 0
					FIND_SHARED_VERTEX_Transp
					*tempVecPos				= (pere->VertsTransf[ref]);
					if(pere->normalsTransformed)		*tempVecNorm = pere->VertNormTransf[ref];
					else								*tempVecNorm = matx * pere->GetMesh()->Verts[ref].Normal;
					curFace->colorVerts[0]  = &(pere->GetMesh()->Verts[ref].color1);
					tempVecPos++;
					tempVecNorm++;
					vrtRef++;

					// Vertex number 1
					FIND_SHARED_VERTEX_Transp
					*tempVecPos				= (pere->VertsTransf[ref]);
					if(pere->normalsTransformed)		*tempVecNorm = pere->VertNormTransf[ref];
					else								*tempVecNorm = matx * pere->GetMesh()->Verts[ref].Normal;
					curFace->colorVerts[1]  = &(pere->GetMesh()->Verts[ref].color1);
					tempVecPos++;
					tempVecNorm++;
					vrtRef++;

					// Vertex number 2
					FIND_SHARED_VERTEX_Transp
					*tempVecPos				= (pere->VertsTransf[ref]);
					if(pere->normalsTransformed)		*tempVecNorm = pere->VertNormTransf[ref];
					else								*tempVecNorm = matx * pere->GetMesh()->Verts[ref].Normal;
					curFace->colorVerts[2]  = &(pere->GetMesh()->Verts[ref].color1);
				}
				else
				{
					vrtRef = Realface->VertRef;

					// positions 3D "bougées"
					*tempVecPos		= ((*vertTransf)[ *vrtRef ]);
					tempVecPos++;
					vrtRef++;
					*tempVecPos		= ((*vertTransf)[ *vrtRef ]);
					tempVecPos++;
					vrtRef++;
					*tempVecPos		= ((*vertTransf)[ *vrtRef ]);

					if( (mesh->dependency==true) || (mesh->displayListCreate==false) )
					{
						vrtRef -= 2;
						*tempVecNorm	= (*normTransf)[ *vrtRef ];
						tempVecNorm++;
						vrtRef++;
						*tempVecNorm	= (*normTransf)[ *vrtRef ];
						tempVecNorm++;
						vrtRef++;
						*tempVecNorm	= (*normTransf)[ *vrtRef ];
					}
					else
					{
						vrtRef -= 2;
						*tempVecNorm	= matx * ((*vert)[ *vrtRef ].Normal);
						tempVecNorm++;
						vrtRef++;
						*tempVecNorm	= matx * ((*vert)[ *vrtRef ].Normal);
						tempVecNorm++;
						vrtRef++;
						*tempVecNorm	= matx * ((*vert)[ *vrtRef ].Normal);
					}

					vrtRef -= 2;
					curFace->colorVerts[0]  = &((*vert)[ *vrtRef ].color1);
					vrtRef++;
					curFace->colorVerts[1]  = &((*vert)[ *vrtRef ].color1);
					vrtRef++;
					curFace->colorVerts[2]  = &((*vert)[ *vrtRef ].color1);
				}

				// projections
				vertMoved	= curFace->vert3D;
				tempFloat	= curFace->Zproj;
				*tempFloat = matA * vertMoved->x + matB * vertMoved->y + matC * vertMoved->z + matD;
				vertMoved++;
				tempFloat++;
				*tempFloat = matA * vertMoved->x + matB * vertMoved->y + matC * vertMoved->z + matD;
				vertMoved++;
				tempFloat++;
				*tempFloat = matA * vertMoved->x + matB * vertMoved->y + matC * vertMoved->z + matD;

				// stocke le + petit Z
				tempFloat = curFace->Zproj;
				curFace->Zmin = *tempFloat;
				tempFloat++;
				if(curFace->Zmin > *tempFloat)		curFace->Zmin = *tempFloat;
				tempFloat++;
				if(curFace->Zmin > *tempFloat)		curFace->Zmin = *tempFloat;
			}
			
		}
	}
	
	// -----------------------------------------------------------
	// ----------		TRAITEMENT DES PARTICULES		----------
	// -----------------------------------------------------------

	float		camRotationZ = curCam->RealWorldAngles.z;

	ZEmitter		*curPcl;
	
	ZMatrix		matCam = curCam->cameraMatx;

	ZMatrix		matBILL  = RotateYXZMatrix(0.0174532925f * curCam->RealWorldAngles);

	for(i=0; i<pclList.Size(); i++)
	{
		curPcl = pclList[i];

		if( (curPcl->rangeOK) && (curPcl->state&PCL_ACTIVE) && !(curPcl->mask&PCL_ADDITIVE) )
		{
			// Traitement suivant le type de particule du systeme
			vector<T_PCL_LIST>::iterator l_it = curPcl->particlelist.begin();
			vector<T_PARTICLE*>::iterator p_it;

			for(; l_it!= curPcl->particlelist.end(); l_it++)
			{
				T_PARTICLE			*part;
				ZParticle			*type	= l_it->parttype;
				vector<T_PARTICLE*>	*plist	= &(l_it->list);

				mesh		= type->GetMesh();
				listeface	= &(mesh->FacesTransp);
				vert		= &(mesh->Verts);


				p_it = plist->begin();
				// -------------------- RENDU D'UN TYPE DE PARTICULE --------------------
				if(type->mask&PCL_BILLBOARD)
				{
					for(; p_it!=plist->end(); p_it++)
					{
						part = (*p_it);								// Current particle

						// ------------- RENDU D'UNE PARTICULE TRANSPARENTE -------------

						matx = matCam * TranslateMatrix(part->position.x, part->position.y, part->position.z);
						matx *= matBILL;
						matx *= RotateZMatrix(part->spin);
						matx *= ScaleMatrix(part->size);

						// resize de la liste des faces transparentes, si besoin est..
						nbTranspFaces += listeface->size();
						if(transpList.size() < nbTranspFaces)		transpList.resize(nbTranspFaces);

						// Introduction des nouvelles faces transparentes
						for(int n=0; n<listeface->size(); n++)
						{
							curFace = &(transpList[curNbTransp]);
							curNbTransp++;

							curFace->face = Realface = (*listeface)[n];
							curFace->type = 1;
							curFace->pclColor = part->color;

							// Pointeurs d'acceleration
							tempVecPos  = curFace->vert3D;
							vrtRef		= Realface->VertRef;

							// positions 3D "bougées"
							*tempVecPos		= matx * (*vert)[ *vrtRef ];
							tempVecPos++;
							vrtRef++;
							*tempVecPos		= matx * (*vert)[ *vrtRef ];
							tempVecPos++;
							vrtRef++;
							*tempVecPos		= matx * (*vert)[ *vrtRef ];

							// projections
							vertMoved	= curFace->vert3D;
							tempFloat	= curFace->Zproj;
							*tempFloat = matA * vertMoved->x + matB * vertMoved->y + matC * vertMoved->z + matD;
							vertMoved++;
							tempFloat++;
							*tempFloat = matA * vertMoved->x + matB * vertMoved->y + matC * vertMoved->z + matD;
							vertMoved++;
							tempFloat++;
							*tempFloat = matA * vertMoved->x + matB * vertMoved->y + matC * vertMoved->z + matD;
							
							// stocke le + petit Z
							tempFloat = curFace->Zproj;
							curFace->Zmin = *tempFloat;
							tempFloat++;
							if(curFace->Zmin > *tempFloat)		curFace->Zmin = *tempFloat;
							tempFloat++;
							if(curFace->Zmin > *tempFloat)		curFace->Zmin = *tempFloat;
						}
					}
				}
				else
				{
					if(type->mask&PCL_JITTER)
					{
						for(; p_it!=plist->end(); p_it++)
						{
							part = (*p_it);								// Current particle

							// ------------- RENDU D'UNE PARTICULE TRANSPARENTE -------------

							matx  = matCam * TranslateMatrix(part->position.x, part->position.y, part->position.z);
							matx *= RotateYXZMatrix(part->rot);
							matx *= ScaleMatrix(part->size);

							// resize de la liste des faces transparentes, si besoin est..
							nbTranspFaces += listeface->size();
							if(transpList.size() < nbTranspFaces)		transpList.resize(nbTranspFaces);

							// Introduction des nouvelles faces transparentes
							for(int n=0; n<listeface->size(); n++)
							{
								curFace = &(transpList[curNbTransp]);
								curNbTransp++;

								curFace->face = Realface = (*listeface)[n];
								curFace->type = 1;
								curFace->pclColor = part->color;

								// Pointeurs d'acceleration
								tempVecPos  = curFace->vert3D;
								vrtRef		= Realface->VertRef;
								
								// positions 3D "bougées"
								*tempVecPos		= matx * (*vert)[ *vrtRef ];
								tempVecPos++;
								vrtRef++;
								*tempVecPos		= matx * (*vert)[ *vrtRef ];
								tempVecPos++;
								vrtRef++;
								*tempVecPos		= matx * (*vert)[ *vrtRef ];

								// projections
								vertMoved	= curFace->vert3D;
								tempFloat	= curFace->Zproj;
								*tempFloat = matA * vertMoved->x + matB * vertMoved->y + matC * vertMoved->z + matD;
								vertMoved++;
								tempFloat++;
								*tempFloat = matA * vertMoved->x + matB * vertMoved->y + matC * vertMoved->z + matD;
								vertMoved++;
								tempFloat++;
								*tempFloat = matA * vertMoved->x + matB * vertMoved->y + matC * vertMoved->z + matD;
								
								// stocke le + petit Z
								tempFloat = curFace->Zproj;
								curFace->Zmin = *tempFloat;
								tempFloat++;
								if(curFace->Zmin > *tempFloat)		curFace->Zmin = *tempFloat;
								tempFloat++;
								if(curFace->Zmin > *tempFloat)		curFace->Zmin = *tempFloat;
							}
						}
					}
					else {
						for(; p_it!=plist->end(); p_it++)
						{
							part = (*p_it);								// Current particle

							// ------------- RENDU D'UNE PARTICULE TRANSPARENTE -------------

							matx = matCam * TranslateMatrix(part->position.x, part->position.y, part->position.z);
							matx *= ScaleMatrix(part->size);

							// resize de la liste des faces transparentes, si besoin est..
							nbTranspFaces += listeface->size();
							if(transpList.size() < nbTranspFaces)		transpList.resize(nbTranspFaces);

							// Introduction des nouvelles faces transparentes
							for(int n=0; n<listeface->size(); n++)
							{
								curFace = &(transpList[curNbTransp]);
								curNbTransp++;

								curFace->face = Realface = (*listeface)[n];
								curFace->type = 1;
								curFace->pclColor = part->color;

								// Pointeurs d'acceleration
								tempVecPos  = curFace->vert3D;
								vrtRef		= Realface->VertRef;
								
								// positions 3D "bougées"
								*tempVecPos		= matx * (*vert)[ *vrtRef ];
								tempVecPos++;
								vrtRef++;
								*tempVecPos		= matx * (*vert)[ *vrtRef ];
								tempVecPos++;
								vrtRef++;
								*tempVecPos		= matx * (*vert)[ *vrtRef ];

								// projections
								vertMoved	= curFace->vert3D;
								tempFloat	= curFace->Zproj;
								*tempFloat = matA * vertMoved->x + matB * vertMoved->y + matC * vertMoved->z + matD;
								vertMoved++;
								tempFloat++;
								*tempFloat = matA * vertMoved->x + matB * vertMoved->y + matC * vertMoved->z + matD;
								vertMoved++;
								tempFloat++;
								*tempFloat = matA * vertMoved->x + matB * vertMoved->y + matC * vertMoved->z + matD;
								
								// stocke le + petit Z
								tempFloat = curFace->Zproj;
								curFace->Zmin = *tempFloat;
								tempFloat++;
								if(curFace->Zmin > *tempFloat)		curFace->Zmin = *tempFloat;
								tempFloat++;
								if(curFace->Zmin > *tempFloat)		curFace->Zmin = *tempFloat;
							}
						}
					}
				}
			}
		}
	}

	// -------------------------------------------------------
	// ----------		TRAITEMENT DES SPRITES		----------
	// -------------------------------------------------------

	ZSprite		*curSpr;
	ZMaterial	*curMat;
	ZVector3	*pos;

	for(i=0; i<sprList.Size(); i++)
	{
		curSpr	= sprList[i];
		curMat = curSpr->GetMaterial();

		if( (curSpr->rangeOK) && (curMat->IsOnMode(RENDER_TRANSP)) )
		{
			// resize de la liste des faces transparentes, si besoin est..
			nbTranspFaces++;
			if(transpList.size() < nbTranspFaces)		transpList.resize(nbTranspFaces);

			curFace = &(transpList[curNbTransp]);
			curNbTransp++;

			curFace->sprite = curSpr;
			curFace->type = 2;

			// stocke le + petit Z (le centre de la face billboard)
			pos   = &(curSpr->worldPos);
			curFace->Zmin = matA * pos->x + matB * pos->y + matC * pos->z + matD;
		}
	}

	// Tronque les éléments restant
	transpList.resize(nbTranspFaces);
	transpListSorted.resize(nbTranspFaces);

	for(i=0; i<nbTranspFaces; i++)		transpListSorted[i] = &(transpList[i]);
	
	// Effectue le tri des polygones transparents suivant
	QuickSortIterative(transpListSorted, tempQuickSort);

	// On affiche directement les coordonnées (sauf pour SPRITE)
	glLoadIdentity();

	// Affichage polygone / polygone
	ZFace		*affFace;
	ZVector3	*point;
	ZVector3	*normal;
	ZVector3	**color;
	ZVector3	*colorFlat;
	float		transp;

	ZUV			*UV;

	ZTexture	*curTex, *lastTex;

	lastTex = NULL;

	float		halfW, halfH, scale;
	ZUV			*texCoord;

	int		orderCounter = -1;
	int		numberFacesTreated = 0;

  //$BLG
  //Added in v4.6a2
  //Removed in v4.6a3: Brought more problems than solutions, especially with ColorLights.  
  //float    blg_alight, blg_color, blg_alpha;
  
  //$BLG
  //Added in v4.6a2
  //Removed in v4.6a3: Brought more problems than solutions, especially with ColorLights.  
  //blg_alight = BLG_GetAmbientLight();
  //blg_color  = (0.50f + blg_alight) * 1.75f;
  // //blg_alpha  = 0.50f + blg_alight;  // Old formula
  //I finally removed the blg_alight param as it modified/"hardened" the material opacity
  //when the ambient light increased.
  //blg_alpha  = 0.50f;

	while(numberFacesTreated < nbTranspFaces)
	{
		orderCounter++;

		if(orderCounter==1)
		{
			// -----> PASS Additive rendering <---- //
			glShadeModel(GL_FLAT);
			glBlendFunc(GL_SRC_ALPHA, GL_ONE);
			RenderAdditiveParticles(curCam->RealWorldAngles, curCam->cameraMatx);
			glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
			// ------------------------------------ //
			glLoadIdentity();
		}

		for(i=0; i<nbTranspFaces; i++)
		{
			curFace = transpListSorted[i];

			point  = curFace->vert3D;
			normal = curFace->normales;
			color  = curFace->colorVerts;

			affFace = curFace->face;
			
			///////////////////////////////////////////////////////////////////////
			// Test d'ordre sur le matériau	///////////////////////////////////////	
			if(curFace->type == 0)		curMat = affFace->GetMaterial();
			else if(curFace->type == 1)		curMat = affFace->GetMaterial();
			else if(curFace->type == 2)		curMat = curFace->sprite->GetMaterial();

			//$BLG
      //Added in v4.6a2
      //Removed in v4.6a3: Brought more problems than solutions, especially with ColorLights.
      //Not sure if it was useful or not
			//curMat->PutGLMultiparams0();

			if(curMat->transparencyOrder!=orderCounter)		continue;

			numberFacesTreated++;



			// -----------------------------------------------
			// ----------	Affichage des objets	----------
			// -----------------------------------------------
			if(curFace->type == 0)
			{
				curTex = curMat->GetTexture1();
				transp = curMat->coeffTransp;

				// ---> TEXTURE <---
				if(curMat->IsOnMode(RENDER_TEXTURED) && curTex && curTex->activated)
				{
					glEnable(GL_TEXTURE_2D);
					
					if(curTex!=lastTex)			curTex->PutGLMultiparams0();
					lastTex = curTex;
					

					if( curMat->IsOnMode(RENDER_ENVMAP) && curMat->IsOnMode(RENDER_GOURAUD_LIGHT) )
					{
						glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
						glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

						glEnable(GL_TEXTURE_GEN_S);							// Enable Texture Coord Generation For S (NEW)
						glEnable(GL_TEXTURE_GEN_T);							// Enable Texture Coord Generation For T (NEW)

						glShadeModel(GL_SMOOTH);

						glBegin(GL_TRIANGLES);

							glColor4f(1.0f, 1.0f, 1.0f, transp);

							// Vertex number 0
							glNormal3fv(normal->vals);
							glVertex3fv(point->vals);
							normal++;
							point++;

							// Vertex number 1
							glNormal3fv(normal->vals);
							glVertex3fv(point->vals);
							normal++;
							point++;

							// Vertex number 2
							glNormal3fv(normal->vals);
							glVertex3fv(point->vals);

						glEnd();

						glDisable(GL_TEXTURE_GEN_S);							// Enable Texture Coord Generation For S (NEW)
						glDisable(GL_TEXTURE_GEN_T);							// Enable Texture Coord Generation For T (NEW)
					}
					else
					if( curMat->IsOnMode(RENDER_ENVMAP) )
					{
						glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
						glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

						glEnable(GL_TEXTURE_GEN_S);							// Enable Texture Coord Generation For S (NEW)
						glEnable(GL_TEXTURE_GEN_T);							// Enable Texture Coord Generation For T (NEW)
						
						glShadeModel(GL_FLAT);

						glBegin(GL_TRIANGLES);

							glColor4f(1.0f, 1.0f, 1.0f, transp);
							glNormal3fv(curFace->normFace.vals);

							// Vertex number 0
							glVertex3fv(point->vals);
							point++;

							// Vertex number 1
							glVertex3fv(point->vals);
							point++;

							// Vertex number 2
							glVertex3fv(point->vals);
						
						glEnd();

						glDisable(GL_TEXTURE_GEN_S);							// Enable Texture Coord Generation For S (NEW)
						glDisable(GL_TEXTURE_GEN_T);							// Enable Texture Coord Generation For T (NEW)
					}
					else
					if( curMat->IsOnMode(RENDER_COLOR1) && curMat->IsOnMode(RENDER_COLOR_VERTEX) )
					{
						if(affFace->clampU1)	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
						else					glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
						if(affFace->clampV1)	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
						else					glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
						
						glShadeModel(GL_SMOOTH);

						glBegin(GL_TRIANGLES);

							UV = affFace->UV1;
						
							// Vertex number 0
							glColor4f((*color)->x, (*color)->y, (*color)->z, transp);
							glMultiTexCoord2fvARB(GL_TEXTURE0_ARB,UV->vals);
							glVertex3fv(point->vals);
							UV++;
							point++;
							color++;

							// Vertex number 1
							glColor4f((*color)->x, (*color)->y, (*color)->z, transp);
							glMultiTexCoord2fvARB(GL_TEXTURE0_ARB,UV->vals);
							glVertex3fv(point->vals);
							UV++;
							point++;
							color++;

							// Vertex number 2
							glColor4f((*color)->x, (*color)->y, (*color)->z, transp);
							glMultiTexCoord2fvARB(GL_TEXTURE0_ARB,UV->vals);
							glVertex3fv(point->vals);
						
						glEnd();
					}
					else
					if( curMat->IsOnMode(RENDER_COLOR1) )
					{
						if(affFace->clampU1)	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
						else					glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
						if(affFace->clampV1)	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
						else					glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

						colorFlat = &(curMat->color1);
					
						glShadeModel(GL_FLAT);

						glBegin(GL_TRIANGLES);
							
							UV = affFace->UV1;
							glColor4f(colorFlat->x, colorFlat->y, colorFlat->z, transp);

							// Vertex number 0
							glMultiTexCoord2fvARB(GL_TEXTURE0_ARB,UV->vals);
							glVertex3fv(point->vals);
							UV++;
							point++;

							// Vertex number 1
							glMultiTexCoord2fvARB(GL_TEXTURE0_ARB,UV->vals);
							glVertex3fv(point->vals);
							UV++;
							point++;

							// Vertex number 2
							glMultiTexCoord2fvARB(GL_TEXTURE0_ARB,UV->vals);
							glVertex3fv(point->vals);
						
						glEnd();
					}
					else
					{
						if(affFace->clampU1)	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
						else					glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
						if(affFace->clampV1)	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
						else					glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

						glShadeModel(GL_FLAT);

						glBegin(GL_TRIANGLES);

						
							UV = affFace->UV1;
							//$BLG Del (This is handled below)
							//glColor4f(1.0f, 1.0f, 1.0f, transp);

  //Added in v4.6a2
  //Removed in v4.6a3: Brought more problems than solutions, especially with ColorLights.
  /*
            //$BLG
            //Original code used only the ELSE part
            if (curMat->IsOnMode(RENDER_LIGHTED))
            {
							//$BLG Note: This formula is just from "try and see the result"
							//Only the Ambient lights are taken into account as I've no idea on how to retrieve other lights impact on vertices
							//Ambient lights vary from -0.50 to +0.50
							//I assumed that most sites do not use ambient lights above 32 (0.0) (which would produce some saturation effect)
							//Ambient lights varying from 10 to 30 seem to produce acceptable "similar" results
							glColor4f(blg_color, blg_color, blg_color, blg_alpha + transp);
							// Vertex number 0
							glMultiTexCoord2fvARB(GL_TEXTURE0_ARB,UV->vals);
							glNormal3fv(affFace->Normal.vals);
							glVertex3fv(point->vals);
							point++;
							UV++;
							// Vertex number 1
							glMultiTexCoord2fvARB(GL_TEXTURE0_ARB,UV->vals);
							glNormal3fv(affFace->Normal.vals);
							glVertex3fv(point->vals);
							point++;
							UV++;
							// Vertex number 2
							glMultiTexCoord2fvARB(GL_TEXTURE0_ARB,UV->vals);
							glNormal3fv(affFace->Normal.vals);
							glVertex3fv(point->vals);
            }
            else
            {
							glColor4f(1.0f, 1.0f, 1.0f, transp);
							// Vertex number 0
							glMultiTexCoord2fvARB(GL_TEXTURE0_ARB,UV->vals);
							glVertex3fv(point->vals);
							UV++;
							point++;
							// Vertex number 1
							glMultiTexCoord2fvARB(GL_TEXTURE0_ARB,UV->vals);
							glVertex3fv(point->vals);
							UV++;
							point++;
							// Vertex number 2
							glMultiTexCoord2fvARB(GL_TEXTURE0_ARB,UV->vals);
							glVertex3fv(point->vals);
            }
		*/	
    //$BLG
    // Original code (above Else part)
							glColor4f(1.0f, 1.0f, 1.0f, transp);
							// Vertex number 0
							glMultiTexCoord2fvARB(GL_TEXTURE0_ARB,UV->vals);
							glVertex3fv(point->vals);
							UV++;
							point++;
							// Vertex number 1
							glMultiTexCoord2fvARB(GL_TEXTURE0_ARB,UV->vals);
							glVertex3fv(point->vals);
							UV++;
							point++;
							// Vertex number 2
							glMultiTexCoord2fvARB(GL_TEXTURE0_ARB,UV->vals);
							glVertex3fv(point->vals);
    // End of code restoration

						glEnd();
					}
	
				}
				else
				// ---> NO TEXTURE <---
				{
					glDisable(GL_TEXTURE_2D);

					if( curMat->IsOnMode(RENDER_COLOR1) && curMat->IsOnMode(RENDER_COLOR_VERTEX) )
					{
						glShadeModel(GL_SMOOTH);

						glBegin(GL_TRIANGLES);
							
							// Vertex number 0
							glColor4f((*color)->x, (*color)->y, (*color)->z, transp);
							glVertex3fv(point->vals);
							point++;
							color++;

							// Vertex number 1
							glColor4f((*color)->x, (*color)->y, (*color)->z, transp);
							glVertex3fv(point->vals);
							point++;
							color++;

							// Vertex number 2
							glColor4f((*color)->x, (*color)->y, (*color)->z, transp);
							glVertex3fv(point->vals);
						
						glEnd();
					}
					else
					if( curMat->IsOnMode(RENDER_COLOR1) )
					{
						colorFlat = &(curMat->color1);
					
						glShadeModel(GL_FLAT);

						glBegin(GL_TRIANGLES);
							
							glColor4f(colorFlat->x, colorFlat->y, colorFlat->z, transp);

							// Vertex number 0
							glVertex3fv(point->vals);
							point++;

							// Vertex number 1
							glVertex3fv(point->vals);
							point++;

							// Vertex number 2
							glVertex3fv(point->vals);

						glEnd();
					}
					else
					{
						colorFlat = &(curMat->color);
					
						glShadeModel(GL_FLAT);

						glBegin(GL_TRIANGLES);
							
							glColor4f(colorFlat->x, colorFlat->y, colorFlat->z, transp);

							// Vertex number 0
							glVertex3fv(point->vals);
							point++;

							// Vertex number 1
							glVertex3fv(point->vals);
							point++;

							// Vertex number 2
							glVertex3fv(point->vals);
						
						glEnd();
					}
				}
			}
			else
			// ---------------------------------------------------
			// ----------	Affichage des particules	----------
			// ---------------------------------------------------
			if(curFace->type == 1)
			{
				curTex = curMat->GetTexture1();


				// ---> TEXTURE <---
				if(curMat->IsOnMode(RENDER_TEXTURED) && curTex && curTex->activated)
				{
					glEnable(GL_TEXTURE_2D);

					if(curTex!=lastTex)			curTex->PutGLMultiparams0();
					lastTex = curTex;
				
	/*
					if(affFace->clampU1 != curClampU)
					{
						curClampU = affFace->clampU1;
						if(curClampU)	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
						else			glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
					}

					if(affFace->clampV1 != curClampV)
					{
						curClampV = affFace->clampV1;
						if(curClampV)	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
						else			glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
					}
	*/
					if(affFace->clampU1)	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
					else					glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
					if(affFace->clampV1)	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
					else					glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

					glShadeModel(GL_FLAT);

					glBegin(GL_TRIANGLES);
						
						UV = affFace->UV1;
						glColor4f(curFace->pclColor.x, curFace->pclColor.y, curFace->pclColor.z, curFace->pclColor.w);

						// Vertex number 0
						glMultiTexCoord2fvARB(GL_TEXTURE0_ARB,UV->vals);
						glVertex3fv(point->vals);
						UV++;
						point++;

						// Vertex number 1
						glMultiTexCoord2fvARB(GL_TEXTURE0_ARB,UV->vals);
						glVertex3fv(point->vals);
						UV++;
						point++;

						// Vertex number 2
						glMultiTexCoord2fvARB(GL_TEXTURE0_ARB,UV->vals);
						glVertex3fv(point->vals);
					
					glEnd();
				}
				else
				// ---> NO TEXTURE <---
				{
					glDisable(GL_TEXTURE_2D);

					glShadeModel(GL_FLAT);

					glBegin(GL_TRIANGLES);
						
						glColor4f(curFace->pclColor.x, curFace->pclColor.y, curFace->pclColor.z, curFace->pclColor.w);

						// Vertex number 0
						glVertex3fv(point->vals);
						point++;

						// Vertex number 1
						glVertex3fv(point->vals);
						point++;

						// Vertex number 2
						glVertex3fv(point->vals);

					glEnd();
				}
			}
			else
			// -----------------------------------------------
			// ----------	Affichage des sprites	----------
			// -----------------------------------------------
			if(curFace->type == 2)
			{
				curSpr = curFace->sprite;

				// Application de la matrice
				glLoadIdentity();

				pos   = &(curSpr->worldPos);
				scale = curSpr->worldScale;
				glTranslatef(pos->x, pos->y, pos->z);
				if(curSpr->CameraOriented)		glRotatef(-camRotationZ+curSpr->rotationZ, 0.0f, 0.0f, 1.0f);
				else							glRotatef(curSpr->rotationZ, 0.0f, 0.0f, 1.0f);
				glScalef(scale, scale, scale);

				// données du sprite
				curTex = curMat->GetTexture1();
				transp = curMat->coeffTransp;

				colorFlat = curSpr->vertColor1;
				texCoord = curSpr->UV1;

				halfW = curSpr->halfW;
				halfH = curSpr->halfH;



				// ---> TEXTURE <---
				if(curMat->IsOnMode(RENDER_TEXTURED) && curTex && curTex->activated)
				{
					glEnable(GL_TEXTURE_2D);

					if(curTex!=lastTex)			curTex->PutGLMultiparams0();
					lastTex = curTex;

	/*
					curClampU = curClampU = false;
					glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
					glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
	*/
					if( curMat->IsOnMode(RENDER_ENVMAP) )
					{
	//					curClampU = curClampV = false;
						glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
						glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

						glEnable(GL_TEXTURE_GEN_S);							// Enable Texture Coord Generation For S (NEW)
						glEnable(GL_TEXTURE_GEN_T);							// Enable Texture Coord Generation For T (NEW)
						
						glShadeModel(GL_FLAT);

						glBegin(GL_QUADS);

							glColor4f(1.0f, 1.0f, 1.0f, transp);
							glNormal3f(0.0f, 0.0f, 1.0f);

							// Vertex number 0
							glVertex3f(-halfW, -halfH, 0.0f);

							// Vertex number 3
							glVertex3f( halfW, -halfH, 0.0f);

							// Vertex number 2
							glVertex3f( halfW,  halfH, 0.0f);

							// Vertex number 1
							glVertex3f(-halfW,  halfH, 0.0f);

						glEnd();

						glDisable(GL_TEXTURE_GEN_S);							// Enable Texture Coord Generation For S (NEW)
						glDisable(GL_TEXTURE_GEN_T);							// Enable Texture Coord Generation For T (NEW)
					}
					else
					if( curMat->IsOnMode(RENDER_COLOR1) && curMat->IsOnMode(RENDER_COLOR_VERTEX) )
					{
	/*					if(curSpr->clampU1 != curClampU)
						{
							curClampU = curSpr->clampU1;
							if(curClampU)	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
							else			glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
						}

						if(curSpr->clampV1 != curClampV)
						{
							curClampV = curSpr->clampV1;
							if(curClampV)	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
							else			glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
						}
	*/
						if(curSpr->clampU1)	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
						else				glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
						if(curSpr->clampV1)	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
						else				glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

						glShadeModel(GL_SMOOTH);

						glBegin(GL_QUADS);

							// Vertex number 0
							glColor4f(colorFlat->x, colorFlat->y, colorFlat->z, transp);
							glMultiTexCoord2fvARB(GL_TEXTURE0_ARB,UV->vals);
							glVertex3f(-halfW, -halfH, 0.0f);
							texCoord++;
							colorFlat++;

							// Vertex number 3
							glColor4f(colorFlat->x, colorFlat->y, colorFlat->z, transp);
							glMultiTexCoord2fvARB(GL_TEXTURE0_ARB,UV->vals);
							glVertex3f( halfW, -halfH, 0.0f);
							texCoord++;
							colorFlat++;

							// Vertex number 2
							glColor4f(colorFlat->x, colorFlat->y, colorFlat->z, transp);
							glMultiTexCoord2fvARB(GL_TEXTURE0_ARB,UV->vals);
							glVertex3f( halfW,  halfH, 0.0f);
							texCoord++;
							colorFlat++;

							// Vertex number 1
							glColor4f(colorFlat->x, colorFlat->y, colorFlat->z, transp);
							glMultiTexCoord2fvARB(GL_TEXTURE0_ARB,UV->vals);
							glVertex3f(-halfW,  halfH, 0.0f);

						glEnd();
					}
					else
					if( curMat->IsOnMode(RENDER_COLOR1) )
					{
	/*					if(curSpr->clampU1 != curClampU)
						{
							curClampU = curSpr->clampU1;
							if(curClampU)	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
							else			glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
						}

						if(curSpr->clampV1 != curClampV)
						{
							curClampV = curSpr->clampV1;
							if(curClampV)	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
							else			glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
						}
	*/
						if(curSpr->clampU1)	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
						else				glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
						if(curSpr->clampV1)	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
						else				glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

						colorFlat = &(curMat->color1);
					
						glShadeModel(GL_FLAT);

						glBegin(GL_QUADS);
							
							glColor4f(colorFlat->x, colorFlat->y, colorFlat->z, transp);

							// Vertex number 0
							glMultiTexCoord2fvARB(GL_TEXTURE0_ARB,UV->vals);
							glVertex3f(-halfW, -halfH, 0.0f);
							texCoord++;

							// Vertex number 3
							glMultiTexCoord2fvARB(GL_TEXTURE0_ARB,UV->vals);
							glVertex3f( halfW, -halfH, 0.0f);
							texCoord++;
						
							// Vertex number 2
							glMultiTexCoord2fvARB(GL_TEXTURE0_ARB,UV->vals);
							glVertex3f( halfW,  halfH, 0.0f);
							texCoord++;

							// Vertex number 1
							glMultiTexCoord2fvARB(GL_TEXTURE0_ARB,UV->vals);
							glVertex3f(-halfW,  halfH, 0.0f);

						glEnd();
					}
					else
					{
	/*					if(curSpr->clampU1 != curClampU)
						{
							curClampU = curSpr->clampU1;
							if(curClampU)	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
							else			glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
						}

						if(curSpr->clampV1 != curClampV)
						{
							curClampV = curSpr->clampV1;
							if(curClampV)	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
							else			glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
						}
	*/
						if(curSpr->clampU1)	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
						else				glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
						if(curSpr->clampV1)	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
						else				glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

						glShadeModel(GL_FLAT);

						glBegin(GL_QUADS);
							
							glColor4f(1.0f, 1.0f, 1.0f, transp);

							// Vertex number 0
							glMultiTexCoord2fvARB(GL_TEXTURE0_ARB,UV->vals);
							glVertex3f(-halfW, -halfH, 0.0f);
							texCoord++;

							// Vertex number 3
							glMultiTexCoord2fvARB(GL_TEXTURE0_ARB,UV->vals);
							glVertex3f( halfW, -halfH, 0.0f);
							texCoord++;

							// Vertex number 2
							glMultiTexCoord2fvARB(GL_TEXTURE0_ARB,UV->vals);
							glVertex3f( halfW,  halfH, 0.0f);
							texCoord++;

							// Vertex number 1
							glMultiTexCoord2fvARB(GL_TEXTURE0_ARB,UV->vals);
							glVertex3f(-halfW,  halfH, 0.0f);

						glEnd();
					}
				}
				else
				// ---> NO TEXTURE <---
				{
					glDisable(GL_TEXTURE_2D);

					if( curMat->IsOnMode(RENDER_COLOR1) && curMat->IsOnMode(RENDER_COLOR_VERTEX) )
					{
						glShadeModel(GL_SMOOTH);

						glBegin(GL_QUADS);
							
							// Vertex number 0
							glColor4f(colorFlat->x, colorFlat->y, colorFlat->z, transp);
							glVertex3f(-halfW, -halfH, 0.0f);
							colorFlat++;

							// Vertex number 3
							glColor4f(colorFlat->x, colorFlat->y, colorFlat->z, transp);
							glVertex3f( halfW, -halfH, 0.0f);
							colorFlat++;
						
							// Vertex number 2
							glColor4f(colorFlat->x, colorFlat->y, colorFlat->z, transp);
							glVertex3f( halfW,  halfH, 0.0f);
							colorFlat++;

							// Vertex number 1
							glColor4f(colorFlat->x, colorFlat->y, colorFlat->z, transp);
							glVertex3f(-halfW,  halfH, 0.0f);

						glEnd();
					}
					else
					if( curMat->IsOnMode(RENDER_COLOR1) )
					{
						colorFlat = &(curMat->color1);
					
						glShadeModel(GL_FLAT);

						glBegin(GL_QUADS);
							
							glColor4f(colorFlat->x, colorFlat->y, colorFlat->z, transp);

							// Vertex number 0
							glVertex3f(-halfW, -halfH, 0.0f);

							// Vertex number 3
							glVertex3f( halfW, -halfH, 0.0f);

							// Vertex number 2
							glVertex3f( halfW,  halfH, 0.0f);

							// Vertex number 1
							glVertex3f(-halfW,  halfH, 0.0f);

						glEnd();
					}
					else
					{
						colorFlat = &(curMat->color);
					
						glShadeModel(GL_FLAT);

						glBegin(GL_QUADS);
							
							glColor4f(colorFlat->x, colorFlat->y, colorFlat->z, transp);

							// Vertex number 0
							glVertex3f(-halfW, -halfH, 0.0f);

							// Vertex number 3
							glVertex3f( halfW, -halfH, 0.0f);

							// Vertex number 2
							glVertex3f( halfW,  halfH, 0.0f);

							// Vertex number 1
							glVertex3f(-halfW,  halfH, 0.0f);

						glEnd();
					}
				}
				glLoadIdentity();
			}
		}
	}

	//////////////
	// Cas particulier où le rendu n'a pas eu lieu dans la boucle générale de rendu
	/////
	if(orderCounter<=0)
	{
		// -----> PASS Additive rendering <---- //
		glShadeModel(GL_FLAT);
		glBlendFunc(GL_SRC_ALPHA, GL_ONE);
		RenderAdditiveParticles(curCam->RealWorldAngles, curCam->cameraMatx);
		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
		// ------------------------------------ //
	}
}








void quicksort(vector<ZFaceSOFT*> &liste, int last)
{
 int i,p,k,first;
 static int firstStack[40];
 static int lastStack[40];
 int sp = 0;

 // Initialise stack
 firstStack[sp] = 0;
 lastStack[sp++]  = last;

 while(sp)
 {// Pop first pair of indexes
  first = firstStack[--sp];
  last  = lastStack[sp];

  // Partition array in the interval [first, last]
  if (first < last)
  {
    ZFaceSOFT *pivot = liste[first];
  	i = first;

   while ((++i <= last) && (pivot->ymax < liste[i]->ymax));

   if (i > last)
   {
   	 liste[first] = liste[last];
     liste[last] = pivot;
     // Push interval [first, last-1]
     // firstStack[sp] = first;
     lastStack[sp++] = last - 1;
   }
   else
   { // The set [p, k[ is the set of the value equal to pivot.
     p = i - 1;
     liste[first] = liste[p];
     k = i;
     while (++i <= last)
      if (pivot->ymax < liste[i]->ymax)
       {
       	 liste[p++] = liste[i];
         liste[i] = liste[k];
         liste[k++] = liste[p];
       }
      else if (pivot->ymax == liste[i]->ymax)
       {
       	 ZFaceSOFT *tmp = liste[i];
         liste[i] = liste[k];
         liste[k++] = tmp;
       }
     if (p > first)
      { liste[p] = pivot;
        // Push interval [first, p-1]
        //firstStack[sp] = first;
        lastStack[sp++] = p - 1;
      }
     // Push interval [p+1, last]
     firstStack[sp] = k;
     lastStack[sp++] = last;
   }
  }
 }
}












 

#define	CLASSIC_SORT	1


void QuickSortSOFT_Y(vector<ZFaceSOFT*> &liste, vector<int> &a) 
{
	int		gauche, droit, g, d, n;


	static int firstStack[40];
	static int lastStack[40];
	int sp = 0;


	if(n = liste.size())
	{
		ZFaceSOFT	*mid;
		ZFaceSOFT	*tmp;

		// On empile les bornes du sous-tableau
		firstStack[sp] = 0;
		lastStack[sp]  = n-1;
		sp++;

		while(sp)
		{
			// Tant que la pile n est pas vide
			sp--;
			g = gauche = firstStack[sp];
			d = droit  = lastStack[sp];

			// on depile deux bornes d un sous tableau
			if (droit-gauche > TailleTabMax)
			{
				// si celui-ci est de taille superieure a la taille fixee au debut, on applique le quicksort
				mid = liste[droit];

				do
				{
					for( ; liste[g]->ymax > mid->ymax; g++);

					while( (--d) && (liste[d]->ymax < mid->ymax) );

					if (g<d)
					{
						tmp = liste[g];
						liste[g] = liste[d];
						liste[d] = tmp;
					}
				}
				while(g<d);

				tmp = liste[g];
				liste[g] = liste[droit];
				liste[droit] = tmp;

				firstStack[sp] = g+1;
				lastStack[sp] = droit;
				sp++;
				firstStack[sp] = gauche;
				lastStack[sp] = g-1;
				sp++;
			}
			else
			// Sinon, on trie le sous tableau par insertion
			while (++g <= droit)
			{
				mid = liste[g];

				for(d=g-1; (d>=0) && (liste[d]->ymax < mid->ymax) && (d >= gauche); d--)			liste[d+1] = liste[d];

				liste[d+1] = mid;
			}
		}
	}
}






float ZWorld::Calclight(ZVector3 *pos, ZVector3 *norm)
{
	ZLight		*light;
	ZVector3	ab;
	float		length;

	float		l0 = 31.0f;


	if(lghList.Size()==0)
	{
		float	coeffLight = (float) ((12-31)>>1);
		l0 += coeffLight - coeffLight * (defaultLightDir * (*norm));
	}
	else
	{
		for(int i=0; i<lghList.Size(); i++)
		{
			light = lghList[i];

			if(light->LightType == LIGHT_AMBIENT)
			{
				l0 += light->alpha;
			}
			else if(light->LightType == LIGHT_PARA)
			{
				l0 += light->alpha + light->beta * (light->target * (*norm));
			}
			else if(light->LightType == LIGHT_OMNI)
			{
				ab		= (light->worldPos - *pos)*100.0f;
				length	= ab.Length();

				if(light->oldStyle)			length = light->dist * light->dist * (1+ (ab*(*norm)/(length+0.0001f))) / (2.0f*(length*length+1));
				else						length = 200.0f * 200.0f * (1+ (ab*(*norm))/(length+0.0001f)) / (2.0f*(length*length+1));

				if(length>1)			length = 1;
				else if(length<0)		length = 0;

				l0 += light->alpha + light->beta * length;
			}
			else if(light->LightType == LIGHT_SPOT)
			{
				ab		= (light->worldPos - *pos)*100.0f;
				length  = ab.Length() + 0.0001f;

				length = light->dist * light->dist * (1+(ab*(*norm))/length) * (1+(ab*light->target)/length)/((length*length+1)*4);

				if(length>1)			length = 1;
				else if(length<0)		length = 0;

				l0 += light->alpha + light->beta * length;
			}
		}
	}

	//l0 += baselight;
	if(l0<0)	l0=0;
	if(l0>63)	l0=63;

	return l0;
}




/*
///////////////////////////////////////////////////////////////////////////////////////////////
/// SelectFaces()																			///
///																							///
///		This function render one sequence of object on the screen							///
///																							///
///////////////////////////////////////////////////////////////////////////////////////////////
void ZWorld::SelectFaces(ZCamera *curCam, bool wired)
{
#ifdef _BENCH_SOFT_
	profile->BeginProfile(7);
	profile->BeginProfileCYCLE(7);
#endif

	vector<ZFace>		*listeface;
	vector<ZVert>		*vert;
	vector<ZVector3>	*vertTransf;
	vector<ZVector3>	*FaceNormTransf;
	vector<ZVector3>	*VertNormTransf;

	ZObject		*curObj;
	ZMesh		*mesh;

	ZFaceSOFT	*curFace;
	ZFace		*Realface;

	int			nbTotalFaces = 0;
	int			curNbFaces	 = 0;

	// Données pour la macro FIND_SHARED_VERTEX_Transp
	ZObject		*pere;
	int			ref, nbVert;

	int			*vrtRef;

	int			i, j;

	ZVector3	*vert3D[3];						// coordonnées des 3 vertices, déjà transformées (tirées de VertTransf dans ZObject)


	// Données pour le ClipPol
	int			nbPt;
	float		y, k, zmin;
	int			fog;
	int			ymin, ymax;

	ZVector3	ab;
	ZVector3	*vec;
	ZVector3	*norm[3];
	float		light[3];

	int			nbPoint;
	int			flag;

	int			pointHaut;

	int			halfX = curCam->width  >> 1;
	int			halfY = curCam->height >> 1;
	float		znear = -curCam->Znear;
	float		zfar  = -curCam->Zfar;
	float		zfog  = -curCam->Zfog;

	int			u0, v0, u1, v1;

	int			index;
	int			color16;

	ZMaterial	*mater;
	int			renderMode;

	ZVertSOFT	*point;


	// Resize du tableau en hauteur des faces
	SOFTListSorted.resize(curCam->height+1);
	for(i=0; i<curCam->height+1; i++)			SOFTListSorted[i] = NULL;


	// Resize du tableau des VRAIES faces
	for(i=0; i<objList.Size(); i++)
	{
		curObj = objList[i];

		if(curObj->visible)
		{
			mesh			= curObj->GetMesh();
			listeface		= &(curObj->GetMesh()->Faces);
//			nbTotalFaces += curObj->GetMesh()->Faces.size();
			nbTotalFaces += listeface->size();
		}
	}
	SOFTList.resize(nbTotalFaces);




	// Traitement des faces par objet
	for(i=0; i<objList.Size(); i++)
	{
		curObj = objList[i];

		if(curObj->visible)
		{
			mesh			= curObj->GetMesh();
			listeface		= &(mesh->Faces);
			vert			= &(mesh->Verts);
			vertTransf		= &(curObj->VertsTransf);
			VertNormTransf	= &(curObj->VertNormTransf);
			FaceNormTransf	= &(curObj->FaceNormTransf);

			for(j=0; j < listeface->size(); j++)
			{
				curFace = &(SOFTList[curNbFaces]);

				curFace->face = Realface = &(*listeface)[j];
				curFace->next = curFace->prev = NULL;


				///////////////////////////////////////////////////////
				///		Get root's informations for the face		///
				///////////////////////////////////////////////////////

				if(Realface->dependency)
				{
					vrtRef = Realface->VertRef;

					// Vertex number 0
					FIND_SHARED_VERTEX_Transp
					vert3D[0] = &(pere->VertsTransf[ref]);
					norm[0]	  = &pere->VertNormTransf[ref];
					vrtRef++;

					// Vertex number 1
					FIND_SHARED_VERTEX_Transp
					vert3D[1] = &(pere->VertsTransf[ref]);
					norm[1]	  = &pere->VertNormTransf[ref];
					vrtRef++;

					// Vertex number 2
					FIND_SHARED_VERTEX_Transp
					vert3D[2] = &(pere->VertsTransf[ref]);
					norm[2]	  = &pere->VertNormTransf[ref];
				}
				else
				{
					vrtRef = Realface->VertRef;

					// Vertex number 0
					vert3D[0] = &((*vertTransf)[ *vrtRef ]);
					norm[0]	  = &(*VertNormTransf)[ *vrtRef ];
					vrtRef++;

					// Vertex number 1
					vert3D[1] = &((*vertTransf)[ *vrtRef ]);
					norm[1]	  = &(*VertNormTransf)[ *vrtRef ];
					vrtRef++;

					// Vertex number 2
					vert3D[2] = &((*vertTransf)[ *vrtRef ]);
					norm[2]	  = &(*VertNormTransf)[ *vrtRef ];
				}


				///////////////////////////////////////////////////////
				///		Compute light for each vertex      			///
				///////////////////////////////////////////////////////

				renderMode = Realface->GetMaterial()->RenderMode;

				if(renderMode & RENDER_LIGHTED)
				{
					if(renderMode & RENDER_GOURAUD_LIGHT)
					{
						light[0]  = Calclight(vert3D[0], norm[0]);
						light[1]  = Calclight(vert3D[1], norm[1]);
						light[2]  = Calclight(vert3D[2], norm[2]);
					}
					else
					{
						vec = &(*FaceNormTransf)[j];
						light[0]  = Calclight(vert3D[0], vec);
						light[1]  = Calclight(vert3D[1], vec);
						light[2]  = Calclight(vert3D[2], vec);
					}
				}
				else
				{
					light[0] = light[1] = light[2] = 31.0f;
				}


				///////////////////////////////////////////////////////
				///		Clipping & Determination of ppties			///
				///////////////////////////////////////////////////////

				nbPoint = pointHaut = flag = 0;
				index	= 2;

				zmin  = zfar;

				mater = curFace->face->GetMaterial();

				point = curFace->vert;


				// Préparation des coords de texture du point de référence
				if(mater->IsOnMode(RENDER_ENVMAP))
				{
					vec	 = norm[2];
					ab.x = -2*vec->z*vec->x;
					ab.y = -2*vec->z*vec->y;
					ab.z = 1-2*vec->z*vec->z;
					vec	 = &ab;

					k = vec->x*128+128;			u0 = k;
					k = vec->y*128+128;			v0 = k;
				}
				else
				{
					u0 = AROUNDINT(curFace->face->UV1[index].u * 256.0f);
					v0 = AROUNDINT(curFace->face->UV1[index].v * 256.0f);
				}

				ymax = -1000000;
				ymin =  1000000;


				// Traitement des données, vertex par vertex
				for(nbPt=0; nbPt<3; nbPt++)
				{
					if(mater->IsOnMode(RENDER_ENVMAP))
					{
						vec	 = norm[nbPt];
						ab.x = -2*vec->z*vec->x;
						ab.y = -2*vec->z*vec->y;
						ab.z = 1-2*vec->z*vec->z;
						vec	 = &ab;

						k = vec->x*128+128;			u1 = k;
						k = vec->y*128+128;			v1 = k;
					}
					else
					{
						u1 = AROUNDINT(curFace->face->UV1[nbPt].u * 256.0f);
						v1 = AROUNDINT(curFace->face->UV1[nbPt].v * 256.0f);
					}

					// Clipping du point en Znear & ajout d'un point supplémentaire si besoin est
					if(		((vert3D[nbPt]->z >= znear) && (vert3D[index]->z <  znear))  
						||  ((vert3D[nbPt]->z <  znear) && (vert3D[index]->z >= znear))	)
					{
						k = (znear - vert3D[index]->z) / (vert3D[nbPt]->z - vert3D[index]->z);

						float	interm = vert3D[index]->x + k*(vert3D[nbPt]->x - vert3D[index]->x);
						point->posX = (curCam->dx * interm) / (-znear);

						interm = vert3D[index]->y + k*(vert3D[nbPt]->y - vert3D[index]->y);
						y = (curCam->dy * interm) / (-znear);
						point->posY  = y;
						point->posY += halfY;

						point->posZ = 1;

						if(point->posX <=  halfX)			flag|=1;
						if(point->posX >= -halfX)			flag|=2;
						if(point->posY <=  halfY<<1)		flag|=4;
						if(point->posY >=  0)				flag|=8;

						zmin = znear;

						flag|=16;

						if(point->posY < ymin)		ymin = point->posY;
						if(point->posY > ymax)
						{
							ymax  = point->posY;
							pointHaut = nbPoint;
						}

						point->u = u0 + k*(u1 - u0);
						point->v = v0 + k*(v1 - v0);
						point->light = light[index] + k*(light[nbPt]-light[index]);
						
						point++;
						nbPoint++;
					}


					// Point sans clipping
					if(vert3D[nbPt]->z < znear)
					{
						point->posX = curCam->dx * vert3D[nbPt]->x / (-vert3D[nbPt]->z);
						point->posY = (int)(curCam->dy * vert3D[nbPt]->y / (-vert3D[nbPt]->z)) + halfY;
						point->posZ = znear / vert3D[nbPt]->z;

						if(point->posX <=  halfX)			flag|=1;
						if(point->posX >= -halfX)			flag|=2;
						if(point->posY <=  halfY*2)			flag|=4;
						if(point->posY >=  0)				flag|=8;

						if(vert3D[nbPt]->z > zmin)
						{
							zmin = vert3D[nbPt]->z;
							flag|=16;
						}

						if(point->posY < ymin)		ymin = point->posY;
						if(point->posY > ymax)
						{
							ymax  = point->posY;
							pointHaut = nbPoint;
						}

						point->u = u1 * point->posZ;
						point->v = v1 * point->posZ;
						point->light = light[nbPt];

						point++;
						nbPoint++;
					}

					index = nbPt;

					u0 = u1;
					v0 = v1;
				}


				// La face ne doit pas être affichée
				if( (nbPoint<3) || (flag!=31) )
				{
					nbTotalFaces--;					
				}
				// La face doit être affichée
				else
				{
					// dernier test : backface culling !
					point -= (nbPoint-1);

					float xx0, xx1, xx2, yy0, yy1, yy2;

					xx0 = point->posX;		yy0 = point->posX;		point++;
					xx1 = point->posX;		yy1 = point->posX;		point++;
					xx2 = point->posX;		yy2 = point->posX;

					if( ((xx1-xx0)*(yy2-yy0) - (xx2-xx0)*(yy1-yy0)) < 0)
					{
						nbTotalFaces--;
					}
					else
					{
						curFace->ymax = ymax;
						curFace->ymin = ymin;

						// Ajout de la face dans la liste verticale
						int position;
						position = ymax>curCam->height?curCam->height:ymax;
						position = position<0?0:position;

						curFace->next = SOFTListSorted[position];
						curFace->prev = NULL;
						if(curFace->next)	curFace->next->prev = curFace;
						SOFTListSorted[position] = curFace;

						// Ici se trouvent les faces à afficher
						curFace->Npoints = nbPoint;
						curFace->pointG = curFace->pointD = pointHaut;

						if(wired)
						{
							color16 = mater->GetDefaultColor();
							curFace->color16 = ((color16>>3)&0x1f)+((color16>>6)&0x3e0)+((color16>>9)&0x7c00);
						}
						else
						{
							fog = 0;

							if(zmin < zfog)
							{
								k	 = (16*(zmin+zfog)) / (zfar+zfog+1);
								fog	 = k;
								fog *= 64;
							}

							// ---- Attribution des tables de couleur ----

							curFace->transp  = mater->IsOnMode(RENDER_TRANSP);

							// Rendu texturé
							if(mater->IsOnMode(RENDER_TEXTURED) && mater->GetTexture1()!=NULL && mater->GetTexture1()->activated )
							{
								ZTexture	*tex = curFace->face->GetMaterial()->GetTexture1();
								curFace->bitmap	 = tex->bitmap16;
								curFace->width	 = tex->Width;
								curFace->height  = tex->Height;
								curFace->color16 = RGBto15( tex->GetTranspR(), tex->GetTranspG(), tex->GetTranspB());
								curFace->table	 = &palette16[fog<<LOGTABCOL];
							}
							// Rendu non texturé
							else
							{
								curFace->bitmap = NULL;

								if(curFace->transp)
								{
									curFace->table		= mater->transpTab;
								}
								else
								{
									color16 = mater->GetDefaultColor();
									curFace->color16	= ((color16>>3)&0x1f)+((color16>>6)&0x3e0)+((color16>>9)&0x7c00);
									curFace->table		= &palette16[fog<<LOGTABCOL];
								}
							}


							// ---- Attribution des fonctions de rendu ----

							// Rendu transparent
							if(curFace->transp)
							{
								if(curFace->bitmap)
								{
									if(mater->GetCoeffTransp() < 128)		curFace->render = &Render_TRANSP_TEX_1;
									else									curFace->render = &Render_TRANSP_TEX_2;
								}
								else
									curFace->render = &Render_TRANSP_NOTEX;
							}
							// Rendu opaque
							else
							{
								if(curFace->bitmap)						curFace->render = &Render_TEX;
								else									curFace->render = &Render_FLAT;
							}
						}

						curNbFaces++;
					}
				}

				///////////////////////////////////////////////////////
				///		End of clipping & determination of ppties	///
				///////////////////////////////////////////////////////
			}
		}
	}

	// Trie le tableau suivant les Y décroissants (Ymax -> Ymin)
	SOFTList.resize(nbTotalFaces);

#ifdef _BENCH_SOFT_
	profile->EndProfile(7);
	profile->EndProfileCYCLE(7);
#endif

}
*/


///////////////////////////////////////////////////////////////////////////////////////////////
/// SelectFaces()																			///
///																							///
///		This function render one sequence of object on the screen							///
///																							///
///////////////////////////////////////////////////////////////////////////////////////////////
void ZWorld::SelectFaces(ZCamera *curCam, bool wired, bool ortho)
{
#ifdef _BENCH_SOFT_
	profile->BeginProfile(7);
	profile->BeginProfileCYCLE(7);
#endif

	vector<ZFace>		*listeface;
	vector<ZVert>		*vert;
	vector<ZVector3>	*vertTransf;
	vector<ZVector3>	*FaceNormTransf;
	vector<ZVector3>	*VertNormTransf;

	ZObject		*curObj;

	ZFaceSOFT	*curFace;
	ZFace		*Realface;

	ZMesh		*mesh;

	int			nbTotalFaces = 0;
	int			curNbFaces	 = 0;

	// Données pour la macro FIND_SHARED_VERTEX_Transp
	ZObject		*pere;
	int			ref, nbVert;

	int			*vrtRef;

	int			i, j;

	ZVector3	*vert3D[3];						// coordonnées des 3 vertices, déjà transformées (tirées de VertTransf dans ZObject)
	

	// Données pour le ClipPol
	int			nbPt;
	float		y, k, zmin;
	int			fog;
	int			ymin, ymax;

	ZVector3	ab;
	ZVector3	*vec;
	ZVector3	*norm[3];
	float		light[3];

	int			nbPoint;
	int			flag;

	int			pointHaut;

	int			halfX = curCam->width  >> 1;
	int			halfY = curCam->height >> 1;
	float		znear = -curCam->Znear;
	float		zfar  = -curCam->Zfar;
	float		zfog  = -curCam->Zfog;

	int			u0, v0, u1, v1;

	int			index;
	//$LB
	int			color24;

	ZMaterial	*mater;
	int			renderMode;

	ZVertSOFT	*point;


	// Resize du tableau en hauteur des faces
	SOFTListSorted.resize(curCam->height+1);
	for(i=0; i<curCam->height+1; i++)			SOFTListSorted[i] = NULL;


	// Resize du tableau des VRAIES faces
	for(i=0; i<objList.Size(); i++)
	{
		curObj = objList[i];
		if(curObj->visible)			nbTotalFaces += curObj->GetMesh()->Faces.size();
	}
	SOFTList.resize(nbTotalFaces);




	// Traitement des faces par objet
	for(i=0; i<objList.Size(); i++)
	{
		curObj = objList[i];

		if(curObj->visible)
		{
			mesh			= curObj->GetMesh();
			listeface		= &(mesh->Faces);
			vert			= &(mesh->Verts);
			vertTransf		= &(curObj->VertsTransf);
			VertNormTransf	= &(curObj->VertNormTransf);
			FaceNormTransf	= &(curObj->FaceNormTransf);

			for(j=0; j < listeface->size(); j++)
			{
				curFace = &(SOFTList[curNbFaces]);

				curFace->face = Realface = &(*listeface)[j];

				mater = Realface->GetMaterial();


				// 1) Recupere les vertices (et normales) de la face
				if(Realface->dependency)
				{
					vrtRef = Realface->VertRef;

					FIND_SHARED_VERTEX_Transp
					vert3D[0] = &(pere->VertsTransf[ref]);
					norm[0]	  = &pere->VertNormTransf[ref];
					vrtRef++;

					FIND_SHARED_VERTEX_Transp
					vert3D[1] = &(pere->VertsTransf[ref]);
					norm[1]	  = &pere->VertNormTransf[ref];
					vrtRef++;

					FIND_SHARED_VERTEX_Transp
					vert3D[2] = &(pere->VertsTransf[ref]);
					norm[2]	  = &pere->VertNormTransf[ref];
				}
				else
				{
					vrtRef = Realface->VertRef;

					vert3D[0] = &((*vertTransf)[ *vrtRef ]);
					norm[0]	  = &(*VertNormTransf)[ *vrtRef ];
					vrtRef++;

					vert3D[1] = &((*vertTransf)[ *vrtRef ]);
					norm[1]	  = &(*VertNormTransf)[ *vrtRef ];
					vrtRef++;

					vert3D[2] = &((*vertTransf)[ *vrtRef ]);
					norm[2]	  = &(*VertNormTransf)[ *vrtRef ];
				}

				// 2) Back Face culling
				if((*FaceNormTransf)[j] * (*vert3D[0]) > 0   && !ortho)
				{
					nbTotalFaces--;
					continue;
				}

				// 3) Calcul des eclairages
				renderMode = mater->RenderMode;

				if(renderMode & RENDER_LIGHTED)
				{
					if(renderMode & RENDER_GOURAUD_LIGHT)
					{
						light[0]  = Calclight(vert3D[0], norm[0]);
						light[1]  = Calclight(vert3D[1], norm[1]);
						light[2]  = Calclight(vert3D[2], norm[2]);
					}
					else
					{
						vec = &(*FaceNormTransf)[j];
						light[0]  = Calclight(vert3D[0], vec);
						light[1]  = Calclight(vert3D[1], vec);
						light[2]  = Calclight(vert3D[2], vec);
					}
				}
				else
				{
					light[0] = light[1] = light[2] = 31.0f;
				}

				// 4) Calcul des coordonnées de texture du point de reference (le n°2)
				if(renderMode & RENDER_ENVMAP)
				{
					vec	 = norm[2];
					ab.x = -2*vec->z*vec->x;
					ab.y = -2*vec->z*vec->y;
					ab.z = 1-2*vec->z*vec->z;
					vec	 = &ab;

					k = vec->x*128+128;			u0 = k;
					k = vec->y*128+128;			v0 = k;
				}
				else
				{
					u0 = AROUNDINT(Realface->UV1[2].u * 256.0f);
					v0 = AROUNDINT(Realface->UV1[2].v * 256.0f);
				}

				// 5) Clipping, projection et calcul de texCoord
				nbPoint = pointHaut = flag = 0;
				index	= 2;

				zmin  = zfar;

				point = curFace->vert;

				ymax = -1000000;
				ymin =  1000000;

				for(nbPt=0; nbPt<3; nbPt++)
				{
					if(renderMode & RENDER_ENVMAP)
					{
						vec	 = norm[nbPt];
						ab.x = -2*vec->z*vec->x;
						ab.y = -2*vec->z*vec->y;
						ab.z = 1-2*vec->z*vec->z;
						vec	 = &ab;

						k = vec->x*128+128;			u1 = k;
						k = vec->y*128+128;			v1 = k;
					}
					else
					{
						u1 = AROUNDINT(Realface->UV1[nbPt].u * 256.0f);
						v1 = AROUNDINT(Realface->UV1[nbPt].v * 256.0f);
					}

					// 5-1) Clipping du point en Znear & ajout d'un point supplémentaire si besoin est
					if(		((vert3D[nbPt]->z >= znear) && (vert3D[index]->z <  znear))  
						||  ((vert3D[nbPt]->z <  znear) && (vert3D[index]->z >= znear))	)
					{
						k = (znear - vert3D[index]->z) / (vert3D[nbPt]->z - vert3D[index]->z);

						float	interm = vert3D[index]->x + k*(vert3D[nbPt]->x - vert3D[index]->x);
						point->posX = (curCam->dx * interm) / (-znear);

						interm = vert3D[index]->y + k*(vert3D[nbPt]->y - vert3D[index]->y);
						y = (curCam->dy * interm) / (-znear);
						point->posY  = y;
						point->posY += halfY;

						point->posZ = 1;

						if(point->posX <=  halfX)			flag|=1;
						if(point->posX >= -halfX)			flag|=2;
						if(point->posY <=  halfY<<1)		flag|=4;
						if(point->posY >=  0)				flag|=8;

						zmin = znear;

						flag|=16;

						if(point->posY < ymin)		ymin = point->posY;
						if(point->posY > ymax)
						{
							ymax  = point->posY;
							pointHaut = nbPoint;
						}

						point->u = u0 + k*(u1 - u0);
						point->v = v0 + k*(v1 - v0);
						point->light = light[index] + k*(light[nbPt]-light[index]);
						
						point++;
						nbPoint++;
					}


					// 5-2) Point sans clipping
					if(vert3D[nbPt]->z < znear && !ortho)
					{
						point->posX = curCam->dx * vert3D[nbPt]->x / (-vert3D[nbPt]->z);
						point->posY = (int)(curCam->dy * vert3D[nbPt]->y / (-vert3D[nbPt]->z)) + halfY;
						point->posZ = znear / vert3D[nbPt]->z;

						if(point->posX <=  halfX)			flag|=1;
						if(point->posX >= -halfX)			flag|=2;
						if(point->posY <=  halfY*2)			flag|=4;
						if(point->posY >=  0)				flag|=8;

						if(vert3D[nbPt]->z > zmin)
						{
							zmin = vert3D[nbPt]->z;
							flag|=16;
						}

						if(point->posY < ymin)		ymin = point->posY;
						if(point->posY > ymax)
						{
							ymax  = point->posY;
							pointHaut = nbPoint;
						}

						point->u = u1 * point->posZ;
						point->v = v1 * point->posZ;
						point->light = light[nbPt];

						point++;
						nbPoint++;
					}
					else if(ortho)	// même chose en mode ORTHO
					{
						point->posX = (curCam->dx * vert3D[nbPt]->x) / 10.0f;
						point->posY = (int)(curCam->dy * vert3D[nbPt]->y / 10.0f) + halfY;
						point->posZ = 1;

						if(point->posX <=  halfX)			flag|=1;
						if(point->posX >= -halfX)			flag|=2;
						if(point->posY <=  halfY*2)			flag|=4;
						if(point->posY >=  0)				flag|=8;
						flag|=16;

						if(point->posY < ymin)		ymin = point->posY;
						if(point->posY > ymax)
						{
							ymax  = point->posY;
							pointHaut = nbPoint;
						}

						point->u = u1;
						point->v = v1;
						point->light = light[nbPt];

						point++;
						nbPoint++;
					}

					index = nbPt;

					u0 = u1;
					v0 = v1;
				}

				// 6) Test de validité de la face
				if( (nbPoint<3) || (flag!=31) )
				{
					nbTotalFaces--;
					continue;
				}

				// 7) Ajout de la face à la liste verticale
				curFace->ymax = ymax;
				curFace->ymin = ymin;
				int position;
				position = ymax>curCam->height?curCam->height:ymax;
				position = position<0?0:position;

				curFace->next = SOFTListSorted[position];
				curFace->prev = NULL;
				if(curFace->next)	curFace->next->prev = curFace;
				SOFTListSorted[position] = curFace;

				// 8) Mise à jour des paramètres de la face
				curFace->Npoints = nbPoint;
				curFace->pointG = curFace->pointD = pointHaut;

				if(wired)
				{

					//$LB
					color24 = mater->GetDefaultColor();
					curFace->color24 = color24;
				}
				else
				{

					fog = 0;

					if(zmin < zfog)
					{
						k	 = (16*(zmin+zfog)) / (zfar+zfog+1);
						fog	 = k;
						fog *= 64;
					}

					// 8-1) Table des couleurs
					curFace->transp  = mater->IsOnMode(RENDER_TRANSP);

					// 8-1a) Rendu texturé
					if( (renderMode&RENDER_TEXTURED) && mater->GetTexture1()!=NULL && mater->GetTexture1()->activated )
					{
						//$LB
						ZTexture	*tex = mater->GetTexture1();
						curFace->bitmap24 = tex->bitmap24;
						curFace->width	 = tex->Width;
						curFace->height  = tex->Height;
						curFace->color24 = _COLOR_BGR_TO_I( tex->GetTranspB(), tex->GetTranspG(), tex->GetTranspR());
						curFace->table24 = &palette24[fog<<LOGTABCOL];
					}
					// 8-1b) Rendu non texturé
					else
					{
						//$LB
						curFace->bitmap24 = NULL;

						if(curFace->transp)
						{
							curFace->table24		= mater->transpTab24;
						}
						else
						{
							//$LB
							color24 = mater->GetDefaultColor();
							curFace->color24	= color24;
							curFace->table24	= &palette24[fog<<LOGTABCOL];
						}
					}

					// 9) Fonctions de rendu
					if(curFace->transp)						// Rendu transparent
					{
						//$LB
						if(curFace->bitmap24)
						{
							if(mater->GetCoeffTransp() < 128)		curFace->render = &Render_TRANSP_TEX_1;
							else									curFace->render = &Render_TRANSP_TEX_2;
						}
						else
							curFace->render = &Render_TRANSP_NOTEX;
					}
					else									// Rendu opaque
					{
						if(curFace->bitmap24)						curFace->render = &Render_TEX;
						else									curFace->render = &Render_FLAT;
					}
				}

				curNbFaces++;

			}
		}
	} 

	SOFTList.resize(nbTotalFaces);

#ifdef _BENCH_SOFT_
	profile->EndProfile(7);
	profile->EndProfileCYCLE(7);
#endif

}





void ZWorld::RenderSOFT_Wired(ZCamera *cam, RenderBuffer *buffer, int fond24, bool clear)
{
	int			nbFaceSoft = SOFTList.size();
	ZFaceSOFT	*curFace;
	ZVertSOFT	*vert0, *vert1;

	for(int i=0; i<nbFaceSoft; i++)
	{
		curFace = &SOFTList[i];

		vert0 = &curFace->vert[curFace->Npoints-1];

		for(int k=0; k<curFace->Npoints; k++)
		{
			vert1 = &curFace->vert[k];
			M3Dline(buffer, vert0->posX, vert0->posY, vert1->posX, vert1->posY, curFace->color24);
			vert0 = vert1;
		}
	}
}





void ZWorld::RenderSOFT(ZCamera *cam, RenderBuffer *buffer, int fond24, bool clear)
{
	base = NULL;

	CELL	ZBValue;
	ZBValue.f = -10.0f;

	ZFaceSOFT	*face, *firstface, *lastface;

#ifdef _BENCH_SOFT_
	profile->InitProfile(8);
	profile->InitProfileCYCLE(8);
	profile->InitProfile(9);
	profile->InitProfileCYCLE(9);
#endif

	int	traceHeight;
	if(cam->height < buffer->height)	traceHeight = cam->height;
	else								traceHeight = buffer->height;


	for(int yscan = traceHeight; yscan > 0; yscan--)
    {
		// Effaçage du Zbuffer
		memset(Zbuffer, ZBValue.d, (1+buffer->width) * 4);

		// Update les nouveaux polygones de la ligne courante
		firstface = lastface = face = SOFTListSorted[yscan];
		while(face)
		{
			face->active = true;
			lastface = face;
			face = face->next;
		}

		// Ajoute les nouveaux polygones à la liste
		if(lastface)
		{
			if(base)	base->prev = lastface;
			lastface->next = base;
			base = firstface;
		}


#ifdef _BENCH_SOFT_
		profile->BeginProfile(8);
		profile->BeginProfileCYCLE(8);
#endif

		// Scan de l'ancienne liste de polygones sur la ligne
		face = base;
		while(face!=NULL)
		{
			UpdateFace(face, yscan);
			face = face->next;
		}
#ifdef _BENCH_SOFT_
		profile->AddProfile(8);
		profile->AddProfileCYCLE(8);
		profile->BeginProfile(9);
		profile->BeginProfileCYCLE(9);
#endif

		// Rendu de la ligne
		RenderlineSOFT(buffer, cam, yscan, traceHeight);

#ifdef _BENCH_SOFT_
		profile->AddProfile(9);
		profile->AddProfileCYCLE(9);
#endif
    }


#ifdef _BENCH_SOFT_
	profile->NextProfile(8);
	profile->NextProfile(9);
	profile->NextProfileCYCLE(8);
	profile->NextProfileCYCLE(9);
#endif

}
















#define ERASE_FACE_IN_LIST											\
	if(face->prev)			/* face interne de liste */				\
	{																\
		face->prev->next = face->next;								\
		if(face->next)		face->next->prev = face->prev;			\
	}																\
	else					/* tête de liste */						\
	{																\
		base = face->next;											\
		if(base)	base->prev = NULL;								\
	}






void ZWorld::UpdateFace(ZFaceSOFT *face, int ytab)
{
	// Suppression de la face
	if(face->active==false)
	{
		ERASE_FACE_IN_LIST
		return;
	}

	// Update de la face
	int			y, index1, index2;
	ZVertSOFT	*point1, *point2;


	//*********** Traitement du bord gauche ***********

	index1 = face->pointG;
	point1 = face->vert + index1;

	if(point1->posY < ytab)				// au mileu d'une pente -> update des valeurs du bord gauche
	{
		face->xg	+= face->dxg;
		face->zg	+= face->dzg;
		face->ug	+= face->dug;
		face->vg	+= face->dvg;
		face->lgtg	+= face->dlgtg;
	}
	else								// en début ou fin de pente -> arrêt, ou calcul de la pente suivante
	{
		do
		{
			index2 = index1;
			index1++;
			if(index1 >= face->Npoints)		index1=0;
			point1 = face->vert + index1;
		}
		while( (ytab <= point1->posY) && (ytab > face->ymin) );

		point2 = face->vert + index2;

		face->xg	= point2->posX;
		face->zg	= point2->posZ;
		face->ug	= point2->u;
		face->vg	= point2->v;
		face->lgtg	= point2->light;

		if(ytab == face->ymin)		face->active = false;
		else
		{
			face->pointG = index1;

			y = point2->posY - point1->posY;

			face->dxg   = (point1->posX	 - point2->posX)	/ y;
			face->dzg   = (point1->posZ  - point2->posZ)	/ y;
			face->dug   = (point1->u	 - point2->u)		/ y;
			face->dvg   = (point1->v	 - point2->v)		/ y;
			face->dlgtg = (point1->light - point2->light)	/ y;

			if(point2->posY > ytab)
			{
				y = point2->posY - ytab;

				face->xg   += y * face->dxg;
				face->zg   += y * face->dzg;
				face->ug   += y * face->dug;
				face->vg   += y * face->dvg;
				face->lgtg += y * face->dlgtg;
			}
		}
	}


	//*********** Traitement du bord droit ***********

	index1 = face->pointD;
	point1 = face->vert + index1;

	if(point1->posY < ytab)				// au mileu d'une pente -> update des valeurs du bord gauche
	{
		face->xd	+= face->dxd;
		face->zd	+= face->dzd;
		face->ud	+= face->dud;
		face->vd	+= face->dvd;
		face->lgtd	+= face->dlgtd;
	}
	else								// en début ou fin de pente -> arrêt, ou calcul de la pente suivante
	{
		do
		{
			index2 = index1;
			if(index1==0)		index1 = face->Npoints;
			index1--;
			point1 = face->vert + index1;
		}
		while( (ytab <= point1->posY) && (ytab > face->ymin) );

		point2 = face->vert + index2;

		face->xd	= point2->posX;
		face->zd	= point2->posZ;
		face->ud	= point2->u;
		face->vd	= point2->v;
		face->lgtd	= point2->light;

		if(ytab == face->ymin)		face->active = false;
		else
		{
			face->pointD = index1;

			y = point2->posY - point1->posY;

			face->dxd   = (point1->posX	 - point2->posX)	/ y;
			face->dzd   = (point1->posZ  - point2->posZ)	/ y;
			face->dud   = (point1->u	 - point2->u)		/ y;
			face->dvd   = (point1->v	 - point2->v)		/ y;
			face->dlgtd = (point1->light - point2->light)	/ y;

			if(point2->posY > ytab)
			{
				y = point2->posY - ytab;

				face->xd   += y * face->dxd;
				face->zd   += y * face->dzd;
				face->ud   += y * face->dud;
				face->vd   += y * face->dvd;
				face->lgtd += y * face->dlgtd;
			}
		}
	}

	if(face->xg > face->xd)
	{
		ERASE_FACE_IN_LIST;
	}

}












///////////////////////////////////////////////////////////////////////////////////////
///		RenderlineSOFT																///
///////////////////////////////////////////////////////////////////////////////////////
///
///		Rendu d'une ligne du scanline
///

void ZWorld::RenderlineSOFT(RenderBuffer *rendBuf, ZCamera *cam, int yscan, int traceHeight)
{
	ZFaceSOFT	*face;
	float		xc, xc2;
	float		zc, zc2;
	float		sx;
	OBJBITMAP_BUFFER buf;


	//$LB
	void	(*rend) (OBJBITMAP_BUFFER buffer, CELL *Zbuf, int tailleX, ZFaceSOFT *face, int xa, int xb, float za, float zb, int yscan);

	sx	= (float)(cam->width >>1);

	// Positionnement dans le buffer de rendu
	buf = rendBuf->Image + (traceHeight-yscan) * rendBuf->BPL + ((cam->width*3)>>1);

	// Affichage des polygones opaques
	face = base;

	while(face!=NULL)
    {
		if(!face->transp)
		{
			if( (face->xg<sx) && (face->xd>-sx) && (face->xd>face->xg) )
			{
				// Test clip Gauche
				if ( face->xg > -sx )	// Pas de clip à gauche
				{
					xc  = face->xg;
					zc  = face->zg;
				}
				else				// Clip à gauche
				{
					xc  = -sx;
					zc  = face->zg + (xc - face->xg) * (face->zd - face->zg)/(face->xd - face->xg);
				}

				// Test clip Droite
				if ( face->xd < sx-1 )	// Pas de clip à droite
				{
					xc2 = face->xd;
					zc2 = face->zd;
				}
				else				// Clip à droite
				{
					xc2 = sx-1;
					zc2 = face->zd + (xc2 - face->xd) * (face->zg - face->zd)/(face->xg - face->xd);
				}


				// Rendu de la ligne du polygone
				rend = (void (__cdecl *)(OBJBITMAP_BUFFER,CELL *,int,struct ZFaceSOFT *,int,int,float,float,int)) face->render;
//				if(rend)	(*rend) ( (short*)buf, Zbuffer, 1+(int)sx, face, (int)xc, (int)xc2, zc, zc2, yscan);

				if(	rend==&Render_TRANSP_TEX_1 || rend==&Render_TRANSP_TEX_2 || rend==&Render_TRANSP_NOTEX || rend==&Render_TEX || rend==&Render_FLAT )	
					(*rend) ( (OBJBITMAP_BUFFER)buf, Zbuffer, 1+(int)sx, face, (int)xc, (int)xc2, zc, zc2, yscan);
			}
		}
		face = face->next;
    }

	// Affichage des polygones avec une couleur de transparence
	face = base;

	while(face!=NULL)
    {
		if (face->render == &Render_TRANSP_TEX_1)
		{
			if ( (face->xg<sx) && (face->xd>-sx) && (face->xd>face->xg) )
			{
				// Test clip Gauche
				if ( face->xg > -sx )	// Pas de clip à gauche
				{
					xc  = face->xg;
					zc  = face->zg;
				}
				else				// Clip à gauche
				{
					xc  = -sx;
					zc  = face->zg + (xc - face->xg) * (face->zd - face->zg)/(face->xd - face->xg);
				}

				// Test clip Droite
				if ( face->xd < sx-1 )	// Pas de clip à droite
				{
					xc2 = face->xd;
					zc2 = face->zd;
				}
				else				// Clip à droite
				{
					xc2 = sx-1;
					zc2 = face->zd + (xc2 - face->xd) * (face->zg - face->zd)/(face->xg - face->xd);
				}


				// Rendu de la ligne du polygone
				rend = (void (__cdecl *)(OBJBITMAP_BUFFER,CELL *,int,struct ZFaceSOFT *,int,int,float,float,int)) face->render;

				if(	rend==&Render_TRANSP_TEX_1 || rend==&Render_TRANSP_TEX_2 || rend==&Render_TRANSP_NOTEX || rend==&Render_TEX || rend==&Render_FLAT )	
					(*rend) ( (OBJBITMAP_BUFFER)buf, Zbuffer, 1+(int)sx, face, (int)xc, (int)xc2, zc, zc2, yscan);
			}
		}
		face = face->next;
    }

	// Affichage des polygones transparents
	face = base;
	while(face!=NULL)
    {
		if ( (face->render == &Render_TRANSP_NOTEX) || (face->render == &Render_TRANSP_TEX_2) )
		{
			if ( (face->xg<sx) && (face->xd>-sx) && (face->xd>face->xg) )
			{
				// Test clip Gauche
				if ( face->xg > -sx )	// Pas de clip à gauche
				{
					xc  = face->xg;
					zc  = face->zg;
				}
				else				// Clip à gauche
				{
					xc  = -sx;
					zc  = face->zg + (xc - face->xg) * (face->zd - face->zg)/(face->xd - face->xg);
				}
				
				// Test clip Droite
				if ( face->xd < sx-1 )	// Pas de clip à droite
				{
					xc2 = face->xd;
					zc2 = face->zd;
				}
				else				// Clip à droite
				{
					xc2 = sx-1;
					zc2 = face->zd + (xc2 - face->xd) * (face->zg - face->zd)/(face->xg - face->xd);
				}



				// Rendu de la ligne du polygone
				rend = (void (__cdecl *)(OBJBITMAP_BUFFER,CELL *,int,struct ZFaceSOFT *,int,int,float,float,int)) face->render;

				if(	rend==&Render_TRANSP_TEX_1 || rend==&Render_TRANSP_TEX_2 || rend==&Render_TRANSP_NOTEX || rend==&Render_TEX || rend==&Render_FLAT )	
					(*rend) ( (OBJBITMAP_BUFFER)buf, Zbuffer, 1+(int)sx, face, (int)xc, (int)xc2, zc, zc2, yscan);
			}
		}
		face = face->next;
    }

}


















///////////////////////////////////////////////////////////////////////////////////////////////
///		PreComputeMatrices																	///
///////////////////////////////////////////////////////////////////////////////////////////////
void ZWorld::RecursComputeMatrices(ZNodeGraph* activeCam, ZNodeGraph*  baseNode, const ZMatrix &refMat, float refScale, bool rangeOK)
{
	ZNodeGraph*		curNode;
	curNode = (ZNodeGraph*) (baseNode->son);
	float			distSQR;


	while(curNode != NULL)
	{
		ZPRS*		curPRS;
		curPRS = curNode->GetPRS();

		// Compute the final matrix
		curNode->worldMat = refMat * curPRS->mat;

		// Compute the final scale
		curNode->worldScale = refScale * curPRS->GetScale();

		// Compute the world position
		curNode->worldPos.SetCoord(curNode->worldMat(0,3), curNode->worldMat(1,3), curNode->worldMat(2,3));

		distSQR = curNode->worldPos.SqLength();


		curNode->rangeOK = true;
		
		if(rangeOK)
		{
			if( (distSQR >= curNode->rangeMIN) && ((distSQR <= curNode->rangeMAX)||(curNode->rangeMAX < 0.0f)) )
				curNode->rangeOK = true;
			else
				curNode->rangeOK = false;
		}
		else
			curNode->rangeOK = false;

		if(curNode->type==OBJ_TYPE_ID)		((ZObject*)curNode)->ChooseGoodMesh(distSQR);

		// Test of recursion
			 if( curNode==activeCam   )		RecursComputeMatrices(activeCam, curNode, IdentityMatrix(), 1.0f, curNode->rangeOK);
		else if( curNode->son != NULL )		RecursComputeMatrices(activeCam, curNode, curNode->worldMat, curNode->worldScale, curNode->rangeOK);

		curNode = (ZNodeGraph*) curNode->next;
	}
}




///////////////////////////////////////////////////////////////////////////////////////////////
// Fonction qui traite le premier élément et qui appelle la fonction de récursion ci-dessus	 //
///////////////////////////////////////////////////////////////////////////////////////////////
void ZWorld::ComputeMatrices(ZNodeGraph* activeCam, ZNodeGraph*  baseNode, const ZMatrix &refMat, float refScale, bool rangeOK)
{
	ZPRS*		curPRS;
	float		distSQR;

	curPRS = baseNode->GetPRS();

	// Compute the final matrix
	baseNode->worldMat = refMat * curPRS->mat;

	// Compute the final scale
	baseNode->worldScale = refScale * curPRS->GetScale();

	// Compute the world position
	baseNode->worldPos.SetCoord(baseNode->worldMat(0,3), baseNode->worldMat(1,3), baseNode->worldMat(2,3));

	distSQR = baseNode->worldPos.SqLength();

	baseNode->rangeOK = true;
	
	if(rangeOK)
	{
		if( (distSQR >= baseNode->rangeMIN) && ((distSQR <= baseNode->rangeMAX)||(baseNode->rangeMAX < 0.0f)) )
			baseNode->rangeOK = true;
		else
			baseNode->rangeOK = false;
	}
	else
		baseNode->rangeOK = false;

	if(baseNode->type==OBJ_TYPE_ID)		((ZObject*)baseNode)->ChooseGoodMesh(distSQR);

	// Test of recursion
		 if( baseNode==activeCam  )		RecursComputeMatrices(activeCam, baseNode, IdentityMatrix(), 1.0f, baseNode->rangeOK);
	else if( baseNode->son!= NULL )		RecursComputeMatrices(activeCam, baseNode, baseNode->worldMat, baseNode->worldScale, baseNode->rangeOK);
}




///////////////////////////////////////////////////////////////////////////////////////////////
/// TransformVertices()																		///
///																							///
///		This function render one sequence of object on the screen							///
///																							///
///////////////////////////////////////////////////////////////////////////////////////////////

void ZWorld::TransformVertices()
{
	// Transform all vertices
	ZObject	*curObj;
	for(int i=0; i<objList.Size(); i++)			
	{
		curObj = objList[i];

		// PEUT ETRE PROBLEMATIQUE POUR LES OBJETS AVEC VERTICES PARTAGES !!!
		// CAR LE CULLING IMPOSE QUE LES OBJETS NON VISIBLES N'ONT AUCUN VERTICES CALCULES !!!!
		
		//if(curObj->visible)		curObj->TransformAllVerts(curObj->worldMat);
		curObj->TransformAllVerts();
	}
}



void ZWorld::ComputeNormals(bool accel)
{
	ZObject		*curObj;
	ZMesh		*curMesh;

	for(int i=0; i<objList.Size(); i++)
	{
		curObj  = objList[i];
		curMesh = curObj->GetMesh();

		curObj->normalsTransformed = false;

		if(curMesh)
		{
			// Transformation des normales pour les DEPENDENCY
			if(curMesh->dependency==true)
			{
				curMesh->CreateFacesNormalsShared(curObj);
				curMesh->CreateVertsNormals();
			}
			// Transforme les normales dans le cas NOT DEPENDENCY
			// Stocke les normales *déjà* transformées dans le cas DEPENDENCY
			if( (accel==false) || (curMesh->dependency==true) || (curMesh->displayListCreate==false))
			{
				curObj->TransformNormals();
				curObj->normalsTransformed = true;
			}
		}
	}
}



///////////////////////////////////////////////////////////////////////////////////////////////
/// IntersectTriangle()																		///
///																							///
///		This function testa triangle intersection with a line (vector+point)				///
///																							///
///////////////////////////////////////////////////////////////////////////////////////////////

#define	TEST_CULL

bool IntersectTriangle(const ZVector3 &orig, const ZVector3 &dir, const ZVector3 &vert0, const ZVector3 &vert1, const ZVector3 &vert2, float *_t, float *_u, float *_v)
{
	ZVector3	edge1, edge2, tvec, pvec, qvec;
	float		det, inv_det;
	float		t, u, v;

	// find vectors for two edges sharing vert0
	edge1 = vert1 - vert0;
	edge2 = vert2 - vert0;

	// begin calculating determinant - also used to calculate U parameter
	pvec = dir ^ edge2;

	// if determinant is near zero, ray lies in plane of triangle
	det = edge1 * pvec;


	// ----------- Define TEST_CULL if culling is desired -----------
#ifdef TEST_CULL           


	if (det < 0.000001f)			return false;

	// calculate distance from vert0 to ray origin
	tvec = orig - vert0;

	// calculate U parameter and test bounds
	u = tvec * pvec;
	if (u<0.0f || u>det)			return false;

	// prepare to test V parameter
	qvec = tvec ^ edge1;

	// calculate V parameter and test bounds
	v = dir * qvec;
	if (v<0.0f || u+v>det)			return false;

	// calculate t, scale parameters, ray intersects triangle
	t = edge2 * qvec;
	inv_det = 1.0f / det;
	u *= inv_det;
	v *= inv_det;
	t *= inv_det;
	//t *= 0.1f;

	// ------------------- The non-culling branch -------------------
#else

	if (det > -0.000001f && det < 0.000001f)	return false;
	inv_det = 1.0f / det;

	// calculate distance from vert0 to ray origin
	tvec = orig - vert0;

	// calculate U parameter and test bounds
	u = (tvec * pvec) * inv_det;
	if (u<0.0f || u>1.0f)						return false;

	// prepare to test V parameter
	qvec = tvec ^ edge1;

	// calculate V parameter and test bounds
	v = (dir * qvec) * inv_det;
	if (v<0.0f || u+v>1.0f)						return false;

	// calculate t, ray intersects triangle
	t = (edge2 * qvec) * inv_det;

#endif
	// --------------------------------------------------------------

	if (_t)		*_t = t;
	if (_u)		*_u = u;
	if (_v)		*_v = v;

	return true;
}



///////////////////////////////////////////////////////////////////////////////////////////////
/// TestObject()																			///
///																							///
///		This function test an oject intersection with a ray (test the BBOX before)			///
///																							///
///////////////////////////////////////////////////////////////////////////////////////////////

bool TestObject(ZMatrix &camMat, ZObject* curObj, const ZVector3 &orig, const ZVector3 &ray, float* dist, float distMin, float* u, float* v, float* z, int* faceNb)
{
	ZVector3	coin0, coin1, coin2, coin3, coin4, coin5, coin6, coin7;
	bool		test = false;
	float		dist_tmp;

	ZMesh		*curMesh = curObj->GetMesh();

	coin0.SetCoord(curMesh->xmin, curMesh->ymin, curMesh->zmin);		coin0 *= curObj->worldMat;
	coin1.SetCoord(curMesh->xmax, curMesh->ymin, curMesh->zmin);		coin1 *= curObj->worldMat;
	coin2.SetCoord(curMesh->xmin, curMesh->ymax, curMesh->zmin);		coin2 *= curObj->worldMat;
	coin3.SetCoord(curMesh->xmax, curMesh->ymax, curMesh->zmin);		coin3 *= curObj->worldMat;
	coin4.SetCoord(curMesh->xmin, curMesh->ymin, curMesh->zmax);		coin4 *= curObj->worldMat;
	coin5.SetCoord(curMesh->xmax, curMesh->ymin, curMesh->zmax);		coin5 *= curObj->worldMat;
	coin6.SetCoord(curMesh->xmin, curMesh->ymax, curMesh->zmax);		coin6 *= curObj->worldMat;
	coin7.SetCoord(curMesh->xmax, curMesh->ymax, curMesh->zmax);		coin7 *= curObj->worldMat;


	// Test first triangle of BBOX
	if (!test)
	{
		test = IntersectTriangle(orig, ray, coin0, coin1, coin3, &dist_tmp, NULL, NULL);
		if(!test)	test = IntersectTriangle(orig, ray, coin0, coin3, coin1, &dist_tmp, NULL, NULL);
	}

	// Test second triangle of BBOX
	if (!test)
	{
		test = IntersectTriangle(orig, ray, coin0, coin3, coin2, &dist_tmp, NULL, NULL);
		if(!test)	test = IntersectTriangle(orig, ray, coin0, coin2, coin3, &dist_tmp, NULL, NULL);
	}

	// Test 3 triangle of BBOX
	if (!test)
	{
		test = IntersectTriangle(orig, ray, coin4, coin5, coin7, &dist_tmp, NULL, NULL);
		if(!test)	test = IntersectTriangle(orig, ray, coin4, coin7, coin5, &dist_tmp, NULL, NULL);
	}

	// Test 4 triangle of BBOX
	if (!test)
	{
		test = IntersectTriangle(orig, ray, coin4, coin7, coin6, &dist_tmp, NULL, NULL);
		if(!test)	test = IntersectTriangle(orig, ray, coin4, coin6, coin7, &dist_tmp, NULL, NULL);
	}

	// Test 5 triangle of BBOX
	if (!test)
	{
		test = IntersectTriangle(orig, ray, coin0, coin4, coin6, &dist_tmp, NULL, NULL);
		if(!test)	test = IntersectTriangle(orig, ray, coin0, coin6, coin4, &dist_tmp, NULL, NULL);
	}

	// Test 6 triangle of BBOX
	if (!test)
	{
		test = IntersectTriangle(orig, ray, coin0, coin6, coin2, &dist_tmp, NULL, NULL);
		if(!test)	test = IntersectTriangle(orig, ray, coin0, coin2, coin6, &dist_tmp, NULL, NULL);
	}

	// Test 7 triangle of BBOX
	if (!test)
	{
		test = IntersectTriangle(orig, ray, coin1, coin5, coin7, &dist_tmp, NULL, NULL);
		if(!test)	test = IntersectTriangle(orig, ray, coin1, coin7, coin5, &dist_tmp, NULL, NULL);
	}

	// Test 8 triangle of BBOX
	if (!test)
	{
		test = IntersectTriangle(orig, ray, coin1, coin7, coin3, &dist_tmp, NULL, NULL);
		if(!test)	test = IntersectTriangle(orig, ray, coin1, coin3, coin7, &dist_tmp, NULL, NULL);
	}

	// Test 9 triangle of BBOX
	if (!test)
	{
		test = IntersectTriangle(orig, ray, coin2, coin3, coin7, NULL, NULL, NULL);
		if(!test)	test = IntersectTriangle(orig, ray, coin2, coin7, coin3, &dist_tmp, NULL, NULL);
	}

	// Test 10 triangle of BBOX
	if (!test)
	{
		test = IntersectTriangle(orig, ray, coin2, coin7, coin6, NULL, NULL, NULL);
		if(!test)	test = IntersectTriangle(orig, ray, coin2, coin6, coin7, &dist_tmp, NULL, NULL);
	}

	// Test 11 triangle of BBOX
	if (!test)
	{
		test = IntersectTriangle(orig, ray, coin0, coin5, coin2, NULL, NULL, NULL);
		if(!test)	test = IntersectTriangle(orig, ray, coin0, coin2, coin5, &dist_tmp, NULL, NULL);
	}

	// Test 12 triangle of BBOX
	if (!test)
	{
		test = IntersectTriangle(orig, ray, coin0, coin5, coin4, NULL, NULL, NULL);
		if(!test)	test = IntersectTriangle(orig, ray, coin0, coin4, coin5, &dist_tmp, NULL, NULL);
	}

	

	int			ref, nbVert;
	ZObject		*pere;
	ZVector3	*vertShared[3];

	ZFace *curFace;
	// test the entire object if its BBOX is in a good place
	if (test)
	{
		test = false;
		
		ZMesh*	mesh;
		mesh = curObj->GetMesh();

		vector<ZFace>	*faces;
		faces = &(mesh->Faces);

		vector<ZVector3>	*verts;
		verts = &(curObj->VertsTransf);

		float		Utmp, Vtmp;
		float		a, b, c, d, e, f;
		float		z0, z1, z2;
		ZVector3	posTmp;

		for(int i=0; i<mesh->NbFaces; i++)
		{
			curFace = &((*faces)[i]);
			
			if(curFace->dependency)
			{
				// find the vertex 0
				ref = curFace->VertRef[0];
				pere = curObj;
				nbVert = curObj->GetMesh()->NbVerts;
				while(ref >= nbVert)
				{
					ref -= nbVert;
					pere = (ZObject*) pere->father;
					nbVert = pere->GetMesh()->NbVerts;
				}
				vertShared[0] = &(pere->VertsTransf[ref]);

				// find the vertex 1
				ref = curFace->VertRef[1];
				pere = curObj;
				nbVert = curObj->GetMesh()->NbVerts;
				while(ref >= nbVert)
				{
					ref -= nbVert;
					pere = (ZObject*) pere->father;
					nbVert = pere->GetMesh()->NbVerts;
				}
				vertShared[1] = &(pere->VertsTransf[ref]);

				// find the vertex 2
				ref = curFace->VertRef[2];
				pere = curObj;
				nbVert = curObj->GetMesh()->NbVerts;
				while(ref >= nbVert)
				{
					ref -= nbVert;
					pere = (ZObject*) pere->father;
					nbVert = pere->GetMesh()->NbVerts;
				}
				vertShared[2] = &(pere->VertsTransf[ref]);

				if( IntersectTriangle(orig, ray, *(vertShared[0]), *(vertShared[1]), *(vertShared[2]), &dist_tmp, &Utmp, &Vtmp) )
				{
					if( (dist_tmp < *dist) && (dist_tmp > distMin) )
					{
						if(faceNb)	*faceNb = i;
						*dist = dist_tmp;
						
						if(u)
						{
							a = curFace->UV1[0].u;		
							c = curFace->UV1[2].u;		
							e = curFace->UV1[1].u;		
							*u = Utmp*(e-a) + Vtmp*(c-a) + a;
						}
						if(v)
						{
							b = curFace->UV1[0].v;
							d = curFace->UV1[2].v;
							f = curFace->UV1[1].v;
							*v = Utmp*(f-b) + Vtmp*(d-b) + b;
						}
						if(z)
						{
							a = vertShared[0]->x;		
							c = vertShared[1]->x;		
							e = vertShared[2]->x;
							posTmp.x = Utmp*(e-a) + Vtmp*(c-a) + a;
							
							a = vertShared[0]->y;		
							c = vertShared[1]->y;		
							e = vertShared[2]->y;
							posTmp.y = Utmp*(e-a) + Vtmp*(c-a) + a;

							z0 = vertShared[0]->z;
							z1 = vertShared[1]->z;
							z2 = vertShared[2]->z;
							//*z = Utmp*(z1-z0) + Vtmp*(z2-z0) + z0;
							posTmp.z = Utmp*(z1-z0) + Vtmp*(z2-z0) + z0;

							posTmp *= camMat;
							*z = posTmp.z;
						}

						test = true;
					}
				}
			}
			else
			// and if vertices are not shared !! classic test..
			{
				if( IntersectTriangle(orig, ray, (*verts)[curFace->VertRef[0]], (*verts)[curFace->VertRef[1]], (*verts)[curFace->VertRef[2]], &dist_tmp, &Utmp, &Vtmp) )
				{
					if( (dist_tmp < *dist) && (dist_tmp > distMin) )
					{
						if(faceNb)	*faceNb = i;
						*dist = dist_tmp;

						if(u)
						{
							a = curFace->UV1[0].u;		
							c = curFace->UV1[2].u;		
							e = curFace->UV1[1].u;		
							*u = Utmp*(e-a) + Vtmp*(c-a) + a;
						}
						if(v)
						{
							b = curFace->UV1[0].v;
							d = curFace->UV1[2].v;
							f = curFace->UV1[1].v;
							*v = Utmp*(f-b) + Vtmp*(d-b) + b;
						}
						if(z)
						{
							a = (*verts)[curFace->VertRef[0]].x;
							c = (*verts)[curFace->VertRef[1]].x;
							e = (*verts)[curFace->VertRef[2]].x;
							posTmp.x = Utmp*(e-a) + Vtmp*(c-a) + a;
							
							a = (*verts)[curFace->VertRef[0]].y;
							c = (*verts)[curFace->VertRef[1]].y;
							e = (*verts)[curFace->VertRef[2]].y;
							posTmp.y = Utmp*(e-a) + Vtmp*(c-a) + a;

							z0 = (*verts)[curFace->VertRef[0]].z;
							z1 = (*verts)[curFace->VertRef[1]].z;
							z2 = (*verts)[curFace->VertRef[2]].z;
							//*z = Utmp*(z1-z0) + Vtmp*(z2-z0) + z0;
							posTmp.z = Utmp*(z1-z0) + Vtmp*(z2-z0) + z0;

							posTmp *= camMat;
							*z = posTmp.z;
						}
						test = true;
					}
				}
			}
		}
	}
	return test;
}


//$$BLG
///////////////////////////////////////////////////////////////////////////////////////////////
/// BLG_TestSprObject()
///
/// This function tests a sprite intersection with a ray
///
///////////////////////////////////////////////////////////////////////////////////////////////
bool BLG_TestSprObject(ZSprite* curSpr, const ZVector3 &orig, const ZVector3 &ray, float* dist, float distMin, float blg_ActiveCamRotZ)
{
	ZVector3	coin0, coin1, coin2, coin3;
	bool		test = false;
	float		dist_tmp;

  float	halfW = curSpr->halfW;
  float halfH = curSpr->halfH;
  
  ZVector3	*pos;
  pos = &(curSpr->worldPos);
  float xs = pos->x;
  float ys = pos->y;
  float zs = pos->z;
  
  float x0, x1, y0, y1, z0, z1;
  float angle;

  if (curSpr->CameraOriented)
  	angle = -blg_ActiveCamRotZ + curSpr->rotationZ;
  else
  	angle = curSpr->rotationZ;
  x0 = xs - (halfW * cos(angle));
  x1 = xs + (halfW * cos(angle));
  y0 = ys - halfH;
  y1 = ys + halfH;
  z0 = zs - (halfW * sin(angle));;
  z1 = zs + (halfW * sin(angle));;

	coin0.SetCoord(x0, y0, z0);		//coin0 *= curSpr->worldMat;
	coin1.SetCoord(x1, y0, z1);		//coin1 *= curSpr->worldMat;
	coin2.SetCoord(x1, y1, z1);		//coin2 *= curSpr->worldMat;
	coin3.SetCoord(x0, y1, z0);		//coin3 *= curSpr->worldMat;

	// Test first triangle
	if (!test)
	{
		test = IntersectTriangle(orig, ray, coin0, coin1, coin2, &dist_tmp, NULL, NULL);
		if(!test)	test = IntersectTriangle(orig, ray, coin0, coin2, coin1, &dist_tmp, NULL, NULL);
	}
	// Test second triangle
	if (!test)
	{
		test = IntersectTriangle(orig, ray, coin0, coin2, coin3, &dist_tmp, NULL, NULL);
		if(!test)	test = IntersectTriangle(orig, ray, coin0, coin3, coin2, &dist_tmp, NULL, NULL);
	}

  if (test && (dist_tmp < *dist) && (dist_tmp > distMin))
		*dist = dist_tmp;

	return test;
}


///////////////////////////////////////////////////////////////////////////////////////////////
/// SelectionTest()																			///
///																							///
///		This function test all the objects intersection with a specific ray					///
///																							///
///////////////////////////////////////////////////////////////////////////////////////////////
//$BLG
/*
void ZWorld::SelectionTest(ZMatrix &camMat, const ZVector3 &orig, const ZVector3 &ray, float* dist, float distMin, float* u, float* v, float* z, ZObject**	result, int* faceNb)
{
	for(int i=0; i<objList.Size(); i++)
	{
		if( objList[i]->visible && objList[i]->clickable && objList[i]->GetMesh() )
			  if ( TestObject(camMat, objList[i], orig, ray, dist, distMin, u, v, z, faceNb) )		*result = objList[i];
	}
}
*/
//$BLG
void ZWorld::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)
{
	for(int i=0; i<objList.Size(); i++)
	{
		if (objList[i]->visible && objList[i]->clickable && objList[i]->GetMesh())
			if (TestObject(camMat, objList[i], orig, ray, dist, distMin, u, v, z, faceNb))
			  result->blg_objspr_obj = objList[i];
	}
	for(i=0; i<sprList.Size(); i++)
	{
		if (sprList[i]->blg_sprClickable)
		  if (BLG_TestSprObject(sprList[i], orig, ray, dist, distMin, blg_ActiveCamRotZ))
		  {
		  	result->blg_objspr_obj = NULL;
		  	result->blg_objspr_spr = sprList[i];
		  }
	}
}



//$BLG
//Retrieves cell ambient light factor (-0.50 -> 0.50) (0.0 is Scol light 32)
//Added in v4.6a2
//Removed in v4.6a3: Brought more problems than solutions, especially with ColorLights.
///////////////////////////////////////////////////////////////////////////////////////////////
// BLG_GetAmbientLight
///////////////////////////////////////////////////////////////////////////////////////////////
/*
float ZWorld::BLG_GetAmbientLight()
{
	float ret;
	int n;
	
	ret = 0.0f;
	n = 0;
	for(int i = 0; i < lghList.Size(); i++)
	{
		if (lghList[i]->LightType == LIGHT_AMBIENT)  
		{
			ret += lghList[i]->ambient[0];
			n++;
		}
	}
	ret /= n;

	return ret;
}
*/


///////////////////////////////////////////////////////////////////////////////////////////////
///		PutLightSettings																	///
///////////////////////////////////////////////////////////////////////////////////////////////
void ZWorld::PutLightSettings(const ZMatrix &matCam)
{
	if(lghList.Size()==0)
	{
		// Light par défault : de type PARA, dirigée suivant l'axe Z (de SCOL)
		glEnable(GL_LIGHT0);

		// Direction de la PARA (suivant Z -> derniere colone de la matrice)
		ZVector4	LightDir;
		LightDir.SetCoord(matCam._13, matCam._23, matCam._33, 0.0f);
		glLightfv(GL_LIGHT0, GL_POSITION, LightDir.vals);

		GLfloat		tmpParam1[] = { 0.0f, 0.0f, 0.0f, 1.0f};
		GLfloat		tmpParam2[] = { 0.45f, 0.45f, 0.45f, 1.0f};
		glLightfv(GL_LIGHT0, GL_AMBIENT,  tmpParam1);
		glLightfv(GL_LIGHT0, GL_DIFFUSE,  tmpParam2);
		glLightfv(GL_LIGHT0, GL_SPECULAR, tmpParam1);

		glLightf(GL_LIGHT0, GL_SPOT_EXPONENT, 0.0f);
		glLightf(GL_LIGHT0, GL_SPOT_CUTOFF,	180.0f);

		glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION,  1.0f);
		glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION,	0.0f);
		glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, 0.0f);

		GLfloat ambient[] = { 0.25f, 0.25f, 0.25f, 1.0f};
		glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient);

		for(int i=1; i<8; i++)						glDisable(GL_LIGHT0+i);
	}
	else
	{
		// Eclairage SCOL
		GLfloat ambient[] = { 0.45f, 0.45f, 0.45f, 1.0f};

		for(int i=0; i<lghList.Size(); i++)
		{
			lghList[i]->PutGLparams(i);		// Put the openGL parameters for the light
			
			if(lghList[i]->oldStyle)
			{
				ambient[0] += lghList[i]->ambient[0];
				ambient[1] += lghList[i]->ambient[1];
				ambient[2] += lghList[i]->ambient[2];
			}
		}

		glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient);

		for(i=lghList.Size(); i<8; i++)				glDisable(GL_LIGHT0+i);
	}
}






/*

///////////////////////////////////////////////////////////////////////////////////////////////
/// DetectCollision()																		///
///																							///
///		This function render one sequence of object on the screen							///
///																							///
///////////////////////////////////////////////////////////////////////////////////////////////
void ZWorld::DetectCollision()
{
	int			tailleListe = objList.size();
	ZObject		*obj1, *obj2;
	ZMesh		*mesh1, *mesh2;
	ZPRS		*prs;
	ZMatrix		mat;
	float		R1[3][3], R2[3][3], T1[3], T2[3], scale1, scale2;

	R1[0][0] = R1[1][1] = R1[2][2] = 1.0;
	R1[0][1] = R1[1][0] = R1[2][0] = 0.0;
	R1[0][2] = R1[1][2] = R1[2][1] = 0.0;

	R2[0][0] = R2[1][1] = R2[2][2] = 1.0;
	R2[0][1] = R2[1][0] = R2[2][0] = 0.0;
	R2[0][2] = R2[1][2] = R2[2][1] = 0.0;


	float		V1[3], V2[3];

	// Re-init of all the collision flags
	for(int i=0; i<tailleListe; i++)		
	{
		objList[i]->inCollision		= false;
		objList[i]->blocked			= false;
		objList[i]->coeff_collide	= 2.0f;			// temporary init for NON translation-collision detecting
		//objList[i]->self_TriID_collide = objList[i]->othe_TriID_collide = -1;
		
		objList[i]->transl = objList[i]->worldPos - objList[i]->worldLastPos;

		objList[i]->obj_collide = NULL;
	}


	bool	coeffChanged;

	// Collision test -> first object
	for(i=0; i<tailleListe; i++)
	{
		obj1  = objList[i];
		
		// if the object is in collide-mode
		if(obj1->IsOnMode(COLLIDE_ON))
		{
			mesh1 = obj1->GetMesh();

			prs   = obj1->GetPRS();

			for(int k=0; k<3; k++)		for(int l=0; l<3; l++)		R1[l][k] = obj1->worldMat(k,l)/obj1->worldScale;

			scale1 = obj1->worldScale;

			T1[0] = obj1->worldLastPos.x;		
			T1[1] = obj1->worldLastPos.y;			
			T1[2] = obj1->worldLastPos.z;

			do
			{
				coeffChanged = false;

				// Collision test -> second object
				for(int j=i+1; j<tailleListe; j++)
				{
					obj2 = objList[j];

					// if the object is in collide mode
					if(obj2->IsOnMode(COLLIDE_ON))
					{
						mesh2 = obj2->GetMesh();

						prs = obj2->GetPRS();

						for(int k=0; k<3; k++)		for(int l=0; l<3; l++)		R2[l][k] = obj2->worldMat(k,l)/obj2->worldScale;

						scale2 = obj2->worldScale;

						T2[0] = obj2->worldLastPos.x;		
						T2[1] = obj2->worldLastPos.y;			
						T2[2] = obj2->worldLastPos.z;

						if((obj1->coeff_collide>1.5f)&&(obj2->coeff_collide>1.5f))
						{
							V1[0] = obj1->transl.x;			V1[1] = obj1->transl.y;			V1[2] = obj1->transl.z;
							V2[0] = obj2->transl.x;			V2[1] = obj2->transl.y;			V2[2] = obj2->transl.z;
						}
						else
						if(obj1->coeff_collide>1.5f)
						{
							V1[0] = obj1->transl.x;			
							V1[1] = obj1->transl.y;			
							V1[2] = obj1->transl.z;
							V2[0] = obj2->transl.x * (obj2->coeff_collide*0.90f);			
							V2[1] = obj2->transl.y * (obj2->coeff_collide*0.90f);			
							V2[2] = obj2->transl.z * (obj2->coeff_collide*0.90f);
						}
						else
						if(obj2->coeff_collide>1.5f)
						{
							V1[0] = obj1->transl.x * (obj1->coeff_collide*0.90f);			
							V1[1] = obj1->transl.y * (obj1->coeff_collide*0.90f);			
							V1[2] = obj1->transl.z * (obj1->coeff_collide*0.90f);
							V2[0] = obj2->transl.x;			
							V2[1] = obj2->transl.y;			
							V2[2] = obj2->transl.z;
						}
						else
						{
							V1[0] = obj1->transl.x * (obj1->coeff_collide*0.90f);			
							V1[1] = obj1->transl.y * (obj1->coeff_collide*0.90f);			
							V1[2] = obj1->transl.z * (obj1->coeff_collide*0.90f);

							V2[0] = obj2->transl.x * (obj2->coeff_collide*0.90f);			
							V2[1] = obj2->transl.y * (obj2->coeff_collide*0.90f);			
							V2[2] = obj2->transl.z * (obj2->coeff_collide*0.90f);
						}
							
						RAPID_Collide_trans(R1, T1, scale1, V1, mesh1->rapid, R2, T2, scale2, V2, mesh2->rapid, RAPID_ALL_CONTACTS);

						// if there is a contact
						if(RAPID_num_contacts)
						{
							// et si collision en translation
							if(RAPID_is_contact_trans==1)
							{
								// Si les deux postulent simultanément pour une collision
								if( (RAPID_coeff<obj1->coeff_collide) && (RAPID_coeff<obj2->coeff_collide) )
								{
									obj1->coeff_collide = obj2->coeff_collide = RAPID_coeff;
									coeffChanged = true;

									obj1->obj_collide	= obj2;
									obj2->obj_collide	= obj1;

									obj1->self_TriID_collide = obj2->othe_TriID_collide = RAPID_tri_id1;
									obj1->othe_TriID_collide = obj2->self_TriID_collide = RAPID_tri_id2;
									
									obj1->inCollision = obj2->inCollision = true;

									if(RAPID_axid2==1)
									{
										obj2->axis = mesh2->Faces[RAPID_tri_id2].Normal * obj2->worldRot;
										obj2->axis.Normalize();
										obj1->axis = obj2->axis;
									}
									else
									if(RAPID_axid2==2)
									{
										obj2->axis = mesh1->Faces[RAPID_tri_id1].Normal * obj1->worldRot;
										obj2->axis.Normalize();
										obj1->axis = obj2->axis;
									}
								}
								else
								// Si un seul postule pour la collision -> l'autre est déjà en collision + proche -> on teste la collision
								if((RAPID_coeff < obj1->coeff_collide))
								{
									obj1->coeff_collide = RAPID_coeff;
									coeffChanged = true;
									obj1->obj_collide	= obj2;

									obj1->self_TriID_collide = RAPID_tri_id1;
									obj1->othe_TriID_collide = RAPID_tri_id2;
									
									if(RAPID_axid2==1)
									{
										obj1->axis = mesh2->Faces[RAPID_tri_id2].Normal * obj2->worldRot;
										obj1->axis.Normalize();
									}
									else
									if(RAPID_axid2==2)
									{
										obj1->axis = mesh1->Faces[RAPID_tri_id1].Normal * obj1->worldRot;
										obj1->axis.Normalize();
									}

									obj1->inCollision = true;
								}
								else
								// Si un seul postule pour la collision - l'autre est déjà en collision + proche
								if((RAPID_coeff < obj2->coeff_collide))
								{
									obj2->coeff_collide = RAPID_coeff;
									obj2->obj_collide	= obj1;

									obj2->self_TriID_collide = RAPID_tri_id2;
									obj2->othe_TriID_collide = RAPID_tri_id1;
									
									if(RAPID_axid2==1)
									{
										obj2->axis = mesh2->Faces[RAPID_tri_id2].Normal * obj2->worldRot;
										obj2->axis.Normalize();
									}
									else
									if(RAPID_axid2==2)
									{
										obj2->axis = mesh1->Faces[RAPID_tri_id1].Normal * obj1->worldRot;
										obj2->axis.Normalize();
									}

									obj2->inCollision = true;
								}
							}
							else
							if(RAPID_is_contact_trans == -1)	// cas de prime intersection
							{
								obj1->inCollision = obj2->inCollision = true;
								obj1->blocked = obj2->blocked = true;
								obj1->coeff_collide = obj2->coeff_collide = 0.0f;
								obj1->transl.SetNull();
								obj2->transl.SetNull();
							}
						}
					}
				}
			}
			while(coeffChanged);
		}
	}

	ZVector3	localTransl;

	for(i=0; i<tailleListe; i++)		
	{
		obj1 = objList[i];

		if(obj1->inCollision)
		{
			// Collision en translation - on translate de ce qu'il faut, avec une petite marge d'erreur sur les flottants :)
			if(!obj1->blocked)
			{
				prs = obj1->GetPRS();
				float	compoAxis  = prs->vites * obj1->axis;
				prs->vites = prs->vites - 2*compoAxis*obj1->axis;

				if(obj1->coeff_collide<1.0f)
				{
					obj1->worldPos = obj1->worldLastPos + (obj1->coeff_collide*0.90f) * obj1->transl;

					localTransl = prs->pos - prs->lastPos;
					prs->pos = prs->lastPos + (obj1->coeff_collide*0.90f) * localTransl;
				}
			}

			// Prime intersection - dans ce cas, on bloque l'objet.
			if(obj1->blocked)		// en fait, on devrait ecrire " == 2.0f ", mais on ne sait jamais avec ces putains d'erreurs de flottant !! (et comme coeff<1 ou coeff=2, ça marche ici :])
			{
				prs = obj1->GetPRS();
				
				obj1->worldPos = obj1->worldLastPos;
				prs->pos = prs->lastPos;
			}
		}
	}

}
*/