From 75094ca39af64e4fe8083cb119d6fb97eedb8630 Mon Sep 17 00:00:00 2001 From: Jack Andersen Date: Fri, 6 Oct 2017 19:32:11 -1000 Subject: [PATCH] Finish CFirstPersonCamera --- Runtime/Camera/CCameraManager.cpp | 29 +++-- Runtime/Camera/CCameraManager.hpp | 3 +- Runtime/Camera/CFirstPersonCamera.cpp | 128 +++++++++++++++++---- Runtime/Camera/CFirstPersonCamera.hpp | 25 ++-- Runtime/Camera/CGameCamera.cpp | 2 +- Runtime/Camera/CGameCamera.hpp | 3 +- Runtime/MkCastTo.py | 2 + Runtime/World/CPlayer.cpp | 2 +- Runtime/World/CPlayerCameraBob.cpp | 2 +- Runtime/World/CScriptCameraPitchVolume.cpp | 8 +- Runtime/World/CScriptCameraPitchVolume.hpp | 12 +- 11 files changed, 151 insertions(+), 65 deletions(-) diff --git a/Runtime/Camera/CCameraManager.cpp b/Runtime/Camera/CCameraManager.cpp index 2ce6c5138..b064f0ee8 100644 --- a/Runtime/Camera/CCameraManager.cpp +++ b/Runtime/Camera/CCameraManager.cpp @@ -146,13 +146,6 @@ void CCameraManager::SkipCinematic(CStateManager& stateMgr) x7c_fpCamera->SkipCinematic(); } -float CCameraManager::sub80009148() const -{ - const zeus::CVector3f uVec = x7c_fpCamera->GetTransform().upVector(); - return 1.f - std::min(std::fabs(std::min(std::fabs(uVec.dot(zeus::CVector3f::skUp)), 1.f) / - std::cos(zeus::degToRad(30.f))), 1.f); -} - void CCameraManager::SetPathCamera(TUniqueId id, CStateManager& mgr) { xa4_pathCamId = id; @@ -663,12 +656,30 @@ void CCameraManager::RenderCameras(const CStateManager& mgr) void CCameraManager::SetupBallCamera(CStateManager& mgr) { - + if (TCastToPtr hint = mgr.ObjectById(xa6_camHintId)) + { + if (hint->GetHint().GetBehaviourType() == CBallCamera::EBallCameraBehaviour::Three) + { + if ((hint->GetHint().GetOverrideFlags() & 0x20) != 0) + x80_ballCamera->TeleportCamera(hint->GetTransform(), mgr); + AddInactiveCameraHint(xa6_camHintId, mgr); + } + else + { + ApplyCameraHint(*hint, mgr); + } + } } void CCameraManager::SetPlayerCamera(CStateManager& mgr, TUniqueId newCamId) { - + if (x88_interpCamera->GetActive()) + { + x88_interpCamera->SetActive(false); + x80_ballCamera->SkipFovInterpolation(); + if (!ShouldBypassInterpolation()) + SetCurrentCameraId(newCamId, mgr); + } } float CCameraManager::GetCameraBobMagnitude() const diff --git a/Runtime/Camera/CCameraManager.hpp b/Runtime/Camera/CCameraManager.hpp index 1da8e295c..da31bbb81 100644 --- a/Runtime/Camera/CCameraManager.hpp +++ b/Runtime/Camera/CCameraManager.hpp @@ -126,7 +126,7 @@ public: CBallCamera* GetBallCamera() { return x80_ballCamera; } CGameArea::CAreaFog& Fog() { return x3c_fog; } - float sub80009148() const; + float GetCameraBobMagnitude() const; void UpdateCameraHints(float dt, CStateManager& mgr); void ThinkCameras(float dt, CStateManager& mgr); @@ -142,7 +142,6 @@ public: void SetupBallCamera(CStateManager& mgr); void SetPlayerCamera(CStateManager& mgr, TUniqueId newCamId); int GetFluidCounter() const { return x74_fluidCounter; } - float GetCameraBobMagnitude() const; bool HasBallCameraInitialPositionHint(CStateManager& mgr) const; void DeleteCameraHint(TUniqueId id, CStateManager& mgr); diff --git a/Runtime/Camera/CFirstPersonCamera.cpp b/Runtime/Camera/CFirstPersonCamera.cpp index 43eda35fc..2cc22a884 100644 --- a/Runtime/Camera/CFirstPersonCamera.cpp +++ b/Runtime/Camera/CFirstPersonCamera.cpp @@ -1,13 +1,10 @@ #include "CFirstPersonCamera.hpp" #include "GameGlobalObjects.hpp" -#include "Character/CCharLayoutInfo.hpp" #include "CStateManager.hpp" #include "World/CPlayer.hpp" -#include "World/CPlayerCameraBob.hpp" #include "World/CScriptGrapplePoint.hpp" -#include "Particle/CGenDescription.hpp" +#include "World/CScriptCameraPitchVolume.hpp" #include "TCastTo.hpp" -#include namespace urde { @@ -15,8 +12,10 @@ namespace urde CFirstPersonCamera::CFirstPersonCamera(TUniqueId uid, const zeus::CTransform& xf, TUniqueId watchedObj, float orbitCameraSpeed, float fov, float nearz, float farz, float aspect) : CGameCamera(uid, true, "First Person Camera", CEntityInfo(kInvalidAreaId, CEntity::NullConnectionList), xf, fov, - nearz, farz, aspect, watchedObj, false, 0), x188_orbitCameraSpeed(orbitCameraSpeed) + nearz, farz, aspect, watchedObj, false, 0), x188_orbitCameraSpeed(orbitCameraSpeed), + x190_gunFollowXf(xf) { + x1c6_24_deferBallTransitionProcessing = false; } void CFirstPersonCamera::Accept(IVisitor& visitor) @@ -24,21 +23,65 @@ void CFirstPersonCamera::Accept(IVisitor& visitor) visitor.Visit(this); } -void CFirstPersonCamera::PreThink(float, CStateManager&) {} - -void CFirstPersonCamera::Think(float, CStateManager&) +void CFirstPersonCamera::PreThink(float dt, CStateManager& mgr) { - + // Empty } -void CFirstPersonCamera::ProcessInput(const CFinalInput&, CStateManager& mgr) {} +void CFirstPersonCamera::Think(float dt, CStateManager& mgr) +{ + if (TCastToPtr player = mgr.ObjectById(xe8_watchedObject)) + { + if (!x1c6_24_deferBallTransitionProcessing) + { + if (player->GetMorphballTransitionState() == CPlayer::EPlayerMorphBallState::Morphed) + { + if (player->GetCameraState() != CPlayer::EPlayerCameraState::Spawned) + return; + SetTransform(player->CreateTransformFromMovementDirection()); + SetTranslation(player->GetEyePosition()); + return; + } + if (player->GetMorphballTransitionState() != CPlayer::EPlayerMorphBallState::Unmorphed) + { + if (player->GetMorphballTransitionState() != CPlayer::EPlayerMorphBallState::Unmorphing) + return; + float morphFactor = 0.f; + if (player->GetMorphDuration() != 0.f) + morphFactor = zeus::clamp(0.f, player->GetMorphTime() / player->GetMorphDuration(), 1.f); + if (std::fabs(morphFactor - 1.f) >= 0.00001f) + return; + } + } + else + { + x1c6_24_deferBallTransitionProcessing = false; + } + zeus::CTransform backupXf = x34_transform; + UpdateElevation(mgr); + UpdateTransform(mgr, dt); + SetTransform(ValidateCameraTransform(x34_transform, backupXf)); + if (x1d4_closeInTimer > 0.f) + x1d4_closeInTimer -= dt; + } +} -void CFirstPersonCamera::Reset(const zeus::CTransform&, CStateManager& mgr) {} +void CFirstPersonCamera::ProcessInput(const CFinalInput&, CStateManager& mgr) +{ + // Empty +} + +void CFirstPersonCamera::Reset(const zeus::CTransform& xf, CStateManager& mgr) +{ + SetTransform(xf); + SetTranslation(mgr.GetPlayer().GetEyePosition()); + x190_gunFollowXf = x34_transform; +} void CFirstPersonCamera::SkipCinematic() { - x1c8_ = zeus::CVector3f::skZero; - x1d4_ = 0.f; + x1c8_closeInVec = zeus::CVector3f::skZero; + x1d4_closeInTimer = 0.f; } void CFirstPersonCamera::CalculateGunFollowOrientationAndTransform(zeus::CTransform& gunXf, zeus::CQuaternion& gunQ, @@ -80,11 +123,11 @@ void CFirstPersonCamera::UpdateTransform(CStateManager& mgr, float dt) zeus::CTransform playerXf = player->GetTransform(); zeus::CVector3f rVec = - playerXf.rotate({0.f, std::min(std::fabs(std::cos(x1c0_)), 1.0f), std::min(std::fabs(std::sin(x1c0_)), 1.0f)}); + playerXf.rotate({0.f, std::min(std::fabs(std::cos(x1c0_pitch)), 1.0f), std::min(std::fabs(std::sin(x1c0_pitch)), 1.0f)}); if (player->x3dc_inFreeLook) { float angle = player->x3ec_freeLookPitchAngle; - float angleClamp = g_tweakPlayer->GetVerticalFreeLookAngleVel() - std::fabs(x1c0_); + float angleClamp = g_tweakPlayer->GetVerticalFreeLookAngleVel() - std::fabs(x1c0_pitch); angle = zeus::clamp(-angleClamp, angle, angleClamp); zeus::CVector3f vec; vec.z = std::sin(angle); @@ -97,9 +140,9 @@ void CFirstPersonCamera::UpdateTransform(CStateManager& mgr, float dt) } zeus::CVector3f eyePos = player->GetEyePosition(); - if (x1d4_ > 0.f) + if (x1d4_closeInTimer > 0.f) { - eyePos += zeus::clamp(0.f, 0.5f * x1d4_, 1.f) * x1c8_; + eyePos += zeus::clamp(0.f, 0.5f * x1d4_closeInTimer, 1.f) * x1c8_closeInVec; player->GetCameraBob()->ResetCameraBobTime(); player->GetCameraBob()->SetCameraBobTransform(zeus::CTransform::Identity()); } @@ -126,7 +169,7 @@ void CFirstPersonCamera::UpdateTransform(CStateManager& mgr, float dt) float angle = zeus::clamp(0.f, (player->x294_jumpCameraTimer - g_tweakPlayer->GetJumpCameraPitchDownStart()) / g_tweakPlayer->GetJumpCameraPitchDownFull(), 1.f) * g_tweakPlayer->GetJumpCameraPitchDownAngle(); - angle += x1c0_; + angle += x1c0_pitch; rVec.x = 0.f; rVec.y = std::cos(angle); rVec.z = -std::sin(angle); @@ -191,13 +234,12 @@ void CFirstPersonCamera::UpdateTransform(CStateManager& mgr, float dt) if (gunFrontVec.canBeNormalized()) gunFrontVec.normalize(); - /* BUG: This is exactly what the runtime is doing, should we restore the intended behavior? */ float angle = gunFrontVec.dot(rVec); float sdt = dt * g_tweakPlayer->GetGrappleCameraSpeed(); angle = zeus::clamp(-1.f, angle, 1.f); - angle = zeus::clamp(0.f, std::acos(angle) / sdt, 1.f); - qGun = zeus::CQuaternion::lookAt(rVec, gunFrontVec, zeus::CRelAngle::FromDegrees(360.f)); + angle = zeus::clamp(0.f, std::acos(angle) / sdt, 1.f) * sdt; + qGun = zeus::CQuaternion::lookAt(rVec, gunFrontVec, angle); } } else if (player->GetOrbitState() == CPlayer::EPlayerOrbitState::OrbitPoint || @@ -259,5 +301,47 @@ void CFirstPersonCamera::UpdateTransform(CStateManager& mgr, float dt) x190_gunFollowXf.orthonormalize(); } -void CFirstPersonCamera::UpdateElevation(CStateManager&) {} +void CFirstPersonCamera::UpdateElevation(CStateManager& mgr) +{ + x1c0_pitch = 0.f; + if (TCastToConstPtr player = mgr.GetObjectById(xe8_watchedObject)) + { + if (x1c4_pitchId != kInvalidUniqueId) + { + if (TCastToConstPtr pvol = mgr.GetObjectById(x1c4_pitchId)) + { + zeus::CVector3f pitchDirFlat = pvol->GetTransform().basis[1]; + pitchDirFlat.z = 0.f; + if (!pitchDirFlat.canBeNormalized()) + pitchDirFlat = zeus::CVector3f::skForward; + + zeus::CVector3f playerDirFlat = player->GetTransform().basis[1]; + playerDirFlat.z = 0.f; + playerDirFlat.normalize(); + + float pitchDot = zeus::clamp(-1.f, pitchDirFlat.dot(playerDirFlat), 1.f); + if (pitchDot < 0.f) + x1c0_pitch = pvol->GetDownPitch() * -pitchDot; + else + x1c0_pitch = pvol->GetUpPitch() * -pitchDot; + + zeus::CVector3f pvolToPlayerFlat = player->GetTranslation() - pvol->GetTranslation(); + pvolToPlayerFlat.z = 0.f; + float pitchMul = 0.f; + if (pvolToPlayerFlat.canBeNormalized()) + { + float pvolPlayerProj = + std::fabs(zeus::clamp(-1.f, pvolToPlayerFlat.dot(pitchDirFlat), 1.f)) * + pvolToPlayerFlat.magnitude(); + if (pvolPlayerProj <= pvol->GetMaxInterpolationDistance()) + pitchMul = 1.f; + else + pitchMul = 1.f - zeus::clamp(-1.f, (pvolPlayerProj - pvol->GetMaxInterpolationDistance()) / + (pvol->GetScale().y - pvol->GetMaxInterpolationDistance()), 1.f); + } + x1c0_pitch *= pitchMul; + } + } + } +} } diff --git a/Runtime/Camera/CFirstPersonCamera.hpp b/Runtime/Camera/CFirstPersonCamera.hpp index c4bc4faf1..dc9f73eb0 100644 --- a/Runtime/Camera/CFirstPersonCamera.hpp +++ b/Runtime/Camera/CFirstPersonCamera.hpp @@ -11,37 +11,30 @@ class CFirstPersonCamera : public CGameCamera float x188_orbitCameraSpeed; bool x18c_lockCamera = false; zeus::CTransform x190_gunFollowXf; - float x1c0_ = 0.f; + float x1c0_pitch = 0.f; TUniqueId x1c4_pitchId = kInvalidUniqueId; - union { - struct - { - bool x1c6_24_ : 1; - }; - u16 _dummy = 0; - }; - - zeus::CVector3f x1c8_; - float x1d4_ = 0.f; + bool x1c6_24_deferBallTransitionProcessing : 1; + zeus::CVector3f x1c8_closeInVec; + float x1d4_closeInTimer = 0.f; public: CFirstPersonCamera(TUniqueId, const zeus::CTransform& xf, TUniqueId, float orbitCameraSpeed, float fov, float nearplane, float farplane, float aspect); void Accept(IVisitor& visitor); - void PreThink(float, CStateManager&); - void Think(float, CStateManager&); + void PreThink(float dt, CStateManager& mgr); + void Think(float dt, CStateManager& mgr); void ProcessInput(const CFinalInput&, CStateManager& mgr); void Reset(const zeus::CTransform&, CStateManager& mgr); void SkipCinematic(); const zeus::CTransform& GetGunFollowTransform() const { return x190_gunFollowXf; } - void UpdateTransform(CStateManager&, float dt); - void UpdateElevation(CStateManager&); + void UpdateTransform(CStateManager& mgr, float dt); + void UpdateElevation(CStateManager& mgr); void CalculateGunFollowOrientationAndTransform(zeus::CTransform&, zeus::CQuaternion&, float, zeus::CVector3f&); void SetScriptPitchId(TUniqueId uid) { x1c4_pitchId = uid; } void SetLockCamera(bool v) { x18c_lockCamera = v; } - void SetX1C6_24(bool v) { x1c6_24_ = v; } + void DeferBallTransitionProcessing() { x1c6_24_deferBallTransitionProcessing = true; } }; } diff --git a/Runtime/Camera/CGameCamera.cpp b/Runtime/Camera/CGameCamera.cpp index 779fbd70d..0a2f447ad 100644 --- a/Runtime/Camera/CGameCamera.cpp +++ b/Runtime/Camera/CGameCamera.cpp @@ -146,7 +146,7 @@ void CGameCamera::SetFovInterpolation(float start, float fov, float time, float } } -void CGameCamera::sub8005AF88() +void CGameCamera::SkipFovInterpolation() { if (x178_ > 0) { diff --git a/Runtime/Camera/CGameCamera.hpp b/Runtime/Camera/CGameCamera.hpp index 54c7a197c..42df99078 100644 --- a/Runtime/Camera/CGameCamera.hpp +++ b/Runtime/Camera/CGameCamera.hpp @@ -13,6 +13,7 @@ class CGameCamera : public CActor friend class CStateManager; friend class CCameraManager; +protected: TUniqueId xe8_watchedObject; zeus::CMatrix4f xec_perspectiveMatrix; zeus::CTransform x12c_; @@ -50,7 +51,7 @@ public: bool DisablesInput() const; void UpdatePerspective(float); void SetFovInterpolation(float start, float end, float time, float f4); - void sub8005AF88(); + void SkipFovInterpolation(); }; } diff --git a/Runtime/MkCastTo.py b/Runtime/MkCastTo.py index 519f7053b..3f187e983 100644 --- a/Runtime/MkCastTo.py +++ b/Runtime/MkCastTo.py @@ -127,6 +127,7 @@ for tp in CENTITY_TYPES: headerf.write(''' T* GetPtr() const { return ptr; } operator T*() const { return GetPtr(); } + T& operator*() const { return *GetPtr(); } T* operator->() const { return GetPtr(); } operator bool() const { return ptr != nullptr; } }; @@ -140,6 +141,7 @@ public: TCastToConstPtr(const CEntity& p) : TCastToPtr(const_cast(p)) {} const T* GetPtr() const { return TCastToPtr::ptr; } operator const T*() const { return GetPtr(); } + const T& operator*() const { return *GetPtr(); } const T* operator->() const { return GetPtr(); } operator bool() const { return TCastToPtr::ptr != nullptr; } }; diff --git a/Runtime/World/CPlayer.cpp b/Runtime/World/CPlayer.cpp index d3a957c64..2a43d5c35 100644 --- a/Runtime/World/CPlayer.cpp +++ b/Runtime/World/CPlayer.cpp @@ -6175,7 +6175,7 @@ void CPlayer::LeaveMorphBallState(CStateManager& mgr) mgr.GetCameraManager()->SetPlayerCamera(mgr, mgr.GetCameraManager()->GetFirstPersonCamera()->GetUniqueId()); mgr.GetCameraManager()->GetBallCamera()->SetState(CBallCamera::EBallCameraState::Zero, mgr); SetCameraState(EPlayerCameraState::FirstPerson, mgr); - mgr.GetCameraManager()->GetFirstPersonCamera()->SetX1C6_24(true); + mgr.GetCameraManager()->GetFirstPersonCamera()->DeferBallTransitionProcessing(); mgr.GetCameraManager()->GetFirstPersonCamera()->Think(0.f, mgr); ForceGunOrientation(x34_transform, mgr); DrawGun(mgr); diff --git a/Runtime/World/CPlayerCameraBob.cpp b/Runtime/World/CPlayerCameraBob.cpp index 3194eceab..8bdf54abc 100644 --- a/Runtime/World/CPlayerCameraBob.cpp +++ b/Runtime/World/CPlayerCameraBob.cpp @@ -167,7 +167,7 @@ void CPlayerCameraBob::Update(float dt, CStateManager& mgr) else x104_ = 0.f; - float f1 = mgr.GetCameraManager()->sub80009148(); + float f1 = mgr.GetCameraManager()->GetCameraBobMagnitude(); x70_landingTranslation *= f1; x78_ *= f1; x104_ *= f1; diff --git a/Runtime/World/CScriptCameraPitchVolume.cpp b/Runtime/World/CScriptCameraPitchVolume.cpp index 0361fc4bd..cbd40a61f 100644 --- a/Runtime/World/CScriptCameraPitchVolume.cpp +++ b/Runtime/World/CScriptCameraPitchVolume.cpp @@ -18,8 +18,8 @@ CScriptCameraPitchVolume::CScriptCameraPitchVolume(TUniqueId uid, bool active, c : CActor(uid, active, name, info, xf, CModelData::CModelDataNull(), CMaterialList(EMaterialTypes::Trigger), CActorParameters::None(), kInvalidUniqueId) , xe8_obbox(xf, scale * skScaleFactor) -, x124_(r1) -, x128_(r2) +, x124_upPitch(r1) +, x128_downPitch(r2) , x12c_scale(scale * skScaleFactor) , x138_maxInterpDistance(maxInterpDistance) { @@ -61,10 +61,6 @@ void CScriptCameraPitchVolume::Touch(CActor& act, CStateManager& mgr) x13c_24_entered = xe8_obbox.AABoxIntersectsBox(plBox.value()); } -const zeus::CVector3f& CScriptCameraPitchVolume::GetScale() const { return x12c_scale; } - -float CScriptCameraPitchVolume::GetMaxInterpolationDistance() const { return x138_maxInterpDistance; } - void CScriptCameraPitchVolume::Entered(urde::CStateManager& mgr) { x13c_25_occupied = true; diff --git a/Runtime/World/CScriptCameraPitchVolume.hpp b/Runtime/World/CScriptCameraPitchVolume.hpp index 00ffa295f..f84bf09dd 100644 --- a/Runtime/World/CScriptCameraPitchVolume.hpp +++ b/Runtime/World/CScriptCameraPitchVolume.hpp @@ -11,8 +11,8 @@ class CScriptCameraPitchVolume : public CActor { static const zeus::CVector3f skScaleFactor; zeus::COBBox xe8_obbox; - zeus::CRelAngle x124_; - zeus::CRelAngle x128_; + zeus::CRelAngle x124_upPitch; + zeus::CRelAngle x128_downPitch; zeus::CVector3f x12c_scale; float x138_maxInterpDistance; @@ -33,10 +33,10 @@ public: void Think(float, CStateManager&); rstl::optional_object GetTouchBounds() const; void Touch(CActor&, CStateManager&); - const zeus::CRelAngle& GetUpPitch() const; - const zeus::CRelAngle& GetDownPitch() const; - const zeus::CVector3f& GetScale() const; - float GetMaxInterpolationDistance() const; + float GetUpPitch() const { return x124_upPitch; } + float GetDownPitch() const { return x128_downPitch; } + const zeus::CVector3f& GetScale() const { return x12c_scale; } + float GetMaxInterpolationDistance() const { return x138_maxInterpDistance; } void Entered(CStateManager&); void Exited(CStateManager&); };