1705 lines
50 KiB
C++
1705 lines
50 KiB
C++
// Copyright (C) 2007 Id Software, Inc.
|
|
//
|
|
|
|
#include "../precompiled.h"
|
|
#pragma hdrstop
|
|
|
|
#if defined( _DEBUG ) && !defined( ID_REDIRECT_NEWDELETE )
|
|
#define new DEBUG_NEW
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
#include "VehicleView.h"
|
|
#include "VehicleWeapon.h"
|
|
#include "Transport.h"
|
|
#include "../ContentMask.h"
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
sdVehicleView
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
sdVehicleViewFactory sdVehicleView::viewFactory;
|
|
|
|
/*
|
|
================
|
|
sdVehicleView::AllocView
|
|
================
|
|
*/
|
|
sdVehicleView* sdVehicleView::AllocView( const char* name ) {
|
|
return viewFactory.CreateType( name );
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdVehicleView::Startup
|
|
================
|
|
*/
|
|
|
|
void sdVehicleView::Startup( void ) {
|
|
viewFactory.RegisterType( sdDampedVehicleView::TypeName(), sdVehicleViewFactory::Allocator< sdDampedVehicleView > );
|
|
viewFactory.RegisterType( "", sdVehicleViewFactory::Allocator< sdDampedVehicleView > );
|
|
viewFactory.RegisterType( sdDampedVehicleView_Pivot::TypeName(), sdVehicleViewFactory::Allocator< sdDampedVehicleView_Pivot > );
|
|
viewFactory.RegisterType( sdDampedVehicleView_FreePivot::TypeName(), sdVehicleViewFactory::Allocator< sdDampedVehicleView_FreePivot > );
|
|
viewFactory.RegisterType( sdDampedVehicleView_Player::TypeName(), sdVehicleViewFactory::Allocator< sdDampedVehicleView_Player > );
|
|
viewFactory.RegisterType( sdSmoothVehicleView::TypeName(), sdVehicleViewFactory::Allocator< sdSmoothVehicleView > );
|
|
viewFactory.RegisterType( sdSmoothVehicleView_Free::TypeName(), sdVehicleViewFactory::Allocator< sdSmoothVehicleView_Free > );
|
|
viewFactory.RegisterType( sdSmoothVehicleView_Locked::TypeName(), sdVehicleViewFactory::Allocator< sdSmoothVehicleView_Locked > );
|
|
viewFactory.RegisterType( sdIcarusVehicleView::TypeName(), sdVehicleViewFactory::Allocator< sdIcarusVehicleView > );
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdVehicleView::Shutdown
|
|
================
|
|
*/
|
|
|
|
void sdVehicleView::Shutdown( void ) {
|
|
viewFactory.Shutdown();
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdVehicleView::Init
|
|
================
|
|
*/
|
|
void sdVehicleView::Init( sdVehiclePosition* _position, const positionViewMode_t& _viewMode ) {
|
|
position = _position;
|
|
viewMode = _viewMode;
|
|
|
|
SetupEyes( position->GetTransport() );
|
|
|
|
zoomTable = gameLocal.declTableType[ viewMode.zoomTable ];
|
|
|
|
sensitivityYaw = cvarSystem->Find( viewMode.sensitivityYaw );
|
|
sensitivityPitch = cvarSystem->Find( viewMode.sensitivityPitch );
|
|
sensitivityYawScale = cvarSystem->Find( viewMode.sensitivityYawScale );
|
|
sensitivityPitchScale = cvarSystem->Find( viewMode.sensitivityPitchScale );
|
|
|
|
thirdPersonViewOrigin.Zero();
|
|
thirdPersonViewAxes.Identity();
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdVehicleView::GetSensitivity
|
|
================
|
|
*/
|
|
bool sdVehicleView::GetSensitivity( float& x, float& y ) {
|
|
bool changed = false;
|
|
if ( sensitivityPitch != NULL ) {
|
|
y = sensitivityPitch->GetFloat();
|
|
changed = true;
|
|
}
|
|
if ( sensitivityYaw != NULL ) {
|
|
x = sensitivityYaw->GetFloat();
|
|
changed = true;
|
|
}
|
|
|
|
if ( sensitivityPitchScale != NULL ) {
|
|
y *= sensitivityPitchScale->GetFloat();
|
|
changed = true;
|
|
}
|
|
if ( sensitivityYawScale != NULL ) {
|
|
x *= sensitivityYawScale->GetFloat();
|
|
changed = true;
|
|
}
|
|
|
|
return changed;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdVehicleView::GetFov
|
|
================
|
|
*/
|
|
float sdVehicleView::GetFov( void ) const {
|
|
if ( !zoomTable ) {
|
|
return 90.0f;
|
|
}
|
|
|
|
idPlayer* player = position->GetPlayer();
|
|
|
|
if ( player->vehicleViewCurrentZoom < 0 || player->vehicleViewCurrentZoom >= zoomTable->NumValues() ) {
|
|
return 90.0f;
|
|
}
|
|
|
|
return zoomTable->GetValue( player->vehicleViewCurrentZoom );
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdVehicleView::ZoomCycle
|
|
================
|
|
*/
|
|
void sdVehicleView::ZoomCycle( void ) const {
|
|
if ( !zoomTable ) {
|
|
return;
|
|
}
|
|
|
|
idPlayer* player = position->GetPlayer();
|
|
player->vehicleViewCurrentZoom++;
|
|
player->vehicleViewCurrentZoom %= zoomTable->NumValues() - 1;
|
|
|
|
if ( player->vehicleViewCurrentZoom == 0 ) {
|
|
gameSoundWorld->PlayShaderDirectly( viewMode.zoomOutSound, SND_VEHICLE_ZOOM );
|
|
} else {
|
|
gameSoundWorld->PlayShaderDirectly( viewMode.zoomInSound, SND_VEHICLE_ZOOM );
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdVehicleView::ClampViewAngles
|
|
================
|
|
*/
|
|
void sdVehicleView::ClampViewAngles( idAngles& viewAngles, const idAngles& oldViewAngles ) const {
|
|
|
|
idAngles oldAngles = oldViewAngles;
|
|
DoFreshEntryAngles( viewAngles, oldAngles );
|
|
|
|
sdVehiclePosition::ClampAngle( viewAngles, oldAngles, viewMode.clampPitch, 0 );
|
|
sdVehiclePosition::ClampAngle( viewAngles, oldAngles, viewMode.clampYaw, 1 );
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdVehicleView::DoFreshEntryAngles
|
|
================
|
|
*/
|
|
void sdVehicleView::DoFreshEntryAngles( idAngles& viewAngles, idAngles& oldAngles ) const {
|
|
if ( freshEntry ) {
|
|
idAngles oldViewAngles = oldAngles;
|
|
|
|
// calculate the angles needed to point in the same direction as pointed
|
|
// when the player entered the vehicle
|
|
freshEntry = false;
|
|
CalcNewViewAngles( oldAngles );
|
|
|
|
idAngles deltaAngles = viewAngles - oldViewAngles;
|
|
viewAngles = oldAngles + deltaAngles;
|
|
viewAngles.Normalize180();
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdVehicleView::ClipView
|
|
================
|
|
*/
|
|
void sdVehicleView::ClipView( idVec3& viewOrigin, const idVec3& pivotPoint ) {
|
|
|
|
idEntity* owner = position->GetTransport();
|
|
owner->DisableClip( false );
|
|
|
|
// HACK: Disable clip of everything bound to it too
|
|
for ( idEntity* ent = owner; ent != NULL; ent = ent->GetNextTeamEntity() ) {
|
|
ent->DisableClip( false );
|
|
}
|
|
|
|
const idClipModel* thirdPersonModel = gameLocal.clip.GetThirdPersonOffsetModel();
|
|
// trace a ray from the origin to the viewpoint to make sure the view isn't
|
|
// in a solid block. Use an 8 by 8 block to prevent the view from near clipping anything
|
|
trace_t trace;
|
|
gameLocal.clip.Translation( CLIP_DEBUG_PARMS trace, pivotPoint, viewOrigin, thirdPersonModel, mat3_identity, MASK_SHOT_RENDERMODEL & ~CONTENTS_FORCEFIELD, owner );
|
|
if ( trace.fraction != 1.0 ) {
|
|
viewOrigin = trace.endpos;
|
|
viewOrigin.z += ( 1.0f - trace.fraction ) * 32.0f;
|
|
|
|
// try another trace to this position, because a tunnel may have the ceiling
|
|
// close enough that this is poking out
|
|
gameLocal.clip.Translation( CLIP_DEBUG_PARMS trace, pivotPoint, viewOrigin, thirdPersonModel, mat3_identity, MASK_SHOT_RENDERMODEL & ~CONTENTS_FORCEFIELD, owner );
|
|
viewOrigin = trace.endpos;
|
|
}
|
|
|
|
owner->EnableClip();
|
|
|
|
for ( idEntity* ent = owner; ent != NULL; ent = ent->GetNextTeamEntity() ) {
|
|
ent->EnableClip();
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdVehicleView::Update
|
|
================
|
|
*/
|
|
void sdVehicleView::Update( sdVehicleWeapon* weapon ) {
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdVehicleView::GetRequiredViewAngles
|
|
================
|
|
*/
|
|
const idAngles sdVehicleView::GetRequiredViewAngles( const idVec3& aimPosition ) const {
|
|
return idAngles( vec3_origin );
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdVehicleView::OnPlayerEntered
|
|
================
|
|
*/
|
|
void sdVehicleView::OnPlayerEntered( idPlayer* player ) {
|
|
GetInitialViewAxis( player->firstPersonViewAxis );
|
|
|
|
OnPlayerSwitched( player, true );
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdVehicleView::OnPlayerSwitched
|
|
================
|
|
*/
|
|
void sdVehicleView::OnPlayerSwitched( idPlayer* player, bool newPosition ) {
|
|
freshEntry = true;
|
|
if ( GetViewParms().matchPrevious || !newPosition ) {
|
|
// aim in the same direction as we were previously aiming
|
|
entryAim = position->GetPlayer()->firstPersonViewAxis;
|
|
} else {
|
|
GetInitialViewAxis( entryAim );
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdVehicleView::GetInitialViewAxis
|
|
================
|
|
*/
|
|
void sdVehicleView::GetInitialViewAxis( idMat3& aim ) const {
|
|
aim = position->GetTransport()->GetAxis();
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdVehicleView::OnTeleport
|
|
================
|
|
*/
|
|
void sdVehicleView::OnTeleport( void ) {
|
|
idPlayer* player = position->GetPlayer();
|
|
OnPlayerEntered( player );
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdVehicleView::ClampFinalAxis
|
|
================
|
|
*/
|
|
void sdVehicleView::ClampFinalAxis( idMat3& axis, const idMat3& baseAxis, idMat3& dampedAxis ) const {
|
|
// clamp this final axis to the damped clamp values
|
|
// need the fovs of the final rendering screen to do it
|
|
const renderView_t& view = gameLocal.playerView.GetCurrentView();
|
|
|
|
// calculate the clamps necessary to prevent the edge of the view exceeding the maximum
|
|
angleClamp_t pitchClamp = viewMode.clampDampedPitch;
|
|
angleClamp_t yawClamp = viewMode.clampDampedYaw;
|
|
pitchClamp.extents[ 0 ] += view.fov_y * 0.5f;
|
|
pitchClamp.extents[ 1 ] -= view.fov_y * 0.5f;
|
|
yawClamp.extents[ 0 ] += view.fov_x * 0.5f;
|
|
yawClamp.extents[ 1 ] -= view.fov_x * 0.5f;
|
|
|
|
idMat3 dampedAxisTransform = axis * dampedAxis.Transpose();
|
|
idMat3 localAxis = axis * baseAxis.Transpose();
|
|
idAngles localAngles = localAxis.ToAngles();
|
|
|
|
idAngles tempAngles = localAngles;
|
|
if ( !sdVehiclePosition::ClampAngle( localAngles, tempAngles, pitchClamp, 0, 0.00001f )
|
|
|| !sdVehiclePosition::ClampAngle( localAngles, tempAngles, yawClamp, 1, 0.00001f ) ) {
|
|
|
|
axis = localAngles.ToMat3() * baseAxis;
|
|
|
|
// now we have the final clamped axis, we can reverse engineer what the damped axis
|
|
// should have been to achieve that... hopefully..
|
|
dampedAxis = dampedAxisTransform.TransposeMultiply( axis );
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
sdDampedVehicleView
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
|
|
/*
|
|
================
|
|
sdDampedVehicleView::SetupEyes
|
|
================
|
|
*/
|
|
void sdDampedVehicleView::SetupEyes( idAnimatedEntity* other ) {
|
|
idAnimator* animator = other->GetAnimator();
|
|
|
|
eyeJoint = animator->GetJointHandle( viewMode.eyes );
|
|
|
|
eyeBaseAxis.Identity();
|
|
|
|
if ( eyeJoint == INVALID_JOINT ) {
|
|
gameLocal.Warning( "sdVehicleView::Init can't find eye joint '%s'", viewMode.eyes.c_str() );
|
|
eyeBaseJoint = INVALID_JOINT;
|
|
} else {
|
|
eyeBaseJoint = animator->GetJointHandle( viewMode.eyePivot );
|
|
if ( eyeBaseJoint == INVALID_JOINT ) {
|
|
eyeBaseJoint = animator->GetJointParent( eyeJoint );
|
|
}
|
|
|
|
if ( eyeBaseJoint != INVALID_JOINT ) {
|
|
idVec3 eyePos;
|
|
idMat3 eyeAxis;
|
|
|
|
other->GetJointTransformForAnim( eyeJoint, 1, gameLocal.time, eyePos, eyeAxis );
|
|
other->GetJointTransformForAnim( eyeBaseJoint, 1, gameLocal.time, eyeBaseOffset, eyeBaseAxis );
|
|
idMat3 eyeBaseAxisT = eyeBaseAxis.Transpose();
|
|
|
|
eyeOffset = ( eyePos - eyeBaseOffset ) * eyeBaseAxisT;
|
|
eyeAxisOffset = eyeBaseAxisT * eyeAxis;
|
|
}
|
|
}
|
|
|
|
lastReturnedAxis = eyeBaseAxis;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDampedVehicleView::GetDampingPos
|
|
================
|
|
*/
|
|
void sdDampedVehicleView::GetDampingPos( idVec3& pos ) const {
|
|
position->GetTransport()->GetWorldOrigin( eyeJoint, pos );
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDampedVehicleView::GetDampingAxis
|
|
================
|
|
*/
|
|
void sdDampedVehicleView::GetDampingAxis( idMat3& axis ) const {
|
|
position->GetTransport()->GetWorldAxis( eyeJoint, axis );
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDampedVehicleView::GetInitialViewAxis
|
|
================
|
|
*/
|
|
void sdDampedVehicleView::GetInitialViewAxis( idMat3& axis ) const {
|
|
position->GetTransport()->GetWorldAxis( eyeJoint, axis );
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDampedVehicleView::DampEyeAxes
|
|
================
|
|
*/
|
|
void sdDampedVehicleView::DampEyeAxes( const idMat3& oldAxes, idMat3& outAxes ) {
|
|
idMat3 vAxes;
|
|
GetDampingAxis( vAxes );
|
|
|
|
if ( !GetViewParms().allowDamping ) {
|
|
outAxes = vAxes;
|
|
return;
|
|
}
|
|
|
|
for ( int i = 0; i < 3; i++ ) {
|
|
outAxes[ i ] = Lerp( oldAxes[ i ], vAxes[ i ], viewMode.dampCopyFactor[ i ] );
|
|
}
|
|
|
|
idQuat a = outAxes.ToQuat();
|
|
idQuat b = vAxes.ToQuat();
|
|
idQuat c;
|
|
c.Slerp( a, b, MS2SEC( gameLocal.msec ) / viewMode.dampSpeed );
|
|
c.Normalize();
|
|
|
|
outAxes = c.ToMat3();
|
|
outAxes.FixDenormals();
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDampedVehicleView::CalcViewOrigin
|
|
================
|
|
*/
|
|
void sdDampedVehicleView::CalcViewOrigin( const idMat3& dampedAxis, const idVec3& posIn, idVec3& posOut, const idAngles& angles ) {
|
|
posOut = posIn;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDampedVehicleView::CalcViewAxes
|
|
================
|
|
*/
|
|
void sdDampedVehicleView::CalcViewAxes( const idMat3& axisIn, idMat3& axisOut, const idAngles& angles ) {
|
|
axisOut = angles.ToMat3() * axisIn;
|
|
|
|
if ( !viewMode.thirdPerson ) {
|
|
sdTransport* transport = position->GetTransport();
|
|
|
|
idRotation rotation;
|
|
rotation.SetVec( transport->GetPhysics()->GetAxis()[ 2 ] );
|
|
rotation.SetAngle( position->GetCurrentViewOffset() );
|
|
|
|
axisOut *= rotation.ToMat3();
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============
|
|
sdDampedVehicleView::CalcThirdPersonView
|
|
===============
|
|
*/
|
|
void sdDampedVehicleView::CalcThirdPersonView( const idVec3& fpOrigin, const idMat3& fpAxis ) {
|
|
|
|
idEntity* owner = position->GetTransport();
|
|
|
|
idVec3 origin = fpOrigin;
|
|
thirdPersonViewAxes = fpAxis;
|
|
|
|
idVec3 focusPoint = origin + thirdPersonViewAxes[ 0 ] * viewMode.cameraFocus + owner->GetAxis()[ 2 ] * viewMode.cameraFocusHeight;
|
|
idVec3 view = origin;
|
|
view.z += 8 + viewMode.cameraHeight;
|
|
|
|
idAngles angles = thirdPersonViewAxes.ToAngles();
|
|
|
|
view -= viewMode.cameraDistance * thirdPersonViewAxes[ 0 ];
|
|
|
|
ClipView( view, origin );
|
|
|
|
// select pitch to look at focus point from vieworg
|
|
focusPoint -= view;
|
|
float focusDist = idMath::Sqrt( focusPoint[0] * focusPoint[0] + focusPoint[1] * focusPoint[1] );
|
|
if ( focusDist < 1 ) {
|
|
focusDist = 1; // should never happen
|
|
}
|
|
|
|
angles.pitch = - RAD2DEG( atan2( focusPoint.z, focusDist ) );
|
|
|
|
thirdPersonViewOrigin = view;
|
|
thirdPersonViewAxes = angles.ToMat3();
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDampedVehicleView::CalculateViewPos
|
|
================
|
|
*/
|
|
void sdDampedVehicleView::CalculateViewPos( idPlayer* player, idVec3& origin, idMat3& axis, bool fullUpdate ) {
|
|
if ( fullUpdate ) {
|
|
if ( freshEntry ) {
|
|
// ensure that the angles have been clamped to the valid range
|
|
idAngles tempAngles = player->clientViewAngles;
|
|
ClampViewAngles( player->clientViewAngles, tempAngles );
|
|
freshEntry = true;
|
|
}
|
|
|
|
|
|
// damping
|
|
DampEyeAxes( player->vehicleEyeAxis, player->vehicleEyeAxis );
|
|
GetDampingPos( player->vehicleEyeOrigin );
|
|
}
|
|
|
|
// axis
|
|
CalcViewAxes( player->vehicleEyeAxis, axis, player->clientViewAngles );
|
|
|
|
if ( fullUpdate ) {
|
|
// clamp the final result
|
|
idMat3 baseAxis;
|
|
GetDampingAxis( baseAxis );
|
|
ClampFinalAxis( axis, baseAxis, player->vehicleEyeAxis );
|
|
}
|
|
|
|
// origin
|
|
CalcViewOrigin( player->vehicleEyeAxis, player->vehicleEyeOrigin, origin, player->clientViewAngles );
|
|
|
|
|
|
if ( viewMode.thirdPerson ) {
|
|
CalcThirdPersonView( origin, axis );
|
|
}
|
|
|
|
lastReturnedAxis = axis;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDampedVehicleView::OnPlayerSwitched
|
|
================
|
|
*/
|
|
void sdDampedVehicleView::OnPlayerSwitched( idPlayer* player, bool newPosition ) {
|
|
GetDampingAxis( player->vehicleEyeAxis );
|
|
|
|
sdVehicleView::OnPlayerSwitched( player, newPosition );
|
|
|
|
lastReturnedAxis = player->firstPersonViewAxis;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDampedVehicleView::GetRequiredViewAngles
|
|
================
|
|
*/
|
|
const idAngles sdDampedVehicleView::GetRequiredViewAngles( const idVec3& aimPosition ) const {
|
|
idVec3 eyePos;
|
|
GetDampingPos( eyePos );
|
|
|
|
idVec3 deltaPos = aimPosition - eyePos;
|
|
const idMat3& ownerAxis = position->GetTransport()->GetAxis();
|
|
|
|
// find the delta in car space
|
|
idVec3 deltaDirection = deltaPos;
|
|
deltaDirection.Normalize();
|
|
deltaDirection = deltaDirection * ownerAxis.Transpose();
|
|
|
|
idAngles result = deltaDirection.ToAngles();
|
|
result.Normalize180();
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDampedVehicleView::CalcNewViewAngles
|
|
================
|
|
*/
|
|
void sdDampedVehicleView::CalcNewViewAngles( idAngles& angles ) const {
|
|
idMat3 dampAxis;
|
|
GetDampingAxis( dampAxis );
|
|
|
|
idMat3 angleMat = entryAim * dampAxis.Transpose();
|
|
angles = angleMat[ 0 ].ToAngles();
|
|
}
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
sdDampedVehicleView_Pivot
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
/*
|
|
================
|
|
sdDampedVehicleView_Pivot::GetDampingAxis
|
|
================
|
|
*/
|
|
void sdDampedVehicleView_Pivot::GetDampingAxis( idMat3& axis ) const {
|
|
axis = position->GetTransport()->GetRenderEntity()->axis;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDampedVehicleView_Pivot::GetDampingPos
|
|
================
|
|
*/
|
|
void sdDampedVehicleView_Pivot::GetDampingPos( idVec3& pos ) const {
|
|
position->GetTransport()->GetWorldOrigin( eyeBaseJoint, pos );
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDampedVehicleView_Pivot::CalcViewOrigin
|
|
================
|
|
*/
|
|
void sdDampedVehicleView_Pivot::CalcViewOrigin( const idMat3& dampedAxis, const idVec3& posIn, idVec3& posOut, const idAngles& angles ) {
|
|
idMat3 gunRotation = mat3_identity;
|
|
|
|
idMat3 temp;
|
|
|
|
if ( viewMode.followPitch ) {
|
|
idAngles::PitchToMat3( angles.pitch, temp );
|
|
gunRotation *= temp;
|
|
}
|
|
|
|
if ( viewMode.followYaw ) {
|
|
idAngles::YawToMat3( angles.yaw, temp );
|
|
gunRotation *= temp;
|
|
}
|
|
|
|
posOut = posIn + ( eyeOffset * eyeBaseAxis ) * gunRotation * dampedAxis;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDampedVehicleView_Pivot::GetRequiredViewAngles
|
|
================
|
|
*/
|
|
const idAngles sdDampedVehicleView_Pivot::GetRequiredViewAngles( const idVec3& aimPosition ) const {
|
|
// FIXME: This isn't quite correct, it doesn't take the arm into account properly.
|
|
return sdDampedVehicleView::GetRequiredViewAngles( aimPosition );
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDampedVehicleView_Pivot::CalcNewViewAngles
|
|
================
|
|
*/
|
|
void sdDampedVehicleView_Pivot::CalcNewViewAngles( idAngles& angles ) const {
|
|
sdDampedVehicleView::CalcNewViewAngles( angles );
|
|
}
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
sdDampedVehicleView_FreePivot
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
/*
|
|
================
|
|
sdDampedVehicleView_FreePivot::GetDampingAxis
|
|
================
|
|
*/
|
|
void sdDampedVehicleView_FreePivot::GetDampingAxis( idMat3& axis ) const {
|
|
axis = mat3_identity;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDampedVehicleView_FreePivot::ClampViewAngles
|
|
================
|
|
*/
|
|
void sdDampedVehicleView_FreePivot::ClampViewAngles( idAngles& viewAngles, const idAngles& oldViewAngles ) const {
|
|
if ( !freshEntry ) {
|
|
// convert angle delta into one in screen space
|
|
idAngles oldFinalViewAngles = lastReturnedAxis.ToAngles();
|
|
|
|
idMat2 rotMat;
|
|
rotMat.Rotation( DEG2RAD( oldFinalViewAngles.roll ) );
|
|
idAngles deltaAngles = ( viewAngles - oldViewAngles ).Normalize180();
|
|
idVec2 deltaVec( deltaAngles.yaw, deltaAngles.pitch );
|
|
deltaVec *= rotMat;
|
|
|
|
deltaAngles.yaw = deltaVec[ 0 ];
|
|
deltaAngles.pitch = deltaVec[ 1 ];
|
|
|
|
viewAngles = oldViewAngles + deltaAngles;
|
|
}
|
|
|
|
idAngles oldAngles = oldViewAngles;
|
|
DoFreshEntryAngles( viewAngles, oldAngles );
|
|
|
|
// do a clamp to prevent it going crazy when the player looks all the way up or all the way down
|
|
angleClamp_t flipClamp;
|
|
flipClamp.extents.x = -80.0f;
|
|
flipClamp.extents.y = 80.0f;
|
|
flipClamp.flags.enabled = true;
|
|
flipClamp.flags.limitRate = false;
|
|
|
|
sdVehiclePosition::ClampAngle( viewAngles, oldAngles, flipClamp, 0 );
|
|
|
|
// move angles back into "clamping space" using the damping axis to find a transform
|
|
idMat3 ownerAxis = position->GetTransport()->GetRenderEntity()->axis;
|
|
idMat3 dampingAxis;
|
|
GetDampingAxis( dampingAxis );
|
|
|
|
idMat3 dampingSpaceToClampSpace = ownerAxis.TransposeMultiply( dampingAxis );
|
|
|
|
// transform forward vectors into clamping space & convert back to angles
|
|
idAngles ownerSpaceOldAngles = ( oldAngles.ToForward() * dampingSpaceToClampSpace ).ToAngles();
|
|
idAngles ownerSpaceAngles = ( viewAngles.ToForward() * dampingSpaceToClampSpace ).ToAngles();
|
|
ownerSpaceAngles.Normalize180();
|
|
ownerSpaceOldAngles.Normalize180();
|
|
|
|
sdVehiclePosition::ClampAngle( ownerSpaceAngles, ownerSpaceOldAngles, viewMode.clampPitch, 0 );
|
|
sdVehiclePosition::ClampAngle( ownerSpaceAngles, ownerSpaceOldAngles, viewMode.clampYaw, 1 );
|
|
|
|
// now transform the clamped angle back into clamping space
|
|
viewAngles = ( dampingSpaceToClampSpace.TransposeMultiply( ownerSpaceAngles.ToForward() ) ).ToAngles();
|
|
viewAngles.Normalize180();
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDampedVehicleView_FreePivot::CalcViewAxes
|
|
================
|
|
*/
|
|
void sdDampedVehicleView_FreePivot::CalcViewAxes( const idMat3& axisIn, idMat3& axisOut, const idAngles& angles ) {
|
|
axisOut = angles.ToMat3() * axisIn;
|
|
|
|
idMat3 ownerAxes = position->GetTransport()->GetRenderEntity()->axis;
|
|
|
|
// stick the up axis of the vehicle in as the z axis and renormalize
|
|
axisOut[ 2 ] = ownerAxes[ 2 ];
|
|
|
|
axisOut[ 1 ].Cross( axisOut[ 2 ], axisOut[ 0 ] );
|
|
axisOut[ 1 ].Normalize();
|
|
|
|
axisOut[ 2 ].Cross( axisOut[ 0 ], axisOut[ 1 ] );
|
|
axisOut[ 2 ].Normalize();
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDampedVehicleView_FreePivot::CalculateViewPos
|
|
================
|
|
*/
|
|
void sdDampedVehicleView_FreePivot::CalculateViewPos( idPlayer* player, idVec3& origin, idMat3& axis, bool fullUpdate ) {
|
|
if ( fullUpdate ) {
|
|
if ( freshEntry ) {
|
|
// ensure that the angles have been clamped to the valid range
|
|
idAngles tempAngles = player->clientViewAngles;
|
|
ClampViewAngles( player->clientViewAngles, tempAngles );
|
|
freshEntry = true;
|
|
}
|
|
|
|
// damping
|
|
DampEyeAxes( player->vehicleEyeAxis, player->vehicleEyeAxis );
|
|
GetDampingPos( player->vehicleEyeOrigin );
|
|
}
|
|
|
|
// axis
|
|
CalcViewAxes( player->vehicleEyeAxis, axis, player->clientViewAngles );
|
|
|
|
if ( fullUpdate ) {
|
|
ClampFinalAxis( axis, mat3_identity, player->vehicleEyeAxis );
|
|
}
|
|
|
|
// origin
|
|
CalcViewOrigin( axis, player->vehicleEyeOrigin, origin, ang_zero );
|
|
|
|
if ( viewMode.thirdPerson ) {
|
|
CalcThirdPersonView( origin, axis );
|
|
}
|
|
|
|
lastReturnedAxis = axis;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDampedVehicleView_FreePivot::GetRequiredViewAngles
|
|
================
|
|
*/
|
|
const idAngles sdDampedVehicleView_FreePivot::GetRequiredViewAngles( const idVec3& aimPosition ) const {
|
|
|
|
// FIXME: This isn't quite correct, it doesn't take the arm into account properly.
|
|
|
|
idVec3 eyePos;
|
|
// position->GetTransport()->GetWorldOrigin( eyeJoint, eyePos );
|
|
GetDampingPos( eyePos );
|
|
|
|
idVec3 deltaDirection = aimPosition - eyePos;
|
|
deltaDirection.Normalize();
|
|
|
|
deltaDirection *= eyeAxisOffset.Transpose();
|
|
|
|
idAngles result = deltaDirection.ToAngles();
|
|
result.Normalize180();
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDampedVehicleView_FreePivot::CalcNewViewAngles
|
|
================
|
|
*/
|
|
void sdDampedVehicleView_FreePivot::CalcNewViewAngles( idAngles& angles ) const {
|
|
angles = entryAim[ 0 ].ToAngles();
|
|
}
|
|
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
sdDampedVehicleView_Player
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
/*
|
|
================
|
|
sdDampedVehicleView_Player::Init
|
|
================
|
|
*/
|
|
void sdDampedVehicleView_Player::Init( sdVehiclePosition* _position, const positionViewMode_t& _viewMode ) {
|
|
position = _position;
|
|
viewMode = _viewMode;
|
|
|
|
zoomTable = NULL;
|
|
|
|
sensitivityYaw = NULL;
|
|
sensitivityPitch = NULL;
|
|
sensitivityYawScale = NULL;
|
|
sensitivityPitchScale = NULL;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDampedVehicleView_Player::CalcViewAxes
|
|
================
|
|
*/
|
|
void sdDampedVehicleView_Player::CalcViewAxes( const idMat3& axisIn, idMat3& axisOut, const idAngles& angles ) {
|
|
axisOut = position->GetTransport()->GetAxis() * axisIn;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDampedVehicleView_Player::CalcViewOrigin
|
|
================
|
|
*/
|
|
void sdDampedVehicleView_Player::CalcViewOrigin( const idMat3& dampedAxis, const idVec3& posIn, idVec3& posOut, const idAngles& angles ) {
|
|
posOut = posIn;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDampedVehicleView_Player::GetDampingPos
|
|
================
|
|
*/
|
|
void sdDampedVehicleView_Player::GetDampingPos( idVec3& pos ) const {
|
|
renderEntity_t* renderEnt = position->GetTransport()->GetRenderEntity();
|
|
pos = renderEnt->origin + idVec3( 0.f, 0.f, 72.f );
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDampedVehicleView_Player::GetDampingAxis
|
|
================
|
|
*/
|
|
void sdDampedVehicleView_Player::GetDampingAxis( idMat3& axis ) const {
|
|
axis = mat3_identity;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDampedVehicleView_Player::GetRequiredViewAngles
|
|
================
|
|
*/
|
|
const idAngles sdDampedVehicleView_Player::GetRequiredViewAngles( const idVec3& aimPosition ) const {
|
|
return sdDampedVehicleView::GetRequiredViewAngles( aimPosition );
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDampedVehicleView_Player::CalcNewViewAngles
|
|
================
|
|
*/
|
|
void sdDampedVehicleView_Player::CalcNewViewAngles( idAngles& angles ) const {
|
|
}
|
|
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
sdSmoothVehicleView
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
/*
|
|
================
|
|
sdSmoothVehicleView::Init
|
|
================
|
|
*/
|
|
void sdSmoothVehicleView::Init( sdVehiclePosition* _position, const positionViewMode_t& _viewMode ) {
|
|
previousAimMatrix.Identity();
|
|
previousRawAimMatrix.Identity();
|
|
previousCameraDistance = _viewMode.cameraDistance;
|
|
previousOwnerOrigin.Zero();
|
|
previousCameraHeightDelta = 0.0f;
|
|
|
|
sdVehicleView::Init( _position, _viewMode );
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdSmoothVehicleView::ClampViewAngles
|
|
================
|
|
*/
|
|
void sdSmoothVehicleView::ClampViewAngles( idAngles& viewAngles, const idAngles& oldViewAngles ) const {
|
|
|
|
idAngles oldAngles = oldViewAngles;
|
|
DoFreshEntryAngles( viewAngles, oldAngles );
|
|
|
|
idPhysics* ownerPhysics = position->GetTransport()->GetPhysics();
|
|
const idMat3& ownerAxes = ownerPhysics->GetAxis();
|
|
|
|
|
|
// transform the angles from world space into local space
|
|
const idMat3 ownerAxesT = ownerAxes.Transpose();
|
|
|
|
// pitch is not relative to the vehicle but yaw is!
|
|
idAngles ownerAngles = ownerAxes.ToAngles();
|
|
viewAngles.yaw += ownerAngles.yaw;
|
|
oldAngles.yaw += ownerAngles.yaw;
|
|
|
|
idAngles localSpaceViewAngles = ( viewAngles.ToMat3() * ownerAxesT ).ToAngles();
|
|
idAngles localSpaceOldAngles = ( oldAngles.ToMat3() * ownerAxesT ).ToAngles();
|
|
|
|
sdVehiclePosition::ClampAngle( localSpaceViewAngles, localSpaceOldAngles, viewMode.clampPitch, 0 );
|
|
sdVehiclePosition::ClampAngle( localSpaceViewAngles, localSpaceOldAngles, viewMode.clampYaw, 1 );
|
|
|
|
// transform the clamped angles back into world space
|
|
viewAngles = ( localSpaceViewAngles.ToMat3() * ownerAxes )[ 0 ].ToAngles();
|
|
|
|
viewAngles.yaw -= ownerAngles.yaw;
|
|
|
|
// clean out the roll, it has a habit of accumulating little values
|
|
viewAngles.roll = 0.0f;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdSmoothVehicleView::CalcNewViewAngles
|
|
================
|
|
*/
|
|
void sdSmoothVehicleView::CalcNewViewAngles( idAngles& angles ) const {
|
|
// yaw relative to body
|
|
const idMat3& ownerAxes = position->GetTransport()->GetPhysics()->GetAxis();
|
|
idAngles ownerAngles = ownerAxes[ 0 ].ToAngles();
|
|
|
|
angles = entryAim[ 0 ].ToAngles();
|
|
angles.yaw -= ownerAngles.yaw;
|
|
angles.Normalize180();
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdSmoothVehicleView::CalculateAimMatrix
|
|
================
|
|
*/
|
|
void sdSmoothVehicleView::CalculateAimMatrix( const viewEvalProperties_t& state ) {
|
|
// in this mode yaw is based off the owner, but pitch is free to smooth out bumps :)
|
|
idMat3 yawMat = ( idRotation( vec3_origin, idVec3( 0.0f, 0.0f, 1.0f ), -state.viewAngles.yaw - state.ownerAngles.yaw ) ).ToMat3();
|
|
idMat3 pitchMat = ( idRotation( vec3_origin, idVec3( 0.0f, 1.0f, 0.0f ), -state.viewAngles.pitch ) ).ToMat3();
|
|
|
|
evalState.aimMatrix = pitchMat * yawMat;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdSmoothVehicleView::ClampToViewConstraints
|
|
================
|
|
*/
|
|
void sdSmoothVehicleView::ClampToViewConstraints( const viewEvalProperties_t& state ) {
|
|
// clamp the resultant angles
|
|
idAngles localAxisAngles = ( evalState.cameraAxis * state.ownerAxesT ).ToAngles();
|
|
idAngles clampedAxisAngles = localAxisAngles;
|
|
bool changed = false;
|
|
changed = !sdVehiclePosition::ClampAngle( clampedAxisAngles, localAxisAngles, viewMode.clampPitch, 0 );
|
|
changed |= !sdVehiclePosition::ClampAngle( clampedAxisAngles, localAxisAngles, viewMode.clampYaw, 1 );
|
|
// clampedAxisAngles.roll = 0.0f;
|
|
|
|
idMat3 ownerSpaceAxis = clampedAxisAngles.ToMat3();
|
|
if ( changed ) {
|
|
evalState.cameraAxis = ownerSpaceAxis * state.ownerAxes;
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdSmoothVehicleView::ClampToWorld
|
|
================
|
|
*/
|
|
void sdSmoothVehicleView::ClampToWorld( const viewEvalProperties_t& state ) {
|
|
ClipView( evalState.cameraOrigin, state.ownerCenter );
|
|
evalState.newCameraDistance = ( state.ownerCenter - evalState.cameraOrigin ).Length();
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdSmoothVehicleView::CalculateCameraDelta
|
|
================
|
|
*/
|
|
idVec3 sdSmoothVehicleView::CalculateCameraDelta( const viewEvalProperties_t& state ) {
|
|
float cameraDist = viewMode.cameraDistance;
|
|
float cameraHeight = viewMode.cameraHeight;
|
|
|
|
idVec3 cameraDelta( -cameraDist, 0.0f, cameraHeight );
|
|
cameraDelta = cameraDelta * evalState.aimMatrix;
|
|
|
|
return cameraDelta;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdSmoothVehicleView::DampenMotion
|
|
================
|
|
*/
|
|
void sdSmoothVehicleView::DampenMotion( const viewEvalProperties_t& state ) {
|
|
if ( !firstFrame ) {
|
|
// find the difference in aiming matrices
|
|
idMat3 aimingDiff = previousAimMatrix.Transpose() * ( evalState.ownerYawAxis.Transpose() * evalState.aimMatrix );
|
|
|
|
// find the difference in result matrices
|
|
idMat3 resultDiff = state.oldAxis.Transpose() * evalState.cameraAxis;
|
|
|
|
// remove the result contribution by the view angle changes
|
|
resultDiff = resultDiff * aimingDiff.Transpose();
|
|
|
|
// now! this result is the change in viewing axis caused by car movement only!
|
|
// damp out the yaw & pitch caused by the car movement
|
|
idAngles angleDiff = resultDiff.ToAngles();
|
|
angleDiff.yaw = DampenYaw( angleDiff.yaw );
|
|
angleDiff.pitch = DampenPitch( angleDiff.pitch );
|
|
|
|
resultDiff = angleDiff.ToMat3();
|
|
evalState.cameraAxis = state.oldAxis * resultDiff * aimingDiff;
|
|
|
|
// ok, this is kinda dodgy isn't it? but it smooths out the tiny
|
|
// fluctuations that creep in at really low level
|
|
idAngles tempAngles = evalState.cameraAxis.ToAngles();
|
|
tempAngles.yaw = idMath::Floor( tempAngles.yaw * 100000.0f ) / 100000.0f;
|
|
tempAngles.pitch = idMath::Floor( tempAngles.pitch * 100000.0f ) / 100000.0f;
|
|
tempAngles.roll = idMath::Floor( tempAngles.roll * 100000.0f ) / 100000.0f;
|
|
evalState.cameraAxis = tempAngles.ToMat3();
|
|
|
|
// FINALLY - eliminate any roll component
|
|
idVec3 newUp( 0.0f, 0.0f, 1.0f );
|
|
idVec3 newRight = newUp.Cross( evalState.cameraAxis[ 0 ] );
|
|
newRight.Normalize();
|
|
newUp = evalState.cameraAxis[ 0 ].Cross( newRight );
|
|
newUp.Normalize();
|
|
|
|
evalState.cameraAxis[ 1 ] = newRight;
|
|
evalState.cameraAxis[ 2 ] = newUp;
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdSmoothVehicleView::DoTeleporting
|
|
================
|
|
*/
|
|
void sdSmoothVehicleView::DoTeleporting( viewEvalProperties_t& state ) const {
|
|
state.viewAngles.Zero();
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdSmoothVehicleView::CalculateViewPos
|
|
================
|
|
*/
|
|
void sdSmoothVehicleView::CalculateViewPos( idPlayer* player, idVec3& origin, idMat3& axis, bool fullUpdate ) {
|
|
if ( !fullUpdate ) {
|
|
origin = thirdPersonViewOrigin;
|
|
axis = thirdPersonViewAxes;
|
|
return;
|
|
}
|
|
|
|
if ( freshEntry ) {
|
|
// ensure that the angles have been clamped to the valid range
|
|
idAngles tempAngles = player->clientViewAngles;
|
|
ClampViewAngles( player->clientViewAngles, tempAngles );
|
|
freshEntry = true;
|
|
}
|
|
|
|
// Harvest data
|
|
viewEvalProperties_t state;
|
|
state.driver = player;
|
|
state.oldOrigin = origin;
|
|
state.oldAxis = axis;
|
|
state.oldAxisAngles = axis.ToAngles();
|
|
state.viewAngles = player->clientViewAngles;
|
|
state.owner = position->GetTransport();
|
|
state.ownerPhysics = state.owner->GetPhysics();
|
|
state.ownerOrigin = state.owner->GetLastPushedOrigin();
|
|
state.ownerAxes = state.owner->GetLastPushedAxis();
|
|
state.ownerAxesT = state.ownerAxes.Transpose();
|
|
state.ownerAngles = state.ownerAxes.ToAngles();
|
|
idAngles::YawToMat3( state.ownerAngles.yaw, evalState.ownerYawAxis );
|
|
state.ownerVelocity = state.ownerPhysics->GetLinearVelocity();
|
|
state.ownerDirection = state.ownerVelocity;
|
|
state.ownerSpeed = state.ownerDirection.NormalizeFast();
|
|
|
|
if ( position->GetTransport()->IsTeleporting() ) {
|
|
DoTeleporting( state );
|
|
}
|
|
|
|
state.timeStep = MS2SEC( gameLocal.msec );
|
|
|
|
evalState.cameraAxis = axis;
|
|
|
|
// TODO: store this joint handle
|
|
jointHandle_t eyeJoint = position->GetTransport()->GetAnimator()->GetJointHandle( viewMode.eyes );
|
|
if ( eyeJoint != INVALID_JOINT ) {
|
|
idMat3 tempAxes;
|
|
state.owner->GetWorldOriginAxisNoUpdate( eyeJoint, state.ownerOrigin, tempAxes );
|
|
}
|
|
|
|
state.ownerCenter = state.ownerPhysics->GetBounds().GetCenter() * state.ownerAxes + state.ownerOrigin;
|
|
previousOwnerOrigin = state.ownerOrigin;
|
|
|
|
|
|
//
|
|
// Aiming
|
|
//
|
|
CalculateAimMatrix( state );
|
|
idVec3 cameraDelta = CalculateCameraDelta( state );
|
|
evalState.cameraOrigin = cameraDelta + state.ownerOrigin;
|
|
|
|
previousRawAimMatrix = evalState.aimMatrix;
|
|
|
|
//
|
|
// Focusing on the target
|
|
//
|
|
|
|
// calculate the axes so its looking at the focus point
|
|
float focusPointHeight = viewMode.cameraHeight;
|
|
evalState.focusPoint = state.ownerOrigin + idVec3( 0.0f, 0.0f, focusPointHeight );
|
|
|
|
idVec3 deltaToCar = evalState.focusPoint - evalState.cameraOrigin;
|
|
deltaToCar.Normalize();
|
|
evalState.cameraAxis = deltaToCar.ToMat3();
|
|
|
|
//
|
|
// Clamping to the view constraints
|
|
//
|
|
ClampToViewConstraints( state );
|
|
|
|
// remove roll
|
|
evalState.cameraAxis = ( evalState.cameraAxis[ 0 ].ToAngles() ).ToMat3();
|
|
|
|
//
|
|
// Prevent it clipping through the vehicle
|
|
//
|
|
float focusLength = ( evalState.focusPoint - evalState.cameraOrigin ).Length();
|
|
|
|
//
|
|
// Damping
|
|
//
|
|
|
|
// do some dampening of the camera movement based on the vehicle movement
|
|
DampenMotion( state );
|
|
previousAimMatrix = evalState.ownerYawAxis.Transpose() * evalState.aimMatrix;
|
|
|
|
// fix up the camera origin (as the axis may have changed)
|
|
evalState.cameraOrigin = evalState.focusPoint - evalState.cameraAxis[ 0 ] * focusLength;
|
|
|
|
//
|
|
// Prevent it clipping through the world
|
|
//
|
|
idVec3 distanceClampDirection = state.ownerCenter - evalState.cameraOrigin;
|
|
evalState.newCameraDistance = distanceClampDirection.Normalize();
|
|
evalState.newCameraHeightDelta = 0.0f;
|
|
|
|
ClampToWorld( state );
|
|
|
|
|
|
//
|
|
// Prevent it clipping through the vehicle
|
|
//
|
|
idClipModel* combatModel = state.owner->GetCombatModel();
|
|
if ( combatModel != NULL ) {
|
|
idBounds bounds = combatModel->GetBounds();
|
|
idBounds absBounds = combatModel->GetAbsBounds();
|
|
|
|
idVec3 traceDownStart = evalState.cameraOrigin;
|
|
idVec3 traceDownEnd = evalState.cameraOrigin;
|
|
|
|
float traceLength = absBounds.GetSize().z;
|
|
traceDownStart.z += traceLength;
|
|
|
|
if ( absBounds.LineIntersection( traceDownStart, traceDownEnd ) ) {
|
|
// it intersects the abs bounds so theres a chance that it'll collide with the combat model
|
|
float traceRadius = 32.0f;
|
|
traceDownStart.z -= traceRadius;
|
|
traceDownEnd.z -= traceRadius;
|
|
|
|
// check against the combat model
|
|
trace_t trace;
|
|
trace.fraction = 1.0f;
|
|
gameLocal.clip.TraceRenderModel( trace, traceDownStart, traceDownEnd, traceRadius, mat3_identity, -1, combatModel );
|
|
float tracedDistance = trace.fraction * traceLength;
|
|
if ( trace.fraction < 1.0f ) {
|
|
evalState.newCameraHeightDelta = trace.endpos.z + 8.0f - evalState.cameraOrigin.z;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Damp out the camera height when lowering rapidly
|
|
//
|
|
if ( evalState.newCameraHeightDelta < previousCameraHeightDelta ) {
|
|
evalState.newCameraHeightDelta -= ( evalState.newCameraHeightDelta - previousCameraHeightDelta ) * ( 1.0f - viewMode.dampSpeed );
|
|
if ( evalState.newCameraHeightDelta < 0.001f ) {
|
|
evalState.newCameraHeightDelta = 0.001f;
|
|
}
|
|
}
|
|
if ( evalState.newCameraHeightDelta > 0.0f ) {
|
|
evalState.cameraOrigin.z += evalState.newCameraHeightDelta;
|
|
|
|
// Re-clamp to the world to make sure it doesn't go through anything as a result
|
|
ClampToWorld( state );
|
|
}
|
|
|
|
//
|
|
// Damp out the camera distance when going out rapidly
|
|
//
|
|
distanceClampDirection = state.ownerCenter - evalState.cameraOrigin;
|
|
evalState.newCameraDistance = distanceClampDirection.Normalize();
|
|
if ( evalState.newCameraDistance > previousCameraDistance ) {
|
|
evalState.newCameraDistance -= ( evalState.newCameraDistance - previousCameraDistance ) * ( 1.0f - viewMode.dampSpeed );
|
|
}
|
|
evalState.cameraOrigin = state.ownerCenter - distanceClampDirection * evalState.newCameraDistance;
|
|
|
|
previousCameraDistance = evalState.newCameraDistance;
|
|
previousCameraHeightDelta = evalState.newCameraHeightDelta;
|
|
|
|
origin = evalState.cameraOrigin;
|
|
axis = evalState.cameraAxis;
|
|
|
|
// clamp the final result
|
|
idMat3 temp = mat3_identity;
|
|
ClampFinalAxis( axis, mat3_identity, temp );
|
|
|
|
thirdPersonViewOrigin = origin;
|
|
thirdPersonViewAxes = axis;
|
|
|
|
firstFrame = false;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdSmoothVehicleView::SetupEyes
|
|
================
|
|
*/
|
|
void sdSmoothVehicleView::SetupEyes( idAnimatedEntity* other ) {
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdSmoothVehicleView::GetRequiredViewAngles
|
|
================
|
|
*/
|
|
const idAngles sdSmoothVehicleView::GetRequiredViewAngles( const idVec3& aimPosition ) const {
|
|
return idAngles( vec3_origin );
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdSmoothVehicleView::OnPlayerSwitched
|
|
================
|
|
*/
|
|
void sdSmoothVehicleView::OnPlayerSwitched( idPlayer* player, bool newPosition ) {
|
|
sdVehicleView::OnPlayerSwitched( player, newPosition );
|
|
|
|
firstFrame = true;
|
|
previousAimMatrix.Identity();
|
|
previousRawAimMatrix.Identity();
|
|
previousCameraDistance = viewMode.cameraDistance;
|
|
previousOwnerOrigin.Zero();
|
|
previousCameraHeightDelta = 0.0f;
|
|
}
|
|
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
sdSmoothVehicleView_Free
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
/*
|
|
================
|
|
sdSmoothVehicleView_Free::ClampViewAngles
|
|
================
|
|
*/
|
|
void sdSmoothVehicleView_Free::ClampViewAngles( idAngles& viewAngles, const idAngles& oldViewAngles ) const {
|
|
|
|
idAngles oldAngles = oldViewAngles;
|
|
DoFreshEntryAngles( viewAngles, oldAngles );
|
|
|
|
idPhysics* ownerPhysics = position->GetTransport()->GetPhysics();
|
|
const idMat3& ownerAxes = ownerPhysics->GetAxis();
|
|
|
|
// transform the angles from world space into local space
|
|
const idMat3 ownerAxesT = ownerAxes.Transpose();
|
|
|
|
idAngles localSpaceViewAngles = ( viewAngles.ToMat3() * ownerAxesT ).ToAngles();
|
|
idAngles localSpaceOldAngles = ( oldAngles.ToMat3() * ownerAxesT ).ToAngles();
|
|
|
|
sdVehiclePosition::ClampAngle( localSpaceViewAngles, localSpaceOldAngles, viewMode.clampPitch, 0 );
|
|
sdVehiclePosition::ClampAngle( localSpaceViewAngles, localSpaceOldAngles, viewMode.clampYaw, 1 );
|
|
|
|
// transform the clamped angles back into world space
|
|
viewAngles = ( localSpaceViewAngles.ToMat3() * ownerAxes ).ToAngles();
|
|
|
|
// clean out the roll, it has a habit of accumulating little values
|
|
viewAngles.roll = 0.0f;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdSmoothVehicleView_Free::CalcNewViewAngles
|
|
================
|
|
*/
|
|
void sdSmoothVehicleView_Free::CalcNewViewAngles( idAngles& angles ) const {
|
|
// angles relative to world
|
|
angles = entryAim[ 0 ].ToAngles();
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdSmoothVehicleView_Free::DoTeleporting
|
|
================
|
|
*/
|
|
void sdSmoothVehicleView_Free::DoTeleporting( viewEvalProperties_t& state ) const {
|
|
state.viewAngles = state.ownerAngles;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdSmoothVehicleView_Free::CalculateAimMatrix
|
|
================
|
|
*/
|
|
void sdSmoothVehicleView_Free::CalculateAimMatrix( const viewEvalProperties_t& state ) {
|
|
evalState.aimMatrix = state.viewAngles.ToMat3();
|
|
}
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
sdSmoothVehicleView_Locked
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
/*
|
|
================
|
|
sdSmoothVehicleView_Locked::InTophat
|
|
================
|
|
*/
|
|
bool sdSmoothVehicleView_Locked::InTophat( const idPlayer* player ) const {
|
|
if ( player == NULL ) {
|
|
return false;
|
|
}
|
|
|
|
if ( player->GetUserInfo().drivingCameraFreelook ) {
|
|
return !player->usercmd.buttons.btn.tophat;
|
|
} else {
|
|
return player->usercmd.buttons.btn.tophat;
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdSmoothVehicleView_Locked::ClampViewAngles
|
|
================
|
|
*/
|
|
void sdSmoothVehicleView_Locked::ClampViewAngles( idAngles& viewAngles, const idAngles& oldViewAngles ) const {
|
|
idPlayer* player = position->GetPlayer();
|
|
assert( player != NULL );
|
|
|
|
if ( !InTophat( player ) ) {
|
|
const idMat3& ownerAxes = position->GetTransport()->GetPhysics()->GetAxis();
|
|
idAngles ownerAngles = ownerAxes[ 0 ].ToAngles();
|
|
|
|
viewAngles = player->firstPersonViewAxis[ 0 ].ToAngles();
|
|
viewAngles.yaw -= ownerAngles.yaw;
|
|
viewAngles.roll = 0.0f;
|
|
viewAngles.Normalize180();
|
|
} else {
|
|
idAngles oldAngles = oldViewAngles;
|
|
DoFreshEntryAngles( viewAngles, oldAngles );
|
|
|
|
viewAngles.Normalize180();
|
|
viewAngles.pitch = idMath::ClampFloat( -40.0f, 40.0f, viewAngles.pitch );
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdSmoothVehicleView_Locked::CalculateViewPos
|
|
================
|
|
*/
|
|
void sdSmoothVehicleView_Locked::CalculateViewPos( idPlayer* player, idVec3& origin, idMat3& axis, bool fullUpdate ) {
|
|
if ( !fullUpdate ) {
|
|
origin = thirdPersonViewOrigin;
|
|
axis = thirdPersonViewAxes;
|
|
return;
|
|
}
|
|
|
|
// update transitioning in and out of tophat
|
|
if ( InTophat( player )) {
|
|
topHatTransition += MS2SEC( gameLocal.msec )*2.0f;
|
|
} else {
|
|
topHatTransition -= MS2SEC( gameLocal.msec )*2.0f;
|
|
}
|
|
topHatTransition = idMath::ClampFloat( 0.0f, 1.0f, topHatTransition );
|
|
|
|
sdSmoothVehicleView::CalculateViewPos( player, origin, axis, fullUpdate );
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdSmoothVehicleView_Locked::OnPlayerSwitched
|
|
================
|
|
*/
|
|
void sdSmoothVehicleView_Locked::OnPlayerSwitched( idPlayer* player, bool newPosition ) {
|
|
sdSmoothVehicleView::OnPlayerSwitched( player, newPosition );
|
|
topHatTransition = 0.0f;
|
|
previousViewAngles = player->clientViewAngles;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdSmoothVehicleView_Locked::CalcNewViewAngles
|
|
================
|
|
*/
|
|
void sdSmoothVehicleView_Locked::CalcNewViewAngles( idAngles& angles ) const {
|
|
// yaw relative to body
|
|
const idMat3& ownerAxes = position->GetTransport()->GetPhysics()->GetAxis();
|
|
idAngles ownerAngles = ownerAxes[ 0 ].ToAngles();
|
|
|
|
angles = entryAim[ 0 ].ToAngles();
|
|
angles.yaw -= ownerAngles.yaw;
|
|
angles.Normalize180();
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdSmoothVehicleView_Locked::DoTeleporting
|
|
================
|
|
*/
|
|
void sdSmoothVehicleView_Locked::DoTeleporting( viewEvalProperties_t& state ) const {
|
|
state.viewAngles.Zero();
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdSmoothVehicleView_Locked::CalculateAimMatrix
|
|
================
|
|
*/
|
|
void sdSmoothVehicleView_Locked::CalculateAimMatrix( const viewEvalProperties_t& state ) {
|
|
// aggressively dampen the pitch
|
|
idAngles idealAngles( state.ownerAngles.pitch * 0.5f, state.ownerAngles.yaw, 0.0f );
|
|
|
|
// don't let it tilt up too far, it looks silly
|
|
if ( idealAngles.pitch < -25.0f ) {
|
|
idealAngles.pitch = -25.0f;
|
|
}
|
|
|
|
if ( !firstFrame ) {
|
|
idAngles fromAngles = ( previousRawAimMatrix ).ToAngles();
|
|
float pitchDiff = idMath::AngleDelta( idealAngles.pitch, fromAngles.pitch );
|
|
float pitchDampSpeed = viewMode.dampSpeed * viewMode.dampSpeed;
|
|
float ownerSpeedSqr = InchesToMetres( state.ownerSpeed*state.ownerSpeed );
|
|
// hooray for magic numbers!
|
|
// TODO: make this configurable, or at least a #define
|
|
if ( ownerSpeedSqr < 7500.0f ) {
|
|
float targetPitchDampSpeed = viewMode.dampSpeed;
|
|
float distToGo = targetPitchDampSpeed - pitchDampSpeed;
|
|
pitchDampSpeed += distToGo * ( 1.0f - ( ownerSpeedSqr / 7500.0f ) );
|
|
}
|
|
|
|
idealAngles.pitch = idMath::AngleNormalize180( fromAngles.pitch + pitchDiff * pitchDampSpeed );
|
|
}
|
|
|
|
evalState.aimMatrix = idealAngles.ToMat3();
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdSmoothVehicleView_Locked::CalculateCameraDelta
|
|
================
|
|
*/
|
|
idVec3 sdSmoothVehicleView_Locked::CalculateCameraDelta( const viewEvalProperties_t& state ) {
|
|
float cameraDist = viewMode.cameraDistance;
|
|
float cameraHeight = viewMode.cameraHeight;
|
|
|
|
idVec3 cameraDelta( -cameraDist, 0.0f, cameraHeight );
|
|
cameraDelta = cameraDelta * evalState.aimMatrix;
|
|
|
|
idVec3 noTopHatFutureDelta = cameraDelta;
|
|
idVec3 currentDelta = state.oldOrigin - state.ownerOrigin;
|
|
if ( !firstFrame && topHatTransition < 1.0f ) {
|
|
// world space
|
|
idVec3 futureDelta = cameraDelta;
|
|
idVec3 futurePredictedPosition = state.ownerOrigin + /*state.ownerVelocity * 0.5f +*/ state.ownerAxes[ 0 ] * 128.0f;
|
|
idVec3 turningPredict = 15.0f * ( state.ownerPhysics->GetAngularVelocity() * state.ownerAxes[ 2 ] ) * state.ownerAxes[ 1 ];
|
|
if ( state.ownerAxes[ 0 ] * state.ownerVelocity < 0.0f ) {
|
|
turningPredict = -turningPredict;
|
|
}
|
|
|
|
futurePredictedPosition += turningPredict;
|
|
idVec3 directionToFuture = futurePredictedPosition - state.ownerOrigin;
|
|
float distanceFromHere = directionToFuture.Normalize();
|
|
if ( distanceFromHere < 32.0f ) {
|
|
futureDelta = currentDelta;
|
|
} else {
|
|
directionToFuture.z = cameraHeight;
|
|
directionToFuture.x *= -cameraDist;
|
|
directionToFuture.y *= -cameraDist;
|
|
futureDelta = directionToFuture;
|
|
}
|
|
|
|
// soften the blow - don't let the delta rotate too fast
|
|
float currentYawAngle = RAD2DEG( idMath::ATan( currentDelta.y, currentDelta.x ) );
|
|
float newYawAngle = RAD2DEG( idMath::ATan( futureDelta.y, futureDelta.x ) );
|
|
float yawDiff = idMath::AngleDelta( newYawAngle, currentYawAngle );
|
|
float maxRotateSpeedMin = 360.0f * MS2SEC( gameLocal.msec );
|
|
float maxRotateSpeedMax = 2000.0f * MS2SEC( gameLocal.msec );
|
|
float maxRotateSpeed = Lerp( maxRotateSpeedMin, maxRotateSpeedMax, idMath::Fabs( yawDiff ) / 180.0f );
|
|
yawDiff = idMath::ClampFloat( -maxRotateSpeed, maxRotateSpeed, yawDiff );
|
|
newYawAngle = currentYawAngle + yawDiff;
|
|
futureDelta.x = cameraDist * idMath::Cos( DEG2RAD( newYawAngle ) );
|
|
futureDelta.y = cameraDist * idMath::Sin( DEG2RAD( newYawAngle ) );
|
|
|
|
// modify the aim matrix to fit what all this has done
|
|
noTopHatFutureDelta = cameraDelta = futureDelta;
|
|
}
|
|
|
|
if ( topHatTransition > 0.0f ) {
|
|
idAngles topHatViewAngles = state.viewAngles;
|
|
topHatViewAngles.yaw += state.ownerAngles.yaw;
|
|
|
|
// dampen the vehicle's motion a little
|
|
if ( topHatTransition >= 1.0f ) {
|
|
float aimingDiff = idMath::AngleDelta( state.viewAngles.yaw, previousViewAngles.yaw );
|
|
float resultDiff = idMath::AngleDelta( topHatViewAngles.yaw, state.oldAxisAngles.yaw );
|
|
resultDiff = idMath::AngleDelta( resultDiff, aimingDiff );
|
|
topHatViewAngles.yaw -= resultDiff * 0.8f;
|
|
}
|
|
|
|
idVec3 topHatDelta = topHatViewAngles.ToMat3()[ 0 ] * -cameraDist;
|
|
topHatDelta.z += cameraHeight;
|
|
|
|
// blend in the delta it'd have without top hat pressed
|
|
if ( topHatTransition < 1.0f ) {
|
|
cameraDelta = Lerp( noTopHatFutureDelta, topHatDelta, topHatTransition );
|
|
idVec3 deltaDirection = cameraDelta;
|
|
float deltaLength = deltaDirection.Normalize();
|
|
if ( deltaLength > idMath::FLT_EPSILON ) {
|
|
float idealLength = topHatDelta.Length();
|
|
cameraDelta = deltaDirection * idealLength;
|
|
} else {
|
|
cameraDelta = currentDelta;
|
|
}
|
|
} else {
|
|
cameraDelta = topHatDelta;
|
|
}
|
|
}
|
|
|
|
previousViewAngles = state.viewAngles;
|
|
|
|
return cameraDelta;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdSmoothVehicleView_Locked::ClampToViewConstraints
|
|
================
|
|
*/
|
|
void sdSmoothVehicleView_Locked::ClampToViewConstraints( const viewEvalProperties_t& state ) {
|
|
if ( InTophat( state.driver ) ) {
|
|
// clamp the resultant angles
|
|
idAngles localAxisAngles = ( evalState.cameraAxis * state.ownerAxesT ).ToAngles();
|
|
localAxisAngles.roll = 0.0f;
|
|
idAngles clampedAxisAngles = localAxisAngles;
|
|
clampedAxisAngles.pitch = idMath::ClampFloat( -40.0f, 40.0f, clampedAxisAngles.pitch );
|
|
|
|
if ( localAxisAngles != clampedAxisAngles ) {
|
|
idMat3 ownerSpaceAxis = clampedAxisAngles.ToMat3();
|
|
evalState.cameraAxis = ownerSpaceAxis * state.ownerAxes;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdSmoothVehicleView_Locked::DampenMotion
|
|
================
|
|
*/
|
|
void sdSmoothVehicleView_Locked::DampenMotion( const viewEvalProperties_t& state ) {
|
|
bool topHatOverride = false;
|
|
if ( topHatTransition == 1.0f ) {
|
|
topHatOverride = true;
|
|
}
|
|
|
|
if ( !topHatOverride ) {
|
|
sdSmoothVehicleView::DampenMotion( state );
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdSmoothVehicleView_Locked::DampenYaw
|
|
================
|
|
*/
|
|
float sdSmoothVehicleView_Locked::DampenYaw( float input ) const {
|
|
float dampSpeed = Lerp( viewMode.dampSpeed, 1.0f, topHatTransition );
|
|
return input * dampSpeed;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdSmoothVehicleView_Locked::DampenPitch
|
|
================
|
|
*/
|
|
float sdSmoothVehicleView_Locked::DampenPitch( float input ) const {
|
|
float dampSpeed = Lerp( viewMode.dampSpeed, 1.0f, topHatTransition );
|
|
return input * dampSpeed;
|
|
}
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
sdIcarusVehicleView
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
/*
|
|
================
|
|
sdIcarusVehicleView::CalculateViewPos
|
|
================
|
|
*/
|
|
void sdIcarusVehicleView::CalculateViewPos( idPlayer* player, idVec3& origin, idMat3& axis, bool fullUpdate ) {
|
|
if ( freshEntry && fullUpdate ) {
|
|
// ensure that the angles have been clamped to the valid range
|
|
idAngles tempAngles = player->clientViewAngles;
|
|
ClampViewAngles( player->clientViewAngles, tempAngles );
|
|
freshEntry = true;
|
|
}
|
|
|
|
origin = position->GetTransport()->GetPhysics()->GetOrigin();
|
|
axis = player->clientViewAngles.ToMat3();
|
|
|
|
sdTeleporter* teleportEnt = position->GetTransport()->GetTeleportEntity();
|
|
if ( teleportEnt != NULL ) {
|
|
idPlayer* player = gameLocal.GetLocalViewPlayer();
|
|
if ( player != NULL && player->GetProxyEntity() == position->GetTransport() ) {
|
|
idEntity* viewer = teleportEnt->GetViewEntity();
|
|
if ( viewer != NULL ) {
|
|
origin = viewer->GetPhysics()->GetOrigin();
|
|
axis = viewer->GetPhysics()->GetAxis();
|
|
}
|
|
}
|
|
}
|
|
|
|
origin += player->GetEyeOffset( idPlayer::EP_NORMAL );
|
|
thirdPersonViewOrigin = origin;
|
|
thirdPersonViewAxes = axis;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdIcarusVehicleView::GetRequiredViewAngles
|
|
================
|
|
*/
|
|
const idAngles sdIcarusVehicleView::GetRequiredViewAngles( const idVec3& aimPosition ) const {
|
|
idVec3 deltaToTarget = aimPosition - position->GetTransport()->GetPhysics()->GetOrigin();
|
|
deltaToTarget.Normalize();
|
|
return deltaToTarget.ToAngles();
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdIcarusVehicleView::SetupEyes
|
|
================
|
|
*/
|
|
void sdIcarusVehicleView::SetupEyes( idAnimatedEntity* other ) {
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdIcarusVehicleView::CalcNewViewAngles
|
|
================
|
|
*/
|
|
void sdIcarusVehicleView::CalcNewViewAngles( idAngles& angles ) const {
|
|
}
|