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