/*
 *=======================================================================================
 * Name        : MecBhv.c
 * Author      : J Thénoz               Date : 01/05/98
 * Description : Mechanic Behaviours
 *=======================================================================================
 */
 
 
#include "MEC/MECInc.h"
#include "MEC/DnmDynam.h"
#include "MEC/ParsData.h"
#include "MEC/DNMSurSt.h"
#include "MEC/mbase.h"
#include "Extheade.h"
#include "COL.h"
 
 
#include "MEC/MecDef.h"
#include "MEC/MECOpt.h"
#include "MEC/MECBhv.h"
#include "MEC/MECCol.h"
#include "MEC/MECTools.h"
 
#include "PCS.h" /* Physical Collide Set */
#include "SCT.h" /* SeCTor*/
#include "FIL.h" /* SeCTor*/
#include "PRT.h" /* PaRTicules*/
#include "GAM.h" /* GAMe*/

/* Global data*/
long g_lCallCounter = 0;	/* recursive call counter*/
extern long COL_g_lMaxNumberOfCollisions; /* size of collide array */
extern COL_tdstGVForCollision COL_g_stGVForCol;
extern ACP_tdxBool g_bWaterNoCollide;

 

ACP_tdxBool g_bHighSpeed = FALSE;
MTH3D_tdstVector g_stFirstMove;


/* private functions*/
 
void MEC_fn_vCollideBaseMechanic
(
	struct DNM_stDynamics *p_stDynamic,
    HIE_tdxHandleToSuperObject hSupObj,
	long lObstacle,
	DNM_tdstMecObstacle a_stObstacle[COL_C_xMaxNumberOfCollisions],
	MTH_tdxReal xDT
)
{
	POS_tdxHandleToPosition hCurrentMatrix, hPreviousMatrix, hAbsolutePreviousMatrix;
	MTH3D_tdstVector stIncidentVector, stResultantVector;
	MTH3D_tdstVector stNormalizeResultantVector;
	MTH3D_tdstVector stPosition;
	MTH3D_tdstVector *p_stPreviousPosition, *p_stCurrentPosition;
	
	MTH3D_tdstVector stBaseRebound, stBaseSlide;
	MTH3D_tdstVector stVector;
	MTH3D_tdstVector stExtremPosition;
	MTH3D_tdstVector stMoveVector;
	MTH3D_tdstVector stAdjustVector;
	MTH3D_tdstVector stNormalVector;
	MTH3D_tdstVector* p_stNormal;
	MTH_tdxReal xDotProd;
	MTH_tdxReal xNorm;
	MTH_tdxReal xRate;
	MTH_tdxReal xOneMinusRate;
	ACP_tdxBool bWallObstacle, bGroundObstacle;
	ACP_tdxBool bOnlyEdge = TRUE;
	ACP_tdxBool bWater = FALSE;
	ACP_tdxBool bCollisionOk = TRUE;
	MTH_tdxReal xSlide, xRebound;
	MTH_tdxReal xResultantNorm;
	MTH_tdxReal xDotProdMax = MTH_C_MinusONE;
	MTH_tdxReal xDotProdMin = MTH_C_2;
	ACP_tdxBool	bCantKeepWallSpeedZ = FALSE;

	MTH3D_tdstVector stVerticalVector;
	DNM_tdstMecObstacle *p_stObstacle, *p_stBestObstacle, *p_stTmpObstacle, *p_stGroundObstacle, *p_stWaterObstacle;
	long lCounter;
 
	long lBestObstacleCounter;
	long lObstacleCounter;
	long lGroundObstacle;
	long lWaterObstacle;
 
	hPreviousMatrix = DNM_M_p_stDynamicsGetPreviousMatrix (p_stDynamic);
	hCurrentMatrix = DNM_M_p_stDynamicsGetCurrentMatrix (p_stDynamic);
	if (DNM_M_bDynamicsIsComplexSize(p_stDynamic)) hAbsolutePreviousMatrix = DNM_M_p_stDynamicsGetAbsolutePreviousMatrix (p_stDynamic);
	p_stCurrentPosition = POS_fn_p_stGetTranslationVector ( hCurrentMatrix );
	p_stPreviousPosition = POS_fn_p_stGetTranslationVector ( hPreviousMatrix );
 
	/* search obstacle */
	p_stObstacle = NULL;
	p_stBestObstacle = NULL;
	p_stGroundObstacle = NULL;
	p_stWaterObstacle = NULL;
	MTH3D_M_vNullVector (&stNormalVector);
	lWaterObstacle = 0;
 
	if (DNM_M_bDynamicsIsCanFall(p_stDynamic))
	{
		for (lCounter=0; lCounter<lObstacle; lCounter++)
		{
			p_stTmpObstacle = a_stObstacle+lCounter;
			if (MEC_fn_bIsObstacleValid(p_stTmpObstacle))
			{
				if (MEC_fn_bGroundObstacle(p_stDynamic,p_stTmpObstacle) )
					MEC_fn_vInvalidateObstacle (p_stTmpObstacle);
			}
		}
	}
	else
	{
		for (lCounter=0; lCounter<lObstacle && !p_stGroundObstacle; lCounter++)
		{
			p_stTmpObstacle = a_stObstacle+lCounter;
			if (MEC_fn_bIsObstacleValid(p_stTmpObstacle))
			{
				if (MEC_fn_bIsWater(p_stTmpObstacle))
				{
					p_stWaterObstacle = p_stTmpObstacle;
				}
				else if (MEC_fn_bGroundObstacle(p_stDynamic,p_stTmpObstacle) )
				{
					p_stGroundObstacle = p_stTmpObstacle;
					lGroundObstacle = lCounter;
				}
			}
		}
	}
 
	if (p_stGroundObstacle && DNM_M_bDynamicsIsSwim(p_stDynamic))
	{
		bWater = ( ( DNM_M_ulReportGetSurfaceState(&g_stReport) & C_WOT_ulWater ) == C_WOT_ulWater );

		/* if actor collides ground when he swims, it's like if he walks on the ground under water*/
		if (!bWater)
		{
			MEC_fn_vGroundObstacleManagement ( p_stDynamic, hSupObj, xDT );
			DNM_M_ulReportSetSurfaceState (&g_stReport,DNM_M_ulReportGetSurfaceState(&g_stReport)&(~C_WOT_ulWater));
			return;
		}
	}
 
	bOnlyEdge = TRUE;
	for (lCounter=0; lCounter<lObstacle; lCounter++)
	{
		p_stTmpObstacle = a_stObstacle+lCounter;

		if (MEC_fn_bIsObstacleValid(p_stTmpObstacle))
		{
			if ((DNM_M_eObstacleGetType(p_stTmpObstacle) & DNM_ObsType_Mobile) == DNM_ObsType_Mobile)
			{
				if (!p_stBestObstacle)
				{
					p_stBestObstacle = p_stTmpObstacle;
					lBestObstacleCounter = lCounter;
				}
			}
			else  if ( MEC_fn_bIsWater(p_stTmpObstacle) )
			{
				if (!p_stBestObstacle)
				{
					p_stBestObstacle = p_stTmpObstacle;
					lBestObstacleCounter = lCounter;
				}
				if (!lWaterObstacle)
					lWaterObstacle = lCounter;
			}

			xDotProd = MTH3D_M_xDotProductVector (DNM_M_pObstacleGetZoneMove(p_stTmpObstacle),DNM_M_p_stObstacleGetNorm(p_stTmpObstacle));	
			if (MTH_M_bLess(xDotProd,xDotProdMin))
			{
				xDotProdMin = xDotProd;
				p_stObstacle = p_stTmpObstacle;
				lObstacleCounter = lCounter;
			}
			
			if (!MEC_fn_bIsEdge(p_stTmpObstacle))
				bOnlyEdge = FALSE;
		}
	}
 
	if ( !p_stObstacle )
	{
		p_stObstacle = p_stBestObstacle;
		lObstacleCounter = lBestObstacleCounter;
	}
 
	if (!p_stObstacle) 
		return;

	if (p_stGroundObstacle && lGroundObstacle>lObstacleCounter) 
		lObstacleCounter=lGroundObstacle;
 
	if (lWaterObstacle>lObstacleCounter)
		lObstacleCounter = lWaterObstacle;

	MEC_fn_vReportCollision (p_stDynamic,hSupObj,lObstacle,a_stObstacle,lObstacleCounter);
 
	if (!bOnlyEdge||DNM_M_bDynamicsIsCanFall(p_stDynamic))
		p_stNormal = DNM_M_p_stObstacleGetNorm (p_stObstacle);
	else
	{
		p_stNormal = &stNormalVector;
		for (lCounter=0; lCounter<lObstacle; lCounter++)
		{
			p_stTmpObstacle = a_stObstacle+lCounter;
			if (MEC_fn_bIsObstacleValid(p_stTmpObstacle))
				MTH3D_M_vAddVector ( p_stNormal, p_stNormal, DNM_M_p_stObstacleGetNorm(p_stTmpObstacle) );
		}
	
		if (!MTH3D_M_bIsNullVector(p_stNormal))
			MTH3D_M_vNormalizeVector ( p_stNormal, p_stNormal )
		else
			p_stNormal = DNM_M_p_stObstacleGetNorm(p_stObstacle);
	
		if (MEC_fn_bGroundNormal(p_stDynamic,p_stNormal) && (!p_stGroundObstacle ||  (p_stGroundObstacle&&MEC_fn_bIsEdge(p_stGroundObstacle)) ) )
		{
			/* choose best face*/
			for (lCounter=0; lCounter<lObstacle; lCounter++)
			{
				p_stTmpObstacle = a_stObstacle+lCounter;
				if (MEC_fn_bIsObstacleValid(p_stTmpObstacle))
				{
					MTH3D_M_vSubVector (&stVector,DNM_M_p_stObstacleGetContact(p_stTmpObstacle),DNM_M_pObstacleGetZonePosition(p_stTmpObstacle)); 
					MTH3D_M_vAddVector (&stVector, &stVector, DNM_M_pObstacleGetZoneMove(p_stTmpObstacle) );
					if (!MEC_fn_bIsNullVector(&stVector)) MTH3D_M_vNormalizeVector (&stVector,&stVector)
					xDotProd = MTH3D_M_xDotProductVector (&stVector,DNM_M_p_stObstacleGetNorm(p_stTmpObstacle));
					if (MTH_M_bGreater(xDotProd,xDotProdMax))
					{
						xDotProdMax = xDotProd;
						p_stNormal = DNM_M_p_stObstacleGetNorm(p_stTmpObstacle);
					}
				}
			} 
		}
	}
	
	xSlide = MEC_fn_xGetSlide (p_stDynamic,p_stObstacle);
	xRebound = MEC_fn_xGetRebound (p_stDynamic,p_stObstacle);
 
	MTH3D_M_vNullVector (&stNormalizeResultantVector);
	MTH3D_M_vNullVector (&stAdjustVector);
 
	/* type of obstacle */
	MTH3D_M_vSetVectorElements (&stVerticalVector, MTH_C_ZERO, MTH_C_ZERO, MTH_C_ONE);
	xDotProd = MTH3D_M_xDotProductVector ( p_stNormal, &stVerticalVector );
	bWallObstacle = MTH_M_bGreaterEqual (xDotProd,MEC_fn_xWallLimit(p_stDynamic)) && MTH_M_bLessEqual (xDotProd,MEC_fn_xGroundLimit(p_stDynamic));
	bGroundObstacle = MTH_M_bGreaterEqual (xDotProd,MEC_fn_xGroundLimit(p_stDynamic));
 
	/* compute incident vector */
	MTH3D_M_vSubVector ( &stIncidentVector, p_stCurrentPosition, p_stPreviousPosition );
	xNorm = MTH3D_M_xNormVector ( &stIncidentVector );
 
	/* compute new base axis */
	xDotProd = MTH3D_M_xDotProductVector ( &stIncidentVector, p_stNormal );
	MTH3D_M_vMulScalarVector ( &stVector, MTH_M_xNeg(xDotProd), p_stNormal );
	MTH3D_M_vAddVector ( &stBaseSlide, &stIncidentVector, &stVector);
	MTH3D_M_vAddVector ( &stBaseRebound, &stBaseSlide, &stVector);
 
	/* compute resultant vector */
	MTH3D_M_vMulScalarVector ( &stResultantVector, xSlide, &stBaseSlide );
	MTH3D_M_vMulScalarVector ( &stVector, xRebound, &stBaseRebound );
	MTH3D_M_vAddVector ( &stResultantVector, &stResultantVector, &stVector );
	xResultantNorm = MTH3D_M_xNormVector ( &stResultantVector );
	if (!MEC_fn_bIsNullVector(&stResultantVector)) MTH3D_M_vMulScalarVector(&stNormalizeResultantVector,MTH_M_xInv(xResultantNorm),&stResultantVector);
 
	/* adjust resultant vector if control speedz */
	/* only for wall obstacle */
	if (DNM_M_bDynamicsIsKeepWallSpeedZ(p_stDynamic) && bWallObstacle && !MTH_M_bEqual(MTH3D_M_xGetZofVector (&stResultantVector),MTH_C_ZERO))
	{
		MTH_tdxReal xZRate, xZResultantVector;
 
		xZRate = MTH3D_M_xGetZofVector (&stIncidentVector);
		xZResultantVector = MTH3D_M_xGetZofVector (&stResultantVector);
		if (!MTH_M_bEqual(xZResultantVector,MTH_C_ZERO))
		{
			xZRate = MTH_M_xDiv ( xZRate, xZResultantVector );
			if (MTH_M_bGreater(xZRate,MTH_C_MinusONE))
			{
				if ( MTH_M_bLessEqual(xZRate,MTH_C_ONE) )
				{
					/* change norm*/
					MTH3D_M_vMulScalarVector ( &stResultantVector, xZRate, &stResultantVector );
				}
				else
				{
					/* change direction*/
					MTH3D_tdstVector stU, stV, stN, stVector;
					MTH_tdxReal xU, xV, xN, xNorm2, xVExtrem, xVExtrem2;
					
					/* system axis */
					MTH3D_M_vCopyVector ( &stN, p_stNormal );
					MTH3D_M_vCrossProductVector ( &stU, &stVerticalVector, &stN );
					MTH3D_M_vCrossProductVector ( &stV, &stN, &stU );
				
					xU = MTH3D_M_xDotProductVector ( &stResultantVector, &stU );
					xV = MTH3D_M_xDotProductVector ( &stResultantVector, &stV );
					xN = MTH3D_M_xDotProductVector ( &stResultantVector, &stN );
					
					xVExtrem = MTH_M_xDiv ( MTH3D_M_xGetZofVector (&stIncidentVector), MTH3D_M_xGetZofVector (&stV) );
 
					xNorm2 = MTH_M_xAdd ( MTH_M_xMul(xU,xU), MTH_M_xMul(xV,xV) );
					xVExtrem2 = MTH_M_xMul( xVExtrem, xVExtrem );	
 
					if ( MTH_M_bGreaterEqual (xNorm2, xVExtrem2) && MTH_M_bGreater ( MTH_M_xAbs(xU),C_xDNM_VERTICAL_FALL_LIMIT) )
					{
//						xU = MTH_M_xMul ( MTH_M_xSqrt ( MTH_M_xSub (xNorm2,xVExtrem2) ),  MTH_M_xSign (xU) );	 	
						xV = xVExtrem;
					}
					else
					{
//						xU = MTH_C_ZERO;
						xV = xVExtrem;
					}
					
					MTH3D_M_vMulScalarVector ( &stResultantVector, xU, &stU );
					MTH3D_M_vMulScalarVector ( &stVector, xV, &stV );
					MTH3D_M_vAddVector ( &stResultantVector, &stResultantVector, &stVector );
					MTH3D_M_vMulScalarVector ( &stVector, xN, &stN );
					MTH3D_M_vAddVector ( &stResultantVector, &stResultantVector, &stVector );
				}
			}
			else 
				bCantKeepWallSpeedZ = TRUE;
		}
	}
 
	/* adjust positions */
	xRate = DNM_M_xObstacleGetRate (p_stObstacle);
	
	bCollisionOk = MEC_fn_vComputeAdjustVector (&stAdjustVector, p_stDynamic, lObstacle, a_stObstacle, lObstacleCounter);
		
	if (DNM_M_bDynamicsIsHanging(p_stDynamic))
		MTH3D_M_vSetZofVector (&stAdjustVector,MTH_C_ZERO); 

	MTH3D_M_vAddVector (&stPosition, p_stCurrentPosition, &stAdjustVector);

	if (MTH_M_bGreaterEqual (xRate, MTH_C_ZERO))
		xOneMinusRate = MTH_M_xSub (MTH_C_ONE,xRate);
	else
//	{
//		if (!MTH_M_bIsNullWithEpsilon(MTH3D_M_xGetZofVector(&stResultantVector),MTH_M_xDoubleToReal(1e-5)) && DNM_M_bDynamicsIsKeepWallSpeedZ(p_stDynamic) && !bCantKeepWallSpeedZ )
//		{
//			MTH3D_M_vSubVector (&stAdjustVector, &stPosition, p_stPreviousPosition);
//			xOneMinusRate = MTH_M_xDiv ( MTH_M_xSub(MTH3D_M_xGetZofVector(&stIncidentVector),MTH3D_M_xGetZofVector(&stAdjustVector)),MTH3D_M_xGetZofVector(&stResultantVector));
//		}
//		else
			xOneMinusRate = MTH_C_ZERO;
//	}

	MTH3D_M_vMulScalarVector (&stVector, xOneMinusRate,&stResultantVector);

	if ( MTH_M_bGreater ( MTH3D_M_xNormVector(&stVector), DNM_M_xObstacleGetZoneRadius(p_stObstacle) ) )
	{
		MTH3D_M_vNormalizeVector ( &stVector, &stVector );
		MTH3D_M_vMulScalarVector ( &stVector, DNM_M_xObstacleGetZoneRadius(p_stObstacle), &stVector );
	}

	MTH3D_M_vAddVector (&stExtremPosition, &stPosition, &stVector);

	MTH3D_M_vSubVector (&stMoveVector, &stExtremPosition, p_stPreviousPosition);
	xDotProd = MTH3D_M_xDotProductVector (p_stNormal,&stMoveVector);
 
	if ( ( ( ((MTH_M_bGreater(xDotProd,C_xDNM_MTH_EPSILON) && bGroundObstacle && MTH_M_bGreaterZero(xRebound)) || ( p_stGroundObstacle && !MEC_fn_bGroundObstacle(p_stDynamic,p_stObstacle) ) || ( p_stWaterObstacle && (p_stObstacle!=p_stWaterObstacle) ) || g_bWaterNoCollide ) && !DNM_M_bDynamicsIsCanFall(p_stDynamic) ) ) )
	{
		MTH3D_M_vCopyVector (p_stCurrentPosition,&stPosition);
		MTH3D_M_vSubVector (p_stPreviousPosition, p_stCurrentPosition, &stResultantVector);
	}
	else
	{
		MTH3D_M_vCopyVector (p_stCurrentPosition,&stExtremPosition);
		MTH3D_M_vSubVector (p_stPreviousPosition, p_stCurrentPosition, &stResultantVector);
	}
 
	if (DNM_M_bDynamicsIsComplexSize(p_stDynamic)) POS_fn_vSetTranslationVector ( hAbsolutePreviousMatrix, p_stPreviousPosition );
 
	MEC_fn_vComputeSpeed (p_stDynamic,xDT);
}
 
 
void MEC_fn_vWallObstacleManagement 
( 
	MTH3D_tdstVector* pstResultMove,
	struct DNM_stDynamics *p_stDynamic, 
	MTH3D_tdstVector* pstMove,
	MTH3D_tdstVector* pstGroundNormal, 
	MTH3D_tdstVector* pstWallNormal,
	MTH_tdxReal xDT,
	ACP_tdxBool bAngleLimit
)
{
	MTH3D_tdstVector stDirection;
	MTH3D_tdstVector stWallNormalAdjust;
	MTH3D_tdstVector stVector;
 	POS_tdxHandleToPosition hCurrentMatrix;
	MTH3D_tdstVector *p_stCurrentTranslation;
	MTH_tdxReal xDotProd1, xDotProd2, xFactor;
 
	if ( MEC_fn_bIsNullVector(pstMove) )
	{
		MTH3D_M_vNullVector (pstResultMove);
		return;
	}
 
	hCurrentMatrix = DNM_M_p_stDynamicsGetCurrentMatrix (p_stDynamic);
	p_stCurrentTranslation = POS_fn_p_stGetTranslationVector ( hCurrentMatrix );
	MTH3D_M_vCrossProductVectorWithoutBuffer ( &stDirection, pstGroundNormal, pstWallNormal );

	if (MEC_fn_bIsNullVector(&stDirection))
	{
		MTH3D_M_vNullVector (pstResultMove);	
		return;
	}


	MTH3D_M_vNormalizeVector (&stDirection,&stDirection);
	xDotProd1 = MTH3D_M_xDotProductVector (&stDirection, pstMove);
 
	if (bAngleLimit && (g_lCallCounter==1))
	{
		if (!MEC_fn_bIsNullVector(pstMove))
			MTH3D_M_vNormalizeVector (&stVector,pstMove)
		else
			MTH3D_M_vNullVector(&stVector);
		
		xDotProd2 = MTH_M_xNeg(MTH3D_M_xDotProductVector (&stVector,pstWallNormal));
		
		xFactor = MTH_M_xMul(MTH3D_M_xNormVector(pstMove),MTH_M_xSign(xDotProd1));
		if (MTH_M_bGreater(xDotProd2,C_xDNM_CLIMB_COS_ANGLE_LIMIT))
			xFactor = MTH_M_xMul ( xFactor, MTH_M_xDiv(MTH_M_xSub(MTH_C_ONE,xDotProd2),MTH_M_xSub(MTH_C_ONE,C_xDNM_CLIMB_COS_ANGLE_LIMIT)) );
	}
	else 		
		xFactor = xDotProd1;

	MTH3D_M_vMulScalarVector ( pstResultMove, xFactor, &stDirection);

//	MTH3D_M_vMulScalarVector ( &stWallNormalAdjust, MTH_M_xMul(MTH3D_M_xNormVector(pstResultMove),MTH_M_xDoubleToReal(0.005)), pstWallNormal );  
	MTH3D_M_vMulScalarVector ( &stWallNormalAdjust, MTH_M_xMul(MTH3D_M_xNormVector(pstResultMove),MTH_M_xDoubleToReal(0.01)), pstWallNormal );  
	MTH3D_M_vAddVector ( pstResultMove, pstResultMove, &stWallNormalAdjust );
 
	MTH3D_M_vAddVector ( p_stCurrentTranslation, p_stCurrentTranslation, pstResultMove);
}
 
/* orient current matrix  ( -y = normal )*/
void MEC_fn_vOrient ( struct DNM_stDynamics *p_stDynamic, MTH3D_tdstVector* p_stNormal)
{
	POS_tdxHandleToPosition hCurrentMatrix; 
	MTH3D_tdstVector stVerticalVector;
	MTH3D_tdstVector *p_stX, *p_stY, *p_stZ;
		
	hCurrentMatrix = DNM_M_p_stDynamicsGetCurrentMatrix (p_stDynamic);
	MTH3D_M_vSetBaseKVector (&stVerticalVector);
 
	POS_fn_vGetRotationVector ( hCurrentMatrix, &p_stX, &p_stY, &p_stZ );
	MTH3D_M_vCopyVector ( p_stY, p_stNormal );
	MTH3D_M_vCrossProductVectorWithoutBuffer (p_stX, p_stY, &stVerticalVector);
	MTH3D_M_vCrossProductVectorWithoutBuffer (p_stZ, p_stX, p_stY );	
	MEC_fn_vUpdateMatrix ( p_stDynamic, hCurrentMatrix );
}
 
 
/* Obstacle collide*/
void MEC_fn_vBaseObstacleManagement ( struct DNM_stDynamics *p_stDynamic, HIE_tdxHandleToSuperObject hSupObj, MTH_tdxReal xDT )
{
	long lObstacle;
  
	POS_tdxHandleToPosition hCurrentMatrix; 
	POS_tdxHandleToPosition hInitialMatrix;
	POS_tdstCompletePosition stInitialMatrix;
 
	#ifdef DNM_DEBUG
		if(p_stDynamic == NULL)
			return;
	#endif
  
	hCurrentMatrix = DNM_M_p_stDynamicsGetCurrentMatrix (p_stDynamic);
	
	if (fn_ucCollSetGetCollComputeFrequencySO(hSupObj)>1)
	{
		hInitialMatrix = &stInitialMatrix;
		POS_fn_vCopyMatrix (hInitialMatrix,DNM_M_p_stDynamicsGetPreviousMatrix (p_stDynamic));
		MEC_fn_vGetCollisionTranslation (p_stDynamic,hInitialMatrix);
	}
	else hInitialMatrix = DNM_M_p_stDynamicsGetPreviousMatrix (p_stDynamic);
 
	/* Detection of collisions */
	g_bWaterNoCollide = FALSE;
	
	if(MEC_fn_bCollision(&lObstacle,g_a_stObstacle,p_stDynamic,hSupObj,hInitialMatrix,hCurrentMatrix,(ACP_tdxBool)DNM_M_bDynamicsIsHanging(p_stDynamic))) 
	{
		MEC_fn_vEdgeAnalysis (p_stDynamic, lObstacle, g_a_stObstacle, NULL );
		MEC_fn_vCollideBaseMechanic ( p_stDynamic, hSupObj, lObstacle, g_a_stObstacle, xDT);
	}
	else
		DNM_M_vDynamicsSetStop (p_stDynamic,FALSE);
 
}
 
 
/* new Gi*/
void MEC_fn_vGiObstacleManagement ( struct DNM_stDynamics *p_stDynamic, HIE_tdxHandleToSuperObject hSupObj, MTH_tdxReal xDT )
{
	long lObstacle;
	long lCounter=0;
	long lCounter1=0;
	long lFace=0;
	ACP_tdxBool bGiFace = FALSE;
 
	MTH_tdxReal xNormalMove;
	MTH_tdxReal	xSlope;
	MTH_tdxReal	xDotProd;
 
	MTH3D_tdstVector *p_stCurrentTranslation;
	MTH3D_tdstVector *p_stPreviousTranslation;
	MTH3D_tdstVector *p_stDownTranslation;
	MTH3D_tdstVector *p_stUpTranslation;
	MTH3D_tdstVector *p_stGiNormal, *p_stGiContact;
	MTH3D_tdstVector stVector;
	MTH3D_tdstVector stNormalMove, stTangentMove, stMove, stSlideMove;
	MTH3D_tdstVector stVerticalVector;
	MTH3D_tdstVector stAdjustVector;
 
	DNM_tdstMecObstacle *p_stTmpObstacle;
	DNM_tdstMecObstacle *p_stGiObstacle, *p_stSlideObstacle;
	DNM_tdstObstacle *p_stPreviousCeilObstacle;
 
	POS_tdstCompletePosition a2_stPosition[2];
	POS_tdstCompletePosition *p_stPOS_DownPosition = a2_stPosition;
	POS_tdstCompletePosition *p_stPOS_UpPosition = a2_stPosition+1;
 	POS_tdxHandleToPosition hCurrentMatrix, hPreviousMatrix;
 
	xSlope = MEC_fn_xMaxSlope (p_stDynamic);
 
	#ifdef DNM_DEBUG
		if(p_stDynamic == NULL)
			return;
		if(!HIE_fn_bIsSuperObjectValid(hSupObj))
			return;
	#endif
  
	/* Matrix init */
	hCurrentMatrix = DNM_M_p_stDynamicsGetCurrentMatrix (p_stDynamic);
	hPreviousMatrix = DNM_M_p_stDynamicsGetPreviousMatrix (p_stDynamic);
	MTH3D_M_vSetVectorElements( &stVerticalVector, MTH_C_ZERO, MTH_C_ZERO, MTH_C_ONE );
 
 
	POS_fn_vCopyMatrix(p_stPOS_UpPosition, hCurrentMatrix);
	POS_fn_vCopyMatrix(p_stPOS_DownPosition, hCurrentMatrix);
	
	p_stCurrentTranslation = POS_fn_p_stGetTranslationVector ( hCurrentMatrix );
	p_stPreviousTranslation = POS_fn_p_stGetTranslationVector ( hPreviousMatrix );
	MTH3D_M_vSubVector (&stMove,p_stCurrentTranslation,p_stPreviousTranslation);
 
	/* stack protection -> no more than 5 recursives calls. ( experience teaches it's enough )*/
	g_lCallCounter++;
	if (g_lCallCounter>5)
	{
		/* stay here 	*/
		MTH3D_M_vCopyVector (p_stCurrentTranslation,p_stPreviousTranslation);
		MTH3D_M_vNullVector ( DNM_M_pDynamicsGetPreviousSpeed(p_stDynamic) );
		return;
	}
 
	xNormalMove = MTH_M_xMul ( xSlope, MTH3D_M_xNormVector(&stMove) );
 
	if (MTH_M_bLess (xNormalMove,C_xDNM_CLIMB_DEFAULT_NORMAL_MOVE)) xNormalMove = C_xDNM_GI_DEFAULT_NORMAL_MOVE;
 
	p_stGiNormal = NULL;
	p_stGiContact = NULL;
	p_stPreviousCeilObstacle = DNM_M_p_stReportGetCeil (DNM_M_p_stDynamicsGetReport(p_stDynamic));
	if (p_stPreviousCeilObstacle)
	{
		p_stGiNormal = DNM_M_p_stObstacleGetNorm(p_stPreviousCeilObstacle);
		p_stGiContact = DNM_M_p_stObstacleGetContact(p_stPreviousCeilObstacle);
	}
	else
	{
		p_stGiNormal = &stVerticalVector;
	}
 
	/* normal and tangent move */
	MTH3D_M_vMulScalarVector ( &stNormalMove, MTH3D_M_xDotProductVector( &stMove, p_stGiNormal ), p_stGiNormal);
	MTH3D_M_vSubVector ( &stTangentMove, &stMove, &stNormalMove );
	MTH3D_M_vMulScalarVector ( &stVector, xNormalMove, p_stGiNormal);
 
	p_stDownTranslation = POS_fn_p_stGetTranslationVector ( p_stPOS_DownPosition );
	MTH3D_M_vCopyVector ( p_stDownTranslation, p_stPreviousTranslation );
	MTH3D_M_vAddVector ( p_stDownTranslation, p_stDownTranslation, &stTangentMove );
	MTH3D_M_vAddVector ( p_stDownTranslation, p_stDownTranslation, &stVector );
 
	p_stUpTranslation = POS_fn_p_stGetTranslationVector ( p_stPOS_UpPosition );
	MTH3D_M_vCopyVector ( p_stUpTranslation, p_stPreviousTranslation );
	MTH3D_M_vAddVector ( p_stUpTranslation, p_stUpTranslation, &stTangentMove );
	MTH3D_M_vSubVector ( p_stUpTranslation, p_stUpTranslation, &stVector );
	
 
	p_stGiObstacle = NULL;
	p_stSlideObstacle = NULL;
	p_stPreviousCeilObstacle = NULL;
 
	/* call collisions*/
	if(MEC_fn_bCollision(&lObstacle,g_a_stObstacle,p_stDynamic,hSupObj,p_stPOS_DownPosition,p_stPOS_UpPosition,TRUE)) 
	{
		MEC_fn_vDeleteGiBackFace (lObstacle,g_a_stObstacle,p_stDynamic,&stMove);
 
		/* search first collided Gi faces */
		for (lCounter=0; lCounter<lObstacle && (!p_stGiObstacle || !bGiFace); lCounter++)
		{
			p_stTmpObstacle = g_a_stObstacle + lCounter;
			if (MEC_fn_bIsObstacleValid(p_stTmpObstacle))
			{
				if ( (MEC_fn_bTypeOfGameMaterial(DNM_M_hObstacleGetCollidedMaterial(p_stTmpObstacle), C_xDNM_GI_TYPE_GAME_MATERIAL)) && !(MEC_fn_bTypeOfGameMaterial(DNM_M_hObstacleGetCollidedMaterial(p_stTmpObstacle), C_xDNM_NO_COLLISION_TYPE_GAME_MATERIAL)) && (MEC_fn_bCeilObstacle (p_stDynamic,p_stTmpObstacle)) )
				{
					if (!p_stGiObstacle)
						p_stGiObstacle = p_stTmpObstacle;
					if (!MEC_fn_bIsEdge(p_stTmpObstacle))
						bGiFace = TRUE;
				}
			}
		}
 
		if (p_stGiObstacle)
		{
			p_stGiNormal = DNM_M_p_stObstacleGetNorm(p_stGiObstacle);
			p_stGiContact = DNM_M_p_stObstacleGetContact(p_stGiObstacle);
		}
 
		for (lCounter1=0; lCounter1<lObstacle && !p_stSlideObstacle; lCounter1++)
		{
			p_stTmpObstacle = g_a_stObstacle + lCounter1;
			if (MEC_fn_bIsObstacleValid(p_stTmpObstacle))
			{
				if 
				(
					!MEC_fn_bTypeOfGameMaterial(DNM_M_hObstacleGetCollidedMaterial(p_stTmpObstacle), C_xDNM_GI_TYPE_GAME_MATERIAL)
				||	MEC_fn_bTypeOfGameMaterial(DNM_M_hObstacleGetCollidedMaterial(p_stTmpObstacle), C_xDNM_NO_COLLISION_TYPE_GAME_MATERIAL)
				)
				{
					xDotProd = MTH3D_M_xDotProductVector ( DNM_M_p_stObstacleGetNorm(p_stTmpObstacle), p_stGiNormal );
					if (MTH_M_bLess(xDotProd,MTH_M_xDoubleToReal(0.707)))
					{
						MTH3D_M_vSubVector ( &stVector, DNM_M_p_stObstacleGetContact(p_stTmpObstacle), p_stGiContact );
						xDotProd = MTH3D_M_xDotProductVector ( &stVector, p_stGiNormal );
						if (MTH_M_bGreater ( xDotProd, MTH_M_xDoubleToReal(-0.01) ))
							p_stSlideObstacle = p_stTmpObstacle;
					}
				}
			}
		}
 
		if (p_stSlideObstacle && lCounter1>lCounter) lCounter=lCounter1;
 
		/* report obstacles in the report.*/
		MEC_fn_vReportCollision (p_stDynamic,hSupObj,lObstacle,g_a_stObstacle,lCounter-1);
 
		/* detect stop to stay compatible with previous Gi mechanics*/
		if (p_stGiObstacle && MEC_fn_bIsEdge(p_stGiObstacle) && !p_stSlideObstacle && !bGiFace)
		{
			for ( lCounter1=0; lCounter1<lObstacle; lCounter1++ )
			{
				p_stTmpObstacle = g_a_stObstacle+lCounter1;
 
				if (MEC_fn_bIsObstacleValid(p_stTmpObstacle))
				{
					MTH3D_M_vSubVector ( &stVector, p_stGiContact, DNM_M_p_stObstacleGetContact(p_stTmpObstacle) );
					if (MEC_fn_bIsNullVector(&stVector))
					{
						lFace++;
						
//						if 
//						( 
//							!MEC_fn_bCeilObstacle (p_stDynamic,p_stTmpObstacle) 
//							|| !MEC_fn_bTypeOfGameMaterial(DNM_M_hObstacleGetCollidedMaterial(p_stTmpObstacle), C_xDNM_GI_TYPE_GAME_MATERIAL) 
//							|| MEC_fn_bTypeOfGameMaterial(DNM_M_hObstacleGetCollidedMaterial(p_stTmpObstacle), C_xDNM_NO_COLLISION_TYPE_GAME_MATERIAL) 
//						)
//						{
//							/* stop */
//							if (!DNM_M_bDynamicsIsMechanicChange(p_stDynamic)) DNM_M_vDynamicsSetStop (p_stDynamic,TRUE);
//							MTH3D_M_vCopyVector (p_stCurrentTranslation,p_stPreviousTranslation);
//							MTH3D_M_vNullVector ( DNM_M_pDynamicsGetPreviousSpeed(p_stDynamic) );
//
//							/*/ report previous collision */
//							if (DNM_M_bDynamicsIsCollisionReport(p_stDynamic))
//								DNM_M_ulReportSetSurfaceState(DNM_M_p_stDynamicsGetReport(p_stDynamic),DNM_M_ulReportGetPrevSurfaceState (DNM_M_p_stDynamicsGetReport(p_stDynamic)) );
//							return;
//						}
					}
				}
			}
 
			if (lFace==1 && !MEC_fn_bIsDoubleEdge(p_stGiObstacle))   
			{
				/* stop */
				if (!DNM_M_bDynamicsIsMechanicChange(p_stDynamic)) DNM_M_vDynamicsSetStop (p_stDynamic,TRUE);
				MTH3D_M_vCopyVector (p_stCurrentTranslation,p_stPreviousTranslation);
				MTH3D_M_vNullVector ( DNM_M_pDynamicsGetPreviousSpeed(p_stDynamic) );

				/*/ report previous collision */
				if (DNM_M_bDynamicsIsCollisionReport(p_stDynamic))
					DNM_M_ulReportSetSurfaceState(DNM_M_p_stDynamicsGetReport(p_stDynamic),DNM_M_ulReportGetPrevSurfaceState (DNM_M_p_stDynamicsGetReport(p_stDynamic)) );
				return;
			}
		}
 
		/* we meet a gi face ...*/
		if (p_stGiObstacle)
		{
			if(!p_stSlideObstacle)
			{
				MTH3D_M_vAddVector (&stVector, p_stUpTranslation, DNM_M_xObstacleGetTranslation (p_stGiObstacle));
				POS_fn_vSetTranslationVector ( hCurrentMatrix, &stVector );
			}
			else
			{
				/* we use its previous position that is safe.*/
				if ( p_stSlideObstacle && MEC_fn_bIsCollide(p_stSlideObstacle) && (g_lCallCounter>2) )
				{
					MEC_fn_vComputeAdjustVector (&stAdjustVector, p_stDynamic, lObstacle, g_a_stObstacle, lCounter);
					MTH3D_M_vAddVector (p_stCurrentTranslation, p_stUpTranslation, &stAdjustVector);
					MTH3D_M_vSubVector (&stVector, p_stCurrentTranslation, p_stPreviousTranslation);
					MTH3D_M_vSubVector (&stMove,&stMove,&stVector);		
					MTH3D_M_vCopyVector (p_stPreviousTranslation,p_stCurrentTranslation);
				}
				else
					/* we use its previous position that is safe.*/
					MTH3D_M_vCopyVector (p_stCurrentTranslation,p_stPreviousTranslation);
 
				/* compute slide -> Current position is the new place were we try to go*/
				MEC_fn_vWallObstacleManagement ( &stSlideMove, p_stDynamic, &stMove, DNM_M_p_stObstacleGetNorm(p_stGiObstacle), DNM_M_p_stObstacleGetNorm(p_stSlideObstacle), xDT, FALSE );
				
				/* stWallMove contains the move due to wall slide. If it's not significant, it's no use to continue.*/
				if (!MEC_fn_bIsNullVector(&stSlideMove))
				{
					MEC_fn_vGiObstacleManagement (p_stDynamic, hSupObj, xDT);
					MEC_fn_vComputeSpeed (p_stDynamic,xDT);
					return;
				}
				else MTH3D_M_vCopyVector (p_stCurrentTranslation,p_stPreviousTranslation);
			}
		}
		else
		{
			if (p_stSlideObstacle)
			{
				/* we use its previous position that is safe.*/
				if ( p_stSlideObstacle && MEC_fn_bIsCollide(p_stSlideObstacle) /*&& !MEC_fn_bIsEdge(p_stSlideObstacle)*/ )
				{
					MEC_fn_vComputeAdjustVector (&stAdjustVector, p_stDynamic, lObstacle, g_a_stObstacle, lCounter);
					MTH3D_M_vAddVector (p_stCurrentTranslation, p_stUpTranslation, &stAdjustVector);
					MTH3D_M_vSubVector (&stVector, p_stCurrentTranslation, p_stPreviousTranslation);
					MTH3D_M_vSubVector (&stMove,&stMove,&stVector);		
					MTH3D_M_vCopyVector (p_stPreviousTranslation,p_stCurrentTranslation);
				}
				else
					/* we use its previous position that is safe.*/
					MTH3D_M_vCopyVector (p_stCurrentTranslation,p_stPreviousTranslation);
 
				MEC_fn_vWallObstacleManagement ( &stSlideMove, p_stDynamic, &stMove, p_stGiNormal, DNM_M_p_stObstacleGetNorm(p_stSlideObstacle), xDT, FALSE );
 
				if (!MEC_fn_bIsNullVector(&stSlideMove))
				{
					MEC_fn_vGiObstacleManagement ( p_stDynamic, hSupObj, xDT );
					MEC_fn_vComputeSpeed (p_stDynamic,xDT);
					return;
				}
				else MTH3D_M_vCopyVector (p_stCurrentTranslation,p_stPreviousTranslation);
			}
			else
			{
				POS_fn_vCopyMatrix ( hCurrentMatrix, hPreviousMatrix );
				MTH3D_M_vNullVector ( DNM_M_pDynamicsGetPreviousSpeed(p_stDynamic) );
				if (!DNM_M_bDynamicsIsMechanicChange(p_stDynamic)) DNM_M_vDynamicsSetStop ( p_stDynamic, TRUE );
 
				/* resport previous state */
				if (DNM_M_bDynamicsIsCollisionReport(p_stDynamic))
					DNM_M_ulReportSetSurfaceState(DNM_M_p_stDynamicsGetReport(p_stDynamic),DNM_M_ulReportGetPrevSurfaceState (DNM_M_p_stDynamicsGetReport(p_stDynamic)) );
				return;
			}
		}
 
		MEC_fn_vComputeSpeed (p_stDynamic,xDT);
		return;
	}
 
 
	/* There is no obstacle at all.*/
	POS_fn_vCopyMatrix ( hCurrentMatrix, hPreviousMatrix );
	MTH3D_M_vNullVector ( DNM_M_pDynamicsGetPreviousSpeed(p_stDynamic) );
	if (!DNM_M_bDynamicsIsMechanicChange(p_stDynamic)) DNM_M_vDynamicsSetStop (p_stDynamic,TRUE);
	
	/* resport previous state */
	if (DNM_M_bDynamicsIsCollisionReport(p_stDynamic))
		DNM_M_ulReportSetSurfaceState(DNM_M_p_stDynamicsGetReport(p_stDynamic),DNM_M_ulReportGetPrevSurfaceState (DNM_M_p_stDynamicsGetReport(p_stDynamic)) );
 
	return;
}
 
/* new climb*/
void MEC_fn_vClimbObstacleManagement 
( 
	struct DNM_stDynamics *p_stDynamic, 
	HIE_tdxHandleToSuperObject hSupObj, 
	MTH_tdxReal xDT 
)
{
	long lObstacle;
	long lCounter=0;
	long lCounter1=0;
	long lCounter2=0;
 
	ACP_tdxBool bStop = FALSE;

	MTH_tdxReal xNormalMove;
	MTH_tdxReal	xSlope;
	MTH_tdxReal	xDotProd;
	MTH_tdxReal	xDotProdMin = MTH_C_ZERO;

	MTH3D_tdstVector *p_stX, *p_stY, *p_stZ;
	MTH3D_tdstVector *p_stCurrentTranslation;
	MTH3D_tdstVector *p_stPreviousTranslation;
	MTH3D_tdstVector *p_stBackTranslation;
	MTH3D_tdstVector *p_stFrontTranslation;
	MTH3D_tdstVector *p_stNormal;
	MTH3D_tdstVector *p_stCollideSlideObstacle = NULL;

	MTH3D_tdstVector stVector;
	MTH3D_tdstVector stAdjustVector;
	MTH3D_tdstVector stMove, stNormalMove, stTangentMove, stSlideMove;
	MTH3D_tdstVector stVerticalVector;
	MTH3D_tdstVector stSafeTranslation;
	MTH3D_tdstVector stNormMove;
	MTH3D_tdstVector stNormTangentMove;
 
	DNM_tdstMecObstacle *p_stTmpObstacle;
	DNM_tdstMecObstacle *p_stClimbObstacle, *p_stSlideObstacle;
	DNM_tdstMecObstacle *p_stEdgeObstacle;
	DNM_tdstMecObstacle *p_stGroundObstacle;
 
	POS_tdstCompletePosition a2_stPosition[2];
	POS_tdstCompletePosition *p_stPOS_BackPosition = a2_stPosition;
	POS_tdstCompletePosition *p_stPOS_FrontPosition = a2_stPosition+1;
 	POS_tdxHandleToPosition hCurrentMatrix, hPreviousMatrix;
 
	xSlope = C_xDNM_CLIMB_SLOPE_LIMIT;
 
	#ifdef DNM_DEBUG
		if(p_stDynamic == NULL)
			return;
		if(!HIE_fn_bIsSuperObjectValid(hSupObj))
			return;
	#endif
  
	/* Matrix init */
	hCurrentMatrix = DNM_M_p_stDynamicsGetCurrentMatrix (p_stDynamic);
	hPreviousMatrix = DNM_M_p_stDynamicsGetPreviousMatrix (p_stDynamic);
	MTH3D_M_vSetVectorElements( &stVerticalVector, MTH_C_ZERO, MTH_C_ZERO, MTH_C_ONE );
 
	/* orient toward the rock the first time */
	if (DNM_M_bDynamicsIsMechanicChange	(p_stDynamic))
	{
		p_stNormal = DNM_M_pDynamicsGetWallNormal (p_stDynamic);
		if (!MTH3D_M_bIsNullVector(p_stNormal))
			MEC_fn_vOrient ( p_stDynamic, p_stNormal );
	} 
 
 
	POS_fn_vCopyMatrix(p_stPOS_FrontPosition, hCurrentMatrix);
	POS_fn_vCopyMatrix(p_stPOS_BackPosition, hCurrentMatrix);
	
	p_stCurrentTranslation = POS_fn_p_stGetTranslationVector ( hCurrentMatrix );
	p_stPreviousTranslation = POS_fn_p_stGetTranslationVector ( hPreviousMatrix );
	MTH3D_M_vSubVector (&stMove,p_stCurrentTranslation,p_stPreviousTranslation);

	if (!MEC_fn_bIsNullVector(&stMove))
		MTH3D_M_vNormalizeVector(&stNormMove,&stMove)
	else
		MTH3D_M_vNullVector(&stNormMove);


	/* stack protection -> no more than 5 recursives calls. ( experience teaches it's enough )*/
	g_lCallCounter++;
	if (g_lCallCounter>5)
	{
		/* stay here 	*/
		MTH3D_M_vCopyVector (p_stCurrentTranslation,p_stPreviousTranslation);
		MTH3D_M_vNullVector ( DNM_M_pDynamicsGetPreviousSpeed(p_stDynamic) );
		return;
	}
 
	/* normal and tangent move */
	POS_fn_vGetRotationVector ( hCurrentMatrix, &p_stX, &p_stY, &p_stZ );
	MTH3D_M_vMulScalarVector ( &stNormalMove, MTH3D_M_xDotProductVector( &stMove, DNM_M_pDynamicsGetWallNormal (p_stDynamic)), DNM_M_pDynamicsGetWallNormal (p_stDynamic));
	MTH3D_M_vSubVector ( &stTangentMove, &stMove, &stNormalMove );
 
	if (g_lCallCounter==1)
		MTH3D_M_vCopyVector ( &g_stFirstMove, &stTangentMove );

	if (!MEC_fn_bIsNullVector(&stTangentMove))
		MTH3D_M_vNormalizeVector(&stNormTangentMove,&stTangentMove)
	else
		MTH3D_M_vNullVector(&stNormTangentMove);

	if (DNM_M_bDynamicsIsMechanicChange	(p_stDynamic)) xNormalMove = C_xDNM_CLIMB_FIRST_NORMAL_MOVE;
	else xNormalMove = MTH_M_xMul ( xSlope, MTH3D_M_xNormVector(&stTangentMove) );
 
	if (MTH_M_bLess (xNormalMove,C_xDNM_CLIMB_DEFAULT_NORMAL_MOVE)) xNormalMove = C_xDNM_CLIMB_DEFAULT_NORMAL_MOVE;
 
	p_stBackTranslation = POS_fn_p_stGetTranslationVector ( p_stPOS_BackPosition );
	MTH3D_M_vAddVector ( p_stBackTranslation, p_stPreviousTranslation, &stTangentMove );
	MTH3D_M_vMulScalarVector (&stVector, xNormalMove, DNM_M_pDynamicsGetWallNormal (p_stDynamic));
	MTH3D_M_vAddVector ( p_stBackTranslation, p_stBackTranslation, &stVector );
 
	p_stFrontTranslation = POS_fn_p_stGetTranslationVector ( p_stPOS_FrontPosition );
	MTH3D_M_vAddVector ( p_stFrontTranslation, p_stPreviousTranslation, &stTangentMove );
	MTH3D_M_vSubVector ( p_stFrontTranslation, p_stFrontTranslation, &stVector );
 
	p_stClimbObstacle = NULL;
	p_stSlideObstacle = NULL;
	p_stEdgeObstacle = NULL;
	p_stGroundObstacle = NULL;

	/* call collisions*/
	if(MEC_fn_bCollision(&lObstacle,g_a_stObstacle,p_stDynamic,hSupObj,p_stPOS_BackPosition,p_stPOS_FrontPosition,TRUE)) 
	{
		/* delete back faces */
		MEC_fn_vDeleteClimbBackFace (lObstacle,g_a_stObstacle,p_stDynamic,&stNormTangentMove);
	
		/* search first collided Climb faces and slide faces*/
		for (lCounter=0; lCounter<lObstacle && !p_stClimbObstacle; lCounter++)
		{
			p_stTmpObstacle = g_a_stObstacle + lCounter;
			if (MEC_fn_bIsObstacleValid(p_stTmpObstacle))
			{
				if ( (MEC_fn_bTypeOfGameMaterial(DNM_M_hObstacleGetCollidedMaterial(p_stTmpObstacle), C_xDNM_CLIMB_TYPE_GAME_MATERIAL)) && !(MEC_fn_bTypeOfGameMaterial(DNM_M_hObstacleGetCollidedMaterial(p_stTmpObstacle), C_xDNM_NO_COLLISION_TYPE_GAME_MATERIAL)) && (MEC_fn_bWallObstacle (p_stDynamic,p_stTmpObstacle)) )
					p_stClimbObstacle = p_stTmpObstacle;
			}
		}
 

		for (lCounter=0; lCounter<lObstacle && !p_stGroundObstacle; lCounter++)
		{
			p_stTmpObstacle = g_a_stObstacle + lCounter;
			if (MEC_fn_bIsObstacleValid(p_stTmpObstacle))
			{
				if (MEC_fn_bGroundObstacle(p_stDynamic,p_stTmpObstacle))
				{
					p_stGroundObstacle = p_stTmpObstacle;
					MEC_fn_vReportCollision (p_stDynamic,hSupObj,1,p_stGroundObstacle,0);
				}
			}
		}

		if (p_stClimbObstacle)
		{
			bStop = FALSE;
			for ( lCounter1=0; lCounter1<lObstacle && !bStop; lCounter1++)
			{
				p_stTmpObstacle = g_a_stObstacle + lCounter1;
				if (MEC_fn_bIsObstacleValid(p_stTmpObstacle))
				{
					xDotProd = MTH3D_M_xDotProductVector ( DNM_M_p_stObstacleGetNorm(p_stTmpObstacle), DNM_M_p_stObstacleGetNorm(p_stClimbObstacle) );
					if (MTH_M_bLess(xDotProd,MTH_M_xDoubleToReal(0.707)))
					{
						MTH3D_M_vSubVector ( &stVector, DNM_M_p_stObstacleGetContact(p_stTmpObstacle), DNM_M_p_stObstacleGetContact(p_stClimbObstacle) );
						xDotProd = MTH3D_M_xDotProductVector ( &stVector, DNM_M_p_stObstacleGetNorm(p_stClimbObstacle) );
						if (MTH_M_bGreater ( xDotProd, MTH_M_xDoubleToReal(0.1) ))
//						if (MTH_M_bGreaterZero ( xDotProd))
						{
							xDotProd = MTH3D_M_xDotProductVector ( &stNormTangentMove, DNM_M_p_stObstacleGetNorm(p_stTmpObstacle));

							if 
							(
								MEC_fn_bTypeOfGameMaterial ( DNM_M_hObstacleGetCollidedMaterial(p_stTmpObstacle), C_xDNM_CLIMB_TYPE_GAME_MATERIAL ) 
							&&	!MEC_fn_bTypeOfGameMaterial(DNM_M_hObstacleGetCollidedMaterial(p_stTmpObstacle), C_xDNM_NO_COLLISION_TYPE_GAME_MATERIAL)
							)
							{
								p_stSlideObstacle=NULL;
								bStop = TRUE;

							}
							else if (MTH_M_bLess(xDotProd,xDotProdMin))
							{
								xDotProdMin = xDotProd;
								p_stSlideObstacle = p_stTmpObstacle;
							}
						}
					}
				}
			}
		}
/*		else if (DNM_M_bDynamicsIsAdvancedSize(p_stDynamic))
		{
			for ( lCounter1=0; lCounter1<lObstacle && !p_stSlideObstacle; lCounter1++)
			{
				p_stTmpObstacle = g_a_stObstacle + lCounter1;
				if (MEC_fn_bIsObstacleValid(p_stTmpObstacle))
				{
					xDotProd = MTH3D_M_xDotProductVector ( DNM_M_p_stObstacleGetNorm(p_stTmpObstacle), DNM_M_pDynamicsGetWallNormal(p_stDynamic) );	
					if (MTH_M_bLess (xDotProd,MTH_M_xDoubleToReal(0.707)))
						p_stSlideObstacle = p_stTmpObstacle;
				}
			}
		}
*/
		/* remove slide obstacle if it's a climb material */
		if
		( 
			p_stSlideObstacle
			&&	MEC_fn_bTypeOfGameMaterial ( DNM_M_hObstacleGetCollidedMaterial(p_stSlideObstacle), C_xDNM_CLIMB_TYPE_GAME_MATERIAL ) 
			&&	!MEC_fn_bTypeOfGameMaterial(DNM_M_hObstacleGetCollidedMaterial(p_stSlideObstacle), C_xDNM_NO_COLLISION_TYPE_GAME_MATERIAL)
			&&  MEC_fn_bWallObstacle (p_stDynamic,p_stSlideObstacle)
		)
		{
			xDotProd = MTH3D_M_xDotProductVector ( DNM_M_p_stObstacleGetNorm(p_stSlideObstacle), DNM_M_p_stObstacleGetNorm(p_stClimbObstacle) );
			if (!MTH_M_bEqual(xDotProd,MTH_C_ZERO))
				p_stSlideObstacle = NULL;
		}
 
		/* search ground to stop ( to stay compatible with previous climb mechanic )*/
		if
		( 
			DNM_M_bDynamicsIsCollisionReport(p_stDynamic) 
		&& ( (DNM_M_ulReportGetPrevSurfaceState(DNM_M_p_stDynamicsGetReport(p_stDynamic)) & C_WOT_ulGround) != C_WOT_ulGround ) 
		&& !DNM_M_bDynamicsIsMechanicChange(p_stDynamic) 
		&& MTH_M_bLessZero (MTH3D_M_xGetZofVector(&stTangentMove))		
		)
		{
			for (lCounter2=0; lCounter2<lObstacle; lCounter2++)
			{
				p_stTmpObstacle = g_a_stObstacle + lCounter2;
				if (MEC_fn_bIsObstacleValid(p_stTmpObstacle))
				{
					if 
					( 
						!MEC_fn_bTypeOfGameMaterial (DNM_M_hObstacleGetCollidedMaterial(p_stTmpObstacle),C_xDNM_NO_COLLISION_TYPE_GAME_MATERIAL)		
						&&	MEC_fn_bGroundObstacle(p_stDynamic,p_stTmpObstacle)
					)
					{
						MTH3D_M_vCopyVector (p_stCurrentTranslation,p_stPreviousTranslation);
						MTH3D_M_vNullVector ( DNM_M_pDynamicsGetPreviousSpeed(p_stDynamic) );
						DNM_M_vDynamicsSetStop (p_stDynamic,TRUE);
						MEC_fn_vReportCollision (p_stDynamic,hSupObj,lObstacle,g_a_stObstacle,lCounter1-1);
						return;
					}
				}
			}
		}
 
		if (p_stSlideObstacle && lCounter1>lCounter) lCounter=lCounter1;
 
		/* report obstacles in the report.*/
		MEC_fn_vReportCollision (p_stDynamic,hSupObj,lObstacle,g_a_stObstacle,lCounter-1);
 
		/* we meet a climb face ...*/
		if (p_stClimbObstacle)
		{
			DNM_M_vDynamicsSetWallNormal ( p_stDynamic, DNM_M_p_stObstacleGetNorm(p_stClimbObstacle) );
			
			if(!p_stSlideObstacle)
			{
				if (!MEC_fn_bIsEdge(p_stClimbObstacle))
				{
					MTH3D_M_vAddVector (&stVector, p_stFrontTranslation, DNM_M_xObstacleGetTranslation (p_stClimbObstacle));
					POS_fn_vSetTranslationVector ( hCurrentMatrix, &stVector );
				}
				else
				{
					/* p_SlideObstacle is used here as temporary variable */
					for (lCounter=0; lCounter<lObstacle && !p_stSlideObstacle; lCounter++)
					{
						p_stTmpObstacle = g_a_stObstacle + lCounter;
						if (MEC_fn_bIsObstacleValid(p_stTmpObstacle))
						{	
							if ( MEC_fn_bWallObstacle ( p_stDynamic, p_stTmpObstacle ) && !MEC_fn_bIsEdge( p_stTmpObstacle ) )
								p_stSlideObstacle = p_stTmpObstacle;
						}
					}
								
					if (p_stSlideObstacle)
					{
						MTH3D_M_vAddVector (&stVector, p_stFrontTranslation, DNM_M_xObstacleGetTranslation (p_stSlideObstacle));
						POS_fn_vSetTranslationVector ( hCurrentMatrix, &stVector );
						p_stSlideObstacle = NULL;
					}
					else
					{
						MTH3D_M_vAddVector (&stVector, p_stFrontTranslation, DNM_M_xObstacleGetTranslation (p_stClimbObstacle));
						POS_fn_vSetTranslationVector ( hCurrentMatrix, &stVector );
					}
				}
			}
			else
			{
				if ( p_stSlideObstacle && MEC_fn_bIsCollide(p_stSlideObstacle) && ( (g_lCallCounter>2) || DNM_M_bDynamicsIsMechanicChange(p_stDynamic) ) )
				{
					MEC_fn_vComputeAdjustVector (&stAdjustVector, p_stDynamic, lObstacle, g_a_stObstacle, lCounter-1);

					xDotProd = MTH3D_M_xDotProductVector (&stAdjustVector,DNM_M_p_stObstacleGetNorm(p_stClimbObstacle));
					MTH3D_M_vMulScalarVector (&stVector,xDotProd,DNM_M_p_stObstacleGetNorm(p_stClimbObstacle));
					MTH3D_M_vSubVector (&stAdjustVector,&stAdjustVector,&stVector);
					MTH3D_M_vAddVector (&stAdjustVector,&stAdjustVector,DNM_M_xObstacleGetTranslation (p_stClimbObstacle));

					MTH3D_M_vAddVector (&stSafeTranslation, p_stFrontTranslation, &stAdjustVector);
					MTH3D_M_vSubVector (&stVector, &stSafeTranslation, p_stPreviousTranslation);
					MTH3D_M_vSubVector (&stMove,&stMove,&stVector);					

				}
				else 
					/* we use its previous position that is safe.*/
					MTH3D_M_vCopyVector (&stSafeTranslation,p_stPreviousTranslation);

				MTH3D_M_vCopyVector (p_stCurrentTranslation,&stSafeTranslation);
 
				/* compute slide -> Current position is the new place were we try to go*/
				MEC_fn_vWallObstacleManagement ( &stSlideMove, p_stDynamic, &stMove, DNM_M_p_stObstacleGetNorm(p_stClimbObstacle), DNM_M_p_stObstacleGetNorm(p_stSlideObstacle), xDT, TRUE );

				xDotProd = MTH3D_M_xDotProductVector (&g_stFirstMove,&stSlideMove);

				/* stWallMove contains the move due to wall slide. If it's not significant, it's no use to continue.*/
				if (!MEC_fn_bIsNullVector(&stSlideMove)&&MTH_M_bGreaterEqualZero(xDotProd))
				{
					MEC_fn_vClimbObstacleManagement (p_stDynamic, hSupObj, xDT);
					MEC_fn_vComputeSpeed (p_stDynamic,xDT);
					return;
				}
				else 
					MTH3D_M_vCopyVector (p_stCurrentTranslation,&stSafeTranslation);
			}
		}
		else
		{
			if (p_stSlideObstacle)
			{
//				if ( p_stSlideObstacle && MEC_fn_bIsCollide(p_stSlideObstacle) )
				{
					MEC_fn_vComputeAdjustVector (&stAdjustVector, p_stDynamic, lObstacle, g_a_stObstacle, lCounter);
					
					MTH3D_M_vAddVector (&stSafeTranslation, p_stFrontTranslation, &stAdjustVector);
					MTH3D_M_vSubVector (&stVector, &stSafeTranslation, p_stPreviousTranslation);
					MTH3D_M_vSubVector (&stMove,&stMove,&stVector);		
				
				}
//				else
//					MTH3D_M_vCopyVector (&stSafeTranslation,p_stPreviousTranslation);
 
				MTH3D_M_vCopyVector (p_stCurrentTranslation,&stSafeTranslation);
 
				MEC_fn_vWallObstacleManagement ( &stSlideMove, p_stDynamic, &stMove, p_stY, DNM_M_p_stObstacleGetNorm(p_stSlideObstacle), xDT, TRUE );

				xDotProd = MTH3D_M_xDotProductVector (&g_stFirstMove,&stSlideMove);
				if (MTH_M_bLessZero(xDotProd))
				{
					/* stay here 	*/
					MTH3D_M_vCopyVector (p_stCurrentTranslation,p_stPreviousTranslation);
					MTH3D_M_vNullVector ( DNM_M_pDynamicsGetPreviousSpeed(p_stDynamic) );
					return;
				}

				if (!MEC_fn_bIsNullVector(&stSlideMove))
				{
					MEC_fn_vClimbObstacleManagement ( p_stDynamic, hSupObj, xDT );
					MEC_fn_vComputeSpeed (p_stDynamic,xDT);
					return;
				}
				else 
					MTH3D_M_vCopyVector (p_stCurrentTranslation,&stSafeTranslation);
			}
			else
			{
				POS_fn_vCopyMatrix ( hCurrentMatrix, hPreviousMatrix );
				MTH3D_M_vNullVector ( DNM_M_pDynamicsGetPreviousSpeed(p_stDynamic) );
				DNM_M_vDynamicsSetStop ( p_stDynamic, TRUE );
 
				/* resport previous state */
				if (DNM_M_bDynamicsIsCollisionReport(p_stDynamic))
					DNM_M_ulReportSetSurfaceState(DNM_M_p_stDynamicsGetReport(p_stDynamic),DNM_M_ulReportGetPrevSurfaceState (DNM_M_p_stDynamicsGetReport(p_stDynamic)) );
				return;
			}
		}
 
		/* orient toward rock */
		if ( p_stClimbObstacle && !MEC_fn_bIsEdge(p_stClimbObstacle) )
		{
			p_stNormal = DNM_M_p_stObstacleGetNorm (p_stClimbObstacle);
			MTH3D_M_vSubVector (&stVector,p_stNormal,p_stY);
			if (!MEC_fn_bIsNullVector(&stVector))
				MEC_fn_vOrient ( p_stDynamic, p_stNormal );
		}
	
		MEC_fn_vComputeSpeed (p_stDynamic,xDT);
		return;
	}
 
 
	/* There is no obstacle at all.*/
	POS_fn_vCopyMatrix ( hCurrentMatrix, hPreviousMatrix );
	MTH3D_M_vNullVector ( DNM_M_pDynamicsGetPreviousSpeed(p_stDynamic) );
	DNM_M_vDynamicsSetStop (p_stDynamic,TRUE);
	
	/* resport previous state */
	if (DNM_M_bDynamicsIsCollisionReport(p_stDynamic))
		DNM_M_ulReportSetSurfaceState(DNM_M_p_stDynamicsGetReport(p_stDynamic),DNM_M_ulReportGetPrevSurfaceState (DNM_M_p_stDynamicsGetReport(p_stDynamic)) );
 
	return;
}
 
 
void MEC_fn_vGroundObstacleManagement 
( 
	struct DNM_stDynamics *p_stDynamic, 
	HIE_tdxHandleToSuperObject hSupObj,     
	MTH_tdxReal xDT
)
{
	long lObstacle, lObstacle2;
	long lCounter, lObstacleCounter;
	long lWallCounter;
 
	MTH_tdxReal xSlide;
	MTH_tdxReal xFactor;
	MTH_tdxReal	xSpeedZ;

	POS_tdstCompletePosition a2_stPosition[2];
	POS_tdstCompletePosition *p_stPOS_DownPosition = a2_stPosition;
	POS_tdstCompletePosition *p_stPOS_UpPosition = a2_stPosition+1;
	POS_tdstCompletePosition stPreviousMatrix;
 	POS_tdxHandleToPosition hCurrentMatrix, hPreviousMatrix;
 
	MTH3D_tdstVector stVector;
	MTH3D_tdstVector stUpVector, stDownVector;
	MTH3D_tdstVector stMove;
	MTH3D_tdstVector stVertical;
	MTH3D_tdstVector stNormalMove;
	MTH3D_tdstVector stTangentMove;
	MTH3D_tdstVector stAbsoluteTangentMove;
	MTH3D_tdstVector stAdjustVector, stAdjustVector1;
	MTH3D_tdstVector stPushVector;
	MTH3D_tdstVector stWallMove;
	MTH3D_tdstVector stSafeTranslation;
	MTH3D_tdstVector stNormalizeTangentMove;
 
	MTH3D_tdstVector *p_stCurrentTranslation;
	MTH3D_tdstVector *p_stPreviousTranslation;
	MTH3D_tdstVector *p_stUpTranslation;
	MTH3D_tdstVector *p_stDownTranslation;
	MTH3D_tdstVector *p_stNormal;
 
	ACP_tdxBool bStep;
	ACP_tdxBool bAdjust;
	ACP_tdxBool bFirstGround;
	ACP_tdxBool bOk = TRUE;
	ACP_tdxBool bWallCheck = FALSE;
	ACP_tdxBool bSqueezeByWall = FALSE;
	ACP_tdxBool bCorner = FALSE;

	MTH_tdxReal	xMinSlope;
	MTH_tdxReal	xMaxSlope;
	MTH_tdxReal xDotProduct;
	MTH_tdxReal xNormTangentMove;
	MTH_tdxReal xWallDistance = MTH_C_InfinitPlus;
	MTH_tdxReal xTmpReal;
 
	DNM_tdstMecObstacle *p_stGroundObstacle, *p_stWallObstacle, *p_stTmpObstacle, *p_stWallObstacle2, *p_stWallEdgeObstacle, *p_stMobileObstacle, stGroundObstacle;
	DNM_tdstObstacle *p_stObstacle;
	HIE_tdxHandleToSuperObject hSupObjCol;

	#ifdef DNM_DEBUG
		if(p_stDynamic == NULL)
			return;
		if(!HIE_fn_bIsSuperObjectValid(hSupObj))
			return;
	#endif
  
	/* variable init*/
	xMinSlope = MEC_fn_xMinSlope ( p_stDynamic);
	xMaxSlope = MEC_fn_xMaxSlope ( p_stDynamic);
	MTH3D_M_vSetVectorElements( &stVertical, MTH_C_ZERO, MTH_C_ZERO, MTH_C_ONE);
	MTH3D_M_vNullVector (&stAdjustVector);
	MTH3D_M_vNullVector (&stPushVector);
	p_stGroundObstacle = NULL;
	p_stWallObstacle = NULL;
	p_stWallEdgeObstacle = NULL;
	p_stObstacle = NULL;
	bAdjust = (g_lCallCounter==0);

	/* Matrix init */
	hCurrentMatrix = DNM_M_p_stDynamicsGetCurrentMatrix (p_stDynamic);
	hPreviousMatrix = DNM_M_p_stDynamicsGetPreviousMatrix (p_stDynamic);

	/* get previous obstacle if there is one*/
	if (DNM_M_bDynamicsIsCollisionReport(p_stDynamic))
		p_stObstacle = DNM_M_p_stReportGetGround (DNM_M_p_stDynamicsGetReport (p_stDynamic));
 
	POS_fn_vCopyMatrix(p_stPOS_DownPosition, hCurrentMatrix);
	POS_fn_vCopyMatrix(p_stPOS_UpPosition, hPreviousMatrix);
 
	/* collision translation*/
	/* if we don't call collisions each frame, we retrieve last collide position, and make as*/
	/* if it's the PreviousMatrix.*/
 	if (fn_ucCollSetGetCollComputeFrequencySO(hSupObj)>1)
	{
		hPreviousMatrix = &stPreviousMatrix;
		POS_fn_vCopyMatrix (hPreviousMatrix,DNM_M_p_stDynamicsGetPreviousMatrix (p_stDynamic));
		MEC_fn_vGetCollisionTranslation (p_stDynamic,hPreviousMatrix);
	}
 
 
	p_stCurrentTranslation = POS_fn_p_stGetTranslationVector ( hCurrentMatrix );
	p_stPreviousTranslation = POS_fn_p_stGetTranslationVector ( hPreviousMatrix );
 	MTH3D_M_vSubVector (&stMove,p_stCurrentTranslation,p_stPreviousTranslation);

	if (DNM_M_bDynamicsIsMechanicChange(p_stDynamic) && !g_lCallCounter)
	{
		if (MEC_fn_bCollision(&lObstacle,g_a_stObstacle,p_stDynamic,hSupObj,hPreviousMatrix,hPreviousMatrix,TRUE))
		{
			MEC_fn_vDeleteBaseBackFace ( lObstacle,g_a_stObstacle, p_stDynamic );
			MEC_fn_vDeleteNullTranslationObstacle ( lObstacle, g_a_stObstacle );
			MEC_fn_vComputeAdjustVector (&stAdjustVector, p_stDynamic, lObstacle, g_a_stObstacle, lObstacle);
			MTH3D_M_vAddVector (p_stPreviousTranslation,p_stPreviousTranslation,&stAdjustVector);
		}
	}
	
	/* stack protection -> no more than 5 recursives calls. ( experience teaches it's enough )*/
	g_lCallCounter++;
	if (g_lCallCounter>5)
	{
		DNM_M_vDynamicsSetForceSafeWalk (p_stDynamic,TRUE);

		if (MEC_fn_bCollision(&lObstacle,g_a_stObstacle,p_stDynamic,hSupObj,hPreviousMatrix,hPreviousMatrix,TRUE))
		{
			MEC_fn_vDeleteBaseBackFace ( lObstacle,g_a_stObstacle, p_stDynamic );
			MEC_fn_vDeleteNullTranslationObstacle ( lObstacle, g_a_stObstacle );
			MEC_fn_vComputeAdjustVector (&stAdjustVector, p_stDynamic, lObstacle, g_a_stObstacle, lObstacle);
			MTH3D_M_vAddVector (p_stPreviousTranslation,p_stPreviousTranslation,&stAdjustVector);
		}

		/* stay here 	*/
		MTH3D_M_vCopyVector (p_stCurrentTranslation,p_stPreviousTranslation);
		MTH3D_M_vNullVector ( DNM_M_pDynamicsGetPreviousSpeed(p_stDynamic) );
		return;
	}
 
	/* normal obstacle*/
	/* If we are in contact with an obstacle, use its normal.*/
	/* if not, make as if previous obstacle is horizontal.*/
	p_stNormal = &stVertical;
 
	if (p_stObstacle && !DNM_M_bDynamicsIsMechanicChange(p_stDynamic))
	{
		p_stNormal = DNM_M_p_stObstacleGetNorm (p_stObstacle);
		if (MTH3D_M_bIsNullVector(p_stNormal))
		{
			p_stNormal = &stVertical;
		}
	}
 
	/* normal and tangent move / previous ground obstacle met.*/
	xDotProduct	= MTH3D_M_xDotProductVector (&stMove,p_stNormal);
	MTH3D_M_vMulScalarVector (&stNormalMove,xDotProduct,p_stNormal);
	MTH3D_M_vSubVector (&stTangentMove,&stMove,&stNormalMove);
 
	xNormTangentMove = MTH3D_M_xNormVector(&stTangentMove);

	if (MTH_M_bGreater(xNormTangentMove,MTH_M_xDoubleToReal(1e-3)))
		MTH3D_M_vDivScalarVector ( &stNormalizeTangentMove, &stTangentMove, xNormTangentMove )
	else
		MTH3D_M_vNullVector ( &stNormalizeTangentMove );
	

	if (g_lCallCounter==1)
	{
		g_bHighSpeed = MTH_M_bGreater(xNormTangentMove,C_ulDNM_RAYMAN_ZDM_RADIUS) || DNM_M_bDynamicsIsForceSafeWalk(p_stDynamic) || DNM_M_bDynamicsIsMechanicChange(p_stDynamic);
		DNM_M_vDynamicsSetForceSafeWalk ( p_stDynamic, FALSE );
	}
	else if (!g_bHighSpeed)
	{
		if (DNM_M_bDynamicsIsForceSafeWalk(p_stDynamic))
			g_bHighSpeed = TRUE;
	}

	if (DNM_M_bDynamicsIsComplexSize(p_stDynamic) && MEC_fn_bIsPlatform(p_stDynamic))
	{
		MTH3D_M_vSubVector (&stAbsoluteTangentMove,p_stCurrentTranslation,POS_fn_p_stGetTranslationVector(DNM_M_p_stDynamicsGetAbsolutePreviousMatrix(p_stDynamic)));
		xDotProduct	= MTH3D_M_xDotProductVector (&stAbsoluteTangentMove,p_stNormal);
		MTH3D_M_vMulScalarVector (&stVector,xDotProduct,p_stNormal);
		MTH3D_M_vSubVector (&stAbsoluteTangentMove,&stAbsoluteTangentMove,&stVector);
	}
	else
		MTH3D_M_vCopyVector ( &stAbsoluteTangentMove, &stTangentMove );

	/* There is only a normal move. Probably, the actor falls with its gravity, so we call "jump" mechanic.*/
	if ( MTH_M_bLess(xNormTangentMove,C_xDNM_NUL_MOVE) && MTH_M_bGreater(MTH3D_M_xNormVector(&stNormalMove),C_xDNM_NUL_MOVE) && ( !DNM_M_bDynamicsIsComplexSize(p_stDynamic) || !MEC_fn_bIsPlatform(p_stDynamic) ) && !DNM_M_bDynamicsIsMechanicChange(p_stDynamic) )
	{
		MEC_fn_vBaseObstacleManagement ( p_stDynamic, hSupObj, xDT );
 
		if (DNM_M_ulReportGetSurfaceState(&g_stReport)&C_WOT_ulGround)
		{
			p_stGroundObstacle = DNM_M_p_stReportGetGround (&g_stReport);
			xSlide = MEC_fn_xGetSlide (p_stDynamic,p_stGroundObstacle);
			if (MTH_M_bEqual(xSlide,MTH_C_ZERO)) DNM_M_vDynamicsSetNoGravity (p_stDynamic,TRUE);
		}
 
		return;
	}
 
 

	/* This part of the code compute the move we are going to pass to collisions.*/
	/**/
	/**/
	/**/
	/**/
	/*         The actor walk : P : previous position*/
	/*							C : current position  ( it's an example )*/
	/**/
	/**/
	/*                      O         X    <- p_stPOS_UpPosition*/
	/*                      |         **/
	/*                     / \        **/
	/*                      |-------->*                   */
	/*                     / \        **/
	/*     -----------------P---------*---------------------------------------------------------------------*/
	/*                                **/
	/*                                **/
	/*                                C*/
	/*                                **/
	/*                                * */
	/*								  X	   <- p_stPOS_DownPosition*/
	/**/
	/**/
	/**/
	/**/
 
	xSpeedZ = MTH_M_xMul ( MTH3D_M_xGetZofVector (DNM_M_pDynamicsGetPreviousSpeed(p_stDynamic)), xDT );

	xFactor = MTH_M_xMul (xMinSlope, xNormTangentMove);
	if (MTH_M_bGreater (xFactor,MTH_M_xNeg(C_xDNM_ON_GROUND_DEFAULT_NORMAL_MOVE))) xFactor = MTH_M_xNeg(C_xDNM_ON_GROUND_DEFAULT_NORMAL_MOVE);

	if (DNM_M_bDynamicsIsMechanicChange(p_stDynamic))
	if (MTH_M_bGreater (xFactor,xSpeedZ)) xFactor = xSpeedZ;

	p_stDownTranslation = POS_fn_p_stGetTranslationVector ( p_stPOS_DownPosition );
	MTH3D_M_vCopyVector ( p_stDownTranslation, p_stPreviousTranslation);
	MTH3D_M_vAddVector (p_stDownTranslation,p_stDownTranslation,&stTangentMove);
	MTH3D_M_vMulScalarVector (&stDownVector,xFactor,p_stNormal);
	MTH3D_M_vAddVector (p_stDownTranslation,p_stDownTranslation,&stDownVector);
 
	lObstacle2 = 0;
	if (g_bHighSpeed)
	{
		p_stUpTranslation = POS_fn_p_stGetTranslationVector ( p_stPOS_UpPosition );
		MTH3D_M_vCopyVector ( p_stUpTranslation, p_stPreviousTranslation);
		MTH3D_M_vAddVector (p_stUpTranslation,p_stUpTranslation,&stTangentMove);

		if (MEC_fn_bCollision(&lObstacle2,g_a_stObstacle,p_stDynamic,hSupObj,hPreviousMatrix,p_stPOS_UpPosition,TRUE))
		{
			for (lCounter=0; lCounter<lObstacle2; lCounter++)
			{
				p_stTmpObstacle = g_a_stObstacle+lCounter;
				if (MEC_fn_bIsObstacleValid(p_stTmpObstacle))
				{
					if (!MEC_fn_bWallObstacle(p_stDynamic,p_stTmpObstacle))
						MEC_fn_vInvalidateObstacle (p_stTmpObstacle);
//					else
//					{
//						xDotProduct = MTH3D_M_xDotProductVector ( DNM_M_p_stObstacleGetNorm(p_stTmpObstacle), &stNormalizeTangentMove );
//						if ( MTH_M_bGreater(xDotProduct,MTH_M_xDoubleToReal(1e-3)) )
//						if ( MTH_M_bGreaterZero(xDotProduct) )
//							MEC_fn_vInvalidateObstacle(p_stTmpObstacle);
//					}
				}
			}
		}
	}

	xFactor = MTH_M_xMul (xMaxSlope, xNormTangentMove);
	if (MTH_M_bLess (xFactor,C_xDNM_ON_GROUND_DEFAULT_NORMAL_MOVE)) xFactor = C_xDNM_ON_GROUND_DEFAULT_NORMAL_MOVE;
 
	p_stUpTranslation = POS_fn_p_stGetTranslationVector ( p_stPOS_UpPosition );
	MTH3D_M_vCopyVector ( p_stUpTranslation, p_stPreviousTranslation);
	MTH3D_M_vAddVector (p_stUpTranslation,p_stUpTranslation,&stTangentMove);
	MTH3D_M_vMulScalarVector (&stUpVector,xFactor,p_stNormal);
	MTH3D_M_vAddVector (p_stUpTranslation,p_stUpTranslation,&stUpVector);
 
	/* call collisions*/
	COL_g_lMaxNumberOfCollisions = COL_C_xMaxNumberOfCollisions - lObstacle2;
	MEC_fn_bCollision(&lObstacle,g_a_stObstacle+lObstacle2,p_stDynamic,hSupObj,p_stPOS_UpPosition,p_stPOS_DownPosition,TRUE); 
	lObstacle += lObstacle2;
	COL_g_lMaxNumberOfCollisions = COL_C_xMaxNumberOfCollisions;

	if (lObstacle)
	{
		p_stGroundObstacle = MEC_fn_pSelectGround (p_stDynamic,lObstacle-lObstacle2,g_a_stObstacle+lObstacle2,&bFirstGround);
		
		if (p_stGroundObstacle)
			bStep = MEC_fn_bDetectStep (p_stDynamic, lObstacle-lObstacle2, g_a_stObstacle+lObstacle2, p_stGroundObstacle, &stAbsoluteTangentMove );
		else
			bStep = FALSE;
	
		/* the actor falls ?*/
		/* test only if he desn't climb a step */
//		if (!bStep && (g_lCallCounter==1)) MEC_fn_vEdgeAnalysis (p_stDynamic, lObstacle, g_a_stObstacle, p_stGroundObstacle);
		if (!bStep && (g_lCallCounter==1)) MEC_fn_vEdgeAnalysis (p_stDynamic, lObstacle-lObstacle2, g_a_stObstacle+lObstacle2, p_stGroundObstacle);
		
		/* delete unnecessary obstacles*/
		if (bFirstGround) MEC_fn_vDeleteWallEdge (lObstacle, g_a_stObstacle, p_stDynamic);
		MEC_fn_vDeleteUnderGroundWall (lObstacle, g_a_stObstacle, p_stDynamic,p_stGroundObstacle);
//		MEC_fn_vDeleteOnGroundBackFace (lObstacle-lObstacle2, g_a_stObstacle+lObstacle2, p_stDynamic, &stAbsoluteTangentMove, p_stGroundObstacle );
		MEC_fn_vDeleteOnGroundBackFace (lObstacle, g_a_stObstacle, p_stDynamic, &stAbsoluteTangentMove, p_stGroundObstacle );

		/* crash test*/
		if (MEC_fn_bMainActor(hSupObj) && (g_lCallCounter==1))
			MEC_fn_vCrashAnalysis ( p_stDynamic,lObstacle, g_a_stObstacle );
 

		/* search first collided ground and wall */
		p_stWallObstacle = NULL;
		p_stMobileObstacle = NULL;
		lObstacleCounter = 0;

		if (lObstacle2)
		{
			for (lCounter=0; lCounter<lObstacle2; lCounter++)
			{
				p_stTmpObstacle = g_a_stObstacle+lCounter;
				if (MEC_fn_bIsObstacleValid(p_stTmpObstacle))
				{
					if ( MEC_fn_bIsCollide(p_stTmpObstacle) && !MEC_fn_bGroundObstacle(p_stDynamic,p_stTmpObstacle) )
						bWallCheck = TRUE;
				}
			}
		}

		for (lCounter=0; lCounter<lObstacle; lCounter++)
		{
			p_stTmpObstacle = g_a_stObstacle+lCounter;
			if (MEC_fn_bIsObstacleValid(p_stTmpObstacle))
			{
				if (MEC_fn_bGroundObstacle (p_stDynamic,p_stTmpObstacle))
				{
					if (p_stGroundObstacle==p_stTmpObstacle)
						lObstacleCounter = lCounter;
				}
				else
				{
					if ( ((DNM_M_eObstacleGetType(p_stTmpObstacle)&DNM_ObsType_Mobile)==DNM_ObsType_Mobile) && !p_stMobileObstacle )
					{
						hSupObjCol = DNM_M_p_stObstacleGetObject (p_stTmpObstacle);
	
						if (HIE_fn_bIsSuperObjectValid(hSupObjCol))
						{
							hSupObjCol = MEC_fn_hGetFatherActor (hSupObjCol);

							if ((fn_ulStandardGameGetCustomBitsSO(hSupObjCol) & C_ulDNM_CAN_PUSH_RAYMAN_CUSTOM_BIT) == C_ulDNM_CAN_PUSH_RAYMAN_CUSTOM_BIT)
								p_stMobileObstacle = p_stTmpObstacle;
						}
					}

					if (MEC_fn_bWallObstacle (p_stDynamic,p_stTmpObstacle))
					{
						MTH3D_M_vSubVector ( &stVector, DNM_M_p_stObstacleGetContact(p_stTmpObstacle), p_stPreviousTranslation );	

						xTmpReal = MTH_M_xAdd ( MTH_M_xSqr(MTH3D_M_xGetXofVector(&stVector)),MTH_M_xSqr(MTH3D_M_xGetYofVector(&stVector)) );

						if (MTH_M_bLess(xTmpReal,xWallDistance))
						{
							p_stWallObstacle = p_stTmpObstacle;
							lObstacleCounter = lCounter;
							xWallDistance = xTmpReal;
						}
					}
					else
					{
						/* swim case : we make as if the ceilling is a wall */
						if (!p_stWallObstacle) 
						{
							p_stWallObstacle = p_stTmpObstacle;
							lObstacleCounter = lCounter;
						}
					}
				}
			}
		}

		/* report obstacles in the report.*/
		MEC_fn_vReportCollision (p_stDynamic,hSupObj,lObstacle,g_a_stObstacle,lObstacleCounter);

		if (DNM_M_bDynamicsIsCanFall(p_stDynamic) && DNM_M_bDynamicsIsNeverFall(p_stDynamic) && !p_stWallObstacle)
		{
			MTH3D_M_vAddVector (p_stCurrentTranslation,p_stPreviousTranslation,&stTangentMove);
			MEC_fn_vComputeSpeed (p_stDynamic,xDT);
			return;
		}

		/* we meet a ground ...*/
		if (p_stGroundObstacle)
		{
			xSlide = MEC_fn_xGetSlide (p_stDynamic,p_stGroundObstacle);
			if (MTH_M_bEqual(xSlide,MTH_C_ZERO)) DNM_M_vDynamicsSetNoGravity (p_stDynamic,TRUE);
			
			if(!p_stWallObstacle)
			{
				/* and just a ground, so we can walk on it and it's all is ok.*/
				MTH3D_M_vAddVector (&stVector, p_stDownTranslation, DNM_M_xObstacleGetTranslation (p_stGroundObstacle));
				POS_fn_vSetTranslationVector ( hCurrentMatrix, &stVector );

				if ( (g_lCallCounter==1) && ( DNM_M_bDynamicsIsCollisionReport(p_stDynamic) && ((DNM_M_ulReportGetPrevSurfaceState(DNM_M_p_stDynamicsGetReport(p_stDynamic))&C_WOT_ulWall)!=C_WOT_ulWall) ))
					DNM_M_vDynamicsSetWallAdjust(p_stDynamic,TRUE);

			}
			else
			{
				if ( p_stMobileObstacle && (g_lCallCounter==1) )
				{
					DNM_M_MecObstacleCopyClone ( &stGroundObstacle, p_stGroundObstacle );
					DNM_M_vDynamicsSetForceSafeWalk (p_stDynamic,TRUE);

					
					if(MEC_fn_bCollision(&lObstacle,g_a_stObstacle,p_stDynamic,hSupObj,hPreviousMatrix,hPreviousMatrix,TRUE))
					{
						MEC_fn_vDeleteBaseBackFace ( lObstacle,g_a_stObstacle, p_stDynamic );
						MEC_fn_vDeleteNullTranslationObstacle ( lObstacle, g_a_stObstacle );

						lWallCounter = 0;
						for (lCounter=0; lCounter<lObstacle; lCounter++)
						{
							p_stTmpObstacle = g_a_stObstacle + lCounter;
							if ( MEC_fn_bIsObstacleValid(p_stTmpObstacle) )
							{
								if ( MEC_fn_bWallObstacle(p_stDynamic,p_stTmpObstacle) && ((DNM_M_eObstacleGetType(p_stTmpObstacle)&DNM_ObsType_Mobile)!=DNM_ObsType_Mobile) )
									lWallCounter++;
							
								if (p_stMobileObstacle && MTH_M_bLess(MTH3D_M_xDotProductVector(DNM_M_p_stObstacleGetNorm(p_stMobileObstacle),DNM_M_p_stObstacleGetNorm(p_stTmpObstacle)),MTH_M_xDoubleToReal(-0.5))) /* 60° */
									bSqueezeByWall = TRUE;
							}
						}
						
						if (lWallCounter>0)
						{
							/* we collide at least one wall of the map -> complete method */
							MEC_fn_vComputeAdjustVector (&stAdjustVector, p_stDynamic, lObstacle, g_a_stObstacle, lObstacle);
							MTH3D_M_vAddVector ( p_stPreviousTranslation, p_stPreviousTranslation, &stAdjustVector );
							MTH3D_M_vAddVector ( p_stCurrentTranslation, p_stPreviousTranslation,  &stMove );
						}
						else
						{
							/* we collide only the ZDR */
							p_stWallObstacle2 = NULL;

							for (lCounter=0; lCounter<lObstacle && !p_stWallObstacle2; lCounter++)
							{
								p_stTmpObstacle = g_a_stObstacle + lCounter;
								if ( MEC_fn_bIsObstacleValid(p_stTmpObstacle) )
								{
									if (p_stTmpObstacle && ((DNM_M_eObstacleGetType(p_stTmpObstacle)&DNM_ObsType_Mobile)==DNM_ObsType_Mobile))
									{
										p_stWallObstacle2 = p_stTmpObstacle;

										if (MTH_M_bLess(MTH3D_M_xNormVector(DNM_M_xObstacleGetTranslation(p_stWallObstacle2)),C_ulDNM_RAYMAN_ZDM_RADIUS))
										{
											xDotProduct = MTH3D_M_xDotProductVector (DNM_M_xObstacleGetTranslation(p_stWallObstacle2),DNM_M_p_stObstacleGetNorm(&stGroundObstacle));
											MTH3D_M_vMulScalarVector (&stVector,xDotProduct,DNM_M_p_stObstacleGetNorm(&stGroundObstacle));
											MTH3D_M_vSubVector (&stVector,DNM_M_xObstacleGetTranslation(p_stWallObstacle2),&stVector);
											MTH3D_M_vAddVector ( p_stPreviousTranslation, p_stPreviousTranslation, &stVector );
											MTH3D_M_vAddVector ( p_stCurrentTranslation, p_stPreviousTranslation, &stMove );
										}
									}
								}
							}
						}
					}
					
					MEC_fn_vGroundObstacleManagement ( p_stDynamic, hSupObj, xDT );
				}
				else
				{ 
					if (DNM_M_bDynamicsIsWallAdjust(p_stDynamic) && ( DNM_M_bDynamicsIsCollisionReport(p_stDynamic) && ((DNM_M_ulReportGetPrevSurfaceState(DNM_M_p_stDynamicsGetReport(p_stDynamic))&C_WOT_ulWall)!=C_WOT_ulWall) ) )
					{
						bWallCheck=TRUE;
						DNM_M_vDynamicsSetWallAdjust(p_stDynamic,FALSE);
					}
					
					DNM_M_vDynamicsSetForceSafeWalk (p_stDynamic,TRUE);

					/* and a wall. The actor must slide on the wall.*/
					if ( p_stWallObstacle && ( DNM_M_bDynamicsIsMechanicChange(p_stDynamic) || (DNM_M_bDynamicsIsComplexSize(p_stDynamic) && MEC_fn_bIsPlatform(p_stDynamic)) || bWallCheck || bSqueezeByWall ) && MEC_fn_bIsCollide(p_stWallObstacle) && MTH_M_bEqualZero(xSlide) )
					{
						bOk = MEC_fn_vComputeAdjustVector (&stAdjustVector, p_stDynamic, lObstacle-lObstacle2, g_a_stObstacle+lObstacle2, lObstacle-lObstacle2);
						if (lObstacle2)
						{
							bOk |= MEC_fn_vComputeAdjustVector (&stAdjustVector1, p_stDynamic, lObstacle2, g_a_stObstacle, lObstacle2);
						}
						else
						{
							MTH3D_M_vNullVector (&stAdjustVector1);
						}

						if ( !lObstacle2 || MEC_fn_bIsNullVector(&stAdjustVector) || MEC_fn_bIsNullVector(&stAdjustVector1) )
						{
							MTH3D_M_vAddVector ( &stAdjustVector, &stAdjustVector, &stAdjustVector1 );
						}
						else
						{
							MTH3D_M_vNormalizeVector ( &stVector, &stAdjustVector1 );
							xDotProduct = MTH3D_M_xDotProductVector (&stAdjustVector,&stVector);
							if (MTH_M_bLess(xDotProduct,MTH3D_M_xNormVector(&stAdjustVector1)))
							{
								MTH3D_M_vMulScalarVector (&stVector,xDotProduct,&stVector);
								MTH3D_M_vSubVector (&stAdjustVector,&stAdjustVector,&stVector);
								MTH3D_M_vAddVector (&stAdjustVector,&stAdjustVector,&stAdjustVector1);
							}
						}

						xDotProduct = MTH3D_M_xDotProductVector (&stAdjustVector,DNM_M_p_stObstacleGetNorm(p_stGroundObstacle));
						MTH3D_M_vMulScalarVector (&stVector,xDotProduct,DNM_M_p_stObstacleGetNorm(p_stGroundObstacle));
						MTH3D_M_vSubVector (&stAdjustVector,&stAdjustVector,&stVector);
						MTH3D_M_vAddVector (&stAdjustVector,&stAdjustVector,DNM_M_xObstacleGetTranslation (p_stGroundObstacle));

						
						if (!DNM_M_bDynamicsIsSwim(p_stDynamic) /*&& !DNM_M_bDynamicsIsMechanicChange(p_stDynamic)*/)
						{
							xDotProduct = MTH3D_M_xDotProductVector (&stAdjustVector,DNM_M_p_stObstacleGetNorm(p_stGroundObstacle));
							MTH3D_M_vMulScalarVector (&stVector,xDotProduct,DNM_M_p_stObstacleGetNorm(p_stGroundObstacle));
							MTH3D_M_vSubVector (&stAdjustVector,&stAdjustVector,&stVector);
							MTH3D_M_vAddVector (&stAdjustVector,&stAdjustVector,DNM_M_xObstacleGetTranslation (p_stGroundObstacle));
						}

						MTH3D_M_vAddVector (&stSafeTranslation,  p_stDownTranslation, &stAdjustVector);
						MTH3D_M_vSubVector (&stVector, &stSafeTranslation, p_stPreviousTranslation);
						MTH3D_M_vSubVector (&stMove,&stMove,&stVector);
					}
					else
						/* we use its previous position that is safe.*/
						MTH3D_M_vCopyVector (&stSafeTranslation,p_stPreviousTranslation);

					MTH3D_M_vCopyVector (p_stCurrentTranslation,&stSafeTranslation);
 
					/* compute wall slide -> Current position is the new place were we try to go*/
					MEC_fn_vWallObstacleManagement ( &stWallMove, p_stDynamic, &stMove, DNM_M_p_stObstacleGetNorm(p_stGroundObstacle), DNM_M_p_stObstacleGetNorm(p_stWallObstacle), xDT, FALSE );

					if (bOk && !(DNM_M_bDynamicsIsComplexSize(p_stDynamic) && MEC_fn_bIsPlatform(p_stDynamic)))
					{
						/* stWallMove contains the move due to wall slide. If it's not significant, it's no use to continue.*/
						MTH3D_M_vSubVector ( &stVector, &stMove, &stWallMove );
//						if (!MEC_fn_bIsNullVector(&stVector))
						{
							if (!MEC_fn_bIsNullVector(&stWallMove))
								MEC_fn_vGroundObstacleManagement (p_stDynamic, hSupObj, xDT);
							else
							{
								/* change z to be sure actor is in contact with ground */
								MTH3D_M_vCopyVector (p_stCurrentTranslation,&stSafeTranslation);
							}
						}
//						else
//						{
//							MTH3D_M_vAddVector (&stVector, p_stDownTranslation, DNM_M_xObstacleGetTranslation (p_stGroundObstacle));
//							POS_fn_vSetTranslationVector ( hCurrentMatrix, &stVector );
//						}
					}
					else
					{
						if (MEC_fn_bCollision(&lObstacle,g_a_stObstacle,p_stDynamic,hSupObj,hCurrentMatrix,hCurrentMatrix,TRUE))
						{
							MEC_fn_vDeleteBaseBackFace ( lObstacle,g_a_stObstacle, p_stDynamic );
							MEC_fn_vDeleteNullTranslationObstacle ( lObstacle, g_a_stObstacle );
							MEC_fn_vComputeAdjustVector (&stAdjustVector, p_stDynamic, lObstacle, g_a_stObstacle, lObstacle);
							MTH3D_M_vAddVector (p_stCurrentTranslation,p_stCurrentTranslation,&stAdjustVector);
						}

						MEC_fn_vComputeSpeed (p_stDynamic,xDT);
						return;
					}
				}
			}
		}
		else
		{

/*			if (lObstacle2>0)
			{
				for (lCounter=0; lCounter<lObstacle2 && !bWall; lCounter++)
				{
					p_stTmpObstacle = g_a_stObstacle+lCounter;
					if (MEC_fn_bIsObstacleValid(p_stTmpObstacle))
					{
						if (MEC_fn_bWallObstacle (p_stDynamic,p_stTmpObstacle))
							bWall=TRUE;
					}
				}
			} */
			
			if ( p_stWallObstacle /*&& (!g_bHighSpeed||bWall)*/ )
			{
				if ( DNM_M_bDynamicsIsCollisionReport(p_stDynamic) && ((DNM_M_ulReportGetPrevSurfaceState(DNM_M_p_stDynamicsGetReport(p_stDynamic))&C_WOT_ulWall)!=C_WOT_ulWall) )
					bWallCheck=TRUE;

				/* there is no ground. So we can't walk.*/
				MEC_fn_vComputeAdjustVector (&stAdjustVector, p_stDynamic, lObstacle-lObstacle2, g_a_stObstacle+lObstacle2, lObstacle-lObstacle2);
				if (lObstacle2)
					MEC_fn_vComputeAdjustVector (&stAdjustVector1, p_stDynamic, lObstacle2, g_a_stObstacle, lObstacle2);
				else
					MTH3D_M_vNullVector (&stAdjustVector1);

				if ( !lObstacle2 || MEC_fn_bIsNullVector(&stAdjustVector) || MEC_fn_bIsNullVector(&stAdjustVector1) )
				{
					MTH3D_M_vAddVector ( &stAdjustVector, &stAdjustVector, &stAdjustVector1 );
				}
				else
				{
					MTH3D_M_vNormalizeVector ( &stVector, &stAdjustVector1 );
					xDotProduct = MTH3D_M_xDotProductVector (&stAdjustVector,&stVector);
					if (MTH_M_bLess(xDotProduct,MTH3D_M_xNormVector(&stAdjustVector1)))
					{
						MTH3D_M_vMulScalarVector (&stVector,xDotProduct,&stVector);
						MTH3D_M_vSubVector (&stAdjustVector,&stAdjustVector,&stVector);
						MTH3D_M_vAddVector (&stAdjustVector,&stAdjustVector,&stAdjustVector1);
					}
				}
					
				MTH3D_M_vAddVector (&stSafeTranslation,  p_stDownTranslation, &stAdjustVector);
				
				MTH3D_M_vSubVector (&stVector, &stSafeTranslation, p_stPreviousTranslation);
				MTH3D_M_vSubVector (&stMove,&stMove,&stVector);	


				DNM_M_vDynamicsSetForceSafeWalk (p_stDynamic,TRUE);

				MTH3D_M_vCopyVector (p_stCurrentTranslation,&stSafeTranslation);
 
				/* We slide on the wall, and hope to find a ground under the new position.*/
				MEC_fn_vWallObstacleManagement ( &stWallMove, p_stDynamic, &stMove, p_stNormal, DNM_M_p_stObstacleGetNorm(p_stWallObstacle), xDT, FALSE );
				
				if (!MEC_fn_bIsNullVector(&stWallMove)) MEC_fn_vGroundObstacleManagement ( p_stDynamic, hSupObj, xDT );
				else
					MTH3D_M_vCopyVector (p_stCurrentTranslation,&stSafeTranslation);
			}
			else
			{
				DNM_M_vDynamicsSetForceSafeWalk (p_stDynamic,TRUE);

				/* Never replace actor under the ground */
				if ( MTH_M_bGreater(MTH3D_M_xNormVector(&stNormalMove),C_ulDNM_RAYMAN_ZDM_RADIUS) && MTH_M_bLessZero(MTH3D_M_xGetZofVector(&stNormalMove)) )
					POS_fn_vCopyMatrix ( hCurrentMatrix, p_stPOS_DownPosition );

				/* there is no ground, no wall, no valid obstacles. So we can't walk anymore.*/
				if (DNM_M_bDynamicsIsNeverFall(p_stDynamic))
					MTH3D_M_vAddVector (p_stCurrentTranslation,p_stPreviousTranslation,&stTangentMove);

				if (g_lCallCounter>1)
					POS_fn_vCopyMatrix ( hCurrentMatrix, hPreviousMatrix );

				DNM_M_vDynamicsSetStop (p_stDynamic,FALSE);
			}
		}
		
		MEC_fn_vComputeSpeed (p_stDynamic,xDT);
		return;
	}
	DNM_M_vDynamicsSetForceSafeWalk (p_stDynamic,TRUE);

	/* Never replace actor under the ground */
	if ( MTH_M_bGreater(MTH3D_M_xNormVector(&stNormalMove),C_ulDNM_RAYMAN_ZDM_RADIUS) && MTH_M_bLessZero(MTH3D_M_xGetZofVector(&stNormalMove)) )
		POS_fn_vCopyMatrix ( hCurrentMatrix, p_stPOS_DownPosition );

	/* There is no obstacle at all.*/
	if (DNM_M_bDynamicsIsNeverFall(p_stDynamic))
		MTH3D_M_vAddVector (p_stCurrentTranslation,p_stPreviousTranslation,&stTangentMove);

	if (g_lCallCounter>1)
		POS_fn_vCopyMatrix ( hCurrentMatrix, hPreviousMatrix );

	DNM_M_vDynamicsSetStop (p_stDynamic,FALSE);
	MEC_fn_vComputeSpeed (p_stDynamic,xDT);
	return;
}
 
			
void MEC_fn_vGroundGuess (DNM_tdstDynamics *p_stDynamic, MTH_tdxReal xDT)
{
	POS_tdxHandleToPosition hCurrentMatrix, hPreviousMatrix;
	MTH3D_tdstVector* p_stNormal;
	MTH3D_tdstVector *p_stCurrentTranslation, *p_stPreviousTranslation; 
	MTH3D_tdstVector stMove, stVector;
	MTH_tdxReal xDotProd;
 
	p_stNormal = DNM_M_pDynamicsGetGroundNormal (p_stDynamic);
	if (MTH3D_M_bIsNullVector(p_stNormal)) return;
	
	hCurrentMatrix = DNM_M_p_stDynamicsGetCurrentMatrix (p_stDynamic);
	hPreviousMatrix = DNM_M_p_stDynamicsGetPreviousMatrix (p_stDynamic);
	
	p_stCurrentTranslation = POS_fn_p_stGetTranslationVector ( hCurrentMatrix );
	p_stPreviousTranslation = POS_fn_p_stGetTranslationVector ( hPreviousMatrix );
	MTH3D_M_vSubVector (&stMove,p_stCurrentTranslation,p_stPreviousTranslation);
 
	xDotProd = MTH3D_M_xDotProductVector (&stMove,p_stNormal);
	MTH3D_M_vNormalizeVector (&stVector,p_stNormal);
	MTH3D_M_vMulScalarVector (&stVector,xDotProd,&stVector);
	MTH3D_M_vSubVector (&stMove,&stMove,&stVector);
 
	MTH3D_M_vAddVector (p_stCurrentTranslation,p_stPreviousTranslation,&stMove);
	MEC_fn_vComputeSpeed (p_stDynamic,xDT);
}
 
 
void MEC_fn_vSpiderObstacleManagement ( struct DNM_stDynamics *p_stDynamic, HIE_tdxHandleToSuperObject hSupObj, MTH_tdxReal xDT )
{
	long lObstacle;
	long lCounter;
	DNM_tdstMecObstacle *p_stObstacle, *p_stTmpObstacle;
	MTH_tdxReal xNormalMove;
	MTH3D_tdstVector stVector;
  
	POS_tdstCompletePosition a2_stPosition[2];
	POS_tdstCompletePosition *p_stPOS_StartPosition = a2_stPosition;
	POS_tdstCompletePosition *p_stPOS_EndPosition = a2_stPosition+1;
 	POS_tdxHandleToPosition hCurrentMatrix, hPreviousMatrix;
	MTH3D_tdstVector *p_stCurrentTranslation;
	MTH3D_tdstVector *p_stPreviousTranslation;
	MTH3D_tdstVector *p_stStartTranslation;
	MTH3D_tdstVector *p_stEndTranslation;
	MTH3D_tdstVector stMove;
	MTH3D_tdstVector *p_stX, *p_stY, *p_stZ;
 
/* XB 05/05/99 */
/* 	ACP_tdxBool bCollision = TRUE; */
/* End XB 05/05/99 */
 
  
	#ifdef DNM_DEBUG
		if(p_stDynamic == NULL)
			return;
		if(!HIE_fn_bIsSuperObjectValid(hSupObj))
			return;
	#endif
  
 
	/* Current Position Matrix */
	hCurrentMatrix = DNM_M_p_stDynamicsGetCurrentMatrix (p_stDynamic);
	hPreviousMatrix = DNM_M_p_stDynamicsGetPreviousMatrix (p_stDynamic);
 
 
	POS_fn_vCopyMatrix(p_stPOS_StartPosition, hCurrentMatrix);
	POS_fn_vCopyMatrix(p_stPOS_EndPosition, hCurrentMatrix);
	
	p_stCurrentTranslation = POS_fn_p_stGetTranslationVector ( hCurrentMatrix );
	p_stPreviousTranslation = POS_fn_p_stGetTranslationVector ( hPreviousMatrix );
	MTH3D_M_vSubVector (&stMove,p_stCurrentTranslation,p_stPreviousTranslation);
 
	/* normal and tangent move */
	POS_fn_vGetRotationVector ( hCurrentMatrix, &p_stX, &p_stY, &p_stZ );
	xNormalMove = MTH_M_xMul ( C_xDNM_SPIDER_SLOPE_LIMIT, MTH3D_M_xNormVector(&stMove) );
	if (MTH_M_bLess (xNormalMove,C_xDNM_SPIDER_DEFAULT_NORMAL_MOVE)) 
		xNormalMove = C_xDNM_SPIDER_DEFAULT_NORMAL_MOVE;
 
	p_stStartTranslation = POS_fn_p_stGetTranslationVector ( p_stPOS_StartPosition );
	MTH3D_M_vMulScalarVector (&stVector, xNormalMove, p_stZ);
	MTH3D_M_vAddVector ( p_stStartTranslation, p_stCurrentTranslation, &stVector );
 
	p_stEndTranslation = POS_fn_p_stGetTranslationVector ( p_stPOS_EndPosition );
	MTH3D_M_vMulScalarVector (&stVector, xNormalMove, p_stZ);
	MTH3D_M_vSubVector ( p_stEndTranslation, p_stCurrentTranslation, &stVector );
 
	if(MEC_fn_bCollision(&lObstacle,g_a_stObstacle,p_stDynamic,hSupObj,p_stPOS_StartPosition,p_stPOS_EndPosition,TRUE)) 
	{
		MTH3D_tdstVector* p_stNormal;
		MTH3D_tdstVector stRotationAxis; 
 
		MEC_fn_vComputeAdjustVector (&stVector, p_stDynamic, lObstacle, g_a_stObstacle, lObstacle);
		MTH3D_M_vAddVector (p_stCurrentTranslation,p_stEndTranslation,&stVector);
 
		p_stObstacle = NULL;
		for (lCounter=0; lCounter<lObstacle && !p_stObstacle; lCounter++)
		{
			p_stTmpObstacle = g_a_stObstacle + lCounter;
			if (MEC_fn_bIsObstacleValid(p_stTmpObstacle)) p_stObstacle = p_stTmpObstacle; 
		}
 
		/* orient actor */
		POS_fn_vGetRotationVector ( hCurrentMatrix, &p_stX, &p_stY, &p_stZ );
		p_stNormal = DNM_M_p_stObstacleGetNorm (p_stObstacle);
 
		MTH3D_M_vCrossProductVectorWithoutBuffer (&stRotationAxis, p_stY, p_stZ);
		MTH3D_M_vCopyVector ( p_stZ, p_stNormal );
		MTH3D_M_vCrossProductVectorWithoutBuffer (p_stY, p_stZ, &stRotationAxis);
		MTH3D_M_vCrossProductVectorWithoutBuffer (p_stX, p_stY, p_stZ);
		MEC_fn_vUpdateMatrix ( p_stDynamic, hCurrentMatrix );
 
		MEC_fn_vReportCollision (p_stDynamic,hSupObj,lObstacle,g_a_stObstacle,lObstacle-1);
		MEC_fn_vComputeSpeed (p_stDynamic,xDT);
		return;
	}
			
	MEC_fn_vComputeSpeed (p_stDynamic,xDT);
}
 
 
