mirror of
https://github.com/mapbase-source/source-sdk-2013.git
synced 2025-01-24 04:37:57 +03:00
beaae8ac45
* Adds support for Visual Studio 2012 and 2013 * VR Mode: . Switches from headtrack.dll to sourcevr.dll . Improved readability of the UI in VR . Removed the IPD calibration tool. TF2 will now obey the Oculus configuration file. Use the Oculus calibration tool in your SDK or install and run "OpenVR" under Tools in Steam to calibrate your IPD. . Added dropdown to enable VR mode in the Video options. Removed the -vr command line option. . Added the ability to switch in and out of VR mode without quitting the game . By default VR mode will run full screen. To switch back to a borderless window set the vr_force_windowed convar. . Added support for VR mode on Linux * Many assorted bug fixes and other changes from Team Fortress in various shared files
1357 lines
39 KiB
C++
1357 lines
39 KiB
C++
//========= Copyright Valve Corporation, All rights reserved. ============//
|
|
//
|
|
// Purpose:
|
|
//
|
|
//===========================================================================//
|
|
|
|
#include "cbase.h"
|
|
#include "view.h"
|
|
#include "iviewrender.h"
|
|
#include "iviewrender_beams.h"
|
|
#include "view_shared.h"
|
|
#include "ivieweffects.h"
|
|
#include "iinput.h"
|
|
#include "iclientmode.h"
|
|
#include "prediction.h"
|
|
#include "viewrender.h"
|
|
#include "c_te_legacytempents.h"
|
|
#include "cl_mat_stub.h"
|
|
#include "tier0/vprof.h"
|
|
#include "iclientvehicle.h"
|
|
#include "engine/IEngineTrace.h"
|
|
#include "mathlib/vmatrix.h"
|
|
#include "rendertexture.h"
|
|
#include "c_world.h"
|
|
#include <KeyValues.h>
|
|
#include "igameevents.h"
|
|
#include "smoke_fog_overlay.h"
|
|
#include "bitmap/tgawriter.h"
|
|
#include "hltvcamera.h"
|
|
#if defined( REPLAY_ENABLED )
|
|
#include "replay/replaycamera.h"
|
|
#include "replay/replay_screenshot.h"
|
|
#endif
|
|
#include "input.h"
|
|
#include "filesystem.h"
|
|
#include "materialsystem/itexture.h"
|
|
#include "materialsystem/imaterialsystem.h"
|
|
#include "materialsystem/materialsystem_config.h"
|
|
#include "VGuiMatSurface/IMatSystemSurface.h"
|
|
#include "toolframework_client.h"
|
|
#include "tier0/icommandline.h"
|
|
#include "ienginevgui.h"
|
|
#include <vgui_controls/Controls.h>
|
|
#include <vgui/ISurface.h>
|
|
#include "ScreenSpaceEffects.h"
|
|
#include "sourcevr/isourcevirtualreality.h"
|
|
#include "client_virtualreality.h"
|
|
|
|
#if defined( REPLAY_ENABLED )
|
|
#include "replay/ireplaysystem.h"
|
|
#include "replay/ienginereplay.h"
|
|
#endif
|
|
|
|
#if defined( HL2_CLIENT_DLL ) || defined( CSTRIKE_DLL )
|
|
#define USE_MONITORS
|
|
#endif
|
|
|
|
#ifdef PORTAL
|
|
#include "c_prop_portal.h" //portal surface rendering functions
|
|
#endif
|
|
|
|
|
|
// memdbgon must be the last include file in a .cpp file!!!
|
|
#include "tier0/memdbgon.h"
|
|
|
|
void ToolFramework_AdjustEngineViewport( int& x, int& y, int& width, int& height );
|
|
bool ToolFramework_SetupEngineView( Vector &origin, QAngle &angles, float &fov );
|
|
bool ToolFramework_SetupEngineMicrophone( Vector &origin, QAngle &angles );
|
|
|
|
|
|
extern ConVar default_fov;
|
|
extern bool g_bRenderingScreenshot;
|
|
|
|
#if !defined( _X360 )
|
|
#define SAVEGAME_SCREENSHOT_WIDTH 180
|
|
#define SAVEGAME_SCREENSHOT_HEIGHT 100
|
|
#else
|
|
#define SAVEGAME_SCREENSHOT_WIDTH 128
|
|
#define SAVEGAME_SCREENSHOT_HEIGHT 128
|
|
#endif
|
|
|
|
#ifndef _XBOX
|
|
extern ConVar sensitivity;
|
|
#endif
|
|
|
|
ConVar zoom_sensitivity_ratio( "zoom_sensitivity_ratio", "1.0", 0, "Additional mouse sensitivity scale factor applied when FOV is zoomed in." );
|
|
|
|
CViewRender g_DefaultViewRender;
|
|
IViewRender *view = NULL; // set in cldll_client_init.cpp if no mod creates their own
|
|
|
|
#if _DEBUG
|
|
bool g_bRenderingCameraView = false;
|
|
#endif
|
|
|
|
|
|
// These are the vectors for the "main" view - the one the player is looking down.
|
|
// For stereo views, they are the vectors for the middle eye.
|
|
static Vector g_vecRenderOrigin(0,0,0);
|
|
static QAngle g_vecRenderAngles(0,0,0);
|
|
static Vector g_vecPrevRenderOrigin(0,0,0); // Last frame's render origin
|
|
static QAngle g_vecPrevRenderAngles(0,0,0); // Last frame's render angles
|
|
static Vector g_vecVForward(0,0,0), g_vecVRight(0,0,0), g_vecVUp(0,0,0);
|
|
static VMatrix g_matCamInverse;
|
|
|
|
extern ConVar cl_forwardspeed;
|
|
|
|
static ConVar v_centermove( "v_centermove", "0.15");
|
|
static ConVar v_centerspeed( "v_centerspeed","500" );
|
|
|
|
#ifdef TF_CLIENT_DLL
|
|
// 54 degrees approximates a 35mm camera - we determined that this makes the viewmodels
|
|
// and motions look the most natural.
|
|
ConVar v_viewmodel_fov( "viewmodel_fov", "54", FCVAR_ARCHIVE );
|
|
#else
|
|
ConVar v_viewmodel_fov( "viewmodel_fov", "54", FCVAR_CHEAT );
|
|
#endif
|
|
ConVar mat_viewportscale( "mat_viewportscale", "1.0", FCVAR_ARCHIVE, "Scale down the main viewport (to reduce GPU impact on CPU profiling)", true, (1.0f / 640.0f), true, 1.0f );
|
|
ConVar mat_viewportupscale( "mat_viewportupscale", "1", FCVAR_ARCHIVE, "Scale the viewport back up" );
|
|
ConVar cl_leveloverview( "cl_leveloverview", "0", FCVAR_CHEAT );
|
|
|
|
static ConVar r_mapextents( "r_mapextents", "16384", FCVAR_CHEAT,
|
|
"Set the max dimension for the map. This determines the far clipping plane" );
|
|
|
|
// UNDONE: Delete this or move to the material system?
|
|
ConVar gl_clear( "gl_clear", "0");
|
|
ConVar gl_clear_randomcolor( "gl_clear_randomcolor", "0", FCVAR_CHEAT, "Clear the back buffer to random colors every frame. Helps spot open seams in geometry." );
|
|
|
|
static ConVar r_farz( "r_farz", "-1", FCVAR_CHEAT, "Override the far clipping plane. -1 means to use the value in env_fog_controller." );
|
|
static ConVar cl_demoviewoverride( "cl_demoviewoverride", "0", 0, "Override view during demo playback" );
|
|
|
|
|
|
void SoftwareCursorChangedCB( IConVar *pVar, const char *pOldValue, float fOldValue )
|
|
{
|
|
ConVar *pConVar = (ConVar *)pVar;
|
|
vgui::surface()->SetSoftwareCursor( pConVar->GetBool() || UseVR() );
|
|
}
|
|
static ConVar cl_software_cursor ( "cl_software_cursor", "0", FCVAR_ARCHIVE, "Switches the game to use a larger software cursor instead of the normal OS cursor", SoftwareCursorChangedCB );
|
|
|
|
|
|
static Vector s_DemoView;
|
|
static QAngle s_DemoAngle;
|
|
|
|
static void CalcDemoViewOverride( Vector &origin, QAngle &angles )
|
|
{
|
|
engine->SetViewAngles( s_DemoAngle );
|
|
|
|
input->ExtraMouseSample( gpGlobals->absoluteframetime, true );
|
|
|
|
engine->GetViewAngles( s_DemoAngle );
|
|
|
|
Vector forward, right, up;
|
|
|
|
AngleVectors( s_DemoAngle, &forward, &right, &up );
|
|
|
|
float speed = gpGlobals->absoluteframetime * cl_demoviewoverride.GetFloat() * 320;
|
|
|
|
s_DemoView += speed * input->KeyState (&in_forward) * forward ;
|
|
s_DemoView -= speed * input->KeyState (&in_back) * forward ;
|
|
|
|
s_DemoView += speed * input->KeyState (&in_moveright) * right ;
|
|
s_DemoView -= speed * input->KeyState (&in_moveleft) * right ;
|
|
|
|
origin = s_DemoView;
|
|
angles = s_DemoAngle;
|
|
}
|
|
|
|
|
|
|
|
// Selects the relevant member variable to update. You could do it manually, but...
|
|
// We always set up the MONO eye, even when doing stereo, and it's set up to be mid-way between the left and right,
|
|
// so if you don't really care about L/R (e.g. culling, sound, etc), just use MONO.
|
|
CViewSetup &CViewRender::GetView(StereoEye_t eEye)
|
|
{
|
|
if ( eEye == STEREO_EYE_MONO )
|
|
{
|
|
return m_View;
|
|
}
|
|
else if ( eEye == STEREO_EYE_RIGHT )
|
|
{
|
|
return m_ViewRight;
|
|
}
|
|
else
|
|
{
|
|
Assert ( eEye == STEREO_EYE_LEFT );
|
|
return m_ViewLeft;
|
|
}
|
|
}
|
|
|
|
const CViewSetup &CViewRender::GetView(StereoEye_t eEye) const
|
|
{
|
|
return (const_cast<CViewRender*>(this))->GetView ( eEye );
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Accessors to return the main view (where the player's looking)
|
|
//-----------------------------------------------------------------------------
|
|
const Vector &MainViewOrigin()
|
|
{
|
|
return g_vecRenderOrigin;
|
|
}
|
|
|
|
const QAngle &MainViewAngles()
|
|
{
|
|
return g_vecRenderAngles;
|
|
}
|
|
|
|
const Vector &MainViewForward()
|
|
{
|
|
return g_vecVForward;
|
|
}
|
|
|
|
const Vector &MainViewRight()
|
|
{
|
|
return g_vecVRight;
|
|
}
|
|
|
|
const Vector &MainViewUp()
|
|
{
|
|
return g_vecVUp;
|
|
}
|
|
|
|
const VMatrix &MainWorldToViewMatrix()
|
|
{
|
|
return g_matCamInverse;
|
|
}
|
|
|
|
const Vector &PrevMainViewOrigin()
|
|
{
|
|
return g_vecPrevRenderOrigin;
|
|
}
|
|
|
|
const QAngle &PrevMainViewAngles()
|
|
{
|
|
return g_vecPrevRenderAngles;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Compute the world->camera transform
|
|
//-----------------------------------------------------------------------------
|
|
void ComputeCameraVariables( const Vector &vecOrigin, const QAngle &vecAngles,
|
|
Vector *pVecForward, Vector *pVecRight, Vector *pVecUp, VMatrix *pMatCamInverse )
|
|
{
|
|
// Compute view bases
|
|
AngleVectors( vecAngles, pVecForward, pVecRight, pVecUp );
|
|
|
|
for (int i = 0; i < 3; ++i)
|
|
{
|
|
(*pMatCamInverse)[0][i] = (*pVecRight)[i];
|
|
(*pMatCamInverse)[1][i] = (*pVecUp)[i];
|
|
(*pMatCamInverse)[2][i] = -(*pVecForward)[i];
|
|
(*pMatCamInverse)[3][i] = 0.0F;
|
|
}
|
|
(*pMatCamInverse)[0][3] = -DotProduct( *pVecRight, vecOrigin );
|
|
(*pMatCamInverse)[1][3] = -DotProduct( *pVecUp, vecOrigin );
|
|
(*pMatCamInverse)[2][3] = DotProduct( *pVecForward, vecOrigin );
|
|
(*pMatCamInverse)[3][3] = 1.0F;
|
|
}
|
|
|
|
|
|
bool R_CullSphere(
|
|
VPlane const *pPlanes,
|
|
int nPlanes,
|
|
Vector const *pCenter,
|
|
float radius)
|
|
{
|
|
for(int i=0; i < nPlanes; i++)
|
|
if(pPlanes[i].DistTo(*pCenter) < -radius)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
static void StartPitchDrift( void )
|
|
{
|
|
view->StartPitchDrift();
|
|
}
|
|
|
|
static ConCommand centerview( "centerview", StartPitchDrift );
|
|
|
|
extern ConVar default_fov;
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Initializes all view systems
|
|
//-----------------------------------------------------------------------------
|
|
void CViewRender::Init( void )
|
|
{
|
|
memset( &m_PitchDrift, 0, sizeof( m_PitchDrift ) );
|
|
|
|
m_bDrawOverlay = false;
|
|
|
|
m_pDrawEntities = cvar->FindVar( "r_drawentities" );
|
|
m_pDrawBrushModels = cvar->FindVar( "r_drawbrushmodels" );
|
|
|
|
beams->InitBeams();
|
|
tempents->Init();
|
|
|
|
m_TranslucentSingleColor.Init( "debug/debugtranslucentsinglecolor", TEXTURE_GROUP_OTHER );
|
|
m_ModulateSingleColor.Init( "engine/modulatesinglecolor", TEXTURE_GROUP_OTHER );
|
|
|
|
extern CMaterialReference g_material_WriteZ;
|
|
g_material_WriteZ.Init( "engine/writez", TEXTURE_GROUP_OTHER );
|
|
|
|
// FIXME:
|
|
QAngle angles;
|
|
engine->GetViewAngles( angles );
|
|
AngleVectors( angles, &m_vecLastFacing );
|
|
|
|
#if defined( REPLAY_ENABLED )
|
|
m_pReplayScreenshotTaker = NULL;
|
|
#endif
|
|
|
|
#if defined( CSTRIKE_DLL )
|
|
m_flLastFOV = default_fov.GetFloat();
|
|
#endif
|
|
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Called once per level change
|
|
//-----------------------------------------------------------------------------
|
|
void CViewRender::LevelInit( void )
|
|
{
|
|
beams->ClearBeams();
|
|
tempents->Clear();
|
|
|
|
m_BuildWorldListsNumber = 0;
|
|
m_BuildRenderableListsNumber = 0;
|
|
|
|
for( int i=0; i < STEREO_EYE_MAX; i++ )
|
|
{
|
|
m_rbTakeFreezeFrame[ i ] = false;
|
|
}
|
|
m_flFreezeFrameUntil = 0;
|
|
|
|
// Clear our overlay materials
|
|
m_ScreenOverlayMaterial.Init( NULL );
|
|
|
|
// Init all IScreenSpaceEffects
|
|
g_pScreenSpaceEffects->InitScreenSpaceEffects( );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Called once per level change
|
|
//-----------------------------------------------------------------------------
|
|
void CViewRender::LevelShutdown( void )
|
|
{
|
|
g_pScreenSpaceEffects->ShutdownScreenSpaceEffects( );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Called at shutdown
|
|
//-----------------------------------------------------------------------------
|
|
void CViewRender::Shutdown( void )
|
|
{
|
|
m_TranslucentSingleColor.Shutdown( );
|
|
m_ModulateSingleColor.Shutdown( );
|
|
m_ScreenOverlayMaterial.Shutdown();
|
|
m_UnderWaterOverlayMaterial.Shutdown();
|
|
beams->ShutdownBeams();
|
|
tempents->Shutdown();
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Returns the worldlists build number
|
|
//-----------------------------------------------------------------------------
|
|
|
|
int CViewRender::BuildWorldListsNumber( void ) const
|
|
{
|
|
return m_BuildWorldListsNumber;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Start moving pitch toward ideal
|
|
//-----------------------------------------------------------------------------
|
|
void CViewRender::StartPitchDrift (void)
|
|
{
|
|
if ( m_PitchDrift.laststop == gpGlobals->curtime )
|
|
{
|
|
// Something else is blocking the drift.
|
|
return;
|
|
}
|
|
|
|
if ( m_PitchDrift.nodrift || !m_PitchDrift.pitchvel )
|
|
{
|
|
m_PitchDrift.pitchvel = v_centerspeed.GetFloat();
|
|
m_PitchDrift.nodrift = false;
|
|
m_PitchDrift.driftmove = 0;
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void CViewRender::StopPitchDrift (void)
|
|
{
|
|
m_PitchDrift.laststop = gpGlobals->curtime;
|
|
m_PitchDrift.nodrift = true;
|
|
m_PitchDrift.pitchvel = 0;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Moves the client pitch angle towards cl.idealpitch sent by the server.
|
|
// If the user is adjusting pitch manually, either with lookup/lookdown,
|
|
// mlook and mouse, or klook and keyboard, pitch drifting is constantly stopped.
|
|
//-----------------------------------------------------------------------------
|
|
void CViewRender::DriftPitch (void)
|
|
{
|
|
float delta, move;
|
|
|
|
C_BasePlayer *player = C_BasePlayer::GetLocalPlayer();
|
|
if ( !player )
|
|
return;
|
|
|
|
#if defined( REPLAY_ENABLED )
|
|
if ( engine->IsHLTV() || g_pEngineClientReplay->IsPlayingReplayDemo() || ( player->GetGroundEntity() == NULL ) || engine->IsPlayingDemo() )
|
|
#else
|
|
if ( engine->IsHLTV() || ( player->GetGroundEntity() == NULL ) || engine->IsPlayingDemo() )
|
|
#endif
|
|
{
|
|
m_PitchDrift.driftmove = 0;
|
|
m_PitchDrift.pitchvel = 0;
|
|
return;
|
|
}
|
|
|
|
// Don't count small mouse motion
|
|
if ( m_PitchDrift.nodrift )
|
|
{
|
|
if ( fabs( input->GetLastForwardMove() ) < cl_forwardspeed.GetFloat() )
|
|
{
|
|
m_PitchDrift.driftmove = 0;
|
|
}
|
|
else
|
|
{
|
|
m_PitchDrift.driftmove += gpGlobals->frametime;
|
|
}
|
|
|
|
if ( m_PitchDrift.driftmove > v_centermove.GetFloat() )
|
|
{
|
|
StartPitchDrift ();
|
|
}
|
|
return;
|
|
}
|
|
|
|
// How far off are we
|
|
delta = prediction->GetIdealPitch() - player->GetAbsAngles()[ PITCH ];
|
|
if ( !delta )
|
|
{
|
|
m_PitchDrift.pitchvel = 0;
|
|
return;
|
|
}
|
|
|
|
// Determine movement amount
|
|
move = gpGlobals->frametime * m_PitchDrift.pitchvel;
|
|
// Accelerate
|
|
m_PitchDrift.pitchvel += gpGlobals->frametime * v_centerspeed.GetFloat();
|
|
|
|
// Move predicted pitch appropriately
|
|
if (delta > 0)
|
|
{
|
|
if ( move > delta )
|
|
{
|
|
m_PitchDrift.pitchvel = 0;
|
|
move = delta;
|
|
}
|
|
player->SetLocalAngles( player->GetLocalAngles() + QAngle( move, 0, 0 ) );
|
|
}
|
|
else if ( delta < 0 )
|
|
{
|
|
if ( move > -delta )
|
|
{
|
|
m_PitchDrift.pitchvel = 0;
|
|
move = -delta;
|
|
}
|
|
player->SetLocalAngles( player->GetLocalAngles() - QAngle( move, 0, 0 ) );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
StereoEye_t CViewRender::GetFirstEye() const
|
|
{
|
|
if( UseVR() )
|
|
return STEREO_EYE_LEFT;
|
|
else
|
|
return STEREO_EYE_MONO;
|
|
}
|
|
|
|
StereoEye_t CViewRender::GetLastEye() const
|
|
{
|
|
if( UseVR() )
|
|
return STEREO_EYE_RIGHT;
|
|
else
|
|
return STEREO_EYE_MONO;
|
|
}
|
|
|
|
|
|
|
|
|
|
// This is called by cdll_client_int to setup view model origins. This has to be done before
|
|
// simulation so entities can access attachment points on view models during simulation.
|
|
void CViewRender::OnRenderStart()
|
|
{
|
|
VPROF_("CViewRender::OnRenderStart", 2, VPROF_BUDGETGROUP_OTHER_UNACCOUNTED, false, 0);
|
|
|
|
SetUpViews();
|
|
|
|
// Adjust mouse sensitivity based upon the current FOV
|
|
C_BasePlayer *player = C_BasePlayer::GetLocalPlayer();
|
|
if ( player )
|
|
{
|
|
default_fov.SetValue( player->m_iDefaultFOV );
|
|
|
|
//Update our FOV, including any zooms going on
|
|
int iDefaultFOV = default_fov.GetInt();
|
|
int localFOV = player->GetFOV();
|
|
int min_fov = player->GetMinFOV();
|
|
|
|
// Don't let it go too low
|
|
localFOV = MAX( min_fov, localFOV );
|
|
|
|
gHUD.m_flFOVSensitivityAdjust = 1.0f;
|
|
#ifndef _XBOX
|
|
if ( gHUD.m_flMouseSensitivityFactor )
|
|
{
|
|
gHUD.m_flMouseSensitivity = sensitivity.GetFloat() * gHUD.m_flMouseSensitivityFactor;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
// No override, don't use huge sensitivity
|
|
if ( localFOV == iDefaultFOV )
|
|
{
|
|
#ifndef _XBOX
|
|
// reset to saved sensitivity
|
|
gHUD.m_flMouseSensitivity = 0;
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
// Set a new sensitivity that is proportional to the change from the FOV default and scaled
|
|
// by a separate compensating factor
|
|
if ( iDefaultFOV == 0 )
|
|
{
|
|
Assert(0); // would divide by zero, something is broken with iDefatulFOV
|
|
iDefaultFOV = 1;
|
|
}
|
|
gHUD.m_flFOVSensitivityAdjust =
|
|
((float)localFOV / (float)iDefaultFOV) * // linear fov downscale
|
|
zoom_sensitivity_ratio.GetFloat(); // sensitivity scale factor
|
|
#ifndef _XBOX
|
|
gHUD.m_flMouseSensitivity = gHUD.m_flFOVSensitivityAdjust * sensitivity.GetFloat(); // regular sensitivity
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
// Output : const CViewSetup
|
|
//-----------------------------------------------------------------------------
|
|
const CViewSetup *CViewRender::GetViewSetup( void ) const
|
|
{
|
|
return &m_CurrentView;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
// Output : const CViewSetup
|
|
//-----------------------------------------------------------------------------
|
|
const CViewSetup *CViewRender::GetPlayerViewSetup( void ) const
|
|
{
|
|
const CViewSetup &view = GetView ( STEREO_EYE_MONO );
|
|
return &view;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void CViewRender::DisableVis( void )
|
|
{
|
|
m_bForceNoVis = true;
|
|
}
|
|
|
|
#ifdef DBGFLAG_ASSERT
|
|
static Vector s_DbgSetupOrigin;
|
|
static QAngle s_DbgSetupAngles;
|
|
#endif
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Gets znear + zfar
|
|
//-----------------------------------------------------------------------------
|
|
float CViewRender::GetZNear()
|
|
{
|
|
return VIEW_NEARZ;
|
|
}
|
|
|
|
float CViewRender::GetZFar()
|
|
{
|
|
// Initialize view structure with default values
|
|
float farZ;
|
|
if ( r_farz.GetFloat() < 1 )
|
|
{
|
|
// Use the far Z from the map's parameters.
|
|
farZ = r_mapextents.GetFloat() * 1.73205080757f;
|
|
|
|
C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
|
|
if( pPlayer && pPlayer->GetFogParams() )
|
|
{
|
|
if ( pPlayer->GetFogParams()->farz > 0 )
|
|
{
|
|
farZ = pPlayer->GetFogParams()->farz;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
farZ = r_farz.GetFloat();
|
|
}
|
|
|
|
return farZ;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Sets up the view parameters
|
|
//-----------------------------------------------------------------------------
|
|
void CViewRender::SetUpViews()
|
|
{
|
|
VPROF("CViewRender::SetUpViews");
|
|
|
|
// Initialize view structure with default values
|
|
float farZ = GetZFar();
|
|
|
|
// Set up the mono/middle view.
|
|
CViewSetup &view = m_View;
|
|
|
|
view.zFar = farZ;
|
|
view.zFarViewmodel = farZ;
|
|
// UNDONE: Make this farther out?
|
|
// closest point of approach seems to be view center to top of crouched box
|
|
view.zNear = GetZNear();
|
|
view.zNearViewmodel = 1;
|
|
view.fov = default_fov.GetFloat();
|
|
|
|
view.m_bOrtho = false;
|
|
view.m_bViewToProjectionOverride = false;
|
|
view.m_eStereoEye = STEREO_EYE_MONO;
|
|
|
|
// Enable spatial partition access to edicts
|
|
partition->SuppressLists( PARTITION_ALL_CLIENT_EDICTS, false );
|
|
|
|
C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
|
|
|
|
// You in-view weapon aim.
|
|
bool bCalcViewModelView = false;
|
|
Vector ViewModelOrigin;
|
|
QAngle ViewModelAngles;
|
|
|
|
if ( engine->IsHLTV() )
|
|
{
|
|
HLTVCamera()->CalcView( view.origin, view.angles, view.fov );
|
|
}
|
|
#if defined( REPLAY_ENABLED )
|
|
else if ( g_pEngineClientReplay->IsPlayingReplayDemo() )
|
|
{
|
|
ReplayCamera()->CalcView( view.origin, view.angles, view.fov );
|
|
}
|
|
#endif
|
|
else
|
|
{
|
|
// FIXME: Are there multiple views? If so, then what?
|
|
// FIXME: What happens when there's no player?
|
|
if (pPlayer)
|
|
{
|
|
pPlayer->CalcView( view.origin, view.angles, view.zNear, view.zFar, view.fov );
|
|
|
|
// If we are looking through another entities eyes, then override the angles/origin for view
|
|
int viewentity = render->GetViewEntity();
|
|
|
|
if ( !g_nKillCamMode && (pPlayer->entindex() != viewentity) )
|
|
{
|
|
C_BaseEntity *ve = cl_entitylist->GetEnt( viewentity );
|
|
if ( ve )
|
|
{
|
|
VectorCopy( ve->GetAbsOrigin(), view.origin );
|
|
VectorCopy( ve->GetAbsAngles(), view.angles );
|
|
}
|
|
}
|
|
|
|
// There is a viewmodel.
|
|
bCalcViewModelView = true;
|
|
ViewModelOrigin = view.origin;
|
|
ViewModelAngles = view.angles;
|
|
}
|
|
else
|
|
{
|
|
view.origin.Init();
|
|
view.angles.Init();
|
|
}
|
|
|
|
// Even if the engine is paused need to override the view
|
|
// for keeping the camera control during pause.
|
|
g_pClientMode->OverrideView( &view );
|
|
}
|
|
|
|
// give the toolsystem a chance to override the view
|
|
ToolFramework_SetupEngineView( view.origin, view.angles, view.fov );
|
|
|
|
if ( engine->IsPlayingDemo() )
|
|
{
|
|
if ( cl_demoviewoverride.GetFloat() > 0.0f )
|
|
{
|
|
// Retreive view angles from engine ( could have been set in IN_AdjustAngles above )
|
|
CalcDemoViewOverride( view.origin, view.angles );
|
|
}
|
|
else
|
|
{
|
|
s_DemoView = view.origin;
|
|
s_DemoAngle = view.angles;
|
|
}
|
|
}
|
|
|
|
//Find the offset our current FOV is from the default value
|
|
float fDefaultFov = default_fov.GetFloat();
|
|
float flFOVOffset = fDefaultFov - view.fov;
|
|
|
|
//Adjust the viewmodel's FOV to move with any FOV offsets on the viewer's end
|
|
view.fovViewmodel = g_pClientMode->GetViewModelFOV() - flFOVOffset;
|
|
|
|
if ( UseVR() )
|
|
{
|
|
// Let the headtracking read the status of the HMD, etc.
|
|
// This call can go almost anywhere, but it needs to know the player FOV for sniper weapon zoom, etc
|
|
if ( flFOVOffset == 0.0f )
|
|
{
|
|
g_ClientVirtualReality.ProcessCurrentTrackingState ( 0.0f );
|
|
}
|
|
else
|
|
{
|
|
g_ClientVirtualReality.ProcessCurrentTrackingState ( view.fov );
|
|
}
|
|
|
|
HeadtrackMovementMode_t hmmOverrideMode = g_pClientMode->ShouldOverrideHeadtrackControl();
|
|
g_ClientVirtualReality.OverrideView( &m_View, &ViewModelOrigin, &ViewModelAngles, hmmOverrideMode );
|
|
|
|
// left and right stereo views should default to being the same as the mono/middle view
|
|
m_ViewLeft = m_View;
|
|
m_ViewRight = m_View;
|
|
m_ViewLeft.m_eStereoEye = STEREO_EYE_LEFT;
|
|
m_ViewRight.m_eStereoEye = STEREO_EYE_RIGHT;
|
|
|
|
g_ClientVirtualReality.OverrideStereoView( &m_View, &m_ViewLeft, &m_ViewRight );
|
|
}
|
|
else
|
|
{
|
|
// left and right stereo views should default to being the same as the mono/middle view
|
|
m_ViewLeft = m_View;
|
|
m_ViewRight = m_View;
|
|
m_ViewLeft.m_eStereoEye = STEREO_EYE_LEFT;
|
|
m_ViewRight.m_eStereoEye = STEREO_EYE_RIGHT;
|
|
}
|
|
|
|
if ( bCalcViewModelView )
|
|
{
|
|
Assert ( pPlayer != NULL );
|
|
pPlayer->CalcViewModelView ( ViewModelOrigin, ViewModelAngles );
|
|
}
|
|
|
|
// Disable spatial partition access
|
|
partition->SuppressLists( PARTITION_ALL_CLIENT_EDICTS, true );
|
|
|
|
// Enable access to all model bones
|
|
C_BaseAnimating::PopBoneAccess( "OnRenderStart->CViewRender::SetUpView" ); // pops the (true, false) bone access set in OnRenderStart
|
|
C_BaseAnimating::PushAllowBoneAccess( true, true, "CViewRender::SetUpView->OnRenderEnd" ); // pop is in OnRenderEnd()
|
|
|
|
// Compute the world->main camera transform
|
|
// This is only done for the main "middle-eye" view, not for the various other views.
|
|
ComputeCameraVariables( view.origin, view.angles,
|
|
&g_vecVForward, &g_vecVRight, &g_vecVUp, &g_matCamInverse );
|
|
|
|
// set up the hearing origin...
|
|
AudioState_t audioState;
|
|
audioState.m_Origin = view.origin;
|
|
audioState.m_Angles = view.angles;
|
|
audioState.m_bIsUnderwater = pPlayer && pPlayer->AudioStateIsUnderwater( view.origin );
|
|
|
|
ToolFramework_SetupAudioState( audioState );
|
|
|
|
// TomF: I wonder when the audio tools modify this, if ever...
|
|
Assert ( view.origin == audioState.m_Origin );
|
|
Assert ( view.angles == audioState.m_Angles );
|
|
view.origin = audioState.m_Origin;
|
|
view.angles = audioState.m_Angles;
|
|
|
|
engine->SetAudioState( audioState );
|
|
|
|
g_vecPrevRenderOrigin = g_vecRenderOrigin;
|
|
g_vecPrevRenderAngles = g_vecRenderAngles;
|
|
g_vecRenderOrigin = view.origin;
|
|
g_vecRenderAngles = view.angles;
|
|
|
|
#ifdef DBGFLAG_ASSERT
|
|
s_DbgSetupOrigin = view.origin;
|
|
s_DbgSetupAngles = view.angles;
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
|
|
void CViewRender::WriteSaveGameScreenshotOfSize( const char *pFilename, int width, int height, bool bCreatePowerOf2Padded/*=false*/,
|
|
bool bWriteVTF/*=false*/ )
|
|
{
|
|
#ifndef _X360
|
|
CMatRenderContextPtr pRenderContext( materials );
|
|
pRenderContext->MatrixMode( MATERIAL_PROJECTION );
|
|
pRenderContext->PushMatrix();
|
|
|
|
pRenderContext->MatrixMode( MATERIAL_VIEW );
|
|
pRenderContext->PushMatrix();
|
|
|
|
g_bRenderingScreenshot = true;
|
|
|
|
// Push back buffer on the stack with small viewport
|
|
pRenderContext->PushRenderTargetAndViewport( NULL, 0, 0, width, height );
|
|
|
|
// render out to the backbuffer
|
|
CViewSetup viewSetup = GetView ( STEREO_EYE_MONO );
|
|
viewSetup.x = 0;
|
|
viewSetup.y = 0;
|
|
viewSetup.width = width;
|
|
viewSetup.height = height;
|
|
viewSetup.fov = ScaleFOVByWidthRatio( viewSetup.fov, ( (float)width / (float)height ) / ( 4.0f / 3.0f ) );
|
|
viewSetup.m_bRenderToSubrectOfLargerScreen = true;
|
|
|
|
// draw out the scene
|
|
// Don't draw the HUD or the viewmodel
|
|
RenderView( viewSetup, VIEW_CLEAR_DEPTH | VIEW_CLEAR_COLOR, 0 );
|
|
|
|
// get the data from the backbuffer and save to disk
|
|
// bitmap bits
|
|
unsigned char *pImage = ( unsigned char * )malloc( width * height * 3 );
|
|
|
|
// Get Bits from the material system
|
|
pRenderContext->ReadPixels( 0, 0, width, height, pImage, IMAGE_FORMAT_RGB888 );
|
|
|
|
// Some stuff to be setup dependent on padded vs. not padded
|
|
int nSrcWidth, nSrcHeight;
|
|
unsigned char *pSrcImage;
|
|
|
|
// Create a padded version if necessary
|
|
unsigned char *pPaddedImage = NULL;
|
|
if ( bCreatePowerOf2Padded )
|
|
{
|
|
// Setup dimensions as needed
|
|
int nPaddedWidth = SmallestPowerOfTwoGreaterOrEqual( width );
|
|
int nPaddedHeight = SmallestPowerOfTwoGreaterOrEqual( height );
|
|
|
|
// Allocate
|
|
int nPaddedImageSize = nPaddedWidth * nPaddedHeight * 3;
|
|
pPaddedImage = ( unsigned char * )malloc( nPaddedImageSize );
|
|
|
|
// Zero out the entire thing
|
|
V_memset( pPaddedImage, 255, nPaddedImageSize );
|
|
|
|
// Copy over each row individually
|
|
for ( int nRow = 0; nRow < height; ++nRow )
|
|
{
|
|
unsigned char *pDst = pPaddedImage + 3 * ( nRow * nPaddedWidth );
|
|
const unsigned char *pSrc = pImage + 3 * ( nRow * width );
|
|
V_memcpy( pDst, pSrc, 3 * width );
|
|
}
|
|
|
|
// Setup source data
|
|
nSrcWidth = nPaddedWidth;
|
|
nSrcHeight = nPaddedHeight;
|
|
pSrcImage = pPaddedImage;
|
|
}
|
|
else
|
|
{
|
|
// Use non-padded info
|
|
nSrcWidth = width;
|
|
nSrcHeight = height;
|
|
pSrcImage = pImage;
|
|
}
|
|
|
|
// allocate a buffer to write the tga into
|
|
CUtlBuffer buffer;
|
|
|
|
bool bWriteResult;
|
|
if ( bWriteVTF )
|
|
{
|
|
// Create and initialize a VTF texture
|
|
IVTFTexture *pVTFTexture = CreateVTFTexture();
|
|
const int nFlags = TEXTUREFLAGS_NOMIP | TEXTUREFLAGS_NOLOD | TEXTUREFLAGS_SRGB;
|
|
if ( pVTFTexture->Init( nSrcWidth, nSrcHeight, 1, IMAGE_FORMAT_RGB888, nFlags, 1, 1 ) )
|
|
{
|
|
// Copy the image data over to the VTF
|
|
unsigned char *pDestBits = pVTFTexture->ImageData();
|
|
int nDstSize = nSrcWidth * nSrcHeight * 3;
|
|
V_memcpy( pDestBits, pSrcImage, nDstSize );
|
|
|
|
// Allocate output buffer
|
|
int iMaxVTFSize = 1024 + ( nSrcWidth * nSrcHeight * 3 );
|
|
void *pVTF = malloc( iMaxVTFSize );
|
|
buffer.SetExternalBuffer( pVTF, iMaxVTFSize, 0 );
|
|
|
|
// Serialize to the buffer
|
|
bWriteResult = pVTFTexture->Serialize( buffer );
|
|
|
|
// Free the VTF texture
|
|
DestroyVTFTexture( pVTFTexture );
|
|
}
|
|
else
|
|
{
|
|
bWriteResult = false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Write TGA format to buffer
|
|
int iMaxTGASize = 1024 + ( nSrcWidth * nSrcHeight * 4 );
|
|
void *pTGA = malloc( iMaxTGASize );
|
|
buffer.SetExternalBuffer( pTGA, iMaxTGASize, 0 );
|
|
|
|
bWriteResult = TGAWriter::WriteToBuffer( pSrcImage, buffer, nSrcWidth, nSrcHeight, IMAGE_FORMAT_RGB888, IMAGE_FORMAT_RGB888 );
|
|
}
|
|
|
|
if ( !bWriteResult )
|
|
{
|
|
Error( "Couldn't write bitmap data snapshot.\n" );
|
|
}
|
|
|
|
free( pImage );
|
|
free( pPaddedImage );
|
|
|
|
// async write to disk (this will take ownership of the memory)
|
|
char szPathedFileName[_MAX_PATH];
|
|
Q_snprintf( szPathedFileName, sizeof(szPathedFileName), "//MOD/%s", pFilename );
|
|
|
|
filesystem->AsyncWrite( szPathedFileName, buffer.Base(), buffer.TellPut(), true );
|
|
|
|
// restore our previous state
|
|
pRenderContext->PopRenderTargetAndViewport();
|
|
|
|
pRenderContext->MatrixMode( MATERIAL_PROJECTION );
|
|
pRenderContext->PopMatrix();
|
|
|
|
pRenderContext->MatrixMode( MATERIAL_VIEW );
|
|
pRenderContext->PopMatrix();
|
|
|
|
g_bRenderingScreenshot = false;
|
|
#endif
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: takes a screenshot for the replay system
|
|
//-----------------------------------------------------------------------------
|
|
void CViewRender::WriteReplayScreenshot( WriteReplayScreenshotParams_t ¶ms )
|
|
{
|
|
#if defined( REPLAY_ENABLED )
|
|
if ( !m_pReplayScreenshotTaker )
|
|
return;
|
|
|
|
m_pReplayScreenshotTaker->TakeScreenshot( params );
|
|
#endif
|
|
}
|
|
|
|
void CViewRender::UpdateReplayScreenshotCache()
|
|
{
|
|
#if defined( REPLAY_ENABLED )
|
|
// Delete the old one
|
|
delete m_pReplayScreenshotTaker;
|
|
|
|
// Create a new one
|
|
m_pReplayScreenshotTaker = new CReplayScreenshotTaker( this, GetView ( STEREO_EYE_MONO ) );
|
|
#endif
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: takes a screenshot of the save game
|
|
//-----------------------------------------------------------------------------
|
|
void CViewRender::WriteSaveGameScreenshot( const char *pFilename )
|
|
{
|
|
WriteSaveGameScreenshotOfSize( pFilename, SAVEGAME_SCREENSHOT_WIDTH, SAVEGAME_SCREENSHOT_HEIGHT );
|
|
}
|
|
|
|
|
|
float ScaleFOVByWidthRatio( float fovDegrees, float ratio )
|
|
{
|
|
float halfAngleRadians = fovDegrees * ( 0.5f * M_PI / 180.0f );
|
|
float t = tan( halfAngleRadians );
|
|
t *= ratio;
|
|
float retDegrees = ( 180.0f / M_PI ) * atan( t );
|
|
return retDegrees * 2.0f;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Sets view parameters for level overview mode
|
|
// Input : *rect -
|
|
//-----------------------------------------------------------------------------
|
|
void CViewRender::SetUpOverView()
|
|
{
|
|
static int oldCRC = 0;
|
|
|
|
CViewSetup &view = GetView ( STEREO_EYE_MONO );
|
|
|
|
view.m_bOrtho = true;
|
|
|
|
float aspect = (float)view.width/(float)view.height;
|
|
|
|
int size_y = 1024.0f * cl_leveloverview.GetFloat(); // scale factor, 1024 = OVERVIEW_MAP_SIZE
|
|
int size_x = size_y * aspect; // standard screen aspect
|
|
|
|
view.origin.x -= size_x / 2;
|
|
view.origin.y += size_y / 2;
|
|
|
|
view.m_OrthoLeft = 0;
|
|
view.m_OrthoTop = -size_y;
|
|
view.m_OrthoRight = size_x;
|
|
view.m_OrthoBottom = 0;
|
|
|
|
view.angles = QAngle( 90, 90, 0 );
|
|
|
|
// simple movement detector, show position if moved
|
|
int newCRC = view.origin.x + view.origin.y + view.origin.z;
|
|
if ( newCRC != oldCRC )
|
|
{
|
|
Msg( "Overview: scale %.2f, pos_x %.0f, pos_y %.0f\n", cl_leveloverview.GetFloat(),
|
|
view.origin.x, view.origin.y );
|
|
oldCRC = newCRC;
|
|
}
|
|
|
|
CMatRenderContextPtr pRenderContext( materials );
|
|
pRenderContext->ClearColor4ub( 0, 255, 0, 255 );
|
|
|
|
// render->DrawTopView( true );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Render current view into specified rectangle
|
|
// Input : *rect - is computed by CVideoMode_Common::GetClientViewRect()
|
|
//-----------------------------------------------------------------------------
|
|
void CViewRender::Render( vrect_t *rect )
|
|
{
|
|
Assert(s_DbgSetupOrigin == m_View.origin);
|
|
Assert(s_DbgSetupAngles == m_View.angles);
|
|
|
|
VPROF_BUDGET( "CViewRender::Render", "CViewRender::Render" );
|
|
tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
|
|
|
|
vrect_t vr = *rect;
|
|
|
|
// Stub out the material system if necessary.
|
|
CMatStubHandler matStub;
|
|
|
|
engine->EngineStats_BeginFrame();
|
|
|
|
// Assume normal vis
|
|
m_bForceNoVis = false;
|
|
|
|
C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
|
|
|
|
|
|
// Set for console commands, etc.
|
|
render->SetMainView ( m_View.origin, m_View.angles );
|
|
|
|
for( StereoEye_t eEye = GetFirstEye(); eEye <= GetLastEye(); eEye = (StereoEye_t)(eEye+1) )
|
|
{
|
|
CViewSetup &view = GetView( eEye );
|
|
|
|
#if 0 && defined( CSTRIKE_DLL )
|
|
const bool bPlayingBackReplay = g_pEngineClientReplay && g_pEngineClientReplay->IsPlayingReplayDemo();
|
|
if ( pPlayer && !bPlayingBackReplay )
|
|
{
|
|
C_BasePlayer *pViewTarget = pPlayer;
|
|
|
|
if ( pPlayer->IsObserver() && pPlayer->GetObserverMode() == OBS_MODE_IN_EYE )
|
|
{
|
|
pViewTarget = dynamic_cast<C_BasePlayer*>( pPlayer->GetObserverTarget() );
|
|
}
|
|
|
|
if ( pViewTarget )
|
|
{
|
|
float targetFOV = (float)pViewTarget->m_iFOV;
|
|
|
|
if ( targetFOV == 0 )
|
|
{
|
|
// FOV of 0 means use the default FOV
|
|
targetFOV = g_pGameRules->DefaultFOV();
|
|
}
|
|
|
|
float deltaFOV = view.fov - m_flLastFOV;
|
|
float FOVDirection = targetFOV - pViewTarget->m_iFOVStart;
|
|
|
|
// Clamp FOV changes to stop FOV oscillation
|
|
if ( ( deltaFOV < 0.0f && FOVDirection > 0.0f ) ||
|
|
( deltaFOV > 0.0f && FOVDirection < 0.0f ) )
|
|
{
|
|
view.fov = m_flLastFOV;
|
|
}
|
|
|
|
// Catch case where FOV overshoots its target FOV
|
|
if ( ( view.fov < targetFOV && FOVDirection <= 0.0f ) ||
|
|
( view.fov > targetFOV && FOVDirection >= 0.0f ) )
|
|
{
|
|
view.fov = targetFOV;
|
|
}
|
|
|
|
m_flLastFOV = view.fov;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
static ConVarRef sv_restrict_aspect_ratio_fov( "sv_restrict_aspect_ratio_fov" );
|
|
float aspectRatio = engine->GetScreenAspectRatio() * 0.75f; // / (4/3)
|
|
float limitedAspectRatio = aspectRatio;
|
|
if ( ( sv_restrict_aspect_ratio_fov.GetInt() > 0 && engine->IsWindowedMode() && gpGlobals->maxClients > 1 ) ||
|
|
sv_restrict_aspect_ratio_fov.GetInt() == 2 )
|
|
{
|
|
limitedAspectRatio = MIN( aspectRatio, 1.85f * 0.75f ); // cap out the FOV advantage at a 1.85:1 ratio (about the widest any legit user should be)
|
|
}
|
|
|
|
view.fov = ScaleFOVByWidthRatio( view.fov, limitedAspectRatio );
|
|
view.fovViewmodel = ScaleFOVByWidthRatio( view.fovViewmodel, aspectRatio );
|
|
|
|
// Let the client mode hook stuff.
|
|
g_pClientMode->PreRender(&view);
|
|
|
|
g_pClientMode->AdjustEngineViewport( vr.x, vr.y, vr.width, vr.height );
|
|
|
|
ToolFramework_AdjustEngineViewport( vr.x, vr.y, vr.width, vr.height );
|
|
|
|
float flViewportScale = mat_viewportscale.GetFloat();
|
|
|
|
view.m_nUnscaledX = vr.x;
|
|
view.m_nUnscaledY = vr.y;
|
|
view.m_nUnscaledWidth = vr.width;
|
|
view.m_nUnscaledHeight = vr.height;
|
|
|
|
switch( eEye )
|
|
{
|
|
case STEREO_EYE_MONO:
|
|
{
|
|
#if 0
|
|
// Good test mode for debugging viewports that are not full-size.
|
|
view.width = vr.width * flViewportScale * 0.75f;
|
|
view.height = vr.height * flViewportScale * 0.75f;
|
|
view.x = vr.x + view.width * 0.10f;
|
|
view.y = vr.y + view.height * 0.20f;
|
|
#else
|
|
view.x = vr.x * flViewportScale;
|
|
view.y = vr.y * flViewportScale;
|
|
view.width = vr.width * flViewportScale;
|
|
view.height = vr.height * flViewportScale;
|
|
#endif
|
|
float engineAspectRatio = engine->GetScreenAspectRatio();
|
|
view.m_flAspectRatio = ( engineAspectRatio > 0.0f ) ? engineAspectRatio : ( (float)view.width / (float)view.height );
|
|
}
|
|
break;
|
|
|
|
case STEREO_EYE_RIGHT:
|
|
case STEREO_EYE_LEFT:
|
|
{
|
|
g_pSourceVR->GetViewportBounds( (ISourceVirtualReality::VREye)(eEye - 1 ), &view.x, &view.y, &view.width, &view.height );
|
|
view.m_nUnscaledWidth = view.width;
|
|
view.m_nUnscaledHeight = view.height;
|
|
view.m_nUnscaledX = view.x;
|
|
view.m_nUnscaledY = view.y;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
Assert ( false );
|
|
break;
|
|
}
|
|
|
|
// if we still don't have an aspect ratio, compute it from the view size
|
|
if( view.m_flAspectRatio <= 0.f )
|
|
view.m_flAspectRatio = (float)view.width / (float)view.height;
|
|
|
|
int nClearFlags = VIEW_CLEAR_DEPTH | VIEW_CLEAR_STENCIL;
|
|
|
|
if( gl_clear_randomcolor.GetBool() )
|
|
{
|
|
CMatRenderContextPtr pRenderContext( materials );
|
|
pRenderContext->ClearColor3ub( rand()%256, rand()%256, rand()%256 );
|
|
pRenderContext->ClearBuffers( true, false, false );
|
|
pRenderContext->Release();
|
|
}
|
|
else if ( gl_clear.GetBool() )
|
|
{
|
|
nClearFlags |= VIEW_CLEAR_COLOR;
|
|
}
|
|
else if ( IsPosix() )
|
|
{
|
|
MaterialAdapterInfo_t adapterInfo;
|
|
materials->GetDisplayAdapterInfo( materials->GetCurrentAdapter(), adapterInfo );
|
|
|
|
// On Posix, on ATI, we always clear color if we're antialiasing
|
|
if ( adapterInfo.m_VendorID == 0x1002 )
|
|
{
|
|
if ( g_pMaterialSystem->GetCurrentConfigForVideoCard().m_nAASamples > 0 )
|
|
{
|
|
nClearFlags |= VIEW_CLEAR_COLOR;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Determine if we should draw view model ( client mode override )
|
|
bool drawViewModel = g_pClientMode->ShouldDrawViewModel();
|
|
|
|
if ( cl_leveloverview.GetFloat() > 0 )
|
|
{
|
|
SetUpOverView();
|
|
nClearFlags |= VIEW_CLEAR_COLOR;
|
|
drawViewModel = false;
|
|
}
|
|
|
|
// Apply any player specific overrides
|
|
if ( pPlayer )
|
|
{
|
|
// Override view model if necessary
|
|
if ( !pPlayer->m_Local.m_bDrawViewmodel )
|
|
{
|
|
drawViewModel = false;
|
|
}
|
|
}
|
|
|
|
int flags = 0;
|
|
if( eEye == STEREO_EYE_MONO || eEye == STEREO_EYE_LEFT || ( g_ClientVirtualReality.ShouldRenderHUDInWorld() ) )
|
|
{
|
|
flags = RENDERVIEW_DRAWHUD;
|
|
}
|
|
if ( drawViewModel )
|
|
{
|
|
flags |= RENDERVIEW_DRAWVIEWMODEL;
|
|
}
|
|
if( eEye == STEREO_EYE_RIGHT )
|
|
{
|
|
// we should use the monitor view from the left eye for both eyes
|
|
flags |= RENDERVIEW_SUPPRESSMONITORRENDERING;
|
|
}
|
|
|
|
RenderView( view, nClearFlags, flags );
|
|
|
|
if ( UseVR() )
|
|
{
|
|
bool bDoUndistort = ! engine->IsTakingScreenshot();
|
|
|
|
if ( bDoUndistort )
|
|
{
|
|
g_ClientVirtualReality.PostProcessFrame( eEye );
|
|
}
|
|
|
|
// logic here all cloned from code in viewrender.cpp around RenderHUDQuad:
|
|
|
|
// figure out if we really want to draw the HUD based on freeze cam
|
|
bool bInFreezeCam = ( pPlayer && pPlayer->GetObserverMode() == OBS_MODE_FREEZECAM );
|
|
|
|
// draw the HUD after the view model so its "I'm closer" depth queues work right.
|
|
if( !bInFreezeCam && g_ClientVirtualReality.ShouldRenderHUDInWorld() )
|
|
{
|
|
// TODO - a bit of a shonky test - basically trying to catch the main menu, the briefing screen, the loadout screen, etc.
|
|
bool bTranslucent = !g_pMatSystemSurface->IsCursorVisible();
|
|
g_ClientVirtualReality.OverlayHUDQuadWithUndistort( view, bDoUndistort, g_pClientMode->ShouldBlackoutAroundHUD(), bTranslucent );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// TODO: should these be inside or outside the stereo eye stuff?
|
|
g_pClientMode->PostRender();
|
|
engine->EngineStats_EndFrame();
|
|
|
|
#if !defined( _X360 )
|
|
// Stop stubbing the material system so we can see the budget panel
|
|
matStub.End();
|
|
#endif
|
|
|
|
|
|
// Draw all of the UI stuff "fullscreen"
|
|
// (this is not health, ammo, etc. Nor is it pre-game briefing interface stuff - this is the stuff that appears when you hit Esc in-game)
|
|
// In stereo mode this is rendered inside of RenderView so it goes into the render target
|
|
if( !g_ClientVirtualReality.ShouldRenderHUDInWorld() )
|
|
{
|
|
CViewSetup view2d;
|
|
view2d.x = rect->x;
|
|
view2d.y = rect->y;
|
|
view2d.width = rect->width;
|
|
view2d.height = rect->height;
|
|
|
|
render->Push2DView( view2d, 0, NULL, GetFrustum() );
|
|
render->VGui_Paint( PAINT_UIPANELS | PAINT_CURSOR );
|
|
render->PopView( GetFrustum() );
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void GetPos( const CCommand &args, Vector &vecOrigin, QAngle &angles )
|
|
{
|
|
vecOrigin = MainViewOrigin();
|
|
angles = MainViewAngles();
|
|
if ( args.ArgC() == 2 && atoi( args[1] ) == 2 )
|
|
{
|
|
C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
|
|
if ( pPlayer )
|
|
{
|
|
vecOrigin = pPlayer->GetAbsOrigin();
|
|
angles = pPlayer->GetAbsAngles();
|
|
}
|
|
}
|
|
}
|
|
|
|
CON_COMMAND( spec_pos, "dump position and angles to the console" )
|
|
{
|
|
Vector vecOrigin;
|
|
QAngle angles;
|
|
GetPos( args, vecOrigin, angles );
|
|
Warning( "spec_goto %.1f %.1f %.1f %.1f %.1f\n", vecOrigin.x, vecOrigin.y,
|
|
vecOrigin.z, angles.x, angles.y );
|
|
}
|
|
|
|
CON_COMMAND( getpos, "dump position and angles to the console" )
|
|
{
|
|
Vector vecOrigin;
|
|
QAngle angles;
|
|
GetPos( args, vecOrigin, angles );
|
|
|
|
const char *pCommand1 = "setpos";
|
|
const char *pCommand2 = "setang";
|
|
if ( args.ArgC() == 2 && atoi( args[1] ) == 2 )
|
|
{
|
|
pCommand1 = "setpos_exact";
|
|
pCommand2 = "setang_exact";
|
|
}
|
|
|
|
Warning( "%s %f %f %f;", pCommand1, vecOrigin.x, vecOrigin.y, vecOrigin.z );
|
|
Warning( "%s %f %f %f\n", pCommand2, angles.x, angles.y, angles.z );
|
|
}
|
|
|