/*	
 *=======================================================================================
 * Name        : MecCol.c
 * Author      : J Thénoz               Date : 01/05/98
 * Description : Mechanic collision functions
 *=======================================================================================
 */
#include "cpa_expt.h"
#include "ACP_Base.h"
 
 
#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/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*/
 

//DNM_tdstMecObstacle g_a_stObstacle [COL_C_xMaxNumberOfCollisions];
DNM_tdstMecObstacle *g_a_stObstacle = (DNM_tdstMecObstacle *) COL_g_stCollisionCase;
ACP_tdxBool g_bWaterNoCollide;
 
ACP_tdxBool MEC_fn_bCollision ( long* p_lObstacle, DNM_tdstMecObstacle *p_stObstacle, struct DNM_stDynamics* p_stDynamic, HIE_tdxHandleToSuperObject p_stSupObj, POS_tdstCompletePosition *p_stStartPosition, POS_tdstCompletePosition *p_stEndPosition, ACP_tdxBool bBackFace )
{
	long lCounter;
	DNM_tdstMecObstacle *p_stTmpObstacle;
	DNM_tdstMecObstacle stHandObstacle;
	POS_tdxHandleToPosition hSupObjMatrix;
	MTH3D_tdstVector stMove, stVector;
	MTH3D_tdstVector *p_stStartTranslation, *p_stEndTranslation;
	MTH3D_tdstVector *p_stX, *p_stY, *p_stZ;
/* XB 05/05/99 */
/* 	ACP_tdxBool bIndexedTriangles = FALSE; */
/* End XB 05/05/99 */
	ACP_tdxBool bObstacleOk = FALSE;
	MTH_tdxReal xDotProd;
	ACP_tdxBool bWaterFace = FALSE;
	MTH_tdxReal xDotProdMax;
 
	*p_lObstacle = 0;
	xDotProdMax = MTH_C_MinusONE;
 
	*p_lObstacle = COL_lHaveITakeSThgIntoTheMug (p_stObstacle, p_stSupObj, p_stStartPosition, p_stEndPosition);
 
	/* delete back faces */
	if (!bBackFace) MEC_fn_vDeleteBaseBackFace ( *p_lObstacle,p_stObstacle, p_stDynamic );
 
	MEC_fn_vDeleteNoCollidedGroundFace (*p_lObstacle,p_stObstacle,p_stDynamic);
 
	if (*p_lObstacle<=0) return FALSE;

	if (DNM_M_bDynamicsIsHanging(p_stDynamic))
		MEC_fn_vDeleteHangingObstacle (*p_lObstacle,p_stObstacle,p_stDynamic);

	p_stStartTranslation = POS_fn_p_stGetTranslationVector (p_stStartPosition);
	p_stEndTranslation = POS_fn_p_stGetTranslationVector (p_stEndPosition);
	MTH3D_M_vSubVector ( &stMove, p_stStartTranslation, p_stEndTranslation );
 
	MEC_fn_vComputeCollisionTranslation (*p_lObstacle,p_stObstacle,&stMove);
	
	hSupObjMatrix = HIE_fn_hGetSuperObjectGlobalMatrix(p_stSupObj);
	POS_fn_vGetRotationVector ( hSupObjMatrix, &p_stX, &p_stY, &p_stZ );
 
	for (lCounter=0; lCounter<*p_lObstacle; lCounter++)
	{
		p_stTmpObstacle = p_stObstacle+lCounter;
		
		if (MEC_fn_bIsObstacleValid(p_stTmpObstacle))
		{
 
			ACP_tdxBool bCollisionOk = TRUE;
 
			/* hands */
			if (MEC_fn_bTypeOfGameMaterial (DNM_M_hObstacleGetMyMaterial(p_stTmpObstacle),C_xDNM_HAND_TYPE_GAME_MATERIAL))
			{
				bCollisionOk = FALSE;
				if (MEC_fn_bTypeOfGameMaterial (DNM_M_hObstacleGetCollidedMaterial(p_stTmpObstacle),C_xDNM_HANG_TYPE_GAME_MATERIAL) )
				{
					/* collide only hand with ground */
					if (MEC_fn_bGroundObstacle(p_stDynamic,p_stTmpObstacle))
					{
						/* choose best hand obstacle */
						MTH3D_M_vSubVector (&stVector,DNM_M_p_stObstacleGetContact(p_stTmpObstacle),POS_fn_p_stGetTranslationVector(hSupObjMatrix));
						if (!MEC_fn_bIsNullVector(&stVector))
							MTH3D_M_vNormalizeVector (&stVector,&stVector);
 
						xDotProd = MTH_M_xAbs(MTH3D_M_xDotProductVector (p_stY,&stVector));
						if (xDotProd>xDotProdMax)
						{
							xDotProdMax = xDotProd;
							DNM_M_MecObstacleCopyClone ( &stHandObstacle, p_stTmpObstacle );
						}
					}
				}
			}
 
			/* water */
			else if (MEC_fn_bTypeOfGameMaterial (DNM_M_hObstacleGetCollidedMaterial(p_stTmpObstacle),C_xDNM_WATER_TYPE_GAME_MATERIAL))
			{
				if (MEC_fn_bTypeOfGameMaterial (DNM_M_hObstacleGetMyMaterial(p_stTmpObstacle),C_xDNM_WATER_TYPE_GAME_MATERIAL))
				{
					
					if (!bWaterFace)
					{
					
						/* delete water back face */
						xDotProd = MTH3D_M_xDotProductVector ( DNM_M_p_stObstacleGetNorm(p_stTmpObstacle),DNM_M_pObstacleGetZoneMove(p_stTmpObstacle) );
 
						if (  MTH_M_bGreater ( MTH_M_xAbs ( MTH3D_M_xGetZofVector (DNM_M_pObstacleGetZoneMove(p_stTmpObstacle))), 0.03 )  )
						{
							if ( MTH_M_bLess(xDotProd, MTH_C_ZERO) )
							{
								MEC_fn_vReportCollision (p_stDynamic, p_stSupObj, 1, p_stTmpObstacle, 0);
								/* the obstacle is used for repositionning only if required*/
								bCollisionOk = fn_bBrainWaterCollideSO(p_stSupObj);
								if (!bCollisionOk) 
									g_bWaterNoCollide = TRUE;			
								bWaterFace = TRUE;
							}
							else 
								bCollisionOk = FALSE;
						}
						else
						{ 
							
							
							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) ); 
 
							xDotProd = MTH3D_M_xDotProductVector ( DNM_M_p_stObstacleGetNorm(p_stTmpObstacle),&stVector );
 
							if (MTH_M_bLessEqual(xDotProd,MTH_C_ZERO))
							{
								MEC_fn_vReportCollision (p_stDynamic, p_stSupObj, 1, p_stTmpObstacle, 0);
								bCollisionOk = fn_bBrainWaterCollideSO(p_stSupObj);
								if (!bCollisionOk) 
									g_bWaterNoCollide = TRUE;			
								bWaterFace = TRUE;
							}
							else 
								bCollisionOk = FALSE;
						} 
							
						if (MTH_M_bGreater(MTH3D_M_xGetZofVector(DNM_M_p_stObstacleGetNorm(p_stTmpObstacle)),MTH_C_ZERO))
							bCollisionOk = FALSE;
 
 
					}
					else
					{
						bCollisionOk = FALSE;
					}
 
				}
				else /*we do not report the collision because it does not exist: do not use the obstable for repositionning*/
					bCollisionOk = FALSE;
			
			}
 
			else
			{
				/* No collision faces */
				if (MEC_fn_bTypeOfGameMaterial (DNM_M_hObstacleGetCollidedMaterial(p_stTmpObstacle),C_xDNM_NO_COLLISION_TYPE_GAME_MATERIAL))
				{
					/* Climb faces */
					if (MEC_fn_bTypeOfGameMaterial (DNM_M_hObstacleGetCollidedMaterial(p_stTmpObstacle),C_xDNM_CLIMB_TYPE_GAME_MATERIAL))
						bCollisionOk = DNM_M_bDynamicsIsClimb(p_stDynamic);

					/* Gi faces */
					else if (MEC_fn_bTypeOfGameMaterial (DNM_M_hObstacleGetCollidedMaterial(p_stTmpObstacle),C_xDNM_GI_TYPE_GAME_MATERIAL))
						bCollisionOk = DNM_M_bDynamicsIsGi(p_stDynamic);

					/* Other faces */
					else if (MEC_fn_bTestMaskGameMaterial(DNM_M_hObstacleGetCollidedMaterial(p_stTmpObstacle),C_xDNM_COLLISION_REPORT_MASK))
					{
						bCollisionOk=FALSE;
						MEC_fn_vReportCollision (p_stDynamic, p_stSupObj, 1, p_stTmpObstacle, 0);
					}

					/* no report */
					else  bCollisionOk=FALSE;
				
				}
			}

			if (!bCollisionOk) MEC_fn_vInvalidateObstacle(p_stTmpObstacle);
			else bObstacleOk=TRUE;
		}
	}
 
 
	/* report hand obstacle */
	if (xDotProdMax != MTH_C_MinusONE)
		MEC_fn_vReportCollision (p_stDynamic, p_stSupObj, 1, &stHandObstacle, 0);
 
	return bObstacleOk;
}
 
 
 
#ifndef _FIRE_DEADCODE_U64_ /* Added by RUC */
ACP_tdxBool MEC_fn_bInCollision ( struct DNM_stDynamics *p_stDynamic, HIE_tdxHandleToSuperObject hSupObj )
{
/*	DNM_tdstMecObstacle a_stObstacle[COL_C_xMaxNumberOfCollisions];*/
	POS_tdxHandleToPosition hCurrentMatrix; 
	POS_tdxHandleToPosition hPreviousMatrix;
 
	hCurrentMatrix = DNM_M_p_stDynamicsGetCurrentMatrix (p_stDynamic);
	hPreviousMatrix = DNM_M_p_stDynamicsGetPreviousMatrix (p_stDynamic);
 
	return COL_lHaveITakeSThgIntoTheMug (g_a_stObstacle, hSupObj, hPreviousMatrix, hCurrentMatrix) > 0;
}
#endif /* _FIRE_DEADCODE_U64_ */ /* Added by RUC */
 
 
 
 
 
/* report collide actor */
void MEC_fn_vReportCollideActor (HIE_tdxHandleToSuperObject hCollideSupObj,DNM_tdstMecObstacle* p_stCollideObstacle)
{
	struct DNM_stDynamics* p_stDynamic;
	DNM_tdstObstacle* p_stObstacle;
	MTH3D_tdstVector stVector;
	HIE_tdxHandleToSuperObject hSupObj;
 
	hSupObj = DNM_M_p_stObstacleGetObject (p_stCollideObstacle);
	
	if (!HIE_fn_bIsSuperObjectValid(hSupObj)) return;
	hSupObj = MEC_fn_hGetFatherActor (hSupObj);
 
	p_stDynamic= fn_p_stDynamGetDynamicsSO (hSupObj);
	if (!p_stDynamic) return;
 
	/* no report so nothing to do here */
	if (!DNM_M_bDynamicsIsCollisionReport(p_stDynamic)) return;
 
	/* flag */
	DNM_M_ulReportAddSurfaceState (DNM_M_p_stDynamicsGetReport(p_stDynamic),C_WOT_ulForceMobile);
 
	/* obstacle */
	p_stObstacle = DNM_M_p_stReportGetCharacter ( DNM_M_p_stDynamicsGetReport(p_stDynamic) );
	DNM_M_xObstacleSetRate (p_stObstacle,0);
	MTH3D_M_vNegVector (&stVector,DNM_M_p_stObstacleGetNorm(p_stCollideObstacle));
	DNM_M_ObstacleSetNorm (p_stObstacle,&stVector);
	DNM_M_ObstacleSetContact (p_stObstacle,DNM_M_p_stObstacleGetContact(p_stCollideObstacle));
	DNM_M_p_stObstacleSetObject (p_stObstacle,hCollideSupObj);
	DNM_M_vObstacleSetCollidedMaterial (p_stObstacle,DNM_M_hObstacleGetMyMaterial(p_stCollideObstacle));
	DNM_M_vObstacleSetMyMaterial (p_stObstacle,DNM_M_hObstacleGetCollidedMaterial(p_stCollideObstacle));
}
 
 
 
/* report collision */
void MEC_fn_vReportCollision
(
	struct DNM_stDynamics* p_stDynamic,
	HIE_tdxHandleToSuperObject hSupObj,
	long lNbObstacle,
	DNM_tdstMecObstacle a_stObstacle[COL_C_xMaxNumberOfCollisions],
	long lObstacle
)
{
	MTH_tdxReal xDotProduct;
	MTH_tdxReal xPreviousRate, xCurrentRate;
	MTH3D_tdstVector stVerticalVector;
	MTH3D_tdstVector* p_stNormalVector;
	DNM_tdstMecObstacle* p_stTmpObstacle = NULL;
	long lCounter;
	ACP_tdxBool bStop = FALSE;
	ACP_tdxBool bHurt = FALSE;
 
	ACP_tdxBool bObstacle = FALSE;
	ACP_tdxBool bCeil = FALSE;
	ACP_tdxBool bWall = FALSE;
	ACP_tdxBool bGround = FALSE;
	ACP_tdxBool bActor = FALSE;
	ACP_tdxBool bWater = FALSE;
 
	ACP_tdxBool bObstacleEdge;
	ACP_tdxBool bCeilEdge;
	ACP_tdxBool bWallEdge;
	ACP_tdxBool bGroundEdge;
	ACP_tdxBool bActorEdge;
	ACP_tdxBool bWaterEdge;
	
	
	ACP_tdxBool bEdge;
 
	MTH3D_M_vSetVectorElements (&stVerticalVector, MTH_C_ZERO, MTH_C_ZERO, MTH_C_ONE);
	xPreviousRate = MTH_C_2;
 
	for (lCounter=0; lCounter<lNbObstacle && !bStop; lCounter++)
	{
		p_stTmpObstacle = a_stObstacle + lCounter;
	
		if (MEC_fn_bIsObstacleValid(p_stTmpObstacle))
		{
			xCurrentRate = DNM_M_xObstacleGetRate (p_stTmpObstacle);
			
			if ( lCounter<=lObstacle || MTH_M_bEqual(xPreviousRate,xCurrentRate) )
			{
				p_stNormalVector = DNM_M_p_stObstacleGetNorm (p_stTmpObstacle);
				bEdge = MEC_fn_bIsEdge (p_stTmpObstacle);
				xPreviousRate = xCurrentRate;
				

				/* obstacle */
				if (!bObstacle)
				{
					DNM_M_MecReportSetObstacle (&g_stReport, p_stTmpObstacle);
					bObstacleEdge = bEdge;
					bObstacle = TRUE;
				}
				else if (bObstacleEdge && !bEdge)
				{
					DNM_M_MecReportSetObstacle (&g_stReport, p_stTmpObstacle);
					bObstacleEdge = FALSE;
				}
 
 
				/* actor */
				if 
				( 
					((DNM_M_eObstacleGetType(p_stTmpObstacle) & DNM_ObsType_Mobile) == DNM_ObsType_Mobile )
				||	((DNM_M_eObstacleGetType(p_stTmpObstacle) & DNM_ObsType_MobileWall) == DNM_ObsType_MobileWall )
				)
				{
					if (!bActor)
					{
						DNM_M_MecReportSetCharacter (&g_stReport,p_stTmpObstacle);
						bActorEdge = bEdge;
						bActor = TRUE;
					}
					else if (bActorEdge && !bEdge)
					{
						DNM_M_MecReportSetCharacter (&g_stReport,p_stTmpObstacle);
						bActorEdge = FALSE;
					}
				}
 
				/* water */
				if 
				(
					(
						MEC_fn_bTypeOfGameMaterial (DNM_M_hObstacleGetCollidedMaterial(p_stTmpObstacle),C_xDNM_WATER_TYPE_GAME_MATERIAL)
						&& MEC_fn_bTypeOfGameMaterial (DNM_M_hObstacleGetMyMaterial(p_stTmpObstacle),C_xDNM_WATER_TYPE_GAME_MATERIAL)
					)
					||
					(
						MEC_fn_bTypeOfGameMaterial (DNM_M_hObstacleGetCollidedMaterial(p_stTmpObstacle),C_xDNM_NO_COLLISION_TYPE_GAME_MATERIAL)	
						&& MEC_fn_bTestMaskGameMaterial(DNM_M_hObstacleGetCollidedMaterial(p_stTmpObstacle),C_xDNM_COLLISION_REPORT_MASK)
					)
				)
				{
					/* water and no_collionable material are reported as water obstacles */
					if (!bWater)
					{
						DNM_M_MecReportSetWater (&g_stReport,p_stTmpObstacle);
						bWaterEdge = bEdge;
						bWater = TRUE;
					}
					else if (bWaterEdge && !bEdge)
					{
						DNM_M_MecReportSetWater (&g_stReport,p_stTmpObstacle);
						bWaterEdge = FALSE;
					}
				}
 
				else
				{	
					/* search collision type : wall or ground ? */
					xDotProduct = MTH3D_M_xDotProductVector ( p_stNormalVector, &stVerticalVector );		
 
					if (xDotProduct>MEC_fn_xGroundLimit(p_stDynamic) )
					{
						/* ground */
						if (!bGround)
						{
							DNM_M_MecReportSetGround (&g_stReport,p_stTmpObstacle);
							bGroundEdge = bEdge;
							bGround = TRUE;
						}
						else if (bGroundEdge && !bEdge)
						{
							DNM_M_MecReportSetGround (&g_stReport,p_stTmpObstacle);
							bGroundEdge = FALSE;
						}
					}
 
					else if (xDotProduct>MEC_fn_xWallLimit(p_stDynamic))
					{
						/* wall */
						if (!bWall)
						{
							DNM_M_MecReportSetWall (&g_stReport,p_stTmpObstacle);
							bWallEdge = bEdge;
							bWall = TRUE;
						}
						else if (bWallEdge && !bEdge)
						{
							DNM_M_MecReportSetWall (&g_stReport,p_stTmpObstacle);
							bWallEdge = FALSE;
						}
					}
					else
					{
						/* ceil */
						if (!bCeil)
						{
							DNM_M_MecReportSetCeil (&g_stReport,p_stTmpObstacle);
							bCeilEdge = bEdge;
							bCeil = TRUE;
						}
						else if (bCeilEdge && !bEdge)
						{
							DNM_M_MecReportSetCeil (&g_stReport,p_stTmpObstacle);
							bCeilEdge = FALSE;
						}
					}
				}
			}
			else bStop=TRUE;
		}
	}
 
	if (bActor)
	{
		DNM_M_ulReportAddSurfaceState (&g_stReport,C_WOT_ulMobile);
		MEC_fn_vReportCollideActor (hSupObj,DNM_M_p_stReportGetCharacter(&g_stReport));
	}
 
	if (bWater)
		DNM_M_ulReportAddSurfaceState (&g_stReport,C_WOT_ulWater);
 
	if (bGround)
	{
		DNM_M_ulReportAddSurfaceState (&g_stReport,C_WOT_ulGround);
		if (DNM_M_bDynamicsIsAdvancedSize(p_stDynamic)) DNM_M_vDynamicsSetGroundNormal (p_stDynamic,DNM_M_p_stObstacleGetNorm(DNM_M_p_stReportGetGround(&g_stReport)));
	}
	
	if (bWall)
	{
		DNM_M_ulReportAddSurfaceState (&g_stReport,C_WOT_ulWall);
		if (DNM_M_bDynamicsIsAdvancedSize(p_stDynamic)) DNM_M_vDynamicsSetWallNormal (p_stDynamic,DNM_M_p_stObstacleGetNorm(DNM_M_p_stReportGetWall(&g_stReport)));
	}
 
	if (bCeil)
		DNM_M_ulReportAddSurfaceState (&g_stReport,C_WOT_ulCeiling);
 
}
 
 
 
 
 
 
void MEC_fn_vFillCollisionReport
(
	struct DNM_stDynamics* p_stDynamic
)
{
	DNM_tdstReport* p_stReport;
 
	if (!DNM_M_bDynamicsIsCollisionReport(p_stDynamic)) return;
	if (DNM_M_ulReportGetSurfaceState(&g_stReport)==0) return;
 
	p_stReport = DNM_M_p_stDynamicsGetReport (p_stDynamic);
 
	DNM_M_ReportSetObstacle ( p_stReport, DNM_M_p_stReportGetObstacle(&g_stReport) );
 
	if ( DNM_M_ulReportGetSurfaceState(&g_stReport) & C_WOT_ulMobile )
	{
		DNM_M_ulReportAddSurfaceState (p_stReport,C_WOT_ulMobile);
		DNM_M_ReportSetCharacter ( p_stReport, DNM_M_p_stReportGetCharacter(&g_stReport) );
	}
 
	if ( DNM_M_ulReportGetSurfaceState(&g_stReport) & C_WOT_ulWater )
	{
		DNM_M_ulReportAddSurfaceState (p_stReport,C_WOT_ulWater);
		DNM_M_ReportSetWater ( p_stReport, DNM_M_p_stReportGetWater(&g_stReport) );
	}
 
	if ( DNM_M_ulReportGetSurfaceState(&g_stReport) & C_WOT_ulGround )
	{
		DNM_M_ulReportAddSurfaceState (p_stReport,C_WOT_ulGround);
		DNM_M_ReportSetGround ( p_stReport, DNM_M_p_stReportGetGround(&g_stReport) );
	}
 
	if ( DNM_M_ulReportGetSurfaceState(&g_stReport) & C_WOT_ulWall )
	{
		DNM_M_ulReportAddSurfaceState (p_stReport,C_WOT_ulWall);
		DNM_M_ReportSetWall ( p_stReport, DNM_M_p_stReportGetWall(&g_stReport) );
	}
 
	if ( DNM_M_ulReportGetSurfaceState(&g_stReport) & C_WOT_ulCeiling )
	{
		DNM_M_ulReportAddSurfaceState (p_stReport,C_WOT_ulCeiling);
		DNM_M_ReportSetCeil ( p_stReport, DNM_M_p_stReportGetCeil(&g_stReport) );
	}
 
}
 
 
ACP_tdxBool MEC_fn_vComputeAdjustVector (MTH3D_tdstVector *p_stAdjustVector, struct DNM_stDynamics* p_stDynamic, long lObstacle, DNM_tdstMecObstacle *p_stObstacle, long lObstacleMin)
{
	long lCounter;
	DNM_tdeObstacleType xObstacleType;
	ACP_tdxBool bAdjustVector = FALSE;
/* XB 05/05/99 */
/* 	ACP_tdxBool bJustOneDynamic = TRUE; */
/* End XB 05/05/99 */
	ACP_tdxBool bContinue;
	ACP_tdxBool bConflict = FALSE;
/* XB 05/05/99 */
/* 	ACP_tdxBool bMobileWall = FALSE; */
/* End XB 05/05/99 */
 
	DNM_tdstMecObstacle* p_stTmpObstacle, *p_stWaterObstacle;
	MTH_tdxReal xDotProd;
	MTH3D_tdstVector stNormalAdjustVector, stTangentAdjustVector, stVector;
	MTH3D_tdstVector stAdjustAxis;
 
	p_stWaterObstacle = NULL;
	MTH3D_M_vNullVector (p_stAdjustVector);
 
	for (lCounter=0; lCounter<lObstacle && !p_stWaterObstacle; lCounter++)
	{
		p_stTmpObstacle = p_stObstacle+lCounter;
		if (MEC_fn_bIsObstacleValid(p_stTmpObstacle) && MEC_fn_bIsWater(p_stTmpObstacle))
			p_stWaterObstacle = p_stTmpObstacle;
	}
 
	for (xObstacleType=DNM_ObsType_Scenery; xObstacleType<=DNM_ObsType_Mobile;  xObstacleType++)
	{
		bContinue=TRUE;
 
		for (lCounter=0; lCounter<lObstacle && bContinue; lCounter++)
		{
			p_stTmpObstacle = p_stObstacle+lCounter;
 
			if ( (DNM_M_eObstacleGetType(p_stTmpObstacle) & xObstacleType) == xObstacleType )
			{
				if ( lCounter<=lObstacleMin || MEC_fn_bIsCollide(p_stTmpObstacle) )
				{
					if ( MEC_fn_bIsObstacleValid(p_stTmpObstacle) && !MEC_fn_bIsWater(p_stTmpObstacle) /*&& MTH_M_bDifferentZero(DNM_M_xObstacleGetRate(p_stTmpObstacle))*/ )
					{
						if (bAdjustVector)
						{
							MTH3D_M_vCopyVector (&stVector,DNM_M_xObstacleGetTranslation(p_stTmpObstacle));
							if (!MEC_fn_bIsNullVector(p_stAdjustVector)) MTH3D_M_vNormalizeVector (&stAdjustAxis,p_stAdjustVector)
							else MTH3D_M_vCopyVector (&stAdjustAxis,p_stAdjustVector);

							xDotProd = MTH3D_M_xDotProductVector (&stAdjustAxis,&stVector);

//							if (MTH_M_bLess(xDotProd,MTH_C_ZERO))
//							if (MTH_M_bLess(xDotProd,MTH_C_MinusInv2))
//								bConflict = TRUE;

//							if (MTH_M_bGreater(xDotProd,MTH_C_MinusInv2))
							if (MTH_M_bGreater(xDotProd,MTH_C_ZERO))
							{									
								if (MTH_M_bLess(xDotProd,MTH3D_M_xNormVector(p_stAdjustVector)))
								{
									MTH3D_M_vMulScalarVector (&stNormalAdjustVector,xDotProd,&stAdjustAxis);
									MTH3D_M_vSubVector (&stTangentAdjustVector,&stVector,&stNormalAdjustVector);
									MTH3D_M_vAddVector (p_stAdjustVector, p_stAdjustVector, &stTangentAdjustVector );
								}
								else
								{
									MTH3D_M_vCopyVector (p_stAdjustVector,&stVector);
								}
							}
							else
							{
								bConflict = TRUE;
								if (xObstacleType==DNM_ObsType_Scenery)
								{
									MTH3D_M_vMulScalarVector (&stNormalAdjustVector,xDotProd,&stAdjustAxis);
									MTH3D_M_vSubVector (&stTangentAdjustVector,&stVector,&stNormalAdjustVector);
									MTH3D_M_vAddVector (p_stAdjustVector, p_stAdjustVector, &stTangentAdjustVector );
								}
							}
						}
						else
						{
							MTH3D_M_vCopyVector (p_stAdjustVector,DNM_M_xObstacleGetTranslation(p_stTmpObstacle));
							bAdjustVector = TRUE;
						}
					}
				}
				else bContinue=FALSE;
			}
		}
	}
 
	
	/* adjust actor position under water*/
	if (p_stWaterObstacle)
	{
		MTH3D_M_vNormalizeVector (&stAdjustAxis,DNM_M_p_stObstacleGetNorm(p_stWaterObstacle));
		xDotProd = MTH3D_M_xDotProductVector ( &stAdjustAxis, p_stAdjustVector );	
		MTH3D_M_vMulScalarVector (&stNormalAdjustVector,MTH_M_xSub(xDotProd,MTH_M_xDoubleToReal(0.01)),&stAdjustAxis);
		MTH3D_M_vSubVector (p_stAdjustVector,p_stAdjustVector,&stNormalAdjustVector);
		MTH3D_M_vAddVector (p_stAdjustVector,p_stAdjustVector,DNM_M_xObstacleGetTranslation(p_stWaterObstacle));
	}
 
	return !bConflict;
}
 
 
void MEC_fn_vEdgeAnalysis (	struct DNM_stDynamics *p_stDynamic, long lObstacle, DNM_tdstMecObstacle *p_stObstacle, DNM_tdstMecObstacle *p_stGround )
{
	long lCounter;
	MTH3D_tdstVector stContact, stVector, stEdgeVector, stVector1;
	DNM_tdstMecObstacle *p_stTmpObstacle;
	DNM_tdstMecObstacle *p_stNotGround = NULL;
/* XB 05/05/99 */
/* 	ACP_tdxBool bGround = FALSE; */
/* End XB 05/05/99 */
	ACP_tdxBool bNotGround = FALSE;
 
	long lGround = 0;
	
	MTH_tdxReal xDotProd;
/* XB 05/05/99 */
/* 	ACP_tdxBool bCanFall = FALSE; */
/* End XB 05/05/99 */
 
	DNM_M_bDynamicsSetCanFall (p_stDynamic,FALSE);
	

	/* no ground*/
	if ( !p_stGround )
	{
		/* there is no ground pass to the function, so we continue as we have always done */
	  
		
		/* if there is no ground edge in the obstacles, we cannot fall (but what about no ground obstacle at all ?)*/
		for
		(
			lCounter = 0, p_stTmpObstacle = p_stObstacle;
			lCounter < lObstacle && !p_stGround;
			lCounter ++, p_stTmpObstacle ++
		)
		{
			if ( MEC_fn_bIsObstacleValid(p_stTmpObstacle) && MEC_fn_bGroundObstacle(p_stDynamic,p_stTmpObstacle) )
			{
				if ( MEC_fn_bIsEdge(p_stTmpObstacle) )
				{
					p_stGround = p_stTmpObstacle; /*record the obstacle we found too...*/
				}
				else return;
			}
		}
	
		if (!p_stGround)
			return;
	
	}
	else
	{
		/* we can only fall if current ground obsacle is an edge */
		if ( !MEC_fn_bIsEdge(p_stGround) )
			return;
	}

	/* ground is a double-edge*/
	if (MEC_fn_bIsDoubleEdge(p_stGround)) return;
 
 
  /*keep the contact position on an edge we found	*/
	MTH3D_M_vCopyVector (&stContact,DNM_M_p_stObstacleGetContact(p_stGround));
 

  /*compute the normed vector from the contact point to the center of the terminal zone position*/
	MTH3D_M_vAddVector (&stVector1, DNM_M_pObstacleGetZonePosition(p_stGround), DNM_M_xObstacleGetTranslation(p_stGround));	
	MTH3D_M_vSubVector (&stVector1, &stVector1, &stContact);	
	MTH3D_M_vNormalizeVector (&stVector1,&stVector1);

	for
	(
		lCounter = 0, p_stTmpObstacle = p_stObstacle;
		lCounter < lObstacle;
		lCounter ++, p_stTmpObstacle ++
	)
	{
		if ( MEC_fn_bIsObstacleValid(p_stTmpObstacle) )
		{
 
			if ( MEC_fn_bGroundObstacle(p_stDynamic,p_stTmpObstacle) ) /*this one is a ground*/
			{
				
				if ( MEC_fn_bIsEdge(p_stTmpObstacle) )
				{
					/* same contact point ?*/
					MTH3D_M_vSubVector (&stVector,&stContact,DNM_M_p_stObstacleGetContact(p_stTmpObstacle));
					if ( MEC_fn_bIsNullVector(&stVector) ) lGround++;
				}
				else return; /*if any other obstacle is a non-edge, we cannot fall*/
 
			}
			else /*we find a non-ground edge*/
			{
				if (MEC_fn_bIsLowEdge(p_stTmpObstacle))
				{
					/*it is an edge, account for it in the number of different edge contact points*/
	  				MTH3D_M_vSubVector (&stVector,&stContact,DNM_M_p_stObstacleGetContact(p_stTmpObstacle));
					if ( MEC_fn_bIsNullVector(&stVector) ) /*at the same contact point than the ground edge*/
					{
						if ( MTH_M_bGreater(DNM_M_xDynamicsGetPreviousSlide (p_stDynamic),MTH_M_xDoubleToReal(0.5)) )
						{
							xDotProd = MTH3D_M_xDotProductVector ( DNM_M_p_stObstacleGetNorm(p_stGround), DNM_M_p_stObstacleGetNorm(p_stTmpObstacle) );
							if (MTH_M_bGreater(xDotProd,MTH_M_xDoubleToReal(0.707)))
								return;
						}
						
						xDotProd = MTH3D_M_xDotProductVector ( DNM_M_p_stObstacleGetNorm(p_stTmpObstacle), &stVector1 );
						
						if ( !p_stNotGround && MTH_M_bGreaterZero(xDotProd) )
						{
							bNotGround = TRUE;
							p_stNotGround = p_stTmpObstacle;
						}
					}
				}
				else if (MEC_fn_bWallObstacle(p_stDynamic,p_stTmpObstacle) && !MEC_fn_bIsHighEdge(p_stTmpObstacle))
				{
	  				MTH3D_M_vSubVector (&stVector,&stContact,DNM_M_p_stObstacleGetContact(p_stTmpObstacle));
					xDotProd = MTH3D_M_xDotProductVector ( DNM_M_p_stObstacleGetNorm(p_stGround), &stVector );
					if (MTH_M_bLessZero(xDotProd))
					{
						/* check we are on the ground side */
						xDotProd = MTH3D_M_xDotProductVector ( DNM_M_p_stObstacleGetNorm(p_stTmpObstacle), &stVector );
						if (MTH_M_bLess(xDotProd,MTH_M_xDoubleToReal(-1e-3)))
							return;
					}
				}
			}
		}
	}
 
	if (lGround>=2) return;
 
  /*here either we have a ground/non-ground obstable pair, or we have only a ground obstacle (bGround is true in either case)*/
 
  /*compute the normed vector from the contact point to the center of the terminal zone position*/
//	MTH3D_M_vAddVector (&stVector, DNM_M_pObstacleGetZonePosition(p_stGround), DNM_M_xObstacleGetTranslation(p_stGround));	
//	MTH3D_M_vSubVector (&stVector, &stVector, &stContact);	
//	MTH3D_M_vNormalizeVector (&stVector,&stVector);
 
	if ( bNotGround )
	{
		MTH3D_M_vAddVector (&stEdgeVector,DNM_M_p_stObstacleGetNorm(p_stGround),DNM_M_p_stObstacleGetNorm(p_stNotGround));
		bNotGround = !MEC_fn_bIsNullVector(&stEdgeVector); /*if the vector is null, we have only one edge normal (backface)*/
	}
 
	if ( bNotGround ) /*we have 2 edge normals*/
	{
		MTH_tdxReal xDotProd;
		MTH3D_M_vNormalizeVector (&stEdgeVector,&stEdgeVector);
		xDotProd = MTH3D_M_xDotProductVector (&stVector1,&stEdgeVector);
 
		if ( MTH_M_bLessZero(xDotProd) )
			return;
	}
 
	if ( MTH_M_bLess(MTH3D_M_xGetZofVector(&stVector1), C_xDNM_EDGE_GROUND_LIMIT) )
	{
		DNM_M_bDynamicsSetCanFall(p_stDynamic,TRUE);
		
		/* compute fall translation */
		if (DNM_M_bDynamicsIsComplexSize(p_stDynamic) )
		{
			MTH3D_M_vSetZofVector ( &stVector1, MTH_C_ZERO );
			if (!MEC_fn_bIsNullVector(&stVector1)) MTH3D_M_vNormalizeVector (&stVector1,&stVector1)
			else MTH3D_M_vNullVector (&stVector1);
			DNM_M_vDynamicsSetFallTranslation (p_stDynamic,&stVector1);
		}
	}
}
 
 
/* is the actor */
void MEC_fn_vCrashAnalysis
(
	struct DNM_stDynamics *p_stDynamic, 
	long lObstacle, 
	DNM_tdstMecObstacle *p_stObstacle 
)
{
	long lCounter;
	DNM_tdstMecObstacle *p_stTmpObstacle;
	DNM_tdstMecObstacle *p_stGroundObstacle, *p_stCeilObstacle;
 
	p_stGroundObstacle = NULL;
	p_stCeilObstacle = NULL;
	DNM_M_vDynamicsSetCrash(p_stDynamic,FALSE);
 
	p_stTmpObstacle = p_stObstacle;
	for (lCounter=0; lCounter<lObstacle; lCounter++)
	{
		if ( MEC_fn_bIsObstacleValid(p_stTmpObstacle) ) 
		{
			if (!p_stGroundObstacle && MEC_fn_bGroundObstacle(p_stDynamic,p_stTmpObstacle))
				p_stGroundObstacle = p_stTmpObstacle;
 
			if (!p_stCeilObstacle && MEC_fn_bCeilObstacle(p_stDynamic,p_stTmpObstacle))
				p_stCeilObstacle = p_stTmpObstacle;
		}
		p_stTmpObstacle++;
	}
 
	if (!p_stCeilObstacle || !p_stGroundObstacle)
		return;

	if 
	(
		(
			(DNM_M_eObstacleGetType(p_stGroundObstacle) & DNM_ObsType_Mobile)
		&&	MEC_fn_bCanCrashActor(p_stGroundObstacle)
		)
	||	
		(
			(DNM_M_eObstacleGetType(p_stCeilObstacle) & DNM_ObsType_Mobile)
		&&	MEC_fn_bCanCrashActor(p_stCeilObstacle)
		)
	)
	DNM_M_vDynamicsSetCrash(p_stDynamic,TRUE);
}
 
 
 
