/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////*****************************************************************************************************////////////////
///////////////** 																									**///////////////
//////////////**								~ Zoo Engine (Moteur 3D pour SCOL) ~								 **//////////////
/////////////**											  ~ version 1.0 ~											  **/////////////
/////////////**																										  **/////////////
//////////////**										par Pacôme DANHIEZ		  									 **//////////////
///////////////** 																									**///////////////
////////////////*****************************************************************************************************////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///																																  ///
///		FICHIER :	ZooM3D.cpp																									  ///
///																																  ///
///		NATURE	:	Lecture et enregistrement d'un fichier au format M3D														  ///
///																																  ///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////






// disable useless conversion warnings
// pbs of float -> double, etc..



#include		"zoom3d.h"




string		errorMsg;





mmachine	machineForLoad;
int			ptrHashTable, ptrHashMat, ptrHashTex;



///////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3Dlitligne																		///
///																							///
///	Lit une ligne dans un fichier et la stocke dans 'buf'									///
/// Renvoit 0 si N caracts lu, sinon le nombre de caract i<N								///
///////////////////////////////////////////////////////////////////////////////////////////////
int M3Dlitligne(FILE *f, char *buf, int n)
{
	int		c, i;

	while((c=fgetc(f))<32)		
	{	
		if (c==EOF)		return 0;	
	}
	
	i=0;
	buf[i++]=c;
	while( ( ((c=fgetc(f))>=32)||(c==9) )&&(c!=EOF)&&(i<n))		buf[i++]=c;
	
	if (i==n)	return 0;
	buf[i]=0;
	
	return i;
}



///////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3Dlitlignebuf																		///
///																							///
///	Lit une ligne dans un le load3D et la stocke dans 'buf'									///
/// Renvoit 0 si N caracts lu, sinon le nombre de caract i<N								///
///////////////////////////////////////////////////////////////////////////////////////////////
int M3Dlitlignebuf(load3d l, char *buf, int n)
{
	int		c,i;

	while((c=(*(l->buf++)))<32)		
	{
		if (c==0) 
		{
			l->buf--;
			return 0;
		}
	}
  
	i=0;
	buf[i++]=c;
	while( ( ((c=(*(l->buf++)))>=32)||(c==9) )&&(c)&&(i<n)) buf[i++]=c;
	
	if (c==0) l->buf--;
	if (i==n) return 0;
	buf[i]=0;
	
	return i;
}



///////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3Ddecoupe																			///
///																							///
///	Lit les caractères dans 'comm', supprime les commentaires, stocke le result dans mots	///
/// Renvoit le nombre de caractères lus (sans compter les commentaires)						///
///////////////////////////////////////////////////////////////////////////////////////////////
int M3Ddecoupe(char *comm, char **mots)
{
	int i,j;
  
	i=j=0;  
	while(*comm)
    { 
		if (((*comm)==32)||((*comm)==9))	*comm=0;
		if ((j==0)&&(*comm))
        {
			if ((*comm)!='#') mots[i++]=comm;
			else return i;
        }
		j=*(comm++);
    }
	return i;
}



///////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3Dnextline																		///
///																							///
///	Stocke les caractères d'une ligne du fichier dans 'bufLoad3d'							///
/// Renvoit -1 si 1024 caracts lu, sinon 0 (ce qu'on veut)									///
///////////////////////////////////////////////////////////////////////////////////////////////
int M3Dnextline(load3d l)
{
	do
    {
		l->argn=0;
		if (l->f)
		{
			if (M3Dlitligne(l->f,l->bufload3d,1023)==0)		return -1;
		}
		else if (M3Dlitlignebuf(l,l->bufload3d,1023)==0)	return -1;
		l->argn=M3Ddecoupe(l->bufload3d,l->argv);
    }
	while(l->argn==0);

	return 0;
}



	


///////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3Dloadvrt																			///
///																							///
///	Lit les caractères dans 'comm', supprime les commentaires, stocke le result dans mots	///
/// Renvoit le nombre de caractères lus sans commentaires									///
///////////////////////////////////////////////////////////////////////////////////////////////
int M3Dloadvrt(ZScene *s, load3d l, ZMesh *curMesh, float coeff)
{
	ZVert	vert;
	int		color;

	do
    {
		if(l->argn >= 3)
        {
			vert.color1.SetCoord(1.0f, 1.0f, 1.0f);
			vert.color2.SetCoord(1.0f, 1.0f, 1.0f);
			vert.SetCoord( atof(l->argv[0])/coeff, atof(l->argv[1])/coeff, -atof(l->argv[2])/coeff );

			if(l->argn >= 4)
			{
				sscanf(l->argv[3],"%x",&color);
				vert.color1.SetCoord( ((float)((color&0x00ff0000)>>16))/CONST_COLOR, ((float)((color&0x0000ff00)>>8))/CONST_COLOR, ((float)((color&0x000000ff)))/CONST_COLOR);

				if(l->argn >= 5)
				{
					sscanf(l->argv[4],"%x",&color);
					vert.color2.SetCoord( ((float)((color&0x00ff0000)>>16))/CONST_COLOR, ((float)((color&0x0000ff00)>>8))/CONST_COLOR, ((float)((color&0x000000ff)))/CONST_COLOR);

					if(l->argn >= 6)	return 0;
				}
			}

			curMesh->addVert(vert);
        }
		else
			return 0;
    }
	while(M3Dnextline(l)==0);

	MMechostr(1,"unexpected end of file - M3Dloadvrt in Mesh : %s\n",curMesh->name.c_str());
	errorMsg += string("unexpected end of file - M3Dloadvrt ");

	return -1;
}



///////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3Dloadpol2																		///
///																							///
///	Lit les caractères dans 'comm', supprime les commentaires, stocke le result dans mots	///
/// Renvoit le nombre de caractères lus sans commentaires									///
///////////////////////////////////////////////////////////////////////////////////////////////
int M3Dloadpol2(ZScene *s, load3d l, ZMesh *curMesh, ZMaterial *curMat)
{
	ZFace	face;
	face.initFace();

	do
    {
		// 3 vertices - 0 texture coordinates
		if ((l->argn==3) && (strcmp(l->argv[2],"{")))
        {
			face.SetVertsRef( atoi(l->argv[0]), atoi(l->argv[1]), atoi(l->argv[2]) );
			face.SetMaterial(curMat);
			face.UV1[0].SetCoord(0.0f, 0.0f);		face.UV1[1].SetCoord(1.0f, 0.0f);		face.UV1[2].SetCoord(0.0f, 1.0f);
			face.UV2[0].SetCoord(0.0f, 0.0f);		face.UV2[1].SetCoord(1.0f, 0.0f);		face.UV2[2].SetCoord(0.0f, 1.0f);

			face.clampU1 = face.clampV1 = face.clampU2 = face.clampV2 = true;

			curMesh->addFace(face);
			face.SetMaterial(NULL);
        }
		// 4 vertices - 0 texture coordinates
		else if (l->argn==4)
        {
			face.SetVertsRef( atoi(l->argv[0]), atoi(l->argv[1]), atoi(l->argv[2]) );
			face.SetMaterial(curMat);
			face.UV1[0].SetCoord(0.0f, 0.0f);		face.UV1[1].SetCoord(1.0f, 0.0f);		face.UV1[2].SetCoord(0.0f, 1.0f);
			face.UV2[0].SetCoord(0.0f, 0.0f);		face.UV2[1].SetCoord(1.0f, 0.0f);		face.UV2[2].SetCoord(0.0f, 1.0f);
			
			face.clampU1 = face.clampV1 = face.clampU2 = face.clampV2 = true;

			curMesh->addFace(face);

			face.SetVertsRef( atoi(l->argv[0]), atoi(l->argv[2]), atoi(l->argv[3]) );

			curMesh->addFace(face);
			face.SetMaterial(NULL);
        }
		// 3 vertices - 2 texture coordinates
		else if (l->argn==9)
        {
			face.SetVertsRef( atoi(l->argv[0]), atoi(l->argv[3]), atoi(l->argv[6]) );
			face.SetMaterial(curMat);
			face.UV1[0].SetCoord( atof(l->argv[1])/CONST_TEX_COORD, atof(l->argv[2])/CONST_TEX_COORD);
			face.UV1[1].SetCoord( atof(l->argv[4])/CONST_TEX_COORD, atof(l->argv[5])/CONST_TEX_COORD);
			face.UV1[2].SetCoord( atof(l->argv[7])/CONST_TEX_COORD, atof(l->argv[8])/CONST_TEX_COORD);
			face.UV2[0] = face.UV1[0];
			face.UV2[1] = face.UV1[1];
			face.UV2[2] = face.UV1[2];

			if( face.UV1[0].u<0.0f || face.UV1[1].u<0.0f || face.UV1[2].u<0.0f || 
				face.UV1[0].u>1.0f || face.UV1[1].u>1.0f || face.UV1[2].u>1.0f )	face.clampU1 = face.clampU2 = false;
			else																	face.clampU1 = face.clampU2 = true;

			if( face.UV1[0].v<0.0f || face.UV1[1].v<0.0f || face.UV1[2].v<0.0f || 
				face.UV1[0].v>1.0f || face.UV1[1].v>1.0f || face.UV1[2].v>1.0f )	face.clampV1 = face.clampV2 = false;
			else																	face.clampV1 = face.clampV2 = true;


			curMesh->addFace(face);
			face.SetMaterial(NULL);
        }
		// 4 vertices - 2 texture coordinates
		else if (l->argn==12)
        {
			face.SetVertsRef( atoi(l->argv[0]), atoi(l->argv[3]), atoi(l->argv[6]) );
			face.SetMaterial(curMat);
			face.UV1[0].SetCoord( atof(l->argv[1])/CONST_TEX_COORD, atof(l->argv[2])/CONST_TEX_COORD);
			face.UV1[1].SetCoord( atof(l->argv[4])/CONST_TEX_COORD, atof(l->argv[5])/CONST_TEX_COORD);
			face.UV1[2].SetCoord( atof(l->argv[7])/CONST_TEX_COORD, atof(l->argv[8])/CONST_TEX_COORD);
			face.UV2[0] = face.UV1[0];
			face.UV2[1] = face.UV1[1];
			face.UV2[2] = face.UV1[2];

			if( face.UV1[0].u<0.0f || face.UV1[1].u<0.0f || face.UV1[2].u<0.0f || 
				face.UV1[0].u>1.0f || face.UV1[1].u>1.0f || face.UV1[2].u>1.0f )	face.clampU1 = face.clampU2 = false;
			else																	face.clampU1 = face.clampU2 = true;

			if( face.UV1[0].v<0.0f || face.UV1[1].v<0.0f || face.UV1[2].v<0.0f || 
				face.UV1[0].v>1.0f || face.UV1[1].v>1.0f || face.UV1[2].v>1.0f )	face.clampV1 = face.clampV2 = false;
			else																	face.clampV1 = face.clampV2 = true;

			curMesh->addFace(face);

			
			face.SetVertsRef( atoi(l->argv[0]), atoi(l->argv[6]), atoi(l->argv[9]) );
			face.UV1[0].SetCoord( atof(l->argv[1])/CONST_TEX_COORD,  atof(l->argv[2])/CONST_TEX_COORD );
			face.UV1[1].SetCoord( atof(l->argv[7])/CONST_TEX_COORD,  atof(l->argv[8])/CONST_TEX_COORD );
			face.UV1[2].SetCoord( atof(l->argv[10])/CONST_TEX_COORD, atof(l->argv[11])/CONST_TEX_COORD);
			face.UV2[0] = face.UV1[0];
			face.UV2[1] = face.UV1[1];
			face.UV2[2] = face.UV1[2];

			if( face.UV1[0].u<0.0f || face.UV1[1].u<0.0f || face.UV1[2].u<0.0f || 
				face.UV1[0].u>1.0f || face.UV1[1].u>1.0f || face.UV1[2].u>1.0f )	face.clampU1 = face.clampU2 = false;
			else																	face.clampU1 = face.clampU2 = true;

			if( face.UV1[0].v<0.0f || face.UV1[1].v<0.0f || face.UV1[2].v<0.0f || 
				face.UV1[0].v>1.0f || face.UV1[1].v>1.0f || face.UV1[2].v>1.0f )	face.clampV1 = face.clampV2 = false;
			else																	face.clampV1 = face.clampV2 = true;
			
			curMesh->addFace(face);
			face.SetMaterial(NULL);
        }
		// 3 vertices - 4 texture coordinates
		else if (l->argn==15)
        {
			face.SetVertsRef( atoi(l->argv[0]), atoi(l->argv[5]), atoi(l->argv[10]) );
			face.SetMaterial(curMat);
			face.UV1[0].SetCoord( atof(l->argv[1])/CONST_TEX_COORD, atof(l->argv[2])/CONST_TEX_COORD);
			face.UV1[1].SetCoord( atof(l->argv[6])/CONST_TEX_COORD, atof(l->argv[7])/CONST_TEX_COORD);
			face.UV1[2].SetCoord( atof(l->argv[11])/CONST_TEX_COORD, atof(l->argv[12])/CONST_TEX_COORD);
			face.UV2[0].SetCoord( atof(l->argv[3])/CONST_TEX_COORD, atof(l->argv[4])/CONST_TEX_COORD);
			face.UV2[1].SetCoord( atof(l->argv[8])/CONST_TEX_COORD, atof(l->argv[9])/CONST_TEX_COORD);
			face.UV2[2].SetCoord( atof(l->argv[13])/CONST_TEX_COORD, atof(l->argv[14])/CONST_TEX_COORD);

			if( face.UV1[0].u<0.0f || face.UV1[1].u<0.0f || face.UV1[2].u<0.0f ||
				face.UV1[0].u>1.0f || face.UV1[1].u>1.0f || face.UV1[2].u>1.0f )	face.clampU1 = false;
			else																	face.clampU1 = true;

			if( face.UV2[0].u<0.0f || face.UV2[1].u<0.0f || face.UV2[2].u<0.0f ||
				face.UV2[0].u>1.0f || face.UV2[1].u>1.0f || face.UV2[2].u>1.0f )	face.clampU2 = false;
			else																	face.clampU2 = true;

			if( face.UV1[0].v<0.0f || face.UV1[1].v<0.0f || face.UV1[2].v<0.0f || 
				face.UV1[0].v>1.0f || face.UV1[1].v>1.0f || face.UV1[2].v>1.0f )	face.clampV1 = false;
			else																	face.clampV1 = true;

			if( face.UV2[0].v<0.0f || face.UV2[1].v<0.0f || face.UV2[2].v<0.0f || 
				face.UV2[0].v>1.0f || face.UV2[1].v>1.0f || face.UV2[2].v>1.0f )	face.clampV2 = false;
			else																	face.clampV2 = true;

			curMesh->addFace(face);
			face.SetMaterial(NULL);
        }
		// 4 vertices - 4 texture coordinates
		else if (l->argn==20)
        {
			face.SetVertsRef( atoi(l->argv[0]), atoi(l->argv[5]), atoi(l->argv[10]) );
			face.SetMaterial(curMat);
			face.UV1[0].SetCoord( atof(l->argv[1])/CONST_TEX_COORD, atof(l->argv[2])/CONST_TEX_COORD);
			face.UV1[1].SetCoord( atof(l->argv[6])/CONST_TEX_COORD, atof(l->argv[7])/CONST_TEX_COORD);
			face.UV1[2].SetCoord( atof(l->argv[11])/CONST_TEX_COORD, atof(l->argv[12])/CONST_TEX_COORD);
			face.UV2[0].SetCoord( atof(l->argv[3])/CONST_TEX_COORD, atof(l->argv[4])/CONST_TEX_COORD);
			face.UV2[1].SetCoord( atof(l->argv[8])/CONST_TEX_COORD, atof(l->argv[9])/CONST_TEX_COORD);
			face.UV2[2].SetCoord( atof(l->argv[13])/CONST_TEX_COORD, atof(l->argv[14])/CONST_TEX_COORD);

			if( face.UV1[0].u<0.0f || face.UV1[1].u<0.0f || face.UV1[2].u<0.0f ||
				face.UV1[0].u>1.0f || face.UV1[1].u>1.0f || face.UV1[2].u>1.0f )	face.clampU1 = false;
			else																	face.clampU1 = true;

			if( face.UV2[0].u<0.0f || face.UV2[1].u<0.0f || face.UV2[2].u<0.0f ||
				face.UV2[0].u>1.0f || face.UV2[1].u>1.0f || face.UV2[2].u>1.0f )	face.clampU2 = false;
			else																	face.clampU2 = true;

			if( face.UV1[0].v<0.0f || face.UV1[1].v<0.0f || face.UV1[2].v<0.0f || 
				face.UV1[0].v>1.0f || face.UV1[1].v>1.0f || face.UV1[2].v>1.0f )	face.clampV1 = false;
			else																	face.clampV1 = true;

			if( face.UV2[0].v<0.0f || face.UV2[1].v<0.0f || face.UV2[2].v<0.0f || 
				face.UV2[0].v>1.0f || face.UV2[1].v>1.0f || face.UV2[2].v>1.0f )	face.clampV2 = false;
			else																	face.clampV2 = true;
			
			curMesh->addFace(face);


			face.SetVertsRef( atoi(l->argv[0]), atoi(l->argv[10]), atoi(l->argv[15]) );
			face.UV1[0].SetCoord( atof(l->argv[1])/CONST_TEX_COORD, atof(l->argv[2])/CONST_TEX_COORD);
			face.UV1[1].SetCoord( atof(l->argv[11])/CONST_TEX_COORD, atof(l->argv[12])/CONST_TEX_COORD);
			face.UV1[2].SetCoord( atof(l->argv[16])/CONST_TEX_COORD, atof(l->argv[17])/CONST_TEX_COORD);
			face.UV2[0].SetCoord( atof(l->argv[3])/CONST_TEX_COORD, atof(l->argv[4])/CONST_TEX_COORD);
			face.UV2[1].SetCoord( atof(l->argv[13])/CONST_TEX_COORD, atof(l->argv[14])/CONST_TEX_COORD);
			face.UV2[2].SetCoord( atof(l->argv[18])/CONST_TEX_COORD, atof(l->argv[19])/CONST_TEX_COORD);

			if( face.UV1[0].u<0.0f || face.UV1[1].u<0.0f || face.UV1[2].u<0.0f ||
				face.UV1[0].u>1.0f || face.UV1[1].u>1.0f || face.UV1[2].u>1.0f )	face.clampU1 = false;
			else																	face.clampU1 = true;

			if( face.UV2[0].u<0.0f || face.UV2[1].u<0.0f || face.UV2[2].u<0.0f ||
				face.UV2[0].u>1.0f || face.UV2[1].u>1.0f || face.UV2[2].u>1.0f )	face.clampU2 = false;
			else																	face.clampU2 = true;

			if( face.UV1[0].v<0.0f || face.UV1[1].v<0.0f || face.UV1[2].v<0.0f || 
				face.UV1[0].v>1.0f || face.UV1[1].v>1.0f || face.UV1[2].v>1.0f )	face.clampV1 = false;
			else																	face.clampV1 = true;

			if( face.UV2[0].v<0.0f || face.UV2[1].v<0.0f || face.UV2[2].v<0.0f || 
				face.UV2[0].v>1.0f || face.UV2[1].v>1.0f || face.UV2[2].v>1.0f )	face.clampV2 = false;
			else																	face.clampV2 = true;

			curMesh->addFace(face);
			face.SetMaterial(NULL);
		}
		else
			return 0;
    }
	while(M3Dnextline(l)==0);

	MMechostr(1,"unexpected end of file - M3Dloadpol2 in Mesh : %s\n",curMesh->name.c_str());
	errorMsg += string("unexpected end of file - M3Dloadpol2");

	return -1;
}



///////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3Dloadpol																			///
///																							///
///	Lit les références de vertices et les IDs de matériaux d'un mesh						///
/// Renvoit 0 si tout se passe bien, -1 sinon												///
///////////////////////////////////////////////////////////////////////////////////////////////
int M3Dloadpol(ZScene *s, load3d l, ZMesh *curMesh)
{
	ZMaterial	*curMat;

	// Lit la presence d'un éclairage par light ou pas
	if( (l->argn==2) && (!strcmp(l->argv[0],"light")) )
    {
		/*light = atoi(l->argv[1]);
		if (light<0)	light = 0;
		if (light>63)	light = 63;
		
		if (ZM3DsetMeshLight(s,handle,light))	return -1;
		*/
		if (M3Dnextline(l))
        {
			MMechostr(1,"unexpected end of file - M3Dloadpol in Mesh : %s\n",curMesh->name.c_str());
			errorMsg += string("unexpected end of file - M3Dloadpol");
			return -1;
        }
    }

	// Lit les refs de vertices et les IDs de matériaux
	while( (l->argn==1) && (strcmp(l->argv[0],"}")) )
    {
		string matName(l->argv[0]);

		curMat = NULL;

		for(int k=0; k<s->MatList.Size(); k++)
		{
			if( s->MatList[k]->name==matName && (curMat==NULL || s->MatList[k]->version>curMat->version) )		curMat = s->MatList[k];
		}

		if(curMat==NULL)
		{
			MMechostr(1,"unexpected name of material - M3Dloadpol in Mesh : %s\n",curMesh->name.c_str());
			errorMsg += string("unexpected name of material : ");
			errorMsg += matName;
			return -1;
		}

		if (M3Dnextline(l))
        {
			MMechostr(1,"unexpected end of file - M3Dloadpol in Mesh : %s\n",curMesh->name.c_str());
			errorMsg += string("unexpected end of file - M3Dloadpol");
			return -1;
        }
		if (M3Dloadpol2(s, l, curMesh, curMat))		return -1;
    }

	return 0;
}



///////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3Dlitligne																		///
///																							///
///	Lit les caractères dans 'comm', supprime les commentaires, stocke le result dans mots	///
/// Renvoit le nombre de caractères lus sans commentaires									///
///////////////////////////////////////////////////////////////////////////////////////////////
int M3DloadUnknown(ZScene *s, load3d l, ZNode *nodeBase)
{
	int i=1;
	
	while(M3Dnextline(l)==0)
	{
		if ((l->argn==3)&&(!strcmp(l->argv[2],"{"))) i++;
		if ((l->argn==1)&&(!strcmp(l->argv[0],"}")))
		{
			i--;
			if (!i)		return 0;
		}
	}
	
	MMechostr(1,"unexpected end of file - M3DloadUnknown \n");
	errorMsg += string("unexpected end of file - M3DloadUnknown");
    return -1;
}



///////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3DrecursObj																		///
///																							///
///	Lit les caractères dans 'comm', supprime les commentaires, stocke le result dans mots	///
/// Renvoit le nombre de caractères lus sans commentaires									///
///////////////////////////////////////////////////////////////////////////////////////////////
int M3DrecursObj(ZScene *s, load3d l, ZNode *nodeBase, float coeff)
{
	FILE	*f;
	int		k;

	do
    {
		if ((l->argn==3)&&(!strcmp(l->argv[0],"mesh")) &&(!strcmp(l->argv[2],"{")) )
        {
			if (M3DloadMesh(s, l, nodeBase, coeff))		return -1;
        }
		else if ((l->argn==3)&&(!strcmp(l->argv[0],"camera")) &&(!strcmp(l->argv[2],"{")))
        {
			if (M3DloadCam(s, l, nodeBase, coeff))		return -1;
        }
		else if ((l->argn==3)&&(!strcmp(l->argv[0],"shell")) &&(!strcmp(l->argv[2],"{")))
        {
			if (M3DloadShell(s, l, nodeBase, coeff))		return -1;
        }
		else if ((l->argn==3)&&(!strcmp(l->argv[0],"coll")) &&(!strcmp(l->argv[2],"{")))
        {
			if (M3DloadColl(s, l, nodeBase, coeff))		return -1;
        }
		else if ((l->argn==3)&&(!strcmp(l->argv[0],"anim")) &&(!strcmp(l->argv[2],"{")))
        {
			if (M3DloadAnim(s, l, nodeBase, coeff))		return -1;
        }
		else if ((l->argn==3)&&(!strcmp(l->argv[0],"light")) &&(!strcmp(l->argv[2],"{")))
	    {
			if (M3DloadLight(s, l, nodeBase, coeff))		return -1;
		}
		else if ((l->argn==3)&&(!strcmp(l->argv[0],"colorlight")) &&(!strcmp(l->argv[2],"{")))
	    {
			if (M3DloadColorLight(s, l, nodeBase, coeff))		return -1;
		}
		else if ((l->argn==3)&&(!strcmp(l->argv[0],"emitter")) && (!strcmp(l->argv[2],"{")))
		{
			if (M3DloadEmitter(s, l, nodeBase, coeff))		return -1;
		}
		else if ((l->argn==3)&&(!strcmp(l->argv[2],"{")))
		{
			if (M3DloadUnknown(s, l, nodeBase))	return -1;
		}
		else if ((l->argn==2)&&(!strcmp(l->argv[0],"include")))
        {
			//MMechostr(1,"include file %s\n",l->argv[1]);
			if (/*(SPfindfile((packdir)SCgetExtra("FirstPack"),l->argv[1],NULL,name)==-1)||((f=fopen(name,"r"))==NULL)*/  (f=fopen(l->argv[1],"r"))==NULL )
			{
				//MMechostr(1,"file %s not found\n",l->argv[1]);
				return -1;
			}
			
			k = M3Dload(s, f, nodeBase, coeff);
			fclose(f);
			if (k)		return k;
        }
		else 
			return 0;
    }
	while(M3Dnextline(l)==0);

	MMechostr(1,"unexpected end of file - M3DrecursObj in BaseNode : %s\n",nodeBase->name.c_str());
	errorMsg += string("unexpected end of file - M3DrecursObj");
	return -1;
}






///////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3DloadTopo																		///
///																							///
///	Lit les caractères dans 'comm', supprime les commentaires, stocke le result dans mots	///
/// Renvoit le nombre de caractères lus sans commentaires									///
///////////////////////////////////////////////////////////////////////////////////////////////
int M3DloadTopo(ZScene *s, load3d l, float coeff)
{
	// Lit le mesh correspondant
	ZMesh	*newMesh;
	newMesh = new ZMesh((int)s, 0, 0);
	if(newMesh==NULL)		return -1;
	s->MshList.Add(newMesh);
	newMesh->SetName(l->argv[1]);


	MMpush(machineForLoad, PTOM(ptrHashTable) );
	MMpush(machineForLoad, PTOM(ptrHashMat)   );
	MMpush(machineForLoad, PTOM(ptrHashTex)   );
	createH3D(machineForLoad, (int)newMesh, ptrHashTable);
	ptrHashTex   = MTOP( MMpull(machineForLoad) );
	ptrHashMat   = MTOP( MMpull(machineForLoad) );
	ptrHashTable = MTOP( MMpull(machineForLoad) );


	if (M3Dnextline(l))
    {
		MMechostr(1,"unexpected end of file - M3DloadTopo in Topo : %s\n",newMesh->name.c_str());
		errorMsg += string("unexpected end of file - M3DloadTopo");
		return -1;
    }

	if (M3Dloadvrt(s, l, newMesh, coeff))		return -1;
	if (M3Dloadpol(s, l, newMesh))				return -1;
/*
	if( (newMesh->dependency==false) && (newMesh->displayListCreate==true) )
	{
		newMesh->CreateFacesNormals();
		newMesh->CreateVertsNormals();
	}

	newMesh->ComputeOBB();
*/
	newMesh->hasTopoChanged = true;
	newMesh->hasViewChanged = true;
	newMesh->MakeFacesList();

	if (strcmp(l->argv[0],"}"))
    {
		MMechostr(1,"} expected - M3DloadTopo in Topo : %s\n",newMesh->name.c_str());
		errorMsg += string("} expected in M3DloadTopo");
		return -1;
    }

	return 0;
}



///////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3DloadMesh																		///
///																							///
///	Lit les caractères dans 'comm', supprime les commentaires, stocke le result dans mots	///
/// Renvoit le nombre de caractères lus sans commentaires									///
///////////////////////////////////////////////////////////////////////////////////////////////
int M3DloadMesh(ZScene *s, load3d l, ZNode *nodeBase, float coeff)
{
	ZObject	*newObj;
	newObj = new ZObject((int)s);
	if (newObj==NULL)		return -1;
	newObj->InsertAsChildOf(nodeBase);
	newObj->SetName(l->argv[1]);


	MMpush(machineForLoad, PTOM(ptrHashTable) );
	MMpush(machineForLoad, PTOM(ptrHashMat)   );
	MMpush(machineForLoad, PTOM(ptrHashTex)   );
	createH3D(machineForLoad, (int)newObj, ptrHashTable);
	ptrHashTex   = MTOP( MMpull(machineForLoad) );
	ptrHashMat   = MTOP( MMpull(machineForLoad) );
	ptrHashTable = MTOP( MMpull(machineForLoad) );

	if (M3Dnextline(l))
    {
		MMechostr(1,"unexpected end of file - M3DloadMesh in Mesh : %s\n",newObj->name.c_str());
		errorMsg += string("unexpected end of file - M3DloadMesh");
		return -1;
    }

	if (l->argn<6)
    {
		MMechostr(1,"unexpected end of file - M3DloadMesh in Mesh : %s\n",newObj->name.c_str());
		errorMsg += string("unexpected end of file - M3DloadMesh");
		return -1;
    }
	

	// Lit la position et la rotation de l'objet
	ZPRS	*newPRS = newObj->GetPRS();
	newPRS->coeffM3D = coeff;
	newPRS->SetPos( atof(l->argv[0])/coeff, atof(l->argv[1])/coeff, -atof(l->argv[2])/coeff );
	newPRS->SetAng( atof(l->argv[4])*360.0f/CONST_ANGLE, atof(l->argv[3])*360.0f/CONST_ANGLE, atof(l->argv[5])*360.0f/CONST_ANGLE );

	// Lit le scale s'il existe
	if(l->argn>6)		newPRS->SetScale(atof(l->argv[6])/100.0f);
	
	// lit le range de visibilité
	if(l->argn>8)
	{
		if(!strcmp(l->argv[7],"RANGE_INFINITY"))	newObj->rangeMIN = 0;
		else										newObj->rangeMIN = atof(l->argv[7]);
		if(!strcmp(l->argv[8],"RANGE_INFINITY"))	newObj->rangeMAX = RANGE_INFINITY;
		else										newObj->rangeMAX = atof(l->argv[8]);
	}

	if (M3Dnextline(l))
    {
		MMechostr(1,"unexpected end of file - M3DloadMesh in Mesh : %s\n",newObj->name.c_str());
		errorMsg += string("unexpected end of file - M3DloadMesh");
		return -1;
    }


	// --> Lit la topo correspondante

	// Lecture référencée SIMPLE
	if((l->argn==2)&&(!strcmp(l->argv[0],"topo")))
	{
		string	nomTopo;
		nomTopo = string(&(l->argv[1][0]));

		// Recherche d'une topo similaire existante
		for(int k=0; k<s->MshList.Size() && s->MshList[k]->name!=nomTopo; k++);

		// Utilisation de la topo existante ou...
		if(k<s->MshList.Size())
		{
			newObj->SetMesh( s->MshList[k] );
		}
		else	// ...plantage !!
		{			
			MMechostr(1,"topology expected - M3DloadMesh in Mesh : %s\n",newObj->name.c_str());
			errorMsg += string("topology expected");
			return -1;
		}

		if (M3Dnextline(l))
		{
			MMechostr(1,"unexpected end of file - M3DloadMesh in Mesh : %s\n",newObj->name.c_str());
			errorMsg += string("unexpected end of file - M3Dloadpol");
			return -1;
		}
	}
	else
	// Lecture référencée MULTIPLE
	if((l->argn==3)&&(!strcmp(l->argv[0],"topo")))
	{
		newObj->setFlagMulti(true);

		string	nomTopo;

		do
		{
			nomTopo = string(&(l->argv[1][0]));

			// Recherche d'une topo similaire existante
			for(int k=0; k<s->MshList.Size() && s->MshList[k]->name!=nomTopo; k++);

			// Utilisation de la topo existante ou...
			if(k<s->MshList.Size())
			{
				if( strcmp(l->argv[2],"RANGE_INFINITY") )
				{
					float range = atof(l->argv[2]);
					newObj->AddMeshInList( s->MshList[k], (range/100.0f) * (range/100.0f) );
				}
				else
					newObj->AddMeshInList( s->MshList[k], FLT_MAX );
			}
			else	// ...plantage !!
			{
				MMechostr(1,"topology expected - M3DloadMesh in Mesh : %s\n",newObj->name.c_str());
				errorMsg += string("topology expected");
				return -1;
			}

			if (M3Dnextline(l))
			{
				MMechostr(1,"unexpected end of file - M3DloadMesh in Mesh : %s\n",newObj->name.c_str());
				errorMsg += string("unexpected end of file - M3Dloadpol");
				return -1;
			}
		}
		while( (strcmp(l->argv[0],"}")) && (!strcmp(l->argv[0],"topo")) && (l->argn==3) );

		if( ((!strcmp(l->argv[0],"topo"))&&(l->argn!=3)) )
		{
			MMechostr(1,"topology expected - M3DloadMesh in Mesh : %s\n",newObj->name.c_str());
			errorMsg += string("topology expected");
			return -1;
		}
	}
	// Lecture complête
	else
	{
		ZMesh	*newMesh;
		newMesh = new ZMesh((int)s, 0, 0);
		if(newMesh==NULL)		return -1;
		s->MshList.Add(newMesh);
		newMesh->SetName(newObj->name);

		MMpush(machineForLoad, PTOM(ptrHashTable) );
		MMpush(machineForLoad, PTOM(ptrHashMat)   );
		MMpush(machineForLoad, PTOM(ptrHashTex)   );
		createH3D(machineForLoad, (int)newMesh, ptrHashTable);
		ptrHashTex   = MTOP( MMpull(machineForLoad) );
		ptrHashMat   = MTOP( MMpull(machineForLoad) );
		ptrHashTable = MTOP( MMpull(machineForLoad) );


		newObj->SetMesh(newMesh);

		if (M3Dloadvrt(s, l, newMesh, coeff))		return -1;
		if (M3Dloadpol(s, l, newMesh))				return -1;
/*
		if( (newMesh->dependency==false) && (newMesh->displayListCreate==true) )
		{
			newMesh->CreateFacesNormals();
			newMesh->CreateVertsNormals();
		}

		newMesh->ComputeOBB();
*/
		newMesh->hasTopoChanged = true;
		newMesh->hasViewChanged = true;
		newMesh->MakeFacesList();
	}


	if (M3DrecursObj(s, l, newObj, coeff))		return -1;

	if (strcmp(l->argv[0],"}"))
	{
		MMechostr(1,"} expected - M3DloadMesh in Mesh : %s\n",newObj->name.c_str());
		errorMsg += string("} expected ");
		return -1;
	}

	return 0;
}



///////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3DloadCam																			///
///																							///
///	Lit les caractères dans 'comm', supprime les commentaires, stocke le result dans mots	///
/// Renvoit le nombre de caractères lus sans commentaires									///
///////////////////////////////////////////////////////////////////////////////////////////////
int M3DloadCam(ZScene *s, load3d l, ZNode *nodeBase, float coeff)
{
	int		sx, sy, dx, dy;

	ZCamera		*curCam;
	curCam = new ZCamera((int)s);
	if (curCam==NULL)	return -1;

	curCam->InsertAsChildOf(nodeBase);
	curCam->SetName(l->argv[1]);


	MMpush(machineForLoad, PTOM(ptrHashTable) );
	MMpush(machineForLoad, PTOM(ptrHashMat)   );
	MMpush(machineForLoad, PTOM(ptrHashTex)   );
	createH3D(machineForLoad, (int)curCam, ptrHashTable);
	ptrHashTex   = MTOP( MMpull(machineForLoad) );
	ptrHashMat   = MTOP( MMpull(machineForLoad) );
	ptrHashTable = MTOP( MMpull(machineForLoad) );



	if (M3Dnextline(l))
    {
		MMechostr(1,"unexpected end of file - M3DloadCam in Camera : %s\n",curCam->name.c_str());
		errorMsg += string("unexpected end of file - M3DloadCam");
		return -1;
    }
	if (l->argn<6)
    {
		MMechostr(1,"position expected - M3DloadCam in Camera : %s\n",curCam->name.c_str());
		errorMsg += string("position expected - M3DloadCam");
		return -1;
    }

	ZPRS	*curPRS = curCam->GetPRS();
	curPRS->coeffM3D = coeff;
	curPRS->SetPos(atof(l->argv[0])/coeff, atof(l->argv[1])/coeff, -atof(l->argv[2])/coeff);
	curPRS->SetAng(atof(l->argv[4])*360.0f/CONST_ANGLE, atof(l->argv[3])*360.0f/CONST_ANGLE, atof(l->argv[5])*360.0f/CONST_ANGLE);

	if (l->argn>6)		curPRS->SetScale(atof(l->argv[6])/100.0f);

	// lit le range de visibilité
	if(l->argn>8)
	{
		if(!strcmp(l->argv[7],"RANGE_INFINITY"))	curCam->rangeMIN = 0;
		else										curCam->rangeMIN = atof(l->argv[7]);
		if(!strcmp(l->argv[8],"RANGE_INFINITY"))	curCam->rangeMAX = RANGE_INFINITY;
		else										curCam->rangeMAX = atof(l->argv[8]);
	}
	
	if (M3Dnextline(l))
    {
		MMechostr(1,"unexpected end of file - M3DloadCam in Camera : %s\n",curCam->name.c_str());
		errorMsg += string("unexpected end of file - M3DloadCam");
		return -1;
    }

	if (l->argn!=4)
    {
		MMechostr(1,"projection parameters expected - M3DloadCam in Camera : %s\n",curCam->name.c_str());
		errorMsg += string("projection parameters expected - M3DloadCam");
		return -1;
    }
	
	dx = atoi(l->argv[0]);
	dy = atoi(l->argv[1]);
	sx = atoi(l->argv[2]);
	sy = atoi(l->argv[3]);

	if (M3Dnextline(l))
    {
		MMechostr(1,"unexpected end of file - M3DloadCam in Camera : %s\n",curCam->name.c_str());
		errorMsg += string("unexpected end of file - M3DloadCam");
		return -1;
    }
	if (l->argn!=3)
    {
		MMechostr(1,"z parameters expected - M3DloadCam in Camera : %s\n",curCam->name.c_str());
		errorMsg += string("z parameters expected - M3DloadCam");
		return -1;
    }

	
	float	znear = atof(l->argv[0]) / coeff;
	float	zfog  = atof(l->argv[1]) / coeff;
	float	zfar  = atof(l->argv[2]) / coeff;
	float	fov	  = (atan2((double)sy,(double)dy)*180.0)/3.1415926535;

	curCam->SetCamera(fov, znear, zfar);
	curCam->Zfog   = zfog;
	curCam->width  = sx*2;
	curCam->height = sy*2;
	curCam->dx	   = dx;
	curCam->dy	   = dy;


	if (M3Dnextline(l))
    {
		MMechostr(1,"unexpected end of file - M3DloadCam in Camera : %s\n",curCam->name.c_str());
		errorMsg += string("unexpected end of file - M3DloadCam");
		return -1;
    }

	if (M3DrecursObj(s, l, curCam, coeff))				return -1;
	
	if (strcmp(l->argv[0],"}"))
    {
		MMechostr(1,"} expected - M3DloadCam in Camera : %s\n",curCam->name.c_str());
		errorMsg += string("} expected ");
		return -1;
    }
  
	return 0;
}





///////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3DloadShell																		///
///																							///
///	Lit les caractères dans 'comm', supprime les commentaires, stocke le result dans mots	///
/// Renvoit le nombre de caractères lus sans commentaires									///
///////////////////////////////////////////////////////////////////////////////////////////////
int M3DloadShell(ZScene *s, load3d l, ZNode *nodeBase, float coeff)
{
	ZShell	*curShell;

	curShell = new ZShell((int)s);
	if(curShell == NULL)	return -1;
	curShell->InsertAsChildOf(nodeBase);
	curShell->SetName(l->argv[1]);
	
	MMpush(machineForLoad, PTOM(ptrHashTable) );
	MMpush(machineForLoad, PTOM(ptrHashMat)   );
	MMpush(machineForLoad, PTOM(ptrHashTex)   );
	createH3D(machineForLoad, (int)curShell, ptrHashTable);
	ptrHashTex   = MTOP( MMpull(machineForLoad) );
	ptrHashMat   = MTOP( MMpull(machineForLoad) );
	ptrHashTable = MTOP( MMpull(machineForLoad) );

	

	ZPRS	*shlPRS;
	shlPRS = curShell->GetPRS();


	if (M3Dnextline(l))
    {
		MMechostr(1,"unexpected end of file - M3DloadShell in Shell : %s\n",curShell->name.c_str());
		errorMsg += string("unexpected end of file - M3DloadShell");
		return -1;
    }
	if (l->argn<6)
    {
		MMechostr(1,"position expected - M3DloadShell in Shell : %s\n",curShell->name.c_str());
		errorMsg += string("position expected - M3DloadShell");
		return -1;
    }
	
	shlPRS->coeffM3D = coeff;
	shlPRS->SetPos(atof(l->argv[0])/coeff,atof(l->argv[1])/coeff, -atof(l->argv[2])/coeff);
	shlPRS->SetAng( atof(l->argv[4])*360.0f/CONST_ANGLE,  atof(l->argv[3])*360.0f/CONST_ANGLE, atof(l->argv[5])*360.0f/CONST_ANGLE);
	
	if (l->argn>6)			shlPRS->SetScale(atof(l->argv[6])/100.0f);

	// lit le range de visibilité
	if(l->argn>8)
	{
		if(!strcmp(l->argv[7],"RANGE_INFINITY"))	curShell->rangeMIN = 0;
		else										curShell->rangeMIN = atof(l->argv[7]);
		if(!strcmp(l->argv[8],"RANGE_INFINITY"))	curShell->rangeMAX = RANGE_INFINITY;
		else										curShell->rangeMAX = atof(l->argv[8]);
	}

	if (M3Dnextline(l))
    {
		MMechostr(1,"unexpected end of file - M3DloadShell in Shell : %s\n",curShell->name.c_str());
		errorMsg += string("unexpected end of file - M3DloadShell");
		return -1;
    }
	
	if (M3DrecursObj(s, l, curShell, coeff))		return -1;
	if (strcmp(l->argv[0],"}"))
    {
		MMechostr(1,"} expected - M3DloadShell in Shell : %s\n",curShell->name.c_str());
		errorMsg += string("} expected ");
		return -1;
    }
  
	return 0;
}



///////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3DloadLight																		///
///																							///
///	Lit les caractères dans 'comm', supprime les commentaires, stocke le result dans mots	///
/// Renvoit le nombre de caractères lus sans commentaires									///
///////////////////////////////////////////////////////////////////////////////////////////////
int M3DloadLight(ZScene *s, load3d l, ZNode *baseNode, float coeff)
{
	ZLight	*curLgh;
	curLgh = new ZLight((int)s);
	if(curLgh == NULL)			return -1;
	curLgh->InsertAsChildOf(baseNode);
	curLgh->SetName(l->argv[1]);
	curLgh->oldStyle = true;

	ZPRS	*curPRS;
	curPRS = curLgh->GetPRS();


	MMpush(machineForLoad, PTOM(ptrHashTable) );
	MMpush(machineForLoad, PTOM(ptrHashMat)   );
	MMpush(machineForLoad, PTOM(ptrHashTex)   );
	createH3D(machineForLoad, (int)curLgh, ptrHashTable);
	ptrHashTex   = MTOP( MMpull(machineForLoad) );
	ptrHashMat   = MTOP( MMpull(machineForLoad) );
	ptrHashTable = MTOP( MMpull(machineForLoad) );


	if(M3Dnextline(l))
    {
		MMechostr(1,"unexpected end of file - M3DloadLight in Light : %s\n",curLgh->name.c_str());
		errorMsg += string("unexpected end of file - M3DloadLight");
		return -1;
    }
	if(l->argn<6)
    {
		MMechostr(1,"position expected - M3DloadLight in Light : %s\n",curLgh->name.c_str());
		errorMsg += string("position expected - M3DloadLight");
		return -1;
    }

	curPRS->coeffM3D = coeff;
	curPRS->SetPos( atof(l->argv[0])/coeff,atof(l->argv[1])/coeff, -atof(l->argv[2])/coeff);
	curPRS->SetAng( atof(l->argv[4])*360.0f/CONST_ANGLE,  atof(l->argv[3])*360.0f/CONST_ANGLE, atof(l->argv[5])*360.0f/CONST_ANGLE);

	if(l->argn>6)			curPRS->SetScale(atof(l->argv[6])/100.0f);

	// lit le range de visibilité
	if(l->argn>8)
	{
		if(!strcmp(l->argv[7],"RANGE_INFINITY"))	curLgh->rangeMIN = 0;
		else										curLgh->rangeMIN = atof(l->argv[7]);
		if(!strcmp(l->argv[8],"RANGE_INFINITY"))	curLgh->rangeMAX = RANGE_INFINITY;
		else										curLgh->rangeMAX = atof(l->argv[8]);
	}

	if(M3Dnextline(l))
    {
		MMechostr(1,"unexpected end of file - M3DloadLight in Light : %s\n",curLgh->name.c_str());
		errorMsg += string("unexpected end of file - M3DloadLight");
		return -1;
    }

	// Récupération du type de light
	if(l->argn>0)
	{
		if (!strcmpi(l->argv[0],"ambient"))		curLgh->LightType = LIGHT_AMBIENT;
		if (!strcmpi(l->argv[0],"para"))		curLgh->LightType = LIGHT_PARA;
		if (!strcmpi(l->argv[0],"omni"))		curLgh->LightType = LIGHT_OMNI;
		if (!strcmpi(l->argv[0],"spot"))		curLgh->LightType = LIGHT_SPOT;
	}

	// Récupération des params de light
	if(l->argn>1)
	{
		float	ambient = atof(l->argv[1]) / 64.0f;
		curLgh->SetAmbient(ambient, ambient, ambient, 1.0f);
		curLgh->alpha = atoi(l->argv[1]);
	}
	if(l->argn>2)
	{
		float	diffuse = atof(l->argv[2]) / 64.0f;
		curLgh->SetDiffuse(diffuse, diffuse, diffuse, 1.0f);
		curLgh->beta = atoi(l->argv[2]);
	}
	if(l->argn>3)
	{
		curLgh->distance = atof(l->argv[3]) / coeff;
		curLgh->dist = atoi(l->argv[3]);
	}


	// Recursion
	if(M3Dnextline(l))
    {
		MMechostr(1,"unexpected end of file - M3DloadLight in Light : %s\n",curLgh->name.c_str());
		errorMsg += string("unexpected end of file - M3DloadLight");
		return -1;
    }

	if (M3DrecursObj(s, l, curLgh, coeff))				return -1;

	if (strcmp(l->argv[0],"}"))
    {
		MMechostr(1,"} expected - M3DloadLight in Light : %s\n",curLgh->name.c_str());
		errorMsg += string("} expected - M3DloadLight");
		return -1;
    }

	return 0;
}



///////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3DloadColorLight																	///
///																							///
///	Lit les caractères dans 'comm', supprime les commentaires, stocke le result dans mots	///
/// Renvoit le nombre de caractères lus sans commentaires									///
///////////////////////////////////////////////////////////////////////////////////////////////
int M3DloadColorLight(ZScene *s, load3d l, ZNode *baseNode, float coeff)
{
	ZLight	*curLgh;
	curLgh = new ZLight((int)s);
	if(curLgh == NULL)			return -1;
	curLgh->InsertAsChildOf(baseNode);
	curLgh->SetName(l->argv[1]);
	curLgh->oldStyle = false;

	ZPRS	*curPRS;
	curPRS = curLgh->GetPRS();


	MMpush(machineForLoad, PTOM(ptrHashTable) );
	MMpush(machineForLoad, PTOM(ptrHashMat)   );
	MMpush(machineForLoad, PTOM(ptrHashTex)   );
	createH3D(machineForLoad, (int)curLgh, ptrHashTable);
	ptrHashTex   = MTOP( MMpull(machineForLoad) );
	ptrHashMat   = MTOP( MMpull(machineForLoad) );
	ptrHashTable = MTOP( MMpull(machineForLoad) );


	if(M3Dnextline(l))
    {
		MMechostr(1,"unexpected end of file - M3DloadColorLight in Light : %s\n",curLgh->name.c_str());
		errorMsg += string("unexpected end of file - M3DloadColorLight");
		return -1;
    }
	if(l->argn<6)
    {
		MMechostr(1,"position expected - M3DloadColorLight in Light : %s\n",curLgh->name.c_str());
		errorMsg += string("position expected - M3DloadLight");
		return -1;
    }

	curPRS->coeffM3D = coeff;
	curPRS->SetPos( atof(l->argv[0])/coeff,atof(l->argv[1])/coeff, -atof(l->argv[2])/coeff);
	curPRS->SetAng( atof(l->argv[4])*360.0f/CONST_ANGLE,  atof(l->argv[3])*360.0f/CONST_ANGLE, atof(l->argv[5])*360.0f/CONST_ANGLE);

	if(l->argn>6)			curPRS->SetScale(atof(l->argv[6])/100.0f);

	// lit le range de visibilité
	if(l->argn>8)
	{
		if(!strcmp(l->argv[7],"RANGE_INFINITY"))	curLgh->rangeMIN = 0;
		else										curLgh->rangeMIN = atof(l->argv[7]);
		if(!strcmp(l->argv[8],"RANGE_INFINITY"))	curLgh->rangeMAX = RANGE_INFINITY;
		else										curLgh->rangeMAX = atof(l->argv[8]);
	}

	if(M3Dnextline(l))
    {
		MMechostr(1,"unexpected end of file - M3DloadColorLight in Light : %s\n",curLgh->name.c_str());
		errorMsg += string("unexpected end of file - M3DloadLight");
		return -1;
    }


	// Récupération du type de light
	if(l->argn>0)
	{
		// Récupération du type de light
		if(!strcmpi(l->argv[0],"ambient"))		curLgh->LightType = LIGHT_AMBIENT;
		if(!strcmpi(l->argv[0],"para"))			curLgh->LightType = LIGHT_PARA;
		if(!strcmpi(l->argv[0],"omni"))			curLgh->LightType = LIGHT_OMNI;
		if(!strcmpi(l->argv[0],"spot"))			curLgh->LightType = LIGHT_SPOT;
	}

	// Récupération des params de light
	int		color;
	if(l->argn>1)
	{
		sscanf(l->argv[1],"%x",&color);
		curLgh->SetAmbient( ((float)((color&0x00ff0000)>>16))/CONST_COLOR, ((float)((color&0x0000ff00)>>8))/CONST_COLOR, ((float)((color&0x000000ff)))/CONST_COLOR, 1.0f);
		curLgh->alpha = (int) ((curLgh->ambient[0]+curLgh->ambient[1]+curLgh->ambient[2]) * 64.0f / 3.0f);
	}
	if(l->argn>2)
	{
		sscanf(l->argv[2],"%x",&color);
		curLgh->SetDiffuse( ((float)((color&0x00ff0000)>>16))/CONST_COLOR, ((float)((color&0x0000ff00)>>8))/CONST_COLOR, ((float)((color&0x000000ff)))/CONST_COLOR, 1.0f);
		curLgh->beta = (int) ((curLgh->diffuse[0]+curLgh->diffuse[1]+curLgh->diffuse[2]) * 64.0f / 3.0f);
	}
	if(l->argn>3)
	{
		sscanf(l->argv[3],"%x",&color);
		curLgh->SetSpecular(((float)((color&0x00ff0000)>>16))/CONST_COLOR, ((float)((color&0x0000ff00)>>8))/CONST_COLOR, ((float)((color&0x000000ff)))/CONST_COLOR, 1.0f);
	}

	if(l->argn>4)		curLgh->spot_cut_off	= atoi(l->argv[4]);
	else				curLgh->spot_cut_off	= 180;

	if(l->argn>5)		curLgh->attenuate_const = atof(l->argv[5]) / 100.0f;
	else				curLgh->attenuate_const = 1.0f;

	if(l->argn>6)		curLgh->attenuate_quadr = atof(l->argv[6]) / 100.0f;
	else				curLgh->attenuate_quadr = 0.0f;


	// Recursion
	if(M3Dnextline(l))
    {
		MMechostr(1,"unexpected end of file - M3DloadColorLight in Light : %s\n",curLgh->name.c_str());
		errorMsg += string("unexpected end of file - M3DloadLight");
		return -1;
    }

	if (M3DrecursObj(s, l, curLgh, coeff))				return -1;
	
	if (strcmp(l->argv[0],"}"))
    {
		MMechostr(1,"} expected - M3DloadColorLight in Light : %s\n",curLgh->name.c_str());
		errorMsg += string("} expected - M3DloadLight");
		return -1;
    }

	return 0;
}



///////////////////////////////////////////////////////////////////////////////////////////////
///		M3DloadEmitter																		///
///																							///
///	Lit les caractères dans 'comm', supprime les commentaires, stocke le result dans mots	///
/// Renvoit le nombre de caractères lus sans commentaires									///
///////////////////////////////////////////////////////////////////////////////////////////////
int M3DloadEmitter(ZScene *s, load3d l, ZNode *nodeBase, float coeff)
{
	ZVector3	pos;
	ZVector3	rot;
	int			mask = 0;
	float		life;
	T_VOLUME	volume;
	string		name = l->argv[1];

	if (M3Dnextline(l))
    {
		MMechostr(1,"unexpected end of file - M3DloadEmitter in emitter : %s\n",name.c_str());
		errorMsg += string("unexpected end of file - M3DloadEmitter");
		return -1;
    }
	if (l->argn<6)
    {
		MMechostr(1,"position expected - M3DloadEmitter in emitter : %s\n",name.c_str());
		errorMsg += string("position expected - M3DloadEmitter");
		return -1;
    }
	
	pos.SetCoord(atof(l->argv[0])/coeff,atof(l->argv[1])/coeff, -atof(l->argv[2])/coeff);
	rot.SetCoord(atof(l->argv[4])*360.0f/CONST_ANGLE,  atof(l->argv[3])*360.0f/CONST_ANGLE, atof(l->argv[5])*360.0f/CONST_ANGLE);

	// lit le range de visibilité
	int rangeMIN = -1;
	int rangeMAX = -1;
	if(l->argn>8)
	{
		if(!strcmp(l->argv[7],"RANGE_INFINITY"))	rangeMIN = 0;
		else										rangeMIN = atof(l->argv[7]);
		if(!strcmp(l->argv[8],"RANGE_INFINITY"))	rangeMAX = RANGE_INFINITY;
		else										rangeMAX = atof(l->argv[8]);
	}

	// Lit le mask de l'emitter
	int tmp = M3Dnextline(l);
	if (tmp)
    {
		MMechostr(1,"unexpected end of file - M3DloadEmitter in emitter : %s\n",name.c_str());
		errorMsg += string("unexpected end of file - M3DloadEmitter");
		return -1;
    }

	bool ok = true;
	mask	= 0;
	do
		if(strcmp(l->argv[0], "mask")==0)
		{
			if(strcmp(l->argv[1], "infinit")==0)	mask += PCL_INFINIT;
			else if(strcmp(l->argv[1], "additive")==0)	mask += PCL_ADDITIVE;

			if(l->argn==3)
				if(strcmp(l->argv[2], "infinit")==0)	mask += PCL_INFINIT;
				else if(strcmp(l->argv[2], "additive")==0)	mask += PCL_ADDITIVE;
			

			tmp = M3Dnextline(l);
		}
		else
		{
			ok = false;
		}
	while(ok);


/*	if (M3Dnextline(l))
    {
		MMechostr(1,"unexpected end of file - M3DloadEmitter in emitter : %s\n",name.c_str());
		errorMsg += string("unexpected end of file - M3DloadEmitter");
		return -1;
    }
	if(strcmp(l->argv[0], "mask")==0)	mask = atoi(l->argv[1]);
*/


	// Lit la life de l'emitter
	if (tmp)
    {
		MMechostr(1,"unexpected end of file - M3DloadEmitter in emitter : %s\n",name.c_str());
		errorMsg += string("unexpected end of file - M3DloadEmitter");
		return -1;
    }

	if(strcmp(l->argv[0], "life")==0)	life = atof(l->argv[1])/100.0f;


	// Lit le volume de l'emitter
	if (M3Dnextline(l))
    {
		MMechostr(1,"unexpected end of file - M3DloadEmitter in emitter : %s\n",name.c_str());
		errorMsg += string("unexpected end of file - M3DloadEmitter");
		return -1;
    }

	if(strcmp(l->argv[0], "volume")==0)
	{
		if(strcmp(l->argv[1], "cone")==0)	volume.type = VOLUME_CONE;
		if(strcmp(l->argv[1], "sphere")==0)	volume.type = VOLUME_SPHERE;
		if(strcmp(l->argv[1], "plan")==0)	volume.type = VOLUME_PLAN;
		if(strcmp(l->argv[1], "line")==0)	volume.type = VOLUME_LINE;
	}
	
	// Lit le vectorA de l'emitter
	if (M3Dnextline(l))
    {
		MMechostr(1,"unexpected end of file - M3DloadEmitter in emitter : %s\n",name.c_str());
		errorMsg += string("unexpected end of file - M3DloadEmitter");
		return -1;
    }

	if(strcmp(l->argv[0], "vectorA")==0)	volume.vectorA.SetCoord(atof(l->argv[1])/100.0f, atof(l->argv[2])/100.0f, atof(l->argv[3])/100.0f);

	// Lit le vectorB de l'emitter
	if (M3Dnextline(l))
    {
		MMechostr(1,"unexpected end of file - M3DloadEmitter in emitter : %s\n",name.c_str());
		errorMsg += string("unexpected end of file - M3DloadEmitter");
		return -1;
    }

	if(strcmp(l->argv[0], "vectorB")==0)	volume.vectorB.SetCoord(atof(l->argv[1]), atof(l->argv[2]), atof(l->argv[3]));


	ZEmitter	*curEmitter = new ZEmitter((int)s, mask, life, volume);
	if(curEmitter == NULL)	return -1;

	if(rangeMIN!=-1)	curEmitter->rangeMIN = rangeMIN;
	if(rangeMAX!=-1)	curEmitter->rangeMAX = rangeMAX;

	curEmitter->InsertAsChildOf(nodeBase);
	curEmitter->SetName(name);
	curEmitter->GetPRS()->SetPos(pos);
	curEmitter->GetPRS()->SetAng(rot);

	// Lit les particules liées à l'emitter
	if (M3Dnextline(l))
    {
		MMechostr(1,"unexpected end of file - M3DloadEmitter in emitter : %s\n",name.c_str());
		errorMsg += string("unexpected end of file - M3DloadEmitter");
		return -1;
    }

	string _name;
	while(strcmp(l->argv[0], "particle")==0 && l->argn==2)
	{
		_name = l->argv[1];
		for(int k=0; k<s->PclDef.Size() && s->PclDef[k]->name!=_name; k++);

		if(k<s->PclDef.Size())
			curEmitter->LinkParticle(s->PclDef[k]);

		if (M3Dnextline(l))
		{	
			MMechostr(1,"unexpected end of file - M3DloadEmitter in emitter : %s\n",name.c_str());
			errorMsg += string("unexpected end of file - M3DloadEmitter");
			return -1;
		}
	}

	while(strcmp(l->argv[0], "effect")==0 && l->argn==2)
	{
		_name = l->argv[1];
		for(int k=0; k<s->PclEff.Size() && s->PclEff[k]->name!=_name; k++);

		if(k<s->PclEff.Size())
			curEmitter->LinkEffect(s->PclEff[k]);

		if (M3Dnextline(l))
		{	
			MMechostr(1,"unexpected end of file - M3DloadEmitter in emitter : %s\n",name.c_str());
			errorMsg += string("unexpected end of file - M3DloadEmitter");
			return -1;
		}
	}
		

	MMpush(machineForLoad, PTOM(ptrHashTable) );
	MMpush(machineForLoad, PTOM(ptrHashMat)   );
	MMpush(machineForLoad, PTOM(ptrHashTex)   );
	createH3D(machineForLoad, (int)curEmitter, ptrHashTable);
	ptrHashTex   = MTOP( MMpull(machineForLoad) );
	ptrHashMat   = MTOP( MMpull(machineForLoad) );
	ptrHashTable = MTOP( MMpull(machineForLoad) );


	if (M3DrecursObj(s, l, curEmitter, coeff))		return -1;
	if (strcmp(l->argv[0],"}"))
    {
		MMechostr(1,"} expected - M3DloadEmitter in emitter : %s\n",name.c_str());
		errorMsg += string("} expected ");
		return -1;
    }
  
	return 0;
}



///////////////////////////////////////////////////////////////////////////////////////////////
///		M3DloadParticle																		///
///																							///
///	Lit les caractères dans 'comm', supprime les commentaires, stocke le result dans mots	///
/// Renvoit le nombre de caractères lus sans commentaires									///
///////////////////////////////////////////////////////////////////////////////////////////////
int M3DloadParticle(ZScene *s, load3d l, ZNode *nodeBase, float coeff)
{
	int				mask = 0;
	float			life;
	float			rate;
	float			weight;
	float			size = 100.f;
	float			spin = 100.f;
	float			polarity;
	ZMesh			*topo;
	T_COLOR			col;
	T_PARAM			par;
	string			name = l->argv[1];

	// Lit le mask de la particule
	int tmp = M3Dnextline(l);
	if (tmp)
    {
		MMechostr(1,"unexpected end of file - M3DloadEmitter in emitter : %s\n",name.c_str());
		errorMsg += string("unexpected end of file - M3DloadEmitter");
		return -1;
    }

	bool ok = true;
	do
		if(strcmp(l->argv[0], "mask")==0)
		{
			if(strcmp(l->argv[1], "billboard")==0)		mask += PCL_BILLBOARD;
			else if(strcmp(l->argv[1], "rainbow")==0)	mask += PCL_RAINBOW;
			else if(strcmp(l->argv[1], "jitter")==0)	mask += PCL_JITTER;
			tmp = M3Dnextline(l);
		}
		else
		{
			ok = false;
		}
	while(ok);


	// Lit la life de la particule
	if (tmp)
    {
		MMechostr(1,"unexpected end of file - M3DloadEmitter in emitter : %s\n",name.c_str());
		errorMsg += string("unexpected end of file - M3DloadEmitter");
		return -1;
    }

	if(strcmp(l->argv[0], "life")==0)	life = atof(l->argv[1])/100.0f;
	

	// Lit le rate de la particule
	if (M3Dnextline(l))
    {
		MMechostr(1,"unexpected end of file - M3DloadEmitter in emitter : %s\n",name.c_str());
		errorMsg += string("unexpected end of file - M3DloadEmitter");
		return -1;
    }

	if(strcmp(l->argv[0], "rate")==0)	rate = atof(l->argv[1])/100.0f;

	// Lit le weight de la particule
	if (M3Dnextline(l))
    {
		MMechostr(1,"unexpected end of file - M3DloadEmitter in emitter : %s\n",name.c_str());
		errorMsg += string("unexpected end of file - M3DloadEmitter");
		return -1;
    }

	if(strcmp(l->argv[0], "weight")==0)	weight = atof(l->argv[1])/100.0f;

	// Lit la size de la particule
	if (M3Dnextline(l))
    {
		MMechostr(1,"unexpected end of file - M3DloadEmitter in emitter : %s\n",name.c_str());
		errorMsg += string("unexpected end of file - M3DloadEmitter");
		return -1;
    }

	if(strcmp(l->argv[0], "size")==0)	size = atof(l->argv[1])/100.0f;

	//	Lit le spin de la particule
	if (M3Dnextline(l))
    {
		MMechostr(1,"unexpected end of file - M3DloadEmitter in emitter : %s\n",name.c_str());
		errorMsg += string("unexpected end of file - M3DloadEmitter");
		return -1;
    }

	if(strcmp(l->argv[0], "spin")==0)	spin = atof(l->argv[1])/100.0f;

	// Lit la polarite de la particule
	if (M3Dnextline(l))
    {
		MMechostr(1,"unexpected end of file - M3DloadEmitter in emitter : %s\n",name.c_str());
		errorMsg += string("unexpected end of file - M3DloadEmitter");
		return -1;
    }

	if(strcmp(l->argv[0], "polarity")==0)	polarity = atof(l->argv[1])/100.0f;


	//	Lit la topologie de la particule
	if (M3Dnextline(l))
    {
		MMechostr(1,"unexpected end of file - M3DloadEmitter in emitter : %s\n",name.c_str());
		errorMsg += string("unexpected end of file - M3DloadEmitter");
		return -1;
    }

	// Lecture référencée SIMPLE
	if((l->argn==2)&&(!strcmp(l->argv[0],"topo")))
	{
		string	nomTopo;
		nomTopo = string(&(l->argv[1][0]));

		// Recherche d'une topo similaire existante
		for(int k=0; k<s->MshList.Size() && s->MshList[k]->name!=nomTopo; k++);

		// Utilisation de la topo existante ou...
		if(k<s->MshList.Size())
		{
			topo = s->MshList[k];
		}
		else	// ...plantage !!
		{			
			MMechostr(1,"topology expected - M3DloadParticle in particle : %s\n",name.c_str());
			errorMsg += string("topology expected");
			return -1;
		}
	}


	ZParticle	*curPart = new ZParticle((int)s, topo, mask, life, rate, weight, size, spin, polarity);

	if(curPart == NULL)	return -1;
	s->PclDef.Add(curPart);
	curPart->SetName(name);


	MMpush(machineForLoad, PTOM(ptrHashTable) );
	MMpush(machineForLoad, PTOM(ptrHashMat)   );
	MMpush(machineForLoad, PTOM(ptrHashTex)   );
	createH3D(machineForLoad, (int)curPart, ptrHashTable);
	ptrHashTex   = MTOP( MMpull(machineForLoad) );
	ptrHashMat   = MTOP( MMpull(machineForLoad) );
	ptrHashTable = MTOP( MMpull(machineForLoad) );


	/*	Lit les tailles de la particule								*/
	if (M3Dnextline(l))
    {
		MMechostr(1,"unexpected end of file - M3DloadEmitter in emitter : %s\n",name.c_str());
		errorMsg += string("unexpected end of file - M3DloadEmitter");
		return -1;
    }

	if(strcmp(l->argv[0], "tsize")==0)
	{
		curPart->size.resize(0);
		while((l->argn==3)&&(!strcmp(l->argv[0],"tsize")))
			{
				par.value	= atof(l->argv[1])/100.f;
				par.pos		= atof(l->argv[2]);
				curPart->size.push_back(par);
				M3Dnextline(l);
			}
	}

	/*	Lit les spins de la particule								*/
	if(strcmp(l->argv[0], "tspin")==0)
	{
		curPart->size.resize(0);
		while((l->argn==3)&&(!strcmp(l->argv[0],"tspin")))
			{
				par.value	= atof(l->argv[1])/100.f;
				par.pos		= atof(l->argv[2]);
				curPart->spin.push_back(par);
				M3Dnextline(l);
			}
	}

	curPart->color.resize(0);

	if(strcmp(l->argv[0], "color")==0)
	{
		int c;
		sscanf(l->argv[1],"%x",&c);

		float r,g,b,a;

		r = (float)((c&0xff000000)>>24)/CONST_COLOR;
		g = (float)((c&0x00ff0000)>>16)/CONST_COLOR;
		b = (float)((c&0x0000ff00)>>8)/CONST_COLOR;
		a = (float)(c&0x000000ff)/CONST_COLOR;

		col.pos = 0.0f;
		col.value.SetCoord(r,g,b,a);
		curPart->color.push_back(col);
	}
	/************************************************************/
	else
	{
		bool ok = true;
		do
			if ((l->argn==3)&&(!strcmp(l->argv[0],"tcolor")))
			{
				M3DloadColor(s, l, (ZNode*)curPart, coeff);
				M3Dnextline(l);
			}
			else if ((l->argn==1)&&(!strcmp(l->argv[0],"}")))	ok = false;
			else
			{
				MMechostr(1,"unexpected end of file - M3DrecursObj in BaseNode : %s\n",nodeBase->name.c_str());
				errorMsg += string("unexpected end of file - M3DrecursObj");
				return -1;
			}
		while(ok);
	}
  
	return 0;
}


///////////////////////////////////////////////////////////////////////////////////////////////
///		M3DloadColor																		///
///																							///
///	Lit les caractères dans 'comm', supprime les commentaires, stocke le result dans mots	///
/// Renvoit le nombre de caractères lus sans commentaires									///
///////////////////////////////////////////////////////////////////////////////////////////////
int M3DloadColor(ZScene *s, load3d l, ZNode *nodeBase, float coeff)
{
	T_COLOR			col;

	int c;
	sscanf(l->argv[1],"%x",&c);

	float r,g,b,a;

	r = (float)((c&0xff000000)>>24)/CONST_COLOR;
	g = (float)((c&0x00ff0000)>>16)/CONST_COLOR;
	b = (float)((c&0x0000ff00)>>8)/CONST_COLOR;
	a = (float)(c&0x000000ff)/CONST_COLOR;

/*
	int r,g,b,a;
	r = (c>>24)&0x000000ff;
	g = (c>>16)&0x000000ff;
	b = (c>>8 )&0x000000ff;
	a = (c    )&0x000000ff;
*/

	col.pos = atof(l->argv[2]);
	col.value.SetCoord(r,g,b,a);
	/************************************************************/


	if(nodeBase->type == PCLDEF_TYPE_ID)
	{
		ZParticle *part = (ZParticle*)nodeBase;
		part->color.push_back(col);
	}

	return 0;
}















///////////////////////////////////////////////////////////////////////////////////////////////
///		M3DloadEffect																		///
///																							///
///	Lit les caractères dans 'comm', supprime les commentaires, stocke le result dans mots	///
/// Renvoit le nombre de caractères lus sans commentaires									///
///////////////////////////////////////////////////////////////////////////////////////////////
int M3DloadEffect(ZScene *s, load3d l, ZNode *nodeBase, float coeff)
{
	int			type;
	ZVector3	vA;
	ZVector3	vB;
	ZVector3	vC;
	
	string		name = l->argv[1];


	/*	Lit le type de l'effet									*/
	if (M3Dnextline(l))
    {
		MMechostr(1,"unexpected end of file - M3DloadEffect in effect : %s\n",name.c_str());
		errorMsg += string("unexpected end of file - M3DloadEffect");
		return -1;
    }
	
	if(strcmp(l->argv[0], "type")==0)
	{
			 if(strcmp(l->argv[1], "constant")==0)	type = EFFECT_CONSTANT;
		else if(strcmp(l->argv[1], "electric")==0)	type = EFFECT_ELECTRIC;
		else if(strcmp(l->argv[1], "magnetic")==0)	type = EFFECT_MAGNETIC;
		else if(strcmp(l->argv[1], "helicoid")==0)	type = EFFECT_HELICOID;
		else if(strcmp(l->argv[1], "chaotic0")==0)	type = EFFECT_CHAOTIC0;
		else if(strcmp(l->argv[1], "chaotic1")==0)	type = EFFECT_CHAOTIC1;
	}
	/************************************************************/


	/*	Lit le vectorA de l'emitter								*/
	if (M3Dnextline(l))
    {
		MMechostr(1,"unexpected end of file - M3DloadEffect in effect : %s\n",name.c_str());
		errorMsg += string("unexpected end of file - M3DloadEffect");
		return -1;
    }

	if(strcmp(l->argv[0], "vectorA")==0)	vA.SetCoord(atof(l->argv[1])/100.0f, atof(l->argv[2])/100.0f, -atof(l->argv[3])/100.0f);
	/************************************************************/

	/*	Lit le vectorB de l'emitter								*/
	if (M3Dnextline(l))
    {
		MMechostr(1,"unexpected end of file - M3DloadEffect in effect : %s\n",name.c_str());
		errorMsg += string("unexpected end of file - M3DloadEffect");
		return -1;
    }

	if(strcmp(l->argv[0], "vectorB")==0)	vB.SetCoord(atof(l->argv[1])/100.0f, atof(l->argv[2])/100.0f, -atof(l->argv[3])/100.0f);
	/************************************************************/


	/*	Lit le vectorC de l'emitter								*/
	if (M3Dnextline(l))
    {
		MMechostr(1,"unexpected end of file - M3DloadEffect in effect : %s\n",name.c_str());
		errorMsg += string("unexpected end of file - M3DloadEffect");
		return -1;
    }

	if(strcmp(l->argv[0], "vectorC")==0)	vC.SetCoord(atof(l->argv[1])/100.0f, atof(l->argv[2])/100.0f, -atof(l->argv[3])/100.0f);
	/************************************************************/


	ZEffect	*curEffect = new ZEffect((int)s, type, vA, vB, vC);

	if(curEffect == NULL)	return -1;
	s->PclEff.Add(curEffect);
	curEffect->SetName(name);


	MMpush(machineForLoad, PTOM(ptrHashTable) );
	MMpush(machineForLoad, PTOM(ptrHashMat)   );
	MMpush(machineForLoad, PTOM(ptrHashTex)   );
	createH3D(machineForLoad, (int)curEffect, ptrHashTable);
	ptrHashTex   = MTOP( MMpull(machineForLoad) );
	ptrHashMat   = MTOP( MMpull(machineForLoad) );
	ptrHashTable = MTOP( MMpull(machineForLoad) );


	if (M3Dnextline(l))
    {
		MMechostr(1,"unexpected end of file - M3DloadEffect in effect : %s\n",name.c_str());
		errorMsg += string("unexpected end of file - M3DloadEffect");
		return -1;
    }

	if (strcmp(l->argv[0],"}"))
    {
		MMechostr(1,"} expected - M3DloadEffect in effect : %s\n",name.c_str());
		errorMsg += string("} expected ");
		return -1;
    }
  
	return 0;
}



int M3DsetMatColor(ZScene *s, ZMaterial *curMat, char *buf)
{
	int x;
	sscanf(buf,"%x",&x);

	curMat->SetDefaultColor(x);

	curMat->color.x = (float)((x&0x00ff0000)>>16)/CONST_COLOR;
	curMat->color.y = (float)((x&0x0000ff00)>>8)/CONST_COLOR;
	curMat->color.z = (float)(x&0x000000ff)/CONST_COLOR;

	return 0;
}


int M3DsetMatColor1(ZScene *s, ZMaterial *curMat, char *buf)
{
	int x;
	sscanf(buf,"%x",&x);

	curMat->color1_24 = x;

	curMat->color1.x = (float)((x&0x00ff0000)>>16)/CONST_COLOR;
	curMat->color1.y = (float)((x&0x0000ff00)>>8)/CONST_COLOR;
	curMat->color1.z = (float)(x&0x000000ff)/CONST_COLOR;

	return 0;
}


int M3DsetMatColor2(ZScene *s, ZMaterial *curMat, char *buf)
{
	int x;
	sscanf(buf,"%x",&x);

	curMat->color2_24 = x;

	curMat->color2.x = (float)((x&0x00ff0000)>>16)/CONST_COLOR;
	curMat->color2.y = (float)((x&0x0000ff00)>>8)/CONST_COLOR;
	curMat->color2.z = (float)(x&0x000000ff)/CONST_COLOR;

	return 0;
}


int M3DsetMatType(ZScene *s, ZMaterial *curMat, char *name)
{
	if		(!strcmp(name,"FLAT"))				curMat->DisableMode(RENDER_TEXTURED);
	else if (!strcmp(name,"LIGHT"))				curMat->EnableMode(RENDER_LIGHTED);
	else if (!strcmp(name,"NOLIGHT"))			curMat->DisableMode(RENDER_LIGHTED);
	else if (!strcmp(name,"GOURAUD"))			curMat->EnableMode(RENDER_GOURAUD_LIGHT);
	else if (!strcmp(name,"ENV"))				curMat->EnableMode(RENDER_ENVMAP);
	else if (!strcmp(name,"TEXTURED"))			curMat->EnableMode(RENDER_TEXTURED);
	else if (!strcmp(name,"TEXTURED_BIS"))		curMat->EnableMode(RENDER_TEXTURED_BIS);
	else if (!strcmp(name,"COLOR1"))			curMat->EnableMode(RENDER_COLOR1);
	else if (!strcmp(name,"COLOR2"))			curMat->EnableMode(RENDER_COLOR2);
	else if (!strcmp(name,"COLOR_VERTEX"))		curMat->EnableMode(RENDER_COLOR_VERTEX);
	else if (!strncmp(name,"TRANSPARENCY",12))
	{
		curMat->EnableMode(RENDER_TRANSP);
		curMat->SetCoeffTransp(atoi(&name[12]));
		curMat->coeffTransp   = 1.0f-((float)curMat->GetCoeffTransp())/CONST_COLOR;
	}

	return 0;
}


int M3DloadFilter(char *buf, ZTexture *curTex)
{
	int pos = 1;

	while(buf[pos]!='%')
	{
		pos++;
/*		if(buf[pos]=='C')
		{
			pos++;
			int x;
			sscanf(&buf[pos],"%8x",&x);

			curTex->C  = true;
			curTex->filterB  = (unsigned char) ((x&0xff000000)>>24);
			curTex->filterG  = (unsigned char) ((x&0x00ff0000)>>16);
			curTex->filterR  = (unsigned char) ((x&0x0000ff00)>>8);
			curTex->rate 	 = (unsigned char)  (x&0x000000ff);

			pos+=8;
		}
		else if(buf[pos]=='X')
		{
			pos++;
			curTex->X  = true;
		}
		else if(buf[pos]=='Y')
		{
			pos++;
			curTex->Y  = true;
		}
		else if(buf[pos]=='A')
		{
			pos++;
			int x = 0;
			sscanf(&buf[pos],"%8x",&x);

			curTex->A  = true;
			curTex->filterB  = (unsigned char) ((x&0xff000000)>>24);
			curTex->filterG  = (unsigned char) ((x&0x00ff0000)>>16);
			curTex->filterR  = (unsigned char) ((x&0x0000ff00)>>8);
			curTex->rate 	 = (unsigned char)  (x&0x000000ff);

			pos+=8;
		}
		else if(buf[pos]=='R')
		{
			pos++;
			int x;
			sscanf(&buf[pos],"%4x",&x);

			curTex->R  = true;
			curTex->value  = x;

			pos+=4;
		}
		else if(buf[pos]=='S')
		{
			pos++;
			int x;
			sscanf(&buf[pos],"%6x",&x);

			curTex->S  = true;
			curTex->value  = x>>8;
			curTex->rate   = (unsigned char) (x&0x000000ff);

			pos+=6;
		}
*/	}

	pos++;

	return pos;
}



///////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3DloadMat																			///
///																							///
///	Lit les caractères dans 'comm', supprime les commentaires, stocke le result dans mots	///
/// Renvoit le nombre de caractères lus sans commentaires									///
///////////////////////////////////////////////////////////////////////////////////////////////
int M3DloadMat(ZScene *s, load3d l)
{
	string MatName(l->argv[1]);

	ZMaterial	*curMat;
	ZTexture	*curTex;

	curMat = new ZMaterial(s->accelerated);
	if(!curMat)		return -1;
	s->MatList.Add(curMat);

	curMat->SetName(MatName);

	MMpush(machineForLoad, PTOM(ptrHashTable) );
	MMpush(machineForLoad, PTOM(ptrHashMat)   );
	MMpush(machineForLoad, PTOM(ptrHashTex)   );
	createHmatHtx(machineForLoad, (int)curMat, ptrHashMat);
	ptrHashTex   = MTOP( MMpull(machineForLoad) );
	ptrHashMat   = MTOP( MMpull(machineForLoad) );
	ptrHashTable = MTOP( MMpull(machineForLoad) );

	while(M3Dnextline(l)==0)
    {
		// Fin de déclaration de matériau
		if ((l->argn==1)&&(!strcmp(l->argv[0],"}")))
		{
			curTex = curMat->GetTexture1();
			if((curTex!=NULL)&&(curTex->activated)&&(curTex->renamed))
			{
				curTex->CreateModifiedImg();
				curTex->SetupTexture();
			}

			curTex = curMat->GetTexture2();
			if((curTex!=NULL)&&(curTex->activated)&&(curTex->renamed))
			{
				curTex->CreateModifiedImg();
				curTex->SetupTexture();
			}
			return 0;
		}
		// Définition de la couleur par défaut
		if ((l->argn==2)&&(!strcmp(l->argv[0],"color")))
        {
			if(M3DsetMatColor(s, curMat, l->argv[1]))		return -1;
        }
		else
		// Définition de la couleur n°1
		if ((l->argn==2)&&(!strcmp(l->argv[0],"facecolor1")))
        {
			if(M3DsetMatColor1(s, curMat, l->argv[1]))		return -1;
        }
		else
		// Définition de la couleur n°2
		if ((l->argn==2)&&(!strcmp(l->argv[0],"facecolor2")))
        {
			if(M3DsetMatColor2(s, curMat, l->argv[1]))		return -1;
        }
		else 
		// Définition de la texture primaire
		if ((l->argn==2)&&(!strcmp(l->argv[0],"texture")))
        {
			string	nomTexture;
			nomTexture = string(&(l->argv[1][0]));

			// Recherche d'une texture similaire existante
			for(int k=0; k<s->TexList.Size() && s->TexList[k]->name!=nomTexture; k++);

			// Utilisation de la texture existante ou...
			if(k<s->TexList.Size())
			{
				curTex = s->TexList[k];
				curMat->SetTexture1(curTex);
				curMat->EnableMode(RENDER_TEXTURED);
			}
			// ... création d'une nouvelle texture
			else
			{			
				curTex = new ZTexture(s->accelerated);
				if(!curTex)	return -1;
				s->TexList.Add(curTex);

				curTex->SetTextureFilter(s->generalTextureFilter);

				int debName = 0;
				if(l->argv[1][0]=='%')			debName = M3DloadFilter(l->argv[1], curTex);

				curTex->SetFileName(&(l->argv[1][0]));
				curTex->SetName(&(l->argv[1][0]));
				curTex->renamed = true;

				curMat->EnableMode(RENDER_TEXTURED);

				bool	test = true;
				char	name[SIZESIGN];
				if(SPfindfile((packdir)SCgetExtra("FirstPack"), &(l->argv[1][debName]), NULL, name)==-1)		test=false;
				if(test)	
				{
					if(curTex->LoadTexture(name)==false)
					{
						curTex->activated = false;
						free(curTex->Image);			curTex->Image		= NULL;	
						free(curTex->ImageModif);		curTex->ImageModif  = NULL;
						test = false;
					}
				}

				MMpush(machineForLoad, PTOM(ptrHashTable) );
				MMpush(machineForLoad, PTOM(ptrHashMat)   );
				MMpush(machineForLoad, PTOM(ptrHashTex)   );
				createHmatHtx(machineForLoad, (int)curTex, ptrHashTex);
				ptrHashTex   = MTOP( MMpull(machineForLoad) );
				ptrHashMat   = MTOP( MMpull(machineForLoad) );
				ptrHashTable = MTOP( MMpull(machineForLoad) );
				
				curMat->SetTexture1(curTex);
			}
		}
		else
		// Définition de la texture secondaire
		if ((l->argn==3)&&(!strcmp(l->argv[0],"texturebis")))
        {
			string	nomTexture;
			nomTexture = string(&(l->argv[1][0]));

			// Recherche d'une texture similaire existante
			for(int k=0; k<s->TexList.Size() && s->TexList[k]->name!=nomTexture; k++);

			// Utilisation de la texture existante ou...
			if(k<s->TexList.Size())
			{
				curTex = s->TexList[k];
				curMat->SetTexture2(curTex);
				curMat->EnableMode(RENDER_TEXTURED_BIS);
				curMat->alpha = atof(l->argv[2]);
			}
			// ... création d'une nouvelle texture
			else
			{	
				curTex = new ZTexture(s->accelerated);
				if(!curTex)	return -1;
				s->TexList.Add(curTex);

				curTex->SetTextureFilter(s->generalTextureFilter);

				int debName = 0;
				if(l->argv[1][0]=='%')			debName = M3DloadFilter(l->argv[1], curTex);

				curTex->SetFileName(&(l->argv[1][0]));
				curTex->SetName(&(l->argv[1][0]));
				curTex->renamed = true;

				curMat->EnableMode(RENDER_TEXTURED_BIS);
				curMat->alpha = atof(l->argv[2]);

				bool	test = true;
				char	name[SIZESIGN];
				if(SPfindfile((packdir)SCgetExtra("FirstPack"), &(l->argv[1][debName]), NULL, name)==-1)		test=false;
				if(test)	
				{	
					if(curTex->LoadTexture(name)==false)
					{
						curTex->activated = false;
						free(curTex->Image);			curTex->Image = NULL;	
						free(curTex->ImageModif);		curTex->ImageModif = NULL;
						test = false;
					}
				}

				MMpush(machineForLoad, PTOM(ptrHashTable) );
				MMpush(machineForLoad, PTOM(ptrHashMat)   );
				MMpush(machineForLoad, PTOM(ptrHashTex)   );
				createHmatHtx(machineForLoad, (int)curTex, ptrHashTex);
				ptrHashTex   = MTOP( MMpull(machineForLoad) );
				ptrHashMat   = MTOP( MMpull(machineForLoad) );
				ptrHashTable = MTOP( MMpull(machineForLoad) );

				curMat->SetTexture2(curTex);
			}
		}
		else
		// Définition des flags de rendu
		if ((l->argn==2)&&(!strcmp(l->argv[0],"type")))
        {
			if(M3DsetMatType(s, curMat, l->argv[1]))		return -1;
        }
		else
		// et dans le cas d'une erreur.....
        {
			MMechostr(1,"}, color, texture or type expected - M3DloadMat in Material : %s\n",curMat->name.c_str());
			errorMsg += string("}, color, texture or type expected - M3DloadMat");
			return -1;
        }
    }

	MMechostr(1,"unexpected end of file - M3DloadMat in Material : %s\n",curMat->name.c_str());
	errorMsg += string("unexpected end of file - M3DloadMat");
	return -1;
}



///////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3DloadCollRec																		///
///////////////////////////////////////////////////////////////////////////////////////////////
int M3DloadCollRec(ZScene *s, load3d l, ZColl *coll, float coeff)
{
	if (l->argn!=1)					return 0;
	if (strcmp(l->argv[0],"("))		return 0;
	if (M3Dnextline(l))
    {
		MMechostr(1,"unexpected end of file - M3DloadCollRec\n");
		errorMsg += string("unexpected end of file - M3DloadCollRec");
		return -1;
    }

	// Collision fille : A
	ZColl	*newColl;
	newColl = new ZColl((int)s, -1);
	if(newColl==NULL)					return -1;

	if (M3DloadColNode(s, l, newColl, coeff))			return -1;
	coll->colA = newColl;

	// Collision fille : B
	if ((l->argn==1)&&(!strcmp(l->argv[0],"|")))
	{
		if (M3Dnextline(l))
		{
			MMechostr(1,"unexpected end of file - M3DloadCollRec\n");
			errorMsg += string("unexpected end of file - M3DloadCollRec");
			return -1;
		}
		newColl = new ZColl((int)s, -1);
		if(newColl==NULL)					return -1;
		if (M3DloadColNode(s, l, newColl, coeff))		return -1;
		coll->colB = newColl;
	}


	if ((l->argn!=1)||(strcmp(l->argv[0],")")))
	{
		MMechostr(1,") expected - M3DloadCollRec\n");
		errorMsg += string(") expected ");
		return -1;
	}
  
	if (M3Dnextline(l))
	{
		MMechostr(1,"unexpected end of file - M3DloadCollRec\n");
		errorMsg += string("unexpected end of file - M3DloadCollRec");
		return -1;
	}
  
	return 0;
}



///////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3DloadColSph																		///
///////////////////////////////////////////////////////////////////////////////////////////////
int M3DloadColSph(ZScene *s, load3d l, ZColl *coll, float coeff)
{
	while (M3Dnextline(l)==0)
    {
		if (l->argn==4)
        {
			coll->pos.SetCoord( atof(l->argv[0])/coeff, atof(l->argv[1])/coeff, -atof(l->argv[2])/coeff);
			coll->rayon = atof(l->argv[3]) / coeff;
			coll->typeColl = 0;
//			if (ZM3DaddCollSph(s,*p,h,atoi(l->argv[0]),atoi(l->argv[1]), atoi(l->argv[2]),atoi(l->argv[3]))) return -1;
        }
		else 
			return M3DloadCollRec(s, l, coll, coeff);
    }

	MMechostr(1,"unexpected end of file - M3DloadColSph \n");
	errorMsg += string("unexpected end of file - M3DloadColSph");
    return -1;
}



///////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3DloadColObb																		///
///////////////////////////////////////////////////////////////////////////////////////////////
int M3DloadColObb(ZScene *s, load3d l, ZColl *coll, float coeff)
{
	while (M3Dnextline(l)==0)
    {
		if (l->argn==12)
        {
			coll->pos.SetCoord( atof(l->argv[0])/coeff, atof(l->argv[1])/coeff, -atof(l->argv[2])/coeff);
			coll->u.SetCoord(atof(l->argv[3])/coeff, atof(l->argv[4])/coeff, -atof(l->argv[5])/coeff);
			coll->v.SetCoord(atof(l->argv[6])/coeff, atof(l->argv[7])/coeff, -atof(l->argv[8])/coeff);
			coll->w.SetCoord(atof(l->argv[9])/coeff, atof(l->argv[10])/coeff, -atof(l->argv[11])/coeff);
			coll->typeColl = 1;
        }
		else
			return M3DloadCollRec(s, l, coll, coeff);
    }

	MMechostr(1,"unexpected end of file - M3DloadColObb \n");
	errorMsg += string("unexpected end of file - M3DloadColObb");
    return -1;
}



///////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3DloadColTri																		///
///////////////////////////////////////////////////////////////////////////////////////////////
int M3DloadColTri(ZScene *s, load3d l, ZColl *coll, float coeff)
{
	while (M3Dnextline(l)==0)
    {
		if (l->argn==12)
        {
//			if (ZM3DaddCollTri(s,*p,h,atoi(l->argv[0]),atoi(l->argv[1]),atoi(l->argv[2]),
//					atoi(l->argv[3]),atoi(l->argv[4]),atoi(l->argv[5]),
//					atoi(l->argv[6]),atoi(l->argv[7]),atoi(l->argv[8]),
//					atoi(l->argv[9]),atoi(l->argv[10]),atoi(l->argv[11])
//				)) return -1;
        }
		else 
			return M3DloadCollRec(s, l, coll, coeff);
    }
	
	MMechostr(1,"unexpected end of file - M3DloadColTri \n");
	errorMsg += string("unexpected end of file - M3DloadColTri");
    return -1;
}



///////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3DloadColNode																		///
///////////////////////////////////////////////////////////////////////////////////////////////
int M3DloadColNode(ZScene *s, load3d l, ZColl *coll, float coeff)
{
	if (l->argn!=1) return 0;

	if (!strcmp(l->argv[0],"Sph"))		return M3DloadColSph(s, l, coll, coeff);
	if (!strcmp(l->argv[0],"Obb"))		return M3DloadColObb(s, l, coll, coeff);
	if (!strcmp(l->argv[0],"Tri"))		return M3DloadColTri(s, l, coll, coeff);
	
	MMechostr(1,"unexpected end of file - M3DloadColNode \n");
	errorMsg += string("empty collision node - M3DloadColNode");
	return -1;
}



///////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3DloadColl																		///
///////////////////////////////////////////////////////////////////////////////////////////////
int M3DloadColl(ZScene *s, load3d l, ZNode *baseNode, float coeff)
{
	// CREATION d'un noeud de collision SANS aucun élément de collision (sert de header)
	ZColl	*coll;
	coll = new ZColl((int)s, -1);				// (-1) : noeud de collision *HEADER* (sans élément de collision)
	if(coll==NULL)						return -1;
	coll->InsertAsChildOf(baseNode);
	coll->SetName(l->argv[1]);
	coll->pos.SetNull();		// zéro, car c'est le sommet de l'arbre de collision

	MMpush(machineForLoad, PTOM(ptrHashTable) );
	MMpush(machineForLoad, PTOM(ptrHashMat)   );
	MMpush(machineForLoad, PTOM(ptrHashTex)   );
	createH3D(machineForLoad, (int)coll, ptrHashTable);
	ptrHashTex   = MTOP( MMpull(machineForLoad) );
	ptrHashMat   = MTOP( MMpull(machineForLoad) );
	ptrHashTable = MTOP( MMpull(machineForLoad) );

	ZPRS	*newPRS;
	newPRS = coll->GetPRS();


	if (M3Dnextline(l))
    {
		MMechostr(1,"unexpected end of file - M3DloadColl in BaseNode : %s\n",baseNode->name.c_str());
		errorMsg += string("unexpected end of file - M3DloadColl");
		return -1;
    }

	if (l->argn<6)
    {
		errorMsg += string("position expected - M3DloadColl");
		MMechostr(1,"unexpected end of file - M3DloadColl in BaseNode : %s\n",baseNode->name.c_str());
		return -1;
    }

	// Lit la position et la rotation du noeud
	newPRS->coeffM3D = coeff;
	newPRS->SetPos( atof(l->argv[0])/coeff, atof(l->argv[1])/coeff, -atof(l->argv[2])/coeff );
	newPRS->SetAng( atof(l->argv[4])*360.0f/CONST_ANGLE, atof(l->argv[3])*360.0f/CONST_ANGLE, atof(l->argv[5])*360.0f/CONST_ANGLE );

	// Lit le scale s'il existe
	if (l->argn>6)		newPRS->SetScale(atof(l->argv[6])/100.0f);

  	if (M3Dnextline(l))
    {
		MMechostr(1,"unexpected end of file - M3DloadColl in BaseNode : %s\n",baseNode->name.c_str());
		errorMsg += string("unexpected end of file - M3DloadColl");
		return -1;
    }

	// Lecture du graphe de collision - premier élement...
	ZColl	*newColl = new ZColl((int)s, -1);
	if(newColl==NULL)								return -1;
	if(M3DloadColNode(s, l, newColl, coeff))		return -1;
	coll->colA = newColl;

	// et peut-être un élément suivant...
	if((l->argn==1)&&(!strcmp(l->argv[0],"|")))
	{
		if (M3Dnextline(l))
		{
			MMechostr(1,"unexpected end of file - M3DloadColl in BaseNode : %s\n",baseNode->name.c_str());
			errorMsg += string("unexpected end of file - M3DloadCollRec");
			return -1;
		}
		newColl = new ZColl((int)s, -1);
		if(newColl==NULL)								return -1;
		if (M3DloadColNode(s, l, newColl, coeff))		return -1;
		coll->colB = newColl;
	}


	// Recursion dans le scene-graph
	if (M3DrecursObj(s, l, coll, coeff))		return -1;

	if (strcmp(l->argv[0],"}"))
    {
		MMechostr(1,"} expected - M3DloadColl in BaseNode : %s\n",baseNode->name.c_str());
		errorMsg += string("} expected - M3DloadColl");
		return -1;
    }

	return 0;
}




int M3DaddKeyPos(ZScene *s, ZAnim *anim, char **arg, int narg, float coeff)
{
	ZVector3	pos;
	
	for(int j=0; j<narg; j++)
	{
		pos.SetCoord(atof(arg[1])/coeff, atof(arg[2])/coeff, -atof(arg[3])/coeff);
		anim->addKeyPos(atoi(arg[0]), pos);
		arg += 4;
	}
  
	return 0;
}

int M3DaddKeyAng(ZScene *s, ZAnim *anim, char **arg, int narg)
{
	ZQuat	quat;

	for(int j=0; j<narg; j++)
	{
		quat.SetCoord(-atof(arg[1]), -atof(arg[2]), atof(arg[3]), atof(arg[4]));

				
		anim->addKeyRot(atoi(arg[0]), quat);
		arg += 5;
	}

	return 0;
}

int M3DsetAnimTrack(ZScene *s, ZAnim *anim, char *field, char **arg, int narg, float coeff)
{
	if (!strcmp(field, "position"))
	{
		if (narg&3)	//test la multiplicité par 4
		{
			//MMechostr(MSKTRACE,"Position Track : Bad number of arguments\n");
			return 0;
		}
		return M3DaddKeyPos(s, anim, arg, narg/4, coeff);
	}
	if (!strcmp(field,"rotation"))
	{
		if ((5*(narg/5))!=narg)
		{
			//MMechostr(MSKTRACE,"Rotation Track : Bad number of arguments\n");
			return 0;
		}
		return M3DaddKeyAng(s, anim, arg, narg/5);
	}
	//MMechostr(MSKTRACE,"Unknown Track : %s\n",field);
	return 0;
}




///////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3DloadAnim																		///
///																							///
///	Lit les caractères dans 'comm', supprime les commentaires, stocke le result dans mots	///
/// Renvoit le nombre de caractères lus sans commentaires									///
///////////////////////////////////////////////////////////////////////////////////////////////
int M3DloadAnim(ZScene *s, load3d l, ZNode *baseNode, float coeff)
{
	ZAnim	*anim;
	anim = new ZAnim((int)s);
	if(!anim)	return -1;
		
	anim->SetName(l->argv[1]);
	
	anim->InsertAsChildOf(baseNode);


	MMpush(machineForLoad, PTOM(ptrHashTable) );
	MMpush(machineForLoad, PTOM(ptrHashMat)   );
	MMpush(machineForLoad, PTOM(ptrHashTex)   );
	createH3D(machineForLoad, (int)anim, ptrHashTable);
	ptrHashTex   = MTOP( MMpull(machineForLoad) );
	ptrHashMat   = MTOP( MMpull(machineForLoad) );
	ptrHashTable = MTOP( MMpull(machineForLoad) );

	ZPRS	*newPRS;
	newPRS = anim->GetPRS();

	
	if (M3Dnextline(l))
    {
		MMechostr(1,"unexpected end of file - M3DloadAnim in Anim : %s\n",anim->name.c_str());
		errorMsg += string("unexpected end of file - M3DloadAnim");
		return -1;
    }
	
	// A VOIR AVEC SYLVAIN !!!!
	if (l->argn>=6)
	{
		if (M3Dnextline(l))
		{
			MMechostr(1,"unexpected end of file - M3DloadAnim in Anim : %s\n",anim->name.c_str());
			errorMsg += string("unexpected end of file - M3DloadAnim");
			return -1;
		}
	}
	
	// Lecture de la longueur d'animiation
	if ((l->argn<2)||(strcmp(l->argv[0],"length")))
    {
		MMechostr(1,"animation length expected - M3DloadAnim in Anim : %s\n",anim->name.c_str());
		errorMsg += string("animation length expected - M3DloadAnim");
		return -1;
    }
	anim->setLength(atoi(l->argv[1]));
	
	
	if (M3Dnextline(l))
    {
		MMechostr(1,"unexpected end of file - M3DloadAnim in Anim : %s\n",anim->name.c_str());
		errorMsg += string("unexpected end of file - M3DloadAnim");
		return -1;
    }


	// Lecture des champs d'animation : position et rotation
	while((strcmp(l->argv[0],"}"))&&((l->argn<3)||(strcmp(l->argv[2],"{"))))
	{
		if (M3DsetAnimTrack(s, anim, l->argv[0], &l->argv[1], l->argn-1, coeff))
		{
			delete(anim);
			return -1;
		}
		
		if (M3Dnextline(l))
	    {
			MMechostr(1,"unexpected end of file - M3DloadAnim in Anim : %s\n",anim->name.c_str());
			errorMsg += string("unexpected end of file - M3DloadAnim");
			return -1;
	    }
	}

	if (M3DrecursObj(s, l, anim, coeff))		return -1;

	if (strcmp(l->argv[0],"}"))
    {
		MMechostr(1,"} expected - M3DloadAnim in Anim : %s\n",anim->name.c_str());
		errorMsg += string("} expected - M3DloadAnim");
		return -1;
    }
	return 0;
}









///////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3DloadA																			///
///																							///
///	Lit les caractères dans 'comm', supprime les commentaires, stocke le result dans mots	///
/// Renvoit le nombre de caractères lus sans commentaires									///
///////////////////////////////////////////////////////////////////////////////////////////////
int M3DloadA(ZScene *s, load3d l, ZNode* nodeBase, float coeff)
{
	FILE	*f;
	int		k;
  
	// Load material
	if ((l->argn==3)&&(!strcmp(l->argv[0],"material")) && (!strcmp(l->argv[2],"{")))
    {
		return M3DloadMat(s, l);
    }

	// Load mesh
	if ((l->argn==3)&&(!strcmp(l->argv[0],"mesh")) && (!strcmp(l->argv[2],"{")))
    {
		return M3DloadMesh(s, l, nodeBase, coeff);
    }

	// Load topo
	if ((l->argn==3)&&(!strcmp(l->argv[0],"topo")) && (!strcmp(l->argv[2],"{")))
    {
		return M3DloadTopo(s, l, coeff);
    }

	// Load camera
	if ((l->argn==3)&&(!strcmp(l->argv[0],"camera")) && (!strcmp(l->argv[2],"{")))
    {
		return M3DloadCam(s, l, nodeBase, coeff);
    }
  
	// Load shell
	if ((l->argn==3)&&(!strcmp(l->argv[0],"shell")) && (!strcmp(l->argv[2],"{")))
    {
		return M3DloadShell(s, l, nodeBase, coeff);
    }

	// Load coll
	if ((l->argn==3)&&(!strcmp(l->argv[0],"coll")) && (!strcmp(l->argv[2],"{")))
	{
		return M3DloadColl(s, l, nodeBase, coeff);
	}
  
	// Load anim
	if ((l->argn==3)&&(!strcmp(l->argv[0],"anim")) && (!strcmp(l->argv[2],"{")))
    {
		return M3DloadAnim(s, l, nodeBase, coeff);
    }
  
	// Load light
	if ((l->argn==3)&&(!strcmp(l->argv[0],"light")) && (!strcmp(l->argv[2],"{")))
    {
		return M3DloadLight(s, l, nodeBase, coeff);
    }

	// Load light
	if ((l->argn==3)&&(!strcmp(l->argv[0],"colorlight")) && (!strcmp(l->argv[2],"{")))
    {
		return M3DloadColorLight(s, l, nodeBase, coeff);
    }

	// Load Emitter
	if ((l->argn==3)&&(!strcmp(l->argv[0],"emitter")) && (!strcmp(l->argv[2],"{")))
    {
		return M3DloadEmitter(s, l, nodeBase, coeff);
    }
	// Load Particle
	if ((l->argn==3)&&(!strcmp(l->argv[0],"particle")) && (!strcmp(l->argv[2],"{")))
    {
		return M3DloadParticle(s, l, nodeBase, coeff);
    }
	// Load Effect
	if ((l->argn==3)&&(!strcmp(l->argv[0],"effect")) && (!strcmp(l->argv[2],"{")))
    {
		return M3DloadEffect(s, l, nodeBase, coeff);
    }
	
	// Load Unknown
	if ((l->argn==3)&&(!strcmp(l->argv[2],"{")))
	{
		return M3DloadUnknown(s, l, nodeBase);
	}
  
	// Load include
	if ((l->argn==2)&&(!strcmp(l->argv[0],"include")))
    {
		//MMechostr(1,"include file %s\n",l->argv[1]);

		if (/*(SPfindfile((packdir)SCgetExtra("FirstPack"),l->argv[1],NULL,name)==-1)||((f=fopen(name,"r"))==NULL)*/  (f=fopen(l->argv[1],"r"))==NULL  )
		{
			//MMechostr(1,"file %s not found\n",l->argv[1]);
			return -1;
		}	
      
		k = M3Dload(s, f, nodeBase, coeff);
		fclose(f);

		return k;
    }
  
	MMechostr(1,"include, material, mesh or camera expected - M3DloadA in BaseNode : %s\n",nodeBase->name.c_str());
	errorMsg += string("include, material, mesh or camera expected ");
	return -1;
}



///////////////////////////////////////////////////////////////////////////////////////////////
///		ZM3Dload																			///
///																							///
///	Lit les caractères dans 'comm', supprime les commentaires, stocke le result dans mots	///
/// Renvoit le nombre de caractères lus sans commentaires									///
///////////////////////////////////////////////////////////////////////////////////////////////
int M3Dload(ZScene *s, FILE *f, ZNode*	nodeBase, float coeff)
{
	struct Load3d l;

	if (nodeBase==NULL)		return -1;
	
	l.f = f;
	
	while(M3Dnextline(&l)==0)		
	{	
		if (M3DloadA(s, &l, nodeBase, coeff))		return -1;	
	}
	
	return 0;
}



int ZM3DloadFILE(mmachine m, int s3d_buf, FILE *f, ZNode* nodeBase, float coeff)
{
	errorMsg = string(" ");

	machineForLoad  = m;
	ZScene*  scene	= (ZScene*) MMfetch(m, s3d_buf, 0);
	ptrHashTable	= MTOP( MMfetch(m,s3d_buf,1) );
	ptrHashMat		= MTOP( MMfetch(m,s3d_buf,2) );
	ptrHashTex		= MTOP( MMfetch(m,s3d_buf,3) );

	M3Dload(scene, f, nodeBase, coeff);


	if(errorMsg == string(" "))		
	{
		errorMsg = string("File Loaded");
		return	0;
	}
	else
		return	1;
}



int ZM3Dloadbuf(mmachine m, int s3d_buf, char *buf, ZNode* nodeBase, float coeff)
{
	struct Load3d l;

	machineForLoad  = m;
	ZScene*  scene	= (ZScene*) MMfetch(m, s3d_buf, 0);
	ptrHashTable	= MTOP( MMfetch(m,s3d_buf,1) );
	ptrHashMat		= MTOP( MMfetch(m,s3d_buf,2) );
	ptrHashTex		= MTOP( MMfetch(m,s3d_buf,3) );

	l.f		= NULL;
	l.buf	= buf;

	while(M3Dnextline(&l)==0)
	{
		if (M3DloadA(scene, &l, nodeBase, coeff))		return -1;
	}

	return 0;
}









//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////







void ZM3DsaveBuf(ZScene *s, save3d l, char *format, ...)
{
	va_list arglist;
	char buf[16384];

	va_start(arglist, format);
	vsprintf(buf, format, arglist);
	va_end(arglist);

	(*l->cb)(buf,l->user);
}



char*	testempty(char *s)
{
	if (s[0])		return s;
	return "_";
}



int ZM3DsaveMat(ZScene *s, save3d l, ZMaterial *curMat)
{
	ZTexture	*tex;

	// Sauvegarde couleur standard
	ZM3DsaveBuf(s,l, "material %s {\ncolor %x\n", testempty((char*)curMat->name.c_str()), curMat->GetDefaultColor());

	// Sauvegarde couleur 1
	if(curMat->color1_24 != -1)
	{
		ZM3DsaveBuf(s,l, "facecolor1 %x\n", curMat->color1_24);
	}

	// Sauvegarde couleur 2
	if(curMat->color1_24 != -1)
	{
		ZM3DsaveBuf(s,l, "facecolor2 %x\n", curMat->color2_24);		
	}

	// Sauvegarde texture 1
	if(curMat->IsOnMode(RENDER_TEXTURED) && (tex=curMat->GetTexture1())!=NULL)
	{
		ZM3DsaveBuf(s,l, "texture %s\n", tex->filename.c_str());
	}

	// Sauvegarde texture 2
	if( (tex=curMat->GetTexture2())!=NULL)
	{
		ZM3DsaveBuf(s,l, "texturebis %s %f\n", tex->filename.c_str(), curMat->alpha);
	}

	// Sauvegarde des options de rendu
	if(!curMat->IsOnMode(RENDER_LIGHTED))			ZM3DsaveBuf(s,l, "type NOLIGHT\n");
	else											ZM3DsaveBuf(s,l, "type LIGHT\n");
	if(curMat->IsOnMode(RENDER_GOURAUD_LIGHT))		ZM3DsaveBuf(s,l, "type GOURAUD\n");
	if(curMat->IsOnMode(RENDER_TEXTURED))			ZM3DsaveBuf(s,l, "type TEXTURED\n");
	if(curMat->IsOnMode(RENDER_TEXTURED_BIS))		ZM3DsaveBuf(s,l, "type TEXTURED_BIS\n");
	if(curMat->IsOnMode(RENDER_COLOR1))				ZM3DsaveBuf(s,l, "type COLOR1\n");
	if(curMat->IsOnMode(RENDER_COLOR2))				ZM3DsaveBuf(s,l, "type COLOR2\n");
	if(curMat->IsOnMode(RENDER_COLOR_VERTEX))		ZM3DsaveBuf(s,l, "type COLOR_VERTEX\n");
	if(curMat->IsOnMode(RENDER_ENVMAP))				ZM3DsaveBuf(s,l, "type ENV\n");
	if(curMat->IsOnMode(RENDER_TRANSP))				ZM3DsaveBuf(s,l, "type TRANSPARENCY%d\n", curMat->GetCoeffTransp());

	ZM3DsaveBuf(s,l,"}\n");

	return 0;
}



int ZM3DsavePRS(ZScene *s, save3d l, ZNode *curNode)
{
	ZPRS *curPRS;

	curPRS = &(((ZNodeGraph*)curNode)->PRS);

	ZM3DsaveBuf(s,l, " %d %d %d  %d %d %d %d\n", (int)(curPRS->GetPos().x*curPRS->coeffM3D), (int)(curPRS->GetPos().y*curPRS->coeffM3D), (int)(-curPRS->GetPos().z*curPRS->coeffM3D), 
												 (int)(curPRS->GetAng().y*CONST_ANGLE/360.0f), (int)(curPRS->GetAng().x*CONST_ANGLE/360.0f), (int)(curPRS->GetAng().z*CONST_ANGLE/360.0f),
												 (int)(curPRS->GetScale()*100.0f));

	return 0;
}



int ZM3DsaveShell(ZScene *s, save3d l, ZShell *curShl)
{
	ZM3DsaveBuf(s, l, "shell %s {\n", testempty((char*)curShl->name.c_str()));
	ZM3DsavePRS(s, l, curShl);

	return 0;
}



int ZM3DsaveCam(ZScene *s, save3d l, ZCamera *curCam)
{
	ZM3DsaveBuf(s,l, "camera %s {\n", testempty((char*)curCam->name.c_str()));
	ZM3DsavePRS(s, l, curCam);
	ZM3DsaveBuf(s,l, " %d %d %d %d\n%d %d %d\n", curCam->dx, curCam->dy, (int)(curCam->width/2), (int)(curCam->height/2), (int)(curCam->Znear*100.0f), (int)(curCam->Zfog*100.0f), (int)(curCam->Zfar*100.0f));

	return 0;
}



int ZM3DsaveLight(ZScene *s, save3d l, ZLight *light)
{
	if(light->oldStyle==true)
	{
		ZM3DsaveBuf(s,l,"light %s {\n",testempty((char*)light->name.c_str()));
		ZM3DsavePRS(s,l, light);
		
		if(light->LightType==LIGHT_AMBIENT)			ZM3DsaveBuf(s,l,"ambient %d\n", light->alpha);
		else if(light->LightType==LIGHT_PARA)		ZM3DsaveBuf(s,l,"para %d %d\n", light->alpha, light->beta);
		else if(light->LightType==LIGHT_OMNI)		ZM3DsaveBuf(s,l,"omni %d %d %d\n", light->alpha, light->beta, light->dist);
		else if(light->LightType==LIGHT_SPOT)		ZM3DsaveBuf(s,l,"spot %d %d %d\n", light->alpha, light->beta, light->dist);
	}
	else
	{
		ZM3DsaveBuf(s,l,"colorlight %s {\n",testempty((char*)light->name.c_str()));
		ZM3DsavePRS(s,l, light);

		if(light->LightType==LIGHT_AMBIENT)			ZM3DsaveBuf(s,l,"ambient ");
		else if(light->LightType==LIGHT_PARA)		ZM3DsaveBuf(s,l,"para ");
		else if(light->LightType==LIGHT_OMNI)		ZM3DsaveBuf(s,l,"omni ");
		else if(light->LightType==LIGHT_SPOT)		ZM3DsaveBuf(s,l,"spot ");

		int	amb  = ((AROUNDINT(light->ambient[0]*CONST_COLOR)&255)<<16) + ((AROUNDINT(light->ambient[1]*CONST_COLOR)&255)<<8) + (AROUNDINT(light->ambient[2]*CONST_COLOR)&255);
		int	diff = ((AROUNDINT(light->diffuse[0]*CONST_COLOR)&255)<<16) + ((AROUNDINT(light->diffuse[1]*CONST_COLOR)&255)<<8) + (AROUNDINT(light->diffuse[2]*CONST_COLOR)&255);
		int	spec = ((AROUNDINT(light->specular[0]*CONST_COLOR)&255)<<16) + ((AROUNDINT(light->specular[1]*CONST_COLOR)&255)<<8) + (AROUNDINT(light->specular[2]*CONST_COLOR)&255);

		ZM3DsaveBuf(s,l,"%x %x %x %d %d %d\n", amb, diff, spec, light->spot_cut_off, AROUNDINT(light->attenuate_const*100.0f), AROUNDINT(light->attenuate_quadr*100.0f) );
	}

	return 0;
}




int ZM3DsaveMesh(ZScene *s, save3d l, ZObject *curObj)
{
	ZM3DsaveBuf(s,l, "mesh %s {\n", testempty((char*)curObj->name.c_str()));
	ZM3DsavePRS(s,l, curObj);

	ZMesh *mesh = curObj->GetMesh();

	float	coeff = curObj->PRS.coeffM3D;

	// si la topo est sauvegardée séparément..
	if(curObj->IsMultiMeshes()==true)
	{
		float	rangeSQR;
		for(int kk=0; kk<curObj->GetMeshList()->Size(); kk++)
		{
			mesh = (*curObj->GetMeshList())[kk];
			rangeSQR = (*curObj->GetRangeSQRList())[kk];

			if(rangeSQR != FLT_MAX)		ZM3DsaveBuf(s,l, "topo %s %d\n", testempty((char*)mesh->name.c_str()), AROUNDINT(sqrt(rangeSQR) * 100.0f));
			else						ZM3DsaveBuf(s,l, "topo %s RANGE_INFINITY\n", testempty((char*)mesh->name.c_str()));
		}
	}
	else
	// avec une SINGLE-topo déjà sauvée
	if(curObj->IsMultiMeshes()==false && mesh && mesh->saved==true)		ZM3DsaveBuf(s,l, "topo %s\n", testempty((char*)mesh->name.c_str()));
	else
	// et sinon, avec un SINGLE-mesh qui n'est pas sauvé..
	if(mesh)
	{
		int		i, j, k, color1, color2;
		ZVert	*v;

		mesh->MakeFacesList();

		// Sauvegarde des vertices
		for(i=0; i<mesh->NbVerts; i++)
		{
			v = &(mesh->Verts[i]);
			ZM3DsaveBuf(s,l, " %f %f %f", v->x*coeff, v->y*coeff, -v->z*coeff);
			color1 = ((AROUNDINT(v->color1.x*CONST_COLOR)&255)<<16) + ((AROUNDINT(v->color1.y*CONST_COLOR)&255)<<8) + (AROUNDINT(v->color1.z*CONST_COLOR)&255);
			color2 = ((AROUNDINT(v->color2.x*CONST_COLOR)&255)<<16) + ((AROUNDINT(v->color2.y*CONST_COLOR)&255)<<8) + (AROUNDINT(v->color2.z*CONST_COLOR)&255);
			ZM3DsaveBuf(s,l, " %x %x\n", color1, color2);
		}

		ZFace	*face;

		// Sauvegarde des polygones (par materiau)
		for(j=0; j<mesh->FacesMatGour.size(); j++)
		{
			if(mesh->FacesMatGour[j].mat != NULL)		ZM3DsaveBuf(s,l, "%s\n", (char*)mesh->FacesMatGour[j].mat->name.c_str());

			// Not texturing
			if(mesh->FacesMatGour[j].mat->GetTexture1() == NULL)
			{
				for(k=0; k<mesh->FacesMatGour[j].faces.size(); k++)
				{
					face = mesh->FacesMatGour[j].faces[k];
					ZM3DsaveBuf(s,l, "  %d", (int)(face->VertRef[0]));
					ZM3DsaveBuf(s,l, "  %d", (int)(face->VertRef[1]));
					ZM3DsaveBuf(s,l, "  %d", (int)(face->VertRef[2]));
					ZM3DsaveBuf(s,l, "\n");
				}
			}
			else			
			// MONO-texturing
			if(mesh->FacesMatGour[j].mat->GetTexture2() == NULL)
			{
				for(k=0; k<mesh->FacesMatGour[j].faces.size(); k++)
				{
					face = mesh->FacesMatGour[j].faces[k];
					ZM3DsaveBuf(s,l, "  %d %d %d", (int)(face->VertRef[0]), (int)(face->UV1[0].u*CONST_TEX_COORD), (int)(face->UV1[0].v*CONST_TEX_COORD));
					ZM3DsaveBuf(s,l, "  %d %d %d", (int)(face->VertRef[1]), (int)(face->UV1[1].u*CONST_TEX_COORD), (int)(face->UV1[1].v*CONST_TEX_COORD));
					ZM3DsaveBuf(s,l, "  %d %d %d", (int)(face->VertRef[2]), (int)(face->UV1[2].u*CONST_TEX_COORD), (int)(face->UV1[2].v*CONST_TEX_COORD));
					ZM3DsaveBuf(s,l, "\n");
				}
			}
			else
			// MULTI-texturing
			{
				for(k=0; k<mesh->FacesMatGour[j].faces.size(); k++)
				{
					face = mesh->FacesMatGour[j].faces[k];
					ZM3DsaveBuf(s,l, "  %d %d %d %d %d", (int)(face->VertRef[0]), (int)(face->UV1[0].u*CONST_TEX_COORD), (int)(face->UV1[0].v*CONST_TEX_COORD), (int)(face->UV2[0].u*CONST_TEX_COORD), (int)(face->UV2[0].v*CONST_TEX_COORD));
					ZM3DsaveBuf(s,l, "  %d %d %d %d %d", (int)(face->VertRef[1]), (int)(face->UV1[1].u*CONST_TEX_COORD), (int)(face->UV1[1].v*CONST_TEX_COORD), (int)(face->UV2[1].u*CONST_TEX_COORD), (int)(face->UV2[1].v*CONST_TEX_COORD));
					ZM3DsaveBuf(s,l, "  %d %d %d %d %d", (int)(face->VertRef[2]), (int)(face->UV1[2].u*CONST_TEX_COORD), (int)(face->UV1[2].v*CONST_TEX_COORD), (int)(face->UV2[2].u*CONST_TEX_COORD), (int)(face->UV2[2].v*CONST_TEX_COORD));
					ZM3DsaveBuf(s,l, "\n");
				}
			}
		}


		for(j=0; j<mesh->FacesMatFlat.size(); j++)
		{
			if(mesh->FacesMatFlat[j].mat != NULL)		ZM3DsaveBuf(s,l, "%s\n", (char*)mesh->FacesMatFlat[j].mat->name.c_str());

			// Not texturing
			if(mesh->FacesMatFlat[j].mat->GetTexture1() == NULL)
			{
				for(k=0; k<mesh->FacesMatFlat[j].faces.size(); k++)
				{
					face = mesh->FacesMatFlat[j].faces[k];
					ZM3DsaveBuf(s,l, "  %d", (int)(face->VertRef[0]));
					ZM3DsaveBuf(s,l, "  %d", (int)(face->VertRef[1]));
					ZM3DsaveBuf(s,l, "  %d", (int)(face->VertRef[2]));
					ZM3DsaveBuf(s,l, "\n");
				}
			}
			else
			// MONO-texturing
			if(mesh->FacesMatFlat[j].mat->GetTexture2() == NULL)
			{
				for(k=0; k<mesh->FacesMatFlat[j].faces.size(); k++)
				{
					face = mesh->FacesMatFlat[j].faces[k];
					ZM3DsaveBuf(s,l, "  %d %d %d", (int)(face->VertRef[0]), (int)(face->UV1[0].u*CONST_TEX_COORD), (int)(face->UV1[0].v*CONST_TEX_COORD));
					ZM3DsaveBuf(s,l, "  %d %d %d", (int)(face->VertRef[1]), (int)(face->UV1[1].u*CONST_TEX_COORD), (int)(face->UV1[1].v*CONST_TEX_COORD));
					ZM3DsaveBuf(s,l, "  %d %d %d", (int)(face->VertRef[2]), (int)(face->UV1[2].u*CONST_TEX_COORD), (int)(face->UV1[2].v*CONST_TEX_COORD));
					ZM3DsaveBuf(s,l, "\n");
				}
			}
			else
			// MULTI-texturing
			{
				for(k=0; k<mesh->FacesMatFlat[j].faces.size(); k++)
				{
					face = mesh->FacesMatFlat[j].faces[k];
					ZM3DsaveBuf(s,l, "  %d %d %d %d %d", (int)(face->VertRef[0]), (int)(face->UV1[0].u*CONST_TEX_COORD), (int)(face->UV1[0].v*CONST_TEX_COORD), (int)(face->UV2[0].u*CONST_TEX_COORD), (int)(face->UV2[0].v*CONST_TEX_COORD));
					ZM3DsaveBuf(s,l, "  %d %d %d %d %d", (int)(face->VertRef[1]), (int)(face->UV1[1].u*CONST_TEX_COORD), (int)(face->UV1[1].v*CONST_TEX_COORD), (int)(face->UV2[1].u*CONST_TEX_COORD), (int)(face->UV2[1].v*CONST_TEX_COORD));
					ZM3DsaveBuf(s,l, "  %d %d %d %d %d", (int)(face->VertRef[2]), (int)(face->UV1[2].u*CONST_TEX_COORD), (int)(face->UV1[2].v*CONST_TEX_COORD), (int)(face->UV2[2].u*CONST_TEX_COORD), (int)(face->UV2[2].v*CONST_TEX_COORD));
					ZM3DsaveBuf(s,l, "\n");
				}
			}
		}


		for(j=0; j<mesh->FacesMatNo.size(); j++)
		{
			if(mesh->FacesMatNo[j].mat != NULL)		ZM3DsaveBuf(s,l, "%s\n", (char*)mesh->FacesMatNo[j].mat->name.c_str());

			// Not texturing
			if(mesh->FacesMatNo[j].mat->GetTexture1() == NULL)
			{
				for(k=0; k<mesh->FacesMatNo[j].faces.size(); k++)
				{
					face = mesh->FacesMatNo[j].faces[k];
					ZM3DsaveBuf(s,l, "  %d", (int)(face->VertRef[0]));
					ZM3DsaveBuf(s,l, "  %d", (int)(face->VertRef[1]));
					ZM3DsaveBuf(s,l, "  %d", (int)(face->VertRef[2]));
					ZM3DsaveBuf(s,l, "\n");
				}
			}
			else
			// MONO-texturing
			if(mesh->FacesMatNo[j].mat->GetTexture2() == NULL)
			{
				for(k=0; k<mesh->FacesMatNo[j].faces.size(); k++)
				{
					face = mesh->FacesMatNo[j].faces[k];
					ZM3DsaveBuf(s,l, "  %d %d %d", (int)(face->VertRef[0]), (int)(face->UV1[0].u*CONST_TEX_COORD), (int)(face->UV1[0].v*CONST_TEX_COORD));
					ZM3DsaveBuf(s,l, "  %d %d %d", (int)(face->VertRef[1]), (int)(face->UV1[1].u*CONST_TEX_COORD), (int)(face->UV1[1].v*CONST_TEX_COORD));
					ZM3DsaveBuf(s,l, "  %d %d %d", (int)(face->VertRef[2]), (int)(face->UV1[2].u*CONST_TEX_COORD), (int)(face->UV1[2].v*CONST_TEX_COORD));
					ZM3DsaveBuf(s,l, "\n");
				}
			}
			else
			// MULTI-texturing
			{
				for(k=0; k<mesh->FacesMatNo[j].faces.size(); k++)
				{
					face = mesh->FacesMatNo[j].faces[k];
					ZM3DsaveBuf(s,l, "  %d %d %d %d %d", (int)(face->VertRef[0]), (int)(face->UV1[0].u*CONST_TEX_COORD), (int)(face->UV1[0].v*CONST_TEX_COORD), (int)(face->UV2[0].u*CONST_TEX_COORD), (int)(face->UV2[0].v*CONST_TEX_COORD));
					ZM3DsaveBuf(s,l, "  %d %d %d %d %d", (int)(face->VertRef[1]), (int)(face->UV1[1].u*CONST_TEX_COORD), (int)(face->UV1[1].v*CONST_TEX_COORD), (int)(face->UV2[1].u*CONST_TEX_COORD), (int)(face->UV2[1].v*CONST_TEX_COORD));
					ZM3DsaveBuf(s,l, "  %d %d %d %d %d", (int)(face->VertRef[2]), (int)(face->UV1[2].u*CONST_TEX_COORD), (int)(face->UV1[2].v*CONST_TEX_COORD), (int)(face->UV2[2].u*CONST_TEX_COORD), (int)(face->UV2[2].v*CONST_TEX_COORD));
					ZM3DsaveBuf(s,l, "\n");
				}
			}
		}

	}
	

	return 0;
}



int ZM3DsaveAnim(ZScene *s, save3d l, ZAnim *curAnim, float coeff)
{
	int		i;

	ZM3DsaveBuf(s,l, "anim %s {\n", curAnim->name.c_str());
	ZM3DsaveBuf(s,l, "length %d\n", curAnim->getLength());

	if (curAnim->listPos.size() != 0)
	{
		ZkeyPos		*pos;
		for(i=0; i<curAnim->listPos.size(); i++)
		{
			if(i%7 == 0)		ZM3DsaveBuf(s, l, "\n position");
			pos = &(curAnim->listPos[i]);
			ZM3DsaveBuf(s,l," %d %f %f %f", pos->key, pos->pos.x*coeff, pos->pos.y*coeff, -pos->pos.z*coeff);
		}
		ZM3DsaveBuf(s,l,"\n");
	}

	if (curAnim->listRot.size() != 0)
	{
		ZkeyRot		*rot;
		for(i=0; i<curAnim->listRot.size(); i++)
		{
			if(i%7 == 0)		ZM3DsaveBuf(s,l,"\n rotation");
			rot = &(curAnim->listRot[i]);
			ZM3DsaveBuf(s,l," %d %f %f %f %f", rot->key, -rot->rot.x, -rot->rot.y, rot->rot.z, rot->rot.w);
		}
		ZM3DsaveBuf(s,l,"\n");
	}

	return 0;
}






int ZM3DrecSaveColl(ZScene *s, save3d l, ZColl *coll)
{
	// sphere
	if(coll->typeColl==0)
	{
		ZM3DsaveBuf(s,l,"Sph\n");
		ZM3DsaveBuf(s,l," %f %f %f %f\n", coll->pos.x*100.0f, coll->pos.y*100.0f, -coll->pos.z*100.0f, coll->rayon*100.0f);
	}
	// OBB
	else if(coll->typeColl==1)
	{
		ZM3DsaveBuf(s,l,"Obb\n");
		ZM3DsaveBuf(s,l," %f %f %f %f %f %f %f %f %f %f %f %f\n", 
			coll->pos.x*100.0f, coll->pos.y*100.0f, -coll->pos.z*100.0f,
			coll->u.x*100.0f,   coll->u.y*100.0f,   -coll->u.z*100.0f,
			coll->v.x*100.0f,   coll->v.y*100.0f,   -coll->v.z*100.0f,
			coll->w.x*100.0f,   coll->w.y*100.0f,   -coll->w.z*100.0f	);
	}

	if(coll->colA)
	{
		ZM3DsaveBuf(s,l,"(\n");
		ZM3DrecSaveColl(s,l,coll->colA);
		
		if(coll->colB)
		{
			ZM3DsaveBuf(s,l,"|\n");
			ZM3DrecSaveColl(s,l,coll->colB);
		}
		ZM3DsaveBuf(s,l,")\n");
	}

	return 0;
}



int ZM3DsaveColl(ZScene *s, save3d l, ZColl *coll)
{
	ZM3DsaveBuf(s, l, "coll %s {\n", coll->name.c_str());
	ZM3DsavePRS(s, l, coll);

	if(coll->colA)
	{
		ZM3DrecSaveColl(s, l, coll->colA);

		if(coll->colB)
		{
			ZM3DsaveBuf(s,l,"|\n");
			ZM3DrecSaveColl(s,l,coll->colB);
		}
	}

	return 0;
}

/*
int ZM3DsaveAnim(ZScene *s, save3d l, ZAnim *curAnim, float coeff)
{
	int		i;

	ZM3DsaveBuf(s,l, "anim %s {\n", curAnim->name.c_str());
	ZM3DsaveBuf(s,l, "length %d\n", curAnim->getLength());

	if (curAnim->listPos.size() != 0)
	{
		ZkeyPos		*pos;
		for(i=0; i<curAnim->listPos.size(); i++)
		{
			if(i%7 == 0)		ZM3DsaveBuf(s, l, "\n position");
			pos = &(curAnim->listPos[i]);
			ZM3DsaveBuf(s,l," %d %f %f %f", pos->key, pos->pos.x*coeff, pos->pos.y*coeff, -pos->pos.z*coeff);
		}
		ZM3DsaveBuf(s,l,"\n");
	}

	if (curAnim->listRot.size() != 0)
	{
		ZkeyRot		*rot;
		for(i=0; i<curAnim->listRot.size(); i++)
		{
			if(i%7 == 0)		ZM3DsaveBuf(s,l,"\n rotation");
			rot = &(curAnim->listRot[i]);
			ZM3DsaveBuf(s,l," %d %f %f %f %f", rot->key, -rot->rot.x, -rot->rot.y, rot->rot.z, rot->rot.w);
		}
		ZM3DsaveBuf(s,l,"\n");
	}

	return 0;
}
*/





// sauvegarde des topologies - effectué une seule fois au début de la sauvegarde
int ZM3DsaveTopo(ZScene *s, save3d l, ZNode *node, bool first, int flag)
{
	if( flag!=NIL && node->type==OBJ_TYPE_ID)
	{
		ZObject		*obj = (ZObject*)node;

		if(obj->IsMultiMeshes()==false && obj->GetMesh() && obj->GetMesh()->nbRef>1 && obj->GetMesh()->saved==false)
		{
			ZMesh	*mesh = obj->GetMesh();
			mesh->MakeFacesList();
			mesh->saved = true;

			ZM3DsaveBuf(s,l, "topo %s {\n", testempty((char*)mesh->name.c_str()));

			int		i, j, k, color1, color2;
			ZVert	*v;

			// Sauvegarde des vertices
			for(i=0; i<mesh->NbVerts; i++)
			{
				v = &(mesh->Verts[i]);
				ZM3DsaveBuf(s,l, " %f %f %f", v->x*100.0f, v->y*100.0f, -v->z*100.0f);
				color1 = ((AROUNDINT(v->color1.x*CONST_COLOR)&255)<<16) + ((AROUNDINT(v->color1.y*CONST_COLOR)&255)<<8) + (AROUNDINT(v->color1.z*CONST_COLOR)&255);
				color2 = ((AROUNDINT(v->color2.x*CONST_COLOR)&255)<<16) + ((AROUNDINT(v->color2.y*CONST_COLOR)&255)<<8) + (AROUNDINT(v->color2.z*CONST_COLOR)&255);
				ZM3DsaveBuf(s,l, " %x %x\n", color1, color2);
			}

			ZFace	*face;

			// Sauvegarde des polygones (par materiau)
			for(j=0; j<mesh->FacesMatGour.size(); j++)
			{
				if(mesh->FacesMatGour[j].mat != NULL)		ZM3DsaveBuf(s,l, "%s\n", (char*)mesh->FacesMatGour[j].mat->name.c_str());

				// Not texturing
				if(mesh->FacesMatGour[j].mat->GetTexture1() == NULL)
				{
					for(k=0; k<mesh->FacesMatGour[j].faces.size(); k++)
					{
						face = mesh->FacesMatGour[j].faces[k];
						ZM3DsaveBuf(s,l, "  %d", (int)(face->VertRef[0]));
						ZM3DsaveBuf(s,l, "  %d", (int)(face->VertRef[1]));
						ZM3DsaveBuf(s,l, "  %d", (int)(face->VertRef[2]));
						ZM3DsaveBuf(s,l, "\n");
					}
				}
				else
				// MONO-texturing
				if(mesh->FacesMatGour[j].mat->GetTexture2() == NULL)
				{
					for(k=0; k<mesh->FacesMatGour[j].faces.size(); k++)
					{
						face = mesh->FacesMatGour[j].faces[k];
						ZM3DsaveBuf(s,l, "  %d %d %d", (int)(face->VertRef[0]), (int)(face->UV1[0].u*CONST_TEX_COORD), (int)(face->UV1[0].v*CONST_TEX_COORD));
						ZM3DsaveBuf(s,l, "  %d %d %d", (int)(face->VertRef[1]), (int)(face->UV1[1].u*CONST_TEX_COORD), (int)(face->UV1[1].v*CONST_TEX_COORD));
						ZM3DsaveBuf(s,l, "  %d %d %d", (int)(face->VertRef[2]), (int)(face->UV1[2].u*CONST_TEX_COORD), (int)(face->UV1[2].v*CONST_TEX_COORD));
						ZM3DsaveBuf(s,l, "\n");
					}
				}
				else
				// MULTI-texturing
				{
					for(k=0; k<mesh->FacesMatGour[j].faces.size(); k++)
					{
						face = mesh->FacesMatGour[j].faces[k];
						ZM3DsaveBuf(s,l, "  %d %d %d %d %d", (int)(face->VertRef[0]), (int)(face->UV1[0].u*CONST_TEX_COORD), (int)(face->UV1[0].v*CONST_TEX_COORD), (int)(face->UV2[0].u*CONST_TEX_COORD), (int)(face->UV2[0].v*CONST_TEX_COORD));
						ZM3DsaveBuf(s,l, "  %d %d %d %d %d", (int)(face->VertRef[1]), (int)(face->UV1[1].u*CONST_TEX_COORD), (int)(face->UV1[1].v*CONST_TEX_COORD), (int)(face->UV2[1].u*CONST_TEX_COORD), (int)(face->UV2[1].v*CONST_TEX_COORD));
						ZM3DsaveBuf(s,l, "  %d %d %d %d %d", (int)(face->VertRef[2]), (int)(face->UV1[2].u*CONST_TEX_COORD), (int)(face->UV1[2].v*CONST_TEX_COORD), (int)(face->UV2[2].u*CONST_TEX_COORD), (int)(face->UV2[2].v*CONST_TEX_COORD));
						ZM3DsaveBuf(s,l, "\n");
					}
				}
			}


			for(j=0; j<mesh->FacesMatFlat.size(); j++)
			{
				if(mesh->FacesMatFlat[j].mat != NULL)		ZM3DsaveBuf(s,l, "%s\n", (char*)mesh->FacesMatFlat[j].mat->name.c_str());

				// Not texturing
				if(mesh->FacesMatFlat[j].mat->GetTexture1() == NULL)
				{
					for(k=0; k<mesh->FacesMatFlat[j].faces.size(); k++)
					{
						face = mesh->FacesMatFlat[j].faces[k];
						ZM3DsaveBuf(s,l, "  %d", (int)(face->VertRef[0]));
						ZM3DsaveBuf(s,l, "  %d", (int)(face->VertRef[1]));
						ZM3DsaveBuf(s,l, "  %d", (int)(face->VertRef[2]));
						ZM3DsaveBuf(s,l, "\n");
					}
				}
				else
				// MONO-texturing
				if(mesh->FacesMatFlat[j].mat->GetTexture2() == NULL)
				{
					for(k=0; k<mesh->FacesMatFlat[j].faces.size(); k++)
					{
						face = mesh->FacesMatFlat[j].faces[k];
						ZM3DsaveBuf(s,l, "  %d %d %d", (int)(face->VertRef[0]), (int)(face->UV1[0].u*CONST_TEX_COORD), (int)(face->UV1[0].v*CONST_TEX_COORD));
						ZM3DsaveBuf(s,l, "  %d %d %d", (int)(face->VertRef[1]), (int)(face->UV1[1].u*CONST_TEX_COORD), (int)(face->UV1[1].v*CONST_TEX_COORD));
						ZM3DsaveBuf(s,l, "  %d %d %d", (int)(face->VertRef[2]), (int)(face->UV1[2].u*CONST_TEX_COORD), (int)(face->UV1[2].v*CONST_TEX_COORD));
						ZM3DsaveBuf(s,l, "\n");
					}
				}
				else
				// MULTI-texturing
				{
					for(k=0; k<mesh->FacesMatFlat[j].faces.size(); k++)
					{
						face = mesh->FacesMatFlat[j].faces[k];
						ZM3DsaveBuf(s,l, "  %d %d %d %d %d", (int)(face->VertRef[0]), (int)(face->UV1[0].u*CONST_TEX_COORD), (int)(face->UV1[0].v*CONST_TEX_COORD), (int)(face->UV2[0].u*CONST_TEX_COORD), (int)(face->UV2[0].v*CONST_TEX_COORD));
						ZM3DsaveBuf(s,l, "  %d %d %d %d %d", (int)(face->VertRef[1]), (int)(face->UV1[1].u*CONST_TEX_COORD), (int)(face->UV1[1].v*CONST_TEX_COORD), (int)(face->UV2[1].u*CONST_TEX_COORD), (int)(face->UV2[1].v*CONST_TEX_COORD));
						ZM3DsaveBuf(s,l, "  %d %d %d %d %d", (int)(face->VertRef[2]), (int)(face->UV1[2].u*CONST_TEX_COORD), (int)(face->UV1[2].v*CONST_TEX_COORD), (int)(face->UV2[2].u*CONST_TEX_COORD), (int)(face->UV2[2].v*CONST_TEX_COORD));
						ZM3DsaveBuf(s,l, "\n");
					}
				}
			}

			
			for(j=0; j<mesh->FacesMatNo.size(); j++)
			{
				if(mesh->FacesMatNo[j].mat != NULL)		ZM3DsaveBuf(s,l, "%s\n", (char*)mesh->FacesMatNo[j].mat->name.c_str());

				// Not texturing
				if(mesh->FacesMatNo[j].mat->GetTexture1() == NULL)
				{
					for(k=0; k<mesh->FacesMatNo[j].faces.size(); k++)
					{
						face = mesh->FacesMatNo[j].faces[k];
						ZM3DsaveBuf(s,l, "  %d", (int)(face->VertRef[0]));
						ZM3DsaveBuf(s,l, "  %d", (int)(face->VertRef[1]));
						ZM3DsaveBuf(s,l, "  %d", (int)(face->VertRef[2]));
						ZM3DsaveBuf(s,l, "\n");
					}
				}
				else
				// MONO-texturing
				if(mesh->FacesMatNo[j].mat->GetTexture2() == NULL)
				{
					for(k=0; k<mesh->FacesMatNo[j].faces.size(); k++)
					{
						face = mesh->FacesMatNo[j].faces[k];
						ZM3DsaveBuf(s,l, "  %d %d %d", (int)(face->VertRef[0]), (int)(face->UV1[0].u*CONST_TEX_COORD), (int)(face->UV1[0].v*CONST_TEX_COORD));
						ZM3DsaveBuf(s,l, "  %d %d %d", (int)(face->VertRef[1]), (int)(face->UV1[1].u*CONST_TEX_COORD), (int)(face->UV1[1].v*CONST_TEX_COORD));
						ZM3DsaveBuf(s,l, "  %d %d %d", (int)(face->VertRef[2]), (int)(face->UV1[2].u*CONST_TEX_COORD), (int)(face->UV1[2].v*CONST_TEX_COORD));
						ZM3DsaveBuf(s,l, "\n");
					}
				}
				else
				// MULTI-texturing
				{
					for(k=0; k<mesh->FacesMatNo[j].faces.size(); k++)
					{
						face = mesh->FacesMatNo[j].faces[k];
						ZM3DsaveBuf(s,l, "  %d %d %d %d %d", (int)(face->VertRef[0]), (int)(face->UV1[0].u*CONST_TEX_COORD), (int)(face->UV1[0].v*CONST_TEX_COORD), (int)(face->UV2[0].u*CONST_TEX_COORD), (int)(face->UV2[0].v*CONST_TEX_COORD));
						ZM3DsaveBuf(s,l, "  %d %d %d %d %d", (int)(face->VertRef[1]), (int)(face->UV1[1].u*CONST_TEX_COORD), (int)(face->UV1[1].v*CONST_TEX_COORD), (int)(face->UV2[1].u*CONST_TEX_COORD), (int)(face->UV2[1].v*CONST_TEX_COORD));
						ZM3DsaveBuf(s,l, "  %d %d %d %d %d", (int)(face->VertRef[2]), (int)(face->UV1[2].u*CONST_TEX_COORD), (int)(face->UV1[2].v*CONST_TEX_COORD), (int)(face->UV2[2].u*CONST_TEX_COORD), (int)(face->UV2[2].v*CONST_TEX_COORD));
						ZM3DsaveBuf(s,l, "\n");
					}
				}
			}

			ZM3DsaveBuf(s,l, "}\n");
		}
		else
		if(obj->IsMultiMeshes()==true && obj->GetMeshList()->Size())
			for(int kk=0; kk<obj->GetMeshList()->Size(); kk++)
				if( (*obj->GetMeshList())[kk]->saved==false )
		{
			ZMesh	*mesh = (*obj->GetMeshList())[kk];
			
			mesh->MakeFacesList();
			mesh->saved = true;

			ZM3DsaveBuf(s,l, "topo %s {\n", testempty((char*)mesh->name.c_str()));

			int		i, j, k, color1, color2;
			ZVert	*v;

			// Sauvegarde des vertices
			for(i=0; i<mesh->NbVerts; i++)
			{
				v = &(mesh->Verts[i]);
				ZM3DsaveBuf(s,l, " %f %f %f", v->x*100.0f, v->y*100.0f, -v->z*100.0f);
				color1 = ((AROUNDINT(v->color1.x*CONST_COLOR)&255)<<16) + ((AROUNDINT(v->color1.y*CONST_COLOR)&255)<<8) + (AROUNDINT(v->color1.z*CONST_COLOR)&255);
				color2 = ((AROUNDINT(v->color2.x*CONST_COLOR)&255)<<16) + ((AROUNDINT(v->color2.y*CONST_COLOR)&255)<<8) + (AROUNDINT(v->color2.z*CONST_COLOR)&255);
				ZM3DsaveBuf(s,l, " %x %x\n", color1, color2);
			}

			ZFace	*face;

			// Sauvegarde des polygones (par materiau)
			for(j=0; j<mesh->FacesMatGour.size(); j++)
			{
				if(mesh->FacesMatGour[j].mat != NULL)		ZM3DsaveBuf(s,l, "%s\n", (char*)mesh->FacesMatGour[j].mat->name.c_str());

				// Not texturing
				if(mesh->FacesMatGour[j].mat->GetTexture1() == NULL)
				{
					for(k=0; k<mesh->FacesMatGour[j].faces.size(); k++)
					{
						face = mesh->FacesMatGour[j].faces[k];
						ZM3DsaveBuf(s,l, "  %d", (int)(face->VertRef[0]));
						ZM3DsaveBuf(s,l, "  %d", (int)(face->VertRef[1]));
						ZM3DsaveBuf(s,l, "  %d", (int)(face->VertRef[2]));
						ZM3DsaveBuf(s,l, "\n");
					}
				}
				else
				// MONO-texturing
				if(mesh->FacesMatGour[j].mat->GetTexture2() == NULL)
				{
					for(k=0; k<mesh->FacesMatGour[j].faces.size(); k++)
					{
						face = mesh->FacesMatGour[j].faces[k];
						ZM3DsaveBuf(s,l, "  %d %d %d", (int)(face->VertRef[0]), (int)(face->UV1[0].u*CONST_TEX_COORD), (int)(face->UV1[0].v*CONST_TEX_COORD));
						ZM3DsaveBuf(s,l, "  %d %d %d", (int)(face->VertRef[1]), (int)(face->UV1[1].u*CONST_TEX_COORD), (int)(face->UV1[1].v*CONST_TEX_COORD));
						ZM3DsaveBuf(s,l, "  %d %d %d", (int)(face->VertRef[2]), (int)(face->UV1[2].u*CONST_TEX_COORD), (int)(face->UV1[2].v*CONST_TEX_COORD));
						ZM3DsaveBuf(s,l, "\n");
					}
				}
				else
				// MULTI-texturing
				{
					for(k=0; k<mesh->FacesMatGour[j].faces.size(); k++)
					{
						face = mesh->FacesMatGour[j].faces[k];
						ZM3DsaveBuf(s,l, "  %d %d %d %d %d", (int)(face->VertRef[0]), (int)(face->UV1[0].u*CONST_TEX_COORD), (int)(face->UV1[0].v*CONST_TEX_COORD), (int)(face->UV2[0].u*CONST_TEX_COORD), (int)(face->UV2[0].v*CONST_TEX_COORD));
						ZM3DsaveBuf(s,l, "  %d %d %d %d %d", (int)(face->VertRef[1]), (int)(face->UV1[1].u*CONST_TEX_COORD), (int)(face->UV1[1].v*CONST_TEX_COORD), (int)(face->UV2[1].u*CONST_TEX_COORD), (int)(face->UV2[1].v*CONST_TEX_COORD));
						ZM3DsaveBuf(s,l, "  %d %d %d %d %d", (int)(face->VertRef[2]), (int)(face->UV1[2].u*CONST_TEX_COORD), (int)(face->UV1[2].v*CONST_TEX_COORD), (int)(face->UV2[2].u*CONST_TEX_COORD), (int)(face->UV2[2].v*CONST_TEX_COORD));
						ZM3DsaveBuf(s,l, "\n");
					}
				}
			}

		
			for(j=0; j<mesh->FacesMatFlat.size(); j++)
			{
				if(mesh->FacesMatFlat[j].mat != NULL)		ZM3DsaveBuf(s,l, "%s\n", (char*)mesh->FacesMatFlat[j].mat->name.c_str());

				// Not texturing
				if(mesh->FacesMatFlat[j].mat->GetTexture1() == NULL)
				{
					for(k=0; k<mesh->FacesMatFlat[j].faces.size(); k++)
					{
						face = mesh->FacesMatFlat[j].faces[k];
						ZM3DsaveBuf(s,l, "  %d", (int)(face->VertRef[0]));
						ZM3DsaveBuf(s,l, "  %d", (int)(face->VertRef[1]));
						ZM3DsaveBuf(s,l, "  %d", (int)(face->VertRef[2]));
						ZM3DsaveBuf(s,l, "\n");
					}
				}
				else
				// MONO-texturing
				if(mesh->FacesMatFlat[j].mat->GetTexture2() == NULL)
				{
					for(k=0; k<mesh->FacesMatFlat[j].faces.size(); k++)
					{
						face = mesh->FacesMatFlat[j].faces[k];
						ZM3DsaveBuf(s,l, "  %d %d %d", (int)(face->VertRef[0]), (int)(face->UV1[0].u*CONST_TEX_COORD), (int)(face->UV1[0].v*CONST_TEX_COORD));
						ZM3DsaveBuf(s,l, "  %d %d %d", (int)(face->VertRef[1]), (int)(face->UV1[1].u*CONST_TEX_COORD), (int)(face->UV1[1].v*CONST_TEX_COORD));
						ZM3DsaveBuf(s,l, "  %d %d %d", (int)(face->VertRef[2]), (int)(face->UV1[2].u*CONST_TEX_COORD), (int)(face->UV1[2].v*CONST_TEX_COORD));
						ZM3DsaveBuf(s,l, "\n");
					}
				}
				else
				// MULTI-texturing
				{
					for(k=0; k<mesh->FacesMatFlat[j].faces.size(); k++)
					{
						face = mesh->FacesMatFlat[j].faces[k];
						ZM3DsaveBuf(s,l, "  %d %d %d %d %d", (int)(face->VertRef[0]), (int)(face->UV1[0].u*CONST_TEX_COORD), (int)(face->UV1[0].v*CONST_TEX_COORD), (int)(face->UV2[0].u*CONST_TEX_COORD), (int)(face->UV2[0].v*CONST_TEX_COORD));
						ZM3DsaveBuf(s,l, "  %d %d %d %d %d", (int)(face->VertRef[1]), (int)(face->UV1[1].u*CONST_TEX_COORD), (int)(face->UV1[1].v*CONST_TEX_COORD), (int)(face->UV2[1].u*CONST_TEX_COORD), (int)(face->UV2[1].v*CONST_TEX_COORD));
						ZM3DsaveBuf(s,l, "  %d %d %d %d %d", (int)(face->VertRef[2]), (int)(face->UV1[2].u*CONST_TEX_COORD), (int)(face->UV1[2].v*CONST_TEX_COORD), (int)(face->UV2[2].u*CONST_TEX_COORD), (int)(face->UV2[2].v*CONST_TEX_COORD));
						ZM3DsaveBuf(s,l, "\n");
					}
				}
			}

			
			for(j=0; j<mesh->FacesMatNo.size(); j++)
			{
				if(mesh->FacesMatNo[j].mat != NULL)		ZM3DsaveBuf(s,l, "%s\n", (char*)mesh->FacesMatNo[j].mat->name.c_str());

				// Not texturing
				if(mesh->FacesMatNo[j].mat->GetTexture1() == NULL)
				{
					for(k=0; k<mesh->FacesMatNo[j].faces.size(); k++)
					{
						face = mesh->FacesMatNo[j].faces[k];
						ZM3DsaveBuf(s,l, "  %d", (int)(face->VertRef[0]));
						ZM3DsaveBuf(s,l, "  %d", (int)(face->VertRef[1]));
						ZM3DsaveBuf(s,l, "  %d", (int)(face->VertRef[2]));
						ZM3DsaveBuf(s,l, "\n");
					}
				}
				else
				// MONO-texturing
				if(mesh->FacesMatNo[j].mat->GetTexture2() == NULL)
				{
					for(k=0; k<mesh->FacesMatNo[j].faces.size(); k++)
					{
						face = mesh->FacesMatNo[j].faces[k];
						ZM3DsaveBuf(s,l, "  %d %d %d", (int)(face->VertRef[0]), (int)(face->UV1[0].u*CONST_TEX_COORD), (int)(face->UV1[0].v*CONST_TEX_COORD));
						ZM3DsaveBuf(s,l, "  %d %d %d", (int)(face->VertRef[1]), (int)(face->UV1[1].u*CONST_TEX_COORD), (int)(face->UV1[1].v*CONST_TEX_COORD));
						ZM3DsaveBuf(s,l, "  %d %d %d", (int)(face->VertRef[2]), (int)(face->UV1[2].u*CONST_TEX_COORD), (int)(face->UV1[2].v*CONST_TEX_COORD));
						ZM3DsaveBuf(s,l, "\n");
					}
				}
				else
				// MULTI-texturing
				{
					for(k=0; k<mesh->FacesMatNo[j].faces.size(); k++)
					{
						face = mesh->FacesMatNo[j].faces[k];
						ZM3DsaveBuf(s,l, "  %d %d %d %d %d", (int)(face->VertRef[0]), (int)(face->UV1[0].u*CONST_TEX_COORD), (int)(face->UV1[0].v*CONST_TEX_COORD), (int)(face->UV2[0].u*CONST_TEX_COORD), (int)(face->UV2[0].v*CONST_TEX_COORD));
						ZM3DsaveBuf(s,l, "  %d %d %d %d %d", (int)(face->VertRef[1]), (int)(face->UV1[1].u*CONST_TEX_COORD), (int)(face->UV1[1].v*CONST_TEX_COORD), (int)(face->UV2[1].u*CONST_TEX_COORD), (int)(face->UV2[1].v*CONST_TEX_COORD));
						ZM3DsaveBuf(s,l, "  %d %d %d %d %d", (int)(face->VertRef[2]), (int)(face->UV1[2].u*CONST_TEX_COORD), (int)(face->UV1[2].v*CONST_TEX_COORD), (int)(face->UV2[2].u*CONST_TEX_COORD), (int)(face->UV2[2].v*CONST_TEX_COORD));
						ZM3DsaveBuf(s,l, "\n");
					}
				}
			}

			ZM3DsaveBuf(s,l, "}\n");
		}
	}
	else if(flag!=NIL && node->type==PCL_TYPE_ID)
	{
		ZMesh	*mesh;
		ZParticle *particle;
		ZEmitter *emitter = (ZEmitter*)node;

		for(int i=0;i<emitter->particlelist.size();i++)
		{
			particle	= emitter->particlelist[i].parttype;
			mesh		= particle->GetMesh();
			if(mesh->saved==false)
			{
				mesh->MakeFacesList();
				mesh->saved = true;

				ZM3DsaveBuf(s,l, "topo %s {\n", testempty((char*)mesh->name.c_str()));

				int		i, j, k, color1, color2;
				ZVert	*v;

				// Sauvegarde des vertices
				for(i=0; i<mesh->NbVerts; i++)
				{
					v = &(mesh->Verts[i]);
					ZM3DsaveBuf(s,l, " %f %f %f", v->x*100.0f, v->y*100.0f, -v->z*100.0f);
					color1 = ((AROUNDINT(v->color1.x*CONST_COLOR)&255)<<16) + ((AROUNDINT(v->color1.y*CONST_COLOR)&255)<<8) + (AROUNDINT(v->color1.z*CONST_COLOR)&255);
					color2 = ((AROUNDINT(v->color2.x*CONST_COLOR)&255)<<16) + ((AROUNDINT(v->color2.y*CONST_COLOR)&255)<<8) + (AROUNDINT(v->color2.z*CONST_COLOR)&255);
					ZM3DsaveBuf(s,l, " %x %x\n", color1, color2);
				}

				ZFace	*face;

				// Sauvegarde des polygones (par materiau)
				for(j=0; j<mesh->FacesMatGour.size(); j++)
				{
					if(mesh->FacesMatGour[j].mat != NULL)		ZM3DsaveBuf(s,l, "%s\n", (char*)mesh->FacesMatGour[j].mat->name.c_str());

					// Not texturing
					if(mesh->FacesMatGour[j].mat->GetTexture1() == NULL)
					{
						for(k=0; k<mesh->FacesMatGour[j].faces.size(); k++)
						{
							face = mesh->FacesMatGour[j].faces[k];
							ZM3DsaveBuf(s,l, "  %d", (int)(face->VertRef[0]));
							ZM3DsaveBuf(s,l, "  %d", (int)(face->VertRef[1]));
							ZM3DsaveBuf(s,l, "  %d", (int)(face->VertRef[2]));
							ZM3DsaveBuf(s,l, "\n");
						}
					}
					else
					// MONO-texturing
					if(mesh->FacesMatGour[j].mat->GetTexture2() == NULL)
					{
						for(k=0; k<mesh->FacesMatGour[j].faces.size(); k++)
						{
							face = mesh->FacesMatGour[j].faces[k];
							ZM3DsaveBuf(s,l, "  %d %d %d", (int)(face->VertRef[0]), (int)(face->UV1[0].u*CONST_TEX_COORD), (int)(face->UV1[0].v*CONST_TEX_COORD));
							ZM3DsaveBuf(s,l, "  %d %d %d", (int)(face->VertRef[1]), (int)(face->UV1[1].u*CONST_TEX_COORD), (int)(face->UV1[1].v*CONST_TEX_COORD));
							ZM3DsaveBuf(s,l, "  %d %d %d", (int)(face->VertRef[2]), (int)(face->UV1[2].u*CONST_TEX_COORD), (int)(face->UV1[2].v*CONST_TEX_COORD));
							ZM3DsaveBuf(s,l, "\n");
						}
					}
					else
					// MULTI-texturing
					{
						for(k=0; k<mesh->FacesMatGour[j].faces.size(); k++)
						{
							face = mesh->FacesMatGour[j].faces[k];
							ZM3DsaveBuf(s,l, "  %d %d %d %d %d", (int)(face->VertRef[0]), (int)(face->UV1[0].u*CONST_TEX_COORD), (int)(face->UV1[0].v*CONST_TEX_COORD), (int)(face->UV2[0].u*CONST_TEX_COORD), (int)(face->UV2[0].v*CONST_TEX_COORD));
							ZM3DsaveBuf(s,l, "  %d %d %d %d %d", (int)(face->VertRef[1]), (int)(face->UV1[1].u*CONST_TEX_COORD), (int)(face->UV1[1].v*CONST_TEX_COORD), (int)(face->UV2[1].u*CONST_TEX_COORD), (int)(face->UV2[1].v*CONST_TEX_COORD));
							ZM3DsaveBuf(s,l, "  %d %d %d %d %d", (int)(face->VertRef[2]), (int)(face->UV1[2].u*CONST_TEX_COORD), (int)(face->UV1[2].v*CONST_TEX_COORD), (int)(face->UV2[2].u*CONST_TEX_COORD), (int)(face->UV2[2].v*CONST_TEX_COORD));
							ZM3DsaveBuf(s,l, "\n");
						}
					}
				}


				for(j=0; j<mesh->FacesMatFlat.size(); j++)
				{
					if(mesh->FacesMatFlat[j].mat != NULL)		ZM3DsaveBuf(s,l, "%s\n", (char*)mesh->FacesMatFlat[j].mat->name.c_str());

					// Not texturing
					if(mesh->FacesMatFlat[j].mat->GetTexture1() == NULL)
					{
						for(k=0; k<mesh->FacesMatFlat[j].faces.size(); k++)
						{
							face = mesh->FacesMatFlat[j].faces[k];
							ZM3DsaveBuf(s,l, "  %d", (int)(face->VertRef[0]));
							ZM3DsaveBuf(s,l, "  %d", (int)(face->VertRef[1]));
							ZM3DsaveBuf(s,l, "  %d", (int)(face->VertRef[2]));
							ZM3DsaveBuf(s,l, "\n");
						}
					}
					else
					// MONO-texturing
					if(mesh->FacesMatFlat[j].mat->GetTexture2() == NULL)
					{
						for(k=0; k<mesh->FacesMatFlat[j].faces.size(); k++)
						{
							face = mesh->FacesMatFlat[j].faces[k];
							ZM3DsaveBuf(s,l, "  %d %d %d", (int)(face->VertRef[0]), (int)(face->UV1[0].u*CONST_TEX_COORD), (int)(face->UV1[0].v*CONST_TEX_COORD));
							ZM3DsaveBuf(s,l, "  %d %d %d", (int)(face->VertRef[1]), (int)(face->UV1[1].u*CONST_TEX_COORD), (int)(face->UV1[1].v*CONST_TEX_COORD));
							ZM3DsaveBuf(s,l, "  %d %d %d", (int)(face->VertRef[2]), (int)(face->UV1[2].u*CONST_TEX_COORD), (int)(face->UV1[2].v*CONST_TEX_COORD));
							ZM3DsaveBuf(s,l, "\n");
						}
					}
					else
					// MULTI-texturing
					{
						for(k=0; k<mesh->FacesMatFlat[j].faces.size(); k++)
						{
							face = mesh->FacesMatFlat[j].faces[k];
							ZM3DsaveBuf(s,l, "  %d %d %d %d %d", (int)(face->VertRef[0]), (int)(face->UV1[0].u*CONST_TEX_COORD), (int)(face->UV1[0].v*CONST_TEX_COORD), (int)(face->UV2[0].u*CONST_TEX_COORD), (int)(face->UV2[0].v*CONST_TEX_COORD));
							ZM3DsaveBuf(s,l, "  %d %d %d %d %d", (int)(face->VertRef[1]), (int)(face->UV1[1].u*CONST_TEX_COORD), (int)(face->UV1[1].v*CONST_TEX_COORD), (int)(face->UV2[1].u*CONST_TEX_COORD), (int)(face->UV2[1].v*CONST_TEX_COORD));
							ZM3DsaveBuf(s,l, "  %d %d %d %d %d", (int)(face->VertRef[2]), (int)(face->UV1[2].u*CONST_TEX_COORD), (int)(face->UV1[2].v*CONST_TEX_COORD), (int)(face->UV2[2].u*CONST_TEX_COORD), (int)(face->UV2[2].v*CONST_TEX_COORD));
							ZM3DsaveBuf(s,l, "\n");
						}
					}
				}

				
				for(j=0; j<mesh->FacesMatNo.size(); j++)
				{
					if(mesh->FacesMatNo[j].mat != NULL)		ZM3DsaveBuf(s,l, "%s\n", (char*)mesh->FacesMatNo[j].mat->name.c_str());

					// Not texturing
					if(mesh->FacesMatNo[j].mat->GetTexture1() == NULL)
					{
						for(k=0; k<mesh->FacesMatNo[j].faces.size(); k++)
						{
							face = mesh->FacesMatNo[j].faces[k];
							ZM3DsaveBuf(s,l, "  %d", (int)(face->VertRef[0]));
							ZM3DsaveBuf(s,l, "  %d", (int)(face->VertRef[1]));
							ZM3DsaveBuf(s,l, "  %d", (int)(face->VertRef[2]));
							ZM3DsaveBuf(s,l, "\n");
						}
					}
					else
					// MONO-texturing
					if(mesh->FacesMatNo[j].mat->GetTexture2() == NULL)
					{
						for(k=0; k<mesh->FacesMatNo[j].faces.size(); k++)
						{
							face = mesh->FacesMatNo[j].faces[k];
							ZM3DsaveBuf(s,l, "  %d %d %d", (int)(face->VertRef[0]), (int)(face->UV1[0].u*CONST_TEX_COORD), (int)(face->UV1[0].v*CONST_TEX_COORD));
							ZM3DsaveBuf(s,l, "  %d %d %d", (int)(face->VertRef[1]), (int)(face->UV1[1].u*CONST_TEX_COORD), (int)(face->UV1[1].v*CONST_TEX_COORD));
							ZM3DsaveBuf(s,l, "  %d %d %d", (int)(face->VertRef[2]), (int)(face->UV1[2].u*CONST_TEX_COORD), (int)(face->UV1[2].v*CONST_TEX_COORD));
							ZM3DsaveBuf(s,l, "\n");
						}
					}
					else
					// MULTI-texturing
					{
						for(k=0; k<mesh->FacesMatNo[j].faces.size(); k++)
						{
							face = mesh->FacesMatNo[j].faces[k];
							ZM3DsaveBuf(s,l, "  %d %d %d %d %d", (int)(face->VertRef[0]), (int)(face->UV1[0].u*CONST_TEX_COORD), (int)(face->UV1[0].v*CONST_TEX_COORD), (int)(face->UV2[0].u*CONST_TEX_COORD), (int)(face->UV2[0].v*CONST_TEX_COORD));
							ZM3DsaveBuf(s,l, "  %d %d %d %d %d", (int)(face->VertRef[1]), (int)(face->UV1[1].u*CONST_TEX_COORD), (int)(face->UV1[1].v*CONST_TEX_COORD), (int)(face->UV2[1].u*CONST_TEX_COORD), (int)(face->UV2[1].v*CONST_TEX_COORD));
							ZM3DsaveBuf(s,l, "  %d %d %d %d %d", (int)(face->VertRef[2]), (int)(face->UV1[2].u*CONST_TEX_COORD), (int)(face->UV1[2].v*CONST_TEX_COORD), (int)(face->UV2[2].u*CONST_TEX_COORD), (int)(face->UV2[2].v*CONST_TEX_COORD));
							ZM3DsaveBuf(s,l, "\n");
						}
					}
				}

				ZM3DsaveBuf(s,l, "}\n");
			}
		}

	}


	if(node->son!=NULL)						ZM3DsaveTopo(s, l, node->son, false, 0);

	if((!first)&&(node->next!=NULL))		ZM3DsaveTopo(s, l, node->next, false, 0);

	return 0;
}



int ZM3DsaveEmitter(ZScene *s, save3d l, ZEmitter *emitter)
{
	ZM3DsaveBuf(s,l,"emitter %s {\n", emitter->name.c_str());
	ZM3DsavePRS(s, l, (ZNode*)emitter);
	
	if(emitter->mask==0)
		ZM3DsaveBuf(s,l,"\tmask 0\n");
	else {
		string tmp;
		tmp = "\tmask";

		if(emitter->mask&PCL_INFINIT)		tmp += " infinit";
		if(emitter->mask&PCL_ADDITIVE)		tmp += " additive";

		tmp += "\n";

		ZM3DsaveBuf(s,l, (char*)tmp.c_str());}
	

	ZM3DsaveBuf(s,l,"\tlife %f\n", emitter->life*100.0f);

		 if(emitter->volume.type==VOLUME_CONE)			ZM3DsaveBuf(s,l,"\tvolume cone\n");
	else if(emitter->volume.type==VOLUME_SPHERE)		ZM3DsaveBuf(s,l,"\tvolume sphere\n");
	else if(emitter->volume.type==VOLUME_PLAN)			ZM3DsaveBuf(s,l,"\tvolume plan\n");
	else if(emitter->volume.type==VOLUME_LINE)			ZM3DsaveBuf(s,l,"\tvolume line\n");

	ZM3DsaveBuf(s,l,"\tvectorA %f %f %f\n", emitter->volume.vectorA.x*100.0f, emitter->volume.vectorA.y*100.0f, emitter->volume.vectorA.z*100.0f);
	ZM3DsaveBuf(s,l,"\tvectorB %f %f %f\n", emitter->volume.vectorB.x*100.0f, emitter->volume.vectorB.y*100.0f, emitter->volume.vectorB.z*100.0f);

	std::vector<T_PCL_LIST>::iterator	pit = emitter->particlelist.begin();
	std::vector<ZEffect*>::iterator		eit = emitter->effectlist.begin();

	for(;pit!=emitter->particlelist.end();pit++)
		ZM3DsaveBuf(s,l,"\tparticle %s\n", pit->parttype->name.c_str());

	for(;eit!=emitter->effectlist.end();eit++)
		ZM3DsaveBuf(s,l,"\teffect %s\n", (*eit)->name.c_str());

	return 0;
}


int ZM3DsaveParticle(ZScene *s, save3d l, ZParticle *particle)
{
	ZM3DsaveBuf(s,l,"particle %s {\n", particle->name.c_str());

	if(particle->mask&PCL_BILLBOARD)		ZM3DsaveBuf(s,l,"\tmask %s\n", "billboard");
	if(particle->mask&PCL_RAINBOW)			ZM3DsaveBuf(s,l,"\tmask %s\n", "rainbow");
	if(particle->mask&PCL_JITTER)			ZM3DsaveBuf(s,l,"\tmask %s\n", "jitter");
	
	ZM3DsaveBuf(s,l,"\tlife %f\n", particle->life*100.0f);
	ZM3DsaveBuf(s,l,"\trate %f\n", particle->rate*100.0f);
	ZM3DsaveBuf(s,l,"\tweight %f\n", particle->weight*100.0f);

	std::vector<T_PARAM>::iterator sit = particle->size.begin();
	ZM3DsaveBuf(s,l,"\tsize %f\n", sit->value*100.0f);

	sit = particle->spin.begin();
	ZM3DsaveBuf(s,l,"\tspin %f\n", sit->value*100.0f);


	ZM3DsaveBuf(s,l,"\tpolarity %f\n", particle->polarity*100.0f);
	ZM3DsaveBuf(s,l,"\ttopo %s\n", particle->GetMesh()->name.c_str());


	sit = particle->size.begin();
	if(particle->size.size()>1)		
	{
		for(;sit!=particle->size.end();sit++)
			ZM3DsaveBuf(s,l,"\ttsize %f %f\n", sit->value*100.0f, sit->pos);
	}

	sit = particle->spin.begin();
	if(particle->spin.size()>1)		
	{
		for(;sit!=particle->spin.end();sit++)
			ZM3DsaveBuf(s,l,"\ttspin %f %f\n", sit->value*100.0f, sit->pos);
	}

	int r,g,b,a,c;
	std::vector<T_COLOR>::iterator cit = particle->color.begin();

	if(particle->color.size()>1)		
	{
		for(;cit!=particle->color.end();cit++)
		{
			r = cit->value.x * CONST_COLOR;
			g = cit->value.y * CONST_COLOR;
			b = cit->value.z * CONST_COLOR;
			a = cit->value.w * CONST_COLOR;

			c = (a&0x000000ff) + ((b&0x000000ff)<<8) + ((g&0x000000ff)<<16) + ((r&0x000000ff)<<24);
			ZM3DsaveBuf(s,l,"\ttcolor %x %f\n", c, cit->pos);
		}
	}
	else
	{
		r = cit->value.x * CONST_COLOR;
		g = cit->value.y * CONST_COLOR;
		b = cit->value.z * CONST_COLOR;
		a = cit->value.w * CONST_COLOR;

		c = (a&0x000000ff) + ((b&0x000000ff)<<8) + ((g&0x000000ff)<<16) + ((r&0x000000ff)<<24);
		ZM3DsaveBuf(s,l,"\tcolor %x\n", c);
	}

	ZM3DsaveBuf(s,l,"}\n");

	return 0;
}

int ZM3DsaveEffect(ZScene *s, save3d l, ZEffect *effect)
{
	ZM3DsaveBuf(s,l,"effect %s {\n", effect->name.c_str());

		 if(effect->etype==EFFECT_CONSTANT)		ZM3DsaveBuf(s,l,"\ttype constant\n");
	else if(effect->etype==EFFECT_ELECTRIC)		ZM3DsaveBuf(s,l,"\ttype electric\n");
	else if(effect->etype==EFFECT_MAGNETIC)		ZM3DsaveBuf(s,l,"\ttype magnetic\n");
	else if(effect->etype==EFFECT_HELICOID)		ZM3DsaveBuf(s,l,"\ttype helicoid\n");
	else if(effect->etype==EFFECT_CHAOTIC0)		ZM3DsaveBuf(s,l,"\ttype chaotic0\n");
	else if(effect->etype==EFFECT_CHAOTIC1)		ZM3DsaveBuf(s,l,"\ttype chaotic1\n");

	ZM3DsaveBuf(s,l,"\tvectorA %f %f %f\n", effect->vectorA.x*100.0f, effect->vectorA.y*100.0f, -effect->vectorA.z*100.0f);
	ZM3DsaveBuf(s,l,"\tvectorB %f %f %f\n", effect->vectorB.x*100.0f, effect->vectorB.y*100.0f, -effect->vectorB.z*100.0f);
	ZM3DsaveBuf(s,l,"\tvectorC %f %f %f\n", effect->vectorC.x*100.0f, effect->vectorC.y*100.0f, -effect->vectorC.z*100.0f);

	ZM3DsaveBuf(s,l,"}\n");

	return 0;
}



int ZM3Dsave(ZScene *s, save3d l, ZNode *curNode, bool first, int flag)
{
	bool	saved = false;

	// Sauvegarde des topologies référencées à + d'une unité
	if(first)
	{
		for(int i=0; i<s->MshList.Size(); i++)		s->MshList[i]->saved = false;
		
		ZM3DsaveTopo(s, l, curNode, true, flag);

		for(i=0;i<s->PclDef.Size(); i++)			ZM3DsaveParticle(s,l,(ZParticle*)s->PclDef[i]);
		for(i=0;i<s->PclEff.Size(); i++)			ZM3DsaveEffect(s,l,(ZEffect*)s->PclEff[i]);
	}

	if(flag!=NIL)
	{
		if (curNode->type==SHL_TYPE_ID)				{	saved = true;		ZM3DsaveShell(s,l,(ZShell*)curNode);		}
		else if (curNode->type==CAM_TYPE_ID)		{	saved = true;		ZM3DsaveCam(s,l,(ZCamera*)curNode);			}
		else if (curNode->type==LGH_TYPE_ID)		{	saved = true;		ZM3DsaveLight(s,l,(ZLight*)curNode);		}
		else if (curNode->type==OBJ_TYPE_ID)		{	saved = true;		ZM3DsaveMesh(s,l,(ZObject*)curNode);		}
		else if (curNode->type==ANI_TYPE_ID)		{	saved = true;		ZM3DsaveAnim(s,l,(ZAnim*)curNode, 100.0f);	}
		else if (curNode->type==COL_TYPE_ID)		{	saved = true;		ZM3DsaveColl(s,l,(ZColl*)curNode);			}
		else if (curNode->type==PCL_TYPE_ID)		{	saved = true;		ZM3DsaveEmitter(s,l,(ZEmitter*)curNode);	}
	}

	if(curNode->son!=NULL)
    {
		if(ZM3Dsave(s, l, curNode->son, false, 0))		return -1;
    }

	if((flag!=NIL) && saved)		ZM3DsaveBuf(s,l,"}\n");

	if((!first)&&(curNode->next!=NULL))
    {
		if(ZM3Dsave(s, l, curNode->next, false, 0))		return -1;
    }

	return 0;
}





int ZM3DsaveMat(ZScene *s, save3d l)
{
	for(int i=0; i<s->MatList.Size(); i++)		ZM3DsaveMat(s, l, s->MatList[i]);

	return 0;
}


