/*
 **************************************************************************************************
 *	Tool functions for camera AI.
 **************************************************************************************************
 */
 
#define D_CineInfo_StructureDefine
 
#include "AIUseCPA.h"
#include "specif/AITools.h"
#include "GEO.h"
#include "GLI.h"
#include "COL.h"
#include "PO.h"
/*XB980821*/
#ifndef D_THROW_IPO
#include "IPO.h"
#endif /* D_THROW_IPO */
/*End XB*/
/* Shaitan Clean Env {*/
/*#include "ENV.h"*/
/*End Shaitan Clean Env }*/
#include "SND.h"
/* Shaitan Clean Env {*/
/*#include "SRF.h"*/
/*End Shaitan Clean Env }*/
#include "SCT.h"
#include "GAM.h"
 
#include "CAM_Base.h"
#include "CAM_Vis.h"
#include "CAM_Tool.h"
#include "safe.h"
/*
 **************************************************************************************************
 **************************************************************************************************
	TOOLS
 **************************************************************************************************
 **************************************************************************************************
 */
 
/*
 *=================================================================================================
 * Fast memcpy
 *=================================================================================================
 */
void CAM_memcpy(void *dest, void *src, long size)
{
	register long *psrc = (long*)src;
	register long *pdest = (long*)dest;
	register long lsize = size;
	while(lsize >= 4)
	{
		*pdest++ = *psrc++;
		lsize -= 4;
	}
	while(lsize)
	{
		*((char *)pdest++) = *((char *)psrc++);
		lsize--;
	}
}
 
/*
 *=================================================================================================
 *	Activate or desactivate an internal flag.
 *=================================================================================================
 */
void CAM_fn_vSetResetInternalFlag
(
	MS_tdxHandleToCineinfo	_hCineInfo,
	unsigned short			*_p_uwCurrentValue,
	unsigned short			*_p_uwVisibilityValue,
	unsigned short			*_p_uwWorkValue,
	long					_lTypeOfChange,
	long					_lChangingMode,
	unsigned short			_uwFlag
)
{
	if (_lTypeOfChange == 1)
	{
		CAM_fn_vSetCineinfoWorkFromCurrent(_hCineInfo);
		if (_lChangingMode)
			*_p_uwWorkValue |= _uwFlag;
		else
			*_p_uwWorkValue &= ~_uwFlag;
	}
	else
	{
		if (_lChangingMode)
		{
			*_p_uwCurrentValue |= _uwFlag;
			*_p_uwVisibilityValue |= _uwFlag;
			*_p_uwWorkValue |= _uwFlag;
		}
		else
		{
			*_p_uwCurrentValue &= ~_uwFlag;
			*_p_uwVisibilityValue &= ~_uwFlag;
			*_p_uwWorkValue &= ~_uwFlag;
		}
	}
}
 
/*
 *=================================================================================================
 *	Force the camera to be at a given position.
 *=================================================================================================
 */
void CAM_fn_vForceCameraPos(HIE_tdxHandleToSuperObject _hSuperObjCamera, MTH3D_tdstVector *_p_stPosition)
{
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
	DNM_tdstReport		*p_stReport;
/*	MTH3D_tdstVector	stTempVector;*/
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
 
	p_stReport = fn_pstGetDNMReport(_hSuperObjCamera);
 
	/*
	 * Force position in global and local matrix.
	 */
	POS_fn_vSetTranslationVector(HIE_fn_hGetSuperObjectGlobalMatrix(_hSuperObjCamera), _p_stPosition);
	POS_fn_vSetTranslationVector(HIE_fn_hGetSuperObjectMatrix(_hSuperObjCamera), _p_stPosition);
 
	/*
	 *	Init Last move in report camera
	 */
/*	MTH3D_M_vNullVector(&stTempVector);*/
/*	MTH3D_M_vCopyVector(DNM_M_p_stReportGetLastMove(p_stReport), &stTempVector);*/
	MTH3D_M_vNullVector(DNM_M_p_stReportGetLastMove(p_stReport));
 
	/*
	 * Recompute sector of camera.
	 */
	fn_vSectInfoInitForSingleCharacter(_hSuperObjCamera, _p_stPosition);
}
 
/*
 *=================================================================================================
 *	Force the camera to be at a given position.
 *=================================================================================================
 */
void CAM_fn_vForceCameraTgt
(
	HIE_tdxHandleToSuperObject	_hSuperObjCamera, 
	MTH3D_tdstVector			*_p_stPosition,
	MTH3D_tdstVector			*_p_stRefAxisZ
)
{
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
	MS_tdxHandleToDynam		h_Dynam;
    MS_tdxHandleToCineinfo	hCineInfo;
	DNM_tdstParsingDatas	*p_stParsingDatas;
	DNM_tdstReport			*p_stReport;
	MTH3D_tdstVector		stX, stY, stZ;
	MTH3D_tdstVector		stCameraPosition;
/*	MTH3D_tdstVector		stTempVector;*/
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
 
	hCineInfo = M_GetMSHandle(_hSuperObjCamera, Cineinfo);
	h_Dynam = M_GetMSHandle(_hSuperObjCamera, Dynam);
	p_stReport = fn_pstGetDNMReport(_hSuperObjCamera);
	p_stParsingDatas = fn_p_stDynamGetParsingDatas(h_Dynam);
 
	/* 
	 *	Get current camera position.
	 */
	POS_fn_vGetTranslationVector(HIE_fn_hGetSuperObjectGlobalMatrix(_hSuperObjCamera), &stCameraPosition); 
 
	/*
	 *	Compute system axis.
	 */
	MTH3D_M_vCopyVector(&stZ, _p_stRefAxisZ);
	CAM_fn_vComputeCameraSystemAxis
	(
		fn_p_stDynamGetDynamics(h_Dynam),
		_hSuperObjCamera,
		&stCameraPosition,
		_p_stPosition,
		&stX,
		&stY,
		&stZ
	);
 
	/*
	 * Set Rotation Matrix
	 */
	POS_fn_vSetRotationMatrix(HIE_fn_hGetSuperObjectMatrix(_hSuperObjCamera), &stX, &stY, &stZ);
	POS_fn_vSetRotationMatrix(HIE_fn_hGetSuperObjectGlobalMatrix(_hSuperObjCamera), &stX, &stY, &stZ);
 
	/*
	 *  - Set Target pos in ParsingDatas structure
	 *	- Init Last move Target in report camera
	 *	- Init Last Good Target Position in report camera
	 */
	MTH3D_M_vCopyVector(DNM_M_p_stCPDGetTarget(p_stParsingDatas), _p_stPosition);
 
/*	MTH3D_M_vNullVector(&stTempVector);*/
/*	MTH3D_M_vCopyVector(DNM_M_p_stReportGetLastTgtMove(p_stReport), &stTempVector);*/
	MTH3D_M_vNullVector(DNM_M_p_stReportGetLastTgtMove(p_stReport));
 
}
 
/*
 *=================================================================================================
 *	Test if perso is moving
 *=================================================================================================
 */       
ACP_tdxBool CAM_fn_bPersoIsMoving(CAM_tdstUpdateCamera *_p_stStruct, MTH3D_tdstVector *_p_stMove)
{
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
	MTH3D_tdstVector	stMove;
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
 
	CAM_fn_vAverageSpeed(_p_stStruct->hCineinfo, CAM_C_xAverageForComputeLinearSpeed, &stMove);
	if(MTH_M_bGreater(MTH3D_M_xNormVector(&stMove), CAM_C_xMinLinearSpeedTgtPerso))
	{
		if(_p_stMove)
		{
			MTH3D_M_vCopyVector(_p_stMove, &stMove);
		}
		return TRUE;
	}
 
	if(_p_stMove)
		MTH3D_M_vNullVector(_p_stMove);
 
	return FALSE;
}
 
/*
 *=================================================================================================
 *	Test if perso is moving
 *=================================================================================================
 */       
ACP_tdxBool CAM_fn_bPersoIsTurning(HIE_tdxHandleToSuperObject _h_SuperObjPerso, MTH_tdxReal *_p_xAngularSpeed)
{
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
	MS_tdxHandleToDynam		h_Dynam;
	DNM_tdstDynamics		*p_stDynamics;
	DNM_tdstReport			*p_stReport;
/*	DNM_tdstMove			*p_stSpeed;*/
	MTH_tdxReal				xAngle;
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
 
	if(_p_xAngularSpeed)
		*_p_xAngularSpeed = MTH_C_ZERO;
 
    h_Dynam = M_GetMSHandle(_h_SuperObjPerso, Dynam);
	if(h_Dynam == NULL)
		return FALSE;
	p_stDynamics = fn_p_stDynamGetDynamics(h_Dynam);  	
    if(p_stDynamics == NULL)
		return FALSE;
	p_stReport = DNM_M_p_stDynamicsGetReport(p_stDynamics);
	if(p_stReport == NULL)
		return FALSE;
 
	xAngle = MTH_M_xRotationGetAngle(MTH_M_p_stMoveGetAngular(DNM_M_p_stReportGetAbsoluteCurrSpeed(p_stReport)));
 
	if(MTH_M_bGreater(xAngle, CAM_C_xMinAngularSpeedTgtPerso))
	{
		if(_p_xAngularSpeed)
			*_p_xAngularSpeed = xAngle;
		return TRUE;
	}
 
	return FALSE;
}
 
/*
 *=================================================================================================
 *	Get normal of face of perso.
 *=================================================================================================
 */       
ACP_tdxBool CAM_fn_bPersoOnFace(HIE_tdxHandleToSuperObject _h_SuperObjPerso, MTH3D_tdstVector *_p_stNormal)
{
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
	MS_tdxHandleToDynam		h_Dynam;
	DNM_tdstDynamics		*p_stDynamics;
	DNM_tdstReport			*p_stReport;
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
 
	/*
	 *	Get the normal of the face the targeted perso is walking on.
	 */
    h_Dynam = M_GetMSHandle(_h_SuperObjPerso, Dynam);
	if(h_Dynam == NULL)
		return FALSE;
	p_stDynamics = fn_p_stDynamGetDynamics(h_Dynam);  	
    if(p_stDynamics == NULL)
		return FALSE;
	p_stReport = DNM_M_p_stDynamicsGetReport(p_stDynamics);
	if(p_stReport == NULL)
		return FALSE;
 
	/* Check if perso is on a ground */
	if(!(p_stReport->m_ulCurrSurfaceState & C_WOT_ulGround))
		return FALSE;
 
	MTH3D_M_vCopyVector(_p_stNormal, &p_stReport->m_stGround.m_stNorm);
	return TRUE;
}
 
/*
 *=================================================================================================
 *	Get the current father of a perso.
 *=================================================================================================
 */       
HIE_tdxHandleToSuperObject CAM_fn_hGetFather(HIE_tdxHandleToSuperObject _h_SuperObjPerso)
{
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
	MS_tdxHandleToDynam			h_Dynam;
	DNM_tdstDynamics			*p_stDynamics;
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
 
	if(_h_SuperObjPerso == NULL)
		return NULL;
    h_Dynam = M_GetMSHandle(_h_SuperObjPerso, Dynam);
	if(h_Dynam == NULL)
		return NULL;
	p_stDynamics = fn_p_stDynamGetDynamics(h_Dynam);  	
    if(p_stDynamics == NULL)
		return NULL;
 
	if (!DNM_M_bDynamicsIsComplexSize(p_stDynamics)) return NULL;
 
	return DNM_M_hDynamicsGetPlatformSO(p_stDynamics);
}
 
/*
 *=================================================================================================
 *	Projection of a vector on to a plane defined by a norm
 *=================================================================================================
 */
void CAM_fn_vComputeProjection
(
	MTH3D_tdstVector	*_p_sDestVector,
	MTH3D_tdstVector	*_p_sSrcVector,
	MTH3D_tdstVector	*_p_sNormVector
)
{
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
	MTH_tdxReal			xScalar;
	MTH3D_tdstVector	stNormPart;
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
 
	if(!MTH_M_bEqualZero(xScalar = MTH3D_M_xDotProductVector(_p_sSrcVector, _p_sNormVector)))
	{
		MTH3D_M_vMulScalarVector(&stNormPart, xScalar, _p_sNormVector);
/*		MTH3D_M_vSubVector(&stNormPart, _p_sSrcVector, &stNormPart);*/
/*		MTH3D_M_vCopyVector(_p_sDestVector, &stNormPart);*/
		MTH3D_M_vSubVector(_p_sDestVector, _p_sSrcVector, &stNormPart);
	}
	else
	{
		MTH3D_M_vCopyVector(_p_sDestVector, _p_sSrcVector);
	}
}
 
/*
 *=================================================================================================
 *	computing rotation between two vectors
 *=================================================================================================
 */
MTH_tdxReal CAM_fn_xComputeRotation
(
	MTH3D_tdstVector	*_p_stDestVector,
	MTH3D_tdstVector	*_p_stSrcVector,
	MTH3D_tdstVector	*_p_stAxisVector
)
{
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
    MTH_tdxReal			xCos;
	MTH_tdxReal			xDenom, xNumer;
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
 
	/* formula : cos(a,b) = a.b / sqrt(a.a * b.b) operation : 1 div, 1 sqrt, 10 mul, 6 add */
	if( MTH3D_M_bIsNullVector(_p_stSrcVector) || MTH3D_M_bIsNullVector(_p_stDestVector) )
		return MTH_C_ZERO;
 
	xDenom = MTH_M_xMul( MTH3D_M_xSqrVector( _p_stSrcVector ), MTH3D_M_xSqrVector( _p_stDestVector ) );
	xNumer = MTH3D_M_xDotProductVector( _p_stSrcVector, _p_stDestVector );
	xCos   = MTH_M_xDiv( xNumer, MTH_M_xSqrt( xDenom ) );
    
	if(_p_stAxisVector)
	{
		MTH3D_M_vCrossProductVector(_p_stAxisVector, _p_stSrcVector, _p_stDestVector);
		if(!MTH3D_M_bIsNullVector(_p_stAxisVector))
		{
			MTH3D_M_vNormalizeVector(_p_stAxisVector, _p_stAxisVector);
		}
	}
 
	if (MTH_M_bLess(xCos,MTH_C_MinusONE))
        xCos = MTH_C_MinusONE;
    else if (MTH_M_bGreater(xCos,MTH_C_ONE))
        xCos =MTH_C_ONE;
 
	return (MTH_M_xACos(xCos));
}
 
 
/*
 *=================================================================================================
 * Two vectors are equal with epsilon ?
 *=================================================================================================
 */
ACP_tdxBool	CAM_fn_bEqualVectorWithEpsilon
(
	MTH3D_tdstVector	*_p_stVector1, 
	MTH3D_tdstVector	*_p_stVector2, 
	MTH_tdxReal			_xEpsilon
)
{
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
	MTH3D_tdstVector	stDiffVector;
	MTH_tdxReal			xDist;
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
 
	MTH3D_M_vSubVector(&stDiffVector, _p_stVector1, _p_stVector2);
	xDist = MTH3D_M_xSqrVector(&stDiffVector);
 
	if(MTH_M_bGreater(xDist, MTH_M_xSqr(_xEpsilon)))
		return FALSE;
	else
		return TRUE;
}
 
/*
 *=================================================================================================
 *	Check validity of the computed angles
 *=================================================================================================
 */
void CAM_fn_vCheckValidityOfComputedAngles
(
	MS_tdxHandleToInternalCineinfo	_hIntCineInfo,
	MTH_tdxReal						*_p_xHorizontalAngle,
	MTH_tdxReal						*_p_xVerticalAngle
)
{
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
	MTH_tdxReal		xAbsHorizontalAngle, xAbsVerticalAngle;
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
 
	xAbsHorizontalAngle =  MTH_M_xAbs(*_p_xHorizontalAngle);
 
	xAbsVerticalAngle = MTH_M_xAbs(*_p_xVerticalAngle);
	if(MTH_M_bGreater(xAbsVerticalAngle, MTH_C_PiBy2))
	{
		if (MTH_M_bGreater(*_p_xVerticalAngle, MTH_C_ZERO))
			*_p_xVerticalAngle = MTH_M_xSub(MTH_C_Pi, *_p_xVerticalAngle);
		else
			*_p_xVerticalAngle = MTH_M_xSub(MTH_M_xNeg(MTH_C_Pi), *_p_xVerticalAngle);
	}
 
	*_p_xHorizontalAngle = CAM_fn_xSetAngleInInterval02Pi(*_p_xHorizontalAngle);
	*_p_xVerticalAngle = CAM_fn_xSetAngleInInterval02Pi(*_p_xVerticalAngle);
}
 
/*
 *=================================================================================================
 *	Compute horizontal angle and vertical angle between two Vector
 *=================================================================================================
 */
void CAM_fn_vComputeAnglesBetweenTwoVectors
(
	MS_tdxHandleToInternalCineinfo	_hIntCineInfo,
	MTH3D_tdstVector				*_p_stSourceVector,
	MTH3D_tdstVector				*_p_stTargetVector,
	MTH_tdxReal						*_p_xHorizontalAngle,
	MTH_tdxReal						*_p_xVerticalAngle,
	MTH3D_tdstVector				*_p_stRefAxisZ
)
{
	*_p_xHorizontalAngle = CAM_fn_xComputeHorizontalAngle(_p_stSourceVector, _p_stTargetVector, _p_stRefAxisZ);
	*_p_xVerticalAngle = CAM_fn_xComputeVerticalAngle(_p_stSourceVector, _p_stTargetVector, _p_stRefAxisZ);
 
	CAM_fn_vCheckValidityOfComputedAngles(_hIntCineInfo, _p_xHorizontalAngle, _p_xVerticalAngle);
}
 
/*
 *=================================================================================================
 *	Set the angle in  ]-Pi,Pi] :
 *=================================================================================================
 */
MTH_tdxReal CAM_fn_xSetAngleInIntervalPiPi(MTH_tdxReal _xAngle)
{
	if(MTH_M_bGreater(_xAngle, MTH_C_Pi))
		return (MTH_M_xSub(_xAngle, MTH_C_2Pi));
	else if(MTH_M_bLessEqual(_xAngle, MTH_M_xNeg(MTH_C_Pi)))
		return (MTH_M_xAdd(_xAngle, MTH_C_2Pi));
	else
		return (_xAngle);
}
 
/*
 *=================================================================================================
 *	Set the angle in  [0,2Pi[ :
 *=================================================================================================
 */
MTH_tdxReal CAM_fn_xSetAngleInInterval02Pi(MTH_tdxReal _xAngle)
{
	if (MTH_M_bLess(_xAngle, MTH_C_ZERO))
		return(MTH_M_xAdd(_xAngle, MTH_C_2Pi));
	else if (MTH_M_bGreaterEqual(_xAngle, MTH_C_2Pi))
		return(MTH_M_xSub(_xAngle, MTH_C_2Pi));
	else
		return (_xAngle);
}
 
 
/*
 **************************************************************************************************
 **************************************************************************************************
 **************************************************************************************************
 **************************************************************************************************
 */
 
 
/*
 *=================================================================================================
 * Test if camera has reached the wanted position.
 * Compute the current camera pos with the actuel global matrix.
 *=================================================================================================
 */
 
#ifndef _FIRE_DEADCODE_U64_ /* Added by RUC */
ACP_tdxBool CAM_fn_bPositionIsReached
(
    HIE_tdxHandleToSuperObject	_hCamera,
	MTH3D_tdstVector			*_p_stWantedPosition,
	MTH_tdxReal					_xDistMin,
	MTH3D_tdstVector			*_p_stCurrentPosition
)
{
	POS_fn_vGetTranslationVector(HIE_fn_hGetSuperObjectGlobalMatrix(_hCamera), _p_stCurrentPosition);
	return(CAM_fn_bEqualVectorWithEpsilon(_p_stCurrentPosition, _p_stWantedPosition, _xDistMin));
}
#endif /* _FIRE_DEADCODE_U64_ */ /* Added by RUC */
 
 
/*
 *=================================================================================================
 * Compute sight axis of a perso. Sight axis depend on the perso matrix and dynamical state.
 *=================================================================================================
 */
void CAM_fn_vGetPersoSightAxis(CAM_tdstUpdateCamera *_p_stStruct, MTH3D_tdstVector *_p_stAxis,  MTH3D_tdstVector *_p_stAxisZ)
{
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
	MTH3D_tdstVector			stFirstComplementaryAxis;
	MTH3D_tdstVector			stSecondComplementaryAxis;
	POS_tdstCompletePosition	*p_stPersoGlobalMatrix;
	MTH3D_tdstVector			stTmpVector1, stTmpVector2;
/*	MTH_tdxReal					xSign;*/
	unsigned char						ucChannel;
	HIE_tdxHandleToSuperObject	hPerso;
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
 
	hPerso = _p_stStruct->hCineinfoWork->hSuperObjectTargeted;
 
	fn_vGetPersoSightAxisSystem
	(
		_p_stStruct->hCineinfo,
		_p_stAxis,/*&stAxis		*/
		&stFirstComplementaryAxis,
		&stSecondComplementaryAxis
	);

	if ((ucChannel = _p_stStruct->hCineinfoWork->cChannel) != C_ucUnknownChannel)
	{
		/* FBF blindage acces modules {*/
#ifdef ACTIVE_EDITOR
		fn_vCheckModuleAccess(hPerso,TRUE, &ucChannel);
#endif
		/* } fin blindage acces modules */
		hPerso = fn_hGetSuperObjectInChannel(fn_h3dDataGetChannelSOList(M_GetMSHandle(hPerso, 3dData)),(short) ucChannel);
	}
	p_stPersoGlobalMatrix = HIE_fn_hGetSuperObjectGlobalMatrix(hPerso);
 
 
/*	if (MTH_M_bEqual(MTH_M_xAbs((xSign = MTH3D_M_xGetXofVector(_p_stAxis))), MTH_C_ONE))
	{
		POS_fn_vGetRotationMatrix( p_stPersoGlobalMatrix, _p_stAxis, &stTmpVector1, &stTmpVector2);
		if (_p_stAxisZ)
			MTH3D_M_vCopyVector(_p_stAxisZ, &stTmpVector2);
	}
	else
	{
		if (MTH_M_bEqual(MTH_M_xAbs((xSign=MTH3D_M_xGetZofVector(_p_stAxis))), MTH_C_ONE))
		{
			POS_fn_vGetRotationMatrix(p_stPersoGlobalMatrix, &stTmpVector1, &stTmpVector2, _p_stAxis);
			if (_p_stAxisZ)
				MTH3D_M_vNegVector(_p_stAxisZ, &stTmpVector2);
		}
		else
		{
			xSign = MTH3D_M_xGetYofVector(_p_stAxis);	
			POS_fn_vGetRotationMatrix(p_stPersoGlobalMatrix, &stTmpVector1, _p_stAxis, &stTmpVector2);
			if (_p_stAxisZ)
				MTH3D_M_vCopyVector(_p_stAxisZ, &stTmpVector2);
		}
	}
 
	if (MTH_M_bLessZero(xSign))
	{
		MTH3D_M_vNegVector(_p_stAxis, _p_stAxis);
	}*/
 
	/* Force axis to be -Y*/
	POS_fn_vGetRotationMatrix(p_stPersoGlobalMatrix, &stTmpVector1, _p_stAxis, &stTmpVector2);
	if (_p_stAxisZ)
		MTH3D_M_vCopyVector(_p_stAxisZ, &stTmpVector2);
	MTH3D_M_vNegVector(_p_stAxis, _p_stAxis);
}
 
/*
 **************************************************************************************************
 **************************************************************************************************
 **************************************************************************************************
 **************************************************************************************************
 */
MTH_tdxReal	Cam_fn_xComputeProjectionRail
(
	MTH3D_tdstVector	*_p_stTargetedPersoPos,
	MTH3D_tdstVector	*_p_stWpPosition,
	MTH3D_tdstVector	*_p_stDestWpPosition
)			
{
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
	MTH3D_tdstVector			stAxe;
	MTH3D_tdstVector			stTargetWp;	
	MTH3D_tdstVector			stProjectedVector;
	MTH3D_tdstVector			stProjectedPoint;
	MTH_tdxReal					xFactor;
	MTH_tdxReal					xDotProduct;
	MTH_tdxReal					xSqrNorm;
	MTH_tdxReal					xDist1, xDist2;
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
	MTH3D_M_vSubVector(&stTargetWp, _p_stTargetedPersoPos, _p_stWpPosition);
	MTH3D_M_vSubVector(&stAxe, _p_stDestWpPosition, _p_stWpPosition);
 
	/*
	 * Factor of projection of Vector on Rail Axis
	 */
	xSqrNorm = MTH3D_M_xSqrVector(&stAxe);
	if (MTH_M_bIsNull(xSqrNorm))
	{
		return (MTH_C_InfinitPlus);
	}
	xDotProduct = MTH3D_M_xDotProductVector(&stAxe,  &stTargetWp);
	xFactor = MTH_M_xDiv(xDotProduct, xSqrNorm);
	
	if(MTH_M_bLessZero(xFactor))
	{
		xDist1 = MTH3D_M_xVectorGap(_p_stWpPosition, _p_stTargetedPersoPos);
		xDist2 = MTH3D_M_xVectorGap(_p_stDestWpPosition, _p_stTargetedPersoPos);
 
		if (MTH_M_bGreater(xDist1,xDist2))
			return (xDist2);
		else
			return (xDist1);
	}
 
	MTH3D_M_vMulScalarVector(&stProjectedVector, xFactor, &stAxe);
 
	MTH3D_M_vAddVector(&stProjectedPoint, &stProjectedVector, _p_stWpPosition);
 
	return (MTH3D_M_xVectorGap(&stProjectedPoint, _p_stTargetedPersoPos));
}
 
/*
 *=================================================================================================
 * Compute the camera moving on a rail
  *=================================================================================================
 */
void Cam_fn_vComputeMovingOnRail
(
	CAM_tdstUpdateCamera    *_p_stStruct,
	MTH3D_tdstVector		*_p_stWantedPosition,
	MTH3D_tdstVector		*_p_stWpPosition,
	MTH3D_tdstVector		*_p_stPreviousWpPosition,
	MTH_tdxReal				_xDistWanted
)
{
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
	MTH3D_tdstVector			stRailAxis;
	MTH3D_tdstVector			stTargetCamera;	
	MTH3D_tdstVector			stVector;
	MTH3D_tdstVector			stVector1;
	MTH3D_tdstVector			stProjectedVector;
	MTH3D_tdstVector			stCameraNextWp;	
	MTH3D_tdstVector			stProjectedPoint;
	MTH3D_tdstVector			stWpDestination;
	MTH_tdxReal					xFactor;
	MTH_tdxReal					xDotProduct;
	MTH_tdxReal					xNorm;
	MTH_tdxReal					xActualNorm;
	MTH_tdxReal					xSqrNorm;
	MTH_tdxReal					xDistWanted;
	char						cCameraIsOnWp = 0;
 
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
	CAM_fn_vComputeReferencePoint(_p_stStruct);
	MTH3D_M_vSubVector(&stCameraNextWp, _p_stWpPosition, &_p_stStruct->stCurrentCameraPos);
	MTH3D_M_vCopyVector(&stWpDestination, _p_stWpPosition);
	MTH3D_M_vSubVector(&stTargetCamera, &_p_stStruct->stTargetedPersoPos, &_p_stStruct->stCurrentCameraPos);
 
	/*
	 * Factor of projection of Vector on Rail Axis
	 */
	xSqrNorm = MTH3D_M_xSqrVector(&stCameraNextWp);
	if (MTH_M_bIsNull(xSqrNorm))
	{
		MTH3D_M_vSubVector(&stCameraNextWp, &_p_stStruct->stCurrentCameraPos, _p_stPreviousWpPosition);
		MTH3D_M_vCopyVector(&stWpDestination, _p_stPreviousWpPosition);
		xSqrNorm = MTH3D_M_xSqrVector(&stCameraNextWp);
		if (MTH_M_bIsNull(xSqrNorm))
		{
			MTH3D_M_vCopyVector(_p_stWantedPosition, &_p_stStruct->stCurrentCameraPos);
			return;
		}
		cCameraIsOnWp = 1;
	}
	xDotProduct = MTH3D_M_xDotProductVector(&stCameraNextWp,  &stTargetCamera);
	xFactor = MTH_M_xDiv(xDotProduct, xSqrNorm);
 
	if (!MTH_M_bIsNullWithEpsilon(xFactor,MTH_M_xFloatToReal(0.0001f)))
	{
		/* axis of rail */
		if (cCameraIsOnWp)
			{MTH3D_M_vSubVector(&stCameraNextWp, &_p_stStruct->stCurrentCameraPos, &stWpDestination);}
		else
			{MTH3D_M_vSubVector(&stCameraNextWp, &stWpDestination, &_p_stStruct->stCurrentCameraPos);}
 
		MTH3D_M_vMulScalarVector(&stProjectedVector, xFactor, &stCameraNextWp);
		MTH3D_M_vSubVector(&stVector1, &stTargetCamera, &stProjectedVector);
		MTH3D_M_vAddVector(&stProjectedPoint, &_p_stStruct->stCurrentCameraPos, &stProjectedVector);
		xNorm = MTH3D_M_xSqrVector(&stVector1);
		xDistWanted = MTH_M_xSqr(_xDistWanted);
		xActualNorm = MTH3D_M_xVectorGap(&stProjectedPoint, &_p_stStruct->stCurrentCameraPos); 
 
		if (!MTH_M_bGreater(xNorm, xDistWanted))
		{
			xNorm = MTH_M_xSqrt(MTH_M_xSub(xDistWanted, xNorm));
			if (MTH_M_bGreater(xNorm, xActualNorm))
			{
				xNorm = MTH_M_xSub(xNorm, xActualNorm);				
				if (MTH_M_bGreaterZero(xFactor))
					{MTH3D_M_vCopyVector(&stWpDestination, _p_stPreviousWpPosition);}/* Change he sens of moving*/
				else
				{if (cCameraIsOnWp) {return;}}/* No moving*/
			}
			else	
			{
				xNorm = MTH_M_xSub(xActualNorm, xNorm);
				if (MTH_M_bLessZero(xFactor))
					{MTH3D_M_vCopyVector(&stWpDestination, _p_stPreviousWpPosition);} /* Change he sens of moving*/
				else
				{if (cCameraIsOnWp) {return;}}/* No moving*/
			}
		}
		else
		{
			/*
			 * Go to the projected point
			 */
			if (MTH_M_bLessZero(xFactor))
			{MTH3D_M_vCopyVector(&stWpDestination, _p_stPreviousWpPosition);} /* Change he sens of moving*/
			else
			{if (cCameraIsOnWp) return;} /* No moving*/
			xNorm = xActualNorm;
		}
 
		MTH3D_M_vSubVector(&stRailAxis, &stWpDestination, &_p_stStruct->stCurrentCameraPos);
		if (MTH_M_bGreater(xNorm,MTH3D_M_xNormVector(&stRailAxis)))
		{
			MTH3D_M_vCopyVector(_p_stWantedPosition, &stWpDestination);
		}
		else
		{
			MTH3D_M_vNormalizeVector(&stRailAxis,&stRailAxis);
			MTH3D_M_vMulScalarVector(&stVector, xNorm, &stRailAxis);
			MTH3D_M_vAddVector(_p_stWantedPosition, &_p_stStruct->stCurrentCameraPos, &stVector);
		}
	}
}
 
/*
 **************************************************************************************************
 **************************************************************************************************
 **************************************************************************************************
 **************************************************************************************************
 */
 
 
/*
 *=================================================================================================
 *	Init camera stucture.
 *=================================================================================================
 */
void CAM_fn_vInitCameraStructure(HIE_tdxHandleToSuperObject _hSuperObjPerso, CAM_tdstUpdateCamera *_p_stStruct)
{
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
	MS_tdxHandleToDynam			hDynam;
	MTH3D_tdstVector			stTempVector;
	DNM_tdstDynamics			*p_stDynamics;
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
 
	memset(_p_stStruct, 0, sizeof(CAM_tdstUpdateCamera));
 
	/*
	 *	Init camera stucture.
	 */
	hDynam = M_GetMSHandle(_hSuperObjPerso, Dynam);
 
	_p_stStruct->p_stDynamics = fn_p_stDynamGetDynamics(hDynam);
	_p_stStruct->p_stReport = DNM_M_p_stDynamicsGetReport(_p_stStruct->p_stDynamics);
 
	_p_stStruct->hCineinfo = M_GetMSHandle(_hSuperObjPerso, Cineinfo);
    _p_stStruct->hCineinfoWork = M_GetCineinfo(_hSuperObjPerso, Work);
    _p_stStruct->hCineinfoCurrent = M_GetCineinfo(_hSuperObjPerso, Current);
    _p_stStruct->hCineinfoInit = M_GetCineinfo(_hSuperObjPerso, Init);
    _p_stStruct->hCineinfoVisibility = M_GetCineinfo(_hSuperObjPerso, Visibility);
 
	_p_stStruct->hSuperObjCamera = _hSuperObjPerso;
 
	/*
	 *	Current camera pos.
	 */
	POS_fn_vGetTranslationVector
	(
		HIE_fn_hGetSuperObjectGlobalMatrix(_hSuperObjPerso), 
		&_p_stStruct->stCurrentCameraPos
	);
 
	/*
	 *	Does targeted perso is moving ?
	 *	We update _p_stStruct->stTgtPersoMove only if perso is moving (cause we want to 
	 *	remember the last move vector of the perso).
	 */
	if(_p_stStruct->hCineinfoWork->hSuperObjectTargeted != NULL)
	{
		/* Absolute move */
		_p_stStruct->cTgtPersoIsMovingAbsolute = CAM_fn_bPersoIsMoving
			(
				_p_stStruct, 
				&_p_stStruct->stTgtPersoMoveAbsolute
			);
 
		/* Relative move */
		if(CAM_fn_hGetFather(_p_stStruct->hCineinfoWork->hSuperObjectTargeted) == NULL)
		{
			_p_stStruct->cTgtPersoIsMovingRelative = _p_stStruct->cTgtPersoIsMovingAbsolute;
			MTH3D_M_vCopyVector(&_p_stStruct->stTgtPersoMoveRelative, &_p_stStruct->stTgtPersoMoveAbsolute);
		}
		else
		{
			hDynam = M_GetMSHandle(_p_stStruct->hCineinfoWork->hSuperObjectTargeted, Dynam);
			p_stDynamics = fn_p_stDynamGetDynamics(hDynam);
			POS_fn_vGetTranslationVector(DNM_M_p_stDynamicsGetPrevPreviousMatrix(p_stDynamics), &stTempVector);
			POS_fn_vGetTranslationVector(DNM_M_p_stDynamicsGetPreviousMatrix(p_stDynamics), &_p_stStruct->stTgtPersoMoveRelative);
			MTH3D_M_vSubVector(&_p_stStruct->stTgtPersoMoveRelative, &stTempVector, &_p_stStruct->stTgtPersoMoveRelative);
			if(MTH_M_bGreater(MTH3D_M_xNormVector(&_p_stStruct->stTgtPersoMoveRelative), CAM_C_xMinLinearSpeedTgtPerso))
				_p_stStruct->cTgtPersoIsMovingRelative = 1;
			else
				_p_stStruct->cTgtPersoIsMovingRelative = 0;
		}
	}
}
 
 
/*
 **************************************************************************************************
 **************************************************************************************************
 **************************************************************************************************
 **************************************************************************************************
 */
 
 
/*
 *=================================================================================================
 *	Description:
 *		Send parameters to Parsing
 *		Fill the Macdpid structur
 *=================================================================================================
 */
void CAM_fn_vSendParametersToParsing(CAM_tdstUpdateCamera *_p_stStruct)
{
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
	tdstMACDPID				*p_stMACDPID;
	DNM_tdstDynamics		*p_stDynamics;
	MS_tdxHandleToDynam		h_Dynam;
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
 
	if((h_Dynam = M_GetMSHandle(_p_stStruct->hSuperObjCamera, Dynam)) == NULL ) 
	  return;
	if((p_stDynamics = fn_p_stDynamGetDynamics(h_Dynam)) == NULL)
  	  return;
    p_stMACDPID = DNM_M_p_stDynamicsGetExternalDatas(p_stDynamics);
 
	/*
	 * Cut angle factor.
	 */
	M_xMACDPIDGetCutAngleFactorPos(p_stMACDPID) = CAM_C_xCutAngleFactorPos;
	M_xMACDPIDGetCutAngleFactorTgt(p_stMACDPID) = CAM_C_xCutAngleFactorTgt;
 
	/* Angle Theta */
	M_xMACDPIDSetTheta(p_stMACDPID, _p_stStruct->hCineinfoWork->xAngleTheta);
 
	/* Target and move vector */
	MTH3D_M_vCopyVector(M_p_stMACDPIDGetTarget(p_stMACDPID), &_p_stStruct->stCptPos.stTarget);
	MTH3D_M_vCopyVector(M_p_stMACDPIDGetMovePos(p_stMACDPID), &_p_stStruct->stCptPos.stMovePos);
 
	/* Linear speed and speeding up */
	M_xMACDPIDGetLinearSpeed(p_stMACDPID) = _p_stStruct->stCptPos.xLinearSpeed;
	if(MTH_M_bEqual(_p_stStruct->hCineinfoWork->xLinearIncreaseSpeed, MTH_C_ZERO))
		_p_stStruct->hCineinfoWork->xLinearIncreaseSpeed = MTH_M_xFloatToReal(0.001f);
	M_xMACDPIDGetLinearIncreaseSpeed(p_stMACDPID) = _p_stStruct->hCineinfoWork->xLinearIncreaseSpeed;
	M_xMACDPIDGetLinearDecreaseSpeed(p_stMACDPID) = _p_stStruct->hCineinfoWork->xLinearDecreaseSpeed;
 
	/* Angular speed and speeding up */
	M_xMACDPIDGetAngularSpeed(p_stMACDPID) = _p_stStruct->stCptPos.xAngularSpeed;
	if(MTH_M_bEqual(_p_stStruct->hCineinfoWork->xAngularIncreaseSpeed, MTH_C_ZERO))
		_p_stStruct->hCineinfoWork->xLinearIncreaseSpeed = MTH_M_xFloatToReal(0.001f);
	M_xMACDPIDGetAngularIncreaseSpeed(p_stMACDPID) = _p_stStruct->hCineinfoWork->xAngularIncreaseSpeed;
	M_xMACDPIDGetAngularDecreaseSpeed(p_stMACDPID) = _p_stStruct->hCineinfoWork->xAngularDecreaseSpeed;
 
	/* Target speed and speeding up */
	M_xMACDPIDGetTargetSpeed(p_stMACDPID) = _p_stStruct->stCptPos.xTargetSpeed;
	if(MTH_M_bEqual(_p_stStruct->hCineinfoWork->xAngularIncreaseSpeed, MTH_C_ZERO))
		_p_stStruct->hCineinfoWork->xTargetIncreaseSpeed = MTH_M_xFloatToReal(0.001f);
	M_xMACDPIDGetTargetIncreaseSpeed(p_stMACDPID) = _p_stStruct->hCineinfoWork->xTargetIncreaseSpeed;
	M_xMACDPIDGetTargetDecreaseSpeed(p_stMACDPID) = _p_stStruct->hCineinfoWork->xTargetDecreaseSpeed;
 
	/* Reference point for camera position (only for angular parsing) */
	MTH3D_M_vCopyVector(M_p_stMACDPIDGetPosReferencePoint(p_stMACDPID), &_p_stStruct->stTargetedPersoPos);
 
	/* Reference axis Z to twist camera */
	MTH3D_M_vCopyVector(M_p_stMACDPIDGetRefAxisZ(p_stMACDPID), &_p_stStruct->stCptPos.stRefAxisZ);
 
	/*
	 *	DNM Flags.
	 *	Change DNM flags depending on context.
	 */
 
	/*---*/
	if(_p_stStruct->hCineinfo->ucVolIAFlags & C_VolIAFlags_InitJustCopiedInCurrent)
	{
		_p_stStruct->hCineinfoWork->uwDNMFlags |= DNM_CAM_C_NoLinearParsing;
		_p_stStruct->hCineinfoWork->uwDNMFlags |= DNM_CAM_C_NoAngularParsing;
		_p_stStruct->hCineinfoWork->uwDNMFlags |= DNM_CAM_C_NoTargetParsing;
	}
 
	/*---*/
	if(_p_stStruct->hCineinfoWork->hSuperObjectTargeted == NULL)
	{
		MTH3D_M_vNullVector(M_p_stMACDPIDGetPosReferencePoint(p_stMACDPID));
	}
 
	/*---*/
	if(_p_stStruct->hCineinfoWork->uwIAFlags & C_IAFlags_PositionIsAlreadyComputed)
	{
		_p_stStruct->hCineinfoWork->uwDNMFlags |= DNM_CAM_C_NoAngularParsing;
		MTH3D_M_vNullVector(M_p_stMACDPIDGetPosReferencePoint(p_stMACDPID));
	}
 
	/*---*/
	if(_p_stStruct->hCineinfoWork->uwDNMFlags & DNM_CAM_C_FixedOrientation)
		_p_stStruct->hCineinfoWork->uwDNMFlags |= DNM_CAM_C_NoTargetParsing;
 
	/*---*/
	if(_p_stStruct->hCineinfoWork->uwDNMFlags & DNM_CAM_C_NoLinearParsing)
	{
		_p_stStruct->hCineinfoWork->uwDNMFlags |= DNM_CAM_C_NoLinearInertia;
		M_xMACDPIDGetCutAngleFactorPos(p_stMACDPID) = MTH_C_ONE;
	}
 
	/*---*/
	if(_p_stStruct->hCineinfoWork->uwDNMFlags & DNM_CAM_C_NoAngularParsing)
	{
		_p_stStruct->hCineinfoWork->uwDNMFlags |= DNM_CAM_C_NoAngularInertia;
		M_xMACDPIDGetCutAngleFactorPos(p_stMACDPID) = MTH_C_ONE;
	}
 
	/*---*/
	if(_p_stStruct->hCineinfoWork->uwDNMFlags & DNM_CAM_C_NoTargetParsing)
	{
		_p_stStruct->hCineinfoWork->uwDNMFlags |= DNM_CAM_C_NoTargetInertia;
		M_xMACDPIDGetCutAngleFactorTgt(p_stMACDPID) = MTH_C_ONE;
	}
 
	/*---*/
	M_uwMACDPIDGetFlags(p_stMACDPID) = _p_stStruct->hCineinfoWork->uwDNMFlags;
 
	/* If no collision, force camera sector to be the same as targeted perso */
	if((_p_stStruct->hCineinfoWork->hSuperObjectTargeted) && (_p_stStruct->hCineinfoWork->uwDNMFlags & DNM_CAM_C_NoObstacle))
	{
		/* the camera is forced in the sector of its target */
		fn_vSectInfoSetCurrentSector(M_GetMSHandle(_p_stStruct->hSuperObjCamera,SectInfo), fn_h_SectInfoGetCurrentSector(M_GetMSHandle(_p_stStruct->hCineinfoWork->hSuperObjectTargeted,SectInfo)));
		//fn_vSectInfoInitForSingleCharacter(_p_stStruct->hSuperObjCamera, &_p_stStruct->stTargetedPersoRealPos);
	}
 
	if(!(_p_stStruct->cTgtPersoIsMovingAbsolute))
	{
		M_xMACDPIDGetCutAngleFactorPos(p_stMACDPID) = M_xMACDPIDGetCutAngleFactorTgt(p_stMACDPID) = MTH_C_ONE;
	}
}
 
 
extern char	cRefAxisIsAlreadyComputed;
extern char	cNoDynChangeTheta;
extern char	cCanTestStatic;
void CAM_fn_vForceBestPosition(HIE_tdxHandleToSuperObject _hCamera)
{
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/*	HIE_tdxHandleToSuperObject	hCamera;*/
    MS_tdxHandleToCineinfo		hCineinfo;
 	CAM_tdstUpdateCamera		stStruct;
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
 
	hCineinfo = M_GetMSHandle(_hCamera, Cineinfo);
	/*
	 *	To have the actual good camera parameters.
	 */
	CAM_fn_vSetCineinfoWorkFromCurrent(hCineinfo);
	CAM_fn_vInitCameraStructure(_hCamera, &stStruct);
 
	cRefAxisIsAlreadyComputed = stStruct.hCineinfoWork->uwIAFlags & C_IAFlags_RefAxisIsAlreadyComputed ? 1 : 0;
	cNoDynChangeTheta = stStruct.hCineinfoWork->uwIAFlags & C_IAFlags_NoDynChangeTheta ? 1 : 0;
	cCanTestStatic = 1;
 
	/*
	 *	Compute target and real wanted camera pos (this is necessary
	 *	for failure when we want a more correct position.
	 */
	CAM_fn_vComputeReferencePoint(&stStruct);
	CAM_fn_vComputeTarget(&stStruct);
	CAM_fn_vComputeRealWantedPos(&stStruct);
	CAM_fn_vComputeMovePosWithDynTheta(&stStruct);
 
	/*
	 *	If no perso, can't do it.
	 */
	if(stStruct.hCineinfoCurrent->hSuperObjectTargeted == NULL)
		return;
 
	/*
	 *	Force visibility failure.
	 */
	CAM_fn_vForceFailureVisibility(&stStruct);
	CAM_fn_vComputeFailureVisibility(&stStruct);
/*	stStruct.hCineinfoWork->uwDNMFlags |= (DNM_CAM_C_NoLinearParsing|DNM_CAM_C_NoAngularParsing);*/
}
