reman3/Rayman_X/cpa/tempgrp/AI/AIGame/CAM_Vis.c

1838 lines
59 KiB
C

/*
**************************************************************************************************
* For camera visibility tests.
**************************************************************************************************
*/
#define D_CineInfo_StructureDefine
#include "AIUseCPA.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 <ASSERT.h>
/*XB*/
#if defined(U64)
void qsort(void *,size_t,size_t,int (*)(const void *,const void *));
#endif
/*End XB*/
/*
**************************************************************************************************
**************************************************************************************************
VISIBILITY : FILL ARRAY OF SIN AND COS
**************************************************************************************************
**************************************************************************************************
*/
/* Array that contains angles to test in both normal and failure mode */
unsigned short guw_NbVectorArrayCpt = 0;
typedef struct
{
MTH3D_tdstVector stDir;
MTH_tdxReal xPound;
} tdst_PosPound;
tdst_PosPound gast_VectorArrayCpt[256];
/* To compute pound : Contains the ideal parameters */
struct tdstInternalStructurCineinfo_ gst_Ideal;
/* To indicate that the ray to test visibility can test static hierarchy */
char cCanTestStatic = 1;
/*
**************************************************************************************************
**************************************************************************************************
VISIBILITY : BASIC TEST OF VISIBILITY
**************************************************************************************************
**************************************************************************************************
*/
/*
*=================================================================================================
* Is sector is in list ?
*=================================================================================================
*/
char CAM_fn_cIsSectorInCollisionList(HIE_tdxHandleToSuperObject _hFirstSector, HIE_tdxHandleToSuperObject _hTestSector)
{
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
int i;
SECT_tdxHandleOfElementLstCollisionInteraction hList;
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
SECT_M_ForEachCollisionNodeInCollisionInteractionList(_hFirstSector, hList, i)
{
if(SECT_GetSectorInCollisionList(hList) == _hTestSector)
return 1;
}
return 0;
}
/*
*=================================================================================================
* Truncate a vector element to avoid computing errors to change the validity of a segment.
*=================================================================================================
*/
#define M_Trunc(Vector, Type)\
{\
int _iTemp_;\
_iTemp_ = (int) MTH_M_xMul(MTH3D_M_xGet##Type##ofVector(&Vector), 1000);\
MTH3D_M_vSet##Type##ofVector(&Vector, MTH_M_xDiv((MTH_tdxReal) _iTemp_, 1000));\
}
/*
*=================================================================================================
* Visibility test with a segment in dynamic world.
* We only test actors which priority is fewer than camera one.
*=================================================================================================
*/
char CAM_fn_cSendSegmentInDynamicWorld
(
MTH3D_tdstVector *_p_stSource,
MTH3D_tdstVector *_p_stDest,
HIE_tdxHandleToSuperObject _hSector,
HIE_tdxHandleToSuperObject _hCamera
)
{
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
long j;
SECT_tdxHandleOfElementLstCharacter hCharacterList;
HIE_tdxHandleToSuperObject hTreatCharacter;
unsigned char ucCameraPriority;
MTH3D_tdstVector stTempVector;
MS_tdxHandleToCollSet hCollset;
MS_tdxHandleToStandardGame hStdGame;
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/* Get camera priority to test character one with */
ucCameraPriority = CS_fn_ucGetCharacterPriority(M_GetMSHandle(_hCamera, CollSet));
MTH3D_M_vSubVector(&stTempVector, _p_stDest, _p_stSource);
SECT_M_ForEachCharListInSector(_hSector, hCharacterList, j)
{
hTreatCharacter = SECT_GetCharacterInList(hCharacterList);
hCollset = M_GetMSHandle(hTreatCharacter, CollSet);
hStdGame = M_GetMSHandle(hTreatCharacter, StandardGame);
if ( (hCollset && (CS_fn_ucGetCharacterPriority(hCollset) == ucCameraPriority)) ||
(hStdGame && (fn_ulStandardGameGetCustomBits(hStdGame) & GAM_C_CustBitCameraHit)) )
/*if (!hCollset || (CS_fn_ucGetCharacterPriority(hCollset) == ucCameraPriority))*/
{
/*if (CS_fn_ucGetCharacterPriority(hCollset) == ucCameraPriority)*/
{
/* Perso must have an anim, so must have some children */
if(HIE_fn_lGetNumberOfChildren(hTreatCharacter))
{
if
(
HIE_bDetectIntersectSegmentWithSuperObject
(
_p_stSource,
/* _p_stDest,*/
&stTempVector,
hTreatCharacter
)
)
return 1;
}
}
}
}
return 0;
}
/*
*=================================================================================================
* Visibility test with a segment in static world and dynamic world.
* We test :
* - In current actor sector
* - In current camera sector
* - In the sectors of collision list of actor
* - In the sectors of collision list of camera
*=================================================================================================
*/
char CAM_fn_cSendSegment
(
CAM_tdstUpdateCamera *_p_stStruct,
MTH3D_tdstVector *_p_stSource,
MTH3D_tdstVector *_p_stDest
)
{
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
MTH3D_tdstVector stTempVector;
int i;
MS_tdxHandleToSectInfo hPersoCineinfo;
MS_tdxHandleToSectInfo hCamCineinfo;
SECT_tdxHandleOfElementLstCollisionInteraction hList;
MTH3D_tdstVector stSource, stDest;
HIE_tdxHandleToSuperObject hPersoTargeted;
HIE_tdxHandleToSuperObject hCamera;
HIE_tdxHandleToSuperObject hCurrentSectorPerso;
HIE_tdxHandleToSuperObject hCurrentSectorCamera;
HIE_tdxHandleToSuperObject hSectorInCollision;
char cVisibilityWithDynWorld;
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
if(MTH3D_M_bEqualVector(_p_stSource, _p_stDest))
return 0;
/*
* Determin if we must test in dynamic world.
*/
cVisibilityWithDynWorld = _p_stStruct->hCineinfoWork->uwIAFlags & C_IAFlags_NoVisibilityWithDynHie ? 0 : 1;
/*
* We truncate source and destination vector to avoid computing errors.
* Positions that are closer from each other are then considered to be equal.
*/
/*MTH3D_M_vCopyVector(&stSource, _p_stSource);
MTH3D_M_vCopyVector(&stDest, _p_stDest);*/
stSource = *_p_stSource;
stDest = *_p_stDest;
M_Trunc(stSource, X);
M_Trunc(stSource, Y);
M_Trunc(stSource, Z);
M_Trunc(stDest, X);
M_Trunc(stDest, Y);
M_Trunc(stDest, Z);
/*
* Retrieve sector of camera and targeted perso.
*/
hCamera = _p_stStruct->hSuperObjCamera;
hCamCineinfo = M_GetMSHandle(hCamera, SectInfo);
hCurrentSectorPerso = hCurrentSectorCamera = fn_h_SectInfoGetCurrentSector(hCamCineinfo);
hPersoTargeted = _p_stStruct->hCineinfoWork->hSuperObjectTargeted;
if(hPersoTargeted)
{
hPersoCineinfo = M_GetMSHandle(hPersoTargeted, SectInfo);
hCurrentSectorPerso = fn_h_SectInfoGetCurrentSector(hPersoCineinfo);
}
/*
* Compute segment.
*/
MTH3D_M_vSubVector(&stTempVector, &stDest, &stSource);
/*
* Current actor sector
*----------------------
*/
/* STATIC */
if
(
cCanTestStatic
&& HIE_bDetectIntersectSegmentWithSuperObject
(
&stSource,
/* &stDest,*/
&stTempVector,
hCurrentSectorPerso
)
)
return 1;
/* DYNAMIC */
if
(
(cVisibilityWithDynWorld)
&& CAM_fn_cSendSegmentInDynamicWorld
(
&stSource,
&stDest,
hCurrentSectorPerso,
hCamera
)
)
return 1;
/*
* Current camera sector (if it's not the same than actor one)
*-------------------------------------------------------------
*/
if(hCurrentSectorPerso != hCurrentSectorCamera)
{
/* STATIC */
if
(
cCanTestStatic
&& HIE_bDetectIntersectSegmentWithSuperObject
(
&stSource,
/* &stDest,*/
&stTempVector,
hCurrentSectorCamera
)
)
return 1;
/* DYNAMIC */
if
(
(cVisibilityWithDynWorld)
&& CAM_fn_cSendSegmentInDynamicWorld
(
&stSource,
&stDest,
hCurrentSectorCamera,
hCamera
)
)
return 1;
}
/*
* Collision sectors of perso
*----------------------------
*/
SECT_M_ForEachCollisionNodeInCollisionInteractionList
(
hCurrentSectorPerso,
hList,
i
)
{
hSectorInCollision = SECT_GetSectorInCollisionList(hList);
/* Sector is not camera one (already treated) */
if(hSectorInCollision != hCurrentSectorCamera)
{
/* STATIC */
if
(
cCanTestStatic
&& HIE_bDetectIntersectSegmentWithSuperObject
(
&stSource,
/* &stDest,*/
&stTempVector,
hSectorInCollision
)
)
return 1;
/* DYNAMIC */
if
(
(cVisibilityWithDynWorld)
&& CAM_fn_cSendSegmentInDynamicWorld
(
&stSource,
&stDest,
hSectorInCollision,
hCamera
)
)
return 1;
}
}
/*
* Collision sectors of camera
*-----------------------------
*/
if(hCurrentSectorPerso != hCurrentSectorCamera)
{
SECT_M_ForEachCollisionNodeInCollisionInteractionList
(
hCurrentSectorCamera,
hList,
i
)
{
hSectorInCollision = SECT_GetSectorInCollisionList(hList);
if
(
/* Sector is not in perso list */
!CAM_fn_cIsSectorInCollisionList
(
hCurrentSectorPerso,
hSectorInCollision
)
/* Sector is not perso one */
&& (hSectorInCollision != hCurrentSectorPerso)
)
{
/* STATIC */
if
(
cCanTestStatic
&& HIE_bDetectIntersectSegmentWithSuperObject
(
&stSource,
/* &stDest,*/
&stTempVector,
hSectorInCollision
)
)
return 1;
/* DYNAMIC */
if
(
(cVisibilityWithDynWorld)
&& CAM_fn_cSendSegmentInDynamicWorld
(
&stSource,
&stDest,
hSectorInCollision,
hCamera
)
)
return 1;
}
}
}
return 0;
}
/*
*=================================================================================================
* Visibility with multi segment.
* This function send "_lNbRay" segment and failed with the first one.
*=================================================================================================
*/
char CAM_fn_cSendMultiSegment
(
CAM_tdstUpdateCamera *_p_stStruct,
MTH3D_tdstVector *_p_stSourcePos,
MTH3D_tdstVector *_p_stTargetPos,
MTH_tdxReal _xRadiusCamera,
MTH_tdxReal _xRadiusTarget,
long _lNbRay
)
{
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
MTH3D_tdstVector stDirection;
MTH3D_tdstVector stPositionSource, stPositionSource1;
MTH3D_tdstVector stPositionTarget, stPositionTarget1;
MTH_tdstRotation stRotation;
MTH3D_tdstVector stAxisZ, stVector;
long i;
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/*
* Center if just one ray.
*/
if(_lNbRay == 1)
{
return CAM_fn_cSendSegment
(
_p_stStruct,
_p_stSourcePos,
_p_stTargetPos
);
}
/*
* Compute the first vector (ray of a sphere from center of source to _xRadiusCamera).
*/
MTH3D_M_vSubVector(&stDirection, _p_stTargetPos, _p_stSourcePos);
MTH3D_M_vNormalizeVector(&stDirection, &stDirection);
MTH3D_M_vSetBaseKVector(&stAxisZ);
MTH3D_M_vCrossProductVectorWithoutBuffer(&stVector, &stDirection, &stAxisZ);
if(MTH3D_M_bIsNullVector(&stVector))
{
MTH3D_M_vSetBaseIVector(&stAxisZ);
MTH3D_M_vCrossProductVectorWithoutBuffer(&stVector, &stDirection, &stAxisZ);
}
MTH3D_M_vNormalizeVector(&stVector, &stVector);
MTH3D_M_vMulScalarVector(&stVector, _xRadiusCamera, &stVector);
/* Rotation axis is vector source to target */
MTH_M_RotationSetAxis(&stRotation, &stDirection);
/* Normal rotation angle is 2Pi / Nb ray */
MTH_M_xRotationSetAngle(&stRotation, MTH_M_xDiv(MTH_C_2Pi, _lNbRay));
for(i = 0; i < _lNbRay; i++)
{
/* Compute source point position */
/*MTH3D_M_vCopyVector(&stPositionSource, &stVector);
MTH3D_M_vMulScalarVector(&stPositionSource, _xRadiusCamera, &stPositionSource);*/
MTH3D_M_vMulScalarVector(&stPositionSource, _xRadiusCamera, &stVector); /* remplace les 2 lignes du dessus*/
MTH3D_M_vAddVector(&stPositionSource1, &stPositionSource, _p_stSourcePos);
/* Compute target point position */
/*MTH3D_M_vCopyVector(&stPositionTarget, &stVector);
MTH3D_M_vMulScalarVector(&stPositionTarget, _xRadiusTarget, &stPositionTarget);*/
MTH3D_M_vMulScalarVector(&stPositionTarget, _xRadiusTarget, &stVector); /* remplace les 2 lignes du dessus*/
MTH3D_M_vAddVector(&stPositionTarget1, &stPositionTarget, _p_stTargetPos);
/* Throw a ray */
if
(
CAM_fn_cSendSegment
(
_p_stStruct,
&stPositionSource1,
&stPositionTarget1
)
)
return 1;
/* Rotate to find the new position */
MTH_p_stRotationMulVector(&stRotation, &stVector, &stVector);
}
return 0;
}
/*
*=================================================================================================
* Compute impact point of camera from a source to a dest point.
* There must be an impact !!! (don't call this function to test a collision, but when a collision
* occured to retreive impact point).
*=================================================================================================
*/
#ifndef _FIRE_DEADCODE_U64_ /* Added by RUC */
char CAM_fn_cComputeImpactPointWithCameraSphere
(
CAM_tdstUpdateCamera *_p_stStruct,
MTH3D_tdstVector *_p_stSource,
MTH3D_tdstVector *_p_stTarget,
MTH3D_tdstVector *_p_stImpact
)
{
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
POS_tdstCompletePosition stMatrix1, stMatrix2;
/*HIE_tdxHandleToSuperObject hTmpSector;*/
char cRes1;
DNM_tdstMecObstacle stObstacle;
MTH_tdxReal xNorm;
/*MS_tdxHandleToSectInfo hSectInfo = M_GetMSHandle(_p_stStruct->hSuperObjCamera, SectInfo);*/
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
if(_p_stImpact == NULL)
return 1;
/*
* Test with camera sphere
*-------------------------
*/
POS_fn_vSetIdentityMatrix(&stMatrix1);
POS_fn_vSetIdentityMatrix(&stMatrix2);
POS_fn_vSetTranslationVector(&stMatrix1, _p_stSource);
POS_fn_vSetTranslationVector(&stMatrix2, _p_stTarget);
/* Save sector */ /*INUTILE CAR LE TEST DE COLLISION NE MET PLUS A JOUR LES INFOS DE SECTEUR*/
/*hTmpSector = fn_h_SectInfoGetCurrentSector(hSectInfo);*/
cRes1 = (char) CAM_lHaveITakeSThgIntoTheMug
(
&stObstacle,
_p_stStruct->hSuperObjCamera,
&stMatrix1,
&stMatrix2
);
/* Restore sector */
/*fn_vSectInfoSetCurrentSector(hSectInfo, hTmpSector);*/
if(!cRes1)
{
MTH3D_M_vNullVector(_p_stImpact);
return 0;
}
/*
* Compute impact point
*----------------------
*/
MTH3D_M_vSubVector(_p_stImpact, _p_stTarget, _p_stSource);
MTH3D_M_vMulScalarVector(_p_stImpact, DNM_M_xObstacleGetRate(&stObstacle), _p_stImpact);
xNorm = MTH_M_xSub(MTH3D_M_xNormVector(_p_stImpact), MTH_M_xFloatToReal(0.02f));
if (MTH_M_bLessZero(xNorm))
{
MTH3D_M_vCopyVector(_p_stImpact,_p_stSource);
}
else
{
MTH3D_M_vNormalizeVector(_p_stImpact, _p_stImpact);
MTH3D_M_vMulScalarVector(_p_stImpact, xNorm, _p_stImpact);
MTH3D_M_vAddVector(_p_stImpact, _p_stImpact, _p_stSource);
}
return 1;
}
#endif /* _FIRE_DEADCODE_U64_ */ /* Added by RUC */
/*
**************************************************************************************************
**************************************************************************************************
VISIBILITY : MORE HIGH LEVEL TEST OF VISIBILITY
**************************************************************************************************
**************************************************************************************************
*/
/*
*=================================================================================================
* Can't camera go to a given point ?
*=================================================================================================
*/
char CAM_fn_cCameraCantGo
(
CAM_tdstUpdateCamera *_p_stStruct,
MTH3D_tdstVector *_p_stSourcePos,
MTH3D_tdstVector *_p_stTargetPos
)
{
return CAM_fn_cSendMultiSegment
(
_p_stStruct,
_p_stSourcePos,
_p_stTargetPos,
CAM_C_xRayCameraSphereToGo1,
CAM_C_xRayCameraSphereToGo2,
CAM_C_xNumRayCameraCanGo
);
}
/*
*=================================================================================================
* Can't camera go to a given point ? For failure, we must be sure that this will be correct.
*=================================================================================================
*/
char CAM_fn_cCameraCantGoFailure
(
CAM_tdstUpdateCamera *_p_stStruct,
MTH3D_tdstVector *_p_stSourcePos,
MTH3D_tdstVector *_p_stTargetPos
)
{
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
MTH3D_tdstVector stTempVector;
MTH_tdxReal xNorm;
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/* First the destination point is farest with the ZDM ray of camera */
MTH3D_M_vSubVector(&stTempVector, _p_stTargetPos, _p_stSourcePos);
xNorm = MTH3D_M_xNormVector(&stTempVector);
xNorm = MTH_M_xAdd(xNorm, MTH_M_xFloatToReal(0.35f));
MTH3D_M_vNormalizeVector(&stTempVector, &stTempVector);
MTH3D_M_vMulScalarVector(&stTempVector, xNorm, &stTempVector);
MTH3D_M_vAddVector(&stTempVector, &stTempVector, _p_stSourcePos);
/* First the few ray */
return CAM_fn_cSendMultiSegment
(
_p_stStruct,
_p_stSourcePos,
&stTempVector,
CAM_C_xRayCameraSphereToGo1,
CAM_C_xRayCameraSphereToGo2,
CAM_C_xNumRayCameraCanGo
);
}
/*
*=================================================================================================
* Can't camera see a given point ?
*=================================================================================================
*/
char CAM_fn_cCameraCantSee
(
CAM_tdstUpdateCamera *_p_stStruct,
MTH3D_tdstVector *_p_stSourcePos,
MTH3D_tdstVector *_p_stTargetPos
)
{
return CAM_fn_cSendMultiSegment
(
_p_stStruct,
_p_stSourcePos,
_p_stTargetPos,
CAM_C_xRayCameraSphereToSee1,
CAM_C_xRayCameraSphereToSee2,
CAM_C_xNumRayCameraCanSee
);
}
/*
*=================================================================================================
* Is wanted pos not good ?
* This function determis if a given position is correct.
*=================================================================================================
*/
char CAM_fn_cIsWantedPosIncorrect
(
CAM_tdstUpdateCamera *_p_stStruct,
MTH3D_tdstVector *_p_stWantedPos,
char _cMode
)
{
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
MTH3D_tdstVector stTempVector;
char cCant;
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/*
* Wanted too short from target : Exit
*/
MTH3D_M_vSubVector(&stTempVector, _p_stWantedPos, &_p_stStruct->stTargetedPersoRealPos);
if(MTH_M_bLess(MTH3D_M_xNormVector(&stTempVector), CAM_C_xMinDistPersoToComputePos))
return 1;
/*
* Test visibility : Target to real wanted
*------------------------------------------
*/
if(_cMode & C_mode_MUSTSEE)
{
/*
* In failure mode, we send a ray cause we want to be sure that position
* is not already in collision.
* Else we send a normal ray.
*/
cCant = ((_cMode & C_mode_FAILURE) ? CAM_fn_cCameraCantGoFailure : CAM_fn_cCameraCantSee) (_p_stStruct, &_p_stStruct->stTargetedPersoRealPos, _p_stWantedPos);
/*EQUIVALENT A CECI, MAIS GENERE NORMALEMENT MOINS DE CODE
if(_cMode & C_mode_FAILURE)
cCant = CAM_fn_cCameraCantGoFailure(_p_stStruct, &_p_stStruct->stTargetedPersoRealPos, _p_stWantedPos);
else
cCant = CAM_fn_cCameraCantSee(_p_stStruct, &_p_stStruct->stTargetedPersoRealPos, _p_stWantedPos);*/
if(cCant)
return 1;
}
/*
* Test visibility : Current to real wanted position
*----------------------------------------------------
*/
if(_cMode & C_mode_MUSTGO)
{
cCant = CAM_fn_cCameraCantGo(_p_stStruct, &_p_stStruct->stCurrentCameraPos, _p_stWantedPos);
if(cCant)
return 1;
}
return 0;
}
/*
**************************************************************************************************
**************************************************************************************************
COMPUTE A NEW GOOD IDEAL POS
**************************************************************************************************
**************************************************************************************************
*/
/*
*=================================================================================================
* Compute a good position with a given direction.
*=================================================================================================
*/
char CAM_fn_cFindCorrectPosWithDir
(
CAM_tdstUpdateCamera *_p_stStruct,
MTH3D_tdstVector *_p_stDir,
MTH3D_tdstVector *_p_stCompute,
char _cMode
)
{
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
MTH3D_tdstVector stTestedPos;
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/*
* Compute new pos with direction
*/
MTH3D_M_vAddVector(&stTestedPos, _p_stDir, &_p_stStruct->stTargetedPersoPos);
/*
* Test position.
*/
if(CAM_fn_cIsWantedPosIncorrect(_p_stStruct, &stTestedPos, _cMode))
return 0;
/*
* Position correct : Success.
*/
else
{
MTH3D_M_vCopyVector(_p_stCompute, &stTestedPos);
return 1;
}
}
/*
*=================================================================================================
* Compute the pound of a position. Less it is, better it is.
*=================================================================================================
*/
MTH_tdxReal CAM_fnx_ComputePosPound(CAM_tdstUpdateCamera *_pst_Struct, MTH3D_tdstVector *_pst_Dir)
{
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
MTH_tdxReal x_Pound, x_Angle, x_Angle1;
MTH_tdxReal x_P1, x_P2, x_P3;
MTH3D_tdstVector st_TempVector;
struct tdstInternalStructurCineinfo_ *pst_Memo;
struct tdstInternalStructurCineinfo_ st_Temp;
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/*
* Compute requested position.
*/
MTH3D_M_vAddVector(&st_TempVector, &_pst_Struct->stTargetedPersoPos, _pst_Dir);
/*
* Compute parameters of camera for that position. We compute the parameters in a private
* internal structure (cause we don't want to save them).
*/
pst_Memo = _pst_Struct->hCineinfoWork;
st_Temp.hSuperObjectTargeted = _pst_Struct->hCineinfoWork->hSuperObjectTargeted;
st_Temp.hSecondSuperObjectTargeted = _pst_Struct->hCineinfoWork->hSecondSuperObjectTargeted;
st_Temp.cChannel = _pst_Struct->hCineinfoWork->cChannel;
_pst_Struct->hCineinfoWork = &st_Temp;
CAM_fn_vComputeCineinfoWorkForAPosition(_pst_Struct, &st_TempVector);
_pst_Struct->hCineinfoWork = pst_Memo;
/*
* Compute pound of that position depending on ideal parameters.
*/
/* Alpha */
x_Angle = MTH_M_bGreater(gst_Ideal.xAngleAlpha, MTH_C_Pi) ? MTH_M_xSub(MTH_C_2Pi, gst_Ideal.xAngleAlpha) : gst_Ideal.xAngleAlpha;
x_Angle1 = MTH_M_bGreater(st_Temp.xAngleAlpha, MTH_C_Pi) ? MTH_M_xSub(MTH_C_2Pi, st_Temp.xAngleAlpha) : st_Temp.xAngleAlpha;
x_P1 = MTH_M_xAbs(MTH_M_xSub(x_Angle, x_Angle1));
x_P1 = MTH_M_xLongToReal(MTH_M_xRealToLongRound(MTH_M_xMul(x_P1, MTH_M_xFloatToReal(100))));
x_P1 = MTH_M_xMul(x_P1, MTH_M_xFloatToReal(0.01f));
/* Theta */
x_Angle = MTH_M_bGreater(gst_Ideal.xAngleTheta, MTH_C_Pi) ? MTH_M_xSub(MTH_C_2Pi, gst_Ideal.xAngleTheta) : gst_Ideal.xAngleTheta;
x_Angle1 = MTH_M_bGreater(st_Temp.xAngleTheta, MTH_C_Pi) ? MTH_M_xSub(st_Temp.xAngleTheta, MTH_C_2Pi) : st_Temp.xAngleTheta;
x_P2 = MTH_M_xAbs(MTH_M_xSub(x_Angle, x_Angle1));
x_P2 = MTH_M_xLongToReal(MTH_M_xRealToLongRound(MTH_M_xMul(x_P2, MTH_M_xFloatToReal(100))));
// x_P2 = MTH_M_xMul(x_P2, MTH_M_xFloatToReal(0.01f));
x_P2 = MTH_M_xMul(x_P2, MTH_M_xFloatToReal(0.10f));
/* Distance to target */
x_P3 = MTH_M_xAbs(MTH_M_xSub(gst_Ideal.xDistMin, st_Temp.xDistMin));
x_P3 = MTH_M_xLongToReal(MTH_M_xRealToLongRound(MTH_M_xMul(x_P3, MTH_M_xFloatToReal(100))));
x_P3 = MTH_M_xMul(x_P3, MTH_M_xFloatToReal(0.01f));
/*
* Compute final pound.
*/
x_Pound = MTH_M_xAdd(x_P1, x_P2);
x_Pound = MTH_M_xAdd(x_Pound, MTH_M_xMul(x_P3, MTH_M_xFloatToReal(0.1f)));
return x_Pound;
}
/*
*=================================================================================================
* Determin if a vector need to be eliminate.
*=================================================================================================
*/
char CAM_fnc_IsDirectionCorrect
(
CAM_tdstUpdateCamera *_p_stStruct,
MTH3D_tdstVector *_pst_Dir,
MTH_tdxReal _x_Pound,
MTH_tdxReal _x_PoundRef,
char _c_Mode
)
{
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
MTH3D_tdstVector stTempVector;
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/* Compute real position */
MTH3D_M_vAddVector(&stTempVector, _pst_Dir, &_p_stStruct->stTargetedPersoRealPos);
/*
* If we want a "more correct" position, assure that this new
* position is better than current one.
*------------------------------------------------------------
*/
if(_c_Mode & C_mode_MORE_CORRECT)
{
/* More bad than current pos */
if(MTH_M_bGreaterEqual(_x_Pound, _x_PoundRef))
return 0;
/* Too close from current pos */
_x_PoundRef = MTH_M_xSub(_x_PoundRef, _x_Pound);
if(MTH_M_bLess(_x_PoundRef, MTH_M_xFloatToReal(0.05f)))
return 0;
/* Position must reset last failed wanted */
if(!CAM_fn_cCanResetConstraintMoveVisFailure(_p_stStruct, &stTempVector))
return 0;
}
/*
* Norm of vector too small (to near from perso)
*-----------------------------------------------
*/
if(MTH_M_bLess(MTH3D_M_xNormVector(_pst_Dir), CAM_C_xMinDistPersoToComputePos))
return 0;
/*
* Vectors too near from wanted camera position
*-----------------------------------------------
*/
if
(
(!(_c_Mode & C_mode_FAILURE))
&& CAM_fn_bEqualVectorWithEpsilon
(
&stTempVector,
&_p_stStruct->stWantedCameraPos,
CAM_C_xEpsilonForEqualVectors
)
)
return 0;
/*
* Vectors too near from current camera position
*-----------------------------------------------
*/
if
(
((!(_c_Mode & C_mode_FAILURE)) || (_c_Mode & C_mode_MORE_CORRECT))
&& CAM_fn_bEqualVectorWithEpsilon
(
&stTempVector,
&_p_stStruct->stCurrentCameraPos,
CAM_C_xEpsilonForEqualVectors
)
)
return 0;
return 1;
}
/*
*=================================================================================================
* Compare two positions.
* To sort vectors depending on their pounds (less to greater).
*=================================================================================================
*/
int CAM_fni_ComparePositions(const void *_pv_Elem1, const void *_pv_Elem2)
{
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
MTH_tdxReal xPound1, xPound2;
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
xPound1 = ((tdst_PosPound *) _pv_Elem1)->xPound;
xPound2 = ((tdst_PosPound *) _pv_Elem2)->xPound;
return (MTH_M_bGreater(xPound2, xPound1)) ? -1 : (MTH_M_bEqual(xPound2, xPound1)) ? 0 : 1;
}
/*
*=================================================================================================
* Fill array gast_VectorArrayCpt to set angles to test.
*=================================================================================================
*/
void CAM_fn_vFillVectorArray(CAM_tdstUpdateCamera *_p_stStruct, char _cMode)
{
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
MTH3D_tdstVector stAxis, stTempVector, *p_stDir;
MTH_tdxReal xAngle, xBaseAngle, xNormIdeal, xSaveTheta;
unsigned long ulCounter, ulMax, ulAngle;
struct tdstInternalStructurCineinfo_ stTemp;
CAM_tdstUpdateCamera stStruct;
enum e_ucCameraStates_ eState;
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/*
* Init structures for compute.
*/
CAM_fn_vInitCameraStructure(_p_stStruct->hSuperObjCamera, &stStruct);
stStruct.hCineinfoWork = &stTemp;
memcpy(&stTemp, &gst_Ideal, sizeof(struct tdstInternalStructurCineinfo_));
CAM_fn_vComputeReferencePoint(&stStruct);
/*
* Get ideal norm.
*/
MTH3D_M_vSubVector(&stTempVector, &_p_stStruct->stRealWantedCameraPos, &_p_stStruct->stTargetedPersoPos);
xNormIdeal = MTH3D_M_xNormVector(&stTempVector);
/*
* Get axis of face perso is walking on.
*/
if(!CAM_fn_bPersoOnFace(_p_stStruct->hCineinfoWork->hSuperObjectTargeted, &stAxis))
{
MTH3D_M_vSetVectorElements(&stAxis, MTH_C_ZERO, MTH_C_ZERO, MTH_C_ONE);
}
/*
* Base rotation angle depending on failure mode or not.
*/
xBaseAngle = (_cMode & C_mode_FAILURE) ? CAM_C_xBaseAngleComputePosFailure : CAM_C_xBaseAngleComputePosNormal;
/* EQUIVALENT A:
if(_cMode & C_mode_FAILURE)
xBaseAngle = CAM_C_xBaseAngleComputePosFailure;
else
xBaseAngle = CAM_C_xBaseAngleComputePosNormal;*/
/*
* Fill array with all vectors computed with angles.
*--------------------------------------------------
*/
ulCounter = 0;
ulMax = MTH_M_xDiv(MTH_C_2Pi, xBaseAngle);
xAngle = stTemp.xAngleAlpha;
/* !!! To force ComputeMovePos to take walues from work and not from current ! */
eState = stStruct.hCineinfo->eState;
stStruct.hCineinfo->eState = CAM_e_State_GoToOptimal;
xSaveTheta = stTemp.xAngleTheta;
for ( ulAngle = 0; ulAngle < ulMax; ulAngle ++ )
{
/* Compute wanted position with a given alpha */
stTemp.xAngleAlpha = xAngle;
stTemp.xAngleAlpha = CAM_fn_xSetAngleInInterval02Pi(stTemp.xAngleAlpha);
stTemp.xAngleTheta = xSaveTheta;
stStruct.hCineinfoWork->uwIAFlags |= C_IAFlags_NoShiftUntilPosReached;
CAM_fn_vComputeMovePosWithDynTheta(&stStruct);
/* Compute direction with good dist */
p_stDir = &gast_VectorArrayCpt[ulCounter].stDir;
MTH3D_M_vSubVector(p_stDir, &stStruct.stWantedCameraPos, &stStruct.stTargetedPersoPos);
gast_VectorArrayCpt[ulCounter].xPound = CAM_fnx_ComputePosPound(_p_stStruct, p_stDir);
ulCounter++;
/* The same dir with a different norm : We took xNormIdeal/2 */
if(!CONSTANT_NODISTVIS)
{
if(_cMode & C_mode_FAILURE)
{
p_stDir = &gast_VectorArrayCpt[ulCounter].stDir;
MTH3D_M_vSubVector(p_stDir, &stStruct.stWantedCameraPos, &stStruct.stTargetedPersoPos);
MTH3D_M_vNormalizeVector(p_stDir, p_stDir);
MTH3D_M_vMulScalarVector(p_stDir, MTH_M_xMul(xNormIdeal, MTH_M_xFloatToReal(0.5f)), p_stDir);
gast_VectorArrayCpt[ulCounter].xPound = CAM_fnx_ComputePosPound(_p_stStruct, p_stDir);
ulCounter++;
if(_cMode & C_mode_MORE_CORRECT)
{
p_stDir = &gast_VectorArrayCpt[ulCounter].stDir;
MTH3D_M_vSubVector(p_stDir, &stStruct.stWantedCameraPos, &stStruct.stTargetedPersoPos);
MTH3D_M_vNormalizeVector(p_stDir, p_stDir);
MTH3D_M_vMulScalarVector(p_stDir, MTH_M_xMul(xNormIdeal, MTH_M_xFloatToReal(0.33f)), p_stDir);
gast_VectorArrayCpt[ulCounter].xPound = CAM_fnx_ComputePosPound(_p_stStruct, p_stDir);
ulCounter++;
}
}
}
/* WITH THETA = 0 */
stTemp.xAngleTheta = MTH_C_ZERO;
stStruct.hCineinfoWork->uwIAFlags |= C_IAFlags_NoShiftUntilPosReached;
CAM_fn_vComputeMovePosWithDynTheta(&stStruct);
/* Compute direction with good dist */
p_stDir = &gast_VectorArrayCpt[ulCounter].stDir;
MTH3D_M_vSubVector(p_stDir, &stStruct.stWantedCameraPos, &stStruct.stTargetedPersoPos);
gast_VectorArrayCpt[ulCounter].xPound = CAM_fnx_ComputePosPound(_p_stStruct, p_stDir);
ulCounter++;
/* WITH THETA = Pi/4 */
stTemp.xAngleTheta = MTH_C_PiBy4;
stStruct.hCineinfoWork->uwIAFlags |= C_IAFlags_NoShiftUntilPosReached;
CAM_fn_vComputeMovePosWithDynTheta(&stStruct);
/* Compute direction with good dist */
p_stDir = &gast_VectorArrayCpt[ulCounter].stDir;
MTH3D_M_vSubVector(p_stDir, &stStruct.stWantedCameraPos, &stStruct.stTargetedPersoPos);
gast_VectorArrayCpt[ulCounter].xPound = CAM_fnx_ComputePosPound(_p_stStruct, p_stDir);
ulCounter++;
/* WITH THETA = -Pi/4 */
stTemp.xAngleTheta = -MTH_C_PiBy4;
stStruct.hCineinfoWork->uwIAFlags |= C_IAFlags_NoShiftUntilPosReached;
CAM_fn_vComputeMovePosWithDynTheta(&stStruct);
/* Compute direction with good dist */
p_stDir = &gast_VectorArrayCpt[ulCounter].stDir;
MTH3D_M_vSubVector(p_stDir, &stStruct.stWantedCameraPos, &stStruct.stTargetedPersoPos);
gast_VectorArrayCpt[ulCounter].xPound = CAM_fnx_ComputePosPound(_p_stStruct, p_stDir);
ulCounter++;
xAngle += xBaseAngle;
}
guw_NbVectorArrayCpt = ulCounter;
stStruct.hCineinfo->eState = eState;
}
/*
*=================================================================================================
* Compute a new good ideal pos depending on real wanted position.
* _p_stComputeVector will receive computed position (if algo didn't fail).
* Returns: 1 in success
* 0 if failed
*=================================================================================================
*/
char CAM_fn_cFindNewGoodIdealPos
(
CAM_tdstUpdateCamera *_p_stStruct,
MTH3D_tdstVector *_p_stComputeVector,
char _cMode
)
{
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
unsigned long ulCounter;
MTH3D_tdstVector stTempVector, *p_stDir;
MTH_tdxReal xPoundRef;
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
MTH3D_M_vNullVector(_p_stComputeVector);
/*
* Compute pound of current wanted pos. When we want a better position, this is
* the reference pound (all positions with a greater poud will be eliminate).
*/
xPoundRef = MTH_C_ZERO;
if(_cMode & C_mode_MORE_CORRECT)
{
if(_cMode & C_mode_FAILURE)
{
MTH3D_M_vSubVector(&stTempVector, &_p_stStruct->stCurrentCameraPos, &_p_stStruct->stTargetedPersoPos);
}
else
{
MTH3D_M_vSubVector(&stTempVector, &_p_stStruct->stWantedCameraPos, &_p_stStruct->stTargetedPersoPos);
}
xPoundRef = CAM_fnx_ComputePosPound(_p_stStruct, &stTempVector);
}
/*
* Fill array of vectors to test.
*/
CAM_fn_vFillVectorArray(_p_stStruct, _cMode);
/*
* Sort array by priority.
*/
qsort
(
gast_VectorArrayCpt,
guw_NbVectorArrayCpt,
sizeof(tdst_PosPound),
CAM_fni_ComparePositions
);
/*
* Compute vector to test, and test...
*/
for ( ulCounter = 0; ulCounter < guw_NbVectorArrayCpt; ulCounter ++ )
{
p_stDir = &gast_VectorArrayCpt[ulCounter].stDir;
if
(
CAM_fnc_IsDirectionCorrect
(
_p_stStruct,
p_stDir,
gast_VectorArrayCpt[ulCounter].xPound,
xPoundRef,
_cMode
)
&&
CAM_fn_cFindCorrectPosWithDir
(
_p_stStruct,
p_stDir,
_p_stComputeVector,
_cMode
)
)
{
if(ulCounter == 0)
return 1;
return 2;
}
}
return 0;
}
/*
**************************************************************************************************
**************************************************************************************************
**************************************************************************************************
**************************************************************************************************
*/
/*
*=================================================================================================
* We must find a position to force the camera, cause we can't go to a new computed position
* without collision or visibility.
* We search a new good position but don't test if we can go to it.
*=================================================================================================
*/
void CAM_fn_vForceFailureVisibility(CAM_tdstUpdateCamera *_p_stStruct)
{
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
MTH3D_tdstVector stComputeVector, stTempVector;
char cMode;
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/*
* Find a new position but we don't care if we can go to.
*/
cMode = C_mode_MUSTSEE|C_mode_FAILURE;
if(CONSTANT_FORCEBESTPOS)
cMode |= C_mode_MORE_CORRECT;
if(!CAM_fn_cFindNewGoodIdealPos(_p_stStruct, &stComputeVector, cMode))
return;
/*
* Determin if we cut or not. If camera can see the computed one, or if distance if
* short enought, don't cut.
*/
MTH3D_M_vSubVector(&stTempVector, &stComputeVector, &_p_stStruct->stCurrentCameraPos);
_p_stStruct->hCineinfo->eState = CAM_e_State_FailureVisibility;
/*
* To remember the position where we want to go.
*/
MTH3D_M_vCopyVector(&_p_stStruct->hCineinfo->stLastFailedWanted, &stComputeVector);
}
/*
*=================================================================================================
* Compute the move after a failure visibility.
*=================================================================================================
*/
void CAM_fn_vComputeFailureVisibility(CAM_tdstUpdateCamera *_p_stStruct)
{
if(_p_stStruct->hCineinfo->eState == CAM_e_State_FailureVisibility)
{
/*
* Force camera to pos at stLastFailedWanted.
* Force target.
*/
CAM_fn_vForceCameraPos(_p_stStruct->hSuperObjCamera, &_p_stStruct->hCineinfo->stLastFailedWanted);
CAM_fn_vForceCameraTgt(_p_stStruct->hSuperObjCamera, &_p_stStruct->stCptPos.stTarget, &_p_stStruct->stCptPos.stRefAxisZ);
MTH3D_M_vCopyVector(&_p_stStruct->stCurrentCameraPos, &_p_stStruct->hCineinfo->stLastFailedWanted);
/*
* This is the new ideal position.
*/
CAM_fn_vMakeAsNewIdealPosition(_p_stStruct, &_p_stStruct->hCineinfo->stLastFailedWanted);
}
}
/*
**************************************************************************************************
**************************************************************************************************
**************************************************************************************************
**************************************************************************************************
*/
/*
*=================================================================================================
* Call to check if perso if not closest from camera.
* If it's a case, we try to find a new good ideal position.
*=================================================================================================
*/
void CAM_fn_vTestBadDistance(CAM_tdstUpdateCamera *_p_stStruct)
{
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
MTH3D_tdstVector stTempVector, stComputeVector;
char cMode;
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/*
* State must be optimal of computed optimal. We make the test cause a previous function
* can have change the state to force to failure.
*/
if
(
(_p_stStruct->hCineinfo->eState != CAM_e_State_GoToOptimal)
&& (_p_stStruct->hCineinfo->eState != CAM_e_State_GoToComputedOptimal)
)
return;
/*
* Flags must be correct.
*/
if
(
(_p_stStruct->hCineinfoWork->uwIAFlags & C_IAFlags_TargetIsAlreadyComputed)
|| (_p_stStruct->hCineinfoWork->uwIAFlags & C_IAFlags_PositionIsAlreadyComputed)
|| (_p_stStruct->hCineinfo->ucVolIAFlags & C_VolIAFlags_InitJustCopiedInCurrent)
)
return;
/*
* Get vector of current camera pos to real target to get distance.
*/
MTH3D_M_vSubVector(&stTempVector, &_p_stStruct->stCurrentCameraPos, &_p_stStruct->stTargetedPersoRealPos);
/*
* Failed in distance if :
* - Distance is less than minimal one.
* - We are in collision or camera doesn't move.
*/
if
(
(MTH_M_bGreater(MTH3D_M_xNormVector(&stTempVector), CAM_C_xMinDistPerso))
|| (
(!(DNM_M_bReportCollision(_p_stStruct->p_stReport)))
&& (!(_p_stStruct->hCineinfo->ucVolIAFlags & C_VolIAFlags_CameraNotMove))
)
)
return;
/*
* If current wanted position is correct, don't search, that's it !
*/
if(!CAM_fn_cIsWantedPosIncorrect(_p_stStruct, &_p_stStruct->stWantedCameraPos, C_mode_MUSTGO|C_mode_MUSTSEE))
return;
/*
* We try to find another correct position.
* If not, failure.
* If yes, this is the new ideal one.
*/
/* ANNECY MT - 03/08/99 { */
/* _p_stStruct->hCineinfo->wCounter1 = 0; */
_p_stStruct->hCineinfo->xCounter1 = MTH_C_ZERO;
/* END ANNECY MT } */
cMode = C_mode_MUSTGO|C_mode_MUSTSEE;
if(_p_stStruct->hCineinfoWork->uwIAFlags & C_IAFlags_NoVisibility)
cMode &= ~C_mode_MUSTSEE;
if(!CAM_fn_cFindNewGoodIdealPos(_p_stStruct, &stComputeVector, cMode))
CAM_fn_vForceFailureVisibility(_p_stStruct);
else
{
CAM_fn_vMakeAsNewIdealPosition(_p_stStruct, &stComputeVector);
_p_stStruct->hCineinfo->ucPerIAFlags |= C_PerIAFlags_ConstraintMoveVisFailure;
}
}
/*
*=====================================================================================================
* Test visibility of camera.
* Returns 1 if camera must pass in a special state cause of unvisibility.
* Returns 0 else.
*=====================================================================================================
*/
void CAM_fn_vTestBadVisibility(CAM_tdstUpdateCamera *_p_stStruct)
{
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
MTH3D_tdstVector stComputeVector, stTempVector;
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/*
* State must be optimal of computed optimal. We make the test cause a previous function
* can have change the state to force to failure.
*/
if
(
(_p_stStruct->hCineinfo->eState != CAM_e_State_GoToOptimal)
&& (_p_stStruct->hCineinfo->eState != CAM_e_State_GoToComputedOptimal)
)
return;
/*
* Flags must be correct.
*/
if
(
(_p_stStruct->hCineinfoWork->uwIAFlags & C_IAFlags_NoVisibility)
// || (_p_stStruct->hCineinfoWork->uwIAFlags & C_IAFlags_TargetIsAlreadyComputed)
|| (_p_stStruct->hCineinfoWork->uwIAFlags & C_IAFlags_PositionIsAlreadyComputed)
|| (_p_stStruct->hCineinfo->ucVolIAFlags & C_VolIAFlags_InitJustCopiedInCurrent)
)
return;
/*
* Counter must be correct to test visibility.
*/
/* ANNECY MT - 03/08/99 { */
/* _p_stStruct->hCineinfo->wCounter2++; */
_p_stStruct->hCineinfo->xCounter2 = MTH_M_xAdd(_p_stStruct->hCineinfo->xCounter2,MTH_M_xFloatToReal(g_stEngineStructure.stEngineTimer.ulUsefulDeltaTime));
/* if(_p_stStruct->hCineinfo->wCounter2 < CAM_C_xTickTestVisibility) */
if(MTH_M_bLess(_p_stStruct->hCineinfo->xCounter2 , CAM_C_xTickTimeTestVisibility))
return;
/* _p_stStruct->hCineinfo->wCounter2 = 0; */
_p_stStruct->hCineinfo->xCounter2 = MTH_C_ZERO;
/* OPTIM RAY : Only if last trame, we don't failed */
/* if(_p_stStruct->hCineinfo->wCounter3 == 0) */
if(MTH_M_bIsNull(_p_stStruct->hCineinfo->xCounter3))
{
/* If camera doesn't move, don't test static hierarchy */
/* if(_p_stStruct->hCineinfo->wCounter4 > 10) */
if(MTH_M_bGreater(_p_stStruct->hCineinfo->xCounter4 , MTH_M_xMul(MTH_M_xFloatToReal(10000.0f),g_stEngineStructure.stEngineTimer.xFrameLength)))
/* END ANNECY MT } */
// {
// if(_p_stStruct->hCineinfo->wCounter4)
cCanTestStatic = 0;
else
{
MTH3D_tdstVector stVectorNull;
MTH3D_M_vNullVector(&stVectorNull);
/* If last move is quiet equal to ray, don't test static */
MTH3D_M_vCopyVector(&stComputeVector, DNM_M_p_stReportGetLastMove(_p_stStruct->p_stReport));
MTH3D_M_vSubVector(&stTempVector, &_p_stStruct->stTargetedPersoRealPos, &_p_stStruct->stCurrentCameraPos);
if
(
(!CAM_fn_bEqualVectorWithEpsilon(&stComputeVector, &stVectorNull,MTH_M_xFloatToReal(0.0001f)))
&& (!CAM_fn_bEqualVectorWithEpsilon(&stTempVector, &stVectorNull,MTH_M_xFloatToReal(0.0001f)))
)
{
MTH3D_M_vNormalizeVector(&stComputeVector, &stComputeVector);
MTH3D_M_vNormalizeVector(&stTempVector, &stTempVector);
if(MTH_M_bGreater(MTH_M_xAbs(MTH3D_M_xDotProductVector(&stTempVector, &stComputeVector)), MTH_M_xFloatToReal(0.9f)))
cCanTestStatic = 0;
}
}
// }
}
/*
* Determin if we can see target real position.
* If we see it, exit cause no failed.
*/
/* ANNECY MT - 03/08/99 { */
if(!CAM_fn_cCameraCantSee(_p_stStruct, &_p_stStruct->stTargetedPersoRealPos, &_p_stStruct->stCurrentCameraPos))
{
/* _p_stStruct->hCineinfo->wCounter3 = 0; */
_p_stStruct->hCineinfo->xCounter3 = MTH_C_ZERO;
return;
}
/*
* FAILURE.
* Check for a too long time without seeing target.
*/
/* _p_stStruct->hCineinfo->wCounter3++; */
_p_stStruct->hCineinfo->xCounter3 = MTH_M_xAdd(_p_stStruct->hCineinfo->xCounter3,MTH_M_xFloatToReal(g_stEngineStructure.stEngineTimer.ulUsefulDeltaTime));
/* if(MTH_M_bGreater(_p_stStruct->hCineinfo->wCounter3, CAM_C_xTickFailureCantSee)) */
if(MTH_M_bGreater(_p_stStruct->hCineinfo->xCounter3 , CAM_C_xTickTimeFailureCantSee))
{
/* _p_stStruct->hCineinfo->wCounter3 = 0; */
_p_stStruct->hCineinfo->xCounter3 = MTH_C_ZERO;
CAM_fn_vForceFailureVisibility(_p_stStruct);
return;
}
/* END ANNECY MT } */
/*
* Test if we can go to wanted position. If yes, exit cause no failed.
*/
if(!CAM_fn_cIsWantedPosIncorrect(_p_stStruct, &_p_stStruct->stWantedCameraPos, C_mode_MUSTGO|C_mode_MUSTSEE))
return;
/*
* We try to find another correct position.
* If not, failure.
* If yes, this is the new ideal one.
*/
/* ANNECY MT - 03/08/99 { */
/*
_p_stStruct->hCineinfo->wCounter1 = 0;
_p_stStruct->hCineinfo->wCounter3 = 0;
*/
_p_stStruct->hCineinfo->xCounter1 = MTH_C_ZERO;
_p_stStruct->hCineinfo->xCounter3 = MTH_C_ZERO;
/* END ANNECY MT } */
if(!CAM_fn_cFindNewGoodIdealPos(_p_stStruct, &stComputeVector, C_mode_MUSTGO|C_mode_MUSTSEE))
CAM_fn_vForceFailureVisibility(_p_stStruct);
else
{
CAM_fn_vMakeAsNewIdealPosition(_p_stStruct, &stComputeVector);
_p_stStruct->hCineinfo->ucPerIAFlags |= C_PerIAFlags_ConstraintMoveVisFailure;
}
}
/*
*=================================================================================================
* Call to check if camera collide with a face with an opposite normal
* If it's a case, we try to find a new good ideal position.
*=================================================================================================
*/
void CAM_fn_vTestOppositeCollision(CAM_tdstUpdateCamera *_p_stStruct)
{
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
MTH3D_tdstVector stCameraMove;
char cMode;
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/*
* State must be optimal of computed optimal. We make the test cause a previous function
* can have change the state to force to failure.
*/
if
(
(_p_stStruct->hCineinfo->eState != CAM_e_State_GoToOptimal)
&& (_p_stStruct->hCineinfo->eState != CAM_e_State_GoToComputedOptimal)
)
return;
/*
* Flags must be correct.
*/
if
(
(_p_stStruct->hCineinfoWork->uwIAFlags & C_IAFlags_TargetIsAlreadyComputed)
|| (_p_stStruct->hCineinfoWork->uwIAFlags & C_IAFlags_PositionIsAlreadyComputed)
|| (_p_stStruct->hCineinfo->ucVolIAFlags & C_VolIAFlags_InitJustCopiedInCurrent)
)
return;
/*
* We must be in collision.
*/
if (!(DNM_M_bReportCollision(_p_stStruct->p_stReport)))
return;
/*
* Check a meca report for an opposite collision.
*/
if(!(DNM_M_bReportIsWall(_p_stStruct->p_stReport)))
return;
/*
* We try to find another correct position.
* If not, failure.
* If yes, this is the new ideal one.
*/
/* ANNECY MT - 03/08/99 { */
/* _p_stStruct->hCineinfo->wCounter1 = 0; */
_p_stStruct->hCineinfo->xCounter1 = MTH_C_ZERO;
/* END ANNECY MT } */
cMode = C_mode_MUSTGO|C_mode_MUSTSEE;
if(_p_stStruct->hCineinfoWork->uwIAFlags & C_IAFlags_NoVisibility)
cMode &= ~C_mode_MUSTSEE;
if(!CAM_fn_cFindNewGoodIdealPos(_p_stStruct, &stCameraMove, cMode))
CAM_fn_vForceFailureVisibility(_p_stStruct);
else
CAM_fn_vMakeAsNewIdealPosition(_p_stStruct, &stCameraMove);
}
/*
**************************************************************************************************
**************************************************************************************************
**************************************************************************************************
**************************************************************************************************
*/
/*
*=====================================================================================================
* Compute cineinfowork parameters to go to a specific position.
* - hCineinfoWork must be correct.
* - In that structure, must be correct :
* * super object (first and second)
* * channel number
*=====================================================================================================
*/
void CAM_fn_vComputeCineinfoWorkForAPosition(CAM_tdstUpdateCamera *_p_stStruct, MTH3D_tdstVector *_p_stPosition)
{
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
MTH3D_tdstVector stDir;
MTH3D_tdstVector stCamTargetVector;
MTH_tdxReal xAlphaAngle, xThetaAngle;
MTH_tdxReal xNorm;
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/* Compute normal axis (super object direction or vector direction in cineinfo */
CAM_fn_vComputeRefAxis(_p_stStruct, &stDir);
/* Compute rotated axis */
MTH3D_M_vSubVector(&stCamTargetVector, _p_stPosition, &_p_stStruct->stTargetedPersoPos);
xNorm = MTH3D_M_xNormVector(&stCamTargetVector);
/* Compute alpha and theta angles */
CAM_fn_vComputeAnglesBetweenTwoVectors
(
_p_stStruct->hCineinfoWork,
&stDir,
&stCamTargetVector,
&xAlphaAngle,
&xThetaAngle,
&_p_stStruct->stCptPos.stRefAxisZ
);
/*
* Set new parameters
*/
_p_stStruct->hCineinfoWork->xDistMin = xNorm;
_p_stStruct->hCineinfoWork->xDistMax = xNorm;
_p_stStruct->hCineinfoWork->xAngleAlpha = xAlphaAngle;
_p_stStruct->hCineinfoWork->xAngleTheta = xThetaAngle;
}
void CAM_fn_vComputeCineinfoCurrentForAPosition(CAM_tdstUpdateCamera *_p_stStruct, MTH3D_tdstVector *_p_stPosition)
{
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
struct tdstInternalStructurCineinfo_ *p_stMemo;
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
p_stMemo = _p_stStruct->hCineinfoWork;
_p_stStruct->hCineinfoWork = _p_stStruct->hCineinfoCurrent;
CAM_fn_vComputeCineinfoWorkForAPosition(_p_stStruct, _p_stPosition);
_p_stStruct->hCineinfoWork = p_stMemo;
}
/*
*=================================================================================================
* Compute a new ideal position.
*=================================================================================================
*/
void CAM_fn_vMakeAsNewIdealPosition(CAM_tdstUpdateCamera *_p_stStruct, MTH3D_tdstVector *_p_stPosition)
{
/*
* Now, cut angle can go in the sens it wants...
*/
_p_stStruct->hCineinfo->cLastCutAngleSens = 0;
/*
* This is now a computed ideal position. Remember actual current cineinfo
* (just the first time, look at function).
*/
/* if(!(_p_stStruct->hCineinfo->ucPerIAFlags & C_PerIAFlags_VisibilityCopied))*/
/* {*/
CAM_fn_vSetCineinfoVisibilityFromCurrent(_p_stStruct->hCineinfo);
/* memcpy(_p_stStruct->hCineinfo->hVisibility, _p_stStruct->hCineinfo->hWork, sizeof(struct tdstInternalStructurCineinfo_));*/
/* _p_stStruct->hCineinfo->ucPerIAFlags |= C_PerIAFlags_VisibilityCopied;*/
/* }*/
/*
* Compute parameters for that position.
*/
CAM_fn_vComputeCineinfoCurrentForAPosition(_p_stStruct, _p_stPosition);
/*
* New state.
*/
_p_stStruct->hCineinfo->eState = CAM_e_State_GoToComputedOptimal;
/*
* When we compute a position, we don't want shift alpha and theta to live...
*/
_p_stStruct->hCineinfo->ucPerIAFlags |= C_PerIAFlags_NoShift;
/*
* Compute for now. We copy in work the filed of cineinfcurrent that have been
* modified by SetCineinfo...
*/
_p_stStruct->hCineinfoWork->xAngleAlpha = _p_stStruct->hCineinfoCurrent->xAngleAlpha;
_p_stStruct->hCineinfoWork->xAngleTheta = _p_stStruct->hCineinfoCurrent->xAngleTheta;
_p_stStruct->hCineinfoWork->xDistMin = _p_stStruct->hCineinfoCurrent->xDistMin;
_p_stStruct->hCineinfoWork->xDistMax = _p_stStruct->hCineinfoCurrent->xDistMax;
/*
* Compute move.
*/
CAM_fn_vComputeMovePos(_p_stStruct);
/*
* Remember positions.
*/
MTH3D_M_vCopyVector(&_p_stStruct->hCineinfo->stLastFailedOrigin, &_p_stStruct->stCurrentCameraPos);
MTH3D_M_vCopyVector(&_p_stStruct->hCineinfo->stLastFailedWanted, _p_stPosition);
}
/*
**************************************************************************************************
**************************************************************************************************
**************************************************************************************************
**************************************************************************************************
*/
/*
*=====================================================================================================
* Determin if we can reset stLastFailedWanted.
*=====================================================================================================
*/
char CAM_fn_cCanResetConstraintMoveVisFailure(CAM_tdstUpdateCamera *_p_stStruct, MTH3D_tdstVector *_p_stWanted)
{
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
MTH3D_tdstVector stTempVector, stTempVector1;
MTH_tdxReal xNorm, xNorm1;
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/*
* Normal state : Ok.
*/
if(_p_stStruct->hCineinfo->eState == CAM_e_State_GoToOptimal)
return 1;
/*
* If camera doesn't move for a too long time, we can reset.
*/
/* ANNECY MT - 03/08/99 { */
/* if(_p_stStruct->hCineinfo->wCounter4 >= CAM_C_xTickFindBetterPosIfNoMove) */
if(MTH_M_bGreaterEqual(_p_stStruct->hCineinfo->xCounter4,CAM_C_xTickTimeFindBetterPosIfNoMove))
return 1;
/* END ANNECY MT } */
/*
* Special process after a failure.
* If we are in a special mode, we must test the end of the mode.
*/
if(!(_p_stStruct->hCineinfo->ucPerIAFlags & C_PerIAFlags_ConstraintMoveVisFailure))
return 1;
/*
* If current camera wanted position is outside the circle (center = last failed origin, ray =
* first shifting), we force last failed wanted to be NULL to tell that we can move now.
* There's a little epsilon on the ray not to be too short.
*/
MTH3D_M_vSubVector
(
&stTempVector,
_p_stWanted,
&_p_stStruct->hCineinfo->stLastFailedOrigin
);
xNorm = MTH3D_M_xNormVector(&stTempVector);
MTH3D_M_vSubVector
(
&stTempVector1,
&_p_stStruct->hCineinfo->stLastFailedWanted,
&_p_stStruct->hCineinfo->stLastFailedOrigin
);
xNorm1 = MTH3D_M_xNormVector(&stTempVector1);
/* if(MTH_M_bGreater(xNorm1, MTH_M_xFloatToReal(5.0f)))*/
/* xNorm1 = MTH_M_xFloatToReal(5.0f);*/
if(MTH_M_bLessEqual(xNorm, MTH_M_xAdd(xNorm1, 0.5)))
return 0;
/*
* We can reset vector.
*/
return 1;
}
/*
*=====================================================================================================
* To restore the normal state.
*=====================================================================================================
*/
void CAM_fn_vRestoreNormalState(CAM_tdstUpdateCamera *_p_stStruct)
{
/* Return to normal state */
_p_stStruct->hCineinfo->eState = CAM_e_State_GoToOptimal;
/* Restore visibility cineinfo structure to current one to restore parameters of ideal position */
CAM_fn_vSetCineinfoCurrentFromVisibility(_p_stStruct->hCineinfo);
CAM_fn_vSetCineinfoWorkFromVisibility(_p_stStruct->hCineinfo);
/*
* No shift until ideal pos is reached.
*/
_p_stStruct->hCineinfo->ucPerIAFlags |= C_PerIAFlags_NoShift;
_p_stStruct->hCineinfo->ucPerIAFlags &= ~C_PerIAFlags_ConstraintMoveVisFailure;
/*
* Compute position for this new position.
*/
CAM_fn_vComputeMovePosWithDynTheta(_p_stStruct);
}
/*
*=====================================================================================================
* Try to find a better position than current one.
*=====================================================================================================
*/
void CAM_fn_vCheckForABetterPos(CAM_tdstUpdateCamera *_p_stStruct)
{
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
MTH3D_tdstVector stComputeVector;
char cRes;
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/*
* One more trame in this new ideal position. If wCounter1 is too small, don't search a better one.
* Else we try to find a better position. We try to find a better position if camera doesn't move
* for a too long time too (wCounter4).
*--------------------------------------------------------------------------------------------------
*/
/* ANNECY MT - 03/08/99 { */
/* _p_stStruct->hCineinfo->wCounter1++; */
_p_stStruct->hCineinfo->xCounter1 = MTH_M_xAdd(_p_stStruct->hCineinfo->xCounter1,MTH_M_xFloatToReal(g_stEngineStructure.stEngineTimer.ulUsefulDeltaTime));
/* if((_p_stStruct->hCineinfo->wCounter1 >= CAM_C_xTickFindBetterPos) && (!(CONSTANT_NOBETTERPOS)) && _p_stStruct->hCineinfo->bCanDoBestPos) */
if(MTH_M_bGreaterEqual(_p_stStruct->hCineinfo->xCounter1 , CAM_C_xTickTimeFindBetterPos) && (!(CONSTANT_NOBETTERPOS)) && _p_stStruct->hCineinfo->bCanDoBestPos)
{
/* _p_stStruct->hCineinfo->wCounter1 = 0; */
_p_stStruct->hCineinfo->xCounter1 = MTH_C_ZERO;
/* END ANNECY MT } */
/*
* Test for a better position.
*/
cRes = CAM_fn_cFindNewGoodIdealPos(_p_stStruct, &stComputeVector, C_mode_MUSTGO|C_mode_MUSTSEE|C_mode_MORE_CORRECT);
if(cRes)
{
if(cRes == 1)
{
CAM_fn_vRestoreNormalState(_p_stStruct);
}
else
{
CAM_fn_vMakeAsNewIdealPosition(_p_stStruct, &stComputeVector);
if(_p_stStruct->hCineinfo->ucPerIAFlags & C_PerIAFlags_ConstraintMoveVisFailure)
cJustBetterPos = 1;
else
cJustBetterPos = 0;
_p_stStruct->hCineinfo->ucPerIAFlags &= ~C_PerIAFlags_ConstraintMoveVisFailure;
}
_p_stStruct->hCineinfo->bCanDoBestPos = FALSE;
}
}
}