mirror of
https://gitlab.com/GaryOderNichts/re3-wiiu.git
synced 2024-12-01 05:24:14 +01:00
1274 lines
41 KiB
C++
1274 lines
41 KiB
C++
#include "common.h"
|
|
#include "patcher.h"
|
|
#include "Draw.h"
|
|
#include "World.h"
|
|
#include "Vehicle.h"
|
|
#include "Ped.h"
|
|
#include "Pad.h"
|
|
#include "General.h"
|
|
#include "CullZones.h"
|
|
#include "SurfaceTable.h"
|
|
#include "MBlur.h"
|
|
#include "Camera.h"
|
|
|
|
const float DefaultFOV = 80.0f; // actually 70.0f
|
|
|
|
CCamera &TheCamera = *(CCamera*)0x6FACF8;
|
|
|
|
WRAPPER void CCamera::DrawBordersForWideScreen(void) { EAXJMP(0x46B430); }
|
|
|
|
bool
|
|
CCamera::IsSphereVisible(const CVector ¢er, float radius, const CMatrix *mat)
|
|
{
|
|
RwV3d c;
|
|
c = *(RwV3d*)¢er;
|
|
RwV3dTransformPoints(&c, &c, 1, &mat->m_matrix);
|
|
if(c.y + radius < CDraw::GetNearClipZ()) return false;
|
|
if(c.y - radius > CDraw::GetFarClipZ()) return false;
|
|
if(c.x*m_vecFrustumNormals[0].x + c.y*m_vecFrustumNormals[0].y > radius) return false;
|
|
if(c.x*m_vecFrustumNormals[1].x + c.y*m_vecFrustumNormals[1].y > radius) return false;
|
|
if(c.y*m_vecFrustumNormals[2].y + c.z*m_vecFrustumNormals[2].z > radius) return false;
|
|
if(c.y*m_vecFrustumNormals[3].y + c.z*m_vecFrustumNormals[3].z > radius) return false;
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
CCamera::IsPointVisible(const CVector ¢er, const CMatrix *mat)
|
|
{
|
|
RwV3d c;
|
|
c = *(RwV3d*)¢er;
|
|
RwV3dTransformPoints(&c, &c, 1, &mat->m_matrix);
|
|
if(c.y < CDraw::GetNearClipZ()) return false;
|
|
if(c.y > CDraw::GetFarClipZ()) return false;
|
|
if(c.x*m_vecFrustumNormals[0].x + c.y*m_vecFrustumNormals[0].y > 0.0f) return false;
|
|
if(c.x*m_vecFrustumNormals[1].x + c.y*m_vecFrustumNormals[1].y > 0.0f) return false;
|
|
if(c.y*m_vecFrustumNormals[2].y + c.z*m_vecFrustumNormals[2].z > 0.0f) return false;
|
|
if(c.y*m_vecFrustumNormals[3].y + c.z*m_vecFrustumNormals[3].z > 0.0f) return false;
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
CCamera::IsBoxVisible(RwV3d *box, const CMatrix *mat)
|
|
{
|
|
int i;
|
|
int frustumTests[6] = { 0 };
|
|
RwV3dTransformPoints(box, box, 8, &mat->m_matrix);
|
|
|
|
for(i = 0; i < 8; i++){
|
|
if(box[i].y < CDraw::GetNearClipZ()) frustumTests[0]++;
|
|
if(box[i].y > CDraw::GetFarClipZ()) frustumTests[1]++;
|
|
if(box[i].x*m_vecFrustumNormals[0].x + box[i].y*m_vecFrustumNormals[0].y > 0.0f) frustumTests[2]++;
|
|
if(box[i].x*m_vecFrustumNormals[1].x + box[i].y*m_vecFrustumNormals[1].y > 0.0f) frustumTests[3]++;
|
|
// Why not test z?
|
|
// if(box[i].y*m_vecFrustumNormals[2].y + box[i].z*m_vecFrustumNormals[2].z > 0.0f) frustumTests[4]++;
|
|
// if(box[i].y*m_vecFrustumNormals[3].y + box[i].z*m_vecFrustumNormals[3].z > 0.0f) frustumTests[5]++;
|
|
}
|
|
for(i = 0; i < 6; i++)
|
|
if(frustumTests[i] == 8)
|
|
return false; // Box is completely outside of one plane
|
|
return true;
|
|
}
|
|
|
|
int
|
|
CCamera::GetLookDirection(void)
|
|
{
|
|
if(Cams[ActiveCam].Mode == CCam::MODE_CAMONASTRING ||
|
|
Cams[ActiveCam].Mode == CCam::MODE_FIRSTPERSON ||
|
|
Cams[ActiveCam].Mode == CCam::MODE_BEHINDBOAT ||
|
|
Cams[ActiveCam].Mode == CCam::MODE_FOLLOWPED)
|
|
return Cams[ActiveCam].DirectionWasLooking;
|
|
return LOOKING_FORWARD;;
|
|
}
|
|
|
|
WRAPPER void CCamera::Fade(float timeout, int16 direction) { EAXJMP(0x46B3A0); }
|
|
WRAPPER void CCamera::ProcessFade(void) { EAXJMP(0x46F080); }
|
|
WRAPPER void CCamera::ProcessMusicFade(void) { EAXJMP(0x46F1E0); }
|
|
|
|
int
|
|
CCamera::GetScreenFadeStatus(void)
|
|
{
|
|
if(m_fFLOATingFade == 0.0f)
|
|
return FADE_0;
|
|
if(m_fFLOATingFade == 255.0f)
|
|
return FADE_2;
|
|
return FADE_1;
|
|
}
|
|
|
|
void
|
|
CCamera::SetFadeColour(uint8 r, uint8 g, uint8 b)
|
|
{
|
|
m_FadeTargetIsSplashScreen = r == 0 && g == 0 && b == 0;
|
|
CDraw::FadeRed = r;
|
|
CDraw::FadeGreen = g;
|
|
CDraw::FadeBlue = b;
|
|
}
|
|
|
|
void
|
|
CCamera::SetMotionBlur(int r, int g, int b, int a, int type)
|
|
{
|
|
m_BlurRed = r;
|
|
m_BlurGreen = g;
|
|
m_BlurBlue = b;
|
|
m_motionBlur = a;
|
|
m_BlurType = type;
|
|
}
|
|
|
|
void
|
|
CCamera::SetMotionBlurAlpha(int a)
|
|
{
|
|
m_imotionBlurAddAlpha = a;
|
|
}
|
|
|
|
void
|
|
CCamera::RenderMotionBlur(void)
|
|
{
|
|
if(m_BlurType == 0)
|
|
return;
|
|
|
|
CMBlur::MotionBlurRender(m_pRwCamera,
|
|
m_BlurRed, m_BlurGreen, m_BlurBlue,
|
|
m_motionBlur, m_BlurType, m_imotionBlurAddAlpha);
|
|
}
|
|
|
|
|
|
/*
|
|
*
|
|
* CCam
|
|
*
|
|
*/
|
|
|
|
|
|
// MaxSpeed is a limit of how fast the value is allowed to change. 1.0 = to Target in up to 1ms
|
|
// Acceleration is how fast the speed will change to MaxSpeed. 1.0 = to MaxSpeed in 1ms
|
|
void
|
|
WellBufferMe(float Target, float *CurrentValue, float *CurrentSpeed, float MaxSpeed, float Acceleration, bool IsAngle)
|
|
{
|
|
float Delta = Target - *CurrentValue;
|
|
|
|
if(IsAngle){
|
|
while(Delta >= PI) Delta -= 2*PI;
|
|
while(Delta < -PI) Delta += 2*PI;
|
|
}
|
|
|
|
float TargetSpeed = Delta * MaxSpeed;
|
|
// Add or subtract absolute depending on sign, genius!
|
|
// if(TargetSpeed - *CurrentSpeed > 0.0f)
|
|
// *CurrentSpeed += Acceleration * fabs(TargetSpeed - *CurrentSpeed) * CTimer::GetTimeStep();
|
|
// else
|
|
// *CurrentSpeed -= Acceleration * fabs(TargetSpeed - *CurrentSpeed) * CTimer::GetTimeStep();
|
|
// this is simpler:
|
|
*CurrentSpeed += Acceleration * (TargetSpeed - *CurrentSpeed) * CTimer::GetTimeStep();
|
|
|
|
// Clamp speed if we overshot
|
|
if(TargetSpeed < 0.0f && *CurrentSpeed < TargetSpeed)
|
|
*CurrentSpeed = TargetSpeed;
|
|
else if(TargetSpeed > 0.0f && *CurrentSpeed > TargetSpeed)
|
|
*CurrentSpeed = TargetSpeed;
|
|
|
|
*CurrentValue += *CurrentSpeed * min(10.0f, CTimer::GetTimeStep());
|
|
}
|
|
|
|
void
|
|
CCam::GetVectorsReadyForRW(void)
|
|
{
|
|
CVector right;
|
|
Up = CVector(0.0f, 0.0f, 1.0f);
|
|
Front.Normalise();
|
|
if(Front.x == 0.0f && Front.y == 0.0f){
|
|
Front.x = 0.0001f;
|
|
Front.y = 0.0001f;
|
|
}
|
|
right = CrossProduct(Front, Up);
|
|
right.Normalise();
|
|
Up = CrossProduct(right, Front);
|
|
}
|
|
|
|
// This code is really bad. wtf R*?
|
|
CVector
|
|
CCam::DoAverageOnVector(const CVector &vec)
|
|
{
|
|
int i;
|
|
CVector Average = { 0.0f, 0.0f, 0.0f };
|
|
|
|
if(ResetStatics){
|
|
m_iRunningVectorArrayPos = 0;
|
|
m_iRunningVectorCounter = 1;
|
|
}
|
|
|
|
// TODO: make this work with NUMBER_OF_VECTORS_FOR_AVERAGE != 2
|
|
if(m_iRunningVectorCounter == 3){
|
|
m_arrPreviousVectors[0] = m_arrPreviousVectors[1];
|
|
m_arrPreviousVectors[1] = vec;
|
|
}else
|
|
m_arrPreviousVectors[m_iRunningVectorArrayPos] = vec;
|
|
|
|
for(i = 0; i <= m_iRunningVectorArrayPos; i++)
|
|
Average += m_arrPreviousVectors[i];
|
|
Average /= i;
|
|
|
|
m_iRunningVectorArrayPos++;
|
|
m_iRunningVectorCounter++;
|
|
if(m_iRunningVectorArrayPos >= NUMBER_OF_VECTORS_FOR_AVERAGE)
|
|
m_iRunningVectorArrayPos = NUMBER_OF_VECTORS_FOR_AVERAGE-1;
|
|
if(m_iRunningVectorCounter > NUMBER_OF_VECTORS_FOR_AVERAGE+1)
|
|
m_iRunningVectorCounter = NUMBER_OF_VECTORS_FOR_AVERAGE+1;
|
|
|
|
return Average;
|
|
}
|
|
|
|
// Rotate Beta in direction opposite of BetaOffset in 5 deg. steps.
|
|
// Return the first angle for which Beta + BetaOffset + Angle has a clear view.
|
|
// i.e. BetaOffset is a safe zone so that Beta + Angle is really clear.
|
|
// If BetaOffset == 0, try both directions.
|
|
float
|
|
CCam::GetPedBetaAngleForClearView(const CVector &Target, float Dist, float BetaOffset, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies)
|
|
{
|
|
CColPoint point;
|
|
CEntity *ent = nil;
|
|
CVector ToSource;
|
|
float a;
|
|
|
|
// This would be so much nicer if we just got the step variable before the loop...R*
|
|
|
|
for(a = 0.0f; a <= PI; a += DEGTORAD(5.0f)){
|
|
if(BetaOffset <= 0.0f){
|
|
ToSource = CVector(cos(Beta + BetaOffset + a), sin(Beta + BetaOffset + a), 0.0f)*Dist;
|
|
if(!CWorld::ProcessLineOfSight(Target, Target + ToSource,
|
|
point, ent, checkBuildings, checkVehicles, checkPeds,
|
|
checkObjects, checkDummies, true, true))
|
|
return a;
|
|
}
|
|
if(BetaOffset >= 0.0f){
|
|
ToSource = CVector(cos(Beta + BetaOffset - a), sin(Beta + BetaOffset - a), 0.0f)*Dist;
|
|
if(!CWorld::ProcessLineOfSight(Target, Target + ToSource,
|
|
point, ent, checkBuildings, checkVehicles, checkPeds,
|
|
checkObjects, checkDummies, true, true))
|
|
return -a;
|
|
}
|
|
}
|
|
return 0.0f;
|
|
}
|
|
|
|
static float DefaultAcceleration = 0.045f;
|
|
static float DefaultMaxStep = 0.15f;
|
|
|
|
void
|
|
CCam::Process_FollowPed(const CVector &CameraTarget, float TargetOrientation, float, float)
|
|
{
|
|
const float GroundDist = 1.85f;
|
|
|
|
CVector TargetCoors, Dist, IdealSource;
|
|
float Length = 0.0f;
|
|
float LateralLeft = 0.0f;
|
|
float LateralRight = 0.0f;
|
|
float Center = 0.0f;
|
|
static bool PreviouslyObscured;
|
|
static bool PickedASide;
|
|
static float FixedTargetOrientation = 0.0f;
|
|
float AngleToGoTo = 0.0f;
|
|
float BetaOffsetAvoidBuildings = 0.45f; // ~25 deg
|
|
float BetaOffsetGoingBehind = 0.45f;
|
|
bool GoingBehind = false;
|
|
bool Obscured = false;
|
|
bool BuildingCheckObscured = false;
|
|
bool HackPlayerOnStoppingTrain = false;
|
|
static int TimeIndicatedWantedToGoDown = 0;
|
|
static bool StartedCountingForGoDown = false;
|
|
float DeltaBeta;
|
|
|
|
m_bFixingBeta = false;
|
|
bBelowMinDist = false;
|
|
bBehindPlayerDesired = false;
|
|
|
|
assert(CamTargetEntity->IsPed());
|
|
|
|
// CenterDist should be > LateralDist because we don't have an angle for safety in this case
|
|
float CenterDist, LateralDist;
|
|
float AngleToGoToSpeed;
|
|
if(m_fCloseInPedHeightOffsetSpeed > 0.00001f){
|
|
LateralDist = 0.55f;
|
|
CenterDist = 1.25f;
|
|
BetaOffsetAvoidBuildings = 0.9f; // ~50 deg
|
|
BetaOffsetGoingBehind = 0.9f;
|
|
AngleToGoToSpeed = 0.88254666f;
|
|
}else{
|
|
LateralDist = 0.8f;
|
|
CenterDist = 1.35f;
|
|
if(TheCamera.PedZoomIndicator == 1.0f || TheCamera.PedZoomIndicator == 4.0f){
|
|
LateralDist = 1.25f;
|
|
CenterDist = 1.6f;
|
|
}
|
|
AngleToGoToSpeed = 0.43254671f;
|
|
}
|
|
|
|
FOV = DefaultFOV;
|
|
|
|
if(ResetStatics){
|
|
Rotating = false;
|
|
m_bCollisionChecksOn = true;
|
|
FixedTargetOrientation = 0.0f;
|
|
PreviouslyObscured = false;
|
|
PickedASide = false;
|
|
StartedCountingForGoDown = false;
|
|
AngleToGoTo = 0.0f;
|
|
// unused LastAngleWithNoPickedASide
|
|
}
|
|
|
|
|
|
TargetCoors = CameraTarget;
|
|
IdealSource = Source;
|
|
TargetCoors.z += m_fSyphonModeTargetZOffSet;
|
|
|
|
CVector TempTargetCoors;
|
|
TempTargetCoors = DoAverageOnVector(TargetCoors);
|
|
TargetCoors = TempTargetCoors;
|
|
// Add this unknown offset, but later it's removed again
|
|
TargetCoors.z += m_fUnknownZOffSet;
|
|
|
|
Dist.x = IdealSource.x - TargetCoors.x;
|
|
Dist.y = IdealSource.y - TargetCoors.y;
|
|
Length = Dist.Magnitude2D();
|
|
|
|
// Cam on a string. With a fixed distance. Zoom in/out is done later.
|
|
if(Length != 0.0f)
|
|
IdealSource = TargetCoors + CVector(Dist.x, Dist.y, 0.0f)/Length * GroundDist;
|
|
else
|
|
IdealSource = TargetCoors + CVector(1.0f, 1.0f, 0.0f);
|
|
|
|
// TODO: what's transition beta?
|
|
if(TheCamera.m_bUseTransitionBeta && ResetStatics){
|
|
CVector VecDistance;
|
|
IdealSource.x = TargetCoors.x + GroundDist*cos(m_fTransitionBeta);
|
|
IdealSource.y = TargetCoors.y + GroundDist*sin(m_fTransitionBeta);
|
|
Beta = CGeneral::GetATanOfXY(IdealSource.x - TargetCoors.x, IdealSource.y - TargetCoors.y);
|
|
}else
|
|
Beta = CGeneral::GetATanOfXY(Source.x - TargetCoors.x, Source.y - TargetCoors.y);
|
|
|
|
if(TheCamera.m_bCamDirectlyBehind){
|
|
m_bCollisionChecksOn = true;
|
|
Beta = TargetOrientation + PI;
|
|
}
|
|
|
|
if(FindPlayerVehicle())
|
|
if(FindPlayerVehicle()->m_vehType == VEHICLE_TYPE_TRAIN)
|
|
HackPlayerOnStoppingTrain = true;
|
|
|
|
if(TheCamera.m_bCamDirectlyInFront){
|
|
m_bCollisionChecksOn = true;
|
|
Beta = TargetOrientation;
|
|
}
|
|
|
|
while(Beta >= PI) Beta -= 2.0f * PI;
|
|
while(Beta < -PI) Beta += 2.0f * PI;
|
|
|
|
// BUG? is this ever used?
|
|
// The values seem to be roughly m_fPedZoomValueSmooth + 1.85
|
|
if(ResetStatics){
|
|
if(TheCamera.PedZoomIndicator == 1.0) m_fRealGroundDist = 2.090556f;
|
|
if(TheCamera.PedZoomIndicator == 2.0) m_fRealGroundDist = 3.34973f;
|
|
if(TheCamera.PedZoomIndicator == 3.0) m_fRealGroundDist = 4.704914f;
|
|
if(TheCamera.PedZoomIndicator == 4.0) m_fRealGroundDist = 2.090556f;
|
|
}
|
|
// And what is this? It's only used for collision and rotation it seems
|
|
float RealGroundDist;
|
|
if(TheCamera.PedZoomIndicator == 1.0) RealGroundDist = 2.090556f;
|
|
if(TheCamera.PedZoomIndicator == 2.0) RealGroundDist = 3.34973f;
|
|
if(TheCamera.PedZoomIndicator == 3.0) RealGroundDist = 4.704914f;
|
|
if(TheCamera.PedZoomIndicator == 4.0) RealGroundDist = 2.090556f;
|
|
if(m_fCloseInPedHeightOffset > 0.00001f)
|
|
RealGroundDist = 1.7016;
|
|
|
|
|
|
bool Shooting = false;
|
|
CPed *ped = (CPed*)CamTargetEntity;
|
|
if(ped->GetWeapon()->m_eWeaponType != WEAPONTYPE_UNARMED)
|
|
if(CPad::GetPad(0)->GetWeapon())
|
|
Shooting = true;
|
|
if(ped->GetWeapon()->m_eWeaponType == WEAPONTYPE_DETONATOR ||
|
|
ped->GetWeapon()->m_eWeaponType == WEAPONTYPE_BASEBALLBAT)
|
|
Shooting = false;
|
|
|
|
|
|
if(m_fCloseInPedHeightOffset > 0.00001f)
|
|
TargetCoors.z -= m_fUnknownZOffSet;
|
|
|
|
// Figure out if and where we want to rotate
|
|
|
|
if(CPad::GetPad(0)->ForceCameraBehindPlayer() || Shooting){
|
|
|
|
// Center cam behind player
|
|
|
|
GoingBehind = true;
|
|
m_bCollisionChecksOn = true;
|
|
float OriginalBeta = Beta;
|
|
// Set Beta behind player
|
|
Beta = TargetOrientation + PI;
|
|
TargetCoors.z -= 0.1f;
|
|
|
|
AngleToGoTo = GetPedBetaAngleForClearView(TargetCoors, CenterDist * RealGroundDist, 0.0f, true, false, false, true, false);
|
|
if(AngleToGoTo != 0.0f){
|
|
if(AngleToGoTo < 0.0f)
|
|
AngleToGoTo -= AngleToGoToSpeed;
|
|
else
|
|
AngleToGoTo += AngleToGoToSpeed;
|
|
}else{
|
|
float LateralLeft = GetPedBetaAngleForClearView(TargetCoors, LateralDist * RealGroundDist, BetaOffsetGoingBehind, true, false, false, true, false);
|
|
float LateralRight = GetPedBetaAngleForClearView(TargetCoors, LateralDist * RealGroundDist, -BetaOffsetGoingBehind, true, false, false, true, false);
|
|
if(LateralLeft == 0.0f && LateralRight != 0.0f)
|
|
AngleToGoTo += LateralRight;
|
|
else if(LateralLeft != 0.0f && LateralRight == 0.0f)
|
|
AngleToGoTo += LateralLeft;
|
|
}
|
|
|
|
TargetCoors.z += 0.1f;
|
|
Beta = OriginalBeta;
|
|
|
|
if(PickedASide){
|
|
if(AngleToGoTo == 0.0f)
|
|
FixedTargetOrientation = TargetOrientation + PI;
|
|
Rotating = true;
|
|
}else{
|
|
FixedTargetOrientation = TargetOrientation + PI + AngleToGoTo;
|
|
Rotating = true;
|
|
PickedASide = true;
|
|
}
|
|
}else{
|
|
|
|
// Rotate cam to avoid clipping into buildings
|
|
|
|
TargetCoors.z -= 0.1f;
|
|
|
|
Center = GetPedBetaAngleForClearView(TargetCoors, CenterDist * RealGroundDist, 0.0f, true, false, false, true, false);
|
|
if(m_bCollisionChecksOn || PreviouslyObscured || Center != 0.0f || m_fCloseInPedHeightOffset > 0.00001f){
|
|
if(Center != 0.0f){
|
|
AngleToGoTo = Center;
|
|
}else{
|
|
LateralLeft = GetPedBetaAngleForClearView(TargetCoors, LateralDist * RealGroundDist, BetaOffsetAvoidBuildings, true, false, false, true, false);
|
|
LateralRight = GetPedBetaAngleForClearView(TargetCoors, LateralDist * RealGroundDist, -BetaOffsetAvoidBuildings, true, false, false, true, false);
|
|
if(LateralLeft == 0.0f && LateralRight != 0.0f){
|
|
AngleToGoTo += LateralRight;
|
|
if(m_fCloseInPedHeightOffset > 0.0f)
|
|
RwCameraSetNearClipPlane(Scene.camera, 0.7f);
|
|
}else if(LateralLeft != 0.0f && LateralRight == 0.0f){
|
|
AngleToGoTo += LateralLeft;
|
|
if(m_fCloseInPedHeightOffset > 0.0f)
|
|
RwCameraSetNearClipPlane(Scene.camera, 0.7f);
|
|
}
|
|
}
|
|
if(LateralLeft != 0.0f || LateralRight != 0.0f || Center != 0.0f)
|
|
BuildingCheckObscured = true;
|
|
}
|
|
|
|
TargetCoors.z += 0.1f;
|
|
}
|
|
|
|
if(m_fCloseInPedHeightOffset > 0.00001f)
|
|
TargetCoors.z += m_fUnknownZOffSet;
|
|
|
|
|
|
// Have to fix to avoid collision
|
|
|
|
if(AngleToGoTo != 0.0f){
|
|
Obscured = true;
|
|
Rotating = true;
|
|
if(CPad::GetPad(0)->ForceCameraBehindPlayer() || Shooting){
|
|
if(!PickedASide)
|
|
FixedTargetOrientation = Beta + AngleToGoTo; // can this even happen?
|
|
}else
|
|
FixedTargetOrientation = Beta + AngleToGoTo;
|
|
|
|
// This calculation is only really used to figure out how fast to rotate out of collision
|
|
|
|
m_fAmountFractionObscured = 1.0f;
|
|
CVector PlayerPos = FindPlayerPed()->GetPosition();
|
|
float RotationDist = (AngleToGoTo == Center ? CenterDist : LateralDist) * RealGroundDist;
|
|
// What's going on here? - AngleToGoTo?
|
|
CVector RotatedSource = PlayerPos + CVector(cos(Beta - AngleToGoTo), sin(Beta - AngleToGoTo), 0.0f) * RotationDist;
|
|
|
|
CColPoint colpoint;
|
|
CEntity *entity;
|
|
if(CWorld::ProcessLineOfSight(PlayerPos, RotatedSource, colpoint, entity, true, false, false, true, false, false, false)){
|
|
if((PlayerPos - RotatedSource).Magnitude() != 0.0f)
|
|
m_fAmountFractionObscured = (PlayerPos - colpoint.point).Magnitude() / (PlayerPos - RotatedSource).Magnitude();
|
|
else
|
|
m_fAmountFractionObscured = 1.0f;
|
|
}
|
|
}
|
|
if(m_fAmountFractionObscured < 0.0f) m_fAmountFractionObscured = 0.0f;
|
|
if(m_fAmountFractionObscured > 1.0f) m_fAmountFractionObscured = 1.0f;
|
|
|
|
|
|
|
|
// Figure out speed values for Beta rotation
|
|
|
|
float Acceleration, MaxSpeed;
|
|
static float AccelerationMult = 0.35f;
|
|
static float MaxSpeedMult = 0.85f;
|
|
static float AccelerationMultClose = 0.7f;
|
|
static float MaxSpeedMultClose = 1.6f;
|
|
float BaseAcceleration = 0.025f;
|
|
float BaseMaxSpeed = 0.09f;
|
|
if(m_fCloseInPedHeightOffset > 0.00001f){
|
|
if(AngleToGoTo == 0.0f){
|
|
BaseAcceleration = 0.022f;
|
|
BaseMaxSpeed = 0.04f;
|
|
}else{
|
|
BaseAcceleration = DefaultAcceleration;
|
|
BaseMaxSpeed = DefaultMaxStep;
|
|
}
|
|
}
|
|
if(AngleToGoTo == 0.0f){
|
|
Acceleration = BaseAcceleration;
|
|
MaxSpeed = BaseMaxSpeed;
|
|
}else if(CPad::GetPad(0)->ForceCameraBehindPlayer() && !Shooting){
|
|
Acceleration = 0.051f;
|
|
MaxSpeed = 0.18f;
|
|
}else if(m_fCloseInPedHeightOffset > 0.00001f){
|
|
Acceleration = BaseAcceleration + AccelerationMultClose*sq(m_fAmountFractionObscured - 1.05f);
|
|
MaxSpeed = BaseMaxSpeed + MaxSpeedMultClose*sq(m_fAmountFractionObscured - 1.05f);
|
|
}else{
|
|
Acceleration = DefaultAcceleration + AccelerationMult*sq(m_fAmountFractionObscured - 1.05f);
|
|
MaxSpeed = DefaultMaxStep + MaxSpeedMult*sq(m_fAmountFractionObscured - 1.05f);
|
|
}
|
|
static float AccelerationLimit = 0.3f;
|
|
static float MaxSpeedLimit = 0.65f;
|
|
if(Acceleration > AccelerationLimit) Acceleration = AccelerationLimit;
|
|
if(MaxSpeed > MaxSpeedLimit) MaxSpeed = MaxSpeedLimit;
|
|
|
|
|
|
int MoveState = ((CPed*)CamTargetEntity)->m_nMoveState;
|
|
if(MoveState != PEDMOVE_NONE && MoveState != PEDMOVE_STILL &&
|
|
!CPad::GetPad(0)->ForceCameraBehindPlayer() && !Obscured && !Shooting){
|
|
Rotating = false;
|
|
BetaSpeed = 0.0f;
|
|
}
|
|
|
|
// Now do the Beta rotation
|
|
|
|
float Distance = (IdealSource - TargetCoors).Magnitude2D();
|
|
m_fDistanceBeforeChanges = Distance;
|
|
|
|
if(Rotating){
|
|
m_bFixingBeta = true;
|
|
|
|
while(FixedTargetOrientation >= PI) FixedTargetOrientation -= 2*PI;
|
|
while(FixedTargetOrientation < -PI) FixedTargetOrientation += 2*PI;
|
|
|
|
while(Beta >= PI) Beta -= 2*PI;
|
|
while(Beta < -PI) Beta += 2*PI;
|
|
|
|
|
|
/*
|
|
// This is inlined WellBufferMe
|
|
DeltaBeta = FixedTargetOrientation - Beta;
|
|
while(DeltaBeta >= PI) DeltaBeta -= 2*PI;
|
|
while(DeltaBeta < -PI) DeltaBeta += 2*PI;
|
|
|
|
float ReqSpeed = DeltaBeta * MaxSpeed;
|
|
// Add or subtract absolute depending on sign, genius!
|
|
if(ReqSpeed - BetaSpeed > 0.0f)
|
|
BetaSpeed += SpeedStep * fabs(ReqSpeed - BetaSpeed) * CTimer::GetTimeStep();
|
|
else
|
|
BetaSpeed -= SpeedStep * fabs(ReqSpeed - BetaSpeed) * CTimer::GetTimeStep();
|
|
// this would be simpler:
|
|
// BetaSpeed += SpeedStep * (ReqSpeed - BetaSpeed) * CTimer::ms_fTimeStep;
|
|
|
|
if(ReqSpeed < 0.0f && BetaSpeed < ReqSpeed)
|
|
BetaSpeed = ReqSpeed;
|
|
else if(ReqSpeed > 0.0f && BetaSpeed > ReqSpeed)
|
|
BetaSpeed = ReqSpeed;
|
|
|
|
Beta += BetaSpeed * min(10.0f, CTimer::GetTimeStep());
|
|
*/
|
|
WellBufferMe(FixedTargetOrientation, &Beta, &BetaSpeed, MaxSpeed, Acceleration, true);
|
|
|
|
if(ResetStatics){
|
|
Beta = FixedTargetOrientation;
|
|
BetaSpeed = 0.0f;
|
|
}
|
|
|
|
Source.x = TargetCoors.x + Distance * cos(Beta);
|
|
Source.y = TargetCoors.y + Distance * sin(Beta);
|
|
|
|
// Check if we can stop rotating
|
|
DeltaBeta = FixedTargetOrientation - Beta;
|
|
while(DeltaBeta >= PI) DeltaBeta -= 2*PI;
|
|
while(DeltaBeta < -PI) DeltaBeta += 2*PI;
|
|
if(fabs(DeltaBeta) < DEGTORAD(1.0f) && !bBehindPlayerDesired){
|
|
// Stop rotation
|
|
PickedASide = false;
|
|
Rotating = false;
|
|
BetaSpeed = 0.0f;
|
|
}
|
|
}
|
|
|
|
|
|
if(TheCamera.m_bCamDirectlyBehind || TheCamera.m_bCamDirectlyInFront ||
|
|
HackPlayerOnStoppingTrain || Rotating){
|
|
if(TheCamera.m_bCamDirectlyBehind){
|
|
Beta = TargetOrientation + PI;
|
|
Source.x = TargetCoors.x + Distance * cos(Beta);
|
|
Source.y = TargetCoors.y + Distance * sin(Beta);
|
|
}
|
|
if(TheCamera.m_bCamDirectlyInFront){
|
|
Beta = TargetOrientation;
|
|
Source.x = TargetCoors.x + Distance * cos(Beta);
|
|
Source.y = TargetCoors.y + Distance * sin(Beta);
|
|
}
|
|
if(HackPlayerOnStoppingTrain){
|
|
Beta = TargetOrientation + PI;
|
|
Source.x = TargetCoors.x + Distance * cos(Beta);
|
|
Source.y = TargetCoors.y + Distance * sin(Beta);
|
|
m_fDimensionOfHighestNearCar = 0.0f;
|
|
m_fCamBufferedHeight = 0.0f;
|
|
m_fCamBufferedHeightSpeed = 0.0f;
|
|
}
|
|
// Beta and Source already set in the rotation code
|
|
}else{
|
|
Source = IdealSource;
|
|
BetaSpeed = 0.0f;
|
|
}
|
|
|
|
// Subtract m_fUnknownZOffSet from both?
|
|
TargetCoors.z -= m_fUnknownZOffSet;
|
|
Source.z = IdealSource.z - m_fUnknownZOffSet;
|
|
|
|
// Apply zoom now
|
|
// m_fPedZoomValueSmooth makes the cam go down the further out it is
|
|
// 0.25 -> 0.20 for nearest dist
|
|
// 1.50 -> -0.05 for mid dist
|
|
// 2.90 -> -0.33 for far dist
|
|
Source.z += (2.5f - TheCamera.m_fPedZoomValueSmooth)*0.2f - 0.25f;
|
|
// Zoom out camera
|
|
Front = TargetCoors - Source;
|
|
Front.Normalise();
|
|
Source -= Front * TheCamera.m_fPedZoomValueSmooth;
|
|
// and then we move up again
|
|
// -0.375
|
|
// 0.25
|
|
// 0.95
|
|
Source.z += (TheCamera.m_fPedZoomValueSmooth - 1.0f)*0.5f + m_fCloseInPedHeightOffset;
|
|
|
|
|
|
// Process height offset to avoid peds and cars
|
|
|
|
float TargetZOffSet = m_fUnknownZOffSet + m_fDimensionOfHighestNearCar;
|
|
TargetZOffSet = max(TargetZOffSet, m_fPedBetweenCameraHeightOffset);
|
|
float TargetHeight = CameraTarget.z + TargetZOffSet - Source.z;
|
|
|
|
if(TargetHeight > m_fCamBufferedHeight){
|
|
// Have to go up
|
|
if(TargetZOffSet == m_fPedBetweenCameraHeightOffset && TargetZOffSet > m_fCamBufferedHeight)
|
|
WellBufferMe(TargetHeight, &m_fCamBufferedHeight, &m_fCamBufferedHeightSpeed, 0.2f, 0.04f, false);
|
|
else if(TargetZOffSet == m_fUnknownZOffSet && TargetZOffSet > m_fCamBufferedHeight){
|
|
// TODO: figure this out
|
|
bool foo = false;
|
|
switch(((CPhysical*)CamTargetEntity)->m_nLastCollType)
|
|
case 2: case 3: case 5:
|
|
case 11: case 23: case 26:
|
|
foo = true;
|
|
if(foo)
|
|
WellBufferMe(TargetHeight, &m_fCamBufferedHeight, &m_fCamBufferedHeightSpeed, 0.4f, 0.05f, false);
|
|
else
|
|
WellBufferMe(TargetHeight, &m_fCamBufferedHeight, &m_fCamBufferedHeightSpeed, 0.2f, 0.025f, false);
|
|
}else
|
|
WellBufferMe(TargetHeight, &m_fCamBufferedHeight, &m_fCamBufferedHeightSpeed, 0.2f, 0.025f, false);
|
|
StartedCountingForGoDown = false;
|
|
}else{
|
|
// Have to go down
|
|
if(StartedCountingForGoDown){
|
|
if(CTimer::GetTimeInMilliseconds() != TimeIndicatedWantedToGoDown){
|
|
if(TargetHeight > 0.0f)
|
|
WellBufferMe(TargetHeight, &m_fCamBufferedHeight, &m_fCamBufferedHeightSpeed, 0.2f, 0.01f, false);
|
|
else
|
|
WellBufferMe(0.0f, &m_fCamBufferedHeight, &m_fCamBufferedHeightSpeed, 0.2f, 0.01f, false);
|
|
}
|
|
}else{
|
|
StartedCountingForGoDown = true;
|
|
TimeIndicatedWantedToGoDown = CTimer::GetTimeInMilliseconds();
|
|
}
|
|
}
|
|
|
|
Source.z += m_fCamBufferedHeight;
|
|
|
|
|
|
// Clip Source if necessary
|
|
|
|
bool ClipSource = m_fCloseInPedHeightOffset > 0.00001f && m_fCamBufferedHeight > 0.001f;
|
|
if(GoingBehind || ResetStatics || ClipSource){
|
|
CColPoint colpoint;
|
|
CEntity *entity;
|
|
if(CWorld::ProcessLineOfSight(TargetCoors, Source, colpoint, entity, true, false, false, true, false, true, true)){
|
|
Source = colpoint.point;
|
|
if((TargetCoors - Source).Magnitude2D() < 1.0f)
|
|
RwCameraSetNearClipPlane(Scene.camera, 0.05f);
|
|
}
|
|
}
|
|
|
|
TargetCoors.z += min(1.0f, m_fCamBufferedHeight/2.0f);
|
|
m_cvecTargetCoorsForFudgeInter = TargetCoors;
|
|
|
|
Front = TargetCoors - Source;
|
|
m_fRealGroundDist = Front.Magnitude2D();
|
|
m_fMinDistAwayFromCamWhenInterPolating = m_fRealGroundDist;
|
|
Front.Normalise();
|
|
GetVectorsReadyForRW();
|
|
TheCamera.m_bCamDirectlyBehind = false;
|
|
TheCamera.m_bCamDirectlyInFront = false;
|
|
PreviouslyObscured = BuildingCheckObscured;
|
|
|
|
ResetStatics = false;
|
|
}
|
|
|
|
void
|
|
CCam::Process_BehindCar(const CVector &CameraTarget, float TargetOrientation, float, float)
|
|
{
|
|
FOV = DefaultFOV;
|
|
|
|
if(!CamTargetEntity->IsVehicle())
|
|
return;
|
|
|
|
CVector TargetCoors = CameraTarget;
|
|
TargetCoors.z -= 0.2f;
|
|
CA_MAX_DISTANCE = 9.95f;
|
|
CA_MIN_DISTANCE = 8.5f;
|
|
|
|
CVector Dist = Source - TargetCoors;
|
|
float Length = Dist.Magnitude2D();
|
|
m_fDistanceBeforeChanges = Length;
|
|
if(Length < 0.002f)
|
|
Length = 0.002f;
|
|
Beta = CGeneral::GetATanOfXY(TargetCoors.x - Source.x, TargetCoors.y - Source.y);
|
|
if(Length > CA_MAX_DISTANCE){
|
|
Source.x = TargetCoors.x + Dist.x/Length * CA_MAX_DISTANCE;
|
|
Source.y = TargetCoors.y + Dist.y/Length * CA_MAX_DISTANCE;
|
|
}else if(Length < CA_MIN_DISTANCE){
|
|
Source.x = TargetCoors.x + Dist.x/Length * CA_MIN_DISTANCE;
|
|
Source.y = TargetCoors.y + Dist.y/Length * CA_MIN_DISTANCE;
|
|
}
|
|
TargetCoors.z += 0.8f;
|
|
|
|
WorkOutCamHeightWeeCar(TargetCoors, TargetOrientation);
|
|
RotCamIfInFrontCar(TargetCoors, TargetOrientation);
|
|
FixCamIfObscured(TargetCoors, 1.2f, TargetOrientation);
|
|
|
|
Front = TargetCoors - Source;
|
|
m_cvecTargetCoorsForFudgeInter = TargetCoors;
|
|
ResetStatics = false;
|
|
GetVectorsReadyForRW();
|
|
}
|
|
|
|
void
|
|
CCam::WorkOutCamHeightWeeCar(CVector &TargetCoors, float TargetOrientation)
|
|
{
|
|
CColPoint colpoint;
|
|
CEntity *ent;
|
|
float TargetZOffSet = 0.0f;
|
|
static bool PreviouslyFailedRoadHeightCheck = false;
|
|
static float RoadHeightFix = 0.0f;
|
|
static float RoadHeightFixSpeed = 0.0f;
|
|
|
|
if(ResetStatics){
|
|
RoadHeightFix = 0.0f;
|
|
RoadHeightFixSpeed = 0.0f;
|
|
Alpha = DEGTORAD(25.0f);
|
|
AlphaSpeed = 0.0f;
|
|
}
|
|
float AlphaTarget = DEGTORAD(25.0f);
|
|
if(CCullZones::CamNoRain() || CCullZones::PlayerNoRain())
|
|
AlphaTarget = DEGTORAD(14.0f);
|
|
WellBufferMe(AlphaTarget, &Alpha, &AlphaSpeed, 0.1f, 0.05f, true);
|
|
Source.z = TargetCoors.z + CA_MAX_DISTANCE*sin(Alpha);
|
|
|
|
if(FindPlayerVehicle()){
|
|
m_fUnknownZOffSet = 0.0f;
|
|
bool FoundRoad = false;
|
|
bool FoundRoof = false;
|
|
float RoadZ = 0.0f;
|
|
float RoofZ = 0.0f;
|
|
|
|
if(CWorld::ProcessVerticalLine(Source, -1000.0f, colpoint, ent, true, false, false, false, false, false, false) &&
|
|
ent->IsBuilding()){
|
|
FoundRoad = true;
|
|
RoadZ = colpoint.point.z;
|
|
}
|
|
|
|
if(FoundRoad){
|
|
if(Source.z - RoadZ < 0.9f){
|
|
PreviouslyFailedRoadHeightCheck = true;
|
|
TargetZOffSet = RoadZ + 0.9f - Source.z;
|
|
}else{
|
|
if(m_bCollisionChecksOn)
|
|
PreviouslyFailedRoadHeightCheck = false;
|
|
else
|
|
TargetZOffSet = 0.0f;
|
|
}
|
|
}else{
|
|
if(CWorld::ProcessVerticalLine(Source, 1000.0f, colpoint, ent, true, false, false, false, false, false, false) &&
|
|
ent->IsBuilding()){
|
|
FoundRoof = true;
|
|
RoofZ = colpoint.point.z;
|
|
}
|
|
if(FoundRoof){
|
|
if(Source.z - RoofZ < 0.9f){
|
|
PreviouslyFailedRoadHeightCheck = true;
|
|
TargetZOffSet = RoofZ + 0.9f - Source.z;
|
|
}else{
|
|
if(m_bCollisionChecksOn)
|
|
PreviouslyFailedRoadHeightCheck = false;
|
|
else
|
|
TargetZOffSet = 0.0f;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(TargetZOffSet > RoadHeightFix)
|
|
RoadHeightFix = TargetZOffSet;
|
|
else
|
|
WellBufferMe(TargetZOffSet, &RoadHeightFix, &RoadHeightFixSpeed, 0.27f, 0.1f, false);
|
|
|
|
if((colpoint.surfaceB == SURFACE_DEFAULT || colpoint.surfaceB >= SURFACE_METAL6) &&
|
|
colpoint.surfaceB != SURFACE_STEEL && colpoint.surfaceB != SURFACE_STONE &&
|
|
RoadHeightFix > 1.4f)
|
|
RoadHeightFix = 1.4f;
|
|
|
|
Source.z += RoadHeightFix;
|
|
}
|
|
|
|
void
|
|
CCam::WorkOutCamHeight(const CVector &TargetCoors, float TargetOrientation, float TargetHeight)
|
|
{
|
|
static float LastTargetAlphaWithCollisionOn = 0.0f;
|
|
static float LastTopAlphaSpeed = 0.0f;
|
|
static float LastAlphaSpeedStep = 0.0f;
|
|
static bool PreviousNearCheckNearClipSmall = false;
|
|
|
|
bool CamClear = true;
|
|
float ModeAlpha = 0.0f;
|
|
|
|
if(ResetStatics){
|
|
LastTargetAlphaWithCollisionOn = 0.0f;
|
|
LastTopAlphaSpeed = 0.0f;
|
|
LastAlphaSpeedStep = 0.0f;
|
|
PreviousNearCheckNearClipSmall = false;
|
|
}
|
|
|
|
float TopAlphaSpeed = 0.15f;
|
|
float AlphaSpeedStep = 0.015f;
|
|
|
|
float zoomvalue = TheCamera.CarZoomValueSmooth;
|
|
if(zoomvalue < 0.1f)
|
|
zoomvalue = 0.1f;
|
|
if(TheCamera.CarZoomIndicator == 1.0f)
|
|
ModeAlpha = CGeneral::GetATanOfXY(23.0f, zoomvalue); // near
|
|
else if(TheCamera.CarZoomIndicator == 2.0f)
|
|
ModeAlpha = CGeneral::GetATanOfXY(10.8f, zoomvalue); // mid
|
|
else if(TheCamera.CarZoomIndicator == 3.0f)
|
|
ModeAlpha = CGeneral::GetATanOfXY(7.0f, zoomvalue); // far
|
|
|
|
|
|
float Length = (Source - TargetCoors).Magnitude2D();
|
|
if(m_bCollisionChecksOn){ // there's another variable (on PC) but it's uninitialised
|
|
CVector Forward = CamTargetEntity->GetForward();
|
|
float CarAlpha = CGeneral::GetATanOfXY(Forward.Magnitude2D(), Forward.z);
|
|
// this shouldn't be necessary....
|
|
while(CarAlpha >= PI) CarAlpha -= 2*PI;
|
|
while(CarAlpha < -PI) CarAlpha += 2*PI;
|
|
|
|
while(Beta >= PI) Beta -= 2*PI;
|
|
while(Beta < -PI) Beta += 2*PI;
|
|
|
|
float deltaBeta = Beta - TargetOrientation;
|
|
while(deltaBeta >= PI) deltaBeta -= 2*PI;
|
|
while(deltaBeta < -PI) deltaBeta += 2*PI;
|
|
|
|
float BehindCarNess = cos(deltaBeta); // 1 if behind car, 0 if side, -1 if in front
|
|
CarAlpha = -CarAlpha * BehindCarNess;
|
|
if(CarAlpha < -0.01f)
|
|
CarAlpha = -0.01f;
|
|
|
|
float DeltaAlpha = CarAlpha - Alpha;
|
|
while(DeltaAlpha >= PI) DeltaAlpha -= 2*PI;
|
|
while(DeltaAlpha < -PI) DeltaAlpha += 2*PI;
|
|
// What's this?? wouldn't it make more sense to clamp?
|
|
float AngleLimit = DEGTORAD(1.8f);
|
|
if(DeltaAlpha < -AngleLimit)
|
|
DeltaAlpha += AngleLimit;
|
|
else if(DeltaAlpha > AngleLimit)
|
|
DeltaAlpha -= AngleLimit;
|
|
else
|
|
DeltaAlpha = 0.0f;
|
|
|
|
// Now the collision
|
|
|
|
float TargetAlpha = 0.0f;
|
|
bool FoundRoofCenter = false;
|
|
bool FoundRoofSide1 = false;
|
|
bool FoundRoofSide2 = false;
|
|
bool FoundCamRoof = false;
|
|
bool FoundCamGround = false;
|
|
float CamRoof = 0.0f;
|
|
float CarBottom = TargetCoors.z - TargetHeight/2.0f;
|
|
|
|
// Check car center
|
|
float CarRoof = CWorld::FindRoofZFor3DCoord(TargetCoors.x, TargetCoors.y, CarBottom, &FoundRoofCenter);
|
|
|
|
// Check sides of the car
|
|
Forward = CamTargetEntity->GetForward(); // we actually still have that...
|
|
Forward.Normalise(); // shouldn't be necessary
|
|
float CarSideAngle = CGeneral::GetATanOfXY(Forward.x, Forward.y) + PI/2.0f;
|
|
float SideX = 2.5f * cos(CarSideAngle);
|
|
float SideY = 2.5f * sin(CarSideAngle);
|
|
CWorld::FindRoofZFor3DCoord(TargetCoors.x + SideX, TargetCoors.y + SideY, CarBottom, &FoundRoofSide1);
|
|
CWorld::FindRoofZFor3DCoord(TargetCoors.x - SideX, TargetCoors.y - SideY, CarBottom, &FoundRoofSide2);
|
|
|
|
// Now find out at what height we'd like to place the camera
|
|
float CamGround = CWorld::FindGroundZFor3DCoord(Source.x, Source.y, TargetCoors.z + Length*sin(Alpha + ModeAlpha) + m_fCloseInCarHeightOffset, &FoundCamGround);
|
|
float CamTargetZ = 0.0f;
|
|
if(FoundCamGround){
|
|
// This is the normal case
|
|
CamRoof = CWorld::FindRoofZFor3DCoord(Source.x, Source.y, CamGround + TargetHeight, &FoundCamRoof);
|
|
CamTargetZ = CamGround + TargetHeight*1.5f + 0.1f;
|
|
}else{
|
|
FoundCamRoof = false;
|
|
CamTargetZ = TargetCoors.z;
|
|
}
|
|
|
|
if(FoundRoofCenter && !FoundCamRoof && (FoundRoofSide1 || FoundRoofSide2)){
|
|
// Car is under something but camera isn't
|
|
// This seems weird...
|
|
TargetAlpha = CGeneral::GetATanOfXY(CA_MAX_DISTANCE, CarRoof - CamTargetZ - 1.5f);
|
|
CamClear = false;
|
|
}
|
|
if(FoundCamRoof){
|
|
// Camera is under something
|
|
float roof = FoundRoofCenter ? min(CamRoof, CarRoof) : CamRoof;
|
|
// Same weirdness again?
|
|
TargetAlpha = CGeneral::GetATanOfXY(CA_MAX_DISTANCE, roof - CamTargetZ - 1.5f);
|
|
CamClear = false;
|
|
}
|
|
while(TargetAlpha >= PI) TargetAlpha -= 2*PI;
|
|
while(TargetAlpha < -PI) TargetAlpha += 2*PI;
|
|
if(TargetAlpha < DEGTORAD(-7.0f))
|
|
TargetAlpha = DEGTORAD(-7.0f);
|
|
|
|
// huh?
|
|
if(TargetAlpha > ModeAlpha)
|
|
CamClear = true;
|
|
// Camera is contrained by collision in some way
|
|
PreviousNearCheckNearClipSmall = false;
|
|
if(!CamClear){
|
|
PreviousNearCheckNearClipSmall = true;
|
|
RwCameraSetNearClipPlane(Scene.camera, 0.9f);
|
|
|
|
DeltaAlpha = TargetAlpha - (Alpha + ModeAlpha);
|
|
while(DeltaAlpha >= PI) DeltaAlpha -= 2*PI;
|
|
while(DeltaAlpha < -PI) DeltaAlpha += 2*PI;
|
|
|
|
TopAlphaSpeed = 0.3f;
|
|
AlphaSpeedStep = 0.03f;
|
|
}
|
|
|
|
// Now do things if CamClear...but what is that anyway?
|
|
float CamZ = TargetCoors.z + Length*sin(Alpha + DeltaAlpha + ModeAlpha) + m_fCloseInCarHeightOffset;
|
|
bool FoundGround, FoundRoof;
|
|
float CamGround2 = CWorld::FindGroundZFor3DCoord(Source.x, Source.y, CamZ, &FoundGround);
|
|
if(FoundGround){
|
|
if(CamClear)
|
|
if(CamZ - CamGround2 < 1.5f){
|
|
PreviousNearCheckNearClipSmall = true;
|
|
RwCameraSetNearClipPlane(Scene.camera, 0.9f);
|
|
|
|
float a;
|
|
if(Length == 0.0f || CamGround2 + 1.5f - TargetCoors.z == 0.0f)
|
|
a = Alpha;
|
|
else
|
|
a = CGeneral::GetATanOfXY(Length, CamGround2 + 1.5f - TargetCoors.z);
|
|
while(a > PI) a -= 2*PI;
|
|
while(a < -PI) a += 2*PI;
|
|
DeltaAlpha = a - Alpha;
|
|
}
|
|
}else{
|
|
if(CamClear){
|
|
float CamRoof2 = CWorld::FindRoofZFor3DCoord(Source.x, Source.y, CamZ, &FoundRoof);
|
|
if(FoundRoof && CamZ - CamRoof2 < 1.5f){
|
|
PreviousNearCheckNearClipSmall = true;
|
|
RwCameraSetNearClipPlane(Scene.camera, 0.9f);
|
|
|
|
if(CamRoof2 > TargetCoors.z + 3.5f)
|
|
CamRoof2 = TargetCoors.z + 3.5f;
|
|
|
|
float a;
|
|
if(Length == 0.0f || CamRoof2 + 1.5f - TargetCoors.z == 0.0f)
|
|
a = Alpha;
|
|
else
|
|
a = CGeneral::GetATanOfXY(Length, CamRoof2 + 1.5f - TargetCoors.z);
|
|
while(a > PI) a -= 2*PI;
|
|
while(a < -PI) a += 2*PI;
|
|
DeltaAlpha = a - Alpha;
|
|
}
|
|
}
|
|
}
|
|
|
|
LastTargetAlphaWithCollisionOn = DeltaAlpha + Alpha;
|
|
LastTopAlphaSpeed = TopAlphaSpeed;
|
|
LastAlphaSpeedStep = AlphaSpeedStep;
|
|
}else{
|
|
if(PreviousNearCheckNearClipSmall)
|
|
RwCameraSetNearClipPlane(Scene.camera, 0.9f);
|
|
}
|
|
|
|
WellBufferMe(LastTargetAlphaWithCollisionOn, &Alpha, &AlphaSpeed, LastTopAlphaSpeed, LastAlphaSpeedStep, true);
|
|
|
|
Source.z = TargetCoors.z + sin(Alpha + ModeAlpha)*Length + m_fCloseInCarHeightOffset;
|
|
}
|
|
|
|
// Rotate cam behind the car when the car is moving forward
|
|
bool
|
|
CCam::RotCamIfInFrontCar(CVector &TargetCoors, float TargetOrientation)
|
|
{
|
|
bool MovingForward = false;
|
|
CPhysical *phys = (CPhysical*)CamTargetEntity;
|
|
|
|
float ForwardSpeed = DotProduct(phys->GetForward(), phys->GetSpeed(CVector(0.0f, 0.0f, 0.0f)));
|
|
if(ForwardSpeed > 0.02f)
|
|
MovingForward = true;
|
|
|
|
float Dist = (Source - TargetCoors).Magnitude2D();
|
|
|
|
float DeltaBeta = TargetOrientation - Beta;
|
|
while(DeltaBeta >= PI) DeltaBeta -= 2*PI;
|
|
while(DeltaBeta < -PI) DeltaBeta += 2*PI;
|
|
|
|
if(fabs(DeltaBeta) > DEGTORAD(20.0f) && MovingForward && TheCamera.m_uiTransitionState == 0)
|
|
m_bFixingBeta = true;
|
|
|
|
CPad *pad = CPad::GetPad(0);
|
|
if(!(pad->GetLookBehindForCar() || pad->GetLookBehindForPed() || pad->GetLookLeft() || pad->GetLookRight()))
|
|
if(DirectionWasLooking != LOOKING_FORWARD)
|
|
TheCamera.m_bCamDirectlyBehind = true;
|
|
|
|
if(!m_bFixingBeta && !TheCamera.m_bUseTransitionBeta && !TheCamera.m_bCamDirectlyBehind && !TheCamera.m_bCamDirectlyInFront)
|
|
return false;
|
|
|
|
bool SetBeta = false;
|
|
if(TheCamera.m_bCamDirectlyBehind || TheCamera.m_bCamDirectlyInFront || TheCamera.m_bUseTransitionBeta)
|
|
if(&TheCamera.Cams[TheCamera.ActiveCam] == this)
|
|
SetBeta = true;
|
|
|
|
if(m_bFixingBeta || SetBeta){
|
|
WellBufferMe(TargetOrientation, &Beta, &BetaSpeed, 0.15f, 0.007f, true);
|
|
|
|
if(TheCamera.m_bCamDirectlyBehind && &TheCamera.Cams[TheCamera.ActiveCam] == this)
|
|
Beta = TargetOrientation;
|
|
if(TheCamera.m_bCamDirectlyInFront && &TheCamera.Cams[TheCamera.ActiveCam] == this)
|
|
Beta = TargetOrientation + PI;
|
|
if(TheCamera.m_bUseTransitionBeta && &TheCamera.Cams[TheCamera.ActiveCam] == this)
|
|
Beta = m_fTransitionBeta;
|
|
|
|
Source.x = TargetCoors.x - cos(Beta)*Dist;
|
|
Source.y = TargetCoors.y - sin(Beta)*Dist;
|
|
|
|
// Check if we're done
|
|
DeltaBeta = TargetOrientation - Beta;
|
|
while(DeltaBeta >= PI) DeltaBeta -= 2*PI;
|
|
while(DeltaBeta < -PI) DeltaBeta += 2*PI;
|
|
if(fabs(DeltaBeta) < DEGTORAD(2.0f))
|
|
m_bFixingBeta = false;
|
|
}
|
|
TheCamera.m_bCamDirectlyBehind = false;
|
|
TheCamera.m_bCamDirectlyInFront = false;
|
|
return true;
|
|
}
|
|
|
|
// Move the cam to avoid clipping through buildings
|
|
bool
|
|
CCam::FixCamIfObscured(CVector &TargetCoors, float TargetHeight, float TargetOrientation)
|
|
{
|
|
CVector Target = TargetCoors;
|
|
bool UseEntityPos = false;
|
|
CVector EntityPos;
|
|
static CColPoint colPoint;
|
|
static bool LastObscured = false;
|
|
|
|
if(Mode == MODE_BEHINDCAR)
|
|
Target.z += TargetHeight/2.0f;
|
|
if(Mode == MODE_CAMONASTRING){
|
|
UseEntityPos = true;
|
|
Target.z += TargetHeight/2.0f;
|
|
EntityPos = CamTargetEntity->GetPosition();
|
|
}
|
|
|
|
CVector TempSource = Source;
|
|
|
|
bool Obscured1 = false;
|
|
bool Obscured2 = false;
|
|
bool Fix1 = false;
|
|
float Dist1 = 0.0f;
|
|
float Dist2 = 0.0f;
|
|
CEntity *ent;
|
|
if(m_bCollisionChecksOn || LastObscured){
|
|
Obscured1 = CWorld::ProcessLineOfSight(Target, TempSource, colPoint, ent, true, false, false, true, false, true, true);
|
|
if(Obscured1){
|
|
Dist1 = (Target - colPoint.point).Magnitude2D();
|
|
Fix1 = true;
|
|
if(UseEntityPos)
|
|
Obscured1 = CWorld::ProcessLineOfSight(EntityPos, TempSource, colPoint, ent, true, false, false, true, false, true, true);
|
|
}else if(m_bFixingBeta){
|
|
float d = (TempSource - Target).Magnitude();
|
|
TempSource.x = Target.x - d*cos(TargetOrientation);
|
|
TempSource.y = Target.y - d*sin(TargetOrientation);
|
|
|
|
// same check again
|
|
Obscured2 = CWorld::ProcessLineOfSight(Target, TempSource, colPoint, ent, true, false, false, true, false, true, true);
|
|
if(Obscured2){
|
|
Dist2 = (Target - colPoint.point).Magnitude2D();
|
|
if(UseEntityPos)
|
|
Obscured2 = CWorld::ProcessLineOfSight(EntityPos, TempSource, colPoint, ent, true, false, false, true, false, true, true);
|
|
}
|
|
}
|
|
LastObscured = Obscured1 || Obscured2;
|
|
}
|
|
|
|
// nothing to do
|
|
if(!LastObscured)
|
|
return false;
|
|
|
|
if(Fix1){
|
|
Source.x = Target.x - cos(Beta)*Dist1;
|
|
Source.y = Target.y - sin(Beta)*Dist1;
|
|
if(Mode == MODE_BEHINDCAR)
|
|
Source = colPoint.point;
|
|
}else{
|
|
WellBufferMe(Dist2, &m_fDistanceBeforeChanges, &DistanceSpeed, 0.2f, 0.025f, false);
|
|
Source.x = Target.x - cos(Beta)*m_fDistanceBeforeChanges;
|
|
Source.y = Target.y - sin(Beta)*m_fDistanceBeforeChanges;
|
|
}
|
|
|
|
if(ResetStatics){
|
|
m_fDistanceBeforeChanges = (Source - Target).Magnitude2D();
|
|
DistanceSpeed = 0.0f;
|
|
Source.x = colPoint.point.x;
|
|
Source.y = colPoint.point.y;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void
|
|
CCam::Process_Cam_On_A_String(const CVector &CameraTarget, float TargetOrientation, float, float)
|
|
{
|
|
if(!CamTargetEntity->IsVehicle())
|
|
return;
|
|
|
|
FOV = DefaultFOV;
|
|
|
|
if(ResetStatics){
|
|
AlphaSpeed = 0.0f;
|
|
if(TheCamera.m_bIdleOn)
|
|
TheCamera.m_uiTimeWeEnteredIdle = CTimer::GetTimeInMilliseconds();
|
|
}
|
|
|
|
CBaseModelInfo *mi = CModelInfo::GetModelInfo(CamTargetEntity->GetModelIndex());
|
|
CVector Dimensions = mi->GetColModel()->boundingBox.max - mi->GetColModel()->boundingBox.min;
|
|
float BaseDist = Dimensions.Magnitude2D();
|
|
|
|
CVector TargetCoors = CameraTarget;
|
|
TargetCoors.z += Dimensions.z - 0.1f; // final
|
|
Beta = CGeneral::GetATanOfXY(TargetCoors.x - Source.x, TargetCoors.y - Source.y);
|
|
while(Alpha >= PI) Alpha -= 2*PI;
|
|
while(Alpha < -PI) Alpha += 2*PI;
|
|
while(Beta >= PI) Beta -= 2*PI;
|
|
while(Beta < -PI) Beta += 2*PI;
|
|
|
|
m_fDistanceBeforeChanges = (Source - TargetCoors).Magnitude2D();
|
|
|
|
Cam_On_A_String_Unobscured(TargetCoors, BaseDist);
|
|
WorkOutCamHeight(TargetCoors, TargetOrientation, Dimensions.z);
|
|
RotCamIfInFrontCar(TargetCoors, TargetOrientation);
|
|
FixCamIfObscured(TargetCoors, Dimensions.z, TargetOrientation);
|
|
FixCamWhenObscuredByVehicle(TargetCoors);
|
|
|
|
m_cvecTargetCoorsForFudgeInter = TargetCoors;
|
|
Front = TargetCoors - Source;
|
|
Front.Normalise();
|
|
GetVectorsReadyForRW();
|
|
ResetStatics = false;
|
|
}
|
|
|
|
// Basic Cam on a string algorithm
|
|
void
|
|
CCam::Cam_On_A_String_Unobscured(const CVector &TargetCoors, float BaseDist)
|
|
{
|
|
CA_MAX_DISTANCE = BaseDist + 0.1f + TheCamera.CarZoomValueSmooth;
|
|
CA_MIN_DISTANCE = min(BaseDist*0.6f, 3.5f);
|
|
|
|
CVector Dist = Source - TargetCoors;
|
|
|
|
if(ResetStatics)
|
|
Source = TargetCoors + Dist*(CA_MAX_DISTANCE + 1.0f);
|
|
|
|
float Length = Dist.Magnitude2D();
|
|
if(Length < 0.001f){
|
|
// This probably shouldn't happen. reset view
|
|
CVector Forward = CamTargetEntity->GetForward();
|
|
Forward.z = 0.0f;
|
|
Forward.Normalise();
|
|
Source = TargetCoors - Forward*CA_MAX_DISTANCE;
|
|
Dist = Source - TargetCoors;
|
|
Length = Dist.Magnitude2D();
|
|
}
|
|
|
|
if(Length > CA_MAX_DISTANCE){
|
|
Source.x = TargetCoors.x + Dist.x/Length * CA_MAX_DISTANCE;
|
|
Source.y = TargetCoors.y + Dist.y/Length * CA_MAX_DISTANCE;
|
|
}else if(Length < CA_MIN_DISTANCE){
|
|
Source.x = TargetCoors.x + Dist.x/Length * CA_MIN_DISTANCE;
|
|
Source.y = TargetCoors.y + Dist.y/Length * CA_MIN_DISTANCE;
|
|
}
|
|
}
|
|
|
|
void
|
|
CCam::FixCamWhenObscuredByVehicle(const CVector &TargetCoors)
|
|
{
|
|
// BUG? is this never reset
|
|
static float HeightFixerCarsObscuring = 0.0f;
|
|
static float HeightFixerCarsObscuringSpeed = 0.0f;
|
|
CColPoint colPoint;
|
|
CEntity *entity;
|
|
|
|
float HeightTarget = 0.0f;
|
|
if(CWorld::ProcessLineOfSight(TargetCoors, Source, colPoint, entity, false, true, false, false, false, false, false)){
|
|
CBaseModelInfo *mi = CModelInfo::GetModelInfo(entity->GetModelIndex());
|
|
HeightTarget = mi->GetColModel()->boundingBox.max.z + 1.0f + TargetCoors.z - Source.z;
|
|
if(HeightTarget < 0.0f)
|
|
HeightTarget = 0.0f;
|
|
}
|
|
WellBufferMe(HeightTarget, &HeightFixerCarsObscuring, &HeightFixerCarsObscuringSpeed, 0.2f, 0.025f, false);
|
|
Source.z += HeightFixerCarsObscuring;
|
|
}
|
|
|
|
STARTPATCHES
|
|
InjectHook(0x42C760, &CCamera::IsSphereVisible, PATCH_JUMP);
|
|
InjectHook(0x46FD00, &CCamera::SetFadeColour, PATCH_JUMP);
|
|
|
|
InjectHook(0x46FD40, &CCamera::SetMotionBlur, PATCH_JUMP);
|
|
InjectHook(0x46FD80, &CCamera::SetMotionBlurAlpha, PATCH_JUMP);
|
|
InjectHook(0x46F940, &CCamera::RenderMotionBlur, PATCH_JUMP);
|
|
|
|
InjectHook(0x456F40, WellBufferMe, PATCH_JUMP);
|
|
InjectHook(0x4582F0, &CCam::GetVectorsReadyForRW, PATCH_JUMP);
|
|
InjectHook(0x457710, &CCam::DoAverageOnVector, PATCH_JUMP);
|
|
InjectHook(0x458060, &CCam::GetPedBetaAngleForClearView, PATCH_JUMP);
|
|
InjectHook(0x457210, &CCam::Cam_On_A_String_Unobscured, PATCH_JUMP);
|
|
InjectHook(0x457A80, &CCam::FixCamWhenObscuredByVehicle, PATCH_JUMP);
|
|
InjectHook(0x457B90, &CCam::FixCamIfObscured, PATCH_JUMP);
|
|
InjectHook(0x465DA0, &CCam::RotCamIfInFrontCar, PATCH_JUMP);
|
|
InjectHook(0x4662D0, &CCam::WorkOutCamHeightWeeCar, PATCH_JUMP);
|
|
InjectHook(0x466650, &CCam::WorkOutCamHeight, PATCH_JUMP);
|
|
|
|
InjectHook(0x45E3A0, &CCam::Process_FollowPed, PATCH_JUMP);
|
|
InjectHook(0x45BE60, &CCam::Process_BehindCar, PATCH_JUMP);
|
|
InjectHook(0x45C090, &CCam::Process_Cam_On_A_String, PATCH_JUMP);
|
|
ENDPATCHES
|