/* ************************************************************************************************** * 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; }