Skip to content

Commit ac7351f

Browse files
authored
Fix camera behavior and getCameraMatrix return values (#1282 & #1284) (#4393)
* align getCameraMatrix FOV/roll with actual rendering and improve transitions * Refactor CClientCamera * Refactor
1 parent 8dcc207 commit ac7351f

File tree

7 files changed

+116
-21
lines changed

7 files changed

+116
-21
lines changed

Client/game_sa/CCameraSA.cpp

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -565,7 +565,53 @@ void CCameraSA::ResetShakeCamera() noexcept
565565
GetInterface()->m_fCamShakeForce = 0.0f;
566566
}
567567

568-
std::uint8_t CCameraSA::GetTransitionState()
568+
std::uint8_t CCameraSA::GetTransitionState() const
569569
{
570570
return GetInterface()->m_uiTransitionState;
571571
}
572+
573+
bool CCameraSA::IsInTransition() const
574+
{
575+
return GetTransitionState() != 0;
576+
}
577+
578+
float CCameraSA::GetTransitionFOV() const
579+
{
580+
CCameraSAInterface* cameraInterface = GetInterface();
581+
return cameraInterface ? cameraInterface->FOVDuringInter : DEFAULT_FOV;
582+
}
583+
584+
bool CCameraSA::GetTransitionMatrix(CMatrix& matrix) const
585+
{
586+
CCameraSAInterface* cameraInterface = GetInterface();
587+
if (!cameraInterface || !IsInTransition())
588+
return false;
589+
590+
CVector source = cameraInterface->SourceDuringInter;
591+
CVector target = cameraInterface->TargetDuringInter;
592+
CVector up = cameraInterface->UpDuringInter;
593+
594+
CVector forward = target - source;
595+
if (forward.Length() < FLOAT_EPSILON)
596+
forward = CVector(0.0f, 1.0f, 0.0f);
597+
else
598+
forward.Normalize();
599+
600+
CVector right = CVector(forward.fY, -forward.fX, 0.0f);
601+
if (right.Length() < FLOAT_EPSILON)
602+
right = CVector(1.0f, 0.0f, 0.0f);
603+
else
604+
right.Normalize();
605+
606+
CVector correctedUp = right;
607+
correctedUp.CrossProduct(&forward);
608+
correctedUp.Normalize();
609+
610+
matrix.vPos = source;
611+
matrix.vFront = forward;
612+
matrix.vRight = -right;
613+
matrix.vUp = correctedUp;
614+
matrix.OrthoNormalize(CMatrix::AXIS_FRONT, CMatrix::AXIS_UP);
615+
616+
return true;
617+
}

Client/game_sa/CCameraSA.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,7 @@ class CCameraSA : public CCamera
381381
CCameraSA(CCameraSAInterface* cameraInterface);
382382
~CCameraSA();
383383

384-
CCameraSAInterface* GetInterface() { return internalInterface; };
384+
CCameraSAInterface* GetInterface() const noexcept { return internalInterface; }
385385

386386
// CCamera interface implementation
387387
void TakeControl(CEntity* entity, eCamMode CamMode, int CamSwitchStyle) override;
@@ -413,7 +413,10 @@ class CCameraSA : public CCamera
413413
float GetShakeForce() override;
414414
void ShakeCamera(float radius, float x, float y, float z) noexcept override;
415415
void ResetShakeCamera() noexcept override;
416-
std::uint8_t GetTransitionState() override;
416+
std::uint8_t GetTransitionState() const override;
417+
bool IsInTransition() const override;
418+
float GetTransitionFOV() const override;
419+
bool GetTransitionMatrix(CMatrix& matrix) const override;
417420

418421
// Additional overload not in base interface
419422
virtual CCam* GetCam(CCamSAInterface* camInterface);

Client/mods/deathmatch/logic/CClientCamera.cpp

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313

1414
#define PI_2 6.283185307179586476925286766559f
1515

16+
// Camera FOV constants
17+
constexpr const std::uintptr_t VAR_CurrentCameraFOV = 0x8D5038; // CCamera::CurrentFOV
18+
1619
CClientCamera::CClientCamera(CClientManager* pManager) : ClassInit(this), CClientEntity(INVALID_ELEMENT_ID)
1720
{
1821
CClientEntityRefManager::AddEntityRefs(ENTITY_REF_DEBUG(this, "CClientCamera"), &m_pFocusedPlayer, &m_pFocusedEntity, NULL);
@@ -27,7 +30,7 @@ CClientCamera::CClientCamera(CClientManager* pManager) : ClassInit(this), CClien
2730
m_bInvalidated = false;
2831
m_bFixed = false;
2932
m_fRoll = 0.0f;
30-
m_fFOV = 70.0f;
33+
m_fFOV = DEFAULT_FOV;
3134
SetTypeName("camera");
3235

3336
m_pCamera = g_pGame->GetCamera();
@@ -359,7 +362,7 @@ void CClientCamera::SetFocus(CClientEntity* pEntity, eCamMode eMode, bool bSmoot
359362
}
360363

361364
m_fRoll = 0.0f;
362-
m_fFOV = 70.0f;
365+
m_fFOV = DEFAULT_FOV;
363366
}
364367

365368
void CClientCamera::SetFocus(CClientPlayer* pPlayer, eCamMode eMode, bool bSmoothTransition)
@@ -387,7 +390,7 @@ void CClientCamera::SetFocus(CClientPlayer* pPlayer, eCamMode eMode, bool bSmoot
387390
// Store the player we focused
388391
m_pFocusedPlayer = pPlayer;
389392
m_fRoll = 0.0f;
390-
m_fFOV = 70.0f;
393+
m_fFOV = DEFAULT_FOV;
391394
m_bFixed = false;
392395
}
393396

@@ -427,7 +430,7 @@ void CClientCamera::Reset()
427430
m_pFocusedGameEntity = NULL;
428431
m_bFixed = false;
429432
m_fRoll = 0.0f;
430-
m_fFOV = 70.0f;
433+
m_fFOV = DEFAULT_FOV;
431434
}
432435

433436
void CClientCamera::SetFocusToLocalPlayerImpl()
@@ -542,7 +545,7 @@ void CClientCamera::ToggleCameraFixedMode(bool bEnabled)
542545
SetFocusToLocalPlayer();
543546

544547
m_fRoll = 0.0f;
545-
m_fFOV = 70.0f;
548+
m_fFOV = DEFAULT_FOV;
546549
}
547550
}
548551

@@ -606,6 +609,9 @@ bool CClientCamera::ProcessFixedCamera(CCam* pCam)
606609
//
607610
CMatrix CClientCamera::GetGtaMatrix() const
608611
{
612+
if (IsInCameraTransition())
613+
return GetInterpolatedCameraMatrix();
614+
609615
CCam* pCam = m_pCamera->GetCam(m_pCamera->GetActiveCam());
610616

611617
CMatrix matResult;
@@ -644,3 +650,28 @@ void CClientCamera::ResetShakeCamera() noexcept
644650
{
645651
m_pCamera->ResetShakeCamera();
646652
}
653+
654+
bool CClientCamera::IsInCameraTransition() const
655+
{
656+
return m_pCamera ? m_pCamera->IsInTransition() : false;
657+
}
658+
659+
CMatrix CClientCamera::GetInterpolatedCameraMatrix() const
660+
{
661+
CMatrix matrix;
662+
if (m_pCamera && m_pCamera->GetTransitionMatrix(matrix))
663+
return matrix;
664+
665+
return CMatrix();
666+
}
667+
668+
float CClientCamera::GetAccurateFOV() const
669+
{
670+
if (!m_pCamera)
671+
return DEFAULT_FOV;
672+
673+
if (IsInCameraTransition())
674+
return m_pCamera->GetTransitionFOV();
675+
676+
return *(float*)VAR_CurrentCameraFOV;
677+
}

Client/mods/deathmatch/logic/CClientCamera.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,10 @@ class CClientCamera final : public CClientEntity
8282

8383
void UnreferencePlayer(CClientPlayer* pPlayer);
8484

85+
bool IsInCameraTransition() const;
86+
CMatrix GetInterpolatedCameraMatrix() const;
87+
float GetAccurateFOV() const;
88+
8589
private:
8690
CClientCamera(CClientManager* pManager);
8791
~CClientCamera();

Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5007,7 +5007,16 @@ bool CStaticFunctionDefinitions::GetCameraMatrix(CVector& vecPosition, CVector&
50075007
{
50085008
m_pCamera->GetPosition(vecPosition);
50095009
m_pCamera->GetFixedTarget(vecLookAt, &fRoll);
5010-
fFOV = m_pCamera->GetFOV();
5010+
5011+
fFOV = m_pCamera->GetAccurateFOV();
5012+
5013+
if (!m_pCamera->IsInFixedMode() && fRoll == 0.0f)
5014+
{
5015+
CVector rotation;
5016+
m_pCamera->GetRotationDegrees(rotation);
5017+
fRoll = rotation.fZ;
5018+
}
5019+
50115020
return true;
50125021
}
50135022

Client/sdk/game/CCamera.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ class CMatrix;
1717
class CCam;
1818
struct RwMatrix;
1919

20+
// Camera constants
21+
constexpr const float DEFAULT_FOV = 70.0f;
22+
2023
enum eCamMode
2124
{
2225
MODE_NONE = 0,
@@ -147,5 +150,8 @@ class CCamera
147150
virtual void ShakeCamera(float radius, float x, float y, float z) noexcept = 0;
148151
virtual void ResetShakeCamera() noexcept = 0;
149152

150-
virtual std::uint8_t GetTransitionState() = 0;
153+
virtual std::uint8_t GetTransitionState() const = 0;
154+
virtual bool IsInTransition() const = 0;
155+
virtual float GetTransitionFOV() const = 0;
156+
virtual bool GetTransitionMatrix(CMatrix& matrix) const = 0;
151157
};

Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4621,17 +4621,13 @@ bool CStaticFunctionDefinitions::GetCameraMatrix(CPlayer* pPlayer, CVector& vecP
46214621
assert(pPlayer);
46224622

46234623
CPlayerCamera* pCamera = pPlayer->GetCamera();
4624-
4625-
// Only allow this if we're in fixed mode?
4626-
if (pCamera->GetMode() == CAMERAMODE_FIXED)
4627-
{
4628-
pCamera->GetPosition(vecPosition);
4629-
pCamera->GetLookAt(vecLookAt);
4630-
fRoll = pCamera->GetRoll();
4631-
fFOV = pCamera->GetFOV();
4632-
return true;
4633-
}
4634-
return false;
4624+
4625+
pCamera->GetPosition(vecPosition);
4626+
pCamera->GetLookAt(vecLookAt);
4627+
fRoll = pCamera->GetRoll();
4628+
fFOV = pCamera->GetFOV();
4629+
4630+
return true;
46354631
}
46364632

46374633
CElement* CStaticFunctionDefinitions::GetCameraTarget(CPlayer* pPlayer)

0 commit comments

Comments
 (0)