/*=========================================================================
*
* SpoLoad.c	- Loading functions for SPO file
*
* Version			1.0
* Revision date
*
*=======================================================================*/

#include "SpoLoad.h"

#include "conventi.h"
#include "main.h"
#include "print.h"
#include "system.h"
#include "vertex.h"

#include "ModLib.h"

//--- Defines ---------------------------------------------------------------

#define C_szTransparencyFlag "TL"
#define C_iTransparencyLength 2


//--- Global defines --------------------------------------------------------

BOOL g_bSubFile			= FALSE;


//--- Global statics --------------------------------------------------------

BOOL gs_bHierarchyAlreadyFree;

MLT_tdstSPOFlags g_stSPOFlags[32];

int				 g_iEditorSPOFlags[32];
int				 g_iNbEditorSPOFlags;



//--------------------------------------------------------------------



/****************************************************************************
*		Description:	register the loading function for the SPO file
*
*		Parameters:		
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
void MLT_vInitSPOLoad()
{    
  SCR_fn_v_RdL0_RegisterCallback(M_SuperObject, MLT_xLoadSuperObject,SCR_CRC_c_RdL0_ForSection);  
  SCR_fn_v_RdL0_RegisterCallback(M_Matrix, MLT_xLoadMatrix,SCR_CRC_c_RdL0_ForSection);
}


/****************************************************************************
*		Description:	load super-object section in SPO file
*
*		Parameters:		p_stFile	: script file pointer
*						szAction	: section or entry name
*						szParams	: parameters
*						cType		: action type
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
SCR_tde_Anl_ReturnValue MLT_xLoadSuperObject(SCR_tdst_File_Description *p_fFile, char *szAction, char *szParams[], SCR_tde_Anl_Action cType)
{
  MLT_tdxHandleToSuperObject hSuperObject;
  MLT_tdxHandleToSuperObject hNewSuperObject;
  MLT_tdstGeometricObject	 *p_stObj;
  MLT_tdstSubMaps			 *p_stSubMaps;
  xString					 sFile, sAction, sIdent, sIdent2;
  char						 *p_Char1, *p_Char2, *p_sConstraintAxis; 
  char						 sValue[20], szName[100];
  long						 i;

  switch (cType)
	{
		case SCR_EA_Anl_BeginSection:
			hSuperObject = (MLT_tdxHandleToSuperObject)calloc(1,sizeof(MLT_tdstSprObj));
			// init parameter
			hSuperObject->lNbChild = 0;
			hSuperObject->iGeomProp = 0;
			hSuperObject->ulSPOFlags = 0;
			hSuperObject->fTransparency = -1.0;
			hSuperObject->stSector.lNbSecteurGraphic = 0;
			hSuperObject->stSector.lNbSecteurActivity = 0;
			hSuperObject->stSector.lNbSecteurCollision = 0;
			hSuperObject->stSector.bIsVirtual = FALSE;
			// get minimal name
			SCR_fn_v_RdL0_SplitSectionName(SCR_M_RdL0_GetCompleteSectionNameR(0), sFile, sAction, sIdent);
			// check for submaps
			if (strstr(sFile, ".sub"))
			{	
				g_bSubFile=TRUE;
				SCR_M_RdL0_GetContextLong(-1,0,MLT_tdstSubMaps*,p_stSubMaps);
			}
			// check for mirror
			if ((p_Char1=strstr(sIdent, "#mir"))!=NULL) 
				hSuperObject->iFlags |= MAYBE_MIRROR;
			else
				hSuperObject->iFlags =0;
			// check for collision flag
			if (strstr(sIdent, "!nocol"))
				hSuperObject->ulSPOFlags |=  1 << g_stSPOFlags[MLT_iGetIndexSPOFlags("NC")].sFlag;
			// compute super-object flags
			MLT_vSetSPOFlags(&hSuperObject->ulSPOFlags, &hSuperObject->fTransparency, &sIdent);
			// compute geometric properties
			p_sConstraintAxis = (char *)malloc(7*sizeof(char));
			if (p_sConstraintAxis) 
			{	
				MLT_vGeomProp( &hSuperObject->iGeomProp, &sIdent, &hSuperObject->cGeom, &hSuperObject->fGeom, &p_sConstraintAxis);
				strcpy(hSuperObject->sConstraintAxis, p_sConstraintAxis);
				free(p_sConstraintAxis);
			}
			// add the "SPO_" prefix if necessary
			if( (strcmp(sIdent, M_Root) != 0) && (strstr(sIdent, M_SPO_) == NULL) )
				sprintf(sIdent2, "SPO_%s", sIdent);
			else
				sprintf(sIdent2, "%s", sIdent);
			SCR_fn_v_RdL0_ComputeSectionName(hSuperObject->sName,  sFile, sAction, sIdent2);
      
			SCR_M_RdL0_SetSectionLong(0,0,(unsigned long)hSuperObject);
			SCR_M_RdL0_SetContextLong(0,0,(unsigned long)hSuperObject);
		break;

		case SCR_EA_Anl_Entry:
			// submap sections have their own function
			if (!g_bSubFile)
			{
				SCR_M_RdL0_GetContextLong(0,0,MLT_tdxHandleToSuperObject,hSuperObject);
				
				// read the comment line and concatenate it to the name of the object
				if (strcmp(szAction,M_SPOActionComment)==0)
				{
					strcat(hSuperObject->sName, szParams[0]);
					SCR_fn_v_RdL0_SplitSectionName(hSuperObject->sName, sFile, sAction, sIdent);
					// check for mirror
					if ((p_Char1=strstr(sIdent, "#mir"))!=NULL) 
						hSuperObject->iFlags |= MAYBE_MIRROR;
					else
						hSuperObject->iFlags =0;
					// check for SPO flags
					MLT_vSetSPOFlags(&hSuperObject->ulSPOFlags, &hSuperObject->fTransparency, &sIdent);
					// check for symmetry
					if (((p_Char1=strstr(sIdent, "#Sym("))!=NULL) || 
						((p_Char1=strstr(sIdent, "#SYM("))!=NULL) ||
						((p_Char1=strstr(sIdent, "#sym("))!=NULL)) 
					{	
						// take first the axe and the center
						p_Char1=strstr(sIdent, "(");
						if (p_Char1) 
						{	hSuperObject->cGeom = (sIdent)[strlen(sIdent)-strlen(p_Char1)+1];
							p_Char1=strstr(sIdent, ",");
							p_Char2=strstr(p_Char1, ")");
							i=0;
							while (p_Char1!=p_Char2) 
							{	sValue[i]=(sIdent)[strlen(sIdent)-strlen(p_Char1)+1];
								p_Char1++;
								i++;
							}
							sValue[i]='\0';
							hSuperObject->fGeom = atof(sValue);
						}
						if (((p_Char1=strstr(sIdent, "#Sym"))!=NULL) || 
							((p_Char1=strstr(sIdent, "#sym"))!=NULL) ||
							((p_Char1=strstr(sIdent, "#SYM"))!=NULL))
						{
							p_Char2=strstr(sIdent, ")");
							(sIdent)[strlen(sIdent)-strlen(p_Char1)]='\0';
							strcpy(szName, sIdent);
							if (*p_Char2 != 0) 
								strcat(szName, p_Char2+1);
							strcpy(sIdent, szName);
						}
						hSuperObject->iGeomProp |= MAYBE_SYM;
					}
					// check for geometric properties
					p_sConstraintAxis = (char *)malloc(7*sizeof(char));
					if (p_sConstraintAxis) 
					{	MLT_vGeomProp( &hSuperObject->iGeomProp, &sIdent, &hSuperObject->cGeom, &hSuperObject->fGeom, &p_sConstraintAxis);
						strcpy(hSuperObject->sConstraintAxis, p_sConstraintAxis);
						free(p_sConstraintAxis);
					}
					// compute corresponding name
					SCR_fn_v_RdL0_ComputeSectionName(hSuperObject->sName,  sFile, sAction, sIdent2);
				}

				// load a Child SuperObject
				if (strcmp(szAction,M_SPOActionAddChild)==0)
				{
					SCR_tdst_Cxt_Values *p_stVal;
        
					p_stVal = SCR_fnp_st_RdL0_AnalyseSection(szParams[0], SCR_CDF_uw_Anl_Normal);
					hNewSuperObject = (MLT_tdxHandleToSuperObject)SCR_M_ul_RdL0_ExtractLongValue(p_stVal,0);

					hSuperObject->d_hChild[hSuperObject->lNbChild] = hNewSuperObject;
					hSuperObject->lNbChild++;
				}

				// read the value from the flags in the .spo file 
				if (strcmp(szAction,M_SPOActionFlags)==0)
				{
					hSuperObject->ulSPOFlags=atoi(szParams[0]);
				}
				// read the value from the transparency in the .spo file 
				if (strcmp(szAction,M_SPOActionTransparency)==0)
				{
					hSuperObject->fTransparency=(float) atof(szParams[0]);
				}

				// read the Matrix
				if (strcmp(szAction,M_SPOActionPutMatrix)==0)
				{
					MLT_tdstMatrix *p_stMatrix;
					SCR_tdst_Cxt_Values *p_stVal;
        
					p_stVal = SCR_fnp_st_RdL0_AnalyseSection(szParams[0], SCR_CDF_uw_Anl_Normal);
					p_stMatrix = (MLT_tdstMatrix*)SCR_M_ul_RdL0_ExtractLongValue(p_stVal,0);

					hSuperObject->p_stMatrix = p_stMatrix;
				}

				// load the associated Geometric Object
				if (strcmp(szAction,M_SPOActionGeometric)==0)
				{
					sprintf(hSuperObject->sGeometric, "%s", szParams[0]);

					SCR_fn_v_RdL0_SplitSectionName(hSuperObject->sGeometric, sFile, sAction, sIdent);
					//remove the $flag$flag from its name
					p_Char1=sIdent;
					MLT_vRemoveFlags(&p_Char1);
					strcpy(sIdent, p_Char1);
					//remove the #geomprop#geomprop from its name
					p_Char1=sIdent;
					MLT_vRemoveGeomProp(&p_Char1);
					strcpy(sIdent, p_Char1);
					// compute result name
					SCR_fn_v_RdL0_ComputeSectionName(hSuperObject->sGeometric, sFile, sAction, sIdent);
					// check if object exists
					if((p_stObj=MLT_pFindInLib(hSuperObject->sGeometric)) == NULL)
					{
						MLT_vOutput( C_ComRes_cErrorLine, "\nError : Can't load %s", hSuperObject->sGeometric);
					}
					// then update the property flags of the object from its super-object
					else
					{
						p_stObj->iFlags =0;
						if (hSuperObject->iGeomProp & MAYBE_SYM)
						{	
							p_stObj->cGeom = hSuperObject->cGeom;
							p_stObj->fGeom = hSuperObject->fGeom;
							p_stObj->iFlags |= MAYBE_SYM;
						}
						if (hSuperObject->iGeomProp & MAYBE_ALTIMAP)
							p_stObj->iFlags |= MAYBE_ALTIMAP;
						if (hSuperObject->iGeomProp & IS_LOOKAT)
						{	p_stObj->iFlags |= IS_LOOKAT;
							strcpy(p_stObj->sConstraintAxis, hSuperObject->sConstraintAxis);
						}
						if (hSuperObject->iGeomProp & IS_SEMI_LA)
						{	p_stObj->iFlags |= IS_SEMI_LA;
							strcpy(p_stObj->sConstraintAxis, hSuperObject->sConstraintAxis);
						}
						if (hSuperObject->iGeomProp & MAYBE_SPH)
							p_stObj->iFlags |= MAYBE_SPH;
						// update the matrix of the obejct
						p_stObj->p_stMatrix = hSuperObject->p_stMatrix;
					}
				}

				// load the linked Object
				if (strcmp(szAction,M_SPOActionLinkedObject)==0)
				{ 
					sprintf(hSuperObject->sLinkedObject, "%s", szParams[0]);

					if((MLT_pFindInLib(hSuperObject->sLinkedObject) == NULL) && (strcmp(sFile, "temp.spo")))
					{
						MLT_vOutput( C_ComRes_cErrorLine, "\nError : Can't load %s", hSuperObject->sLinkedObject);
					}
				}
			}
			break;

		case SCR_EA_Anl_EndSection:
			break;
	}
	return  SCR_ERV_Anl_NormalReturn;
}

/****************************************************************************
*		Description:	load matrix section in SPO file
*
*		Parameters:		p_stFile	: script file pointer
*						szAction	: section or entry name
*						szParams	: parameters
*						cType		: action type
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
SCR_tde_Anl_ReturnValue MLT_xLoadMatrix(SCR_tdst_File_Description *p_fFile, char *szAction, char *szParams[], SCR_tde_Anl_Action cType)
{
	MTH3D_tdstVector	stI,stJ,stK;
    MLT_tdstSubMaps		*p_stSubMaps;
	MLT_tdstMatrix		*p_stMatrix;
	MTH_tdxReal			a_xVertex[9];
    xString				sFile, sAction, sIdent, sIdent2;
	long				i;

	switch (cType)
	{
		case SCR_EA_Anl_BeginSection:
			// allocate and init matrix to identity
			p_stMatrix=(MLT_tdstMatrix*)malloc(sizeof(MLT_tdstMatrix));
			MLT_xSetIdentityMatrix(p_stMatrix);
			SCR_fn_v_RdL0_SplitSectionName(SCR_M_RdL0_GetCompleteSectionNameR(0), sFile, sAction, sIdent);
			// check for submaps
			if (strstr(sFile, ".sub"))
			{	
				g_bSubFile=TRUE;
				SCR_M_RdL0_GetContextLong(-1,0,MLT_tdstSubMaps*,p_stSubMaps);
			}
			// if necessary add the "SPO_" prefix
			if( (strcmp(sIdent, M_Root) != 0) && (strstr(sIdent, M_SPO_) == NULL) )
				sprintf(sIdent2, "SPO_%s", sIdent);
			else
				sprintf(sIdent2, "%s", sIdent);
			SCR_fn_v_RdL0_ComputeSectionName(p_stMatrix->sName,  sFile, sAction, sIdent2);

			SCR_M_RdL0_SetSectionLong(0,0,(unsigned long)p_stMatrix);
			SCR_M_RdL0_SetContextLong(0,0,(unsigned long)p_stMatrix);
			break;
	
		case SCR_EA_Anl_Entry:
			// submap sections have their own function
			if (!g_bSubFile)
			{
				SCR_M_RdL0_GetContextLong(0,0,MLT_tdstMatrix*,p_stMatrix);

				// load the translation
				if (strcmp(szAction,M_MATActionTranslation)==0)
				{

					for (i=0;i<3;i++)
						a_xVertex[i]=(MTH_tdxReal)MTH_M_xFloatToReal(atof(szParams[i])*MLT_dGetUnitInMeterInFile(p_fFile->a_szOpenFileName));

					MLT_M_SetVertexXYZ(&stI,a_xVertex[0],a_xVertex[1],a_xVertex[2]);
					MLT_xSetTranslationMatrix(p_stMatrix,&stI);
				}
				// load the rotation
				if (strcmp(szAction,M_MATActionRotation)==0)
				{
					for (i=0;i<9;i++)
						a_xVertex[i]=(MTH_tdxReal)MTH_M_xFloatToReal(atof(szParams[i]));

					MLT_M_SetVertexXYZ(&stI,a_xVertex[0],a_xVertex[1],a_xVertex[2]);
					MLT_M_SetVertexXYZ(&stJ,a_xVertex[3],a_xVertex[4],a_xVertex[5]);
					MLT_M_SetVertexXYZ(&stK,a_xVertex[6],a_xVertex[7],a_xVertex[8]);
					MLT_xSetRotationMatrix(p_stMatrix,&stI,&stJ,&stK);
				}
				// load the scale
				if (strcmp(szAction,M_MATActionScale)==0)
				{
					for (i=0;i<9;i++)
						a_xVertex[i]=(MTH_tdxReal)MTH_M_xFloatToReal(atof(szParams[i]));

					MLT_M_SetVertexXYZ(&stI,a_xVertex[0],a_xVertex[1],a_xVertex[2]);
					MLT_M_SetVertexXYZ(&stJ,a_xVertex[3],a_xVertex[4],a_xVertex[5]);
					MLT_M_SetVertexXYZ(&stK,a_xVertex[6],a_xVertex[7],a_xVertex[8]);
					MLT_xSetScaleMatrix(p_stMatrix,&stI,&stJ,&stK);
				}
			}
			break;

		case SCR_EA_Anl_EndSection:
			break;
	}
	return  SCR_ERV_Anl_NormalReturn;
}



/****************************************************************************
*		Description:	read the SPOFlags file to init the flag values
*
*		Parameters:		sRawData	: source directory
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
void MLT_vReadSPOFlagsFile (xString sRawData)
{
  FILE		*fileR;
  xString	sDirectory, sRead, sDir, sIdent, sIniFile;
  char		szEditorFlags[10][15];
  char		*p_char, *p_Char1;
  int		i=0, j=0;

  //create a structure with the corresponding values and strings
  for (i=0; i<32; i++)
  {	  
	  strcpy(g_stSPOFlags[i].szFlag, "");
	  g_stSPOFlags[i].sFlag = -1;
  }

  // change directory
  GetCurrentDirectory(256, sDirectory);
  SetCurrentDirectory(g_sInitialDir);

  // open file, in main directory or in rawdata directory
  fileR = fopen("SuperObjectsFlags.txt", "rt");
  i=0;
  if (!fileR)
  { 
	if (g_bStandardConfig)
	{
	  strcpy(sDir, sRawData);
	  strcat(sDir, "\\World\\Levels");
	}
	else
	  strcpy(sDir, g_szLevels);

	 SetCurrentDirectory(sDir);
	 fileR = fopen("SuperObjectsFlags.txt", "rt");
	 if (!fileR)
	 {  
		SetCurrentDirectory(sDirectory);
		if (g_bStandardConfig)
			MLT_vOutput( C_ComRes_cErrorLine, "\nError : No file SuperObjectsFlags.txt in the RawData\\World\\Levels neither in the directory of the program ");
		else
			MLT_vOutput( C_ComRes_cErrorLine, "\nError : No file SuperObjectsFlags.txt in the Levels directory, neither in the directory of the program ");
		return;
	 }
  }

  // read the file
  while(fgets(sRead, 256, fileR) != NULL)
  {
     if( (p_char=strstr(sRead, "=")) != NULL)
     {
		// complete the structure with the names and the values taken from the .ini file
		sRead[strlen(sRead)-strlen(p_char)-1]='\0';
		strcpy(g_stSPOFlags[i].szFlag, sRead+1);
		g_stSPOFlags[i].sFlag = atoi(p_char+1);
		i++;
     }
  }
  fclose(fileR);

  // read the editor flags
  sprintf(sIniFile, "%s\\GIData.ini", g_sInitialDir);
  GetPrivateProfileString( "EditorFlags", "SuperObject", "", sIdent, MAX_PATH, sIniFile );
  j=0;
  if (strcmp(sIdent, "")) 
  {   
	  p_Char1=sIdent;
	  while( (*p_Char1 != ',') && (*p_Char1 != 0))
	  {	
		  i=0;
		  while( (*p_Char1 != ',') && (*p_Char1 != 0))
		  {	
			  szEditorFlags[j][i]=*p_Char1;
			  p_Char1++;
			  i++;
		  }
		  szEditorFlags[j][i] = '\0';
		  if (*p_Char1 != 0)
			  p_Char1++;
		  j++;
	  }
  }

  g_iNbEditorSPOFlags= j;

  // identify the editor flags 
  for (i=0; i<g_iNbEditorSPOFlags; i++)
	  g_iEditorSPOFlags[i] = MLT_iGetIndexSPOFlags(szEditorFlags[i]);


  // restore directory
  SetCurrentDirectory(sDirectory);
}


/****************************************************************************
*		Description:	compute the SPO flags and remove them from the given name 
*
*		Parameters:		p_ulSPOFlags	: returns the flags
*						p_fTransparency	: returns the transparency
*						sIdent			: name to check and update
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
void MLT_vSetSPOFlags (unsigned long *p_ulSPOFlags, float *p_fTransparency, xString *sIdent)
{
	char	*p_Char1, *p_Char2;
    char	szName[50], szFlags[5];
	int		i;

	// flags are identified with $
	if ((p_Char1=strstr(*sIdent, "$"))!=NULL) 
	{	
		p_Char2=p_Char1;
		// flags are separated by $ or _
		while ((*p_Char1 == '$') || (*p_Char1 == '_'))
		{ 
		  p_Char1++;
		  i=0;
	      // look for separation characters
		  while((*p_Char1 != 0)  && (*p_Char1 != '|')
			&& (*p_Char1 != '#') && (*p_Char1 != '&')
			&& (*p_Char1 != '=') && (*p_Char1 != '_') 
			&& (*p_Char1 != '$') && (*p_Char1 != '!'))
		  { 
			szFlags[i]=*p_Char1;
			p_Char1++;
			i++;
		  }
		  szFlags[i] = '\0';
		  // specific flag: transparency level
		  if (!strncmp(szFlags, C_szTransparencyFlag, C_iTransparencyLength))
			  *p_fTransparency = (float) atof(szFlags + C_iTransparencyLength);
		  //complete the flag for the object
		  else
			  *p_ulSPOFlags |=  1 << g_stSPOFlags[MLT_iGetIndexSPOFlags(szFlags)].sFlag;
		}
		//remove the $flag$flag from the name
		(*sIdent)[strlen(*sIdent)-strlen(p_Char2)]='\0';
		strcpy(szName, *sIdent);
		if (*p_Char1 != 0) 
			strcat(szName, p_Char1);
		strcpy(*sIdent, szName);
	  }
}

/****************************************************************************
*		Description:	get the index of the flag in the flag array
*
*		Parameters:		szFlag	: flag to search for
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
int MLT_iGetIndexSPOFlags (char *szFlag)
{
  int i;

  for (i=0; i<32; i++)
  {
	if (!strcmp(g_stSPOFlags[i].szFlag, szFlag))
		return i;
  }
  return -1;
}


/****************************************************************************
*		Description:	compute the geometric properties and remove them from the given name 
*
*		Parameters:		p_iGeomProp			: returns the geometric flags
*						sIdent				: name to check and update
*						p_cGeom				: returns the geometric properties
*						p_fGeom				: returns the geometric values
*						p_sConstraintAxis	: returns the constraint axis
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
void MLT_vGeomProp (int * p_iGeomProp, xString *sIdent, char *p_cGeom, double* p_fGeom, char * p_sConstraintAxis[4] )
{	
  char *p_Char1, *p_Char2;
  long i;
  char sValue[20];

  // ini parameters
  (*p_sConstraintAxis)[0] = '\0';

  // check for mirror
  if (((p_Char1=strstr(*sIdent, "#mir"))!=NULL) || 
	  ((p_Char1=strstr(*sIdent, "#MIR"))!=NULL)) 
  {
	//remove from name #mir
	p_Char1=*sIdent;
	MLT_vExtractPropFromName(&p_Char1, "#mir");
	strcpy(*sIdent, p_Char1);
	p_Char1=*sIdent;
	MLT_vExtractPropFromName(&p_Char1, "#MIR");
	strcpy(*sIdent, p_Char1);
  }

  // check for altimap
  if (((p_Char1=strstr(*sIdent, "#alt"))!=NULL) || 
	  ((p_Char1=strstr(*sIdent, "#ALT"))!=NULL)) 
  {	
	//remove from name #alt
	p_Char1=*sIdent;
	MLT_vExtractPropFromName(&p_Char1, "#alt");
	strcpy(*sIdent, p_Char1);
	p_Char1=*sIdent;
	MLT_vExtractPropFromName(&p_Char1, "#ALT");
	strcpy(*sIdent, p_Char1);
	*p_iGeomProp |= MAYBE_ALTIMAP;
  }
  
  // check for symmetry
  if (((p_Char1=strstr(*sIdent, "#Sym"))!=NULL) || 
	  ((p_Char1=strstr(*sIdent, "#SYM"))!=NULL) ||
	  ((p_Char1=strstr(*sIdent, "#sym"))!=NULL)) 
  {	
	// remove from name #sym
	if (((p_Char1=strstr(*sIdent, "#Sym"))!=NULL) || ((p_Char1=strstr(*sIdent, "#sym"))!=NULL)|| ((p_Char1=strstr(*sIdent, "#SYM"))!=NULL))
	{	
		p_Char2=p_Char1;
		p_Char1+=4;
		i=0;
		*p_cGeom = *p_Char1;
		//take the point
		while( (*p_Char1 != 0)   && (*p_Char1 != '|')
			&& (*p_Char1 != '$') && (*p_Char1 != '&')
			&& (*p_Char1 != '=') && (*p_Char1 != '_') 
			&& (*p_Char1 != '#') && (*p_Char1 != '!'))
		{	sValue[i]=(*sIdent)[strlen(*sIdent)-strlen(p_Char1)+1];
			p_Char1++; i++;
		}
		sValue[i]='\0';
		*p_fGeom=atof(sValue);
	}
	(*sIdent)[strlen(*sIdent)-strlen(p_Char2)]='\0';
	strcat(*sIdent, p_Char1);
	*p_iGeomProp |= MAYBE_SYM;
  }
  
  // check for lookat
  if (((p_Char1=strstr(*sIdent, "#la"))!=NULL) || 
	  ((p_Char1=strstr(*sIdent, "#LA"))!=NULL)) 
  {	
	//remove from name #la
	if (((p_Char1=strstr(*sIdent, "#la"))!=NULL) || ((p_Char1=strstr(*sIdent, "#LA"))!=NULL))
	{	
		p_Char2=p_Char1;
		p_Char1+=3;
		i=0;
		//take the ConstraintAxe
		while( (*p_Char1 != 0)   && (*p_Char1 != '|')
			&& (*p_Char1 != '$') && (*p_Char1 != '&')
			&& (*p_Char1 != '=') && (*p_Char1 != '_') 
			&& (*p_Char1 != '#') && (*p_Char1 != '!')
			&& (i<7))
		{	(*p_sConstraintAxis)[i]=(*p_Char1);
			p_Char1++; i++;
		}
		(*p_sConstraintAxis)[i] = '\0';
		(*sIdent)[strlen(*sIdent)-strlen(p_Char2)]='\0';
		strcat(*sIdent, p_Char1);

		*p_iGeomProp |= (i>0) ? IS_SEMI_LA : IS_LOOKAT;
	}
  }
  
  // check for sphere
  if (((p_Char1=strstr(*sIdent, "#sph"))!=NULL) || 
	  ((p_Char1=strstr(*sIdent, "#SPH"))!=NULL)) 
  {	
	//remove from name #sph
	p_Char1=*sIdent;
	MLT_vExtractPropFromName(&p_Char1, "#sph");
	strcpy(*sIdent, p_Char1);
	p_Char1=*sIdent;
	MLT_vExtractPropFromName(&p_Char1, "#SPH");
	strcpy(*sIdent, p_Char1);
	*p_iGeomProp |= MAYBE_SPH;
  }
}




/****************************************************************************
*		Description:	load the hierarchy from the SPO file
*
*		Parameters:		p_hRoot	: pointer on the root that must be loaded
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
void MLT_vLoadHierarchy (MLT_tdxHandleToSuperObject *p_hRoot)
{
  SCR_tdst_Cxt_Values	*p_stVal;
  xString				sSection, sFileSpo;
  xString				sDirectory;

  // save directory
  GetCurrentDirectory(256, sDirectory);

  sprintf(sFileSpo, "%s.spo", g_sFileIn);
  SCR_fn_v_RdL0_ComputeSectionName(sSection, sFileSpo, M_SuperObject, M_Root);

  p_stVal = SCR_fnp_st_RdL0_AnalyseSection(sSection, SCR_CDF_uw_Anl_Normal);
  *p_hRoot = (MLT_tdxHandleToSuperObject)SCR_M_ul_RdL0_ExtractLongValue(p_stVal,0);

  if (*p_hRoot == NULL)
  {
	MLT_vOutput( C_ComRes_cErrorLine, "\nError : Can't load hierarchy %s", sFileSpo);
    MLT_vExitSystem();
  }

  gs_bHierarchyAlreadyFree = FALSE;

  // restore directory
  SetCurrentDirectory(sDirectory); 
}


/****************************************************************************
*		Description:	check the hierarchy for the mirror objects (recursive function)
*
*		Parameters:		p_hRoot	: pointer on the hierarchy root 
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
void MLT_vCheckHierarchy (MLT_tdxHandleToSuperObject *p_hRoot)
{
	int						i, j, iNumberGeometric;
	char					szName[500];
	MLT_tdstGeometricObject *p_stGeometric, *p_stGeometricFather;

	if (!(*p_hRoot)) 
		return;

	if ((*p_hRoot)->iFlags & MAYBE_MIRROR)
	{
		// the object is a mirror
		if ((*p_hRoot)->lNbChild)
		{
			for (i=0; i<(*p_hRoot)->lNbChild; i++)
			{  
				// check each child
				strcpy(szName, (*p_hRoot)->d_hChild[i]->sGeometric);
				// check for the geometric object
				if ((p_stGeometric=MLT_pFindInLib(szName))!=NULL)
				{
					// the number of the vertexes in a mirror is 4
					if (p_stGeometric->xNbPoints==4)	
					{   
						// find object father
						p_stGeometricFather=MLT_pFindInLib((*p_hRoot)->sGeometric);
						if(p_stGeometricFather == NULL)
  						{
							MLT_vOutput( C_ComRes_cErrorLine, "\nError : Can't load %s", (*p_hRoot)->sGeometric);
							return;
						}
					    // update father with mirror object
						p_stGeometricFather->xNbPoints+=4;
						p_stGeometricFather->d_stListOfPoints=
							(MTH3D_tdstVector*)realloc(p_stGeometricFather->d_stListOfPoints,(p_stGeometricFather->xNbPoints)*sizeof(MTH3D_tdstVector));
						if (p_stGeometricFather->d_stListOfPoints==NULL)
							return;
						for (j=0; j<4; j++)
						{   p_stGeometricFather->d_stListOfPoints[p_stGeometricFather->xNbPoints-4+j].xX = p_stGeometric->d_stListOfPoints[j].xX;
							p_stGeometricFather->d_stListOfPoints[p_stGeometricFather->xNbPoints-4+j].xY = p_stGeometric->d_stListOfPoints[j].xY;
							p_stGeometricFather->d_stListOfPoints[p_stGeometricFather->xNbPoints-4+j].xZ = p_stGeometric->d_stListOfPoints[j].xZ;
						}
						p_stGeometricFather->d_stListOfPointsNormals=(MTH3D_tdstVector*)realloc(p_stGeometricFather->d_stListOfPointsNormals, p_stGeometricFather->xNbPoints*sizeof(MTH3D_tdstVector));
						if (p_stGeometricFather->d_stListOfPointsNormals==NULL)
							return;
						for (j=0; j<4; j++)
						{   p_stGeometricFather->d_stListOfPointsNormals[p_stGeometricFather->xNbPoints-4+j].xX = p_stGeometric->d_stListOfPointsNormals[j].xX;
							p_stGeometricFather->d_stListOfPointsNormals[p_stGeometricFather->xNbPoints-4+j].xY = p_stGeometric->d_stListOfPointsNormals[j].xY;
							p_stGeometricFather->d_stListOfPointsNormals[p_stGeometricFather->xNbPoints-4+j].xZ = p_stGeometric->d_stListOfPointsNormals[j].xZ;
						}
						p_stGeometricFather->d_stListOfPointsReceivedLightIntensity=(MLT_tdstColor*)realloc(p_stGeometricFather->d_stListOfPointsReceivedLightIntensity, p_stGeometricFather->xNbPoints*sizeof(MLT_tdstColor));
						if (p_stGeometricFather->d_stListOfPointsReceivedLightIntensity==NULL)
							return;
						for (j=0; j<4; j++)
						{   p_stGeometricFather->d_stListOfPointsReceivedLightIntensity[p_stGeometricFather->xNbPoints-4+j].xR = p_stGeometric->d_stListOfPointsReceivedLightIntensity[j].xR;
							p_stGeometricFather->d_stListOfPointsReceivedLightIntensity[p_stGeometricFather->xNbPoints-4+j].xG = p_stGeometric->d_stListOfPointsReceivedLightIntensity[j].xG;
							p_stGeometricFather->d_stListOfPointsReceivedLightIntensity[p_stGeometricFather->xNbPoints-4+j].xB = p_stGeometric->d_stListOfPointsReceivedLightIntensity[j].xB;
						}
						// remove miror object from the library
						iNumberGeometric=MLT_lGetNumberObjectInLib();
						iNumberGeometric--;
						MLT_vEraseObjInLib(p_stGeometric);
						// remove mirror object from the hierarchy
						strcpy((*p_hRoot)->d_hChild[i]->sGeometric, "");	
						MLT_vDeleteHierarchy((*p_hRoot)->d_hChild[i]); 
						// update root
						(*p_hRoot)->lNbChild=0; 
						(*p_hRoot)->iFlags |= IS_MIRROR;
						return;
					}
				}
			}
		}
	}

	// iteration on next level
	for (i=0; i<(*p_hRoot)->lNbChild; i++)
	{
		MLT_vCheckHierarchy(&(*p_hRoot)->d_hChild[i]);
	}

}

/****************************************************************************
*		Description:	delete the complete hierarchy (recursive function) 
*
*		Parameters:		hSprObj		: hierarchy root
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
void MLT_vDeleteHierarchy (MLT_tdxHandleToSuperObject hSprObj)
{
  long i;
  
  if(gs_bHierarchyAlreadyFree) return;
  if(hSprObj == NULL) return;
  
  free(hSprObj->p_stMatrix);

  for(i=0; i<hSprObj->lNbChild; i++)
  {
    MLT_vDeleteHierarchy(hSprObj->d_hChild[i]);
    hSprObj->d_hChild[i] = NULL;
  }
  hSprObj->lNbChild = 0;
  free(hSprObj);

  gs_bHierarchyAlreadyFree = TRUE;
}




/****************************************************************************
*		Description:	find object with the given name in the hierarchy (recursive function) 
*
*		Parameters:		sName		: name of object to search for
*						hSprObj		: hierarchy root
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
MLT_tdxHandleToSuperObject MLT_hFindInHierarchy (char *sName, MLT_tdxHandleToSuperObject hSprObj)
{
  long i;
  
  if (hSprObj == NULL) 
	  return NULL;

  // compare name
  if(strstr(hSprObj->sName, sName) != NULL) 
    return hSprObj;
  // search next level
  else
  {
    for(i=0; i<hSprObj->lNbChild; i++)
    {
      MLT_tdxHandleToSuperObject hTmp;

      hTmp = MLT_hFindInHierarchy(sName, hSprObj->d_hChild[i]);
      
      if (hTmp != NULL)
        return hTmp;
    }
    return NULL;
  }
}


/****************************************************************************
*		Description:	find sector with the given name in the hierarchy  
*
*		Parameters:		sName		: name of sector to search for
*						hSprObj		: hierarchy root
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
MLT_tdxHandleToSuperObject MLT_hFindInHierarchySector (char *sName, MLT_tdxHandleToSuperObject hSprObj)
{
  long i;

  char sLwrName[256], sLwrSprObjName[256];
  char sFile[256], sAction[256];

  strcpy(sLwrName, sName);
  
  if(hSprObj == NULL) 
	  return NULL;

  // compare with super object
  SCR_fn_v_RdL0_SplitSectionName(hSprObj->sName, sFile, sAction, sLwrSprObjName);
  if (stricmp(sLwrSprObjName, sLwrName) == 0) 
    return hSprObj;
  if (!strncmp(sLwrSprObjName, "SPO_", 4) && !stricmp(sLwrSprObjName+4, sLwrName))
	  return hSprObj;

  // compare with childs
  for(i=0; i<hSprObj->lNbChild; i++)
  {
	  SCR_fn_v_RdL0_SplitSectionName(hSprObj->d_hChild[i]->sName, sFile, sAction, sLwrSprObjName);
	  if (stricmp(sLwrSprObjName, sLwrName) == 0) 
		  return hSprObj->d_hChild[i];
	  if (!strncmp(sLwrSprObjName, "SPO_", 4) && !stricmp(sLwrSprObjName+4, sLwrName))
		  return hSprObj->d_hChild[i];
  }
  // not found
  return NULL;
}

/****************************************************************************
*		Description:	compare the name of a super-object with the section name of a sector
*
*		Parameters:		sName		: name of super-object
*						sSector		: section name of sector
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
BOOL MLT_bIsNotSameSector (char *sName, char *sSector)
{
	char sFile[256], sAction[256], sIdent[256];

	SCR_fn_v_RdL0_SplitSectionName(sSector, sFile, sAction, sIdent);
	return (stricmp(sName+4, sIdent) != 0); 
}



/****************************************************************************
*		Description:	get unit (in meter) for geometric objets
*
*		Parameters:		szGeometricFile		: name of the geometric file
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
double MLT_dGetUnitInMeterInFile (char *szGeometricFile)
{
  double ret;

  SCR_M_RdL0_GetFileDouble(0, 1, ret);

  return ret;
}






