/*=========================================================================
*
* Normals.c	- normal functions
*
* Version			1.0
* Revision date
*
*=======================================================================*/
#include "Normals.h" 

#include "defines.h"

#include "ModLib.h"

#include "Borders.h"

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

double gs_fLim=0.01;

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


/****************************************************************************
*		Description:	compute all the normals for all the points of the geometric objects
*
*		Parameters:		
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
void MLT_xComputeAllNormals ( )
{
	int i, j, k, l, iCurrent=0, m=0, xIndex, n=0, p=0, n1, n3;
	MTH3D_tdstVector stNormalResult, *p_stVertex, *p_stLastVertex;
	MLT_tdstElementIndexedTriangles		*p_stLocalElement;
	MLT_tdstElementFaceMapDescriptors	*p_stLocalElementFMD;
	
	// compute minmax points for each object
	for (i=0; i<g_lGeometricIndex; i++) // for all the objects
	{
		MTH3D_M_vSetVectorElements(&g_hGeometricInFile[i]->stMinPoint, MTH_C_InfinitPlus, MTH_C_InfinitPlus, MTH_C_InfinitPlus);
		MTH3D_M_vSetVectorElements(&g_hGeometricInFile[i]->stMaxPoint, MTH_C_InfinitMinus, MTH_C_InfinitMinus, MTH_C_InfinitMinus);

		MLT_vComputeMinMaxPointWithMatrix(g_hGeometricInFile[i], &g_hGeometricInFile[i]->stMinPoint, &g_hGeometricInFile[i]->stMaxPoint, g_hGeometricInFile[i]->p_stMatrix);
	}

	//compute the face normals for all the objects
	for (i=0; i<g_lGeometricIndex; i++)
	{
		// for all the elements
		for (xIndex=0; xIndex<g_hGeometricInFile[i]->xNbElements; xIndex++)
		{
			// indexed triangle
			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++)
				{
					MLT_xComputeNormalWeightedBySurf 
					(	&stNormalResult, 
						g_hGeometricInFile[i]->d_stListOfPoints + p_stLocalElement->d_stListOfFacesTripled[j].a3_xIndex[0], 
						g_hGeometricInFile[i]->d_stListOfPoints + p_stLocalElement->d_stListOfFacesTripled[j].a3_xIndex[1], 
						g_hGeometricInFile[i]->d_stListOfPoints + p_stLocalElement->d_stListOfFacesTripled[j].a3_xIndex[2]
					);
					p_stLocalElement->d_stListOfFacesNormals[j] = stNormalResult;
				}
			}
			// face map descriptor
			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++)
				{
					MLT_xComputeNormalWeightedBySurf 
					(	&stNormalResult, 
						g_hGeometricInFile[i]->d_stListOfPoints + p_stLocalElementFMD->d_stListOfFacesQuadrupled[j].stFaceTripled.a3_xIndex[0], 
						g_hGeometricInFile[i]->d_stListOfPoints + p_stLocalElementFMD->d_stListOfFacesQuadrupled[j].stFaceTripled.a3_xIndex[1], 
						g_hGeometricInFile[i]->d_stListOfPoints + p_stLocalElementFMD->d_stListOfFacesQuadrupled[j].stFaceTripled.a3_xIndex[2]
					);
					p_stLocalElementFMD->d_stListOfFacesNormals[j] = stNormalResult;
				}
			}
		}
	}
	
	p_stLocalElement = ((MLT_tdstElementIndexedTriangles *)g_hGeometricInFile[0]->d_stListOfElements[0]);

	// for all the objects make some initialization and/or allocation
	for (i=0; i<g_lGeometricIndex; i++) 
	{	
		if ( g_hGeometricInFile[i]->d_stListOfPointsNormals == NULL )
			g_hGeometricInFile[i]->d_stListOfPointsNormals = (MTH3D_tdstVector *)malloc(sizeof(MTH3D_tdstVector *)*g_hGeometricInFile[i]->xNbPoints);

		p_stVertex = g_hGeometricInFile[i]->d_stListOfPointsNormals;
		p_stLastVertex = p_stVertex + g_hGeometricInFile[i]->xNbPoints;
		for ( ; p_stVertex < p_stLastVertex ; p_stVertex ++ )
			MTH3D_M_vNullVector ( p_stVertex );
		
		for (k=0; k<g_hGeometricInFile[i]->xNbPoints; k++)
		{	
			g_hGeometricInFile[i]->p_stFaceIndexes[k].iIndexObj = (int *)malloc(sizeof(int)*200); //malloc(sizeof(int)*(g_lGeometricIndex-1));
			g_hGeometricInFile[i]->p_stFaceIndexes[k].iIndexPoint = (int *)malloc(200*sizeof(int));
			for (m=0; m<200; m++)
			{	g_hGeometricInFile[i]->p_stFaceIndexes[k].iIndexObj[m] = -1;
				g_hGeometricInFile[i]->p_stFaceIndexes[k].iIndexPoint[m] = -1;
			}
		}
	}

	// for all the objects
	for (i=0; i<g_lGeometricIndex; i++) 
	{	
		for (j=i+1; j<g_lGeometricIndex; j++)
		{
			// if the bounding boxes contains common points
			if (MLT_bIntersBoundingBoxes(g_hGeometricInFile[i], g_hGeometricInFile[j])) 
			{	
				for (k=0; k<g_hGeometricInFile[i]->xNbPoints; k++)
				{	
					MTH3D_tdstVector stPoint_ik;

					MLT_xMulMatrixVertex(&stPoint_ik, g_hGeometricInFile[i]->p_stMatrix, &g_hGeometricInFile[i]->d_stListOfPoints[k]);
					
					if (MLT_bPointInBoundingBox(stPoint_ik, g_hGeometricInFile[j]))
					{	
						for (l=0; l<g_hGeometricInFile[j]->xNbPoints; l++)
						{	
							MTH3D_tdstVector stPoint_jl;

							MLT_xMulMatrixVertex(&stPoint_jl, g_hGeometricInFile[j]->p_stMatrix, &g_hGeometricInFile[j]->d_stListOfPoints[l]);

							if (   (fabs(stPoint_ik.xX - stPoint_jl.xX) <= gs_fLim)
								&& (fabs(stPoint_ik.xY - stPoint_jl.xY) <= gs_fLim)
								&& (fabs(stPoint_ik.xZ - stPoint_jl.xZ) <= gs_fLim))
							//the point k from the first object is equal with the point l of the second object
							{	
								p=0;
								if (g_hGeometricInFile[i]->p_stFaceIndexes[k].iIndexObj)
								{	while (g_hGeometricInFile[i]->p_stFaceIndexes[k].iIndexObj[p] != -1) p++;
									g_hGeometricInFile[i]->p_stFaceIndexes[k].iIndexObj[p] = j;
									g_hGeometricInFile[i]->p_stFaceIndexes[k].iIndexPoint[p] = l;
								}
								p=0; 
								if (g_hGeometricInFile[j]->p_stFaceIndexes[l].iIndexObj)
								{	while (g_hGeometricInFile[j]->p_stFaceIndexes[l].iIndexObj[p] != -1) p++;
									g_hGeometricInFile[j]->p_stFaceIndexes[l].iIndexObj[p] = i;
									g_hGeometricInFile[j]->p_stFaceIndexes[l].iIndexPoint[p] = k;
								}
							}
						} // !!!!!
						n = 0;
						while (g_hGeometricInFile[i]->p_stFaceIndexes[k].iIndexPoint[n] != -1)
						{
							m = g_hGeometricInFile[i]->p_stFaceIndexes[k].iIndexPoint[n];
							p = g_hGeometricInFile[i]->p_stFaceIndexes[k].iIndexObj[n];
							n1= 0;
							while (g_hGeometricInFile[p]->p_stFaceIndexes[m].iIndexElem[n1] != -1) 
							{	
								if (g_hGeometricInFile[p]->d_xListOfElementsTypes[g_hGeometricInFile[p]->p_stFaceIndexes[m].iIndexElem[n1]] == MLT_C_xElementIndexedTriangles)
								{	
									p_stLocalElement = ((MLT_tdstElementIndexedTriangles *)g_hGeometricInFile[p]->d_stListOfElements[g_hGeometricInFile[p]->p_stFaceIndexes[m].iIndexElem[n1]]);
									MTH3D_M_vAddVector ( g_hGeometricInFile[i]->d_stListOfPointsNormals + k, 
										g_hGeometricInFile[i]->d_stListOfPointsNormals + k, 
										&p_stLocalElement->d_stListOfFacesNormals[g_hGeometricInFile[p]->p_stFaceIndexes[m].iIndex[n1]] );
									MTH3D_M_vNormalizeVector ( &p_stLocalElement->d_stListOfFacesNormals[g_hGeometricInFile[p]->p_stFaceIndexes[m].iIndex[n1]], 
										&p_stLocalElement->d_stListOfFacesNormals[g_hGeometricInFile[p]->p_stFaceIndexes[m].iIndex[n1]]);
								}
								else if (g_hGeometricInFile[p]->d_xListOfElementsTypes[g_hGeometricInFile[p]->p_stFaceIndexes[m].iIndexElem[n1]] == MLT_C_xElementFaceMapDescriptors)
								{	
									p_stLocalElementFMD = ((MLT_tdstElementFaceMapDescriptors *)g_hGeometricInFile[p]->d_stListOfElements[g_hGeometricInFile[p]->p_stFaceIndexes[m].iIndexElem[n1]]);
									MTH3D_M_vAddVector ( g_hGeometricInFile[i]->d_stListOfPointsNormals + k, 
										g_hGeometricInFile[i]->d_stListOfPointsNormals + k, 
										&p_stLocalElementFMD->d_stListOfFacesNormals[g_hGeometricInFile[p]->p_stFaceIndexes[m].iIndex[n1]] );
									MTH3D_M_vNormalizeVector ( &p_stLocalElementFMD->d_stListOfFacesNormals[g_hGeometricInFile[p]->p_stFaceIndexes[m].iIndex[n1]], 
										&p_stLocalElementFMD->d_stListOfFacesNormals[g_hGeometricInFile[p]->p_stFaceIndexes[m].iIndex[n1]]);
								}
								n1++;
							}

							n3=0;
							while (g_hGeometricInFile[i]->p_stFaceIndexes[k].iIndexElem[n3] != -1) 
							{	
								if (g_hGeometricInFile[i]->d_xListOfElementsTypes[g_hGeometricInFile[i]->p_stFaceIndexes[k].iIndexElem[n3]] == MLT_C_xElementIndexedTriangles)
								{	
									p_stLocalElement = ((MLT_tdstElementIndexedTriangles *)g_hGeometricInFile[i]->d_stListOfElements[g_hGeometricInFile[i]->p_stFaceIndexes[k].iIndexElem[n3]]);
									MTH3D_M_vAddVector ( g_hGeometricInFile[p]->d_stListOfPointsNormals + m, 
										g_hGeometricInFile[p]->d_stListOfPointsNormals + m, 
										&p_stLocalElement->d_stListOfFacesNormals[g_hGeometricInFile[i]->p_stFaceIndexes[k].iIndex[n3]] );
									MTH3D_M_vNormalizeVector ( &p_stLocalElement->d_stListOfFacesNormals[g_hGeometricInFile[i]->p_stFaceIndexes[k].iIndex[n3]], 
										&p_stLocalElement->d_stListOfFacesNormals[g_hGeometricInFile[i]->p_stFaceIndexes[k].iIndex[n3]]);
								}
								else if (g_hGeometricInFile[i]->d_xListOfElementsTypes[g_hGeometricInFile[i]->p_stFaceIndexes[k].iIndexElem[n3]] == MLT_C_xElementFaceMapDescriptors)
								{	
									p_stLocalElementFMD = ((MLT_tdstElementFaceMapDescriptors *)g_hGeometricInFile[i]->d_stListOfElements[g_hGeometricInFile[i]->p_stFaceIndexes[k].iIndexElem[n3]]);
									MTH3D_M_vAddVector ( g_hGeometricInFile[p]->d_stListOfPointsNormals + m, 
										g_hGeometricInFile[p]->d_stListOfPointsNormals + m, 
										&p_stLocalElementFMD->d_stListOfFacesNormals[g_hGeometricInFile[i]->p_stFaceIndexes[k].iIndex[n3]] );
									MTH3D_M_vNormalizeVector ( &p_stLocalElementFMD->d_stListOfFacesNormals[g_hGeometricInFile[i]->p_stFaceIndexes[k].iIndex[n3]], 
										&p_stLocalElementFMD->d_stListOfFacesNormals[g_hGeometricInFile[i]->p_stFaceIndexes[k].iIndex[n3]]);
								}
								n3++;
							}
							n++;
						}
					}
				}
			}
		}

		for (k=0; k<g_hGeometricInFile[i]->xNbPoints; k++)
		{	
			n = 0;
			while(g_hGeometricInFile[i]->p_stFaceIndexes[k].iIndex[n] != -1)
			{	
				if (g_hGeometricInFile[i]->d_xListOfElementsTypes[g_hGeometricInFile[i]->p_stFaceIndexes[k].iIndexElem[n]] == MLT_C_xElementIndexedTriangles)
				{	
					p_stLocalElement = ((MLT_tdstElementIndexedTriangles *)g_hGeometricInFile[i]->d_stListOfElements[g_hGeometricInFile[i]->p_stFaceIndexes[k].iIndexElem[n]]);
					MTH3D_M_vAddVector (g_hGeometricInFile[i]->d_stListOfPointsNormals+k, 
						g_hGeometricInFile[i]->d_stListOfPointsNormals+k, 
						&p_stLocalElement->d_stListOfFacesNormals[g_hGeometricInFile[i]->p_stFaceIndexes[k].iIndex[n]] );

					if ((p_stLocalElement->d_stListOfFacesNormals[g_hGeometricInFile[i]->p_stFaceIndexes[k].iIndex[n]].xX == 0) &&
						(p_stLocalElement->d_stListOfFacesNormals[g_hGeometricInFile[i]->p_stFaceIndexes[k].iIndex[n]].xY == 0) &&
						(p_stLocalElement->d_stListOfFacesNormals[g_hGeometricInFile[i]->p_stFaceIndexes[k].iIndex[n]].xZ == 0))
					{	p_stLocalElement->d_stListOfFacesNormals[g_hGeometricInFile[i]->p_stFaceIndexes[k].iIndex[n]].xX = 0.00;
						p_stLocalElement->d_stListOfFacesNormals[g_hGeometricInFile[i]->p_stFaceIndexes[k].iIndex[n]].xY = 0.00;
						p_stLocalElement->d_stListOfFacesNormals[g_hGeometricInFile[i]->p_stFaceIndexes[k].iIndex[n]].xZ = -1.00;
					}
					else
						MTH3D_M_vNormalizeVector ( &p_stLocalElement->d_stListOfFacesNormals[g_hGeometricInFile[i]->p_stFaceIndexes[k].iIndex[n]], 
							&p_stLocalElement->d_stListOfFacesNormals[g_hGeometricInFile[i]->p_stFaceIndexes[k].iIndex[n]]);
				}
				else if (g_hGeometricInFile[i]->d_xListOfElementsTypes[g_hGeometricInFile[i]->p_stFaceIndexes[k].iIndexElem[n]] == MLT_C_xElementIndexedTriangles)
				{	
					p_stLocalElementFMD = ((MLT_tdstElementFaceMapDescriptors *)g_hGeometricInFile[i]->d_stListOfElements[g_hGeometricInFile[i]->p_stFaceIndexes[k].iIndexElem[n]]);
					MTH3D_M_vAddVector (g_hGeometricInFile[i]->d_stListOfPointsNormals+k, 
						g_hGeometricInFile[i]->d_stListOfPointsNormals+k, 
						&p_stLocalElementFMD->d_stListOfFacesNormals[g_hGeometricInFile[i]->p_stFaceIndexes[k].iIndex[n]] );
						MTH3D_M_vNormalizeVector ( &p_stLocalElementFMD->d_stListOfFacesNormals[g_hGeometricInFile[i]->p_stFaceIndexes[k].iIndex[n]], 
							&p_stLocalElementFMD->d_stListOfFacesNormals[g_hGeometricInFile[i]->p_stFaceIndexes[k].iIndex[n]]);
				}
				n++;								
			}
		}

		p_stVertex = g_hGeometricInFile[i]->d_stListOfPointsNormals;
		p_stLastVertex = p_stVertex + g_hGeometricInFile[i]->xNbPoints;
		for ( ; p_stVertex < p_stLastVertex ; p_stVertex ++ )
		{	
			if ( MTH3D_M_bIsNullVector( p_stVertex) )
				MTH3D_M_vSetVectorElements ( p_stVertex, MTH_C_ZERO, MTH_C_ZERO, MTH_C_ONE)
			else
				MTH3D_M_vNormalizeVector ( p_stVertex, p_stVertex );
		}
	}

	for (i=0; i<g_lGeometricIndex; i++) 
	{	
		for (k=0; k<g_hGeometricInFile[i]->xNbPoints; k++)
		{	
			if (g_hGeometricInFile[i]->p_stFaceIndexes[k].iIndexObj) 
				free(g_hGeometricInFile[i]->p_stFaceIndexes[k].iIndexObj);
			if (g_hGeometricInFile[i]->p_stFaceIndexes[k].iIndexPoint) 
				free(g_hGeometricInFile[i]->p_stFaceIndexes[k].iIndexPoint);
		}
		free(g_hGeometricInFile[i]->p_stFaceIndexes);
	}
}


/****************************************************************************
*		Description:	get the index of the faces for all the points of a geometric object
*
*		Parameters:		p_stObj	: geometric object
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
void MLT_vIndexFace (MLT_tdstGeometricObject *p_stObj)
{
	int									i, xIndex, j=0, k;
	MLT_tdstElementIndexedTriangles		*p_stLocalElement;
	MLT_tdstElementFaceMapDescriptors	*p_stLocalElementFMD;

	p_stObj->p_stFaceIndexes = (MLT_tdstVector *)malloc(sizeof(MLT_tdstVector) * p_stObj->xNbPoints);
	for (k=0; k<p_stObj->xNbPoints; k++)
	{	
		for (i=0; i<100; i++)
		{	
			p_stObj->p_stFaceIndexes[k].iIndexElem[i] = -1;	
			p_stObj->p_stFaceIndexes[k].iIndex[i] = -1;	
		}
		for (xIndex=0; xIndex<p_stObj->xNbElements; xIndex++)
		{	
			if ( p_stObj->d_xListOfElementsTypes[xIndex] == MLT_C_xElementIndexedTriangles )
			{	
				p_stLocalElement = ((MLT_tdstElementIndexedTriangles *)p_stObj->d_stListOfElements[xIndex]);
				for (i=0; i<p_stLocalElement->xNbFaces; i++)
				{
					if ((k == p_stLocalElement->d_stListOfFacesTripled[i].a3_xIndex[0]) || 
						(k == p_stLocalElement->d_stListOfFacesTripled[i].a3_xIndex[1]) || 
						(k == p_stLocalElement->d_stListOfFacesTripled[i].a3_xIndex[2]))		
					{	
						p_stObj->p_stFaceIndexes[k].iIndexElem[j] = xIndex;	
						p_stObj->p_stFaceIndexes[k].iIndex[j] = i;	
						j++;
					}
				}
			}
			else if (p_stObj->d_xListOfElementsTypes[xIndex] == MLT_C_xElementFaceMapDescriptors )
			{	
				p_stLocalElementFMD = ((MLT_tdstElementFaceMapDescriptors *)p_stObj->d_stListOfElements[xIndex]);
				for (i=0; i<p_stLocalElementFMD->xNbFaces; i++)
				{
					if ((k == p_stLocalElementFMD->d_stListOfFacesQuadrupled[i].stFaceTripled.a3_xIndex[0]) || 
						(k == p_stLocalElementFMD->d_stListOfFacesQuadrupled[i].stFaceTripled.a3_xIndex[1]) || 
						(k == p_stLocalElementFMD->d_stListOfFacesQuadrupled[i].stFaceTripled.a3_xIndex[2]))		
					{	
						p_stObj->p_stFaceIndexes[k].iIndexElem[j] = xIndex;	
						p_stObj->p_stFaceIndexes[k].iIndex[j] = i;	
						j++;
					}
				}
			}
		}
		j = 0;
	}
}



/****************************************************************************
*		Description:	compute the normals for the object
*
*		Parameters:		p_stObj	: geometric object
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
void MLT_xComputeObjectNormals ( MLT_tdstGeometricObject *p_stObj )
{
	MTH3D_tdstVector					*p_stVertex, *p_stLastVertex, stNormalResult;
	MLT_tdstTripledIndex				*p_stITStart, *p_stITLast;
	MLT_tdstElementIndexedTriangles		*p_stLocalElement;
	MLT_tdstFaceMapTriangle				*p_stITStartFMD, *p_stITLastFMD;
	MLT_tdstElementFaceMapDescriptors	*p_stLocalElementFMD;
	ACP_tdxIndex						xIndex, xTriangleIndex;
  
#ifdef USE_ALTIMAPS
	if ( p_stObj->d_xListOfElementsTypes[0] == MLT_C_xElementAltimap )
		MLT_xComputeAltimapObjectNormals( p_stObj );
#endif
  
	if ( p_stObj->xNbPoints == 0 )
		return;

	if ( p_stObj->d_stListOfPointsNormals == NULL )
	    p_stObj->d_stListOfPointsNormals = (MTH3D_tdstVector *)malloc(sizeof(MTH3D_tdstVector *)*p_stObj->xNbPoints);

	p_stVertex = p_stObj->d_stListOfPointsNormals;
	p_stLastVertex = p_stVertex + p_stObj->xNbPoints;
	for ( ; p_stVertex < p_stLastVertex ; p_stVertex ++ )
		MTH3D_M_vNullVector ( p_stVertex );

	for ( xIndex = 0 ; xIndex < p_stObj->xNbElements ; xIndex ++ )
	{
		if ( p_stObj->d_xListOfElementsTypes[xIndex] == MLT_C_xElementIndexedTriangles )
		{
			p_stLocalElement = ((MLT_tdstElementIndexedTriangles *)p_stObj->d_stListOfElements[xIndex]);

			p_stITStart = p_stLocalElement->d_stListOfFacesTripled;
			p_stITLast = p_stITStart + p_stLocalElement->xNbFaces;
			for ( xTriangleIndex = 0 ; p_stITStart < p_stITLast ; p_stITStart ++ , xTriangleIndex ++ )
			{
				MLT_xComputeNormalWeightedBySurf 
					(	&stNormalResult, 
						p_stObj->d_stListOfPoints + p_stITStart->a3_xIndex[0], 
						p_stObj->d_stListOfPoints + p_stITStart->a3_xIndex[1], 
						p_stObj->d_stListOfPoints + p_stITStart->a3_xIndex[2]
					);
				p_stLocalElement->d_stListOfFacesNormals[xTriangleIndex] = stNormalResult;

				if ( !MTH3D_M_bIsNullVector(&stNormalResult) )
				{
					MTH3D_M_vAddVector ( p_stObj->d_stListOfPointsNormals + p_stITStart->a3_xIndex[0], p_stObj->d_stListOfPointsNormals + p_stITStart->a3_xIndex[0], &stNormalResult );
					MTH3D_M_vAddVector ( p_stObj->d_stListOfPointsNormals + p_stITStart->a3_xIndex[1], p_stObj->d_stListOfPointsNormals + p_stITStart->a3_xIndex[1], &stNormalResult );
					MTH3D_M_vAddVector ( p_stObj->d_stListOfPointsNormals + p_stITStart->a3_xIndex[2], p_stObj->d_stListOfPointsNormals + p_stITStart->a3_xIndex[2], &stNormalResult );
					MTH3D_M_vNormalizeVector ( &p_stLocalElement->d_stListOfFacesNormals[xTriangleIndex], &p_stLocalElement->d_stListOfFacesNormals[xTriangleIndex] );
				}
			}
		}		
		else if ( p_stObj->d_xListOfElementsTypes[xIndex] == MLT_C_xElementFaceMapDescriptors )
		{
			p_stLocalElementFMD = ((MLT_tdstElementFaceMapDescriptors *)p_stObj->d_stListOfElements[xIndex]);
			
			p_stITStartFMD = p_stLocalElementFMD->d_stListOfFacesQuadrupled;
			p_stITLastFMD = p_stITStartFMD + p_stLocalElementFMD->xNbFaces;
			for ( xTriangleIndex=0 ; p_stITStartFMD < p_stITLastFMD ; p_stITStartFMD ++ , xTriangleIndex ++ )
			{
				MLT_xComputeNormalWeightedBySurf 
					(	&stNormalResult, 
						p_stObj->d_stListOfPoints + p_stITStartFMD->stFaceTripled.a3_xIndex[0],
						p_stObj->d_stListOfPoints + p_stITStartFMD->stFaceTripled.a3_xIndex[1],
                        p_stObj->d_stListOfPoints + p_stITStartFMD->stFaceTripled.a3_xIndex[2] 
					);
				p_stLocalElementFMD->d_stListOfFacesNormals[xTriangleIndex] = stNormalResult;

				if ( !MTH3D_M_bIsNullVector( &stNormalResult ) )
				{
					MTH3D_M_vAddVector ( p_stObj->d_stListOfPointsNormals + p_stITStartFMD->stFaceTripled.a3_xIndex[0], p_stObj->d_stListOfPointsNormals + p_stITStartFMD->stFaceTripled.a3_xIndex[0], &stNormalResult );
					MTH3D_M_vAddVector ( p_stObj->d_stListOfPointsNormals + p_stITStartFMD->stFaceTripled.a3_xIndex[1], p_stObj->d_stListOfPointsNormals + p_stITStartFMD->stFaceTripled.a3_xIndex[1], &stNormalResult );
					MTH3D_M_vAddVector ( p_stObj->d_stListOfPointsNormals + p_stITStartFMD->stFaceTripled.a3_xIndex[2], p_stObj->d_stListOfPointsNormals + p_stITStartFMD->stFaceTripled.a3_xIndex[2], &stNormalResult );
					MTH3D_M_vNormalizeVector ( &p_stLocalElementFMD->d_stListOfFacesNormals[xTriangleIndex], &p_stLocalElementFMD->d_stListOfFacesNormals[xTriangleIndex] );
				}
			}
		}
	}

	p_stVertex = p_stObj->d_stListOfPointsNormals;
	p_stLastVertex = p_stVertex + p_stObj->xNbPoints;
	for ( ; p_stVertex < p_stLastVertex ; p_stVertex ++ )
	{
		if ( MTH3D_M_bIsNullVector( p_stVertex) )
			MTH3D_M_vSetVectorElements ( p_stVertex, MTH_C_ZERO, MTH_C_ZERO, MTH_C_ONE)
		else
			MTH3D_M_vNormalizeVector ( p_stVertex, p_stVertex );
	}
}


/****************************************************************************
*		Description:	compute the normals for the altimap object
*
*		Parameters:		p_stObj	: geometric object
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
#ifdef USE_ALTIMAPS
void MLT_xComputeAltimapObjectNormals ( MLT_tdstGeometricObject *p_stObj )
{
	MLT_tdstElementAltimap  *p_stAltimap;
	ACP_tdxIndex            xI, xJ, xK, xL, xA, xB, xC, xSquareBLVertex;
	MTH3D_tdstVector        *d_stPoints, stOriginNoZ;
	MLT_tdstAltimapSquare   *stSquare; 
	unsigned char           ucType;

	p_stAltimap = (MLT_tdstElementAltimap *) p_stObj->d_stListOfElements[0];

	d_stPoints = (MTH3D_tdstVector *)malloc(( p_stAltimap->xWidth+1 ) * ( p_stAltimap->xDepth+1 ) * sizeof(MTH3D_tdstVector));

	MTH3D_M_vSetVectorElements( &stOriginNoZ, p_stAltimap->stOrigin.xX, p_stAltimap->stOrigin.xY, MTH_C_ZERO );
	for (xJ = 0, xK = 0; xJ < p_stAltimap->xDepth+1; xJ++)
	{
		for(xI = 0 ; xI< p_stAltimap->xWidth+1; xI++, xK ++)
		{
			//--- For each Vertex, sets the coordinates in its super object axis system
			MTH3D_M_vNullVector(p_stAltimap->d_stPointNormals + xK);
			(d_stPoints + xK) -> xX = MTH_M_xRealToLong(xI) * p_stAltimap->xDeltaX;
			(d_stPoints + xK) -> xY = MTH_M_xRealToLong(xJ) * p_stAltimap->xDeltaY;
			(d_stPoints + xK) -> xZ = p_stAltimap->d_xHeight[xK];
			MTH3D_M_vAddVector(d_stPoints + xK, d_stPoints + xK, &stOriginNoZ);
		}
	}

	for(xJ = 0, xK = 0 ; xJ < p_stAltimap->xDepth ; xJ++)
	{
		for(xI = 0 ; xI < p_stAltimap->xWidth; xI++, xK++)
		{
			stSquare        = (p_stAltimap->d_stSquare) + xK;
			xL              = stSquare->xFaceIndex;
			ucType          = stSquare->ucType;
			xSquareBLVertex = xJ * (p_stAltimap->xWidth + 1) + xI;

			while( ucType )
			{
				if( ucType & MLT_C_xAltiSquareTopRight )
				{
					xA = xSquareBLVertex + 1;
					xB = xSquareBLVertex + 1 + p_stAltimap->xWidth + 1;
					xC = xSquareBLVertex + p_stAltimap->xWidth + 1;
					ucType &= ~MLT_C_xAltiSquareTopRight;
					ucType <<= 4;
				}
				else if( ucType & MLT_C_xAltiSquareBottomLeft )
				{
					xA = xSquareBLVertex;
					xB = xSquareBLVertex + 1;
					xC = xSquareBLVertex + p_stAltimap->xWidth + 1;
					ucType = 0;
				}
				else if( (ucType >> 4) & MLT_C_xAltiSquareBottomLeft )
				{
					xA = xSquareBLVertex;
					xB = xSquareBLVertex + 1;
					xC = xSquareBLVertex + p_stAltimap->xWidth + 1;
					ucType = 0;
					xL++;
				}
				else if( ucType & MLT_C_xAltiSquareTopLeft )
				{
					xA = xSquareBLVertex;
					xB = xSquareBLVertex + 1 + p_stAltimap->xWidth + 1;
					xC = xSquareBLVertex + p_stAltimap->xWidth + 1;
					ucType &= ~MLT_C_xAltiSquareTopLeft;
					ucType <<= 4;
				}
				else if( ucType & MLT_C_xAltiSquareBottomRight )
				{
					xA = xSquareBLVertex;
					xB = xSquareBLVertex + 1;
					xC = xSquareBLVertex + 1 + p_stAltimap->xWidth + 1;
					ucType = 0;
				}
				else if( (ucType >> 4) & MLT_C_xAltiSquareBottomRight )
				{
					xA = xSquareBLVertex;
					xB = xSquareBLVertex + 1;
					xC = xSquareBLVertex + 1 + p_stAltimap->xWidth + 1;
					ucType = 0;
					xL++;
				}
				else
					break;

				MLT_xComputeNormalWeightedBySurf( &(p_stAltimap->d_stFaceNormals[xL]), d_stPoints + xA, d_stPoints + xB, d_stPoints + xC );
				MTH3D_M_vAddVector( p_stAltimap->d_stPointNormals + xA, p_stAltimap->d_stPointNormals + xA, &(p_stAltimap->d_stFaceNormals[xL]) );
				MTH3D_M_vAddVector( p_stAltimap->d_stPointNormals + xB, p_stAltimap->d_stPointNormals + xB, &(p_stAltimap->d_stFaceNormals[xL]) );
				MTH3D_M_vAddVector( p_stAltimap->d_stPointNormals + xC, p_stAltimap->d_stPointNormals + xC, &(p_stAltimap->d_stFaceNormals[xL]) );
 
				MTH3D_M_vNormalizeVector ( &(p_stAltimap->d_stFaceNormals[xL]), &(p_stAltimap->d_stFaceNormals[xL]) );       
			}  
		}

		for(xJ = 0, xK = 0; xJ < p_stAltimap->xDepth+1; xJ++)
		{
			for(xI = 0; xI< p_stAltimap->xWidth+1; xI++, xK++)
			{
				if( MTH_M_bEqualZero( MTH3D_M_xNormVector( p_stAltimap->d_stPointNormals + xK ) ) )
					MTH3D_M_vSetVectorElements( p_stAltimap->d_stPointNormals + xK, MTH_C_ZERO, MTH_C_ZERO, MTH_C_ONE )
				else 
					MTH3D_M_vNormalizeVector( p_stAltimap->d_stPointNormals + xK, p_stAltimap->d_stPointNormals + xK )
			}
		}
		free(d_stPoints);
	}
	return;
}
#endif //USE_ALTIMAPS


/****************************************************************************
*		Description:	compute normal
*
*		Parameters:		p_stPResult	: result vector
*						p_stPA		: first point
*						p_stPB		: second point
*						p_stPC		: third point
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
void MLT_xComputeNormalWeightedBySurf ( MTH3D_tdstVector *p_stPResult, MTH3D_tdstVector *p_stPA, MTH3D_tdstVector *p_stPB, MTH3D_tdstVector *p_stPC )
{
	MTH3D_tdstVector stEdgeAB, stEdgeAC;

	MTH3D_M_vSubVector ( &stEdgeAB, p_stPB, p_stPA );
	MTH3D_M_vSubVector ( &stEdgeAC, p_stPC, p_stPA );

	MTH3D_M_vCrossProductVectorWithoutBuffer( p_stPResult, &stEdgeAB, &stEdgeAC );
}




/****************************************************************************
*		Description:	test if the bounding boxes of two geometric objects have common points
*
*		Parameters:		p_stObj1	: first geometric object
*						p_stObj2	: second geometric object
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
BOOL MLT_bIntersBoundingBoxes ( MLT_tdstGeometricObject *p_stObj1, MLT_tdstGeometricObject *p_stObj2 )
{
	if (   (p_stObj2->stMinPoint.xX <= (p_stObj1->stMaxPoint.xX + gs_fLim)) 
		&& (p_stObj2->stMaxPoint.xX >= (p_stObj1->stMinPoint.xX - gs_fLim)) 
		&& (p_stObj2->stMinPoint.xY <= (p_stObj1->stMaxPoint.xY + gs_fLim)) 
		&& (p_stObj2->stMaxPoint.xY >= (p_stObj1->stMinPoint.xY - gs_fLim)) 
		&& (p_stObj2->stMinPoint.xZ <= (p_stObj1->stMaxPoint.xZ + gs_fLim)) 
		&& (p_stObj2->stMaxPoint.xZ >= (p_stObj1->stMinPoint.xZ - gs_fLim))) 
			return TRUE;

	return FALSE;
}

/****************************************************************************
*		Description:	test if the specified point is in the bounding box of the geometric object
*
*		Parameters:		stPoint		: point to test
*						p_stObj		: geometric object
*---------------------------------------------------------------------------
*		Revision date:                                      Author:         
*****************************************************************************/
BOOL MLT_bPointInBoundingBox (MTH3D_tdstVector stPoint, MLT_tdstGeometricObject *p_stObj)
{
	if ((stPoint.xX >= (p_stObj->stMinPoint.xX - gs_fLim)) && (stPoint.xX <= (p_stObj->stMaxPoint.xX + gs_fLim)) &&
		(stPoint.xY >= (p_stObj->stMinPoint.xY - gs_fLim)) && (stPoint.xY <= (p_stObj->stMaxPoint.xY + gs_fLim)) &&
		(stPoint.xZ >= (p_stObj->stMinPoint.xZ - gs_fLim)) && (stPoint.xZ <= (p_stObj->stMaxPoint.xZ + gs_fLim)))
		return TRUE;
	return FALSE; 
}


