//========= 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( 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