/*=========================================================================
*
* RLISave.c	- Saving functions for RLI file
*
* Version			1.0
* Revision date
*
*=======================================================================*/
#include <Windows.h>

#include "RliSave.h"

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

#include "Levels.h"
#include "ModLib.h"
#include "Submaps.h"
#include "VseSave.h"


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

long		g_lLightIndex = 0;		


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

MLT_Light **gs_hLights = NULL;		

char		*gs_LightTypes[]	= {"Spherical", "Ambient", "HotSpot", "Parallel"};
char		*gs_LightPrefix[]	= {"_paint", "_alpha", "_list"};



//--- Mathematic functions --------------------------------------------------------

// compute the power2
float sqr(float x)
{
	return x*x;
}


// compute the scalar product between 2 3D vectors
float ScalarProduct(MTH3D_tdstVector *v1, MTH3D_tdstVector *v2)
{
	return v1->xX*v2->xX + v1->xY*v2->xY + v1->xZ*v2->xZ;
}


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



/****************************************************************************
*		Description:	Load a LG2 file
*
*		Parameters:		
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
void MLT_vLoadLG2()
{
	SCR_tdst_Cxt_Values *p_stVal;
	xString				szFileName;
	int					f;

	sprintf(szFileName, "%s.lg2", g_sFileIn);

	MLT_vDeleteAllLights();
	SCR_fn_v_RdL0_RegisterCallback(M_Light, MLT_xLoadLight, SCR_CRC_c_RdL0_ForSection);  

	f = _open(szFileName, O_RDONLY, S_IREAD);
	if(f != -1)
	{
		_close(f);
		p_stVal = SCR_fnp_st_RdL0_AnalyseSection(szFileName, SCR_CDF_uw_Anl_ForceAnalyse);
	}
	
	SCR_fn_v_RdL0_DeleteRegisterCallback(M_Light, SCR_CRC_c_RdL0_ForSection, SCR_CDR_c_RdL0_Match);
}


/****************************************************************************
*		Description:	Load a LGT file
*
*		Parameters:		
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
void MLT_LoadLGT()
{
  SCR_tdst_Cxt_Values	*p_stVal;
  xString				szFileName;
  int					f;
  
  sprintf(szFileName, "%s.lgt", g_sFileIn);

  MLT_vDeleteAllLights();
  SCR_fn_v_RdL0_RegisterCallback(M_Light, MLT_xLoadLight, SCR_CRC_c_RdL0_ForSection);  

  f = _open(szFileName, O_RDONLY, S_IREAD);
  if(f != -1)
  {
	_close(f);
	p_stVal = SCR_fnp_st_RdL0_AnalyseSection(szFileName, SCR_CDF_uw_Anl_ForceAnalyse);
  }
  SCR_fn_v_RdL0_DeleteRegisterCallback(M_Light, SCR_CRC_c_RdL0_ForSection, SCR_CDR_c_RdL0_Match);
}


/****************************************************************************
*		Description:	create and save the RLI file
*
*		Parameters:		
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
void MLT_vCreateRLI ()
{
	MLT_tdxHandleToSuperObject	hRoot;
	SCR_tdst_File_Description	stFile;
	SCR_tdst_Cxt_Values			*p_stVal;
	MLT_tdstMatrix				stMatrix;
	MLT_tdstColor				**rli;
	xString						sRoot, sFileSpo, sDir, sRawBank;
	xString						sFile, sAction, sIdent, sSection;
	int							i, j, nRLI = 0;

	g_bExistSpoBank=FALSE;

	if (!g_bLevel)
	{
		// find SPO file
	  if (g_bStandardConfig)
	  {	
		switch (g_iRaw)
		{	
			case 0:
					sprintf(sRawBank, "%s\\World\\Graphics\\Objects\\Banks", g_sRawCommon);	  
					break;
			case 1:
					sprintf(sRawBank, "%s\\World\\Graphics\\Objects\\Banks", g_sRawSpecific1);	  
					break;
			case 2:
					sprintf(sRawBank, "%s\\World\\Graphics\\Objects\\Banks", g_sRawSpecific2);	  
					break;
		}
	  }
	  else
		sprintf(sRawBank, g_szBanks);	  
	}
	else
	{	
	  if (g_bStandardConfig)
	  {
		switch (g_iRaw)
		{	
			case 0:
				sprintf(sRawBank, "%s\\World\\Levels\\%s", g_sRawCommon, g_sFileIn);	  
				break;
			case 1:
				sprintf(sRawBank, "%s\\World\\Levels\\%s", g_sRawSpecific1, g_sFileIn);	  
				break;
			case 2:
				sprintf(sRawBank, "%s\\World\\Levels\\%s", g_sRawSpecific2, g_sFileIn);	  
				break;
		}
	  }
	  else
		sprintf(sRawBank, "%s\\%s", g_szLevels, g_sFileIn);	  
	}

	GetCurrentDirectory(256, sDir);
	SetCurrentDirectory(sRawBank);
	sprintf(sFileSpo, "%s.spo", g_sFileIn);

	if (!g_bLevel)
	{
		SCR_fn_v_RdL0_ComputeSectionName(sRoot, sFileSpo, M_SuperObject, M_Root);

		// load module hierarchy
		if(SCR_fn_c_RdL0_IsSectionExists(sRoot))
		{	
			p_stVal = SCR_fnp_st_RdL0_AnalyseSection(sRoot, SCR_CDF_uw_Anl_Normal);
			hRoot = (MLT_tdxHandleToSuperObject)SCR_M_ul_RdL0_ExtractLongValue(p_stVal,0);
			g_bExistSpoBank = TRUE;
			MLT_vOutput( C_ComRes_cNormalLine, "\n\tCreate RLI...");
		}
		else
			g_bExistSpoBank = FALSE;
	}
	else
		hRoot = g_hRoot;

	if (g_bExistSpoBank || g_bLevel) 
	{
		if (!g_bLevel)
		{
			// find SPO file
			switch (g_iData)
			{	
				case 0:
						sprintf(sRawBank, "%s\\World\\Graphics\\Objects\\Banks\\%s", g_sGameCommon, g_sFileIn);	  
						break;
				case 1:
						sprintf(sRawBank, "%s\\World\\Graphics\\Objects\\Banks\\%s", g_sGameSpecific1, g_sFileIn);	  
						break;
				case 2:
						sprintf(sRawBank, "%s\\World\\Graphics\\Objects\\Banks\\%s", g_sGameSpecific2, g_sFileIn);	  
						break;
			}
		}
		else
		{	
			switch (g_iData)
			{	
				case 0:
					sprintf(sRawBank, "%s\\World\\Levels\\%s", g_sGameCommon, g_sFileIn);	  
					break;
				case 1:
					sprintf(sRawBank, "%s\\World\\Levels\\%s", g_sGameSpecific1, g_sFileIn);	  
					break;
				case 2:
					sprintf(sRawBank, "%s\\World\\Levels\\%s", g_sGameSpecific2, g_sFileIn);	  
					break;
			}
		}
	    SetCurrentDirectory(sRawBank);

		// init RLI file
		sprintf(stFile.a_szFileName,"%s.rli", g_sFileIn);
		remove(stFile.a_szFileName);
		strcpy(stFile.a_szOpenFileName, stFile.a_szFileName);
		stFile.p_stHandle = (SCR_tdst_File_Handle*)malloc(sizeof(SCR_tdst_File_Handle));
		stFile.p_stHandle->xHandle = (FILE*)_open(stFile.a_szFileName, O_WRONLY | O_CREAT | _O_TEXT, S_IREAD | S_IWRITE);;
		stFile.p_stHandle->p_cBase = stFile.p_stHandle->p_cCurrent = 0;
		stFile.p_stHandle->iCnt = 0;
		stFile.d_stFirstPage = stFile.d_stLastPage = stFile.d_stCurPage = NULL;
		stFile.iCurPosInPage = 0;

		if(stFile.p_stHandle->xHandle != 0)
		{
			// number of RLI tables
			for (i = 0; i<g_lLightIndex; i++) 
				nRLI = max(nRLI, gs_hLights[i]->iRLI);
			nRLI++;		
			rli = (MLT_tdstColor **)malloc(nRLI*sizeof(MLT_tdstColor *));

			// loop in modules hierarchy
			MLT_xSetIdentityMatrix(&stMatrix);

			
			if (g_bLevel)
			{
				sprintf(sFile, "%s.sct", g_sFileIn);
				if(! SCR_fn_c_RdL0_IsSectionExists(sFile))
					return;

				for(i=0; i<hRoot->lNbChild-(g_iUnivSectors+1); i++)
				{
					// recover the old sector
					SCR_fn_v_RdL0_SplitSectionName(hRoot->d_hChild[i]->stSector.sName, sFile, sSection, sIdent);
					SCR_fn_v_RdL0_ComputeSectionName(sAction, sFile, M_Sector, sIdent);

					if(SCR_fn_c_RdL0_IsSectionExists(sAction))
					{
						MLT_tdstSector *p_stOldSector;
						
						p_stVal = SCR_fnp_st_RdL0_AnalyseSection(sAction, SCR_CDF_uw_Anl_Normal);
						p_stOldSector = (MLT_tdstSector*) SCR_M_ul_RdL0_ExtractLongValue(p_stVal,0);

						// copy lights
						for (j=0; j<p_stOldSector->lNbStaticLights; j++)
							strcpy(hRoot->d_hChild[i]->stSector.a_sStaticLights[j], p_stOldSector->a_sStaticLights[j]);
						hRoot->d_hChild[i]->stSector.lNbStaticLights = p_stOldSector->lNbStaticLights;
					}
				}

				for (i = 0; i < hRoot->lNbChild; i++)
				{
					for (j = 0; j < hRoot->d_hChild[i]->lNbChild; j++)
					{	
						hRoot->d_hChild[i]->d_hChild[j]->stSector = hRoot->d_hChild[i]->stSector;
						MLT_vComputeSector (hRoot->d_hChild[i]->d_hChild[j]);
					}
				}
			}

			MLT_vComputeOneRLI(hRoot, &stMatrix, rli, nRLI, &stFile);

			free(rli);
		}
		_close((int)stFile.p_stHandle->xHandle);
		free(stFile.p_stHandle);
//		MLT_vDeleteAllLights();
	}
	else
	    SetCurrentDirectory(sDir);
}

/****************************************************************************
*		Description:	Clears the light list
*
*		Parameters:		
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
void MLT_vDeleteAllLights()
{
	int i;
	if(g_lLightIndex)
	{
		for(i=0; i<g_lLightIndex; i++) 
		{
			if(gs_hLights[i]->Matrix) free(gs_hLights[i]->Matrix);
			free(gs_hLights[i]);
		}
		free(gs_hLights);
		gs_hLights = NULL;
		g_lLightIndex = 0;
	}	
}



/****************************************************************************
*		Description:	Light section callback
*
*		Parameters:		p_stFile	: script file pointer
*						szAction	: section or entry name
*						szParams	: parameters
*						cType		: action type
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
SCR_tde_Anl_ReturnValue MLT_xLoadLight(SCR_tdst_File_Description *p_fFile, char *szAction, char *szParams[], SCR_tde_Anl_Action cType)
{
  SCR_tdst_Cxt_Values	*p_stVal;
  MLT_Light				*l;
  char					*c;

  switch (cType)
  {
    case SCR_EA_Anl_BeginSection:
      l = (MLT_Light*)malloc(sizeof(MLT_Light));
      SCR_M_RdL0_SetSectionLong(0,0,(long)l);
      SCR_M_RdL0_SetContextLong(0,0,(long)l);
	  gs_hLights	= (MLT_Light**)realloc(gs_hLights, (++g_lLightIndex)*sizeof(MLT_Light*));
	  gs_hLights[g_lLightIndex - 1] = l;
      l->iGeomType = MLT_iGetLightType(szParams[0]);
      sprintf(l->sName,"%s",SCR_M_RdL0_GetCompleteSectionNameR(0));

	  if ( strstr(l->sName, "FORCE_FULL_LIGHT_"))
		  l->bNotCompute = TRUE;
	  else
		  l->bNotCompute = FALSE;

			l->Matrix = NULL;
			l->iState = 0;
			l->iRLI = 0;			
			l->iType = L_RGB;	
			if(strstr(l->sName, gs_LightPrefix[0])) l->iType |= L_PAINT;
			if(strstr(l->sName, gs_LightPrefix[1])) l->iType |= L_ALPHA;
			c = l->sName;	
			do c = strstr(c+1, gs_LightPrefix[2]);
			while(c && (!isdigit(c[5]) || !isdigit(c[6]))); 
			if(c) l->iRLI = atoi(c+5);
      break;
                
    case SCR_EA_Anl_Entry:
      SCR_M_RdL0_GetContextLong(0, 0, MLT_Light*, l);
	  // set light's state
      if(!lstrcmpi(szAction, M_LGTActionSetState)) l->iState = atoi(szParams[0]);
      if(!lstrcmpi(szAction, M_LGTActionSetColor))
      {
		l->color.xR = (float) atof(szParams[0]);
		l->color.xG = (float) atof(szParams[1]);
		l->color.xB = (float) atof(szParams[2]);
		if(l->iType & L_ALPHA)
			l->color.xA = (float) atof(szParams[0]);
		else
			l->color.xA = (float) atof(szParams[3]);
      } 
	  // matrix name
      if(!lstrcmpi(szAction, M_LGTActionSetMatrix))
      {
				c = strchr(szParams[0], '^');
				if(c)
				{
					*(c-1) = '*';
					p_stVal = SCR_fnp_st_RdL0_AnalyseSection(c-1, SCR_CDF_uw_Anl_Normal);
					l->Matrix = (MLT_tdstMatrix*)SCR_M_ul_RdL0_ExtractLongValue(p_stVal, 0);
				}
      }
	  // Near/Far parameters
      if(!lstrcmpi(szAction, M_LGTActionSetNearFar))
			{
				l->fNearFar[0] = (float)atof(szParams[0]);
				l->fNearFar[1] = (float)atof(szParams[1]);
			}
	  // Alpha angles
      if(!lstrcmpi(szAction, M_LGTActionSetAlphas))
			{
				l->fAlphas[0] = (float)atof(szParams[0]);
				l->fAlphas[1] = (float)atof(szParams[1]);
			}
			break;

    case SCR_EA_Anl_EndSection:
      break;
  }
  return  SCR_ERV_Anl_NormalReturn;
}



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

	switch (cType)
	{
		case SCR_EA_Anl_BeginSection:
			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);
			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:
			{
			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_M_SetVertexXYZ(&stI,a_xVertex[0],a_xVertex[1],a_xVertex[2]);
				MLT_xSetTranslationMatrix(p_stMatrix,&stI);
			}
			
			// 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);
			}
			
			// 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);
			}
			}
			break;

		case SCR_EA_Anl_EndSection:
			break;
	}
  return  SCR_ERV_Anl_NormalReturn;
}






/****************************************************************************
*		Description:	compute RLI for Full Light
*
*		Parameters:		obj	: geometric object
*						rli	: rli list
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
void MLT_vComputeFullRLI(MLT_tdstGeometricObject *obj, MLT_tdstColor *rli)
{
	int i;
	for(i=0; i<obj->xNbPoints; i++) 
	{
		(rli+i)->xR = (float) 255.0;
		(rli+i)->xG = (float) 255.0;
		(rli+i)->xB = (float) 255.0;
		(rli+i)->xA = (float) 255.0;
	}
}

/****************************************************************************
*		Description:	compute RLI for Spherical Light
*
*		Parameters:		p_stMatrix	: current matrix
*						light		: current light
*						obj			: geometric object
*						rli			: rli list
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
void MLT_vComputeSphericalRLI (MLT_tdstMatrix *p_stMatrix, MLT_Light *light, MLT_tdstGeometricObject *obj, MLT_tdstColor *rli)
{
	MTH3D_tdstVector dist, lightpos, norm, realpoint;
	MTH3D_tdstVector *point = obj->d_stListOfPoints;
	MTH3D_tdstVector *normal = obj->d_stListOfPointsNormals;
	float			 near2 = sqr(light->fNearFar[0]);
	float			 far2 = sqr(light->fNearFar[1]);
	float			 delta, d, coef;
	int				 i;

	delta = far2 - near2 > 1e-8 ? 1.f/(far2 - near2) : 1.f;
	MLT_xGetTranslationMatrix(light->Matrix, &lightpos);

	// for all object's points
	for (i=0; i<obj->xNbPoints; i++)																		
	{																																	
		MTH3D_M_vCopyVector(&norm, normal+i);
		MTH3D_M_vNormalizeVector(&norm, &norm);
		MLT_xMulMatrixVertex(&realpoint, p_stMatrix, point+i);
		// compute the vector light-point
		MTH3D_M_vSubVector(&dist, &lightpos, &realpoint);												
		// compute the square distance
		d = sqr(dist.xX) + sqr(dist.xY) + sqr(dist.xZ);									
		// if point may be in the light action zone
		if (d < far2)												
		{
			// compute the reflexion coeficient
			coef = -ScalarProduct(&dist, &norm) / (float)(d > 1e-4 ? sqrt(d) : 1e-2); 
			// if PaintLight, then no backface
			if (light->iType|L_PAINT && coef<0) 
				coef = -coef;							
			// update the coeficient
			if (d >= near2) 
				coef *= (far2 - d)*delta;											
			// adds the light effect to RLI
			if (coef > 0)	
				MLT_vAddLightEffect(rli+i, &light->color, coef);			
		}
	}
}


/****************************************************************************
*		Description:	compute RLI for Ambiant Light
*
*		Parameters:		p_stMatrix	: current matrix
*						light		: current light
*						obj			: geometric object
*						rli			: rli list
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
void MLT_vComputeAmbientRLI (MLT_tdstMatrix *p_stMatrix, MLT_Light *light, MLT_tdstGeometricObject *obj, MLT_tdstColor *rli)
{
	int i;

	for (i=0; i<obj->xNbPoints; i++) 
		MLT_vAddLightEffect(rli+i, &light->color, 1.f);
}


/****************************************************************************
*		Description:	compute RLI for HotSpot Light
*
*		Parameters:		p_stMatrix	: current matrix
*						light		: current light
*						obj			: geometric object
*						rli			: rli list
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
void MLT_vComputeHotSpotRLI (MLT_tdstMatrix *p_stMatrix, MLT_Light *light, MLT_tdstGeometricObject *obj, MLT_tdstColor *rli)
{
	MTH3D_tdstVector dist, c0, c1, c2, norm, realpoint;
	MTH3D_tdstVector *point = obj->d_stListOfPoints;
	MTH3D_tdstVector *normal = obj->d_stListOfPointsNormals;
	float			 near2 = sqr(light->fNearFar[0]);
	float			 far2 = sqr(light->fNearFar[1]);
	float			 ltan = (float)tan(light->fAlphas[0]/2);
	float			 btan = (float)tan(light->fAlphas[1]/2);
	float			 delta, deltatg, d, coef;
	int				 i;

	delta = far2 - near2 > 1e-8 ? 1.f/(far2 - near2) : 1.f;
	deltatg = btan - ltan > 1e-8 ? 1.f/(btan - ltan) : 1.f;

	// for all object's points
	for (i=0; i<obj->xNbPoints; i++)																				
	{
		MTH3D_M_vCopyVector(&norm, normal+i);
		MTH3D_M_vNormalizeVector(&norm, &norm)
		MLT_xMulMatrixVertex(&realpoint, p_stMatrix, point+i);
		// get the light-point vector
		MTH3D_M_vSubVector(&c2, &light->Matrix->stTranslation, &realpoint);		
		// get the rotation matrix on columns
		MLT_xGetRotationMatrix(light->Matrix, &c0, &c1, &dist);						
		dist.xZ = ScalarProduct(&dist, &c2);									
		dist.xY = ScalarProduct(&c1, &c2);										
		dist.xX = ScalarProduct(&c0, &c2);										
		// compute the partial square distance
		d = sqr(dist.xY) + sqr(dist.xZ);											
		// if point may be in the light spot
		if (dist.xX < light->fNearFar[1] && dist.xX > 1e-4f && d < far2)			
		{
			// get the light-point axis tangent in the light space
			float tangent = (float)(sqrt(d) / dist.xX);						
			// if point may be in the light spot
			if(tangent < btan)												
			{
				// compute the full square distance
				d += sqr(dist.xZ);													
				// compute the reflexion coeficient
				coef = d < near2 ? 1.f : (far2 - d) * delta;					
				// update the coeficient 
				if(tangent > ltan) 
					coef *= (btan - tangent) * deltatg;			
				coef *= ScalarProduct(&c0, &norm);									
				// if PaintLight then no backface
				if(light->iType|L_PAINT && coef<0) 
					coef = -coef;				
				// adds the light effect to RLI
				if(coef > 0)
					MLT_vAddLightEffect(rli+i, &light->color, coef);				
			}
		}
	}
}


/****************************************************************************
*		Description:	compute RLI for Parallel Light
*
*		Parameters:		p_stMatrix	: current matrix
*						light		: current light
*						obj			: geometric object
*						rli			: rli list
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
void MLT_vComputeParallelRLI (MLT_tdstMatrix *p_stMatrix, MLT_Light *light, MLT_tdstGeometricObject *obj, MLT_tdstColor *rli)
{
	MTH3D_tdstVector c0, c1, c2, norm;
	MTH3D_tdstVector *normal = obj->d_stListOfPointsNormals;
	float			 coef;
	int				 i;

	// get the rotation matrix on columns, so get the light's vector in the world space
	MLT_xGetRotationMatrix(light->Matrix, &c0, &c1, &c2);					

	// for all object's points
	for(i=0; i<obj->xNbPoints; i++)																
	{
		MTH3D_M_vCopyVector(&norm, normal+i);
		MTH3D_M_vNormalizeVector(&norm, &norm)
		// compute the reflexion coeficient
		coef = -ScalarProduct(&c2, &norm);												
		if(light->iType|L_PAINT && coef<0) 
			coef = -coef;
		// adds the light effect to RLI
		if(coef > 0) 
			MLT_vAddLightEffect(rli+i, &light->color, coef);		
	}
}


/****************************************************************************
*		Description:	compute one RLI 
*
*		Parameters:		hSupObj		: current super-object
*						p_stMatrix	: current matrix
*						rli			: pointer on rli lists
*						nRLI		: nb of rli lists
*						p_stFile	: script pointer of the rli file
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
void MLT_vComputeOneRLI (MLT_tdxHandleToSuperObject hSupObj, MLT_tdstMatrix *p_stMatrix, MLT_tdstColor **rli, int nRLI, SCR_tdst_File_Description *p_stFile)
{
	MLT_tdstMatrix	stMatrix;
	xString			sFile, sAction, sIdent, sSection;
	xString			sName, sForme, sHabillage;
	long			lNoPhy, lNoLod;
	int				i, j, k;
	
	MLT_xMulMatrixMatrix(&stMatrix, hSupObj->p_stMatrix, p_stMatrix);
	
	// look for geometry
	if (strcmp(hSupObj->sGeometric, ""))
	{
		// find geometry
		MLT_tdstGeometricObject *obj = MLT_pFindInLib(hSupObj->sGeometric);
		if(obj == NULL)
  		{
			MLT_vOutput( C_ComRes_cErrorLine, "\nError : Can't load %s", hSupObj->sGeometric);
			return;
		}
		
		if(strlen(obj->sPhysicalSection) || g_bLevel) 
		{
			// create the RLI list
			for(j=0; j<nRLI; j++) 
			{
				rli[j] = (MLT_tdstColor *)malloc(obj->xNbPoints*sizeof(MLT_tdstColor));
				for(k=0; k<obj->xNbPoints; k++)
				{
					rli[j][k].xR = rli[j][k].xG = rli[j][k].xB = 0;	// initialize the RLI list
					rli[j][k].xA = 255;								// initialize the RLI list
				}
			}
			if (!g_bLevel) 
			{
				// for all lights
				for(j=0; j<g_lLightIndex; j++)
				{
					MLT_Light *light = gs_hLights[j];
					if (light->bNotCompute)
					{
						MLT_vComputeFullRLI(obj, rli[light->iRLI]);
					}
					// if the light is ON
					else if(light->iState && light->Matrix)			
					{
						// Compute the RLI lists
						switch(light->iGeomType)
						{
							case SPHERICAL:	MLT_vComputeSphericalRLI(&stMatrix, light, obj, rli[light->iRLI]); break;
							case AMBIENT:	MLT_vComputeAmbientRLI(&stMatrix, light, obj, rli[light->iRLI]); break;
							case HOTSPOT:	MLT_vComputeHotSpotRLI(&stMatrix, light, obj, rli[light->iRLI]); break;
							case PARALLEL:	MLT_vComputeParallelRLI(&stMatrix, light, obj, rli[light->iRLI]); break;
						}
					}		
				}
			}
			else //for the level uses just the lights specified in sct file
			{
				for(j=0; j<hSupObj->stSector.lNbStaticLights; j++)
				{
					MLT_Light *light = MLT_hGetLight(hSupObj->stSector.a_sStaticLights[j], gs_hLights);
					if (light == NULL)
					{	
						MLT_vOutput( C_ComRes_cErrorLine, "\nError : The light %s doesn't exist", hSupObj->stSector.a_sStaticLights[j]);
						continue;
					}

					if(light->iState && light->Matrix)			// if the light is ON
					{
						// Compute the RLI lists
						switch(light->iGeomType)
						{
							case SPHERICAL:	MLT_vComputeSphericalRLI(&stMatrix, light, obj, rli[light->iRLI]); break;
							case AMBIENT:	MLT_vComputeAmbientRLI(&stMatrix, light, obj, rli[light->iRLI]); break;
							case HOTSPOT:	MLT_vComputeHotSpotRLI(&stMatrix, light, obj, rli[light->iRLI]); break;
							case PARALLEL:	MLT_vComputeParallelRLI(&stMatrix, light, obj, rli[light->iRLI]); break;
						}
					}		
				}	

			}
			// Save the RLI data
			if (g_bLevel) 
			{
				MLT_vMakePhysicalInLib();
				SCR_fn_v_RdL0_SplitSectionName(obj->sPhysicalSection, sFile, sAction, sIdent);
				for(j=0; j<nRLI; j++)
				{
					SCR_fn_v_RdL0_SplitSectionName(obj->sPhysicalSection, sFile, sAction, sIdent);
					sprintf(sFile, "%s.vse", g_sFileIn);
					MLT_vSplitModuleSectionName(sIdent, sForme, sHabillage, &lNoPhy, &lNoLod, sName);
					MLT_vComputeVisualSetSectionName(sIdent, sForme, sHabillage, sName);
					SCR_fn_v_RdL0_ComputeSectionName(sSection, sFile, M_VS, sIdent);
					obj->lNbLod = MLT_lSaveLodInFile(sSection);
					wsprintf(sSection, "ISI:ISI_%s(NBRLOD, %d)", sIdent, obj->lNbLod);
					SCR_M_SvL0_SaveBeginSection(p_stFile, sSection, SCR_CC_C_Cfg_EOL);
					SCR_M_SvL0_SaveEntry(p_stFile, M_RLIActionAddLOD, SCR_CC_C_Cfg_NoChar);
					SCR_fn_v_SvL0_SaveParameters_MP(p_stFile, SCR_EF_SvL0_Scanf, 2, "%d,%d", 0, obj->xNbPoints);
					for(k=0; k<obj->xNbPoints; k++)
					{
						SCR_M_SvL0_SaveEntry(p_stFile, M_RLIActionAddVertexLOD, SCR_CC_C_Cfg_NoChar);
						SCR_fn_v_SvL0_SaveParameters_MP(p_stFile, SCR_EF_SvL0_Scanf, 5, "%d,%d,%d,%d,%d", k, (int)rli[j][k].xR, (int)rli[j][k].xG, (int)rli[j][k].xB, (int)rli[j][k].xA);
					}
					SCR_M_SvL0_SaveEndSection(p_stFile, SCR_CC_C_Cfg_EOL);
					free(rli[j]);
				}	
			}
			else 
			{
				SCR_fn_v_RdL0_SplitSectionName(obj->sPhysicalSection, sFile, sAction, sIdent);
				sprintf(sSection, "RLI:%s(NBRLI, %d)", sIdent, nRLI);
				SCR_M_SvL0_SaveBeginSection(p_stFile, sSection, SCR_CC_C_Cfg_EOL);
				for(j=0; j<nRLI; j++)
				{
					SCR_fn_v_RdL0_SplitSectionName(obj->sPhysicalSection, sFile, sAction, sIdent);
					sprintf(sFile, "%s.vse", g_sFileIn);
					MLT_vSplitModuleSectionName(sIdent, sForme, sHabillage, &lNoPhy, &lNoLod, sName);
					MLT_vComputeVisualSetSectionName(sIdent, sForme, sHabillage, sName);
					SCR_fn_v_RdL0_ComputeSectionName(sSection, sFile, M_VS, sIdent);
					obj->lNbLod = MLT_lSaveLodInFile(sSection);
					wsprintf(sSection, "IS2:ISI_RLI%02d(NBRLOD, %d)", j, obj->lNbLod);
					SCR_M_SvL0_SaveBeginSection(p_stFile, sSection, SCR_CC_C_Cfg_EOL);
					SCR_M_SvL0_SaveEntry(p_stFile, M_RLIActionAddLOD, SCR_CC_C_Cfg_NoChar);
					SCR_fn_v_SvL0_SaveParameters_MP(p_stFile, SCR_EF_SvL0_Scanf, 2, "%d,%d", 0, obj->xNbPoints);
					for(k=0; k<obj->xNbPoints; k++)
					{
						SCR_M_SvL0_SaveEntry(p_stFile, M_RLIActionAddVertexLOD, SCR_CC_C_Cfg_NoChar);
							SCR_fn_v_SvL0_SaveParameters_MP(p_stFile, SCR_EF_SvL0_Scanf, 5, "%d,%d,%d,%d,%d", k, (int)rli[j][k].xR, (int)rli[j][k].xG, (int)rli[j][k].xB, (int)rli[j][k].xA);
					}
					SCR_M_SvL0_SaveEndSection(p_stFile, SCR_CC_C_Cfg_EOL);
					free(rli[j]);
				}
				SCR_M_SvL0_SaveEndSection(p_stFile, SCR_CC_C_Cfg_EOL);
			}
		}
	}

	// loop on each child
	for (i=0; i<hSupObj->lNbChild; i++)
		MLT_vComputeOneRLI(hSupObj->d_hChild[i], &stMatrix, rli, nRLI, p_stFile);
}



/****************************************************************************
*		Description:	Get the light type from it's name
*
*		Parameters:		type	: name to parse
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
int MLT_iGetLightType(char *type)
{
	int i;
	for (i=0; i<sizeof(gs_LightTypes)/sizeof(char*); i++)
	{
		if (!lstrcmpi(type, gs_LightTypes[i])) 
			return i;
	}
	return 0;
}





/****************************************************************************
*		Description:	adds the light effect to the rli, with the given coefficient
*
*		Parameters:		dst		: destination color
*						src		: source color
*						coef	: coefficient
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
void MLT_vAddLightEffect(MLT_tdstColor *dst, MLT_tdstColor *src, float coef)
{
	dst->xR += src->xR * coef * 255;
	dst->xG += src->xG * coef * 255;
	dst->xB += src->xB * coef * 255;
	if (!g_bLevel)
		dst->xA -= src->xA * coef * 255;
	else
		dst->xA += src->xA * coef * 255;

	if (!g_bLevel) 
	{
		dst->xR = (dst->xR > 255.0) ? (float) 255.0 : dst->xR;
		dst->xG = (dst->xG > 255.0) ? (float) 255.0 : dst->xG;
		dst->xB = (dst->xB > 255.0) ? (float) 255.0 : dst->xB;
		dst->xA = (dst->xA > 255.0) ? (float) 255.0 : dst->xA;
		dst->xA = (dst->xA < 0.0) ? (float) 0.0 : dst->xA;
	}
}




/****************************************************************************
*		Description:	get a light from its name in the array of light
*
*		Parameters:		sStaticLight	: name of the light to find
*						g_hLights		: array of light to search
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
MLT_Light *MLT_hGetLight (xString sStaticLight, MLT_Light **g_hLights)
{
	MLT_Light	*p_stLight = NULL;
	char *		p_sShortName;
	int			i;

	// get short name (without level name)
	p_sShortName = strstr(sStaticLight, "\\");
	if (!p_sShortName)
		p_sShortName = sStaticLight;
	else
		p_sShortName++;

	for (i=0; i<g_lLightIndex; i++)
	{
		if (!stricmp(g_hLights[i]->sName, p_sShortName))
			return g_hLights[i];
	}

	return p_stLight;
}


/****************************************************************************
*		Description:	compute the sector parameters
*
*		Parameters:		hSupObj		: root
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
void MLT_vComputeSector (MLT_tdxHandleToSuperObject hSupObj)
{
    int i;
	// loop on each child
	for (i = 0; i < hSupObj->lNbChild; i++)
		hSupObj->d_hChild[i]->stSector = hSupObj->stSector;

	for (i=0; i<hSupObj->lNbChild; i++)
		MLT_vComputeSector(hSupObj->d_hChild[i]);
}



