source-engine-2018-hl2_src/game/shared/weapon_ifmbasecamera.cpp

405 lines
13 KiB
C++
Raw Permalink Normal View History

2020-04-23 00:56:21 +08:00
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//===========================================================================//
#include "cbase.h"
#include "weapon_ifmbasecamera.h"
#ifdef CLIENT_DLL
#include "view_shared.h"
#include "iviewrender.h"
#include "vgui_controls/Controls.h"
#include "vgui/ISurface.h"
bool ToolFramework_SetupEngineView( Vector &origin, QAngle &angles, float &fov );
#endif
#define INSET_VIEW_FACTOR 0.3f
//-----------------------------------------------------------------------------
// CWeaponIFMBaseCamera tables.
//-----------------------------------------------------------------------------
IMPLEMENT_NETWORKCLASS_ALIASED( WeaponIFMBaseCamera, DT_WeaponIFMBaseCamera )
LINK_ENTITY_TO_CLASS( weapon_ifm_base_camera, CWeaponIFMBaseCamera );
BEGIN_NETWORK_TABLE( CWeaponIFMBaseCamera, DT_WeaponIFMBaseCamera )
#if !defined( CLIENT_DLL )
SendPropFloat( SENDINFO( m_flRenderAspectRatio ), 0, SPROP_NOSCALE ),
SendPropFloat( SENDINFO( m_flRenderFOV ), 0, SPROP_NOSCALE ),
SendPropFloat( SENDINFO( m_flRenderArmLength ), 0, SPROP_NOSCALE ),
SendPropVector( SENDINFO( m_vecRenderPosition ), 0, SPROP_NOSCALE ),
SendPropQAngles( SENDINFO( m_angRenderAngles ), 0, SPROP_NOSCALE ),
#else
RecvPropFloat( RECVINFO( m_flRenderAspectRatio ) ),
RecvPropFloat( RECVINFO( m_flRenderFOV ) ),
RecvPropFloat( RECVINFO( m_flRenderArmLength ) ),
RecvPropVector( RECVINFO( m_vecRenderPosition ) ),
RecvPropQAngles( RECVINFO( m_angRenderAngles ) ),
#endif
END_NETWORK_TABLE()
#ifdef CLIENT_DLL
BEGIN_PREDICTION_DATA( CWeaponIFMBaseCamera )
DEFINE_PRED_FIELD( m_flFOV, FIELD_FLOAT, 0 ),
DEFINE_PRED_FIELD( m_flArmLength, FIELD_FLOAT, 0 ),
DEFINE_PRED_FIELD( m_vecRelativePosition, FIELD_VECTOR, 0 ),
DEFINE_PRED_FIELD( m_angRelativeAngles, FIELD_VECTOR, 0 ),
DEFINE_PRED_FIELD( m_bFullScreen, FIELD_BOOLEAN, 0 ),
END_PREDICTION_DATA()
#endif
#ifdef GAME_DLL
BEGIN_DATADESC( CWeaponIFMBaseCamera )
DEFINE_FIELD( m_flRenderAspectRatio, FIELD_FLOAT ),
DEFINE_FIELD( m_flRenderFOV, FIELD_FLOAT ),
DEFINE_FIELD( m_flRenderArmLength, FIELD_FLOAT ),
DEFINE_FIELD( m_vecRenderPosition, FIELD_VECTOR ),
DEFINE_FIELD( m_angRenderAngles, FIELD_VECTOR ),
END_DATADESC()
#endif
//-----------------------------------------------------------------------------
// CWeaponIFMBaseCamera implementation.
//-----------------------------------------------------------------------------
CWeaponIFMBaseCamera::CWeaponIFMBaseCamera()
{
#ifdef CLIENT_DLL
m_flFOV = 75.0f;
m_flArmLength = 4;
m_vecRelativePosition.Init();
m_angRelativeAngles.Init();
m_bFullScreen = false;
m_nScreenWidth = 0;
m_nScreenHeight = 0;
#endif
}
//-----------------------------------------------------------------------------
//
// Specific methods on the server
//
//-----------------------------------------------------------------------------
#ifdef GAME_DLL
void CWeaponIFMBaseCamera::SetRenderInfo( float flAspectRatio, float flFOV, float flArmLength, const Vector &vecPosition, const QAngle &angles )
{
m_flRenderAspectRatio = flAspectRatio;
m_flRenderFOV = flFOV;
m_flRenderArmLength = flArmLength;
m_vecRenderPosition = vecPosition;
m_angRenderAngles = angles;
}
CON_COMMAND( ifm_basecamera_camerastate, "Set camera state" )
{
CBasePlayer *pPlayer = ToBasePlayer( UTIL_GetCommandClient() );
if ( !pPlayer )
return;
if ( args.ArgC() != 10 )
return;
Vector vecPosition;
QAngle angAngles;
float flAspectRatio = atof( args[1] );
float flFOV = atof( args[2] );
float flArmLength = atof( args[3] );
vecPosition.x = atof( args[4] );
vecPosition.y = atof( args[5] );
vecPosition.z = atof( args[6] );
angAngles.x = atof( args[7] );
angAngles.y = atof( args[8] );
angAngles.z = atof( args[9] );
int nCount = pPlayer->WeaponCount();
for ( int i = 0; i < nCount; ++i )
{
CWeaponIFMBaseCamera *pCamera = dynamic_cast<CWeaponIFMBaseCamera*>( pPlayer->GetWeapon( i ) );
if ( !pCamera )
continue;
pCamera->SetRenderInfo( flAspectRatio, flFOV, flArmLength, vecPosition, angAngles );
}
}
#endif // GAME_DLL
//-----------------------------------------------------------------------------
//
// Specific methods on the client
//
//-----------------------------------------------------------------------------
#ifdef CLIENT_DLL
//-----------------------------------------------------------------------------
// Sets up the material to draw with
//-----------------------------------------------------------------------------
void CWeaponIFMBaseCamera::OnDataChanged( DataUpdateType_t updateType )
{
BaseClass::OnDataChanged( updateType );
if (updateType == DATA_UPDATE_CREATED)
{
m_FrustumMaterial.Init( "effects/steadycamfrustum", TEXTURE_GROUP_OTHER );
m_FrustumWireframeMaterial.Init( "shadertest/wireframevertexcolor", TEXTURE_GROUP_OTHER );
}
}
//-----------------------------------------------------------------------------
// Transmits render information
//-----------------------------------------------------------------------------
void CWeaponIFMBaseCamera::TransmitRenderInfo()
{
float flAspectRatio = (m_nScreenHeight != 0) ? (float)m_nScreenWidth / (float)m_nScreenHeight : 1.0f;
float flFOV = m_flFOV;
Vector position;
QAngle angles;
ComputeAbsCameraTransform( position, angles );
// give the toolsystem a chance to override the view
ToolFramework_SetupEngineView( position, angles, flFOV );
char pBuf[256];
Q_snprintf( pBuf, sizeof(pBuf), "ifm_basecamera_camerastate %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f",
flAspectRatio, flFOV, m_flArmLength, position.x, position.y, position.z,
angles.x, angles.y, angles.z );
engine->ClientCmd( pBuf );
}
//-----------------------------------------------------------------------------
// Purpose: In 3rd person, draws the cone of the steadycam
//-----------------------------------------------------------------------------
#define FRUSTUM_SIZE 1000
int CWeaponIFMBaseCamera::DrawModel( int flags )
{
int nRetVal = BaseClass::DrawModel( flags );
CBasePlayer *pPlayer = GetPlayerOwner();
if ( pPlayer && !pPlayer->IsLocalPlayer() )
{
// Compute endpoints
float flMaxD = 1.0f / tan( M_PI * m_flFOV / 360.0f );
float ex = flMaxD * FRUSTUM_SIZE;
float ey = flMaxD * FRUSTUM_SIZE / m_flRenderAspectRatio;
// Compute basis
Vector vecForward, vecUp, vecRight;
AngleVectors( m_angRenderAngles, &vecForward, &vecRight, &vecUp );
Vector vecCenter;
VectorMA( m_vecRenderPosition, FRUSTUM_SIZE, vecForward, vecCenter );
Vector vecEndPoint[4];
VectorMA( vecCenter, ex, vecRight, vecEndPoint[0] );
VectorMA( vecEndPoint[0], ey, vecUp, vecEndPoint[0] );
VectorMA( vecEndPoint[0], -2.0f * ex, vecRight, vecEndPoint[1] );
VectorMA( vecEndPoint[1], -2.0f * ey, vecUp, vecEndPoint[2] );
VectorMA( vecEndPoint[2], 2.0f * ex, vecRight, vecEndPoint[3] );
CMatRenderContextPtr pRenderContext( materials );
pRenderContext->Bind( m_FrustumMaterial );
IMesh* pMesh = pRenderContext->GetDynamicMesh( true );
CMeshBuilder meshBuilder;
meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, 4 );
for ( int i = 0; i < 4; ++i )
{
meshBuilder.Position3fv( m_vecRenderPosition.Get().Base() );
meshBuilder.Color4ub( 128, 0, 0, 255 );
meshBuilder.AdvanceVertex();
meshBuilder.Position3fv( vecEndPoint[i].Base() );
meshBuilder.Color4ub( 128, 0, 0, 255 );
meshBuilder.AdvanceVertex();
meshBuilder.Position3fv( vecEndPoint[(i+1)%4].Base() );
meshBuilder.Color4ub( 128, 0, 0, 255 );
meshBuilder.AdvanceVertex();
}
meshBuilder.End();
pMesh->Draw();
pRenderContext->Bind( m_FrustumWireframeMaterial );
pMesh = pRenderContext->GetDynamicMesh( true );
meshBuilder.Begin( pMesh, MATERIAL_LINES, 8 );
for ( int i = 0; i < 4; ++i )
{
meshBuilder.Position3fv( m_vecRenderPosition.Get().Base() );
meshBuilder.Color4ub( 255, 255, 255, 255 );
meshBuilder.AdvanceVertex();
meshBuilder.Position3fv( vecEndPoint[i].Base() );
meshBuilder.Color4ub( 255, 255, 255, 255 );
meshBuilder.AdvanceVertex();
meshBuilder.Position3fv( vecEndPoint[i].Base() );
meshBuilder.Color4ub( 255, 255, 255, 255 );
meshBuilder.AdvanceVertex();
meshBuilder.Position3fv( vecEndPoint[(i+1)%4].Base() );
meshBuilder.Color4ub( 255, 255, 255, 255 );
meshBuilder.AdvanceVertex();
}
meshBuilder.End();
pMesh->Draw();
}
return nRetVal;
}
//-----------------------------------------------------------------------------
// Gets the size of the overlay to draw
//-----------------------------------------------------------------------------
void CWeaponIFMBaseCamera::GetViewportSize( int &w, int &h )
{
if ( !m_bFullScreen )
{
w = m_nScreenWidth * INSET_VIEW_FACTOR;
h = m_nScreenHeight * INSET_VIEW_FACTOR;
}
else
{
w = m_nScreenWidth;
h = m_nScreenHeight;
}
}
//-----------------------------------------------------------------------------
// Gets the abs orientation of the camera
//-----------------------------------------------------------------------------
void CWeaponIFMBaseCamera::ComputeAbsCameraTransform( Vector &vecAbsOrigin, QAngle &angAbsRotation )
{
CBasePlayer *pPlayer = GetPlayerOwner();
if ( !pPlayer )
{
vecAbsOrigin.Init();
angAbsRotation.Init();
return;
}
float flFOV = m_flFOV;
float flZNear = view->GetZNear();
float flZFar = view->GetZFar();
Vector viewOrigin;
QAngle viewAngles;
pPlayer->CalcView( viewOrigin, viewAngles, flZNear, flZFar, flFOV );
// Offset the view along the forward direction vector by the arm length
Vector vecForward;
AngleVectors( viewAngles, &vecForward );
VectorMA( viewOrigin, m_flArmLength, vecForward, viewOrigin );
// Use player roll
QAngle angles = m_angRelativeAngles;
angles.z = viewAngles.z;
// Compute the actual orientation of the view
matrix3x4_t cameraToWorld, overlayToCamera, overlayToWorld;
AngleMatrix( vec3_angle, viewOrigin, cameraToWorld );
AngleMatrix( angles, m_vecRelativePosition, overlayToCamera );
ConcatTransforms( cameraToWorld, overlayToCamera, overlayToWorld );
MatrixAngles( overlayToWorld, angAbsRotation, vecAbsOrigin );
// give the toolsystem a chance to override the view
ToolFramework_SetupEngineView( vecAbsOrigin, angAbsRotation, flFOV );
}
//-----------------------------------------------------------------------------
// Gets the bounds of the overlay to draw
//-----------------------------------------------------------------------------
void CWeaponIFMBaseCamera::GetOverlayBounds( int &x, int &y, int &w, int &h )
{
const CViewSetup *pViewSetup = view->GetViewSetup();
if ( !m_bFullScreen )
{
w = pViewSetup->width * INSET_VIEW_FACTOR;
h = pViewSetup->height * INSET_VIEW_FACTOR;
x = pViewSetup->x + ( pViewSetup->width - w ) / 2;
y = pViewSetup->height - h;
}
else
{
w = pViewSetup->width;
h = pViewSetup->height;
x = pViewSetup->x;
y = pViewSetup->y;
}
}
//-----------------------------------------------------------------------------
// When drawing the model, if drawing the viewmodel, draw an overlay of what's being rendered
//-----------------------------------------------------------------------------
void CWeaponIFMBaseCamera::ViewModelDrawn( CBaseViewModel *pBaseViewModel )
{
// NOTE: This is not recursively called because we do not draw viewmodels in the overlay
CViewSetup overlayView = *view->GetViewSetup();
m_nScreenWidth = overlayView.width;
m_nScreenHeight = overlayView.height;
GetOverlayBounds( overlayView.x, overlayView.y, overlayView.width, overlayView.height );
overlayView.m_bRenderToSubrectOfLargerScreen = true;
overlayView.fov = m_flFOV;
// Compute the location of the camera
ComputeAbsCameraTransform( overlayView.origin, overlayView.angles );
// give the toolsystem a chance to override the view
ToolFramework_SetupEngineView( overlayView.origin, overlayView.angles, overlayView.fov );
view->QueueOverlayRenderView( overlayView, VIEW_CLEAR_COLOR | VIEW_CLEAR_DEPTH, RENDERVIEW_UNSPECIFIED );
}
//-----------------------------------------------------------------------------
// Purpose: Draw the weapon's crosshair
//-----------------------------------------------------------------------------
void CWeaponIFMBaseCamera::DrawCrosshair( void )
{
BaseClass::DrawCrosshair();
int x, y, w, h;
GetOverlayBounds( x, y, w, h );
// Draw the targeting zone around the crosshair
int r, g, b, a;
gHUD.m_clrYellowish.GetColor( r, g, b, a );
Color light( r, g, b, 160 );
int nBorderSize = 4;
vgui::surface()->DrawSetColor( light );
vgui::surface()->DrawFilledRect( x-nBorderSize, y-nBorderSize, x+w+nBorderSize, y );
vgui::surface()->DrawFilledRect( x-nBorderSize, y+h, x+w+nBorderSize, y+h+nBorderSize );
vgui::surface()->DrawFilledRect( x-nBorderSize, y, x, y+h );
vgui::surface()->DrawFilledRect( x+w, y, x+w+nBorderSize, y+h );
}
#endif // CLIENT_DLL