/*
0         1         2         3         4         5         6         7
01234567890123456789012345678901234567890123456789012345678901234567890123456789
--------------------------------------------------------------------------------
-- Description : Geometric object collision part
--------------------------------------------------------------------------------
-- Creation date : 22 aug 1996               Author : FPI
--------------------------------------------------------------------------------
*/
 
#include "acp_base.h"
#include "MTH.h"
#include "MEC.h"
#include "GMT.h"
#include "GEO.h"
#include "GLI.h"
 
#include "COL/CollGOCo.h"
 
/*XB 98/09/11*/
#include "PRF.h"
/*End XB*/
 
/* ANNECY AV {*/
#define  C_wDoubleEdge   2
/* END ANNECY AV }*/
 
/*
--------------------------------------------------------------------------------
-- Description : Global variables
--------------------------------------------------------------------------------
*/
 
/* cas de collision */
/* Global Collisiosn Array */
COL_tdstCollisionCase COL_g_stCollisionCase [COL_C_xMaxNumberOfCollisions];

/* Pointer to Beginning of Array to be computed
/* Usually COL_g_stCollisionCaseReal = COL_g_stCollisionCase
/* but it can be usefull to compute collisions in two steps
/* then COL_g_stCollisionCaseReal = COL_g_stCollisionCase + Number of collisions computed in first step */
COL_tdstCollisionCase *COL_g_stCollisionCaseReal = COL_g_stCollisionCase;
  
COL_tdstGVForCollision COL_g_stGVForCol;

long COL_g_lNbElementsInTable = COL_C_xMaxNumberOfCollisions; /* Number of elements added in Collision Array */

/* size free for collide array 
/* usually COL_g_lMaxNumberOfCollisions =  COL_C_xMaxNumberOfCollisions
/* but it can be usefull to compute collisions in two steps
/* then  COL_g_lMaxNumberOfCollisions =  COL_C_xMaxNumberOfCollisions - Number of collisions computed in first step */

extern long COL_g_lMaxNumberOfCollisions; 

/*
--------------------------------------------------------------------------------
-- Description : Initialize the collision table
--------------------------------------------------------------------------------
-- Creation date : 23 oct 1996               Author : FPI
--------------------------------------------------------------------------------
*/

//#define COL_fn_vInitCollisionTable() COL_g_lNbElementsInTable = 0

/* init de la table de collision */
/* passer en macro */
//void COL_fn_vInitCollisionTable ( void )
//{
	/* Anthony */
	/*COL_tdstCollisionCase * p;
	COL_tdstCollisionCase * end;*/

	/* opti par Yann Le Guyader 07/99 */
	//if (COL_g_lNbElementsInTable)
	//{
		
		/*end = &COL_g_stCollisionCaseReal[COL_g_lNbElementsInTable];*/
//		COL_g_lNbElementsInTable = 0;
	//}
	/*else	return;*/
	
	
	/*for (p = COL_g_stCollisionCaseReal; p < end ; p ++)
	{
		/* temps de collision */
		//p -> xCollisionTime = MTH_C_2;	
	//}*/
//}
 
/*
--------------------------------------------------------------------------------
-- Description : Add a collision case in the collision table
--------------------------------------------------------------------------------
-- Creation date : 06 oct 1997               Author : FPI
--------------------------------------------------------------------------------
*/
 
/* ajout dans la table de collision */
void COL_fn_vAddInStaticCollisionTable (MTH_tdxReal _xT,
                                        MTH3D_tdstVector *_p_stTranslation,
                                        MTH3D_tdstVector *_p_stHit,
                                        MTH3D_tdstVector *_p_stNormal,
                                        GMT_tdxHandleToGameMaterial _hDynMat,
                                        GMT_tdxHandleToGameMaterial _hStatMat,
                                        ACP_tdxIndex _xDynamicGeomEntity,
                                        ACP_tdxIndex _xStaticGeomEntity,
                                        void *_p_vParameter1,
                                        short _sParameter2,
                                        MTH3D_tdstVector *_p_stMovement,
                                        MTH_tdxReal      _xSphereRadius,
                                        MTH3D_tdstVector * _p_stEndPosition)
{
#ifdef USE_PROFILER
		/*XB 98/09/11*/
		static long s_l_MaxNbCollisions=0;
		/*End XB*/
#endif /* USE_PROFILER */
    long            i;
    COL_tdstCollisionCase * p_stCollisionCase;

/* jt 120599 */
	GMT_tdxHandleToCollideMaterial hCollideMaterial;
/* end jt 120599 */ 

#define M_bIsVectorsEqualWithEpsilon( VectA, VectB, Eps ) \
        ( MTH_M_bEqualWithEpsilon( MTH3D_M_xGetXofVector( VectA ), MTH3D_M_xGetXofVector( VectB ), Eps ) && \
          MTH_M_bEqualWithEpsilon( MTH3D_M_xGetYofVector( VectA ), MTH3D_M_xGetYofVector( VectB ), Eps ) && \
          MTH_M_bEqualWithEpsilon( MTH3D_M_xGetZofVector( VectA ), MTH3D_M_xGetZofVector( VectB ), Eps ) )
 

	/* jt 120599 : no registration if hand type zone hurt something else than a hang material type */
	hCollideMaterial = GMT_fn_hGetCollideMaterial (_hDynMat);

	/* zone has a collide material with hand type */
	if ( (hCollideMaterial!=GMT_C_InvalidCollideMaterial) && (GMT_fn_hGetCollideMaterialIdentifier(hCollideMaterial)&(1<<3)) )
	{
		/* this is a ground */	
		hCollideMaterial = GMT_fn_hGetCollideMaterial (_hStatMat);
		if ( (hCollideMaterial==GMT_C_InvalidCollideMaterial) || ((GMT_fn_hGetCollideMaterialIdentifier(hCollideMaterial)&4)!=4) )
			/* the ground hasn't hand type material */
			return;
	}
	/* end jt 120599 */

    if (_xStaticGeomEntity == COL_C_xHighEdgeEntity ||
        _xStaticGeomEntity == COL_C_xLowEdgeEntity)  /* The function can be called twice for the same edge : we have to detect this*/
    {
        /* anthony */
		/*p_stCollisionCase = COL_g_stCollisionCase;*/
		p_stCollisionCase = COL_g_stCollisionCaseReal;

		for (i = 0 ; i < COL_g_lNbElementsInTable ; i ++)
        {
           
            {
                /* If the collision with the edge is already registered, we do nothing*/
                if (p_stCollisionCase -> xStaticGeomEntity == _xStaticGeomEntity &&
                    p_stCollisionCase -> p_vParameter1 == _p_vParameter1 &&    /* Is it the same super object ?*/
                    MTH_M_bEqualWithEpsilon (p_stCollisionCase -> xCollisionTime , _xT , 0.001) &&
                    M_bIsVectorsEqualWithEpsilon (& p_stCollisionCase -> stCollisionPoint  , _p_stHit    , 0.005) &&
                    M_bIsVectorsEqualWithEpsilon (& p_stCollisionCase -> stCollisionNormal , _p_stNormal , 0.005))
				{
					/* Say that the edge is present twice*/
					p_stCollisionCase -> sParameter2 |= C_wDoubleEdge;
					return;
				}
            }
             

            p_stCollisionCase ++;
        }
    }
 
	/* anthony */
    /*p_stCollisionCase = COL_g_stCollisionCase;*/
	p_stCollisionCase = COL_g_stCollisionCaseReal;
    
	for (i = 0 ; i < COL_g_lNbElementsInTable ; i ++)
    {
		if(MTH_M_bEqualWithEpsilon(_xT, p_stCollisionCase->xCollisionTime, 0.0001f))
		{
			
			if(_p_stNormal->xX < p_stCollisionCase->stCollisionNormal.xX)
			{
				int iNumberOfElementToCopy  = 0;
				COL_tdstCollisionCase * p   = p_stCollisionCase;
				/*COL_tdstCollisionCase * end = COL_g_stCollisionCase +  COL_g_lNbElementsInTable ;*/ /* anthony */
				COL_tdstCollisionCase * end = COL_g_stCollisionCaseReal +  COL_g_lNbElementsInTable ;

				while (p ++ < end) iNumberOfElementToCopy ++;
				/* Not to go over array Boudary in memmove*/
				if (p == (COL_g_stCollisionCase + (COL_C_xMaxNumberOfCollisions+1))) iNumberOfElementToCopy --; 

				if (iNumberOfElementToCopy )
					memmove (p_stCollisionCase + 1 , p_stCollisionCase , iNumberOfElementToCopy * sizeof (COL_g_stCollisionCase [0]));

				break;
			}
		}
		else
		{
			if (_xT < p_stCollisionCase -> xCollisionTime)
			{
				int iNumberOfElementToCopy  = 0;
				COL_tdstCollisionCase * p   = p_stCollisionCase;
				/*COL_tdstCollisionCase * end = COL_g_stCollisionCase + COL_g_lNbElementsInTable ;*/ /* anthony */
				COL_tdstCollisionCase * end = COL_g_stCollisionCaseReal +  COL_g_lNbElementsInTable ;

				/* Not to go over array Boudary in memmove*/
				while (p ++ < end) iNumberOfElementToCopy ++;
				if (p == (COL_g_stCollisionCase + (COL_C_xMaxNumberOfCollisions + 1))) iNumberOfElementToCopy --;

				if (iNumberOfElementToCopy)
					memmove (p_stCollisionCase + 1 , p_stCollisionCase , iNumberOfElementToCopy * sizeof (COL_g_stCollisionCase [0]));
				break;
			}
			
		}
        p_stCollisionCase ++;
    }
    //if (i == COL_C_xMaxNumberOfCollisions)  return;    /* The table is full*/
	if (i == COL_g_lMaxNumberOfCollisions)  return; /* anthony */
 
		/*XB 98/09/11*/
#ifdef USE_PROFILER
		if(s_l_MaxNbCollisions<i)
		{
			s_l_MaxNbCollisions=i;
		}
		PRF_fn_vSetIndependantVariable( PRF_C_ulIdpMaxNbCollisions,s_l_MaxNbCollisions );
		PRF_fn_vSetIndependantVariable( PRF_C_ulIdpAllowedNbCollisions,COL_C_xMaxNumberOfCollisions );
#endif /* USE_PROFILER */
		/*End XB*/
    p_stCollisionCase -> xCollisionTime = _xT;
    MTH3D_M_vCopyVector (& p_stCollisionCase -> stTranslation     , _p_stTranslation);
    MTH3D_M_vCopyVector (& p_stCollisionCase -> stCollisionPoint  , _p_stHit);
    MTH3D_M_vCopyVector (& p_stCollisionCase -> stCollisionNormal , _p_stNormal);
    MTH3D_M_vCopyVector (& p_stCollisionCase -> stMovement        , _p_stMovement);
    MTH3D_M_vCopyVector (& p_stCollisionCase -> stEndPosition     , _p_stEndPosition);
    p_stCollisionCase -> hDynamicMaterial   = _hDynMat;
    p_stCollisionCase -> hStaticMaterial    = _hStatMat;
    p_stCollisionCase -> xDynamicGeomEntity = _xDynamicGeomEntity;
    p_stCollisionCase -> xStaticGeomEntity  = _xStaticGeomEntity;
    p_stCollisionCase -> xSphereRadius      = _xSphereRadius;
    p_stCollisionCase -> p_vParameter1      = _p_vParameter1;
    p_stCollisionCase -> sParameter2        = _sParameter2;

   /* p_stCollisionCase -> bCollisionState    = TRUE;*/ /* not usefull anymore */

	if (COL_g_lNbElementsInTable == COL_g_lMaxNumberOfCollisions)
		return;
	else
		COL_g_lNbElementsInTable++;


	
}
 
/*
--------------------------------------------------------------------------------
-- Description : Get of collision result
--------------------------------------------------------------------------------
-- Creation date : 22 apr 1997               Author : FPI
--------------------------------------------------------------------------------
qq*/
 
/* get du resultat des collisions */
 
/*
#ifndef _FIRE_DEADCODE_U64_
ACP_tdxBool COL_fn_bGetResultCollision ( COL_tdstCollisionCase * p_stCollisionCaseDst )
{
  // resultat
  if ( COL_g_stCollisionCase [0] . bCollisionState )
  {
    MTH3D_M_vNormalizeVector (& COL_g_stCollisionCase [0] . stCollisionNormal , & COL_g_stCollisionCase [0] . stCollisionNormal);
    memcpy (p_stCollisionCaseDst , & COL_g_stCollisionCase [0] , sizeof (COL_tdstCollisionCase));
  }
 
  return COL_g_stCollisionCase [0] . bCollisionState;
}
#endif
*/
 
 
/*
--------------------------------------------------------------------------------
-- Description : Get several collision results
--------------------------------------------------------------------------------
-- Creation date : March 3, 1998              Author : Alexis Vaisse
--------------------------------------------------------------------------------
*/
ACP_tdxBool COL_fn_bGetMultipleResultCollision (COL_tdstCollisionCase * * _p_p_stCollisionCaseDst)
{
	ACP_tdxBool temp;
    /* return a pointer to the array of collision case*/
    //* _p_p_stCollisionCaseDst = COL_g_stCollisionCase;
	* _p_p_stCollisionCaseDst = COL_g_stCollisionCaseReal;
    //return COL_g_stCollisionCase [0] . bCollisionState;  /* If there is a collision, the position 0 is not empty*/
	return 	temp = (COL_g_lNbElementsInTable!=0);

/*
    long            i , lNumberOfElementToCopy;
    COL_tdstCollisionCase * p;
 
    p = p_stCollisionCaseDst;
    for (i = 0 ; i < COL_C_xMaxNumberOfCollisions ; i ++)
    {
        (p ++) -> bCollisionState = FALSE;
    }
 
    // Normalize the normals
    p = COL_g_stCollisionCase;
    for (i = 0 ; i < COL_C_xMaxNumberOfCollisions ; i ++)
    {
        if (p -> bCollisionState)
        {
            MTH3D_M_vNormalizeVector (& p -> stCollisionNormal , & p -> stCollisionNormal);
        }
        else break;    // No collision : it is not necessary to use the next elements of the array
 
        p ++;
    }
 
    lNumberOfElementToCopy = (i < COL_C_xMaxNumberOfCollisions) ? (i + 1) : COL_C_xMaxNumberOfCollisions;
 
    // Copy only the minimum
    memcpy (p_stCollisionCaseDst , & COL_g_stCollisionCase , sizeof (COL_tdstCollisionCase) * lNumberOfElementToCopy);
 
    return COL_g_stCollisionCase [0] . bCollisionState;  // If there is a collision, the position 0 is not empty
*/
}
