// // camera/CamInterface.cpp // // Copyright (C) 1999-2013 Rockstar Games. All Rights Reserved. // #include "camera/CamInterface.h" #include "profile/group.h" #include "profile/page.h" #include "system/param.h" #include "fwsys/timer.h" #include "camera/animscene/AnimSceneDirector.h" #include "camera/cinematic/CinematicDirector.h" #include "camera/cinematic/camera/mounted/CinematicMountedCamera.h" #include "camera/cinematic/context/CinematicOnFootSpectatingContext.h" #include "camera/cutscene/CutsceneDirector.h" #include "camera/debug/DebugDirector.h" #include "camera/gameplay/GameplayDirector.h" #include "camera/gameplay/follow/FollowCamera.h" #include "camera/gameplay/aim/FirstPersonAimCamera.h" #include "camera/gameplay/aim/FirstPersonShooterCamera.h" #include "camera/gameplay/aim/ThirdPersonPedAssistedAimCamera.h" #include "camera/helpers/FramePropagator.h" #include "camera/helpers/switch/BaseSwitchHelper.h" #include "camera/marketing/MarketingDirector.h" #include "camera/replay/ReplayDirector.h" #include "camera/scripted/ScriptDirector.h" #include "camera/scripted/ScriptedCamera.h" #include "camera/switch/SwitchDirector.h" #include "camera/syncedscene/SyncedSceneDirector.h" #include "camera/system/CameraManager.h" #include "camera/system/CameraMetadata.h" #include "camera/viewports/ViewportManager.h" #include "Control/replay/replay.h" #include "debug/DebugScene.h" #include "frontend/LoadingScreens.h" #include "game/ModelIndices.h" #include "network/Network.h" #include "network/NetworkInterface.h" #include "peds/PedIntelligence.h" #include "physics/gtaInst.h" #include "physics/physics.h" #include "scene/EntityIterator.h" #include "scene/FocusEntity.h" #include "scene/world/GameWorld.h" #include "streaming/streamingvisualize.h" #include "system/controlMgr.h" #include "text/messages.h" #include "tools/SectorTools.h" #include "vehicles/Metadata/VehicleEntryPointInfo.h" #include "peds/ped.h" #include "vehicles/vehicle.h" CAMERA_OPTIMISATIONS() XPARAM(cameraWidgets); RAGE_DEFINE_CHANNEL(camera) PF_PAGE(camInterfacePage, "Camera Interface"); PF_GROUP(camInterfaceFrameDetails); PF_LINK(camInterfacePage, camInterfaceFrameDetails); PF_VALUE_FLOAT(camInterfaceFrameVelocityMag, camInterfaceFrameDetails); PF_VALUE_FLOAT(camInterfaceFrameAccelerationMag, camInterfaceFrameDetails); PF_VALUE_FLOAT(camInterfaceFrameRateOfChangeOfAccelerationMag, camInterfaceFrameDetails); PF_VALUE_FLOAT(camInterfaceFrameAngularVelocityMag, camInterfaceFrameDetails); PF_VALUE_FLOAT(camInterfaceFov, camInterfaceFrameDetails); #define FIND_DIRECTOR_FATAL(_DirectorClass, _DirectorMember, _DirectorFriendlyName) \ { _DirectorMember = camManager::FindDirector<_DirectorClass>(); \ cameraFatalAssertf(_DirectorMember.Get() != NULL, "The " _DirectorFriendlyName \ " camera director was not found in the camera metadata." \ " Please check you have up-to-date camera metadata PSOs or an up-to-date .meta file if you are running with -rawCameraMetadata"); } #define GET_DIRECTOR_FATAL(_DirectorClass, _DirectorMember, _DirectorFriendlyName) \ { cameraFatalAssertf(_DirectorMember.Get() != NULL, "The " _DirectorFriendlyName " camera director is invalid"); \ return *((_DirectorClass*)_DirectorMember.Get()); } CViewportFader camInterface::ms_Fader; camFrame camInterface::ms_CachedFrame; #if GTA_REPLAY RegdConstEnt camInterface::ms_CachedAttachedEntity; #endif Vector3 camInterface::ms_FramePositionDelta; Vector3 camInterface::ms_FrameVelocity; Vector3 camInterface::ms_FrameAcceleration; Vector3 camInterface::ms_FrameRateOfChangeOfAcceleration; RegdCamBaseDirector camInterface::ms_CinematicDirector; RegdCamBaseDirector camInterface::ms_CutsceneDirector; RegdCamBaseDirector camInterface::ms_DebugDirector; RegdCamBaseDirector camInterface::ms_GameplayDirector; RegdCamBaseDirector camInterface::ms_MarketingDirector; RegdCamBaseDirector camInterface::ms_ScriptDirector; RegdCamBaseDirector camInterface::ms_SwitchDirector; RegdCamBaseDirector camInterface::ms_ReplayDirector; RegdCamBaseDirector camInterface::ms_SyncedSceneDirector; RegdCamBaseDirector camInterface::ms_AnimSceneDirector; RegdConstPed camInterface::ms_ScriptControlledFollowPedThisUpdate; s32 camInterface::ms_DeathFailEffectState; float camInterface::ms_CachedHeading; float camInterface::ms_CachedPitch; float camInterface::ms_CachedRoll; bool camInterface::ms_IsInitialized = false; bool camInterface::ms_IsOverridingStreamingFocus = false; bool camInterface::ms_IsRenderedCamInVehicle = false; #if FPS_MODE_SUPPORTED bool camInterface::ms_SetScriptedCameraIsFirstPersonThisFrame = false; #endif // FPS_MODE_SUPPORTED #if __BANK u32 camInterface::ms_DebugRespotCounter = 10000; bool camInterface::ms_DebugFlashLocallyWhileRespotting = false; bool camInterface::ms_DebugFlashRemotelyWhileRespotting = true; bool camInterface::ms_DebugShouldFollowDebugFocusPed = false; bool camInterface::ms_DebugForceFollowPedControlOrientation = false; bool camInterface::ms_DebugShouldDisplayActiveCameraInfo = false; bool camInterface::ms_DebugShouldDisplayGameViewportInfo = false; bool camInterface::ms_DebugShouldRestartSystemAtEndOfFrame = false; #endif // __BANK void camInterface::Init() { //Find and cache our game-specific directors to enable direct access. FIND_DIRECTOR_FATAL(camCinematicDirector, ms_CinematicDirector, "cinematic"); FIND_DIRECTOR_FATAL(camCutsceneDirector, ms_CutsceneDirector, "cutscene"); FIND_DIRECTOR_FATAL(camDebugDirector, ms_DebugDirector, "debug"); FIND_DIRECTOR_FATAL(camGameplayDirector, ms_GameplayDirector, "gameplay"); FIND_DIRECTOR_FATAL(camMarketingDirector, ms_MarketingDirector, "marketing"); FIND_DIRECTOR_FATAL(camScriptDirector, ms_ScriptDirector, "script"); FIND_DIRECTOR_FATAL(camSwitchDirector, ms_SwitchDirector, "switch"); FIND_DIRECTOR_FATAL(camReplayDirector, ms_ReplayDirector, "replay"); FIND_DIRECTOR_FATAL(camSyncedSceneDirector, ms_SyncedSceneDirector, "synced-scene"); FIND_DIRECTOR_FATAL(camAnimSceneDirector, ms_AnimSceneDirector, "animscene"); camFrame defaultFrame; ms_CachedFrame.CloneFrom(defaultFrame); //Clone a clean default frame. ms_FramePositionDelta.Zero(); ms_FrameVelocity.Zero(); ms_FrameAcceleration.Zero(); ms_FrameRateOfChangeOfAcceleration.Zero(); ms_CachedHeading = 0.0f; ms_CachedPitch = 0.0f; ms_CachedRoll = 0.0f; ms_DeathFailEffectState = DEATH_FAIL_EFFECT_INACTIVE; ms_ScriptControlledFollowPedThisUpdate = NULL; ms_IsInitialized = true; #if __BANK if(PARAM_cameraWidgets.Get()) { //Enable rendering of camera-related on-screen debug text by default with -cameraWidgets. ms_DebugShouldDisplayActiveCameraInfo = true; } #endif // __BANK } void camInterface::Shutdown() { ms_IsInitialized = false; } const Matrix34& camInterface::GetMat() { return ms_CachedFrame.GetWorldMatrix(); } bool camInterface::GetObjectSpaceCameraMatrix(const CEntity* pTargetEntity, Matrix34& mat) { if(!pTargetEntity) { return false; } const camBaseCamera* pCamera = GetDominantRenderedCamera(); if(!pCamera) { return false; } if(GetRenderedCameras().GetCount() == 1) { return pCamera->GetObjectSpaceCameraMatrix(pTargetEntity, mat); } else if(GetRenderedCameras().GetCount() > 1) { mat = ms_CachedFrame.GetWorldMatrix(); mat.DotTranspose(MAT34V_TO_MATRIX34(pTargetEntity->GetMatrix())); return true; } return false; } const Vector3& camInterface::GetPos() { return ms_CachedFrame.GetPosition(); } const Vector3& camInterface::GetFront() { return ms_CachedFrame.GetFront(); } const Vector3& camInterface::GetRight() { return ms_CachedFrame.GetRight(); } const Vector3& camInterface::GetUp() { return ms_CachedFrame.GetUp(); } float camInterface::GetNear() { return ms_CachedFrame.GetNearClip(); } float camInterface::GetFar() { return ms_CachedFrame.GetFarClip(); } float camInterface::GetNearDof() { return ms_CachedFrame.GetNearInFocusDofPlane(); } float camInterface::GetFarDof() { return ms_CachedFrame.GetFarInFocusDofPlane(); } float camInterface::GetFov() { return ms_CachedFrame.GetFov(); } float camInterface::GetMotionBlurStrength() { return ms_CachedFrame.GetMotionBlurStrength(); } bool camInterface::IsDominantRenderedDirector(const camBaseDirector& director) { const camBaseDirector* renderedDirector = camManager::GetDominantRenderedDirector(); const bool isTheRenderedDirector = (&director == renderedDirector); return isTheRenderedDirector; } const camBaseDirector* camInterface::GetDominantRenderedDirector() { const camBaseDirector* renderedDirector = camManager::GetDominantRenderedDirector(); return renderedDirector; } bool camInterface::IsRenderingDirector(const camBaseDirector& director) { bool isRenderingDirector = false; const atArray& renderedDirectors = camManager::GetRenderedDirectors(); const s32 numRenderedDirectors = renderedDirectors.GetCount(); for(s32 directorIndex=0; directorIndex& camInterface::GetRenderedDirectors() { const atArray& renderedDirectors = camManager::GetRenderedDirectors(); return renderedDirectors; } bool camInterface::IsDominantRenderedCamera(const camBaseCamera& camera) { const camBaseCamera* renderedCamera = camManager::GetDominantRenderedCamera(); const bool isTheRenderedCamera = (&camera == renderedCamera); return isTheRenderedCamera; } const camBaseCamera* camInterface::GetDominantRenderedCamera() { const camBaseCamera* renderedCamera = camManager::GetDominantRenderedCamera(); return renderedCamera; } bool camInterface::IsRenderingCamera(const camBaseCamera& camera) { bool isRenderingCamera = false; const atArray& renderedCameras = camManager::GetRenderedCameras(); const s32 numRenderedCameras = renderedCameras.GetCount(); for(s32 cameraIndex=0; cameraIndex& camInterface::GetRenderedCameras() { const atArray& renderedCameras = camManager::GetRenderedCameras(); return renderedCameras; } #if FPS_MODE_SUPPORTED bool camInterface::IsRenderingFirstPersonCamera() { const bool isRenderingFirstPersonCamera = camManager::IsRenderingFirstPersonCamera(); return isRenderingFirstPersonCamera; } bool camInterface::IsRenderingFirstPersonShooterCamera() { const bool isRenderingFirstPersonShooterCamera = camManager::IsRenderingFirstPersonShooterCamera(); return isRenderingFirstPersonShooterCamera; } bool camInterface::IsRenderingFirstPersonShooterCustomFallBackCamera() { const bool isRenderingFirstPersonShooterCustomFallBackCamera = camManager::IsRenderingFirstPersonShooterCustomFallBackCamera(); return isRenderingFirstPersonShooterCustomFallBackCamera; } bool camInterface::IsDominantRenderedCameraAnyFirstPersonCamera() { #if GTA_REPLAY //check we're in replay, we only care about the replay cameras if we are const bool isReplayActive = IsRenderingDirector(GetReplayDirector()); if (isReplayActive) { if (CReplayMgr::GetCamInFirstPersonFlag()) { return true; } else { return false; } } #endif //GTA_REPLAY const camBaseCamera* dominantCamera = camInterface::GetDominantRenderedCamera(); if(!dominantCamera) { return false; } if (dominantCamera->GetIsClassId(camFirstPersonShooterCamera::GetStaticClassId())) { return true; } if (dominantCamera->GetIsClassId(camCinematicMountedCamera::GetStaticClassId())) { const camCinematicMountedCamera* povCamera = static_cast(dominantCamera); if(povCamera->IsFirstPersonCamera()) { return true; } } if (ms_SetScriptedCameraIsFirstPersonThisFrame && dominantCamera->GetIsClassId(camScriptedCamera::GetStaticClassId())) { return true; } return false; } void camInterface::SetScriptedCameraIsFirstPersonThisFrame(bool isFirstPersonThisFrame) { ms_SetScriptedCameraIsFirstPersonThisFrame = isFirstPersonThisFrame; } #endif // FPS_MODE_SUPPORTED camCinematicDirector& camInterface::GetCinematicDirector() { GET_DIRECTOR_FATAL(camCinematicDirector, ms_CinematicDirector, "cinematic"); } camCutsceneDirector& camInterface::GetCutsceneDirector() { GET_DIRECTOR_FATAL(camCutsceneDirector, ms_CutsceneDirector, "cutscene"); } camDebugDirector& camInterface::GetDebugDirector() { GET_DIRECTOR_FATAL(camDebugDirector, ms_DebugDirector, "debug"); } camDebugDirector* camInterface::GetDebugDirectorSafe() { return static_cast(ms_DebugDirector.Get()); } camGameplayDirector& camInterface::GetGameplayDirector() { GET_DIRECTOR_FATAL(camGameplayDirector, ms_GameplayDirector, "gameplay"); } camGameplayDirector* camInterface::GetGameplayDirectorSafe() { return static_cast(ms_GameplayDirector.Get()); } camMarketingDirector& camInterface::GetMarketingDirector() { GET_DIRECTOR_FATAL(camMarketingDirector, ms_MarketingDirector, "marketing"); } camScriptDirector& camInterface::GetScriptDirector() { GET_DIRECTOR_FATAL(camScriptDirector, ms_ScriptDirector, "script"); } camSwitchDirector& camInterface::GetSwitchDirector() { GET_DIRECTOR_FATAL(camSwitchDirector, ms_SwitchDirector, "switch"); } camSyncedSceneDirector& camInterface::GetSyncedSceneDirector() { GET_DIRECTOR_FATAL(camSyncedSceneDirector, ms_SyncedSceneDirector, "syncedscene"); } camAnimSceneDirector& camInterface::GetAnimSceneDirector() { GET_DIRECTOR_FATAL(camAnimSceneDirector, ms_AnimSceneDirector, "animscene"); } camReplayDirector& camInterface::GetReplayDirector() { GET_DIRECTOR_FATAL(camReplayDirector, ms_ReplayDirector, "replay"); } //As far as player control goes what should we consider the camera heading to be? float camInterface::GetPlayerControlCamHeading(const CPed& player) { float heading; const camThirdPersonCamera* thirdPersonCamera = GetGameplayDirector().GetThirdPersonCamera(&player); #if FPS_MODE_SUPPORTED const camFirstPersonShooterCamera* firstPersonShooterCamera = GetGameplayDirector().GetFirstPersonShooterCamera(&player); #endif // FPS_MODE_SUPPORTED if (player.GetPedResetFlag(CPED_RESET_FLAG_ForcePedToUseScripCamHeading) && GetScriptDirector().IsRendering()) { heading = GetScriptDirector().GetFrame().ComputeHeading(); } else if(thirdPersonCamera && (BANK_ONLY(ms_DebugForceFollowPedControlOrientation || )(!GetDebugDirector().IsFreeCamActive() && !GetMarketingDirector().IsCameraActive()))) { const Vector3& front = thirdPersonCamera->GetBaseFront(); heading = camFrame::ComputeHeadingFromFront(front); } #if FPS_MODE_SUPPORTED else if (firstPersonShooterCamera) { heading = firstPersonShooterCamera->GetHeading(); } #endif // FPS_MODE_SUPPORTED else { heading = GetHeading(); } return heading; } //As far as player control goes what should we consider the camera pitch to be? float camInterface::GetPlayerControlCamPitch(const CPed& player) { float pitch; const camThirdPersonCamera* thirdPersonCamera = GetGameplayDirector().GetThirdPersonCamera(&player); #if FPS_MODE_SUPPORTED const camFirstPersonShooterCamera* firstPersonShooterCamera = GetGameplayDirector().GetFirstPersonShooterCamera(&player); #endif // FPS_MODE_SUPPORTED if(thirdPersonCamera && (BANK_ONLY(ms_DebugForceFollowPedControlOrientation ||) (!GetDebugDirector().IsFreeCamActive() && !GetMarketingDirector().IsCameraActive()))) { const Vector3& front = thirdPersonCamera->GetBaseFront(); pitch = camFrame::ComputePitchFromFront(front); } #if FPS_MODE_SUPPORTED else if (firstPersonShooterCamera) { pitch = firstPersonShooterCamera->GetPitch(); } #endif // FPS_MODE_SUPPORTED else { pitch = GetPitch(); } return pitch; } //As far as player control goes what should we consider the camera aim frame to be? const camFrame& camInterface::GetPlayerControlCamAimFrame() { const camBaseCamera* dominantRenderedCamera = GetDominantRenderedCamera(); if(dominantRenderedCamera && dominantRenderedCamera->GetIsClassId(camCinematicMountedCamera::GetStaticClassId()) && static_cast(dominantRenderedCamera)->ShouldAffectAiming()) { const camFrame& mountedCameraFrame = dominantRenderedCamera->GetFrameNoPostEffects(); return mountedCameraFrame; } else if(dominantRenderedCamera && dominantRenderedCamera->GetIsClassId(camThirdPersonPedAssistedAimCamera::GetStaticClassId()) && static_cast(dominantRenderedCamera)->ShouldAffectAiming()) { const camFrame& assistedAimFrame = static_cast(dominantRenderedCamera)->GetFrameForAiming(); return assistedAimFrame; } //Use the frame of the rendered scripted camera if it is configured to affect aiming. bool shouldUseScriptCameraFrame = false; const bool isScriptDirectorRendering = GetScriptDirector().IsRendering(); if(isScriptDirectorRendering) { const camBaseCamera* renderedCamera = GetScriptDirector().GetRenderedCamera(); if(renderedCamera && renderedCamera->GetIsClassId(camScriptedCamera::GetStaticClassId())) { const camScriptedCamera* scriptedCamera = static_cast(renderedCamera); shouldUseScriptCameraFrame = scriptedCamera->ShouldAffectAiming(); } } const camFrame& aimFrame = shouldUseScriptCameraFrame ? GetScriptDirector().GetFrame() : GetGameplayDirector().GetFrame(); return aimFrame; } float camInterface::ComputeMiniMapHeading() { //Use the heading of the debug free camera if it is active. const bool isFreeCameraActive = GetDebugDirector().IsFreeCamActive(); if(isFreeCameraActive) { const float heading = GetDebugDirector().GetFreeCamFrame().ComputeHeading(); return heading; } //Use the heading of the rendered scripted camera if it is configured to control the mini map orientation. const bool isScriptDirectorRendering = GetScriptDirector().IsRendering(); if(isScriptDirectorRendering) { const camBaseCamera* renderedCamera = GetScriptDirector().GetRenderedCamera(); if(renderedCamera) { bool shouldCameraControlMiniMapHeading = false; if (renderedCamera->GetIsClassId(camScriptedCamera::GetStaticClassId())) { const camScriptedCamera* scriptedCamera = static_cast(renderedCamera); shouldCameraControlMiniMapHeading = scriptedCamera->ShouldControlMiniMapHeading(); } else if (renderedCamera->GetIsClassId(camAnimatedCamera::GetStaticClassId())) { const camAnimatedCamera* animatedCamera = static_cast(renderedCamera); shouldCameraControlMiniMapHeading = animatedCamera->ShouldControlMiniMapHeading(); } if(shouldCameraControlMiniMapHeading) { //Use the script director's frame, as this can include the result of interpolation not visible in rendered camera itself. const float heading = GetScriptDirector().GetFrameNoPostEffects().ComputeHeading(); return heading; } } } const bool isRenderingCinematicCamera = GetCinematicDirector().IsRendering(); if(isRenderingCinematicCamera) { const bool isRenderingMountedCamera = (GetCinematicDirector().IsRenderingCinematicMountedCamera()); if(isRenderingMountedCamera) { //Use the base front, the no post effects frame has already cloned the post effect frame by this point const camBaseCamera* renderedCamera = camInterface::GetDominantRenderedCamera(); const Vector3& front = renderedCamera->GetBaseFront(); const float heading = camFrame::ComputeHeadingFromFront(front); return heading; } const bool isRendingIdleCamera = (GetCinematicDirector().IsRenderingCinematicIdleCamera()); if(isRendingIdleCamera) { return 0.0f; } //Lock the mini-map to point north when spectating a remote player that is on-foot. Otherwise the mini-map can spin around in an //unintuitive way. const camBaseCinematicContext* currentContext = GetCinematicDirector().GetCurrentContext(); if(currentContext && currentContext->GetIsClassId(camCinematicOnFootSpectatingContext::GetStaticClassId())) { return 0.0f; } const camThirdPersonCamera* thirdPersonCamera = GetGameplayDirector().GetThirdPersonCamera(); if(thirdPersonCamera) { //Use the base front, as this ignores look-behind and thereby avoids confusing the user when a cinematic camera is rendering. const Vector3& front = thirdPersonCamera->GetBaseFront(); const float heading = camFrame::ComputeHeadingFromFront(front); return heading; } } #if GTA_REPLAY if(CReplayMgr::IsEditModeActive()) { const bool isRenderingReplayCamera = camManager::FindDirector()->IsRendering(); if(isRenderingReplayCamera) { const float heading = camManager::FindDirector()->GetFrameNoPostEffects().ComputeHeading(); return heading; } } #endif // GTA_REPLAY const float heading = GetGameplayDirector().GetFrameNoPostEffects().ComputeHeading(); return heading; } void camInterface::CacheFrame(const camFrame& sourceFrame) { ms_FramePositionDelta = sourceFrame.GetPosition() - ms_CachedFrame.GetPosition(); float invTimeStep = fwTimer::GetInvTimeStep(); Vector3 velocity = ms_FramePositionDelta * invTimeStep; Vector3 acceleration = (velocity - ms_FrameVelocity) * invTimeStep; ms_FrameVelocity = velocity; ms_FrameRateOfChangeOfAcceleration = (acceleration - ms_FrameAcceleration) * invTimeStep; ms_FrameAcceleration = acceleration; PF_SET(camInterfaceFrameVelocityMag, ms_FrameVelocity.Mag()); PF_SET(camInterfaceFrameAccelerationMag, ms_FrameAcceleration.Mag()); PF_SET(camInterfaceFrameRateOfChangeOfAccelerationMag, ms_FrameRateOfChangeOfAcceleration.Mag()); PF_SET(camInterfaceFrameAngularVelocityMag, sourceFrame.GetFront().FastAngle(ms_CachedFrame.GetFront()) * invTimeStep); PF_SET(camInterfaceFov, sourceFrame.GetFov()); ms_CachedFrame.CloneFrom(sourceFrame); ms_CachedFrame.ComputeHeadingPitchAndRoll(ms_CachedHeading, ms_CachedPitch, ms_CachedRoll); UpdateRenderedCamInVehicle(); //Override the streaming focus, as necessary. const bool shouldOverrideStreamingFocus = sourceFrame.GetFlags().IsFlagSet(camFrame::Flag_ShouldOverrideStreamingFocus); if(shouldOverrideStreamingFocus) { CFocusEntityMgr::GetMgr().SetPosAndVel(sourceFrame.GetPosition(), velocity); } else if(ms_IsOverridingStreamingFocus) { //Reset the streaming focus, which is persistent. CFocusEntityMgr::GetMgr().SetDefault(true); } ms_IsOverridingStreamingFocus = shouldOverrideStreamingFocus; if(IsDeathFailEffectActive()) { cameraDebugf3("Camera death/fail effect is active (state = %d)", ms_DeathFailEffectState); } if (CControlMgr::GetKeyboard().GetKeyJustDown(KEY_F3, KEYBOARD_MODE_DEBUG_ALT)) { rage::ioHeadTracking::EnableFPSCamera(!rage::ioHeadTracking::UseFPSCamera()); } CPad *pPad = CControlMgr::GetPlayerPad(); if (pPad) { #if !__FINAL if(pPad->GetLeftShoulder1() && pPad->GetLeftShoulder2() && rage::ioHeadTracking::IsMotionTrackingEnabled()) { rage::ioHeadTracking::EnableFPSCamera(!rage::ioHeadTracking::UseFPSCamera()); } #endif // !__FINAL if(pPad->GetDPadLeft() && pPad->ButtonCrossJustDown()) { rage::ioHeadTracking::Reset(); } } fwTimer::SetTimeWarpCamera(sourceFrame.GetCameraTimeScaleThisUpdate()); } void camInterface::SetCachedFrameOnly(const camFrame& sourceFrame) { ms_CachedFrame.CloneFrom(sourceFrame); } const CPed* camInterface::FindFollowPed() { const CPed* followPlayer = static_cast(CGameWorld::FindFollowPlayer()); if(ms_ScriptControlledFollowPedThisUpdate) { followPlayer = ms_ScriptControlledFollowPedThisUpdate; } else if(ms_GameplayDirector) { const camBaseSwitchHelper* switchHelper = static_cast(ms_GameplayDirector.Get())->GetSwitchHelper(); if(switchHelper) { const CPed* desiredFollowPedForSwitch = switchHelper->GetDesiredFollowPed(); if(desiredFollowPedForSwitch) { followPlayer = desiredFollowPedForSwitch; } } } #if __BANK if(ms_DebugShouldFollowDebugFocusPed) { CEntity* debugFocusEntity = CDebugScene::FocusEntities_Get(0); if(debugFocusEntity) { if(debugFocusEntity->GetIsTypePed()) { followPlayer = static_cast(debugFocusEntity); } else if(debugFocusEntity->GetIsTypeVehicle()) { const CPed* driver = static_cast(debugFocusEntity)->GetDriver(); if(driver) { followPlayer = driver; } } } } #endif // __BANK return followPlayer; } //Resurrect the main player - cameras associated with this player are cleaned up and reinstated. void camInterface::ResurrectPlayer() { SetDeathFailEffectState(DEATH_FAIL_EFFECT_INACTIVE); GetGameplayDirector().ResurrectPlayer(); GetCinematicDirector().InvalidateIdleCamera(); } void camInterface::ShakeCameraExplosion(u32 shakeNameHash, float explosionStrength, float rollOffScaling, const Vector3& positionOfExplosion) { if(explosionStrength < SMALL_FLOAT) { return; } GetGameplayDirector().RegisterExplosion(shakeNameHash, explosionStrength, rollOffScaling, positionOfExplosion); } bool camInterface::IsCameraShaking(const bool includeExplosions) { const camBaseDirector* renderedDirector = GetDominantRenderedDirector(); if(renderedDirector && renderedDirector->IsShaking()) { return true; } if(includeExplosions) { const atArray& explosionSettingsList = GetGameplayDirector().GetExplosionSettings(); for(s32 explosionIndex = 0; explosionIndex < explosionSettingsList.GetCount(); ++explosionIndex) { if(explosionSettingsList[explosionIndex].m_FrameShaker) { return true; } } } return false; } void camInterface::RegisterWeaponFire(const CWeapon& weapon, const CEntity& firingEntity, const bool isNetworkClone) { const int numDirectors = camManager::ms_Directors.GetCount(); for(int i = 0; i < numDirectors; i++) { camBaseDirector* director = camManager::ms_Directors[i]; if(director) { director->RegisterWeaponFire(weapon, firingEntity, isNetworkClone); } } } float camInterface::GetViewportTanFovH() { return gVpMan.GetCurrentViewport()->GetGrcViewport().GetTanHFOV(); } float camInterface::GetViewportTanFovV() { return gVpMan.GetCurrentViewport()->GetGrcViewport().GetTanVFOV(); } const Vector3& camInterface::GetViewportUp() { return RCC_VECTOR3(gVpMan.GetCurrentViewport()->GetGrcViewport().GetCameraMtx().GetCol2ConstRef()); } void camInterface::SetFixedFade(float fadeValue) { SetFixedFade(fadeValue, Color_black); } void camInterface::SetFixedFade(float fadeValue, const Color32 &fadeColor) { ms_Fader.SetFixedFade(fadeValue, &fadeColor); } void camInterface::FadeOut(s32 duration, bool shouldHoldAtEnd) { FadeOut(duration, shouldHoldAtEnd, Color_black); } void camInterface::FadeOut(s32 duration, bool shouldHoldAtEnd, const Color32& fadeColour) { STRVIS_ADD_MARKER(strStreamingVisualize::MARKER); STRVIS_SET_MARKER_TEXT("FADE OUT"); CViewport* viewport = gVpMan.GetPrimaryOrthoViewport(); if(viewport) { ms_Fader.Set(duration, false, &fadeColour, shouldHoldAtEnd); if (!CLoadingScreens::AreActive()) { CLoadingText::SetActive(true); } } } bool camInterface::IsFadingOut() { CViewport* viewport = gVpMan.GetPrimaryOrthoViewport(); bool isFadingOut = viewport && (ms_Fader.IsFadingOut()); return isFadingOut; } bool camInterface::IsFadedOut() { CViewport* viewport = gVpMan.GetPrimaryOrthoViewport(); bool isFadedOut = viewport && (ms_Fader.IsFadedOut()); return isFadedOut; } void camInterface::FadeIn(s32 duration) { FadeIn(duration, Color_black); } void camInterface::FadeIn(s32 duration, const Color32& fadeColour) { STRVIS_ADD_MARKER(strStreamingVisualize::MARKER); STRVIS_SET_MARKER_TEXT("FADE IN"); CViewport* viewport = gVpMan.GetPrimaryOrthoViewport(); if(viewport) { ms_Fader.Set(duration, true, &fadeColour); CLoadingText::SetActive(false); } } void camInterface::RenderFade() { ms_Fader.Render(); } bool camInterface::IsFadingIn() { CViewport* viewport = gVpMan.GetPrimaryOrthoViewport(); bool isFadingIn = viewport && (ms_Fader.IsFadingIn()); return isFadingIn; } bool camInterface::IsFadedIn() { CViewport* viewport = gVpMan.GetPrimaryOrthoViewport(); bool isFadedIn = viewport && (ms_Fader.IsFadedIn()); return isFadedIn; } bool camInterface::IsFading() { bool isFading = IsFadingIn() || IsFadingOut(); return isFading; } bool camInterface::IsFadingOrJustFaded() { #define NUM_FRAMES_TO_WAIT (15) bool isFadingOrJustFaded = IsFading(); static u32 releaseFramesRemaining = NUM_FRAMES_TO_WAIT; if(isFadingOrJustFaded) { releaseFramesRemaining = NUM_FRAMES_TO_WAIT; } else if(releaseFramesRemaining > 0) { releaseFramesRemaining--; } if(releaseFramesRemaining > 0) { isFadingOrJustFaded = true; } return isFadingOrJustFaded; } void camInterface::UpdateFade() { ms_Fader.Process(); } float camInterface::GetFadeLevel() { float fadeLevel = ms_Fader.GetAudioFade(); return fadeLevel; } #if GTA_REPLAY void camInterface::SetFader(const CViewportFader& fader) { ms_Fader = fader; } #endif //Returns true if the specified sphere is visible in the game viewport. bool camInterface::IsSphereVisibleInGameViewport(const Vector3& centre, float radius) { bool isVisible = false; CViewport* gameViewport = gVpMan.GetGameViewport(); if(cameraVerifyf(gameViewport, "camInterface::IsSphereVisibleInGameViewport was called when no game viewport was active")) { isVisible = (gameViewport->GetGrcViewport().IsSphereVisible(centre.x, centre.y, centre.z, radius) != cullOutside); } return isVisible; } bool camInterface::IsSphereVisibleInGameViewport(Vec4V_In centreAndRadius) { bool isVisible = false; CViewport* gameViewport = gVpMan.GetGameViewport(); if(cameraVerifyf(gameViewport, "camInterface::IsSphereVisibleInGameViewport was called when no game viewport was active")) { isVisible = (gameViewport->GetGrcViewport().IsSphereVisible(centreAndRadius) != 0); } return isVisible; } bool camInterface::IsSphereVisibleInViewport(int viewportId, const Vector3& centre, float radius) { bool isVisible = false; CViewport* viewport = gVpMan.FindById(viewportId); if(cameraVerifyf(viewport, "camInterface::IsSphereVisibleInViewport was called with an inactive viewport ID")) { isVisible = (viewport->GetGrcViewport().IsSphereVisible(centre.x, centre.y, centre.z, radius) != cullOutside); } return isVisible; } bool camInterface::ComputeVehicleEntryExitPointPositionAndOrientation(const CPed& targetPed, const CVehicle& targetVehicle, Vector3& entryExitPointPosition, Quaternion& entryExitOrientation, bool& hasClimbDown) { CQueriableInterface* queriableInterface = targetPed.GetPedIntelligence()->GetQueriableInterface(); if(!queriableInterface) { return false; } s32 entryPointId = -1; bool isGetInTaskActive = queriableInterface->IsTaskCurrentlyRunning(CTaskTypes::TASK_ENTER_VEHICLE); if(isGetInTaskActive) { entryPointId = queriableInterface->GetTargetEntryPointForTaskType(CTaskTypes::TASK_ENTER_VEHICLE); } bool isGetOutTaskActive = queriableInterface->IsTaskCurrentlyRunning(CTaskTypes::TASK_EXIT_VEHICLE); if(isGetOutTaskActive) { entryPointId = queriableInterface->GetTargetEntryPointForTaskType(CTaskTypes::TASK_EXIT_VEHICLE); } if(entryPointId < 0) { return false; } CModelSeatInfo::CalculateEntrySituation(&targetVehicle, &targetPed, entryExitPointPosition, entryExitOrientation, entryPointId); const CVehicleEntryPointAnimInfo* clipInfo = targetVehicle.GetEntryAnimInfo(entryPointId); hasClimbDown = clipInfo && clipInfo->GetHasClimbDown(); return true; } bool camInterface::ComputeShouldPauseCameras() { #if SECTOR_TOOLS_EXPORT const bool isRunningSectorTools = CSectorTools::GetEnabled(); #else const bool isRunningSectorTools = false; #endif // SECTOR_TOOLS_EXPORT //Only during a single-player game does the front-end pause the cameras. //MF: Also only when the player settings menu is not running, don't forget that. //NOTE: Cameras are never paused when the debug sector tools are running, as all cameras must update during the tests. const bool shouldPause = !isRunningSectorTools && BANK_ONLY(!fwTimer::GetSingleStepThisFrame() &&) ((fwTimer::IsUserPaused() && !NetworkInterface::IsGameInProgress()) || fwTimer::IsGamePaused()); return shouldPause REPLAY_ONLY(&& !CReplayMgr::IsEditModeActive()); } struct tCameraFocusPedCandidate { CPed* m_Ped; float m_ScaledDistance; }; s32 CameraFocusPedCandidateCompareFunc(const tCameraFocusPedCandidate* candidateA, const tCameraFocusPedCandidate* candidateB) { return (candidateA->m_ScaledDistance < candidateB->m_ScaledDistance) ? -1 : 1; } CPed* camInterface::ComputeFocusPedOnScreen(float maxValidDistance, s32 screenPositionTestBoneTag, float maxScreenWidthRatioAroundCentreForTestBone, float maxScreenHeightRatioAroundCentreForTestBone, float minRelativeHeadingScore, float maxScreenCentreScoreBoost, float maxScreenRatioAroundCentreForScoreBoost, s32 losTestBoneTag1, s32 losTestBoneTag2) { const CPed* followPed = FindFollowPed(); const Vector3& cameraPosition = ms_CachedFrame.GetPosition(); const Vector3& cameraFront = ms_CachedFrame.GetFront(); const float verticalFov = ms_CachedFrame.GetFov(); const CViewport* viewport = gVpMan.GetGameViewport(); const float aspectRatio = viewport ? viewport->GetGrcViewport().GetAspectRatio() : (16.0f / 9.0f); const float horizontalFov = verticalFov * aspectRatio; const float maxCameraToScreenTestBoneHeadingDelta = 0.5f * maxScreenWidthRatioAroundCentreForTestBone * horizontalFov * DtoR; const float maxCameraToScreenTestBonePitchDelta = 0.5f * maxScreenHeightRatioAroundCentreForTestBone * verticalFov * DtoR; atArray candidatePeds; Vec3V vIteratorPos = VECTOR3_TO_VEC3V(cameraPosition); CEntityIterator entityIterator(IteratePeds, followPed, &vIteratorPos, maxValidDistance); while(true) { CEntity* nearbyEntity = entityIterator.GetNext(); if(!nearbyEntity) { break; } if(nearbyEntity->GetIsTypePed()) { CPed* ped = static_cast(nearbyEntity); if(screenPositionTestBoneTag != BONETAG_INVALID) { //Ensure that the specified test bone is within the view frustum, including a sensible border width. Vector3 screenTestBonePosition; const bool hasValidBone = ped->GetBonePosition(screenTestBonePosition, static_cast(screenPositionTestBoneTag)); if(!hasValidBone) { continue; } Vector3 cameraToScreenTestBoneFront(screenTestBonePosition - cameraPosition); cameraToScreenTestBoneFront.NormalizeSafe(cameraFront); const float headingDelta = Abs(camFrame::ComputeHeadingDeltaBetweenFronts(cameraFront, cameraToScreenTestBoneFront)); if(headingDelta > maxCameraToScreenTestBoneHeadingDelta) { //This ped's test bone is outside of the screen-space safe zone. continue; } const float pitchDelta = Abs(camFrame::ComputePitchDeltaBetweenFronts(cameraFront, cameraToScreenTestBoneFront)); if(pitchDelta > maxCameraToScreenTestBonePitchDelta) { //This ped's test bone is outside of the screen-space safe zone. continue; } } //Score the camera-relative heading to the ped, as more centrally framed peds are more relevant. const Vector3 pedPosition = VEC3V_TO_VECTOR3(ped->GetTransform().GetPosition()); const Vector3 cameraToPedDelta = pedPosition - cameraPosition; Vector3 cameraToPedFront(cameraToPedDelta); cameraToPedFront.NormalizeSafe(cameraFront); const float headingDelta = Abs(camFrame::ComputeHeadingDeltaBetweenFronts(cameraFront, cameraToPedFront)); float headingScoreScaling = RampValueSafe(headingDelta, 0.0f, 0.5f * horizontalFov * DtoR, 1.0f, 0.0f); headingScoreScaling = SlowInOut(headingScoreScaling); headingScoreScaling = RampValue(headingScoreScaling, 0.0f, 1.0f, minRelativeHeadingScore, 1.0f); //Compute the any score boost around the screen centre. float screenCentreScoreBoost = RampValueSafe(headingDelta, 0.0f, 0.5f * maxScreenRatioAroundCentreForScoreBoost * horizontalFov * DtoR, 1.0f, 0.0f); screenCentreScoreBoost = SlowInOut(screenCentreScoreBoost); screenCentreScoreBoost = RampValue(screenCentreScoreBoost, 0.0f, 1.0f, 1.0f, maxScreenCentreScoreBoost); headingScoreScaling *= screenCentreScoreBoost; if(headingScoreScaling >= SMALL_FLOAT) { //Now factor in the distance to the ped. tCameraFocusPedCandidate& candidate = candidatePeds.Grow(); candidate.m_Ped = ped; candidate.m_ScaledDistance = cameraToPedDelta.Mag() / headingScoreScaling; } } } //Order the candidates by scaled distance, nearest first. candidatePeds.QSort(0, -1, CameraFocusPedCandidateCompareFunc); CPed* focusPed = NULL; //Find the best candidate ped that meets the LOS requirements. const int numCandidatePeds = candidatePeds.GetCount(); for(int i=0; iGetHitTValue() < b->GetHitTValue()) ? -1 : 1; } bool camInterface::ComputeHasClearLineOfSightToPedBone(const CPed& ped, s32 boneTag, bool shouldIgnoreOcclusionDueToFollowPed, bool shouldIgnoreOcclusionDueToFollowVehicle) { Vector3 bonePosition; const bool hasValidBone = ped.GetBonePosition(bonePosition, static_cast(boneTag)); if(!hasValidBone) { return false; } WorldProbe::CShapeTestProbeDesc probeTest; WorldProbe::CShapeTestFixedResults<> probeTestResults; probeTest.SetResultsStructure(&probeTestResults); probeTest.SetContext(WorldProbe::LOS_Camera); const u32 typesToCollideWith = ArchetypeFlags::GTA_ALL_TYPES_WEAPON | ArchetypeFlags::GTA_RAGDOLL_TYPE; probeTest.SetIncludeFlags(typesToCollideWith); atArray excludeInstances; //Exclude all of the ped's immediate child attachments. const fwEntity* childAttachment = ped.GetChildAttachment(); while(childAttachment) { const phInst* attachmentInstance = childAttachment->GetCurrentPhysicsInst(); if(attachmentInstance) { excludeInstances.Grow() = attachmentInstance; } childAttachment = childAttachment->GetSiblingAttachment(); } if(shouldIgnoreOcclusionDueToFollowPed) { //Exclude the follow ped capsule and ragdoll bounds. const CPed* followPed = FindFollowPed(); if(followPed) { const phInst* animatedInstance = followPed->GetAnimatedInst(); if(animatedInstance) { excludeInstances.Grow() = animatedInstance; } const phInst* ragdollInstance = followPed->GetRagdollInst(); if(ragdollInstance) { excludeInstances.Grow() = ragdollInstance; } //Exclude all of the follow ped's immediate child attachments. const fwEntity* childAttachment = followPed->GetChildAttachment(); while(childAttachment) { const phInst* attachmentInstance = childAttachment->GetCurrentPhysicsInst(); if(attachmentInstance) { excludeInstances.Grow() = attachmentInstance; } childAttachment = childAttachment->GetSiblingAttachment(); } } } if(shouldIgnoreOcclusionDueToFollowVehicle) { const CVehicle* followVehicle = camInterface::GetGameplayDirector().GetFollowVehicle(); if(followVehicle) { const phInst* followVehicleInstance = followVehicle->GetCurrentPhysicsInst(); if(followVehicleInstance) { excludeInstances.Grow() = followVehicleInstance; } } } const int numExcludeInstances = excludeInstances.GetCount(); if(numExcludeInstances > 0) { probeTest.SetExcludeInstances(excludeInstances.GetElements(), numExcludeInstances); } const Vector3& cameraPosition = ms_CachedFrame.GetPosition(); probeTest.SetStartAndEnd(cameraPosition, bonePosition); WorldProbe::GetShapeTestManager()->SubmitTest(probeTest, WorldProbe::PERFORM_SYNCHRONOUS_TEST); const u32 numHits = probeTestResults.GetNumHits(); if(numHits == 0) { return false; } if(numHits > 1) { probeTestResults.SortHits(CompareLosProbeIntersections); } phInst* hitInstance = probeTestResults[0].GetHitInst(); CEntity* hitEntity = hitInstance ? CPhysics::GetEntityFromInst(hitInstance) : NULL; const bool hasClearLosToPed = (hitEntity == &ped); return hasClearLosToPed; } //This is for Alex (and decals for rendering bullet holes and stuff on glass.) bool camInterface::IsRenderedCameraInsideVehicle() { #if GTA_REPLAY if(CReplayMgr::IsEditModeActive()) { return CReplayMgr::IsRenderedCamInVehicle(); } else #endif { return ms_IsRenderedCamInVehicle; } } bool camInterface::IsRenderedCameraForcingMotionBlur() { const camCinematicDirector& cinematicDirector = GetCinematicDirector(); const camBaseCamera* renderedCinematicCamera = cinematicDirector.GetRenderedCamera(); const bool isActuallyRenderingCinematicCamera = renderedCinematicCamera && IsDominantRenderedCamera(*renderedCinematicCamera); return isActuallyRenderingCinematicCamera && cinematicDirector.IsRenderedCameraForcingMotionBlur(); } void camInterface::UpdateRenderedCamInVehicle() { const camCinematicDirector& cinematicDirector = GetCinematicDirector(); const camBaseCamera* renderedCinematicCamera = cinematicDirector.GetRenderedCamera(); const bool isActuallyRenderingCinematicCamera = renderedCinematicCamera && IsDominantRenderedCamera(*renderedCinematicCamera); ms_IsRenderedCamInVehicle = isActuallyRenderingCinematicCamera && cinematicDirector.IsRenderedCameraInsideVehicle(); if(!ms_IsRenderedCamInVehicle) { //Check if we're rendering a scripted camera that has been specially flagged by script as being inside a vehicle. const camBaseCamera* dominantRenderedCamera = GetDominantRenderedCamera(); ms_IsRenderedCamInVehicle = (dominantRenderedCamera && dominantRenderedCamera->GetIsClassId(camScriptedCamera::GetStaticClassId()) && static_cast(dominantRenderedCamera)->IsInsideVehicle()); } } bool camInterface::ComputeShouldMakePedHeadInvisible(const CPed& ped) { const CPed* pedToMakeHeadInvisible = NULL; //Hide the follow ped's head if we're fully rendering gameplay and first-person mode is active. // TODO: remove if we drop using third person camera for first person mode, head visibility state read from FirstPersonAimCamera metadata #if FPS_MODE_SUPPORTED camGameplayDirector* gameplayDirector = static_cast(ms_GameplayDirector.Get()); if(gameplayDirector) { const bool isFirstPersonModeActive = (gameplayDirector->IsFirstPersonModeEnabled() && gameplayDirector->IsFirstPersonModeAllowed()); if(isFirstPersonModeActive && gameplayDirector->ShouldUseThirdPersonCameraForFirstPersonMode()) { const atArray& renderedDirectors = GetRenderedDirectors(); const int numRenderedDirectors = renderedDirectors.GetCount(); if((numRenderedDirectors == 1) && (static_cast(renderedDirectors[0].m_Object.Get()) == gameplayDirector)) { const CPed* followPed = gameplayDirector->GetFollowPed(); if(followPed == &ped) { return true; } } } } #endif // FPS_MODE_SUPPORTED //Otherwise, we only make the ped's head invisible if we are fully rendering a cinematic mounted or first-person camera that has flagged this ped. const atArray& renderedCameras = GetRenderedCameras(); const int numRenderedCameras = renderedCameras.GetCount(); if(numRenderedCameras < 1) { return false; } const camBaseCamera* renderedCamera = static_cast(renderedCameras[0].m_Object.Get()); if(!renderedCamera) { return false; } bool isInterpolatingBetweenTableGamesCameras = false; if (numRenderedCameras == 2) { const camBaseCamera* firstCamera = renderedCamera; const camBaseCamera* secondCamera = static_cast(renderedCameras[1].m_Object.Get()); const bool isFirstCameraTableGames = firstCamera->GetIsClassId(camFirstPersonShooterCamera::GetStaticClassId()) && static_cast(firstCamera)->IsTableGamesCamera(); const bool isSecondCameraTableGames = secondCamera && secondCamera->GetIsClassId(camFirstPersonShooterCamera::GetStaticClassId()) && static_cast(secondCamera)->IsTableGamesCamera(); isInterpolatingBetweenTableGamesCameras = isFirstCameraTableGames || isSecondCameraTableGames; } if (!isInterpolatingBetweenTableGamesCameras) { // If cinematic camera is rendering and it wants ped head to be invisible, allow head to be hidden while interpolating. (i.e. 2 cameras rendering) bool bCinematicCameraWantsPedHeadInvisible = renderedCamera->GetIsClassId(camCinematicMountedCamera::GetStaticClassId()) && static_cast(renderedCamera)->GetPedToMakeHeadInvisible(); if (numRenderedCameras != 1 && (!bCinematicCameraWantsPedHeadInvisible || numRenderedCameras != 2)) { return false; } } if( renderedCamera->GetIsClassId(camCinematicMountedCamera::GetStaticClassId()) ) { pedToMakeHeadInvisible = static_cast(renderedCamera)->GetPedToMakeHeadInvisible(); } else if( renderedCamera->GetIsClassId(camFirstPersonAimCamera::GetStaticClassId()) ) { const camFirstPersonAimCamera* pFirstPersonAimCamera = static_cast(renderedCamera); if( !pFirstPersonAimCamera->ShouldMakeAttachedEntityInvisible() && pFirstPersonAimCamera->ShouldMakeAttachedPedHeadInvisible() ) { const CEntity* entityToMakeInvisible = pFirstPersonAimCamera->GetAttachParent(); if(entityToMakeInvisible && entityToMakeInvisible->GetIsTypePed()) { pedToMakeHeadInvisible = static_cast(entityToMakeInvisible); } } } #if FPS_MODE_SUPPORTED && 0 // If free camera is active and only other camera is first person camera, don't render the head. camGameplayDirector* gameplayDirector = static_cast(ms_GameplayDirector.Get()); if(ms_DebugDirector.Get() && GetDebugDirector().IsFreeCamActive() && ms_GameplayDirector.Get()) { const bool isFirstPersonModeActive = (GetGameplayDirector().IsFirstPersonModeEnabled() && GetGameplayDirector().IsFirstPersonModeAllowed()); if(isFirstPersonModeActive) { const int numRenderedDirectors = renderedDirectors.GetCount(); if((numRenderedDirectors == 2) && (static_cast(renderedDirectors[0].m_Object.Get()) == gameplayDirector)) { const CPed* followPed = gameplayDirector->GetFollowPed(); if(followPed == &ped) { return true; } } } } #endif // FPS_MODE_SUPPORTED const bool shouldMakeInvisible = (pedToMakeHeadInvisible == &ped); return shouldMakeInvisible; } void camInterface::DisableNearClipScanThisUpdate() { camManager::ms_FramePropagator.DisableNearClipScanThisUpdate(); } u32 camInterface::ComputePovTurretCameraHash(const CVehicle* pVehicle) { const CPed* pFollowPed = FindFollowPed(); if(!pVehicle || !pVehicle->GetVehicleModelInfo() || !pFollowPed) { return 0; } const s32 seatIndex = camGameplayDirector::ComputeSeatIndexPedIsIn(*pVehicle, *pFollowPed); const bool isPedOnATurret = camGameplayDirector::IsTurretSeat(pVehicle, seatIndex); if(isPedOnATurret) { const CVehicleModelInfo* pVehicleModelInfo = pVehicle->GetVehicleModelInfo(); const CWeaponInfo* pTurretWeaponInfo = camGameplayDirector::GetTurretWeaponInfoForSeat(*pVehicle, seatIndex); if(pTurretWeaponInfo && pTurretWeaponInfo->GetPovTurretCameraHash() != 0) { return pTurretWeaponInfo->GetPovTurretCameraHash(); } else if(pVehicleModelInfo && pVehicleModelInfo->GetPovTurretCameraNameHash() != 0) { return pVehicleModelInfo->GetPovTurretCameraNameHash(); } } return 0; } #if RSG_PC float camInterface::GetStereoConvergence() { return camManager::ms_fStereoConvergence; } #endif void camInterface::SetDeathFailEffectState(s32 state) { if(ms_DeathFailEffectState == state) { return; } const bool hasSucceeded = GetGameplayDirector().SetDeathFailEffectState(state); if(hasSucceeded) { ms_DeathFailEffectState = state; } } #if FPS_MODE_SUPPORTED void camInterface::ApplyPedBoneOverridesForFirstPerson(const CPed& ped, crSkeleton& skeleton) { //Rotate the attach ped's spine backwards a little if we're rendering an FPS camera that's been pushed back out of collision (towards a safe fall back position.) const camBaseCamera* renderedCamera = camManager::GetDominantRenderedCamera(); if(!renderedCamera || !renderedCamera->GetIsClassId(camFirstPersonShooterCamera::GetStaticClassId())) { return; } const camFirstPersonShooterCamera* fpsCamera = static_cast(renderedCamera); const float rotationToApply = fpsCamera->ComputeRotationToApplyToPedSpineBone(ped); if(IsNearZero(rotationToApply)) { return; } const s32 tempBoneIndex = ped.GetBoneIndexFromBoneTag(BONETAG_SPINE0); if(tempBoneIndex == -1) { return; } const u32 boneIndex = static_cast(tempBoneIndex); Mat34V& localBoneMatrix = skeleton.GetLocalMtx(boneIndex); Matrix34 tmpLocalBoneMatrix = RC_MATRIX34(localBoneMatrix); tmpLocalBoneMatrix.RotateLocalZ(rotationToApply); localBoneMatrix = MATRIX34_TO_MAT34V(tmpLocalBoneMatrix); skeleton.PartialUpdate(boneIndex); } #endif // FPS_MODE_SUPPORTED #if __BANK void camInterface::AddWidgets(bkBank &bank) { bank.AddToggle("Display active camera info on-screen", &ms_DebugShouldDisplayActiveCameraInfo); bank.AddToggle("Display game viewport info on-screen", &ms_DebugShouldDisplayGameViewportInfo); bank.AddButton("Dump spectator ped info (network ped id & spectator cam)", datCallback(CFA(DebugDumpSpectatorPedInfo))); bank.AddToggle("Follow debug focus ped", &ms_DebugShouldFollowDebugFocusPed); bank.AddToggle("Always take control orientation from follow-ped camera", &ms_DebugForceFollowPedControlOrientation); bank.AddToggle("Flash Locally While Respotting", &ms_DebugFlashLocallyWhileRespotting); bank.AddToggle("Flash Remotely While Respotting", &ms_DebugFlashRemotelyWhileRespotting); bank.AddSlider("Respot counter to apply", &ms_DebugRespotCounter, 0, 600000, 1); bank.AddButton("Set respot counter on debug focus vehicle", datCallback(CFA(DebugSetRespotCounterOnDebugFocusVehicle))); } void camInterface::DebugDisplayCameraInfoText() { const int debugStringLength = 256; char debugString[debugStringLength]; if(ms_DebugShouldDisplayActiveCameraInfo) { const camBaseCamera* renderedCamera = camManager::GetDominantRenderedCamera(); const char* renderedCameraName = SAFE_CSTRING(renderedCamera ? renderedCamera->GetName() : NULL); if (renderedCamera && renderedCamera->GetIsClassId(camScriptedCamera::GetStaticClassId())) { const camScriptedCamera* pScriptedCamera = static_cast(renderedCamera); if ( pScriptedCamera->GetDebugName() != NULL && pScriptedCamera->GetDebugName()[0] != 0 ) { renderedCameraName = pScriptedCamera->GetDebugName(); } } const Vector3& position = GetPos(); #if FPS_MODE_SUPPORTED if( renderedCamera && (renderedCamera->GetIsClassId(camFirstPersonShooterCamera::GetStaticClassId()) || renderedCamera->GetIsClassId(camCinematicMountedCamera::GetStaticClassId())) ) { formatf(debugString, debugStringLength, "%s: %8.2f %8.2f %8.2f[Clip:%5.2f>%8.1f][DOF:%5.2f>%8.1f][FOV:%5.2f][HDG:%.2f][PCH:%.2f]", renderedCameraName, position.x, position.y, position.z, GetNear(), GetFar(), GetNearDof(), GetFarDof(), GetFov(), GetHeading(), GetPitch()); if(renderedCamera->GetIsClassId(camFirstPersonShooterCamera::GetStaticClassId()) && Abs(GetRoll()) >= 0.001f) safecatf(debugString, debugStringLength, "[RLL:%2.3f]", GetRoll()); if( GetMotionBlurStrength() > SMALL_FLOAT ) { safecatf(debugString, debugStringLength, "[MB:%2.3f]", GetMotionBlurStrength()); } if(renderedCamera->GetIsClassId(camFirstPersonShooterCamera::GetStaticClassId())) { const camFirstPersonShooterCamera* fpsCamera = (const camFirstPersonShooterCamera*)renderedCamera; if(Abs(fpsCamera->GetRelativeHeading()) > SMALL_FLOAT) { safecatf(debugString, debugStringLength, "[rH:%.3f]", fpsCamera->GetRelativeHeading()); } if(Abs(fpsCamera->GetRelativePitch()) > SMALL_FLOAT) { safecatf(debugString, debugStringLength, "[rP:%.3f]", fpsCamera->GetRelativePitch()); } } } else #endif { formatf(debugString, debugStringLength, "%s: %8.2f %8.2f %8.2f[Clip:%5.2f>%8.2f][DOF:%5.2f>%8.2f][FOV:%5.2f][HDG:%.2f][MB:%2.3f]", renderedCameraName, position.x, position.y, position.z, GetNear(), GetFar(), GetNearDof(), GetFarDof(), GetFov(), GetHeading(), GetMotionBlurStrength()); } GetScriptDirector().DebugBuildCameraStringForTextDisplay(debugString, debugStringLength); grcDebugDraw::AddDebugOutput(debugString); } if(ms_DebugShouldDisplayGameViewportInfo) { CViewport *viewport = gVpMan.GetGameViewport(); if(viewport) { const grcViewport& grcVp = viewport->GetGrcViewport(); const Vector2 shear = grcVp.GetPerspectiveShear(); formatf(debugString, debugStringLength, "Game VPort:[AR %5.3f][WIN %dx%d][FOVY %5.3f][TANHFOV %5.3f][TANVFOV %5.3f][SHEARX %.1f][SHEARY %.1f]", grcVp.GetAspectRatio(), grcVp.GetWidth(), grcVp.GetHeight(), grcVp.GetFOVY(), grcVp.GetTanHFOV(), grcVp.GetTanVFOV(), shear.x, shear.y); } else { debugString[0] = '\0'; } grcDebugDraw::AddDebugOutput(debugString); } const bool shouldDisplay = camManager::GetFramePropagator().ComputeDebugOutputText(debugString, debugStringLength); if(shouldDisplay) { grcDebugDraw::AddDebugOutput(debugString); } } void camInterface::DebugDumpSpectatorPedInfo() { if(NetworkInterface::IsGameInProgress() && NetworkInterface::IsInSpectatorMode()) { ObjectId objid = NetworkInterface::GetSpectatorObjectId(); Printf("In Spectator Mode - Dump Network Object Id Info\n"); Printf("================================================\n"); Printf("Network Object Id=\"%d\"\n", objid); Printf("================================================\n"); netObject* netobj = NetworkInterface::GetNetworkObject(objid); if(netobj) { NetworkObjectType objtype = netobj->GetObjectType(); if (AssertVerify(objtype == NET_OBJ_TYPE_PLAYER || objtype == NET_OBJ_TYPE_PED)) { CPed* ped = static_cast(static_cast(netobj)->GetPed()); if(AssertVerify(ped)) { cameraDisplayf("%s: Network ObjId#%d address %p pedID %d\n", objtype == NET_OBJ_TYPE_PLAYER ? "Player" : "Ped", objid, ped, CPed::GetPool()->GetIndex(ped)); } } } } } void camInterface::DebugSetRespotCounterOnDebugFocusVehicle() { CEntity* debugFocusEntity = CDebugScene::FocusEntities_Get(0); if(debugFocusEntity && debugFocusEntity->GetIsTypeVehicle()) { static_cast(debugFocusEntity)->SetFlashLocallyDuringRespotting(ms_DebugFlashLocallyWhileRespotting); static_cast(debugFocusEntity)->SetFlashRemotelyDuringRespotting(ms_DebugFlashRemotelyWhileRespotting); static_cast(debugFocusEntity)->SetRespotCounter(ms_DebugRespotCounter); } } void camInterface::UpdateAtEndOfFrame() { if (ms_DebugShouldRestartSystemAtEndOfFrame) { camManager::Shutdown(SHUTDOWN_SESSION); camManager::Init(INIT_SESSION); ms_DebugShouldRestartSystemAtEndOfFrame = false; } } #endif // __BANK #if RSG_PC bool camInterface::IsTripleHeadDisplay() { const float sceneWidth = static_cast(VideoResManager::GetSceneWidth()); const float sceneHeight = static_cast(VideoResManager::GetSceneHeight()); const float viewportAspect = sceneWidth / sceneHeight; const float baseLineAspectRatio = 4.0f/3.0f; const float wideScreenAspectRatio = baseLineAspectRatio * baseLineAspectRatio; //16:9 const float ultraWideScreenAspectRatio = wideScreenAspectRatio * baseLineAspectRatio; //21:9 //we arbitrarily pick up a point in between the wide and ultra-wide aspect ratio. This because we often see windowed resolutions //which have an aspect ratio bigger than 16:9 screen but smaller than 21:9 const float minValueToConsiderTripleHead = (wideScreenAspectRatio + ultraWideScreenAspectRatio) * 0.5f; //mid point const bool isTripleHeadDisplay = viewportAspect >= minValueToConsiderTripleHead; TUNE_BOOL(FORCE_TRIPLEHEAD_CAMERA_CODE_EVERYWHERE, false); return isTripleHeadDisplay || FORCE_TRIPLEHEAD_CAMERA_CODE_EVERYWHERE; } #endif