/*=========================================================================
*
* Levels.c	- Level conversion
*
* Version			1.0
* Revision date
*
*=======================================================================*/
#include <Windows.h>

#include "Levels.h"

#include "SCR.h"			

#include "conventi.h"
#include "defines.h"
#include "main.h"
#include "print.h"
#include "system.h"
#include "util.h"

#include "ModLib.h"
#include "LgtLoad.h"
#include "PlgLoad.h"
#include "SpoLoad.h"
#include "IpoSave.h"
#include "ModSave.h"
#include "PhySave.h"
#include "RliSave.h"
#include "SctSave.h"		
#include "SpoSave.h"
#include "VseSave.h"
#include "ZooSave.h"

#include "Actors.h"
#include "Borders.h"
#include "Normals.h"
#include "Submaps.h"

#include "MatStack.h"
#include "Merge.h"		

#include "SaveModifLst.h"


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

MLT_tdxHandleToSuperObject	g_hRoot;
MLT_tdstMatrix				g_stMatrixCenter;
xString						g_sLevelFileIn;

BOOL						g_bLevel = FALSE;
// multitextures
BOOL g_bExistTex;


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

MTH3D_tdstVector			gs_stMinPointOfMap;
MTH3D_tdstVector			gs_stMaxPointOfMap;


//--- header functions --------------------------------------------------------

void MLT_vSaveEmptyLg2Header(SCR_tdst_File_Description *p_stFile, char *sFileName, void *p_vPtr, SCR_tde_Ntfy_Action xAction)
{
}
void MLT_vSaveEmptyLvlHeader(SCR_tdst_File_Description *p_stFile, char *sFileName, void *p_vPtr, SCR_tde_Ntfy_Action xAction)
{
}
void MLT_vSaveEmptyWayHeader(SCR_tdst_File_Description *p_stFile, char *sFileName, void *p_vPtr, SCR_tde_Ntfy_Action xAction)
{
}
void MLT_vSaveEmptyWpHeader(SCR_tdst_File_Description *p_stFile, char *sFileName, void *p_vPtr, SCR_tde_Ntfy_Action xAction)
{
}
void MLT_vSaveEmptyPgbHeader(SCR_tdst_File_Description *p_stFile, char *sFileName, void *p_vPtr, SCR_tde_Ntfy_Action xAction)
{
}
void MLT_vSaveEmptyDscHeader(SCR_tdst_File_Description *p_stFile, char *sFileName, void *p_vPtr, SCR_tde_Ntfy_Action xAction)
{
}
void MLT_vSaveEmptyAlwHeader(SCR_tdst_File_Description *p_stFile, char *sFileName, void *p_vPtr, SCR_tde_Ntfy_Action xAction)
{
}
void MLT_vSaveEmptyAiHeader(SCR_tdst_File_Description *p_stFile, char *sFileName, void *p_vPtr, SCR_tde_Ntfy_Action xAction)
{
}
void MLT_vSaveEmptyDecHeader(SCR_tdst_File_Description *p_stFile, char *sFileName, void *p_vPtr, SCR_tde_Ntfy_Action xAction)
{
}
void MLT_vSaveEmptyEdeHeader(SCR_tdst_File_Description *p_stFile, char *sFileName, void *p_vPtr, SCR_tde_Ntfy_Action xAction)
{
}
void MLT_vSaveEmptyEmaHeader(SCR_tdst_File_Description *p_stFile, char *sFileName, void *p_vPtr, SCR_tde_Ntfy_Action xAction)
{
}
void MLT_vSaveEmptyEmcHeader(SCR_tdst_File_Description *p_stFile, char *sFileName, void *p_vPtr, SCR_tde_Ntfy_Action xAction)
{
}
void MLT_vSaveEmptyErfHeader(SCR_tdst_File_Description *p_stFile, char *sFileName, void *p_vPtr, SCR_tde_Ntfy_Action xAction)
{
}
void MLT_vSaveEmptyEruHeader(SCR_tdst_File_Description *p_stFile, char *sFileName, void *p_vPtr, SCR_tde_Ntfy_Action xAction)
{
}
void MLT_vSaveEmptyEsbHeader(SCR_tdst_File_Description *p_stFile, char *sFileName, void *p_vPtr, SCR_tde_Ntfy_Action xAction)
{
}
void MLT_vSaveEmptyMacHeader(SCR_tdst_File_Description *p_stFile, char *sFileName, void *p_vPtr, SCR_tde_Ntfy_Action xAction)
{
}
void MLT_vSaveEmptyRfxHeader(SCR_tdst_File_Description *p_stFile, char *sFileName, void *p_vPtr, SCR_tde_Ntfy_Action xAction)
{
}
void MLT_vSaveEmptyRulHeader(SCR_tdst_File_Description *p_stFile, char *sFileName, void *p_vPtr, SCR_tde_Ntfy_Action xAction)
{
}

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


/****************************************************************************
*		Description:	compute all the levels found in the source directory
*
*		Parameters:		sRawData	: source directory
*						sGameData	: destination directory
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
void MLT_vComputeAllLevels (char *sRawData, char *sGameData)
{
  xString			sDirectory;
  HANDLE			hHandle;
  WIN32_FIND_DATA	stFindFileData;

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

  // search all the levels files
  memset(&stFindFileData,0,sizeof(stFindFileData));
  hHandle = FindFirstFile("World\\Levels\\*.*", &stFindFileData);
  if( hHandle == INVALID_HANDLE_VALUE)
  {
    SetCurrentDirectory(sDirectory);
    fprintf(stderr, "\nError : Can't find Levels directory\n");
    return;
  }
  
  do if(stFindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  {
    if(strlen(stFindFileData.cFileName) == 0) break;
    if(strcmp(stFindFileData.cFileName, ".") == 0) continue;
    if(strcmp(stFindFileData.cFileName, "..") == 0) continue;

    // compute the level
    MLT_vComputeOneLevel(stFindFileData.cFileName, sRawData, sGameData);
  }
  while(FindNextFile(hHandle, &stFindFileData));
  FindClose(hHandle);

  // restore directory
  SetCurrentDirectory(sDirectory);
}


/****************************************************************************
*		Description:	compute the specified level
*
*		Parameters:		sLevelName	: level to convert
*						sRawData	: source directory
*						sGameData	: destination directory
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
void MLT_vComputeOneLevel (char *sLevelName, char *sRawData, char *sGameData)
{
  char				*sTmp;
  BOOL				bIsOK = FALSE;
  xString			sFileSearch;
  HANDLE			hHandle;
  WIN32_FIND_DATA	stFindFileData;

// WIN version
#ifdef _WINDOWS

  char				szInterm[50];

  if(  ((sTmp=strstr(sLevelName, "\\")) == NULL)
    && ((sTmp=strstr(sLevelName, "/")) == NULL) )
  { 
	if (g_bStandardConfig)
	{
	  // get SPO name
	  sprintf(sFileSearch, "World\\Levels\\%s\\*.spo", sLevelName);
	  // change directory
      SetCurrentDirectory(sRawData);
	}
	else
	  sprintf(sFileSearch, "%s\\%s\\*.spo", g_szLevels, sLevelName);

	// search for the level file
	memset(&stFindFileData,0,sizeof(stFindFileData));
	hHandle = FindFirstFile(sFileSearch, &stFindFileData);
	if( hHandle == INVALID_HANDLE_VALUE)
	{
		sprintf(szInterm, "\nError : Can't find %s level\n", sLevelName);
    	fn_vAfxOutputStringRes( szInterm, C_ComRes_cErrorLine);
		return;
	}
	do
	{
		if(strlen(stFindFileData.cFileName) == 0) break;

		// compute the SPO file
		MLT_vComputeOneSpo(sLevelName, MLT_p_cGetFileNameWithoutExt(stFindFileData.cFileName), sRawData, sGameData);
		bIsOK = TRUE;
	}
	while(FindNextFile(hHandle, &stFindFileData));
	FindClose(hHandle);

	// if file was not found raise an error
	if (!bIsOK)
	{
		sprintf(szInterm, "\nError : Can't find %s\n", sFileSearch);
	    fn_vAfxOutputStringRes( szInterm, C_ComRes_cErrorLine);
		return;
	}
  }
  else
	MLT_vComputeOneSpo(sLevelName, sLevelName, sRawData, sGameData);

// DOS version
#else

  // get SPO name
  if(  ((sTmp=strstr(sLevelName, "\\")) == NULL)
    && ((sTmp=strstr(sLevelName, "/")) == NULL) )
    sprintf(sFileSearch, "World\\Levels\\%s\\*.spo", sLevelName);
  else
  {
    sprintf(sFileSearch, "World\\Levels\\%s", sLevelName);
    *sTmp = 0;
  }
  
  // change directory
  SetCurrentDirectory(sRawData);

  // search for the level file
  memset(&stFindFileData,0,sizeof(stFindFileData));
  hHandle = FindFirstFile(sFileSearch, &stFindFileData);
  if( hHandle == INVALID_HANDLE_VALUE)
  {
    fprintf(stderr, "\nError : Can't find %s level\n", sLevelName);
    return;
  }
  do
  {
    if(strlen(stFindFileData.cFileName) == 0) break;

	// compute the SPO file
    MLT_vComputeOneSpo(sLevelName, MLT_p_cGetFileNameWithoutExt(stFindFileData.cFileName), sRawData, sGameData);
    bIsOK = TRUE;
  }
  while(FindNextFile(hHandle, &stFindFileData));
  FindClose(hHandle);

  // if file was not found raise an error
  if(! bIsOK)
  {
    fprintf(stderr, "\nError : Can't find %s\n", sFileSearch);
    return;
  }
#endif
}

/****************************************************************************
*		Description:	compute the SPO file in the specified level
*
*		Parameters:		sLevelName	: level to convert
*						sFileSpo	: file to convert
*						sRawData	: source directory
*						sGameData	: destination directory
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
void MLT_vComputeOneSpo (char *sLevelName, char *sFileSpo, char *sRawData, char *sGameData)
{
  int							i, f;
  char							szFile[256], szLev[256];
  BOOL							bRLI = FALSE;
  FILE							*file;
  xString						sDirectory, sDir, sRawDir, sRead;
  xString						sRawLevel, sGameLevel, sFile, sFileM, sFile1;

  // init min and max point of the map
  MTH3D_M_vSetVectorElements(&gs_stMinPointOfMap, MLT_C_InfinitPlus, MLT_C_InfinitPlus, MLT_C_InfinitPlus);
  MTH3D_M_vSetVectorElements(&gs_stMaxPointOfMap, MLT_C_InfinitMinus, MLT_C_InfinitMinus, MLT_C_InfinitMinus);

  // register globals
  sprintf(g_sFileIn, "%s", sFileSpo);
  sprintf(g_sLevelFileIn, "%s", sFileSpo);
  sprintf(g_sFileMaterial, "%s", sLevelName);
  sprintf(g_sDirectorySave, "%s\\", sLevelName);

  // init directories
  if (g_bStandardConfig)
	sprintf(sRawLevel, "%s\\World\\Levels\\%s", sRawData, g_sDirectorySave);
  else
	sprintf(sRawLevel, "%s\\%s", g_szLevels, g_sDirectorySave);

  sprintf(sGameLevel, "%s\\World\\Levels\\%s", sGameData, g_sDirectorySave);

  // DISPLAY
  MLT_vOutput( C_ComRes_cTitleLine, "\nLevel %s\\%s.spo",sLevelName, sFileSpo);

  // change directory
  GetCurrentDirectory(256, sDirectory);
  CreateDirectory(sGameLevel, NULL);

  // DISPLAY
  MLT_vOutput( C_ComRes_cNormalLine, "\n\tCopy...");

  // change directory
  SetCurrentDirectory(sGameLevel); 

  // update or create level world 
  MLT_vUpdateLevelWorld(sGameLevel, sLevelName, sGameData);
  // notify and update all static files of the level
  MLT_vUpdateLevelStaticFiles(sGameLevel);
  // notify and update all dynamyc files of the level
  MLT_vUpdateLevelDynamicFiles(sGameLevel, sRawLevel, sLevelName);

  // DISPLAY
  MLT_vOutput( C_ComRes_cNormalLine, "\n\tLoad...");

  // change directory
  SetCurrentDirectory(sRawLevel); 

  // init loading parameters
  g_lNbSector = 0;
  MLT_xInitMatrixStack();

  // load MOD file
  MLT_vLoadModFileInLib();
  MLT_vEraseDuplicatedPoints();
  // load PLG file
  MLT_vLoadPLGFileInLib();
  // load SPO file
  MLT_vLoadHierarchy(&g_hRoot);

  // check hierarchy for submaps
  MLT_vCheckHierarchyForSubmaps(g_hRoot, sGameLevel, sRawLevel);

  // DISPLAY
  MLT_vOutput( C_ComRes_cNormalLine, "\n\tCompute normals...");

  // get the indexes of the faces for each geometric objects
  for (i=0; i<g_lGeometricIndex; i++)
	  MLT_vIndexFace(g_hGeometricInFile[i]);
  // compute the normals 
  MLT_xComputeAllNormals();

  // if necessary load the lights for RLI
  if (g_bGenerateRLI) 
  {	 
	  switch (g_iData)
	 {	
	  case 0:
				sprintf(sRawDir, "%s\\World\\Levels\\%s", g_sGameCommon, g_sFileIn);	  
				break;
		case 1:
				sprintf(sRawDir, "%s\\World\\Levels\\%s", g_sGameSpecific1, g_sFileIn);	  
				break;
		case 2:
				sprintf(sRawDir, "%s\\World\\Levels\\%s", g_sGameSpecific2, g_sFileIn);	  
				break;
	  }
	  GetCurrentDirectory(256, sDir);
	  SetCurrentDirectory(sRawDir);
	  MLT_LoadLGT();
	  SetCurrentDirectory(sDir);
  }

  // check hierarchy to manage mirror objects
  MLT_vCheckHierarchy(&g_hRoot);

  // force matrix to identity on first level
  if (g_bVersionN64)
  {
    MLT_vSearchAllSector(g_hRoot);
  }
  else
  {
    SCR_fn_v_RdL0_RegisterPath(sGameLevel);
    MLT_vOutput( C_ComRes_cNormalLine, "\n\tConvert Matrix...");
    MLT_vMatrixIdentityHierarchy(g_hRoot);
  }

  // DISPLAY
  MLT_vOutput( C_ComRes_cNormalLine, "\n\tConvert Sectors and Surfaces...");
  // build the sector structure
  MLT_vMakeSectorInHierarchy(g_hRoot);

  // check the maximal size of the map
  if ((gs_stMaxPointOfMap.xX - gs_stMinPointOfMap.xX >= 1024.0) ||
	  (gs_stMaxPointOfMap.xY - gs_stMinPointOfMap.xY >= 1024.0) ||
	  (gs_stMaxPointOfMap.xZ - gs_stMinPointOfMap.xZ >= 1024.0)) 
  {
    MLT_vOutput( C_ComRes_cErrorLine, "\n\n !!! Warning N64 : The map is too big for N64 (> 512m) !!!\n");
  }

  // save center of the map in SPO
  MLT_xSetIdentityMatrix(&g_stMatrixCenter);
  strcpy(g_stMatrixCenter.sName, M_MatrixCenter);
  g_stMatrixCenter.stTranslation.xX = (gs_stMaxPointOfMap.xX + gs_stMinPointOfMap.xX)/2;
  g_stMatrixCenter.stTranslation.xY = (gs_stMaxPointOfMap.xY + gs_stMinPointOfMap.xY)/2;
  g_stMatrixCenter.stTranslation.xZ = (gs_stMaxPointOfMap.xZ + gs_stMinPointOfMap.xZ)/2;


  // DISPLAY
  if (!g_bRaymanII)
	MLT_vOutput( C_ComRes_cNormalLine, "\n\tErase Borders...");
  // clean borders in hierarchy
  MLT_xInitMatrixStack();
  MLT_vEraseBorderInHierarchy(g_hRoot, "");

  // erase unused points
  MLT_vEraseUnusedPoints();
  
  // DISPLAY
  if (!g_bRaymanII)
	MLT_vOutput( C_ComRes_cNormalLine, "\n\tCreate Gothroughs...");
  // build borders in library
  MLT_vMakeGoThroughInLib(g_hRoot);

  // DISPLAY
  MLT_vOutput( C_ComRes_cNormalLine, "\n\tCreate Instantiated Physicals...");
  // merge all the splitted objects
  MLT_vMergeObjectsInHierarchy(g_hRoot);


  // compute RLIs
  if (g_bGenerateRLI) 
  {
	  //test if the LGT file exist
	  strcpy(szFile, sGameLevel);
	  strcat(szFile, "\\");
	  strcpy(szLev, g_sDirectorySave);
	  szLev[strlen(szLev)-1]='\0';
	  strcat(szFile, szLev);
	  strcat(szFile, ".lgt");
	  if (!(file=fopen(szFile, "r")))
		bRLI = FALSE;
	  else  
	  { 
	    fclose(file);
	    bRLI= TRUE;
	    //test if the SCT file exist
		strcpy(szFile, sGameLevel);
		strcat(szFile, "\\");
		strcpy(szLev, g_sDirectorySave);
		szLev[strlen(szLev)-1]='\0';
		strcat(szFile, szLev);
		strcat(szFile, ".sct");
		if (!(file=fopen(szFile, "r")))
			bRLI = FALSE;
		else  
		{ 
		  fclose(file);
		  bRLI = TRUE;
		}
	  }
	  if (bRLI) 
	  {
		MLT_vLoadLGTFileInLib();
		//compute the RLI
  		g_bLevel = TRUE;
		MLT_vCreateRLI();
		g_bLevel = FALSE;
	  }
  }


  
  // create IPOs 
  MLT_vMakeIpoInHierarchy(g_hRoot);

  // DISPLAY
  MLT_vOutput( C_ComRes_cNormalLine, "\n\tCreate Physicals...");
  // create POs 
  MLT_vMakePhysicalInLib();

  // change directory
  SetCurrentDirectory(sGameLevel); 

  // DISPLAY
  MLT_vOutput( C_ComRes_cNormalLine, "\n\tSave...");

  // save SPO file
  MLT_vSaveHierarchy(g_hRoot);
  // save MOD file
  MLT_vSaveLibInModFile(TRUE, FALSE, TRUE, TRUE);
  // save PLG file
  MLT_vSaveLibInPLGFile();

  // if necessary, remove modification files
  g_bExistMdf = FALSE;
  g_bExistMdt = FALSE;
  if (g_bEraseMdf)	
  {	
	  strcpy (sFile, sGameLevel);
	  sprintf(sFileM, "%s.mdf", sLevelName);
	  strcat(sFile, sFileM);
      _chmod(sFile, _S_IREAD | _S_IWRITE );
	  f=remove(sFile);		
	  if (f != -1) 
	    g_bExistMdf = TRUE;

	  strcpy (sFile, sGameLevel);
	  sprintf(sFileM, "%s.mdt", sLevelName);
	  strcat(sFile, sFileM);
      _chmod(sFile, _S_IREAD | _S_IWRITE );
	  f=remove(sFile);		
	  if (f != -1) 
	    g_bExistMdt = TRUE;
  }
    
  // save all notified sections
  SCR_fn_v_SvL1_UpdateAllNotify();

  // update SCT file
  sprintf(sFile, "%s.sct", g_sFileIn);
  MLT_vUpdateSctFile(sFile);
  // if necessary, update submap SCT file
  if (g_hRoot2)
  {
	  sprintf(sFile, "%s_Submap.sct", g_sFileIn);
	  MLT_vUpdateSctFile(sFile);
  }

  // clean MOD library
  MLT_vEraseLib();
  // clean PLG library
  MLT_vErasePLGLib();
  // clean ALW library
  MLT_vEraseALWLib();

  // clean LGT library
  if (bRLI && g_bGenerateRLI ) 
	  MLT_vEraseLGTLib();



  // clean SPO hierarchy
  MLT_vDeleteHierarchy(g_hRoot);

  // change directory
  SetCurrentDirectory(sDirectory); 
  // update ModifLst file
  MLT_vUpdatePathInModifFile(sGameLevel);

  // remove temporary files
  MLT_vRemoveLevelTemporaryFiles(sGameLevel);
  
  // DISPLAY
  MLT_vOutput( C_ComRes_cResultLine, "\nLevel %s converted\n",sLevelName);

  // clean all opened structures
  for (i=3; i<256; i++)
	_close((int)i);
  MLT_vInitSystem();

// multitextures
  if (g_bIgnoreTex && g_bExistTex)
  {
	  FILE *fileR;
	  
	  strcpy (sFile, sGameLevel);
	  sprintf(sFileM, "%s.tex", sLevelName);
	  strcat(sFile, sFileM);

	  strcpy (sFile1, sGameLevel);
	  strcat(sFile1, "temp.tex");

	  fileR=fopen(sFile1, "rt");
	  file =fopen(sFile, "r+");
	  if (!fileR) return;
	  if (!file) return;

	  while (!feof(fileR))
	  {
		fgets(sRead, 256, fileR);
		if (strstr(sRead, "Texture"))
		{	//a new section begins
			MLT_vSearch(sRead, file);
			fputs(sRead, file);
			fgets(sRead, 256, fileR);
			while (!strstr(sRead, "}"))
			{	fputs(sRead, file);
				fgets(sRead, 256, fileR);
			}
		}
	  }
	  fclose(file);
	  fclose(fileR);
	  remove(sFile1);
  }
}





/****************************************************************************
*		Description:	create or update the world character of the level
*
*		Parameters:		sGameLevel	: directory of the level
*						sLevelName	: level to convert
*						sGameData	: destination directory
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
void MLT_vUpdateLevelWorld (char *sGameLevel, char *sLevelName, char *sGameData)
{
  xString						sDirectory;
  xString						sDir, sName;
  xString						sGameLevelMy, sGameLevelMyChar;
  xString						sLevelDefaultDir, sDefaultCharDir;

  // change directory
  GetCurrentDirectory(256, sDirectory);

  // create or update the world associated to the level
  sprintf(sDir, "%s\\World\\Levels\\_Common\\Families\\World", sGameData);
  CreateDirectory(sDir, NULL);

  // create world level directory
  strcat(sDir, "\\Level");
  strcat(sDir, sLevelName);
  CreateDirectory(sDir, NULL);
  strcpy(sGameLevelMy, sDir);

  // create world character directory
  strcat(sDir,"\\Charact" );
  CreateDirectory(sDir, NULL);
  strcpy(sGameLevelMyChar, sDir);

  // change directory
  SetCurrentDirectory(sGameLevel); 

  // get default world files
  strcpy(sLevelDefaultDir, g_sGameCommon);
  strcat(sLevelDefaultDir, "\\default\\LevelDefault");
  strcpy(sDefaultCharDir, sLevelDefaultDir);
  strcat(sDefaultCharDir, "\\Charact");

  // update character file
  sprintf(sName, "world.car");
  MLT_vCopyAndUpdateFile("world.car", sDefaultCharDir, "world.car", sGameLevelMyChar, "<nomdulevel>", sLevelName, FALSE);

  // change directory
  SetCurrentDirectory(sGameLevel); 
  sprintf(sDir, "%s\\Default\\LevelDefault", sGameData);

  // update AI file
  sprintf(sName, "Level%s.ai", sLevelName);
  MLT_vCopyAndUpdateFile("LevelDefault.ai", sDir, sName, sGameLevelMy, "<nomdulevel>", sLevelName, FALSE);

  // update DEC file
  sprintf(sName, "Level%s.dec", sLevelName);
  MLT_vCopyAndRenameFile("LevelDefault.dec", sLevelDefaultDir, sName, sGameLevelMy, FALSE);

  // update EDE file
  sprintf(sName, "Level%s.ede", sLevelName);
  MLT_vCopyAndRenameFile("LevelDefault.ede", sLevelDefaultDir, sName, sGameLevelMy, FALSE);

  // update EMA file
  sprintf(sName, "Level%s.ema", sLevelName);
  MLT_vCopyAndUpdateFile("LevelDefault.ema", sLevelDefaultDir, sName, sGameLevelMy, "<nomdulevel>", sLevelName, FALSE);

  // update EMC file
  sprintf(sName, "Level%s.emc", sLevelName);
  MLT_vCopyAndRenameFile("LevelDefault.emc", sLevelDefaultDir, sName, sGameLevelMy, FALSE);

  // update ERF file
  sprintf(sName, "Level%s.erf", sLevelName);
  MLT_vCopyAndRenameFile("LevelDefault.erf", sLevelDefaultDir, sName, sGameLevelMy, FALSE);

  // update ERU file
  sprintf(sName, "Level%s.eru", sLevelName);
  MLT_vCopyAndRenameFile("LevelDefault.eru", sLevelDefaultDir, sName, sGameLevelMy, FALSE);

  // update ESB file
  sprintf(sName, "Level%s.esb", sLevelName);
  MLT_vCopyAndRenameFile("LevelDefault.esb", sLevelDefaultDir, sName, sGameLevelMy, FALSE);

  // update MAC file
  sprintf(sName, "Level%s.mac", sLevelName);
  MLT_vCopyAndRenameFile("LevelDefault.mac", sLevelDefaultDir, sName, sGameLevelMy, FALSE);

  // update RFX file
  sprintf(sName, "Level%s.rfx", sLevelName);
  MLT_vCopyAndRenameFile("LevelDefault.rfx", sLevelDefaultDir, sName, sGameLevelMy, FALSE);

  // update RUL file
  sprintf(sName, "Level%s.rul", sLevelName);
  MLT_vCopyAndUpdateFile("LevelDefault.rul", sLevelDefaultDir, sName, sGameLevelMy, "<nomdulevel>", sLevelName, FALSE);

  // restore directory
  SetCurrentDirectory(sDirectory);
}


/****************************************************************************
*		Description:	notify and update the static files of the level
*
*		Parameters:		sGameLevel	: directory of the level
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
void MLT_vUpdateLevelStaticFiles (char *sGameLevel)
{
  xString	sDirectory;
  xString	sFile;
  int		i;

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

  // check if the destination SPO file already exist
  strcpy(sFile, g_sFileIn);
  strcat(sFile, ".spo");
  if(! SCR_fn_c_RdL0_IsSectionExists(sFile))
	g_bCreatedSpo=FALSE;	
  else
	g_bCreatedSpo=TRUE;	
  // if necessary, save it as temporary file
  if (g_bCreatedSpo)	
	CopyFile(sFile, "temp.spo", FALSE);
  else
    remove(sFile);

  // Notify SPO file
  sprintf(sFile, "%s.spo", g_sFileIn);
  SCR_fn_v_SvL1_RegisterNotify(sFile, MLT_vSaveEmptySpoHeader, NULL, SCR_EA_Ntfy_AddOrModifySection);

  // Notify MOD file
  sprintf(sFile, "%s.mod", g_sFileIn);
  SCR_fn_v_SvL1_RegisterNotify(sFile, MLT_vSaveEmptyModHeader, NULL, SCR_EA_Ntfy_AddOrModifySection);

// multitextures
  // Notify TEX file
  sprintf(sFile, "%s.tex", g_sFileIn);
  if (! SCR_fn_c_RdL0_IsSectionExists(sFile))
  {
    SCR_fn_v_SvL1_RegisterNotify(sFile, MLT_vSaveTexFile, NULL, SCR_EA_Ntfy_AddOrModifySection);
	g_bExistTex = FALSE;
  }
  else
	g_bExistTex= TRUE;

  // Notify VMT file
  sprintf(sFile, "%s.vmt", g_sFileIn);
  if (! SCR_fn_c_RdL0_IsSectionExists(sFile))
    SCR_fn_v_SvL1_RegisterNotify(sFile, MLT_vSaveVmtFile, NULL, SCR_EA_Ntfy_AddOrModifySection);

  // Notify GMT file
  sprintf(sFile, "%s.gmt", g_sFileIn);
  if (! SCR_fn_c_RdL0_IsSectionExists(sFile))
  {  
	 SCR_fn_v_SvL1_RegisterNotify(sFile, MLT_vSaveGmtFile, NULL, SCR_EA_Ntfy_AddOrModifySection);
	 g_bCreatedGmt=FALSE;	
  }
  else
	g_bCreatedGmt=TRUE;	
  // if the .gmt file exist, check if it must be rebuilt 
  if (g_bCreatedGmt)
  { 
    //remove it is we want to ignore it
	if (g_bIgnoreGmt)	
	{   
		remove(sFile);
	    SCR_fn_v_SvL1_RegisterNotify(sFile, MLT_vSaveGmtFile, NULL, SCR_EA_Ntfy_AddOrModifySection);
	}
	// else save it as temporary file
	else
	{	
		CopyFile(sFile, "temp.gmt", FALSE);
		remove(sFile);
		SCR_fn_v_SvL1_RegisterNotify(sFile, MLT_vSaveGmtFile, NULL, SCR_EA_Ntfy_AddOrModifySection);
	}
  }
  
  // Notify IPO file
  sprintf(sFile, "%s.ipo", g_sFileIn);
  SCR_fn_v_SvL1_RegisterNotify(sFile, MLT_vSaveIpoFile, NULL, SCR_EA_Ntfy_AddSection);
  
  // Notify PHY file
  sprintf(sFile, "%s.phy", g_sFileIn);
  SCR_fn_v_SvL1_RegisterNotify(sFile, MLT_vSavePhyFile, NULL, SCR_EA_Ntfy_AddSection);
  
  // Notify VSE file
  sprintf(sFile, "%s.vse", g_sFileIn);
  SCR_fn_v_SvL1_RegisterNotify(sFile, MLT_vSaveVseFile, NULL, SCR_EA_Ntfy_AddSection);
  
  // Notify ZOO file
  sprintf(sFile, "%s.zoo", g_sFileIn);
  if (! SCR_fn_c_RdL0_IsSectionExists(sFile))
    SCR_fn_v_SvL1_RegisterNotify(sFile, MLT_vSaveZooFile, NULL, SCR_EA_Ntfy_AddSection);
  // if the ZOO file exists, check if it must be rebuilt
  else
  {	  
	  if (g_bIgnoreZoo)
	  {	
		i=remove(sFile);
		if (!i)
			SCR_fn_v_SvL1_RegisterNotify(sFile, MLT_vSaveZooFile, NULL, SCR_EA_Ntfy_AddSection);
	  }
	  else
	  {	 
		 xString sSection;
		 
		 CopyFile(sFile, "temp.zoo", FALSE);
		 SCR_fn_v_RdL0_ComputeSectionName(sSection, sFile, M_AllCollideSets, "");
		 SCR_fn_v_SvL1_RegisterNotify(sSection/*sFile*/, MLT_vSaveAllCollideSetsSection, NULL, SCR_EA_Ntfy_RebuildSection);
	  }
  }

  // save all notified sections
  SCR_fn_v_SvL1_UpdateAllNotify();

  // restore directory
  SetCurrentDirectory(sDirectory);
}  

/****************************************************************************
*		Description:	notify and update the dynamic files of the level
*
*		Parameters:		sGameLevel	: destination directory of the level
*						sRawLevel	: source directory of the level
*						sLevelName	: level to convert
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
void MLT_vUpdateLevelDynamicFiles (char *sGameLevel, char *sRawLevel, char *sLevelName)
{
  xString						sDirectory;
  xString						sDefaultDir, sGameDefault;
  xString						sFileMem, sGameLevelMem;
  xString						sName, sRoot;
  HANDLE						hHandle;
  WIN32_FIND_DATA				stFindFileData;
  SCR_tdst_Cxt_Values			*p_stVal;
  MLT_tdstInsertCharacter		*hInsert;

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

  // get level default directory
  strcpy(sDefaultDir, g_sGameCommon);
  strcat(sDefaultDir, "\\default");

  // compute the name of the level MEM file
  strcpy(sFileMem, g_sDirectorySave);
  sFileMem[strlen(sFileMem)-1]='\0';
  strcat(sFileMem, ".mem");
  strcpy(sGameLevelMem, sGameLevel);
  // compute the name of the default MEM file
  strcat(sGameLevelMem, sFileMem);
  strcpy(sGameDefault, g_sGameCommon);
  strcat(sGameDefault, "\\Default\\");
  // change directory
  SetCurrentDirectory(sGameDefault);
  // search for default MEM file
  memset(&stFindFileData,0,sizeof(stFindFileData));
  hHandle = FindFirstFile("Default.mem", &stFindFileData);
  if( hHandle == INVALID_HANDLE_VALUE)
  {
	MLT_vOutput( C_ComRes_cErrorLine, "\nError: No Default.mem file in the Default directory");
	FindClose(hHandle);
  }
  else
  {
      FindClose(hHandle);
	  CopyFile("Default.mem", sGameLevelMem, FALSE);
  }


  // ALW file
  sprintf(sName, "%s.alw", sLevelName);
  // if necessary, create ALW file
  if (! SCR_fn_c_RdL0_IsSectionExists(sName)) 
  {  
	 MLT_vCopyAndRenameFile("Default.alw", sDefaultDir, sName, sGameLevel, FALSE);
	 SCR_fn_v_SvL1_RegisterNotify(sName, MLT_vSaveEmptyAlwHeader, NULL, SCR_EA_Ntfy_AddSection);
  }
  // otherwise, load it
  else 
  {
	MLT_vLoadALWFileInLib();
	MLT_vSaveLibInALWFile();
  }

  // DSC file
  sprintf(sName, "%s.dsc", sLevelName);
  MLT_vCopyAndRenameFile("Default.dsc", sDefaultDir, sName, sGameLevel, FALSE);
  SCR_fn_v_SvL1_RegisterNotify(sName, MLT_vSaveEmptyDscHeader, NULL, SCR_EA_Ntfy_AddSection);
  
  // PGB file
  sprintf(sName, "%s.pgb", sLevelName);
  MLT_vCopyAndRenameFile("Default.pgb", sDefaultDir, sName, sGameLevel, FALSE);
  SCR_fn_v_SvL1_RegisterNotify(sName, MLT_vSaveEmptyPgbHeader, NULL, SCR_EA_Ntfy_AddSection);
  
  // WP file
  sprintf(sName, "%s.wp", sLevelName);
  MLT_vCopyAndRenameFile("Default.wp", sDefaultDir, sName, sGameLevel, FALSE);
  SCR_fn_v_SvL1_RegisterNotify(sName, MLT_vSaveEmptyWpHeader, NULL, SCR_EA_Ntfy_AddSection);
  
  // WAY file
  sprintf(sName, "%s.way", sLevelName);
  MLT_vCopyAndRenameFile("Default.way", sDefaultDir, sName, sGameLevel, FALSE);
  SCR_fn_v_SvL1_RegisterNotify(sName, MLT_vSaveEmptyWayHeader, NULL, SCR_EA_Ntfy_AddSection);
  
  // LVL file
  sprintf(sName, "%s.lvl", sLevelName);
  MLT_vCopyAndRenameFile("Default.lvl", sDefaultDir, sName, sGameLevel, FALSE);
  SCR_fn_v_SvL1_RegisterNotify(sName, MLT_vSaveEmptyLvlHeader, NULL, SCR_EA_Ntfy_AddSection);

  // LG2 file
  sprintf(sName, "%s.lg2", sLevelName);
  MLT_vCopyAndRenameFile(sName, sRawLevel, sName, sGameLevel, TRUE);
  SCR_fn_v_SvL1_RegisterNotify(sName, MLT_vSaveEmptyLg2Header, NULL, SCR_EA_Ntfy_AddSection);

  // DISPLAY
  MLT_vOutput( C_ComRes_cNormalLine, "\n\tDelete RLI...");

  // remove the RLI file
  SetCurrentDirectory(sGameLevel);
  sprintf(sName, "%s.rli", sLevelName);
  remove(sName);

  // if necessary, update world character in LVL file
  SetCurrentDirectory(sGameLevel);
  sprintf(sName, "%s.lvl", sLevelName);
  SCR_fn_v_RdL0_ComputeSectionName(sRoot, sName, "InsertCharacter", "W<nomdulevel>");
  // load module hierarchy
  if (SCR_fn_c_RdL0_IsSectionExists(sRoot))
  {	
	p_stVal = SCR_fnp_st_RdL0_AnalyseSection(sRoot, SCR_CDF_uw_Anl_Normal);
	hInsert = (MLT_tdstInsertCharacter *)SCR_M_ul_RdL0_ExtractLongValue(p_stVal,0);
    SCR_fn_v_SvL1_RegisterNotify(hInsert->sName, MLT_vSaveInsertCharacter, hInsert, SCR_EA_Ntfy_AddOrModifySection);
  }

  // restore directory
  SetCurrentDirectory(sDirectory);
}

/****************************************************************************
*		Description:	remove the temporary files created for the level
*
*		Parameters:		sGameLevel	: destination directory of the level
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
void MLT_vRemoveLevelTemporaryFiles	(char *sGameLevel)
{
  xString sDirectory, sFile;
  
  // if necessary, remove temporary SPO file
  if (g_bCreatedSpo)	
  {	
	GetCurrentDirectory(256, sDirectory);
	SetCurrentDirectory(sGameLevel);
	remove("temp.spo");
 	SetCurrentDirectory(sDirectory);
  }

  // if necessary, remove temporary GMT file
  if (g_bCreatedGmt && !g_bIgnoreGmt)	
  {	
	  SCR_fn_v_RdL0_Close();
	  strcpy (sFile, sGameLevel);
	  strcat(sFile, "temp.gmt");
      _chmod(sFile, _S_IREAD | _S_IWRITE );
	  remove(sFile);		
	  MLT_vInitSystem();
  }

  // remove temporary VSE file
  SCR_fn_v_RdL0_Close();
  strcpy(sFile, sGameLevel);
  strcat(sFile, "temp.vse");
  remove(sFile);			
  MLT_vInitSystem();

  // if necessary, remove temporary ZOO file
  if (!g_bIgnoreZoo)
  {	
	  SCR_fn_v_RdL0_Close();
	  strcpy (sFile, sGameLevel);
	  strcat(sFile, "temp.zoo");
	  remove(sFile);
	  MLT_vInitSystem();
  }

  // if necessary, remove temporary SUB file
  if (g_bSubmaps)
  {   
	  SCR_fn_v_RdL0_Close();
	  strcpy (sFile, sGameLevel);
	  strcat(sFile, "temp.sub");
	  remove(sFile);
	  MLT_vInitSystem();
  }

  // clean root1 for submaps
  if (g_hRoot1)
  {
	  free(g_hRoot1);
	  g_hRoot1 = NULL;
  }
  // clean root2 for submaps
  if (g_hRoot2)
  {
	  free(g_hRoot2);
	  g_hRoot2 = NULL;
	  g_iUnivSectors = 0;
  }
}



/****************************************************************************
*		Description:	search for all the sectors in first level of the hierarchy
*
*		Parameters:		hRoot		: root of the hierarchy
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
void MLT_vSearchAllSector(MLT_tdxHandleToSuperObject hRoot)
{
  xString	sFile, sAction, sIdent, sIdent2;
  long		i;

  // there must at least one sector
  if(hRoot->lNbChild == 0)
  {
	  MLT_vOutput( C_ComRes_cErrorLine, "\nError : No sector");
  }

  // cover the sectors (first level in the hierarchy)
  for(i=0; i<hRoot->lNbChild; i++)
  {
    SCR_fn_v_RdL0_SplitSectionName(hRoot->d_hChild[i]->sName, sFile, sAction, sIdent);
    sprintf(sIdent2, "%s", sIdent+strlen(M_SPO_)); 
    MLT_vAddSector(sIdent2); 
  }
}

/****************************************************************************
*		Description:	set the identity matrix for all the objects on the first level
*
*		Parameters:		hRoot		: root of the hierarchy
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
void MLT_vMatrixIdentityHierarchy(MLT_tdxHandleToSuperObject hRoot)
{
  xString	sName, sFile, sAction, sIdent, sIdent2;
  long		i;

  // there must at least one sector
  if(hRoot->lNbChild == 0)
  {
	MLT_vOutput( C_ComRes_cErrorLine, "\nError : No sector");
  }

  // cover the sectors (first floor in the hierarchy)
  for(i=0; i<hRoot->lNbChild; i++)
  {
    SCR_fn_v_RdL0_SplitSectionName(hRoot->d_hChild[i]->sName, sFile, sAction, sIdent);
    sprintf(sIdent2, "%s", sIdent+strlen(M_SPO_)); 
    MLT_vAddSector(sIdent2); 

    // update the matrix
	sprintf(sName, "%s", hRoot->d_hChild[i]->p_stMatrix->sName);
    MLT_xMulMatrixMatrix(hRoot->d_hChild[i]->p_stMatrix, hRoot->p_stMatrix, hRoot->d_hChild[i]->p_stMatrix);
    sprintf(hRoot->d_hChild[i]->p_stMatrix->sName, "%s", sName);

    // the sector's matrix must be no identity
    if(strstr(hRoot->d_hChild[i]->sName, M_Surface) == NULL)
    {
      MLT_vMatrixIdentitySector(hRoot->d_hChild[i]);
    }

  }

  MLT_xSetIdentityMatrix (hRoot->p_stMatrix);
}

/****************************************************************************
*		Description:	force the sector's matrix to be identity
*
*		Parameters:		hRoot		: sector super object
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
void MLT_vMatrixIdentitySector(MLT_tdxHandleToSuperObject hSprObj)
{
  xString sName;
  long i;

  // there must at least one child in the sector
  if(hSprObj->lNbChild == 0)
  {
	if (g_bRaymanII)
	  MLT_vOutput( C_ComRes_cErrorLine, "\nError : No object or bounding box in sector %s", hSprObj->sName);
	else
	  MLT_vOutput( C_ComRes_cErrorLine, "\nError : No object in sector %s", hSprObj->sName);
  }

  // cover the visibles borders (second floor in the hierarchy)
  for(i=0; i<hSprObj->lNbChild; i++)
  {
    // sector's matrix not identity
    sprintf(sName, "%s", hSprObj->d_hChild[i]->p_stMatrix->sName);
    MLT_xMulMatrixMatrix(hSprObj->d_hChild[i]->p_stMatrix, hSprObj->p_stMatrix, hSprObj->d_hChild[i]->p_stMatrix);
    sprintf(hSprObj->d_hChild[i]->p_stMatrix->sName, "%s", sName);

    // manage special objects
	if(strstr(hSprObj->d_hChild[i]->sName, M_Surface) == NULL) 
	{
	  if (strstr(hSprObj->d_hChild[i]->sName, "=") == NULL)
	    MLT_vMatrixIdentityFronteer(hSprObj->d_hChild[i]);
	}
  }

  MLT_xSetIdentityMatrix (hSprObj->p_stMatrix);
}

/****************************************************************************
*		Description:	force the border's matrix to be identity
*
*		Parameters:		hRoot		: fronteer super object
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
void MLT_vMatrixIdentityFronteer (MLT_tdxHandleToSuperObject hSprObj)
{
  MLT_tdstGeometricObject	*p_stObj;
  xString					sName;
  long						i;

  // cover the statics objets (third floor in the hierarchy)
  for(i=0; i<hSprObj->lNbChild; i++)
  {
    sprintf(sName, "%s", hSprObj->d_hChild[i]->p_stMatrix->sName);
    MLT_xMulMatrixMatrix(hSprObj->d_hChild[i]->p_stMatrix, hSprObj->p_stMatrix, hSprObj->d_hChild[i]->p_stMatrix);
    sprintf(hSprObj->d_hChild[i]->p_stMatrix->sName, "%s", sName);
  }

  // spread to the geometric object
  if(strlen(hSprObj->sGeometric) != 0)
  {
    p_stObj = MLT_pFindInLib(hSprObj->sGeometric);
    if(p_stObj == NULL)
    {
		MLT_vOutput( C_ComRes_cErrorLine, "\nError : Can't load %s", hSprObj->sGeometric);
    }
    else
    {
      // compute absolute vertex
      for(i=0; i<p_stObj->xNbPoints; i++)
      {
        MLT_xMulMatrixVertex(p_stObj->d_stListOfPoints+i, hSprObj->p_stMatrix, p_stObj->d_stListOfPoints+i);
      }
    }
  }
  // specific case : spo is a dummy grouping several elements
  else 
  {
	int j;
	// compute the minmax points for each element 
	for (j=0; j<hSprObj->lNbChild; j++)
	{
	  if (strstr(hSprObj->d_hChild[j]->sName, "&") != NULL)
	  {
		p_stObj = MLT_pFindInLib(hSprObj->d_hChild[j]->sGeometric);
		if(p_stObj == NULL)
		{
		   MLT_vOutput( C_ComRes_cErrorLine, "\nError : Can't load %s", hSprObj->d_hChild[j]->sGeometric);
		}
		else
		{
		   // compute absolute vertex
		   for(i=0; i<p_stObj->xNbPoints; i++)
		   {

			   MLT_xMulMatrixVertex(p_stObj->d_stListOfPoints+i, hSprObj->d_hChild[j]->p_stMatrix, p_stObj->d_stListOfPoints+i);
		   }
		}
	  }
	}
  }

  MLT_xSetIdentityMatrix (hSprObj->p_stMatrix);
}


/****************************************************************************
*		Description:	create the sectors in the hierarchy
*
*		Parameters:		hSprObj		: root super-object
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
void MLT_vMakeSectorInHierarchy(MLT_tdxHandleToSuperObject hSprObj)
{
  long		i, lNbChild;
  xString	sFile, sAction, sIdent;
  
  lNbChild = 0;
  
  // check all children
  for (i=0; i<hSprObj->lNbChild; i++ )
  {
    lNbChild++;

    // detect a bad border among the sector
    if (strstr(hSprObj->d_hChild[i]->sName, "frt") != NULL)
    {
	  MLT_vOutput( C_ComRes_cErrorLine, "\nError : No frontier among the sectors : %s", hSprObj->d_hChild[i]->sName);
      continue;
    }

	// init the flag for the sector telling if it has a new or old frontier
	hSprObj->d_hChild[i]->stSector.iFlag |= 0x00;	

    // create sector
    MLT_vCreateSector(hSprObj->d_hChild[i]);

    // if in a sector, we have both types of frontier generate a warning
	if ((hSprObj->d_hChild[i]->stSector.iFlag & IS_OLDFRONTIER) && (hSprObj->d_hChild[i]->stSector.iFlag & IS_NEWFRONTIER))
	{	
      SCR_fn_v_RdL0_SplitSectionName(hSprObj->d_hChild[i]->stSector.sName, sFile, sAction, sIdent);
	  MLT_vOutput( C_ComRes_cWarningLine, "\nWarning : New and old frontier for the %s sector", sIdent);
	}

    // compute the surfaces
    if (strstr(hSprObj->d_hChild[i]->sName, M_Surface) != NULL)
    {
      MLT_bAttachSurfaceToSector(hSprObj, hSprObj->d_hChild[i], g_sDirectorySave);

      // delete the surface from the hierarchy
      MLT_vDeleteHierarchy(hSprObj->d_hChild[i]);
      hSprObj->d_hChild[i] = NULL;
      lNbChild--;
    }
  }

  // for submaps : create Univers sectors
  for (i=0; i<g_iUnivSectors; i++)
  {
	  SCR_fn_v_RdL0_SplitSectionName(g_hRoot2->d_hChild[i]->sName, sFile, sAction, sIdent);
	  MLT_vCreateUniversSector(hSprObj, sIdent+7);
	  lNbChild++;
  }
  
  // insert Univers sector 
  MLT_vCreateUniversSector(hSprObj, "");
  lNbChild++;

  // update sub hierarchy
  for(i=0; i<lNbChild; i++)
  {
    MLT_tdxHandleToSuperObject	hTemp;
    int							j;
    
    j=i;
    while (hSprObj->d_hChild[j] == NULL) 
		j++;
    hTemp = hSprObj->d_hChild[j];
    hSprObj->d_hChild[j] = NULL;
    hSprObj->d_hChild[i] = hTemp;
  }
  hSprObj->lNbChild = lNbChild;
}

/****************************************************************************
*		Description:	create the sector structure
*
*		Parameters:		hSprObj		: sector super-object
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
void MLT_vCreateSector (MLT_tdxHandleToSuperObject hSprObj)
{
  MLT_tdxHandleToSuperObject	hChild;
  MLT_tdstGeometricObject		*p_stObj;
  MTH3D_tdstVector				stPointMin;
  MTH3D_tdstVector				stPointMax;
  xString						sAction, sIdent, sFile, sIdent2;
  xString						sName1, sIdent1;
  long							i, lNbChild;

  //set the initial values for the minimum and maximum of the bounding box
  MTH3D_M_vSetVectorElements(&stPointMin, MLT_C_InfinitPlus, MLT_C_InfinitPlus, MLT_C_InfinitPlus);
  MTH3D_M_vSetVectorElements(&stPointMax, MLT_C_InfinitMinus, MLT_C_InfinitMinus, MLT_C_InfinitMinus);

  // the super-object must not be a surface
  if (strstr(hSprObj->sName, M_Surface) == NULL)
  {
    // get super-object name
    SCR_fn_v_RdL0_SplitSectionName(hSprObj->sName, sFile, sAction, sIdent);
    // build corresponding sector name
	sprintf(sFile, "%s.sct", g_sFileIn);
    sprintf(sIdent2, "%s", sIdent+strlen(M_SPO_)); 
    SCR_fn_v_RdL0_ComputeSectionName(hSprObj->stSector.sName, sFile, M_Sector, sIdent2);
    // init sectr parameter
	hSprObj->stSector.lNbSurface = 0;
    
	// (Rayman2 version only)
	if (g_bRaymanII)
	{	
		//set the initial values for the min and max of the bounding box
		MTH3D_M_vSetVectorElements(&hSprObj->stSector.stPointMin, MLT_C_InfinitPlus, MLT_C_InfinitPlus, MLT_C_InfinitPlus);
		MTH3D_M_vSetVectorElements(&hSprObj->stSector.stPointMax, MLT_C_InfinitMinus, MLT_C_InfinitMinus, MLT_C_InfinitMinus);
	}

	// (TonicTrouble version only)
    else
	{
		// detect surfaces under the sector
		lNbChild = 0;
		SCR_fn_v_RdL0_SplitSectionName(hSprObj->stSector.sName, sFile, sAction, sIdent);
		for(i=0; i<hSprObj->lNbChild; i++ )
		{
		  lNbChild++;

		  // add the surface : the test is in the function
		  MLT_vAddSurfaceToSector(g_hRoot, hSprObj->d_hChild[i]->sName, sIdent, g_sDirectorySave);

		  //set the flag to tell if it is a new or old frontier
		  if(strstr(hSprObj->d_hChild[i]->sName, M_NewFronRever) != NULL)
			hSprObj->stSector.iFlag |= IS_NEWFRONTIER;
		  if(strstr(hSprObj->d_hChild[i]->sName, M_FronRever) != NULL)
			hSprObj->stSector.iFlag |= IS_OLDFRONTIER;

		  // delete the surface from the hierarchy
		  if(strstr(hSprObj->d_hChild[i]->sName, M_Surface) != NULL)
		  { 
			MLT_vDeleteHierarchy(hSprObj->d_hChild[i]);
			hSprObj->d_hChild[i] = NULL;
			lNbChild--;
		  }
		}

		// reorganization of the sub hierarchy
		for (i=0; i<lNbChild; i++)
		{
		  MLT_tdxHandleToSuperObject	hTemp;
		  long							j;
    
		  j=i;
		  while (hSprObj->d_hChild[j] == NULL) 
			  j++;
		  hTemp = hSprObj->d_hChild[j];
		  hSprObj->d_hChild[j] = NULL;
		  hSprObj->d_hChild[i] = hTemp;
		}
		hSprObj->lNbChild = lNbChild;
	  }
  }
  else
  {
	  sprintf(hSprObj->stSector.sName, "");
  }

  // (Rayman2 version only)
  if (g_bRaymanII)
  { 
	  //for all the children of the sector
	  for(i=0; i<hSprObj->lNbChild; i++ )
	  {
		  hChild = hSprObj->d_hChild[i];
	  
		  // if there is a bouding box, use it
		  if (strstr(hChild->sName, M_BoundingBox) != NULL)
		  {
			  p_stObj = MLT_pFindInLib(hChild->sGeometric);
			  if(p_stObj == NULL)
				  MLT_vOutput( C_ComRes_cErrorLine, "\nError : Can't load %s", hChild->sGeometric);
			  else
				  MLT_vComputeMinMaxPointOfBorder (p_stObj, &hSprObj->stSector.stPointMin, &hSprObj->stSector.stPointMax);
		  }

		  // use geometric children to compute the real bouding box
		  else
		  {
			  // instance
			  if (strstr(hChild->sName, "=") != NULL)
			  {
				// save name
				strcpy(sName1, hChild->sName);
				// create dummy name
				SCR_fn_v_RdL0_SplitSectionName(sName1, sFile, sAction, sIdent);
				strcpy(sIdent1, "SPO_dum_");
				if (!strstr(sIdent, "SPO_"))
					strcat(sIdent1, sIdent);
				else
					strcat(sIdent1, sIdent+4);
				SCR_fn_v_RdL0_ComputeSectionName(hChild->sName, sFile, sAction, sIdent1);
				// create new child and copy instance
				hChild->d_hChild[0] = (MLT_tdxHandleToSuperObject)malloc(sizeof(MLT_tdstSprObj));
				strcpy(hChild->d_hChild[0]->sName, sName1);
				strcpy(hChild->d_hChild[0]->sGeometric, hChild->sGeometric);
				strcpy(hChild->d_hChild[0]->sLinkedObject, hChild->sLinkedObject);
				hChild->d_hChild[0]->fTransparency = hChild->fTransparency;
				hChild->d_hChild[0]->p_stMatrix	= hChild->p_stMatrix;
				hChild->d_hChild[0]->ulSPOFlags	= hChild->ulSPOFlags;
				hChild->d_hChild[0]->stSector	= hChild->stSector;
				hChild->d_hChild[0]->lNbChild	= 0;
				hChild->d_hChild[0]->iFlags		= hChild->iFlags;
				// update dummy
				hChild->lNbChild=1;
				strcpy(hChild->sGeometric, "");
				hChild->p_stMatrix = (MLT_tdstMatrix*)malloc(sizeof(MLT_tdstMatrix));
				MLT_xSetIdentityMatrix(hChild->p_stMatrix);
				SCR_fn_v_RdL0_SplitSectionName(hChild->sName, sFile, sAction, sIdent);
				SCR_fn_v_RdL0_ComputeSectionName(hChild->p_stMatrix->sName,  sFile, M_Matrix, sIdent);
				// compute minmax from the instance
				p_stObj = MLT_pFindInLib(hChild->d_hChild[0]->sGeometric);
				if(p_stObj == NULL)
					MLT_vOutput( C_ComRes_cErrorLine, "\nError : Can't load %s", hChild->d_hChild[0]->sGeometric);
				else
					MLT_vComputeMinMaxPointWithMatrix (p_stObj, &stPointMin, &stPointMax, hChild->d_hChild[0]->p_stMatrix);
			  }

			  // dummy grouping some elements
			  else if (strlen(hChild->sGeometric) == 0) 
			  {
				int j;
				// compute the minmax points for each element 
				for (j=0; j<hChild->lNbChild; j++)
				{
				  if (strstr(hChild->d_hChild[j]->sName, "&") != NULL)
				  {
					  p_stObj = MLT_pFindInLib(hChild->d_hChild[j]->sGeometric);
					  if(p_stObj == NULL)
						  MLT_vOutput( C_ComRes_cErrorLine, "\nError : Can't load %s", hChild->d_hChild[j]->sGeometric);
					  else
						  MLT_vComputeMinMaxPointOfBorder (p_stObj, &stPointMin, &stPointMax);
				  }
				}
			  }
			  
			  // normal case : child is a geometric one
			  else
			  {
				p_stObj = MLT_pFindInLib(hChild->sGeometric);
				if(p_stObj == NULL)
					MLT_vOutput( C_ComRes_cErrorLine, "\nError : Can't load %s", hChild->sGeometric);
				else
					MLT_vComputeMinMaxPointOfBorder (p_stObj, &stPointMin, &stPointMax);
			  }
		  }
	  }

	// set the final values of the bounding box : max size of frtb and graphic children
 	if (hSprObj->stSector.stPointMin.xX == MLT_C_InfinitPlus)
		MTH3D_M_vSetXofVector(&hSprObj->stSector.stPointMin, stPointMin.xX);
	if (hSprObj->stSector.stPointMin.xY == MLT_C_InfinitPlus)
		MTH3D_M_vSetYofVector(&hSprObj->stSector.stPointMin, stPointMin.xY);
	if (hSprObj->stSector.stPointMin.xZ == MLT_C_InfinitPlus)
		MTH3D_M_vSetZofVector(&hSprObj->stSector.stPointMin, stPointMin.xZ);

	if (hSprObj->stSector.stPointMax.xX == MLT_C_InfinitMinus)
		MTH3D_M_vSetXofVector(&hSprObj->stSector.stPointMax, stPointMax.xX);
	if (hSprObj->stSector.stPointMax.xY == MLT_C_InfinitMinus)
		MTH3D_M_vSetYofVector(&hSprObj->stSector.stPointMax, stPointMax.xY);
	if (hSprObj->stSector.stPointMax.xZ == MLT_C_InfinitMinus)
		MTH3D_M_vSetZofVector(&hSprObj->stSector.stPointMax, stPointMax.xZ);

	// check min and max points for the map
 	if (gs_stMinPointOfMap.xX > stPointMin.xX)
		MTH3D_M_vSetXofVector(&gs_stMinPointOfMap, stPointMin.xX);
	if (gs_stMinPointOfMap.xY > stPointMin.xY)
		MTH3D_M_vSetYofVector(&gs_stMinPointOfMap, stPointMin.xY);
	if (gs_stMinPointOfMap.xZ > stPointMin.xZ)
		MTH3D_M_vSetZofVector(&gs_stMinPointOfMap, stPointMin.xZ);

	if (gs_stMaxPointOfMap.xX < stPointMax.xX)
		MTH3D_M_vSetXofVector(&gs_stMaxPointOfMap, stPointMax.xX);
	if (gs_stMaxPointOfMap.xY < stPointMax.xY)
		MTH3D_M_vSetYofVector(&gs_stMaxPointOfMap, stPointMax.xY);
	if (gs_stMaxPointOfMap.xZ < stPointMax.xZ)
		MTH3D_M_vSetZofVector(&gs_stMaxPointOfMap, stPointMax.xZ);
  }
}



/****************************************************************************
*		Description:	create the Univers sector, for global or for submap
*
*		Parameters:		hSprObj		: root super-object
*						sSubmapName	: name of submap, or empty string for global
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
void MLT_vCreateUniversSector (MLT_tdxHandleToSuperObject hSprObj, xString sSubmapName)
{
  xString sFile, sSuperObject, sSector;

  // build the name of the sector accroding to its status (submap or global)
  if (strcmp(sSubmapName, ""))
  {
	  sprintf(sSuperObject, "%s_%s", M_SPO_Univers, sSubmapName);
	  sprintf(sSector, "%s_%s", M_Univers, sSubmapName);
  }
  else
  {
	  strcpy(sSuperObject, M_SPO_Univers);
	  strcpy(sSector, M_Univers);
  }


  // allocate Univers super-object as last child of the root
  hSprObj->d_hChild[hSprObj->lNbChild] = (MLT_tdxHandleToSuperObject)calloc(1, sizeof(MLT_tdstSprObj));
  // compute corresponding section name
  sprintf(sFile, "%s.spo", g_sFileIn);
  SCR_fn_v_RdL0_ComputeSectionName(hSprObj->d_hChild[hSprObj->lNbChild]->sName, sFile, M_SuperObject, sSuperObject);

  // allocate Univers matrix (default value : identity)
  hSprObj->d_hChild[hSprObj->lNbChild]->p_stMatrix = (MLT_tdstMatrix*)calloc(1, sizeof(MLT_tdstMatrix));
  MLT_xSetIdentityMatrix(hSprObj->d_hChild[hSprObj->lNbChild]->p_stMatrix);
  // compute corresponding section name
  sprintf(sFile, "%s.spo", g_sFileIn);
  SCR_fn_v_RdL0_ComputeSectionName(hSprObj->d_hChild[hSprObj->lNbChild]->p_stMatrix->sName, sFile, M_Matrix, sSuperObject);

  // init Univers sector
  hSprObj->d_hChild[hSprObj->lNbChild]->stSector.lNbSurface = 0;
  // compute corresponding section name
  sprintf(sFile, "%s.sct", g_sFileIn);
  SCR_fn_v_RdL0_ComputeSectionName(hSprObj->d_hChild[hSprObj->lNbChild]->stSector.sName, sFile, M_Sector, sSector);

  // update the number of children
  hSprObj->lNbChild++;
}



/****************************************************************************
*		Description:	Insert an Ipo between SuperObject and Geometric
*
*		Parameters:		hSprObj		: root of the hierarchy
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
void MLT_vMakeIpoInHierarchy (MLT_tdxHandleToSuperObject hSprObj)
{
  long i;

  // check if super-object encapsulate a geometric object
  if (strlen(hSprObj->sGeometric) != 0)
  {
    xString sFile, sAction, sIdent, sForme, sHabillage, sSection, sName;
    long	lNoPhy, lNoLod;

    // get minimal geometric name
	SCR_fn_v_RdL0_SplitSectionName(hSprObj->sGeometric, sFile, sAction, sIdent);
    MLT_vSplitModuleSectionName(sIdent, sForme, sHabillage, &lNoPhy, &lNoLod, sName);
	// compute corresponding PO name
    MLT_vComputePhysicalSectionName(sSection, sForme, sHabillage, lNoPhy, sName);
    // compute corresponding IPO section name
	sprintf(sFile, "%s.ipo", g_sFileIn);
    SCR_fn_v_RdL0_ComputeSectionName(hSprObj->sLinkedObject, sFile, M_Ipo, sSection);
	// remove the geometric entry
    sprintf(hSprObj->sGeometric, "");
  }
  
  // iteration on next level
  for (i=0; i<hSprObj->lNbChild; i++)
  {
    MLT_vMakeIpoInHierarchy(hSprObj->d_hChild[i]);
  }
}

/****************************************************************************
*		Description:	compute the name of Physical from the name of Geometric
*
*		Parameters:		
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
void MLT_vMakePhysicalInLib ()
{
  MLT_tdstGeometricObject	*p_stObj;
  xString					sFile, sAction, sIdent, sForme ,sHabillage, sName;
  long						i, lNbObjInLib, lNoPhy, lNoLod;

  // search the library
  lNbObjInLib = MLT_lGetNumberObjectInLib();
  for(i=0; i<lNbObjInLib; i++)
  {
    p_stObj = MLT_lGetObjectFromLib(i);
	if (!p_stObj)
		continue; 

    // No Physical for the borders
    if(strstr(p_stObj->sName, M_NameGothrough) != NULL)
    {
	  sprintf(p_stObj->sComment, "");
      sprintf(p_stObj->sPhysicalSection, "");
      continue;
    }

    // No Physical for the surfaces
    if(strstr(p_stObj->sName, M_Surface) != NULL)
    {
      sprintf(p_stObj->sPhysicalSection, "");
      continue;
    }

    // get minimal geometric name
	SCR_fn_v_RdL0_SplitSectionName(p_stObj->sName, sFile, sAction, sIdent);
    MLT_vSplitModuleSectionName(sIdent, sForme, sHabillage, &lNoPhy, &lNoLod, sName);

    // compute corresponding physical name
	MLT_vComputePhysicalSectionName(sIdent, sForme, sHabillage, lNoPhy, "");
    // compute corresponding section name
	sprintf(sFile, "%s.phy", g_sFileIn);
    SCR_fn_v_RdL0_ComputeSectionName(p_stObj->sPhysicalSection, sFile, M_Phy, sIdent);
    // register index in library
	p_stObj->lNumberInTable = i;
  }
}



/****************************************************************************
*		Description:	Detect and erase the unused points in all geometric objects of the hierarchy
*
*		Parameters:		
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
void MLT_vEraseUnusedPoints ()
{
	MLT_tdstElementIndexedTriangles		*p_stLocalElement;
	MLT_tdstElementFaceMapDescriptors	*p_stLocalElementFMD;
	xString								sFile, sAction, sIdent;
	BOOL								bIsSprite;
	char								buf[5];
	int									xIndex, iIndexM=0; 
	int									i, j, m, n, k; 

	// check all the geometric objects 
	for (i=0; i<g_lGeometricIndex; i++) 
	{	
		// the object still exist in the hierarchy
		if (g_hGeometricInFile[i])	
		{ 
		  MTH3D_tdstVector	 *p_stListOfPoints;
  		  MTH3D_tdstVector	 *p_stListOfPointsNormals;
  		  MLT_tdstColor		 *p_stListOfColors;
		  int				 *p_iIndex; 
		  
		  bIsSprite = FALSE;
		  n=0;

		  // check if the unused points must be deleted
		  if (g_bEraseUnused) 
		  {
			p_stListOfPoints = (MTH3D_tdstVector *) malloc(g_hGeometricInFile[i]->xNbPoints*sizeof(MTH3D_tdstVector));
			p_stListOfPointsNormals = (MTH3D_tdstVector *) malloc(g_hGeometricInFile[i]->xNbPoints*sizeof(MTH3D_tdstVector));
			p_stListOfColors = (MLT_tdstColor *) malloc(g_hGeometricInFile[i]->xNbPoints*sizeof(MLT_tdstColor));
			p_iIndex=(int *)malloc(sizeof(int) * g_hGeometricInFile[i]->xNbPoints);
		  }

		  for (m=0; m<g_hGeometricInFile[i]->xNbPoints; m++)
		  {  
			 iIndexM = 0;
			 for (xIndex=0; xIndex<g_hGeometricInFile[i]->xNbElements; xIndex++)
			 {
			  if ( g_hGeometricInFile[i]->d_xListOfElementsTypes[xIndex] == MLT_C_xElementIndexedTriangles )
			  {  
				 p_stLocalElement = ((MLT_tdstElementIndexedTriangles *)g_hGeometricInFile[i]->d_stListOfElements[xIndex]);
				 for (j=0; j<p_stLocalElement->xNbFaces; j++) //for all faces
				 {   
					 if ((m == p_stLocalElement->d_stListOfFacesTripled[j].a3_xIndex[0])
						||(m == p_stLocalElement->d_stListOfFacesTripled[j].a3_xIndex[1])
						||(m == p_stLocalElement->d_stListOfFacesTripled[j].a3_xIndex[2]))
						iIndexM++;
				 }
			   }
			   else if (g_hGeometricInFile[i]->d_xListOfElementsTypes[xIndex] == MLT_C_xElementFaceMapDescriptors)
			   { 
				 p_stLocalElementFMD = ((MLT_tdstElementFaceMapDescriptors *)g_hGeometricInFile[i]->d_stListOfElements[xIndex]);
				 for (j=0; j<p_stLocalElementFMD->xNbFaces; j++)
				 {   
					 if ((m == p_stLocalElementFMD->d_stListOfFacesQuadrupled[j].stFaceTripled.a3_xIndex[0])
						||(m == p_stLocalElementFMD->d_stListOfFacesQuadrupled[j].stFaceTripled.a3_xIndex[1])
						||(m == p_stLocalElementFMD->d_stListOfFacesQuadrupled[j].stFaceTripled.a3_xIndex[2]))
						iIndexM++;
				 }
			   }
			   else if (g_hGeometricInFile[i]->d_xListOfElementsTypes[xIndex] == MLT_C_xElementSprites)
				   bIsSprite = TRUE;
			}
			
			// the point m is  not used in any face
		    if (!iIndexM && !bIsSprite) 
			{	
				if (g_bEraseUnused)
				{	
					MLT_vOutput( C_ComRes_cWarningLine, "\n\tFrom the object ");
					//MLT_vOutput( C_ComRes_cWarningLine, g_hGeometricInFile[i]->sName);
					SCR_fn_v_RdL0_SplitSectionName(g_hGeometricInFile[i]->sName, sFile, sAction, sIdent);
					MLT_vOutput( C_ComRes_cErrorLine, sIdent);
					MLT_vOutput( C_ComRes_cWarningLine, " was deleted the unused point n°");
					sprintf(buf, "%d", m);
					MLT_vOutput( C_ComRes_cErrorLine, buf);
					p_iIndex[m] = -1;	//the point is not anymore
				}
				else
				{	
					MLT_vOutput( C_ComRes_cErrorLine, "\n\tIn the object ");
					//MLT_vOutput( C_ComRes_cErrorLine, g_hGeometricInFile[i]->sName);
					SCR_fn_v_RdL0_SplitSectionName(g_hGeometricInFile[i]->sName, sFile, sAction, sIdent);
					MLT_vOutput( C_ComRes_cWarningLine, sIdent);
					MLT_vOutput( C_ComRes_cErrorLine, " the point n°");
					sprintf(buf, "%d", m);
					MLT_vOutput( C_ComRes_cWarningLine, buf);
					MLT_vOutput( C_ComRes_cErrorLine, " is not used.");
				}
			}
		    //the points is still used, so completye the new structure
			else
			{	
				if (g_bEraseUnused)
				{
					MTH3D_M_vSetVectorElements(&p_stListOfPoints[n],  
						g_hGeometricInFile[i]->d_stListOfPoints[m].xX,
						g_hGeometricInFile[i]->d_stListOfPoints[m].xY,
						g_hGeometricInFile[i]->d_stListOfPoints[m].xZ);
					MTH3D_M_vSetVectorElements(&p_stListOfPointsNormals[n],  
						g_hGeometricInFile[i]->d_stListOfPointsNormals[m].xX,
						g_hGeometricInFile[i]->d_stListOfPointsNormals[m].xY,
						g_hGeometricInFile[i]->d_stListOfPointsNormals[m].xZ);
					p_stListOfColors[n].xR = g_hGeometricInFile[i]->d_stListOfPointsReceivedLightIntensity[m].xR;
					p_stListOfColors[n].xG = g_hGeometricInFile[i]->d_stListOfPointsReceivedLightIntensity[m].xG;
					p_stListOfColors[n].xB = g_hGeometricInFile[i]->d_stListOfPointsReceivedLightIntensity[m].xB;
					p_iIndex[m] = n;
					n++;
				}
			}
		}
		if (g_bEraseUnused) 
		{	
			g_hGeometricInFile[i]->xNbPoints = n;
			for (m=0; m<n; m++)
			{	
				MTH3D_M_vSetVectorElements(&g_hGeometricInFile[i]->d_stListOfPoints[m],  
					p_stListOfPoints[m].xX,
					p_stListOfPoints[m].xY,
					p_stListOfPoints[m].xZ);
				MTH3D_M_vSetVectorElements(&g_hGeometricInFile[i]->d_stListOfPointsNormals[m],  
					p_stListOfPointsNormals[m].xX,
					p_stListOfPointsNormals[m].xY,
					p_stListOfPointsNormals[m].xZ);
				g_hGeometricInFile[i]->d_stListOfPointsReceivedLightIntensity[m].xR = p_stListOfColors[m].xR;
				g_hGeometricInFile[i]->d_stListOfPointsReceivedLightIntensity[m].xG = p_stListOfColors[m].xG;
				g_hGeometricInFile[i]->d_stListOfPointsReceivedLightIntensity[m].xB = p_stListOfColors[m].xB;
			}
			for (xIndex=0; xIndex < g_hGeometricInFile[i]->xNbElements; xIndex++)
			{
				if ( g_hGeometricInFile[i]->d_xListOfElementsTypes[xIndex] == MLT_C_xElementIndexedTriangles )
				{   
					MLT_tdstTripledIndex *p_stListOfFacesTripled;
					p_stLocalElement = ((MLT_tdstElementIndexedTriangles *)g_hGeometricInFile[i]->d_stListOfElements[xIndex]);
					p_stListOfFacesTripled = (MLT_tdstTripledIndex *)malloc(sizeof(MLT_tdstTripledIndex)* p_stLocalElement->xNbFaces);
					for (j=0; j<p_stLocalElement->xNbFaces; j++)
					{
						for (k=0; k<3; k++)
							p_stListOfFacesTripled[j].a3_xIndex[k] = p_iIndex[p_stLocalElement->d_stListOfFacesTripled[j].a3_xIndex[k]];
					}
					for (j=0; j<p_stLocalElement->xNbFaces; j++) 
					{
						for (k=0; k<3; k++)
							p_stLocalElement->d_stListOfFacesTripled[j].a3_xIndex[k] = p_stListOfFacesTripled[j].a3_xIndex[k];
					}
					free(p_stListOfFacesTripled);
				}
				else if (g_hGeometricInFile[i]->d_xListOfElementsTypes[xIndex] == MLT_C_xElementFaceMapDescriptors)
				{	
					MLT_tdstTripledIndex *p_stListOfFacesTripled;
					p_stLocalElementFMD = ((MLT_tdstElementFaceMapDescriptors *)g_hGeometricInFile[i]->d_stListOfElements[xIndex]);
					p_stListOfFacesTripled = (MLT_tdstTripledIndex *)malloc(sizeof(MLT_tdstTripledIndex)* p_stLocalElement->xNbFaces);
					for (j=0; j<p_stLocalElement->xNbFaces; j++) 
					{
						for (k=0; k<3; k++)							
							p_stListOfFacesTripled[j].a3_xIndex[k] = p_iIndex[p_stLocalElementFMD->d_stListOfFacesQuadrupled[j].stFaceTripled.a3_xIndex[k]];
					}
					for (j=0; j<p_stLocalElement->xNbFaces; j++) 
					{
						for (k=0; k<3; k++)
							p_stLocalElementFMD->d_stListOfFacesQuadrupled[j].stFaceTripled.a3_xIndex[k] = p_stListOfFacesTripled[j].a3_xIndex[k];
					}
					free(p_stListOfFacesTripled);
				}
			}

			free(p_stListOfPoints);
			free(p_stListOfPointsNormals);
			free(p_stListOfColors);
		 }
	  }
	}
}



/****************************************************************************
*		Description:	Detect and erase the duplicated points in all geometric objects of the hierarchy
*
*		Parameters:		
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
void MLT_vEraseDuplicatedPoints ()
{
	MLT_tdstElementIndexedTriangles		*p_stLocalElement;
	MLT_tdstElementFaceMapDescriptors	*p_stLocalElementFMD;
	xString								sFile, sAction, sIdent;
	char								buf[5];
	int									xIndex; 
	int									i, j, k, l, m, n, p, p1; 

	// check all geometric objects
	for (i=0; i<g_lGeometricIndex; i++) 
	{   
		m = 0;
		for (xIndex=0; xIndex < g_hGeometricInFile[i]->xNbElements; xIndex++)
		{	
			MLT_tdstTripledIndex *p_stListOfFacesTripled  = NULL;
			MLT_tdstTripledIndex *p_stListOfFacesTripledIndexUV  = NULL;
			MTH3D_tdstVector	 *p_stListOfFaceNormals  = NULL;
			
			n=0;
			if ( g_hGeometricInFile[i]->d_xListOfElementsTypes[xIndex] == MLT_C_xElementIndexedTriangles )
			{	
				p_stLocalElement = ((MLT_tdstElementIndexedTriangles *)g_hGeometricInFile[i]->d_stListOfElements[xIndex]);
				
				p_stListOfFacesTripled = (MLT_tdstTripledIndex *) malloc(p_stLocalElement->xNbFaces*sizeof(MLT_tdstTripledIndex));
				p_stListOfFacesTripledIndexUV = (MLT_tdstTripledIndex *) malloc(p_stLocalElement->xNbFaces*sizeof(MLT_tdstTripledIndex));
				p_stListOfFaceNormals = (MTH3D_tdstVector *) malloc(p_stLocalElement->xNbFaces*sizeof(MTH3D_tdstVector));
				
				//for all faces
				for (j=0; j<p_stLocalElement->xNbFaces; j++) 
				{	
					MTH3D_tdstVector stPoint[3];
					BOOL bNot = FALSE;
					
					for (k=0; k<3; k++)
						MTH3D_M_vSetVectorElements(&stPoint[k],  // k -> pk
								(g_hGeometricInFile[i]->d_stListOfPoints + p_stLocalElement->d_stListOfFacesTripled[j].a3_xIndex[k])->xX,
								(g_hGeometricInFile[i]->d_stListOfPoints + p_stLocalElement->d_stListOfFacesTripled[j].a3_xIndex[k])->xY,
								(g_hGeometricInFile[i]->d_stListOfPoints + p_stLocalElement->d_stListOfFacesTripled[j].a3_xIndex[k])->xZ);
					
					for (k=0; k<3; k++)
					{
						for (l=k+1; l<3; l++)
						{
							if ((fabs(stPoint[k].xX - stPoint[l].xX) <= g_fLimit3) && 
								(fabs(stPoint[k].xY - stPoint[l].xY) <= g_fLimit3) && 
								(fabs(stPoint[k].xZ - stPoint[l].xZ) <= g_fLimit3)) //duplicate points
							{	
								if (g_bEraseDuplicated)
								{   //erase the face from the object
									bNot = TRUE;
									MLT_vOutput( C_ComRes_cWarningLine, "\nWarning: From the object ");
									//MLT_vOutput( C_ComRes_cWarningLine, g_hGeometricInFile[i]->sName);
									SCR_fn_v_RdL0_SplitSectionName(g_hGeometricInFile[i]->sName, sFile, sAction, sIdent);
									MLT_vOutput( C_ComRes_cErrorLine, sIdent);
									MLT_vOutput( C_ComRes_cWarningLine, " in the element ");
									//MLT_vOutput( C_ComRes_cWarningLine, p_stLocalElement->sName);
									SCR_fn_v_RdL0_SplitSectionName(p_stLocalElement->sName, sFile, sAction, sIdent);
									MLT_vOutput( C_ComRes_cErrorLine, sIdent);
									MLT_vOutput( C_ComRes_cWarningLine, " was deleted the face n° ");
									sprintf(buf, "%d", j);
									MLT_vOutput( C_ComRes_cErrorLine, buf);
									MLT_vOutput( C_ComRes_cWarningLine, " which contained the duplicated points n° ");
									sprintf(buf, "%d", p_stLocalElement->d_stListOfFacesTripled[j].a3_xIndex[k]);
									MLT_vOutput( C_ComRes_cErrorLine, buf);
									MLT_vOutput( C_ComRes_cWarningLine, " and ");
									sprintf(buf, "%d", p_stLocalElement->d_stListOfFacesTripled[j].a3_xIndex[l]);
									MLT_vOutput( C_ComRes_cErrorLine, buf);
								}
								else
								{
									MLT_vOutput( C_ComRes_cErrorLine, "\nError: In the object ");
									//MLT_vOutput( C_ComRes_cErrorLine, g_hGeometricInFile[i]->sName);
									SCR_fn_v_RdL0_SplitSectionName(g_hGeometricInFile[i]->sName, sFile, sAction, sIdent);
									MLT_vOutput( C_ComRes_cWarningLine, sIdent);
									MLT_vOutput( C_ComRes_cErrorLine, " in the element ");
									//MLT_vOutput( C_ComRes_cErrorLine, p_stLocalElement->sName);
									SCR_fn_v_RdL0_SplitSectionName(p_stLocalElement->sName, sFile, sAction, sIdent);
									MLT_vOutput( C_ComRes_cWarningLine, sIdent);
									MLT_vOutput( C_ComRes_cErrorLine, " was detected the face n° ");
									sprintf(buf, "%d", j);
									MLT_vOutput( C_ComRes_cWarningLine, buf);
									MLT_vOutput( C_ComRes_cErrorLine, " which contains the duplicated points n° ");
									sprintf(buf, "%d", p_stLocalElement->d_stListOfFacesTripled[j].a3_xIndex[k]);
									MLT_vOutput( C_ComRes_cWarningLine, buf);
									MLT_vOutput( C_ComRes_cErrorLine, " and ");
									sprintf(buf, "%d", p_stLocalElement->d_stListOfFacesTripled[j].a3_xIndex[l]);
									MLT_vOutput( C_ComRes_cWarningLine, buf);
								}
							}
						}
					}
					if (!bNot) // the face remains, complete the new structures
					{	
						for (p=0; p<3; p++)
						{	p_stListOfFacesTripled[n].a3_xIndex[p] =  p_stLocalElement->d_stListOfFacesTripled[j].a3_xIndex[p];
							p_stListOfFacesTripledIndexUV[n].a3_xIndex[p] =  p_stLocalElement->d_stListOfFacesTripledIndexUV[j].a3_xIndex[p];
						}
						MTH3D_M_vSetVectorElements(&p_stListOfFaceNormals[n],
								p_stLocalElement->d_stListOfFacesNormals[j].xX,
								p_stLocalElement->d_stListOfFacesNormals[j].xY,
								p_stLocalElement->d_stListOfFacesNormals[j].xZ);
						n++;
					}
				}
			}
			else if (g_hGeometricInFile[i]->d_xListOfElementsTypes[xIndex] == MLT_C_xElementFaceMapDescriptors)
			{	
				p_stLocalElementFMD = ((MLT_tdstElementFaceMapDescriptors *)g_hGeometricInFile[i]->d_stListOfElements[xIndex]);

				p_stListOfFacesTripled = (MLT_tdstTripledIndex *) malloc(p_stLocalElement->xNbFaces*sizeof(MLT_tdstTripledIndex));
				p_stListOfFacesTripledIndexUV = (MLT_tdstTripledIndex *) malloc(p_stLocalElement->xNbFaces*sizeof(MLT_tdstTripledIndex));
				p_stListOfFaceNormals = (MTH3D_tdstVector *) malloc(p_stLocalElement->xNbFaces*sizeof(MTH3D_tdstVector));
				for (j=0; j<p_stLocalElementFMD->xNbFaces; j++)
				{
					MTH3D_tdstVector stPoint[3];
					BOOL bNot = FALSE;
					
					for (k=0; k<3; k++)
						MTH3D_M_vSetVectorElements(&stPoint[k],  // k -> pk
								(g_hGeometricInFile[i]->d_stListOfPoints + p_stLocalElementFMD->d_stListOfFacesQuadrupled[j].stFaceTripled.a3_xIndex[k])->xX,
								(g_hGeometricInFile[i]->d_stListOfPoints + p_stLocalElementFMD->d_stListOfFacesQuadrupled[j].stFaceTripled.a3_xIndex[k])->xY,
								(g_hGeometricInFile[i]->d_stListOfPoints + p_stLocalElementFMD->d_stListOfFacesQuadrupled[j].stFaceTripled.a3_xIndex[k])->xZ);
					
					for (k=0; k<3; k++)
					{
						for (l=k+1; l<3; l++)
						{
							if ((fabs(stPoint[k].xX - stPoint[l].xX) <= g_fLimit3)&& 
								(fabs(stPoint[k].xY - stPoint[l].xY) <= g_fLimit3)&& 
								(fabs(stPoint[k].xZ - stPoint[l].xZ) <= g_fLimit3)) //duplicate points
							{	
								if (g_bEraseDuplicated)
								{   //erase the face from the object
									bNot = TRUE;
									MLT_vOutput( C_ComRes_cWarningLine, "\nError: From the object ");
									//MLT_vOutput( C_ComRes_cWarningLine, g_hGeometricInFile[i]->sName);
									SCR_fn_v_RdL0_SplitSectionName(g_hGeometricInFile[i]->sName, sFile, sAction, sIdent);
									MLT_vOutput( C_ComRes_cErrorLine, sIdent);
									MLT_vOutput( C_ComRes_cWarningLine, " in the element ");
									//MLT_vOutput( C_ComRes_cWarningLine, p_stLocalElementFMD->sName);
									SCR_fn_v_RdL0_SplitSectionName(p_stLocalElementFMD->sName, sFile, sAction, sIdent);
									MLT_vOutput( C_ComRes_cErrorLine, sIdent);
									MLT_vOutput( C_ComRes_cWarningLine, " was deleted the face n° ");
									sprintf(buf, "%d", j);
									MLT_vOutput( C_ComRes_cErrorLine, buf);
									MLT_vOutput( C_ComRes_cWarningLine, " which contained the duplicated points n° ");
									sprintf(buf, "%d", p_stLocalElement->d_stListOfFacesTripled[j].a3_xIndex[k]);
									MLT_vOutput( C_ComRes_cErrorLine, buf);
									MLT_vOutput( C_ComRes_cWarningLine, " and ");
									sprintf(buf, "%d", p_stLocalElement->d_stListOfFacesTripled[j].a3_xIndex[l]);
									MLT_vOutput( C_ComRes_cErrorLine, buf);
								}
								else
								{
									MLT_vOutput( C_ComRes_cErrorLine, "\nError: In the object ");
									//MLT_vOutput( C_ComRes_cErrorLine, g_hGeometricInFile[i]->sName);
									SCR_fn_v_RdL0_SplitSectionName(g_hGeometricInFile[i]->sName, sFile, sAction, sIdent);
									MLT_vOutput( C_ComRes_cWarningLine, sIdent);
									MLT_vOutput( C_ComRes_cErrorLine, " in the element ");
									//MLT_vOutput( C_ComRes_cErrorLine, p_stLocalElementFMD->sName);
									SCR_fn_v_RdL0_SplitSectionName(p_stLocalElementFMD->sName, sFile, sAction, sIdent);
									MLT_vOutput( C_ComRes_cWarningLine, sIdent);
									MLT_vOutput( C_ComRes_cErrorLine, " was detected the face n° ");
									sprintf(buf, "%d", j);
									MLT_vOutput( C_ComRes_cWarningLine, buf);
									MLT_vOutput( C_ComRes_cErrorLine, " which contains the duplicated points n° ");
									sprintf(buf, "%d", p_stLocalElement->d_stListOfFacesTripled[j].a3_xIndex[k]);
									MLT_vOutput( C_ComRes_cWarningLine, buf);
									MLT_vOutput( C_ComRes_cErrorLine, " and ");
									sprintf(buf, "%d", p_stLocalElement->d_stListOfFacesTripled[j].a3_xIndex[l]);
									MLT_vOutput( C_ComRes_cWarningLine, buf);
								}
							}
						}
					}
					if (!bNot) // the face remains
					{	
						for (p=0; p<3; p++)
							p_stListOfFacesTripled[n].a3_xIndex[p] =  p_stLocalElementFMD->d_stListOfFacesQuadrupled[j].stFaceTripled.a3_xIndex[p];
						MTH3D_M_vSetVectorElements(&p_stListOfFaceNormals[n],
								p_stLocalElementFMD->d_stListOfFacesNormals[j].xX,
								p_stLocalElementFMD->d_stListOfFacesNormals[j].xY,
								p_stLocalElementFMD->d_stListOfFacesNormals[j].xZ);
						n++;
					}
				}
			}
			if ( g_hGeometricInFile[i]->d_xListOfElementsTypes[xIndex] == MLT_C_xElementIndexedTriangles )
			{	
				p_stLocalElement = ((MLT_tdstElementIndexedTriangles *)g_hGeometricInFile[i]->d_stListOfElements[xIndex]);
				for (p=0; p<n; p++)
				{	
					for (p1=0; p1<3; p1++)
					{	p_stLocalElement->d_stListOfFacesTripled[p].a3_xIndex[p1] = p_stListOfFacesTripled[p].a3_xIndex[p1];
						p_stLocalElement->d_stListOfFacesTripledIndexUV[p].a3_xIndex[p1] = p_stListOfFacesTripledIndexUV[p].a3_xIndex[p1];
					}
					MTH3D_M_vSetVectorElements(&p_stLocalElement->d_stListOfFacesNormals[p],
						p_stListOfFaceNormals[p].xX,
						p_stListOfFaceNormals[p].xY,
						p_stListOfFaceNormals[p].xZ);
				}
				p_stLocalElement->xNbFaces = n; 
			}
			else if (g_hGeometricInFile[i]->d_xListOfElementsTypes[xIndex] == MLT_C_xElementFaceMapDescriptors)
			{	
				p_stLocalElementFMD = ((MLT_tdstElementFaceMapDescriptors *)g_hGeometricInFile[i]->d_stListOfElements[xIndex]);
				for (p=0; p<n; p++)
				{	
					for (p1=0; p1<3; p1++)
						p_stLocalElementFMD->d_stListOfFacesQuadrupled[p].stFaceTripled.a3_xIndex[p1] = p_stListOfFacesTripled[p].a3_xIndex[p1];
					MTH3D_M_vSetVectorElements(&p_stLocalElementFMD->d_stListOfFacesNormals[p],
						p_stListOfFaceNormals[p].xX,
						p_stListOfFaceNormals[p].xY,
						p_stListOfFaceNormals[p].xZ);
				}
				p_stLocalElementFMD->xNbFaces = n; 
			}
			if (p_stListOfFacesTripled)
				free(p_stListOfFacesTripled);
			if (p_stListOfFacesTripledIndexUV)
				free(p_stListOfFacesTripledIndexUV);
			if (p_stListOfFaceNormals)
				free(p_stListOfFaceNormals);
		}
	}
}



// multitextures
void MLT_vSearch (char *sRead, FILE*file)
{
	long lIndex;
	char sRead1[256];

	fseek(file, 0L, 0);
	fgets(sRead1, 256, file);
	while(!strstr(sRead1, sRead))
	{	lIndex=ftell(file);
		fgets(sRead1, 256, file);
	}
	fseek(file, lIndex, 0);
}

