1774 lines
61 KiB
C
1774 lines
61 KiB
C
/*
|
|
**************************************************************************************************
|
|
* General functions for camera AI.
|
|
**************************************************************************************************
|
|
*/
|
|
|
|
#define D_CineInfo_StructureDefine
|
|
|
|
#include "AIUseCPA.h"
|
|
|
|
#include "CAM_Base.h"
|
|
#include "CAM_Tool.h"
|
|
#include "CAM_Vis.h"
|
|
#include "Gam.h"
|
|
|
|
#include "safe.h"
|
|
#include "specif/aitools.h"
|
|
/*
|
|
* FLAGS THAT DEPEND ON ACTUAL WORK.
|
|
* That flags can change the compute of moving vectors.
|
|
* Determin if we must take a special axis.
|
|
*/
|
|
char cRefAxisIsAlreadyComputed;
|
|
char cNoDynChangeTheta;
|
|
|
|
/* Set when we find a better position, and we just became from a failure visibility */
|
|
char cJustBetterPos = 0;
|
|
|
|
extern char cCanTestStatic;
|
|
|
|
/*
|
|
**************************************************************************************************
|
|
**************************************************************************************************
|
|
COMPUTE REFERENCE POSITION
|
|
**************************************************************************************************
|
|
**************************************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
*=================================================================================================
|
|
* Compute reference camera axis to compute position.
|
|
*=================================================================================================
|
|
*/
|
|
void CAM_fn_vComputeRefAxis(CAM_tdstUpdateCamera *_p_stStruct, MTH3D_tdstVector *_p_stRefAxis)
|
|
{
|
|
/*
|
|
* Determin if reference axis has already been computed.
|
|
*/
|
|
if(cRefAxisIsAlreadyComputed)
|
|
{
|
|
MTH3D_tdstVector stVectorNull;
|
|
|
|
|
|
MTH3D_M_vNullVector(&stVectorNull);
|
|
/* Blindage ! */
|
|
/* if(MTH3D_M_bIsNullVector(&_p_stStruct->hCineinfo->stForceRefAxisY))*/
|
|
if (CAM_fn_bEqualVectorWithEpsilon(&_p_stStruct->hCineinfo->stForceRefAxisY, &stVectorNull,MTH_M_xFloatToReal(0.0001f)))
|
|
{
|
|
MTH3D_M_vSetVectorElements(&_p_stStruct->hCineinfo->stForceRefAxisY, MTH_C_ZERO, -MTH_C_ONE, MTH_C_ZERO);
|
|
MTH3D_M_vCopyVector(_p_stRefAxis, &_p_stStruct->hCineinfo->stForceRefAxisY);
|
|
}
|
|
else
|
|
{
|
|
MTH3D_M_vNormalizeVector(_p_stRefAxis, &_p_stStruct->hCineinfo->stForceRefAxisY);
|
|
}
|
|
/* Blindage ! */
|
|
/* if(MTH3D_M_bIsNullVector(&_p_stStruct->hCineinfo->stForceRefAxisZ))*/
|
|
if (CAM_fn_bEqualVectorWithEpsilon(&_p_stStruct->hCineinfo->stForceRefAxisZ, &stVectorNull,MTH_M_xFloatToReal(0.0001f)))
|
|
{
|
|
MTH3D_M_vSetVectorElements(&_p_stStruct->hCineinfo->stForceRefAxisZ, MTH_C_ZERO, MTH_C_ZERO, MTH_C_ONE);
|
|
}
|
|
else
|
|
{
|
|
MTH3D_M_vNormalizeVector(&_p_stStruct->stCptPos.stRefAxisZ, &_p_stStruct->hCineinfo->stForceRefAxisZ);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Apex mode if a second superobject is defined.
|
|
* Reference axis is the axis between the two persos.
|
|
*/
|
|
else if(_p_stStruct->hCineinfoWork->hSecondSuperObjectTargeted)
|
|
{
|
|
MTH3D_M_vSubVector(_p_stRefAxis, &_p_stStruct->stSecondTargetedPersoPos, &_p_stStruct->stTargetedPersoPos);
|
|
MTH3D_M_vNormalizeVector(_p_stRefAxis, _p_stRefAxis);
|
|
MTH3D_M_vSetVectorElements(&_p_stStruct->stCptPos.stRefAxisZ, MTH_C_ZERO, MTH_C_ZERO, MTH_C_ONE);
|
|
}
|
|
|
|
/*
|
|
* Else reference axis is perso sight axis.
|
|
*/
|
|
else
|
|
{
|
|
CAM_fn_vGetPersoSightAxis(_p_stStruct, _p_stRefAxis, &_p_stStruct->stCptPos.stRefAxisZ);
|
|
MTH3D_M_vSetVectorElements(&_p_stStruct->stCptPos.stRefAxisZ, MTH_C_ZERO, MTH_C_ZERO, MTH_C_ONE);
|
|
MTH3D_M_vNegVector(_p_stRefAxis, _p_stRefAxis);
|
|
}
|
|
}
|
|
|
|
/*
|
|
*=================================================================================================
|
|
* Compute the targeted perso position.
|
|
* This is the position of perso return by meca (average or linear) + the stShiftPos.
|
|
*=================================================================================================
|
|
*/
|
|
void CAM_fn_vComputeTargetedPersoPos
|
|
(
|
|
CAM_tdstUpdateCamera *_p_stStruct,
|
|
HIE_tdxHandleToSuperObject _hPerso,
|
|
MTH3D_tdstVector *_p_stTargetedPersoPos,
|
|
MTH3D_tdstVector *_p_stTargetedPersoRealPos
|
|
)
|
|
{
|
|
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
|
MTH3D_tdstVector stTempVector;
|
|
unsigned char ucChannel;
|
|
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
|
|
|
if(_hPerso == NULL)
|
|
{
|
|
MTH3D_M_vNullVector(_p_stTargetedPersoPos);
|
|
MTH3D_M_vNullVector(_p_stTargetedPersoRealPos);
|
|
return;
|
|
}
|
|
|
|
/* Get eventual channel number for that perso */
|
|
ucChannel = CAM_fn_cCineInfoGetChannel(_p_stStruct->hCineinfoWork);
|
|
if(ucChannel != 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);
|
|
}
|
|
|
|
/* Get real targeted perso position */
|
|
POS_fn_vGetTranslationVector(HIE_fn_hGetSuperObjectGlobalMatrix(_hPerso), _p_stTargetedPersoRealPos);
|
|
|
|
/*
|
|
* Compute perso position that will serve to compute following camera position.
|
|
* In some case, the position is the real one.
|
|
* In other cases, position is the average one computed by meca.
|
|
*/
|
|
if
|
|
(
|
|
(_p_stStruct->hCineinfo->ucVolIAFlags & C_VolIAFlags_InitJustCopiedInCurrent) /* It's the first trame */
|
|
|| (_p_stStruct->hCineinfoWork->uwIAFlags & C_IAFlags_NoAverageMoveTgtPerso) /* We want real pos of perso */
|
|
|| ((ucChannel == C_ucUnknownChannel) && (!M_GetMSHandle(_hPerso, Dynam))) /* Perso has no meca */
|
|
|| (ucChannel != C_ucUnknownChannel) /* We want a channel of perso */
|
|
)
|
|
{
|
|
MTH3D_M_vCopyVector(_p_stTargetedPersoPos, _p_stTargetedPersoRealPos);
|
|
}
|
|
else
|
|
{
|
|
CAM_fn_vAveragePosition(_p_stStruct->hCineinfo, CAM_C_xAverageForComputePos, _p_stTargetedPersoPos);
|
|
}
|
|
|
|
/*
|
|
* Compute shift pos. We rotate it depending on perso rotation matrix.
|
|
*/
|
|
MTH3D_M_vCopyVector(&stTempVector, &_p_stStruct->hCineinfoWork->stShiftPos);
|
|
|
|
POS_fn_vRotateVector(&stTempVector, HIE_fn_hGetSuperObjectGlobalMatrix(_hPerso), &stTempVector);
|
|
|
|
/*
|
|
* Add shift pos to the 2 computed vectors.
|
|
*/
|
|
MTH3D_M_vAddVector
|
|
(
|
|
_p_stTargetedPersoPos,
|
|
_p_stTargetedPersoPos,
|
|
&stTempVector
|
|
);
|
|
MTH3D_M_vAddVector
|
|
(
|
|
_p_stTargetedPersoRealPos,
|
|
_p_stTargetedPersoRealPos,
|
|
&stTempVector
|
|
);
|
|
}
|
|
|
|
|
|
/*
|
|
*=================================================================================================
|
|
* Compute the reference position to compute target and camera position.
|
|
*=================================================================================================
|
|
*/
|
|
void CAM_fn_vComputeReferencePoint(CAM_tdstUpdateCamera *_p_stStruct)
|
|
{
|
|
/*
|
|
* If there are 2 persos, force camera to take real position instead of
|
|
* average cause of a wonderful optim (average in camera and not in meca).
|
|
*/
|
|
if(_p_stStruct->hCineinfoWork->hSecondSuperObjectTargeted)
|
|
_p_stStruct->hCineinfoWork->uwIAFlags |= C_IAFlags_NoAverageMoveTgtPerso;
|
|
|
|
/*
|
|
* Position of first perso;
|
|
*/
|
|
CAM_fn_vComputeTargetedPersoPos
|
|
(
|
|
_p_stStruct,
|
|
_p_stStruct->hCineinfoWork->hSuperObjectTargeted,
|
|
&_p_stStruct->stTargetedPersoPos,
|
|
&_p_stStruct->stTargetedPersoRealPos
|
|
);
|
|
|
|
/*
|
|
* Position of second perso. If yes, we took the middle of the axis between the
|
|
* two persos.
|
|
*/
|
|
if(_p_stStruct->hCineinfoWork->hSecondSuperObjectTargeted)
|
|
{
|
|
CAM_fn_vComputeTargetedPersoPos
|
|
(
|
|
_p_stStruct,
|
|
_p_stStruct->hCineinfoWork->hSecondSuperObjectTargeted,
|
|
&_p_stStruct->stSecondTargetedPersoPos,
|
|
&_p_stStruct->stSecondTargetedPersoRealPos
|
|
);
|
|
|
|
MTH3D_M_vLinearInterpolVector
|
|
(
|
|
&_p_stStruct->stTargetedPersoPos,
|
|
&_p_stStruct->stTargetedPersoPos,
|
|
&_p_stStruct->stSecondTargetedPersoPos,
|
|
MTH_M_xFloatToReal(_p_stStruct->hCineinfo->xApexRatio)
|
|
);
|
|
MTH3D_M_vLinearInterpolVector
|
|
(
|
|
&_p_stStruct->stTargetedPersoRealPos,
|
|
&_p_stStruct->stTargetedPersoRealPos,
|
|
&_p_stStruct->stSecondTargetedPersoRealPos,
|
|
MTH_M_xFloatToReal(_p_stStruct->hCineinfo->xApexRatio)
|
|
);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
**************************************************************************************************
|
|
**************************************************************************************************
|
|
COMPUTE TARGET
|
|
**************************************************************************************************
|
|
**************************************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
*=================================================================================================
|
|
* To be sure that targeted perso is visible.
|
|
*=================================================================================================
|
|
*/
|
|
|
|
#ifndef _FIRE_DEADCODE_U64_ /* Added by RUC */
|
|
void CAM_fn_vDynChangeTarget(CAM_tdstUpdateCamera *_p_stStruct, MTH3D_tdstVector *_p_stTempVector)
|
|
{
|
|
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
|
MTH_tdxReal xFocal = MTH_M_xMul(_p_stStruct->hCineinfoWork->xFocal, MTH_C_Inv2);
|
|
MTH_tdxReal xAngle, xNorm;
|
|
MTH3D_tdstVector stTempVector, stTempVector1;
|
|
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
|
|
|
/*
|
|
* If no dynamic target request or first trame, don't process.
|
|
*/
|
|
if
|
|
(
|
|
(_p_stStruct->hCineinfoWork->uwIAFlags & C_IAFlags_NoDynamicTarget)
|
|
|| (_p_stStruct->hCineinfo->ucVolIAFlags & C_VolIAFlags_InitJustCopiedInCurrent)
|
|
)
|
|
return;
|
|
|
|
MTH3D_M_vSubVector(&stTempVector, &_p_stStruct->stTargetedPersoPos, &_p_stStruct->stCurrentCameraPos);
|
|
MTH3D_M_vAddVector(&stTempVector, &stTempVector, _p_stTempVector);
|
|
MTH3D_M_vSubVector(&stTempVector1, &_p_stStruct->stTargetedPersoRealPos, &_p_stStruct->stCurrentCameraPos);
|
|
xAngle = CAM_fn_xComputeRotation(&stTempVector, &stTempVector1, NULL);
|
|
|
|
/* Add an epsilon to demi-focal angle */
|
|
xFocal = MTH_M_xSub(xFocal, CAM_C_xEpsilonDynTgtFocalAngle);
|
|
|
|
if(MTH_M_bLess(xAngle , xFocal))
|
|
return;
|
|
|
|
xNorm = MTH_M_xDiv(MTH3D_M_xNormVector(&stTempVector), MTH_M_xCos(xFocal));
|
|
xNorm = MTH_M_xMul(MTH_M_xSin(xFocal), xNorm);
|
|
MTH3D_M_vSubVector(&stTempVector, &_p_stStruct->stTargetedPersoRealPos, &_p_stStruct->stTargetedPersoPos);
|
|
MTH3D_M_vAddVector(&stTempVector, &stTempVector, _p_stTempVector);
|
|
MTH3D_M_vNormalizeVector(&stTempVector, &stTempVector);
|
|
/* MTH3D_M_vMulScalarVector(&stTempVector, xNorm, &stTempVector);*/
|
|
/* MTH3D_M_vCopyVector(_p_stTempVector, &stTempVector);*/
|
|
MTH3D_M_vMulScalarVector(_p_stTempVector, xNorm, &stTempVector);
|
|
}
|
|
#endif /* _FIRE_DEADCODE_U64_ */ /* Added by RUC */
|
|
|
|
|
|
/*
|
|
*=================================================================================================
|
|
* Compute the target depending on shift and persos.
|
|
*=================================================================================================
|
|
*/
|
|
void CAM_fn_vComputeTarget(CAM_tdstUpdateCamera *_p_stStruct)
|
|
{
|
|
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
|
MTH3D_tdstVector stTempLook;
|
|
HIE_tdxHandleToSuperObject h_Perso;
|
|
unsigned char ucChannel;
|
|
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
|
|
|
/*
|
|
* If target vertex was already computed, we copy it without additional process.
|
|
*-------------------------------------------------------------------------------
|
|
*/
|
|
if(_p_stStruct->hCineinfoWork->uwIAFlags & C_IAFlags_TargetIsAlreadyComputed)
|
|
{
|
|
MTH3D_M_vCopyVector(&_p_stStruct->stCptPos.stTarget, &_p_stStruct->hCineinfo->stForceTarget);
|
|
}
|
|
|
|
/*
|
|
* No handle to target, and no forced target : strange...
|
|
*--------------------------------------------------------
|
|
*/
|
|
else if (_p_stStruct->hCineinfoWork->hSuperObjectTargeted == NULL)
|
|
{
|
|
MTH3D_M_vNullVector(&_p_stStruct->stCptPos.stTarget);
|
|
}
|
|
|
|
/*
|
|
* For 2 persos, the shift target must be in the new camera axis (axis between the 2 persos).
|
|
* Don't care of stShiftTarget.
|
|
*--------------------------------------------------------------------------------------------
|
|
*/
|
|
else if(_p_stStruct->hCineinfoWork->hSecondSuperObjectTargeted)
|
|
{
|
|
MTH3D_M_vCopyVector(&_p_stStruct->stCptPos.stTarget, &_p_stStruct->stTargetedPersoPos);
|
|
}
|
|
|
|
/*
|
|
* Else we compute target depending on targeted perso position.
|
|
*--------------------------------------------------------------
|
|
*/
|
|
else
|
|
{
|
|
/*
|
|
* Get targeted perso
|
|
*/
|
|
h_Perso = _p_stStruct->hCineinfoWork->hSuperObjectTargeted;
|
|
if ((ucChannel = CAM_fn_cCineInfoGetChannel(_p_stStruct->hCineinfoWork)) != C_ucUnknownChannel)
|
|
{
|
|
/* FBF blindage acces modules {*/
|
|
#ifdef ACTIVE_EDITOR
|
|
fn_vCheckModuleAccess(h_Perso,TRUE, &ucChannel);
|
|
#endif
|
|
/* } fin blindage acces modules */
|
|
h_Perso = fn_hGetSuperObjectInChannel(fn_h3dDataGetChannelSOList(M_GetMSHandle(h_Perso, 3dData)), (short) ucChannel);
|
|
}
|
|
|
|
/*
|
|
* Compute additional target vertex.
|
|
*/
|
|
MTH3D_M_vCopyVector(&stTempLook, &_p_stStruct->hCineinfoWork->stShiftTarget);
|
|
POS_fn_vRotateVector(&stTempLook, HIE_fn_hGetSuperObjectGlobalMatrix(h_Perso), &stTempLook);
|
|
MTH3D_M_vAddVector(&_p_stStruct->stCptPos.stTarget, &_p_stStruct->stTargetedPersoPos, &stTempLook);
|
|
|
|
/*
|
|
* A little change. We change the look vertex to be as max as possible from perso, so for the gameplay,
|
|
* this will permit to see as possible what the perso can see.
|
|
*/
|
|
/* CAM_fn_vDynChangeTarget(_p_stStruct, &stTempLook);*/
|
|
|
|
/*
|
|
* Compute resultant look position and update field.
|
|
*/
|
|
MTH3D_M_vAddVector(&_p_stStruct->stCptPos.stTarget, &_p_stStruct->stTargetedPersoPos, &stTempLook);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
**************************************************************************************************
|
|
**************************************************************************************************
|
|
COMPUTE MOVE VECTOR
|
|
**************************************************************************************************
|
|
**************************************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
*=================================================================================================
|
|
* Description : bound angle
|
|
* _p_xAngleToBound -> angle to bound (current real angle)
|
|
* _p_xCutAngle -> To receive cut angle.
|
|
* _xAngle -> angle ideal
|
|
* _xTolerance -> tolerance
|
|
*=================================================================================================
|
|
*/
|
|
void CAM_fn_vBoundAngleWithTolerance
|
|
(
|
|
CAM_tdstUpdateCamera *_p_stStruct,
|
|
MTH_tdxReal *_p_xAngleToBound,
|
|
MTH_tdxReal *_p_xCutAngle,
|
|
MTH_tdxReal *_p_xDeltaAngle,
|
|
MTH_tdxReal _xRequestAngle,
|
|
MTH_tdxReal _xTolerance
|
|
)
|
|
{
|
|
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
|
MTH_tdxReal xAngleMin;
|
|
MTH_tdxReal xAngleMax;
|
|
MTH_tdxReal xDelta;
|
|
MTH_tdxReal xNewAngle;
|
|
BOOL bInTolerance;
|
|
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
|
|
|
/*
|
|
* If tolerance is greater equal than Pi, current angle is correct. Don't need to bound.
|
|
*/
|
|
if (MTH_M_bGreaterEqual(_xTolerance, MTH_C_Pi))
|
|
{
|
|
*_p_xCutAngle = *_p_xAngleToBound;
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* If tolerance.
|
|
*/
|
|
xNewAngle = _xRequestAngle;
|
|
if (MTH_M_bGreater(_xTolerance, MTH_C_ZERO))
|
|
{
|
|
/*
|
|
* Compute angle min and angle max.
|
|
*/
|
|
_xTolerance = MTH_M_xAdd(_xTolerance, MTH_M_xFloatToReal(0.0001f));
|
|
xAngleMin = MTH_M_xSub(_xRequestAngle, _xTolerance);
|
|
if (MTH_M_bLessZero(xAngleMin))
|
|
xAngleMin = MTH_M_xAdd(xAngleMin, MTH_C_2Pi);
|
|
|
|
xAngleMax = MTH_M_xAdd(_xRequestAngle, _xTolerance);
|
|
if (MTH_M_bGreater(xAngleMax, MTH_C_2Pi))
|
|
xAngleMax = MTH_M_xSub(xAngleMax, MTH_C_2Pi);
|
|
|
|
/*
|
|
* Determin if current angle is between angle min and max.
|
|
*/
|
|
if (MTH_M_bGreater(xAngleMax, xAngleMin))
|
|
bInTolerance = MTH_M_bInRangeEqual(*_p_xAngleToBound, xAngleMin, xAngleMax);
|
|
else
|
|
bInTolerance = !MTH_M_bInRange(*_p_xAngleToBound, xAngleMax, xAngleMin);
|
|
|
|
/*
|
|
* If current angle is not between that 2 values, we must bound it.
|
|
*/
|
|
if (!bInTolerance)
|
|
{
|
|
xDelta = MTH_M_xSub(*_p_xAngleToBound, _xRequestAngle);
|
|
xDelta = CAM_fn_xSetAngleInIntervalPiPi(xDelta);
|
|
|
|
/*
|
|
* We set wanted angle to angle min or max depending on the sens.
|
|
*/
|
|
if (MTH_M_bGreater(xDelta, MTH_C_ZERO))
|
|
xNewAngle = xAngleMax;
|
|
else
|
|
xNewAngle = xAngleMin;
|
|
}
|
|
else
|
|
xNewAngle = *_p_xAngleToBound;
|
|
}
|
|
|
|
/*
|
|
* Cut big angle in smaller one if necessary.
|
|
*/
|
|
xDelta = MTH_M_xSub(xNewAngle, *_p_xAngleToBound);
|
|
xDelta = CAM_fn_xSetAngleInIntervalPiPi(xDelta);
|
|
*_p_xDeltaAngle = xDelta;
|
|
if(MTH_M_bGreaterEqual(MTH_M_xAbs(xDelta), CAM_C_xBaseCutAngle))
|
|
{
|
|
if (MTH_M_bGreaterZero(xDelta))
|
|
*_p_xCutAngle = MTH_M_xAdd(*_p_xAngleToBound, CAM_C_xBaseCutAngle);
|
|
else
|
|
*_p_xCutAngle = MTH_M_xSub(*_p_xAngleToBound, CAM_C_xBaseCutAngle);
|
|
*_p_xCutAngle = CAM_fn_xSetAngleInInterval02Pi(*_p_xCutAngle);
|
|
}
|
|
else
|
|
*_p_xCutAngle = xNewAngle;
|
|
|
|
/*
|
|
* Set new bounded angle.
|
|
*/
|
|
*_p_xAngleToBound = xNewAngle;
|
|
}
|
|
|
|
/*
|
|
*=================================================================================================
|
|
Description : compute ideal angles that depend of parameters and old camera position
|
|
_p_stStruct -> camera data
|
|
_p_stCameraAxis -> new camera axis (without rotation)
|
|
_p_stCamTargetAxis -> old camera position to new target axis
|
|
_p_xHorAngle -> horizontal angle
|
|
_p_xVerAngle -> vertical angle
|
|
*=================================================================================================
|
|
*/
|
|
void CAM_fn_vComputeCameraAxisAngles
|
|
(
|
|
CAM_tdstUpdateCamera *_p_stStruct,
|
|
MTH3D_tdstVector *_p_stCameraAxis,
|
|
MTH3D_tdstVector *_p_stCamTargetAxis,
|
|
MTH_tdxReal *_p_xHorAngle,
|
|
MTH_tdxReal *_p_xVerAngle
|
|
)
|
|
{
|
|
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
|
MTH_tdxReal xTemp, xShiftAlpha, xShiftTheta;
|
|
MTH_tdxReal xAngleTheta;
|
|
MS_tdxHandleToInternalCineinfo hCineInfoWork;
|
|
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
|
|
|
hCineInfoWork = _p_stStruct->hCineinfoWork;
|
|
/*
|
|
* compute angle between old direction and new dir
|
|
*/
|
|
CAM_fn_vComputeAnglesBetweenTwoVectors
|
|
(
|
|
hCineInfoWork,
|
|
_p_stCameraAxis,
|
|
_p_stCamTargetAxis,
|
|
_p_xHorAngle,
|
|
_p_xVerAngle,
|
|
&_p_stStruct->stCptPos.stRefAxisZ
|
|
);
|
|
|
|
/*
|
|
* If no shift flag is set, no tolerance for angles.
|
|
*/
|
|
if
|
|
(
|
|
(_p_stStruct->hCineinfo->ucPerIAFlags & C_PerIAFlags_NoShift)
|
|
|| (_p_stStruct->hCineinfoWork->uwIAFlags & C_IAFlags_NoShiftUntilPosReached)
|
|
)
|
|
{
|
|
xShiftAlpha = MTH_C_ZERO;
|
|
xShiftTheta = MTH_C_ZERO;
|
|
}
|
|
else
|
|
{
|
|
xShiftAlpha = _p_stStruct->hCineinfoWork->xAngleShiftAlpha;
|
|
xShiftTheta = _p_stStruct->hCineinfoWork->xAngleShiftTheta;
|
|
}
|
|
|
|
/*
|
|
* Tolerance on horizontal angle
|
|
*/
|
|
_p_stStruct->cHasCutAlpha = 0;
|
|
CAM_fn_vBoundAngleWithTolerance
|
|
(
|
|
_p_stStruct,
|
|
_p_xHorAngle,
|
|
&_p_stStruct->xAngleAlphaCut,
|
|
&_p_stStruct->xAngleDeltaAlphaCut,
|
|
_p_stStruct->hCineinfoWork->xAngleAlpha,
|
|
xShiftAlpha
|
|
);
|
|
if(!(MTH_M_bEqual(*_p_xHorAngle, _p_stStruct->xAngleAlphaCut)))
|
|
_p_stStruct->cHasCutAlpha = 1;
|
|
|
|
/*
|
|
* Tolerance on vertical angle
|
|
*/
|
|
if(_p_stStruct->hCineinfo->eState == CAM_e_State_GoToComputedOptimal)
|
|
xAngleTheta = _p_stStruct->hCineinfoCurrent->xAngleTheta;
|
|
else
|
|
xAngleTheta = _p_stStruct->hCineinfoWork->xAngleTheta;
|
|
|
|
CAM_fn_vBoundAngleWithTolerance
|
|
(
|
|
_p_stStruct,
|
|
_p_xVerAngle,
|
|
&xTemp,
|
|
&xTemp,
|
|
xAngleTheta,
|
|
xShiftTheta
|
|
);
|
|
}
|
|
|
|
/*
|
|
*=================================================================================================
|
|
* Rotate camera axis with two angles (one in horizontal plane, the other in vertical plane)
|
|
* _p_stCameraAxis -> axis (result axis is set in this parameter)
|
|
* _xHorAngle -> rotation in horizontal plane (xOy)
|
|
* _xVerAngle -> rotation in vertical plane (zOy)
|
|
*=================================================================================================
|
|
*/
|
|
void CAM_fn_vRotateCameraAxis
|
|
(
|
|
MTH3D_tdstVector *_p_stCameraAxis,
|
|
MTH_tdxReal _xHorAngle,
|
|
MTH_tdxReal _xVerAngle,
|
|
MTH3D_tdstVector *_p_stRefAxisZ
|
|
)
|
|
{
|
|
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
|
MTH_tdstRotation stRotation;
|
|
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
|
|
|
/*
|
|
* Rotate axis around Z axis.
|
|
*/
|
|
stRotation.m_xAngle = _xHorAngle;
|
|
MTH3D_M_vCopyVector(&stRotation.m_stAxis, _p_stRefAxisZ);
|
|
MTH_p_stRotationMulVector(&stRotation, _p_stCameraAxis, _p_stCameraAxis);
|
|
|
|
/*
|
|
* Compute x Axis, and rotate axis around x axis.
|
|
*/
|
|
MTH3D_M_vCrossProductVectorWithoutBuffer(&stRotation.m_stAxis, _p_stCameraAxis, _p_stRefAxisZ);
|
|
MTH3D_M_vNormalizeVector(&stRotation.m_stAxis, &stRotation.m_stAxis);
|
|
stRotation.m_xAngle = _xVerAngle;
|
|
MTH_p_stRotationMulVector(&stRotation, _p_stCameraAxis, _p_stCameraAxis);
|
|
|
|
}
|
|
|
|
/*
|
|
*=================================================================================================
|
|
* Compute real camera wanted position.
|
|
*=================================================================================================
|
|
*/
|
|
void CAM_fn_vComputeRealWantedPos(CAM_tdstUpdateCamera *_p_stStruct)
|
|
{
|
|
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
|
CAM_tdstUpdateCamera stTempStruct;
|
|
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
|
|
|
/*
|
|
* A temporary structure.
|
|
*/
|
|
memcpy(&stTempStruct, _p_stStruct, sizeof(CAM_tdstUpdateCamera));
|
|
|
|
/*
|
|
* Real wanted position for normal state is the same that current wanted position.
|
|
* We must assure that there's no shifting vertex to retreive the ideal position, so we
|
|
* get current working structure (we copy it in visibility one that is not used).
|
|
*/
|
|
if(_p_stStruct->hCineinfo->ucPerIAFlags & C_PerIAFlags_VisibilityCopied)
|
|
{
|
|
memcpy(&gst_Ideal, _p_stStruct->hCineinfoVisibility, sizeof(struct tdstInternalStructurCineinfo_));
|
|
/* gst_Ideal.xAngleTheta = _p_stStruct->hCineinfoWork->xAngleTheta;*/
|
|
|
|
gst_Ideal.xDistMin = _p_stStruct->hCineinfoWork->xDistMin;
|
|
gst_Ideal.xDistMax = _p_stStruct->hCineinfoWork->xDistMax;
|
|
}
|
|
else
|
|
memcpy(&gst_Ideal, _p_stStruct->hCineinfoWork, sizeof(struct tdstInternalStructurCineinfo_));
|
|
|
|
/*
|
|
* Compute position. Force to have no shift to compute the real wanted position only
|
|
* depending on alpha and theta (and not shift values).
|
|
*/
|
|
gst_Ideal.uwIAFlags |= C_IAFlags_NoShiftUntilPosReached;
|
|
stTempStruct.hCineinfoWork = &gst_Ideal;
|
|
CAM_fn_vComputeMovePosWithDynTheta(&stTempStruct);
|
|
MTH3D_M_vCopyVector(&_p_stStruct->stRealWantedCameraPos, &stTempStruct.stWantedCameraPos);
|
|
}
|
|
|
|
/*
|
|
*=================================================================================================
|
|
* Change theta depending of current targeted perso move.
|
|
* Return 0 if theta is not changed, and 1 else.
|
|
*=================================================================================================
|
|
*/
|
|
char CAM_fn_cDynChangeTheta(CAM_tdstUpdateCamera *_p_stStruct, MTH3D_tdstVector *_p_stTestedPos)
|
|
{
|
|
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
|
MTH3D_tdstVector stMove, stRef, stSightAxis;
|
|
MTH3D_tdstVector stNormal;
|
|
MTH_tdxReal xAngle, xThetaAngle;
|
|
MTH_tdxReal xCos;
|
|
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
|
|
|
/*
|
|
* Get the normal of the face the targeted perso is walking on.
|
|
*/
|
|
if(!CAM_fn_bPersoOnFace(_p_stStruct->hCineinfoWork->hSuperObjectTargeted, &stNormal))
|
|
return 0;
|
|
|
|
/*
|
|
* Compute projection of perso sight axis on face.
|
|
*/
|
|
CAM_fn_vComputeRefAxis(_p_stStruct, &stSightAxis);
|
|
CAM_fn_vComputeProjection(&stMove, &stSightAxis, &stNormal);
|
|
MTH3D_M_vNormalizeVector(&stMove, &stMove);
|
|
|
|
/*
|
|
* Compute requested theta angle.
|
|
*/
|
|
MTH3D_M_vSetVectorElements(&stRef, MTH_C_ZERO, MTH_C_ZERO, MTH_C_ONE);
|
|
xAngle = CAM_fn_xComputeRotation(&stRef, &stMove, NULL);
|
|
xAngle = MTH_M_xSub(xAngle, MTH_C_PiBy2);
|
|
|
|
MTH3D_M_vSubVector(&stRef, &_p_stStruct->stTargetedPersoPos, _p_stTestedPos);
|
|
MTH3D_M_vNormalizeVector(&stRef, &stRef);
|
|
xCos = MTH3D_M_xDotProductVector(&stRef, &stMove);
|
|
xAngle = MTH_M_xMul(xAngle, xCos);
|
|
|
|
/*
|
|
* Compute normal theta angle for tested position.
|
|
*/
|
|
if(_p_stStruct->hCineinfo->ucPerIAFlags & C_PerIAFlags_VisibilityCopied)
|
|
xThetaAngle = _p_stStruct->hCineinfoVisibility->xAngleTheta;
|
|
else
|
|
/* ANNECY MT - 09/07/99 { */
|
|
/*xThetaAngle = _p_stStruct->hCineinfoCurrent->xAngleTheta;*/
|
|
xThetaAngle = _p_stStruct->hCineinfoWork->xAngleTheta;
|
|
/* END ANNECY MT } */
|
|
|
|
/*
|
|
* Compute additional theta angle.
|
|
* Epsilon is current theta angle.
|
|
*
|
|
* - If actual and requested theta are opposite, we will add xAngle to current theta.
|
|
* - Else we compute the difference between the two angles.
|
|
* - Cause of current theta, new angle can be the same as wanted one.
|
|
*/
|
|
if(MTH_M_bLess(MTH_M_xMul(xThetaAngle, xAngle), MTH_C_ZERO))
|
|
{
|
|
xAngle = xAngle;
|
|
}
|
|
else if
|
|
(
|
|
MTH_M_bLessEqual
|
|
(
|
|
MTH_M_xAbs(xThetaAngle),
|
|
MTH_M_xAbs(xAngle)
|
|
)
|
|
)
|
|
{
|
|
xAngle = MTH_M_xSub(xAngle, xThetaAngle);
|
|
}
|
|
else
|
|
{
|
|
xAngle = MTH_C_ZERO;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Add angle to current theta.
|
|
*/
|
|
_p_stStruct->hCineinfoWork->xAngleTheta = MTH_M_xAdd(xThetaAngle, xAngle);
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
*=================================================================================================
|
|
* Description : Take care of camera's altitude
|
|
*=================================================================================================
|
|
*/
|
|
void CAM_fn_vTakeCareOfCameraAltitude(MS_tdxHandleToCineinfo _hCineinfo, MTH3D_tdstVector *_p_stNewCameraPosition)
|
|
{
|
|
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
|
MTH_tdxReal xZCamera;
|
|
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
|
|
|
xZCamera = _p_stNewCameraPosition->xZ;
|
|
|
|
if (MTH_M_bGreater(xZCamera, _hCineinfo->hWork->xZMax))
|
|
_p_stNewCameraPosition->xZ = _hCineinfo->hWork->xZMax;
|
|
|
|
if (MTH_M_bLess(xZCamera, _hCineinfo->hWork->xZMin))
|
|
_p_stNewCameraPosition->xZ = _hCineinfo->hWork->xZMin;
|
|
|
|
}
|
|
|
|
/*
|
|
*=================================================================================================
|
|
* Compute move vector of camera.
|
|
*=================================================================================================
|
|
*/
|
|
void CAM_fn_vComputeMovePos(CAM_tdstUpdateCamera *_p_stStruct)
|
|
{
|
|
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
|
MTH3D_tdstVector stDir;
|
|
MTH3D_tdstVector stCamTargetVector;
|
|
MTH_tdxReal xNorm;
|
|
MTH_tdxReal xDistMin;
|
|
MTH_tdxReal xDistMax;
|
|
MTH_tdxReal xAlphaAngle, xThetaAngle;
|
|
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
|
|
|
/*
|
|
* Test if we have force camera position.
|
|
*/
|
|
if(_p_stStruct->hCineinfoWork->uwIAFlags & C_IAFlags_PositionIsAlreadyComputed)
|
|
{
|
|
if(cRefAxisIsAlreadyComputed)
|
|
{
|
|
MTH3D_M_vNormalizeVector(&_p_stStruct->stCptPos.stRefAxisZ, &_p_stStruct->hCineinfo->stForceRefAxisZ);
|
|
}
|
|
else
|
|
{
|
|
MTH3D_M_vSetVectorElements(&_p_stStruct->stCptPos.stRefAxisZ, MTH_C_ZERO, MTH_C_ZERO, MTH_C_ONE);
|
|
}
|
|
/* no Dynamic Theta change when we have force camera position */
|
|
cNoDynChangeTheta = 1;
|
|
|
|
/* Wanted position and move */
|
|
MTH3D_M_vCopyVector(&_p_stStruct->stWantedCameraPos, &_p_stStruct->hCineinfo->stForcePosition);
|
|
MTH3D_M_vSubVector(&_p_stStruct->stCptPos.stMovePos, &_p_stStruct->stWantedCameraPos, &_p_stStruct->stCurrentCameraPos);
|
|
}
|
|
|
|
/*
|
|
* Test if the camera has a target.
|
|
*/
|
|
else if(!_p_stStruct->hCineinfoWork->hSuperObjectTargeted)
|
|
{
|
|
if(cRefAxisIsAlreadyComputed)
|
|
{
|
|
MTH3D_M_vNormalizeVector(&_p_stStruct->stCptPos.stRefAxisZ, &_p_stStruct->hCineinfo->stForceRefAxisZ);
|
|
}
|
|
else
|
|
{
|
|
MTH3D_M_vSetVectorElements(&_p_stStruct->stCptPos.stRefAxisZ, MTH_C_ZERO, MTH_C_ZERO, MTH_C_ONE);
|
|
}
|
|
/* Wanted position and move */
|
|
CAM_fn_vComputeRefAxis(_p_stStruct, &stDir);
|
|
MTH3D_M_vCopyVector(&_p_stStruct->stWantedCameraPos, &_p_stStruct->stCurrentCameraPos);
|
|
MTH3D_M_vNullVector(&_p_stStruct->stCptPos.stMovePos);
|
|
}
|
|
|
|
/*
|
|
* Else normal computing.
|
|
*/
|
|
else
|
|
{
|
|
/* Compute vector between old camera and new target */
|
|
MTH3D_M_vSubVector(&stCamTargetVector, &_p_stStruct->stCurrentCameraPos, &_p_stStruct->stTargetedPersoPos);
|
|
|
|
if
|
|
(
|
|
(stCamTargetVector.xX == _p_stStruct->stCptPos.stRefAxisZ.xX)
|
|
&& (stCamTargetVector.xY == _p_stStruct->stCptPos.stRefAxisZ.xY)
|
|
)
|
|
stCamTargetVector.xX += 0.5;
|
|
|
|
/* Compute new axis (super object direction or vector direction in cineinfo */
|
|
CAM_fn_vComputeRefAxis(_p_stStruct, &stDir);
|
|
|
|
/* Look if old axis is in ideal angle */
|
|
CAM_fn_vComputeCameraAxisAngles(_p_stStruct, &stDir, &stCamTargetVector, &xAlphaAngle, &xThetaAngle);
|
|
|
|
/* Rotate camera system with alpha and Theta angles */
|
|
CAM_fn_vRotateCameraAxis(&stDir, xAlphaAngle, xThetaAngle, &_p_stStruct->stCptPos.stRefAxisZ);
|
|
|
|
/* Compute actual distance (between old camera and new target) */
|
|
/*xNorm = MTH3D_M_xNormVector(&stCamTargetVector);*/
|
|
xNorm = MTH3D_M_xSqrVector(&stCamTargetVector);
|
|
|
|
/* Compute ideal distance */
|
|
xDistMin = _p_stStruct->hCineinfoWork->xDistMin;
|
|
xDistMax = _p_stStruct->hCineinfoWork->xDistMax;
|
|
|
|
/* Test norm */
|
|
if (MTH_M_bLess( xNorm, MTH_M_xSqr(xDistMin)))
|
|
xNorm = xDistMin;
|
|
else if (MTH_M_bGreater(xNorm, MTH_M_xSqr(xDistMax)))
|
|
xNorm = xDistMax;
|
|
else
|
|
xNorm = MTH_M_xSqrt(xNorm);
|
|
|
|
if (MTH_M_bLessEqual(xNorm, MTH_M_xFloatToReal(0.01f)))
|
|
xNorm = MTH_M_xFloatToReal(0.01f);
|
|
|
|
/*
|
|
* Compute new wanted camera position
|
|
*/
|
|
MTH3D_M_vMulScalarVector(&stDir, xNorm, &stDir);
|
|
|
|
MTH3D_M_vAddVector(&_p_stStruct->stWantedCameraPos, &_p_stStruct->stTargetedPersoPos, &stDir);
|
|
CAM_fn_vTakeCareOfCameraAltitude(_p_stStruct->hCineinfo, &_p_stStruct->stWantedCameraPos);
|
|
MTH3D_M_vSubVector(&_p_stStruct->stCptPos.stMovePos, &_p_stStruct->stWantedCameraPos, &_p_stStruct->stCurrentCameraPos);
|
|
}
|
|
}
|
|
|
|
/*
|
|
*=================================================================================================
|
|
* Compute move vector of camera with dynamic theta.
|
|
*=================================================================================================
|
|
*/
|
|
void CAM_fn_vComputeMovePosWithDynTheta(CAM_tdstUpdateCamera *_p_stStruct)
|
|
{
|
|
CAM_fn_vComputeMovePos(_p_stStruct);
|
|
if
|
|
(
|
|
(!((_p_stStruct)->hCineinfo->ucVolIAFlags & C_VolIAFlags_InitJustCopiedInCurrent))
|
|
&& ((_p_stStruct)->hCineinfoWork->hSuperObjectTargeted)
|
|
&& (!cNoDynChangeTheta)
|
|
)
|
|
{
|
|
if(CAM_fn_cDynChangeTheta(_p_stStruct, &_p_stStruct->stWantedCameraPos))
|
|
CAM_fn_vComputeMovePos(_p_stStruct);
|
|
}
|
|
}
|
|
|
|
/*
|
|
**************************************************************************************************
|
|
**************************************************************************************************
|
|
SPEED
|
|
**************************************************************************************************
|
|
**************************************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
*=================================================================================================
|
|
* Compute the speed and accel of the camera.
|
|
*=================================================================================================
|
|
*/
|
|
void CAM_fn_vComputeSpeed(CAM_tdstUpdateCamera *_p_stStruct)
|
|
{
|
|
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
|
MTH3D_tdstVector stTempVector, stTempVector1, stMoveTgt;
|
|
MTH_tdxReal xNorm, xAngle, xDot, xNorm2;
|
|
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
|
|
|
/*
|
|
* If no shift is set, this is a vis failure. We use dynamic speed with inertia
|
|
* of current cineinfo.
|
|
*/
|
|
/*
|
|
if
|
|
(
|
|
(_p_stStruct->hCineinfo->ucPerIAFlags & C_PerIAFlags_NoShift)
|
|
&& (_p_stStruct->hCineinfo->eState == CAM_e_State_GoToComputedOptimal)
|
|
)
|
|
{
|
|
_p_stStruct->hCineinfoWork->uwIAFlags |= C_IAFlags_NoDynSpeed;
|
|
_p_stStruct->hCineinfoWork->xLinearIncreaseSpeed = _p_stStruct->hCineinfoCurrent->xLinearIncreaseSpeed;
|
|
_p_stStruct->hCineinfoWork->xLinearDecreaseSpeed = _p_stStruct->hCineinfoCurrent->xLinearDecreaseSpeed;
|
|
_p_stStruct->hCineinfoWork->xAngularIncreaseSpeed = _p_stStruct->hCineinfoCurrent->xAngularIncreaseSpeed;
|
|
_p_stStruct->hCineinfoWork->xAngularDecreaseSpeed = _p_stStruct->hCineinfoCurrent->xAngularDecreaseSpeed;
|
|
_p_stStruct->hCineinfoWork->xTargetIncreaseSpeed = _p_stStruct->hCineinfoCurrent->xTargetIncreaseSpeed;
|
|
_p_stStruct->hCineinfoWork->xTargetDecreaseSpeed = _p_stStruct->hCineinfoCurrent->xTargetDecreaseSpeed;
|
|
}
|
|
*/
|
|
/*
|
|
* Speeds are the one of IA.
|
|
*/
|
|
if(_p_stStruct->hCineinfoWork->uwIAFlags & C_IAFlags_NoDynSpeed)
|
|
{
|
|
_p_stStruct->stCptPos.xLinearSpeed = _p_stStruct->hCineinfoWork->xLinearSpeed;
|
|
_p_stStruct->stCptPos.xAngularSpeed = _p_stStruct->hCineinfoWork->xAngularSpeed;
|
|
_p_stStruct->stCptPos.xTargetSpeed = _p_stStruct->hCineinfoWork->xTargetSpeed;
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Linear speed.
|
|
* Angular speed.
|
|
*/
|
|
if
|
|
(
|
|
(_p_stStruct->hCineinfoWork->uwIAFlags & C_IAFlags_PositionIsAlreadyComputed)
|
|
|| (_p_stStruct->hCineinfoWork->hSuperObjectTargeted == NULL)
|
|
)
|
|
{
|
|
_p_stStruct->stCptPos.xLinearSpeed = _p_stStruct->hCineinfoWork->xLinearSpeed;
|
|
_p_stStruct->stCptPos.xAngularSpeed = _p_stStruct->hCineinfoWork->xAngularSpeed;
|
|
}
|
|
else
|
|
{
|
|
/* LINEAR */
|
|
xNorm = MTH_C_ZERO;
|
|
if(!(_p_stStruct->hCineinfoWork->uwDNMFlags & DNM_CAM_C_NoLinearParsing))
|
|
{
|
|
MTH3D_M_vSubVector(&stTempVector, &_p_stStruct->stWantedCameraPos, &_p_stStruct->stCurrentCameraPos);
|
|
xNorm = MTH3D_M_xNormVector(&stTempVector);
|
|
|
|
xNorm = MTH_M_xMul(xNorm, CAM_C_xDynSpeed_LinearFactNorm);
|
|
if(MTH_M_bGreater(xNorm, CAM_C_xDynSpeed_LinearMax))
|
|
xNorm = CAM_C_xDynSpeed_LinearMax;
|
|
|
|
CAM_fn_bPersoIsMoving(_p_stStruct, &stTempVector);
|
|
xNorm2 = MTH3D_M_xNormVector(&stTempVector);
|
|
if(MTH_M_bLess(xNorm, MTH_M_xMul(xNorm2, CAM_C_xDynSpeed_LinearMulPerso)))
|
|
xNorm = MTH_M_xMul(xNorm2, CAM_C_xDynSpeed_LinearMulPerso);
|
|
}
|
|
_p_stStruct->stCptPos.xLinearSpeed = xNorm;
|
|
|
|
/* ANGULAR */
|
|
if(!(_p_stStruct->hCineinfoWork->uwDNMFlags & DNM_CAM_C_NoAngularParsing))
|
|
{
|
|
xNorm = MTH_C_ZERO;
|
|
MTH3D_M_vSubVector(&stTempVector, &_p_stStruct->stTargetedPersoPos, &_p_stStruct->stCurrentCameraPos);
|
|
if(!MTH3D_M_bIsNullVector(&stTempVector))
|
|
{
|
|
if (!MTH3D_M_bIsNullVector(&stTempVector))
|
|
MTH3D_M_vNormalizeVector(&stTempVector, &stTempVector);
|
|
MTH3D_M_vSubVector(&stTempVector1, &_p_stStruct->stTargetedPersoPos, &_p_stStruct->stWantedCameraPos);
|
|
if (!MTH3D_M_bIsNullVector(&stTempVector1))
|
|
MTH3D_M_vNormalizeVector(&stTempVector1, &stTempVector1);
|
|
xNorm = CAM_fn_xComputeRotation(&stTempVector, &stTempVector1, NULL);
|
|
}
|
|
|
|
xNorm = MTH_M_xMul(xNorm, CAM_C_xDynSpeed_AngularFactNorm);
|
|
if(MTH_M_bGreater(xNorm, CAM_C_xDynSpeed_AngularMax))
|
|
xNorm = CAM_C_xDynSpeed_AngularMax;
|
|
|
|
CAM_fn_bPersoIsTurning(_p_stStruct->hCineinfoWork->hSuperObjectTargeted, &xAngle);
|
|
if(MTH_M_bLess(xNorm, MTH_M_xMul(xAngle, CAM_C_xDynSpeed_AngularMulPerso)))
|
|
xNorm = xAngle;
|
|
|
|
/* Decrease speed depending on distance to target (regardless of ideal distance) */
|
|
xAngle = _p_stStruct->hCineinfoWork->xDistMin;
|
|
MTH3D_M_vSubVector(&stTempVector, &_p_stStruct->stTargetedPersoPos, &_p_stStruct->stCurrentCameraPos);
|
|
xAngle = MTH_M_xSub(xAngle, MTH3D_M_xNormVector(&stTempVector));
|
|
if(MTH_M_bGreater(xAngle, MTH_C_ONE))
|
|
xNorm = MTH_M_xDiv(xNorm, xAngle);
|
|
else if(MTH_M_bLess(xAngle, MTH_M_xNeg(MTH_C_ONE)))
|
|
xNorm = MTH_M_xMul(xNorm, MTH_M_xAbs(xAngle));
|
|
}
|
|
_p_stStruct->stCptPos.xAngularSpeed = xNorm;
|
|
}
|
|
|
|
/*
|
|
* Target speed.
|
|
*/
|
|
if
|
|
(
|
|
(_p_stStruct->hCineinfo->ucPerIAFlags & C_IAFlags_TargetIsAlreadyComputed)
|
|
|| (_p_stStruct->hCineinfoWork->hSuperObjectTargeted == NULL)
|
|
)
|
|
{
|
|
_p_stStruct->stCptPos.xTargetSpeed = _p_stStruct->hCineinfoWork->xTargetSpeed;
|
|
}
|
|
else
|
|
{
|
|
xNorm = MTH_C_ZERO;
|
|
MTH3D_M_vNullVector(&stMoveTgt);
|
|
if(!(_p_stStruct->hCineinfoWork->uwDNMFlags & DNM_CAM_C_NoTargetParsing))
|
|
{
|
|
MTH3D_M_vCopyVector(&stTempVector, DNM_M_p_stCPDGetTarget(fn_p_stDynamGetParsingDatas(M_GetMSHandle(_p_stStruct->hSuperObjCamera, Dynam))));
|
|
MTH3D_M_vSubVector
|
|
(
|
|
&stTempVector,
|
|
&_p_stStruct->stCptPos.stTarget,
|
|
&stTempVector
|
|
);
|
|
xNorm = MTH3D_M_xNormVector(&stTempVector);
|
|
MTH3D_M_vCopyVector(&stMoveTgt, &stTempVector);
|
|
}
|
|
|
|
xNorm = MTH_M_xMul(xNorm, CAM_C_xDynSpeed_TargetFactNorm);
|
|
if(MTH_M_bGreater(xNorm, CAM_C_xDynSpeed_TargetMax))
|
|
xNorm = CAM_C_xDynSpeed_TargetMax;
|
|
|
|
/* Norm must be greater than current perso speed */
|
|
CAM_fn_bPersoIsMoving(_p_stStruct, &stTempVector);
|
|
if(MTH_M_bLess(xNorm, MTH_M_xMul(MTH3D_M_xNormVector(&stTempVector), CAM_C_xDynSpeed_TargetMulPerso)))
|
|
xNorm = MTH_M_xMul(MTH3D_M_xNormVector(&stTempVector), CAM_C_xDynSpeed_TargetMulPerso);
|
|
|
|
_p_stStruct->stCptPos.xTargetSpeed = xNorm;
|
|
|
|
/*
|
|
* Modifs inertie.
|
|
*/
|
|
if((!MTH3D_M_bIsNullVector(&stMoveTgt)) && (!MTH3D_M_bIsNullVector(DNM_M_p_stReportGetLastTgtMove(_p_stStruct->p_stReport))))
|
|
{
|
|
xDot = MTH3D_M_xDotProductVector(&stMoveTgt, DNM_M_p_stReportGetLastTgtMove(_p_stStruct->p_stReport));
|
|
if(MTH_M_bLess(xDot, -0.9f))
|
|
{
|
|
_p_stStruct->hCineinfoWork->xTargetDecreaseSpeed = 40;
|
|
_p_stStruct->hCineinfoWork->xTargetIncreaseSpeed = 40;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
**************************************************************************************************
|
|
**************************************************************************************************
|
|
MOVE CONSTRAINT
|
|
**************************************************************************************************
|
|
**************************************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
*=================================================================================================
|
|
* Determin if it's not better to not move.
|
|
* This function is called to avoid camera to move on the same side where the visiblity failed a
|
|
* short time after the failure.
|
|
*=================================================================================================
|
|
*/
|
|
void CAM_fn_vConstraintMoveAfterVisFailure(CAM_tdstUpdateCamera *_p_stStruct)
|
|
{
|
|
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
|
MTH3D_tdstVector stTempVector, stTempVector1;
|
|
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
|
|
|
/*
|
|
* If perso is moving (relative to its father), projection of current moving camera pos to axe
|
|
* (lastfailed wanted - lastfailed origin).
|
|
*/
|
|
if((_p_stStruct->cTgtPersoIsMovingRelative) && (!(CONSTANT_NOVISPROJ)))
|
|
{
|
|
MTH3D_M_vSubVector(&stTempVector, &_p_stStruct->stWantedCameraPos, &_p_stStruct->hCineinfo->stLastFailedWanted);
|
|
MTH3D_M_vSubVector(&stTempVector1, &_p_stStruct->stTargetedPersoPos, &_p_stStruct->hCineinfo->stLastFailedWanted);
|
|
if((!MTH3D_M_bIsNullVector(&stTempVector)) && (!MTH3D_M_bIsNullVector(&stTempVector1)))
|
|
{
|
|
MTH3D_M_vNormalizeVector(&stTempVector1, &stTempVector1);
|
|
MTH3D_M_vMulScalarVector(&stTempVector, MTH3D_M_xDotProductVector(&stTempVector, &stTempVector1), &stTempVector1);
|
|
MTH3D_M_vAddVector(&stTempVector, &stTempVector, &_p_stStruct->hCineinfo->stLastFailedWanted);
|
|
}
|
|
else
|
|
{
|
|
MTH3D_M_vCopyVector(&stTempVector, &_p_stStruct->hCineinfo->stLastFailedWanted);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Previous wanted position became the new ideal one (so camera will go to the position computed just
|
|
* after the failure).
|
|
*/
|
|
else
|
|
{
|
|
MTH3D_M_vCopyVector(&stTempVector, &_p_stStruct->hCineinfo->stLastFailedWanted);
|
|
}
|
|
|
|
/*
|
|
* stTempVector is the position we want to go now. We compute movepos and we set Cineinfo current
|
|
* to be at this new position.
|
|
*/
|
|
MTH3D_M_vSubVector(&_p_stStruct->stCptPos.stMovePos, &stTempVector, &_p_stStruct->stCurrentCameraPos);
|
|
MTH3D_M_vCopyVector(&_p_stStruct->stWantedCameraPos, &stTempVector);
|
|
CAM_fn_vComputeCineinfoCurrentForAPosition(_p_stStruct, &stTempVector);
|
|
|
|
MTH3D_M_vCopyVector(&_p_stStruct->hCineinfo->stLastFailedWanted, &_p_stStruct->stWantedCameraPos);
|
|
}
|
|
|
|
/*
|
|
*=================================================================================================
|
|
* Test a position with an angle.
|
|
*=================================================================================================
|
|
*/
|
|
char CAM_fn_cConstraintMoveCutTestAngle(CAM_tdstUpdateCamera *_p_stStruct, MTH_tdxReal _xAngle)
|
|
{
|
|
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
|
struct tdstInternalStructurCineinfo_ stTemp;
|
|
CAM_tdstUpdateCamera stStruct;
|
|
char cMode;
|
|
MTH3D_tdstVector stTempVector, stTempVector1;
|
|
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
|
|
|
/*
|
|
* A temporary structure just for our compute.
|
|
*/
|
|
memcpy(&stTemp, _p_stStruct->hCineinfoWork, sizeof(struct tdstInternalStructurCineinfo_));
|
|
stTemp.xAngleAlpha = _xAngle;
|
|
CAM_fn_vInitCameraStructure(_p_stStruct->hSuperObjCamera, &stStruct);
|
|
stStruct.hCineinfoWork = &stTemp;
|
|
|
|
/*
|
|
* Compute move and wanted position to take care of cut angles.
|
|
*/
|
|
CAM_fn_vComputeReferencePoint(&stStruct);
|
|
CAM_fn_vComputeMovePosWithDynTheta(&stStruct);
|
|
|
|
/*
|
|
* If cJustBetterPos is set, we must not go to the sens of the last visibility failure.
|
|
*/
|
|
if(cJustBetterPos)
|
|
{
|
|
MTH3D_M_vSubVector(&stTempVector, &_p_stStruct->hCineinfo->stLastFailedOrigin, &_p_stStruct->stCurrentCameraPos);
|
|
MTH3D_M_vSubVector(&stTempVector1, &_p_stStruct->hCineinfo->stLastFailedOrigin, &stStruct.stWantedCameraPos);
|
|
if(MTH_M_bGreater(MTH3D_M_xNormVector(&stTempVector), MTH3D_M_xNormVector(&stTempVector1)))
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Test if position is correct. If not, requested move is not change.
|
|
*/
|
|
cMode = 0;
|
|
if
|
|
(
|
|
(_p_stStruct->hCineinfo->ucPerIAFlags & C_PerIAFlags_NoShift)
|
|
&& (_p_stStruct->hCineinfo->eState == CAM_e_State_GoToComputedOptimal)
|
|
)
|
|
{
|
|
cMode = C_mode_MUSTGO|C_mode_MUSTSEE;
|
|
if(_p_stStruct->hCineinfoWork->uwIAFlags & C_IAFlags_NoVisibility)
|
|
cMode &= ~C_mode_MUSTSEE;
|
|
}
|
|
if
|
|
(
|
|
CAM_fn_cIsWantedPosIncorrect
|
|
(
|
|
&stStruct,
|
|
&stStruct.stWantedCameraPos,
|
|
cMode
|
|
)
|
|
)
|
|
return 0;
|
|
|
|
/*
|
|
* Else we change the position to take care of the cutted angle.
|
|
*/
|
|
MTH3D_M_vCopyVector(&_p_stStruct->stWantedCameraPos, &stStruct.stWantedCameraPos);
|
|
MTH3D_M_vCopyVector(&_p_stStruct->stCptPos.stMovePos, &stStruct.stCptPos.stMovePos);
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
*=================================================================================================
|
|
* Function do inverse cut angle (other sens).
|
|
*=================================================================================================
|
|
*/
|
|
MTH_tdxReal CAM_fn_xOppositeAngle(CAM_tdstUpdateCamera *_p_stStruct)
|
|
{
|
|
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
|
MTH_tdxReal xNewAngle;
|
|
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
|
|
|
xNewAngle = MTH_M_xMul(CAM_C_xBaseCutAngle, MTH_M_xFloatToReal(2.0f));
|
|
if(MTH_M_bGreater(_p_stStruct->xAngleDeltaAlphaCut, MTH_C_ZERO))
|
|
xNewAngle = MTH_M_xNeg(xNewAngle);
|
|
xNewAngle = MTH_M_xAdd(_p_stStruct->xAngleAlphaCut, xNewAngle);
|
|
xNewAngle = CAM_fn_xSetAngleInInterval02Pi(xNewAngle);
|
|
return xNewAngle;
|
|
}
|
|
|
|
/*
|
|
*=================================================================================================
|
|
* Camera will go to near from targeted perso. Try to go elsewhere.
|
|
*=================================================================================================
|
|
*/
|
|
void CAM_fn_vConstraintMoveCutAngles(CAM_tdstUpdateCamera *_p_stStruct)
|
|
{
|
|
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
|
MTH_tdxReal xNewAngle;
|
|
char cWantedSens;
|
|
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
|
|
|
/*
|
|
* If -2, the last sens is not a sens, and in fact we don't want to cut.
|
|
*/
|
|
if(_p_stStruct->hCineinfo->cLastCutAngleSens == -2)
|
|
return;
|
|
|
|
if(DNM_M_bReportCollision(_p_stStruct->p_stReport) && (!(CONSTANT_CUT_COL)))
|
|
{
|
|
_p_stStruct->hCineinfo->cLastCutAngleSens = -2;
|
|
return;
|
|
}
|
|
|
|
if
|
|
(
|
|
(MTH_M_bLess(MTH_M_xMul(_p_stStruct->hCineinfo->xLastDeltaCut, _p_stStruct->xAngleDeltaAlphaCut), MTH_C_ZERO))
|
|
&& (MTH_M_bLess(MTH_M_xAbs(_p_stStruct->xAngleDeltaAlphaCut), MTH_M_xSub(MTH_C_Pi, CAM_C_xBaseCutAngle)))
|
|
)
|
|
{
|
|
_p_stStruct->hCineinfo->cLastCutAngleSens = 0;
|
|
}
|
|
|
|
/*
|
|
* Save current delta.
|
|
*/
|
|
if(_p_stStruct->hCineinfo->cLastCutAngleSens == 0)
|
|
_p_stStruct->hCineinfo->xLastDeltaCut = _p_stStruct->xAngleDeltaAlphaCut;
|
|
|
|
/*
|
|
* There's a problem to know in which sens the cut angle will work.
|
|
* We force cut angle to go in sens defined by _p_stStruct->hCineinfo->cLastCutAngleSens.
|
|
* If it is equal to 0, we can test in the normal sens, and in opposite one if we want
|
|
* to go to a position at the opposite of current one.
|
|
*/
|
|
|
|
xNewAngle = _p_stStruct->xAngleAlphaCut;
|
|
if((_p_stStruct->hCineinfo->cLastCutAngleSens == -1) && (MTH_M_bGreater(_p_stStruct->xAngleDeltaAlphaCut, MTH_C_ZERO)))
|
|
xNewAngle = CAM_fn_xOppositeAngle(_p_stStruct);
|
|
if((_p_stStruct->hCineinfo->cLastCutAngleSens == 1) && (MTH_M_bLess(_p_stStruct->xAngleDeltaAlphaCut, MTH_C_ZERO)))
|
|
xNewAngle = CAM_fn_xOppositeAngle(_p_stStruct);
|
|
|
|
if(CAM_fn_cConstraintMoveCutTestAngle(_p_stStruct, xNewAngle))
|
|
{
|
|
cWantedSens = _p_stStruct->hCineinfo->cLastCutAngleSens;
|
|
if(cWantedSens == 0)
|
|
{
|
|
/* Force next cut angle to work in the same sens than this one */
|
|
if(MTH_M_bGreater(_p_stStruct->xAngleDeltaAlphaCut, MTH_C_ZERO))
|
|
_p_stStruct->hCineinfo->cLastCutAngleSens = 1;
|
|
else
|
|
_p_stStruct->hCineinfo->cLastCutAngleSens = -1;
|
|
}
|
|
return;
|
|
}
|
|
|
|
if(_p_stStruct->hCineinfo->cLastCutAngleSens == 0)
|
|
{
|
|
if(MTH_M_bGreaterEqual(MTH_M_xAbs(_p_stStruct->xAngleDeltaAlphaCut), MTH_M_xSub(MTH_C_Pi, CAM_C_xBaseCutAngle)))
|
|
{
|
|
xNewAngle = CAM_fn_xOppositeAngle(_p_stStruct);
|
|
if(CAM_fn_cConstraintMoveCutTestAngle(_p_stStruct, xNewAngle))
|
|
{
|
|
/* Force next cut angle to work in the same sens than this one */
|
|
if(MTH_M_bGreater(_p_stStruct->xAngleDeltaAlphaCut, MTH_C_ZERO))
|
|
_p_stStruct->hCineinfo->cLastCutAngleSens = -1;
|
|
else
|
|
_p_stStruct->hCineinfo->cLastCutAngleSens = 1;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* To say that we don't want to cut angle anymore */
|
|
_p_stStruct->hCineinfo->cLastCutAngleSens = -2;
|
|
}
|
|
|
|
/*
|
|
*=================================================================================================
|
|
* Is it better not to move ?
|
|
*=================================================================================================
|
|
*/
|
|
void CAM_fn_vConstraintNoMove(CAM_tdstUpdateCamera *_p_stStruct, MTH3D_tdstVector *_p_stWanted)
|
|
{
|
|
#if 0
|
|
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
|
MTH3D_tdstVector stTempVector;
|
|
MTH_tdxReal xCurPound, xWantPound;
|
|
char cMode;
|
|
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
|
|
|
MTH3D_M_vSubVector(&stTempVector, &_p_stStruct->stCurrentCameraPos, &_p_stStruct->stTargetedPersoPos);
|
|
xCurPound = CAM_fnx_ComputePosPound(_p_stStruct, &stTempVector);
|
|
MTH3D_M_vSubVector(&stTempVector, _p_stWanted, &_p_stStruct->stTargetedPersoPos);
|
|
xWantPound = CAM_fnx_ComputePosPound(_p_stStruct, &stTempVector);
|
|
if(MTH_M_bLess(xCurPound, xWantPound))
|
|
{
|
|
cMode = C_mode_MUSTSEE;
|
|
if(_p_stStruct->hCineinfoWork->uwIAFlags & C_IAFlags_NoVisibility)
|
|
cMode &= ~C_mode_MUSTSEE;
|
|
if(!CAM_fn_cIsWantedPosIncorrect(_p_stStruct, &_p_stStruct->stCurrentCameraPos, cMode))
|
|
{
|
|
MTH3D_M_vCopyVector(&_p_stStruct->stWantedCameraPos, &_p_stStruct->stCurrentCameraPos);
|
|
MTH3D_M_vNullVector(&_p_stStruct->stCptPos.stMovePos);
|
|
CAM_fn_vComputeCineinfoCurrentForAPosition(_p_stStruct, &_p_stStruct->stCurrentCameraPos);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
*=================================================================================================
|
|
* If camera has no moved, and we want to go to the same position than previous one, force
|
|
* move pos to be NULL.
|
|
*=================================================================================================
|
|
*/
|
|
void CAM_fn_vConstraintMove(CAM_tdstUpdateCamera *_p_stStruct)
|
|
{
|
|
/*
|
|
* No constraint the first trame, and if we have force the position.
|
|
*/
|
|
if
|
|
(
|
|
(_p_stStruct->hCineinfo->ucVolIAFlags & C_VolIAFlags_InitJustCopiedInCurrent)
|
|
|| (_p_stStruct->hCineinfoWork->uwIAFlags & C_IAFlags_PositionIsAlreadyComputed)
|
|
|| (_p_stStruct->hCineinfoWork->hSuperObjectTargeted == NULL)
|
|
)
|
|
return;
|
|
|
|
/*
|
|
* Determin if we can reset last failed wanted.
|
|
*/
|
|
if(CAM_fn_cCanResetConstraintMoveVisFailure(_p_stStruct, &_p_stStruct->stWantedCameraPos))
|
|
{
|
|
_p_stStruct->hCineinfo->ucPerIAFlags &= ~C_PerIAFlags_ConstraintMoveVisFailure;
|
|
}
|
|
|
|
/*
|
|
* Constraint cause of a special mode.
|
|
*/
|
|
if(_p_stStruct->hCineinfo->ucPerIAFlags & C_PerIAFlags_ConstraintMoveVisFailure)
|
|
{
|
|
CAM_fn_vConstraintMoveAfterVisFailure(_p_stStruct);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* If we have cut angle, we try to go to the position defined by the cutted angles.
|
|
* If we don't want to cut angle, we reset the last sens of cutting.
|
|
*/
|
|
if
|
|
(
|
|
(_p_stStruct->cHasCutAlpha)
|
|
&& (!(_p_stStruct->hCineinfoWork->uwIAFlags & C_IAFlags_NoParseCutAngle))
|
|
)
|
|
{
|
|
CAM_fn_vConstraintMoveCutAngles(_p_stStruct);
|
|
}
|
|
else
|
|
{
|
|
_p_stStruct->hCineinfo->cLastCutAngleSens = 0;
|
|
}
|
|
|
|
/*
|
|
* Force camera to stay in place if it is not moved
|
|
*/
|
|
if(_p_stStruct->hCineinfo->eState == CAM_e_State_GoToComputedOptimal)
|
|
{
|
|
CAM_fn_vConstraintNoMove(_p_stStruct, &_p_stStruct->stWantedCameraPos);
|
|
}
|
|
}
|
|
|
|
/*
|
|
*=================================================================================================
|
|
* Take care of targeted perso father.
|
|
*=================================================================================================
|
|
*/
|
|
void CAM_fn_vTakeCareOfFather(CAM_tdstUpdateCamera *_p_stStruct)
|
|
{
|
|
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
|
/* MS_tdxHandleToDynam h_Dynam;*/
|
|
/* DNM_tdstDynamics *p_stDynamics;*/
|
|
HIE_tdxHandleToSuperObject hFather;
|
|
/* POS_tdstCompletePosition stMatrix;*/
|
|
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
|
|
|
hFather = CAM_fn_hGetFather(_p_stStruct->hCineinfoWork->hSuperObjectTargeted);
|
|
/* if(hFather == NULL)*/
|
|
/* return;*/
|
|
/* h_Dynam = M_GetMSHandle(hFather, Dynam);*/
|
|
/* if(h_Dynam == NULL)*/
|
|
/* return;*/
|
|
/* p_stDynamics = fn_p_stDynamGetDynamics(h_Dynam); */
|
|
/* if(p_stDynamics == NULL)*/
|
|
/* return;*/
|
|
|
|
/* POS_fn_vInvertMatrix(&stMatrix, DNM_M_p_stDynamicsGetPrevPreviousMatrix(p_stDynamics));*/
|
|
/* POS_fn_vMulMatrixMatrix(&stMatrix, DNM_M_p_stDynamicsGetPreviousMatrix(p_stDynamics), &stMatrix);*/
|
|
|
|
/* POS_fn_vMulMatrixVertex(&_p_stStruct->hCineinfo->stLastFailedWanted, &stMatrix, &_p_stStruct->hCineinfo->stLastFailedWanted);*/
|
|
/* POS_fn_vMulMatrixVertex(&_p_stStruct->hCineinfo->stLastFailedOrigin, &stMatrix, &_p_stStruct->hCineinfo->stLastFailedOrigin);*/
|
|
}
|
|
|
|
|
|
/*
|
|
**************************************************************************************************
|
|
**************************************************************************************************
|
|
GENERAL MANAGMENT
|
|
**************************************************************************************************
|
|
**************************************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
*=================================================================================================
|
|
* Main camera function.
|
|
*=================================================================================================
|
|
*/
|
|
void CAM_fn_vUpdateGeneralCamera(CAM_tdstUpdateCamera *_p_stStruct)
|
|
{
|
|
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
|
MTH3D_tdstVector stMoveVector;
|
|
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
|
|
|
recom: /* C'est ignoble, mais j'assume */
|
|
|
|
cCanTestStatic = 1;
|
|
|
|
/*
|
|
**********************************************************************************************
|
|
**********************************************************************************************
|
|
*/
|
|
|
|
/*
|
|
* Take care of father to change last computed positions.
|
|
*/
|
|
CAM_fn_vTakeCareOfFather(_p_stStruct);
|
|
|
|
/*
|
|
**********************************************************************************************
|
|
**********************************************************************************************
|
|
*/
|
|
|
|
/*
|
|
* Test if camera is moving. wCounter4 is increased each time camera is not moving, and
|
|
* reset to 0 else.
|
|
*/
|
|
MTH3D_M_vCopyVector(&stMoveVector, DNM_M_p_stReportGetLastMove(_p_stStruct->p_stReport));
|
|
if(MTH_M_bLess(MTH3D_M_xNormVector(&stMoveVector), CAM_C_xMinLinearSpeedCamera))
|
|
{
|
|
|
|
_p_stStruct->hCineinfo->ucVolIAFlags |= C_VolIAFlags_CameraNotMove;
|
|
/*
|
|
* We don't increase wCounter4 if it's greater than CAM_C_xTickFindBetterPosIfNoMove.
|
|
*/
|
|
|
|
/* ANNECY MT - 03/08/99 { */
|
|
/*
|
|
if(_p_stStruct->hCineinfo->wCounter4 < CAM_C_xTickFindBetterPosIfNoMove)
|
|
{
|
|
_p_stStruct->hCineinfo->wCounter4++;
|
|
}
|
|
*/
|
|
if(MTH_M_bLess(_p_stStruct->hCineinfo->xCounter4,CAM_C_xTickTimeFindBetterPosIfNoMove))
|
|
{
|
|
_p_stStruct->hCineinfo->xCounter4 = MTH_M_xAdd(_p_stStruct->hCineinfo->xCounter4,MTH_M_xFloatToReal(g_stEngineStructure.stEngineTimer.ulUsefulDeltaTime));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*_p_stStruct->hCineinfo->wCounter4 = 0; */
|
|
_p_stStruct->hCineinfo->xCounter4 = MTH_C_ZERO;
|
|
}
|
|
/* END ANNECY MT } */
|
|
|
|
/*
|
|
* Special case in flying mode. Force some values.
|
|
*/
|
|
if (g_ucIsEdInGhostMode)
|
|
{
|
|
CAM_fn_vInitCompleteCineinfo(_p_stStruct->hCineinfo);
|
|
memcpy(_p_stStruct->hCineinfo->hWork, _p_stStruct->hCineinfo->hCurrent, sizeof(struct tdstInternalStructurCineinfo_));
|
|
_p_stStruct->hCineinfoWork->xDistMin = MTH_M_xFloatToReal(2.0f);
|
|
_p_stStruct->hCineinfoWork->xDistMax = MTH_M_xFloatToReal(2.0f);
|
|
_p_stStruct->hCineinfoWork->xAngleAlpha = MTH_C_ZERO;
|
|
_p_stStruct->hCineinfoWork->xAngleShiftAlpha = MTH_C_ZERO;
|
|
_p_stStruct->hCineinfoWork->xAngleTheta = MTH_C_ZERO;
|
|
_p_stStruct->hCineinfoWork->xAngleShiftTheta = MTH_C_ZERO;
|
|
_p_stStruct->hCineinfoWork->uwDNMFlags = DNM_CAM_C_NoLinearParsing|DNM_CAM_C_NoAngularParsing|DNM_CAM_C_NoTargetParsing|DNM_CAM_C_NoObstacle;
|
|
_p_stStruct->hCineinfoWork->uwIAFlags = C_IAFlags_NoVisibility|C_IAFlags_NoAverageMoveTgtPerso;
|
|
_p_stStruct->hCineinfo->ucPerIAFlags = 0;
|
|
_p_stStruct->hCineinfo->ucVolIAFlags = 0;
|
|
_p_stStruct->hCineinfo->eState = CAM_e_TempState_GhostMode;
|
|
}
|
|
|
|
/*
|
|
* Camera for cinematic scenary.
|
|
*/
|
|
if
|
|
(
|
|
(_p_stStruct->hCineinfoWork->hSuperObjectTargeted)
|
|
&& (_p_stStruct->hCineinfoWork->hSecondSuperObjectTargeted)
|
|
)
|
|
{
|
|
_p_stStruct->hCineinfo->ucPerIAFlags &= ~C_PerIAFlags_ConstraintMoveVisFailure;
|
|
_p_stStruct->hCineinfoWork->uwIAFlags |= C_IAFlags_NoVisibility;
|
|
_p_stStruct->hCineinfo->eState = CAM_e_TempState_ApexMode;
|
|
}
|
|
|
|
/*
|
|
**********************************************************************************************
|
|
* General.
|
|
**********************************************************************************************
|
|
*/
|
|
|
|
/*
|
|
* Every moving compute must take care of current axis requested. Even if make a position
|
|
* compute with a cineinfo without that flag, we must in fact compute the position with that
|
|
* flag (it determins the actual reference axis to compute all the positions).
|
|
* This is a global variable, so the computerefaxis will don't care of cineinfowork defined
|
|
* in the structure passed to it (look at the function...).
|
|
*
|
|
* The same for dyntheta.
|
|
*/
|
|
cRefAxisIsAlreadyComputed = _p_stStruct->hCineinfoWork->uwIAFlags & C_IAFlags_RefAxisIsAlreadyComputed ? 1 : 0;
|
|
cNoDynChangeTheta = _p_stStruct->hCineinfoWork->uwIAFlags & C_IAFlags_NoDynChangeTheta ? 1 : 0;
|
|
|
|
/*
|
|
* - Compute position of targeted perso
|
|
* - Compute target
|
|
* - Compute the real IA wanted position.
|
|
*/
|
|
CAM_fn_vComputeReferencePoint(_p_stStruct);
|
|
CAM_fn_vComputeTarget(_p_stStruct);
|
|
CAM_fn_vComputeRealWantedPos(_p_stStruct);
|
|
|
|
/*
|
|
* Compute camera move.
|
|
*/
|
|
CAM_fn_vComputeMovePos(_p_stStruct);
|
|
|
|
if
|
|
(
|
|
(!((_p_stStruct)->hCineinfo->ucVolIAFlags & C_VolIAFlags_InitJustCopiedInCurrent))
|
|
&& ((_p_stStruct)->hCineinfoWork->hSuperObjectTargeted)
|
|
&& (!cNoDynChangeTheta)
|
|
&& (!(_p_stStruct->hCineinfo->ucPerIAFlags & C_PerIAFlags_ConstraintMoveVisFailure))
|
|
&& (!(_p_stStruct->hCineinfoWork->uwIAFlags & C_IAFlags_PositionIsAlreadyComputed))
|
|
)
|
|
{
|
|
if(CAM_fn_cDynChangeTheta(_p_stStruct, &_p_stStruct->stWantedCameraPos))
|
|
CAM_fn_vComputeMovePos(_p_stStruct);
|
|
}
|
|
|
|
/*
|
|
* Test if we can restore initial shift alpha and theta.
|
|
* When camera is to current wanted camera pos, we can restore.
|
|
*/
|
|
if
|
|
(
|
|
(_p_stStruct->hCineinfo->ucPerIAFlags & C_PerIAFlags_NoShift)
|
|
|| (_p_stStruct->hCineinfoWork->uwIAFlags & C_IAFlags_NoShiftUntilPosReached)
|
|
)
|
|
{
|
|
if
|
|
(
|
|
(_p_stStruct->hCineinfoWork->uwIAFlags & C_IAFlags_TargetIsAlreadyComputed)
|
|
|| (_p_stStruct->hCineinfoWork->uwIAFlags & C_IAFlags_PositionIsAlreadyComputed)
|
|
|| (_p_stStruct->hCineinfo->ucVolIAFlags & C_VolIAFlags_InitJustCopiedInCurrent)
|
|
|| CAM_fn_bEqualVectorWithEpsilon
|
|
(
|
|
&_p_stStruct->stCurrentCameraPos,
|
|
&_p_stStruct->stWantedCameraPos,
|
|
CAM_C_xEpsilonForEqualVectors
|
|
)
|
|
)
|
|
{
|
|
_p_stStruct->hCineinfoCurrent->uwIAFlags &= ~C_IAFlags_NoShiftUntilPosReached;
|
|
_p_stStruct->hCineinfoWork->uwIAFlags &= ~C_IAFlags_NoShiftUntilPosReached;
|
|
_p_stStruct->hCineinfo->ucPerIAFlags &= ~C_PerIAFlags_NoShift;
|
|
_p_stStruct->hCineinfo->cLastCutAngleSens = 0;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* If current is the same as wanted, force normal state.
|
|
*/
|
|
if
|
|
(
|
|
(CONSTANT_NORMALIFJOIN)
|
|
&& (_p_stStruct->hCineinfo->eState == CAM_e_State_GoToComputedOptimal)
|
|
&& (_p_stStruct->cTgtPersoIsMovingRelative)
|
|
)
|
|
{
|
|
if
|
|
(
|
|
CAM_fn_bEqualVectorWithEpsilon
|
|
(
|
|
&_p_stStruct->stCurrentCameraPos,
|
|
&_p_stStruct->stWantedCameraPos,
|
|
CAM_C_xEpsilonForEqualVectors
|
|
)
|
|
)
|
|
{
|
|
if (_p_stStruct->hCineinfo->ucPerIAFlags & C_PerIAFlags_VisibilityCopied)
|
|
CAM_fn_vSetCineinfoCurrentFromVisibility(_p_stStruct->hCineinfo);
|
|
_p_stStruct->hCineinfo->ucPerIAFlags &= ~C_PerIAFlags_ConstraintMoveVisFailure;
|
|
_p_stStruct->hCineinfo->ucVolIAFlags &= ~C_VolIAFlags_CurrentAlreadyCopiedInWork;
|
|
_p_stStruct->hCineinfo->eState = CAM_e_State_GoToOptimal;
|
|
|
|
goto recom;
|
|
}
|
|
}
|
|
|
|
/*
|
|
**********************************************************************************************
|
|
* Process the states.
|
|
**********************************************************************************************
|
|
*/
|
|
|
|
/*
|
|
* Some functions can change the current state to be in failure
|
|
*--------------------------------------------------------------
|
|
*/
|
|
switch(_p_stStruct->hCineinfo->eState)
|
|
{
|
|
/*
|
|
* - If target is not seen.
|
|
* - If camera distance is too near from target.
|
|
* - If collision is oppsition to current move.
|
|
*/
|
|
case CAM_e_State_GoToOptimal:
|
|
case CAM_e_State_GoToComputedOptimal:
|
|
|
|
CAM_fn_vTestBadVisibility(_p_stStruct);
|
|
CAM_fn_vTestBadDistance(_p_stStruct);
|
|
CAM_fn_vTestOppositeCollision(_p_stStruct);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* Process of each state.
|
|
*-----------------------
|
|
*/
|
|
switch(_p_stStruct->hCineinfo->eState)
|
|
{
|
|
/*
|
|
* We want to go to the optimal position defined in the MS with all the
|
|
* camera parameters.
|
|
*=========================================================================================
|
|
*/
|
|
case CAM_e_State_GoToOptimal:
|
|
|
|
CAM_fn_vConstraintMove(_p_stStruct);
|
|
break;
|
|
|
|
case CAM_e_State_GoToComputedOptimal:
|
|
|
|
CAM_fn_vCheckForABetterPos(_p_stStruct);
|
|
CAM_fn_vConstraintMove(_p_stStruct);
|
|
break;
|
|
|
|
/*
|
|
* Camera failure with visibility.
|
|
*=========================================================================================
|
|
*/
|
|
case CAM_e_State_FailureVisibility:
|
|
CAM_fn_vComputeFailureVisibility(_p_stStruct);
|
|
break;
|
|
|
|
/*
|
|
* Apex mode.
|
|
*=========================================================================================
|
|
*/
|
|
|
|
case CAM_e_TempState_ApexMode:
|
|
|
|
_p_stStruct->hCineinfo->eState = CAM_e_State_GoToOptimal;
|
|
break;
|
|
|
|
/*
|
|
* Ghost mode.
|
|
*=========================================================================================
|
|
*/
|
|
case CAM_e_TempState_GhostMode:
|
|
|
|
_p_stStruct->hCineinfo->eState = CAM_e_State_GoToOptimal;
|
|
break;
|
|
|
|
/* XB 05/05/99 */
|
|
default:
|
|
break;
|
|
/* End XB 05/05/99 */
|
|
}
|
|
|
|
/*
|
|
* Some update at the end.
|
|
*-------------------------
|
|
*/
|
|
|
|
/* Compute speed of camera */
|
|
CAM_fn_vComputeSpeed(_p_stStruct);
|
|
|
|
/* Reset values for visibility */
|
|
if
|
|
(
|
|
(_p_stStruct->hCineinfoWork->uwIAFlags & C_IAFlags_TargetIsAlreadyComputed)
|
|
|| (_p_stStruct->hCineinfoWork->uwIAFlags & C_IAFlags_PositionIsAlreadyComputed)
|
|
|| (_p_stStruct->hCineinfo->ucVolIAFlags & C_VolIAFlags_InitJustCopiedInCurrent)
|
|
|| (_p_stStruct->hCineinfo->eState == CAM_e_State_GoToOptimal)
|
|
)
|
|
{
|
|
MTH3D_M_vNullVector(&_p_stStruct->hCineinfo->stLastFailedOrigin);
|
|
MTH3D_M_vNullVector(&_p_stStruct->hCineinfo->stLastFailedWanted);
|
|
/* 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 } */
|
|
_p_stStruct->hCineinfo->ucPerIAFlags &= ~C_PerIAFlags_ConstraintMoveVisFailure;
|
|
}
|
|
|
|
/* Valid for one trame only */
|
|
cJustBetterPos = 0;
|
|
}
|