csgo-2018-source/engine/enginetool.cpp
2021-07-24 21:11:47 -07:00

1128 lines
30 KiB
C++

//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. =======
//
// Purpose: Implmentation of IEngineTool callback interface
// Tool .dlls can call back through this interface to talk to the engine
//
//=============================================================================
#include "ienginetoolinternal.h"
#include "EngineSoundInternal.h"
#include "vengineserver_impl.h"
#include "cdll_engine_int.h"
#include "toolframework/ienginetool.h"
#include "client.h"
#include "server.h"
#include "con_nprint.h"
#include "toolframework/itoolframework.h"
#include "sound.h"
#include "screen.h"
#include "render.h"
#include "gl_matsysiface.h"
#include "cl_main.h"
#include "sys_dll.h"
#include "ivideomode.h"
#include "voice.h"
#include "filesystem_engine.h"
#include "enginetrace.h"
#include "Overlay.h"
#include "r_efx.h"
#include "r_local.h"
#include "lightcache.h"
#include "ispatialpartitioninternal.h"
#include "networkstringtableserver.h"
#include "networkstringtable.h"
#include "igame.h"
#include "gl_rmain.h"
#ifndef DEDICATED
#include "vgui_baseui_interface.h"
#endif
// NOTE: This has to be the last file included!
#include "tier0/memdbgon.h"
// External variables and APIs needed
extern CSysModule *g_GameDLL;
extern ConVar host_timescale;
extern CGlobalVars g_ServerGlobalVariables;
void SV_ForceSend();
CreateInterfaceFn ClientDLL_GetFactory( void );
extern CNetworkStringTableContainer *networkStringTableContainerServer;
IOverlayMgr *OverlayMgr();
void SV_ForceSend();
extern ConVar host_framerate;
void CL_StartMovie( const char *filename, int flags, int nWidth, int nHeight, float flFrameRate, int jpeg_quality );
void CL_EndMovie();
bool CL_IsRecordingMovie();
void VGui_SetGameDLLPanelsVisible( bool show );
float AudioSource_GetSoundDuration( char const *pName );
//-----------------------------------------------------------------------------
// Purpose: Singleton implementation of external tools callback interface
//-----------------------------------------------------------------------------
class CEngineTool : public IEngineToolInternal
{
public:
CEngineTool();
// Methods of IEngineToolFramework
// Take over input
virtual void ShowCursor( bool show );
virtual bool IsCursorVisible() const;
// Helpers for implementing a tool switching UI
virtual int GetToolCount() const;
virtual const char *GetToolName( int index ) const;
virtual void SwitchToTool( int index );
virtual bool IsTopmostTool( const IToolSystem *sys ) const;
virtual const IToolSystem *GetToolSystem( int index ) const;
virtual IToolSystem *GetTopmostTool();
// If module not already loaded, loads it and optionally switches to first tool in module. Returns false if load failed or tool already loaded
virtual bool LoadToolModule( char const *pToolModule, bool bSwitchToFirst );
public:
// Retrieve factories from server.dll and client.dll to get at specific interfaces defined within
virtual void GetServerFactory( CreateInterfaceFn& factory );
virtual void GetClientFactory( CreateInterfaceFn& factory );
// Issue a console command
virtual void Command( const char *cmd );
// Flush console command buffer right away
virtual void Execute();
// If in a level, get name of current level
virtual const char *GetCurrentMap();
virtual void ChangeToMap( const char *mapname );
virtual bool IsMapValid( const char *mapname );
// Method for causing engine to call client to render scene with no view model or overlays
virtual void RenderView( CViewSetup &view, int nFlags, int nWhatToRender );
// Returns true if the player is fully connected and active in game (i.e, not still loading)
virtual bool IsInGame();
// Returns true if the player is connected, but not necessarily active in game (could still be loading)
virtual bool IsConnected();
virtual int GetMaxClients(); // Tools might want to ensure single player, e.g.
virtual bool IsGamePaused();
virtual void SetGamePaused( bool paused );
virtual float GetTimescale(); // host_timescale ConVar multiplied by the game timescale
virtual void SetTimescale( float scale );
// Real time is unscaled, but is updated once per frame
virtual float GetRealTime();
virtual float GetRealFrameTime(); // unscaled
virtual float Time(); // Get high precision timer (for profiling?)
// Host time is scaled
virtual float HostFrameTime(); // host_frametime
virtual float HostTime(); // host_time
virtual int HostTick(); // host_tickcount
virtual int HostFrameCount(); // total famecount
virtual float ServerTime(); // gpGlobals->curtime on server
virtual float ServerFrameTime(); // gpGlobals->frametime on server
virtual int ServerTick(); // gpGlobals->tickcount on server
virtual float ServerTickInterval(); // tick interval on server
virtual float ClientTime(); // gpGlobals->curtime on client
virtual float ClientFrameTime(); // gpGlobals->frametime on client
virtual int ClientTick(); // gpGlobals->tickcount on client
virtual void SetClientFrameTime( float frametime ); // gpGlobals->frametime on client
// Currently the engine doesn't like to do networking when it's paused, but if a tool changes entity state, it can be useful to force
// a network update to get that state over to the client
virtual void ForceUpdateDuringPause();
// Maybe through modelcache???
virtual model_t *GetModel( HTOOLHANDLE hEntity );
// Get the .mdl file used by entity (if it's a cbaseanimating)
virtual studiohdr_t *GetStudioModel( HTOOLHANDLE hEntity );
// SINGLE PLAYER/LISTEN SERVER ONLY (just matching the client .dll api for this)
// Prints the formatted string to the notification area of the screen ( down the right hand edge
// numbered lines starting at position 0
virtual void Con_NPrintf( int pos, const char *fmt, ... );
// SINGLE PLAYER/LISTEN SERVER ONLY(just matching the client .dll api for this)
// Similar to Con_NPrintf, but allows specifying custom text color and duration information
virtual void Con_NXPrintf( const struct con_nprint_s *info, const char *fmt, ... );
// Get the current game directory (hl2, tf2, hl1, cstrike, etc.)
virtual void GetGameDir( char *szGetGameDir, int maxlength );
// Do we need separate rects for the 3d "viewport" vs. the tools surface??? and can we control viewports from
virtual void GetScreenSize( int& width, int &height );
virtual int StartSound(
int iUserData,
bool staticsound,
int iEntIndex,
int iChannel,
const char *pSample,
float flVolume,
soundlevel_t iSoundlevel,
const Vector& origin,
const Vector& direction,
int iFlags = 0,
int iPitch = PITCH_NORM,
bool bUpdatePositions = true,
float delay = 0.0f,
int speakerentity = -1 );
virtual void StopSoundByGuid( int guid );
virtual void SetVolumeByGuid( int guid, float flVolume );
virtual bool IsSoundStillPlaying( int guid );
virtual bool GetSoundChannelVolume( const char* sound, float &flVolumeLeft, float &flVolumeRight ) { return false; }
virtual float GetSoundDuration( int guid );
virtual void ReloadSound( const char *pSample );
virtual void StopAllSounds( );
virtual void SetAudioState( const AudioState_t &audioState );
virtual void SetMainView( const Vector &vecOrigin, const QAngle &angles );
virtual bool GetPlayerView( CViewSetup &playerView, int x, int y, int w, int h );
virtual void CreatePickingRay( const CViewSetup &viewSetup, int x, int y, Vector& org, Vector& forward );
virtual bool IsLoopingSound( int guid );
virtual void InstallQuitHandler( void *pvUserData, FnQuitHandler func );
virtual void TakeTGAScreenShot( const char *filename, int width, int height );
// Even if game is paused, force networking to update to get new server state down to client
virtual void ForceSend();
virtual bool IsRecordingMovie();
// NOTE: Params can contain file name, frame rate, output avi, output raw, and duration
virtual void StartMovieRecording( KeyValues *pMovieParams );
virtual void EndMovieRecording();
virtual void CancelMovieRecording();
virtual AVIHandle_t GetRecordingAVIHandle();
virtual void StartRecordingVoiceToFile( const char *filename, const char *pPathID = 0 );
virtual void StopRecordingVoiceToFile();
virtual bool IsVoiceRecording();
virtual void TraceRay( const Ray_t &ray, unsigned int fMask, ITraceFilter *pTraceFilter, CBaseTrace *pTrace );
virtual void TraceRayServer( const Ray_t &ray, unsigned int fMask, ITraceFilter *pTraceFilter, CBaseTrace *pTrace );
bool CanQuit();
void UpdateScreenshot();
bool ShouldSuppressDeInit() const;
virtual bool IsConsoleVisible();
virtual int GetPointContents( const Vector &vecPosition );
virtual int GetActiveDLights( dlight_t *pList[MAX_DLIGHTS] );
virtual int GetLightingConditions( const Vector &vecPosition, Vector *pColors, int nMaxLocalLights, LightDesc_t *pLocalLights );
// precache methods
virtual bool PrecacheSound( const char *pName, bool bPreload = false );
virtual bool PrecacheModel( const char *pName, bool bPreload = false );
virtual float GetMono16Samples( const char *pszName, CUtlVector< short >& sampleList );
virtual void GetWorldToScreenMatrixForView( const CViewSetup &view, VMatrix *pVMatrix );
virtual SpatialPartitionHandle_t CreatePartitionHandle( IHandleEntity *pEntity, SpatialPartitionListMask_t listMask, const Vector& mins, const Vector& maxs );
virtual void DestroyPartitionHandle( SpatialPartitionHandle_t hPartition );
virtual void InstallPartitionQueryCallback( IPartitionQueryCallback *pQuery );
virtual void RemovePartitionQueryCallback( IPartitionQueryCallback *pQuery );
virtual void ElementMoved( SpatialPartitionHandle_t handle, const Vector& mins, const Vector& maxs );
virtual float GetSoundDuration( const char *pszName );
virtual void ValidateSoundCache( char const *pchSoundName );
virtual void PrefetchSound( char const *pchSoundName );
virtual void* GetEngineHwnd();
virtual void OnModeChanged( bool bGameMode );
public:
// Methods of IEngineToolInternal
virtual void SetIsInGame( bool bIsInGame );
virtual float GetSoundElapsedTime( int guid );
virtual bool GetPreventSound( void );
private:
bool m_bIsInGame;
struct QuitHandler_t
{
void *userdata;
FnQuitHandler func;
};
CUtlVector< QuitHandler_t > m_QuitHandlers;
char m_szScreenshotFile[ MAX_OSPATH ];
int m_nScreenshotWidth;
int m_nScreenshotHeight;
bool m_bRecordingMovie;
bool m_bSuppressDeInit;
char m_szVoiceoverFile[ MAX_OSPATH ];
};
//-----------------------------------------------------------------------------
// Singleton
//-----------------------------------------------------------------------------
static CEngineTool g_EngineTool;
IEngineToolInternal *g_pEngineToolInternal = &g_EngineTool;
void EngineTool_InstallQuitHandler( void *pvUserData, FnQuitHandler func )
{
g_EngineTool.InstallQuitHandler( pvUserData, func );
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool EngineTool_CheckQuitHandlers()
{
return g_EngineTool.CanQuit();
}
void EngineTool_UpdateScreenshot()
{
g_EngineTool.UpdateScreenshot();
}
//-----------------------------------------------------------------------------
// Constructor
//-----------------------------------------------------------------------------
CEngineTool::CEngineTool()
{
m_bIsInGame = false;
m_szScreenshotFile[ 0 ] = 0;
m_nScreenshotWidth = 180;
m_nScreenshotHeight = 100;
m_bRecordingMovie = false;
m_bSuppressDeInit = false;
m_szVoiceoverFile[ 0 ] = 0;
}
//-----------------------------------------------------------------------------
// Singleton
//-----------------------------------------------------------------------------
void CEngineTool::ShowCursor( bool show )
{
Assert( 0 );
}
bool CEngineTool::IsCursorVisible() const
{
Assert( 0 );
return true;
}
int CEngineTool::GetPointContents( const Vector &vecPosition )
{
return g_pEngineTraceClient->GetPointContents( vecPosition, NULL );
}
int CEngineTool::GetActiveDLights( dlight_t *pList[MAX_DLIGHTS] )
{
return g_pEfx->CL_GetActiveDLights( pList );
}
bool WorldLightToMaterialLight( dworldlight_t* pWorldLight, LightDesc_t& light );
int CEngineTool::GetLightingConditions( const Vector &vecLightingOrigin, Vector *pColors, int nMaxLocalLights, LightDesc_t *pLocalLights )
{
LightcacheGetDynamic_Stats stats;
LightingState_t state;
LightcacheGetDynamic( vecLightingOrigin, state, stats, NULL );
Assert( state.numlights >= 0 && state.numlights < MAXLOCALLIGHTS );
memcpy( pColors, state.r_boxcolor, sizeof(state.r_boxcolor) );
int nLightCount = 0;
for ( int i = 0; i < state.numlights; ++i )
{
LightDesc_t *pLightDesc = &pLocalLights[nLightCount];
if (!WorldLightToMaterialLight( state.locallight[i], *pLightDesc ))
continue;
// Apply lightstyle
float bias = LightStyleValue( state.locallight[i]->style );
// Deal with overbrighting + bias
pLightDesc->m_Color[0] *= bias;
pLightDesc->m_Color[1] *= bias;
pLightDesc->m_Color[2] *= bias;
if ( ++nLightCount >= nMaxLocalLights )
break;
}
return nLightCount;
}
void CEngineTool::GetServerFactory( CreateInterfaceFn& factory )
{
factory = Sys_GetFactory( g_GameDLL );
}
void CEngineTool::GetClientFactory( CreateInterfaceFn& factory )
{
factory = ClientDLL_GetFactory();
}
void CEngineTool::Command( const char *cmd )
{
Cbuf_AddText( Cbuf_GetCurrentPlayer(), cmd );
}
void CEngineTool::Execute()
{
Cbuf_Execute();
}
const char *CEngineTool::GetCurrentMap()
{
if ( sv.IsDedicated() )
return "Dedicated Server";
if ( !GetBaseLocalClient().IsConnected() )
{
if ( sv.IsLoading() )
return sv.GetMapName();
return "";
}
return GetBaseLocalClient().m_szLevelName;
}
void CEngineTool::ChangeToMap( const char *mapname )
{
if ( modelloader->Map_IsValid( mapname ) )
{
Cbuf_AddText( Cbuf_GetCurrentPlayer(), va( "map \"%s\"\n", mapname ) );
}
}
bool CEngineTool::IsMapValid( const char *mapname )
{
return modelloader->Map_IsValid( mapname );
}
// Allows tools to kick off rendering by having the engine call the client
void CEngineTool::RenderView( CViewSetup &view, int nFlags, int whatToRender )
{
// Call client
ACTIVE_SPLITSCREEN_PLAYER_GUARD( 0 );
g_ClientDLL->RenderView( view, nFlags, whatToRender );
}
void CEngineTool::SetIsInGame( bool bIsInGame )
{
m_bIsInGame = bIsInGame;
}
bool CEngineTool::IsInGame()
{
return m_bIsInGame && GetBaseLocalClient().IsConnected();
}
bool CEngineTool::IsConnected()
{
return GetBaseLocalClient().IsConnected();
}
int CEngineTool::GetMaxClients()
{
return GetBaseLocalClient().m_nMaxClients;
}
bool CEngineTool::IsGamePaused()
{
return GetBaseLocalClient().IsPaused();
}
bool CEngineTool::IsConsoleVisible()
{
#ifdef DEDICATED
return false;
#else
return EngineVGui()->IsConsoleVisible();
#endif
}
void CEngineTool::SetGamePaused( bool paused )
{
sv.SetPaused( paused );
}
float CEngineTool::GetTimescale()
{
return host_timescale.GetFloat() * sv.GetTimescale();
}
void CEngineTool::SetTimescale( float scale )
{
host_timescale.SetValue( scale );
}
float CEngineTool::Time()
{
return Plat_FloatTime();
}
// Real time is unscaled, but is updated once per frame
float CEngineTool::GetRealTime()
{
return realtime;
}
float CEngineTool::GetRealFrameTime()
{
return host_frametime_unscaled;
}
float CEngineTool::HostFrameTime()
{
return host_frametime;
}
float CEngineTool::HostTime()
{
return host_time;
}
int CEngineTool::HostTick()
{
return host_tickcount;
}
int CEngineTool::HostFrameCount()
{
return host_framecount;
}
float CEngineTool::ServerTime()
{
return g_ServerGlobalVariables.curtime;
}
float CEngineTool::ServerFrameTime()
{
return g_ServerGlobalVariables.frametime;
}
int CEngineTool::ServerTick()
{
return g_ServerGlobalVariables.tickcount;
}
float CEngineTool::ServerTickInterval()
{
return g_ServerGlobalVariables.interval_per_tick;
}
float CEngineTool::ClientTime()
{
return g_ClientGlobalVariables.curtime;
}
float CEngineTool::ClientFrameTime()
{
return g_ClientGlobalVariables.frametime;
}
int CEngineTool::ClientTick()
{
return g_ClientGlobalVariables.tickcount;
}
void CEngineTool::SetClientFrameTime( float frametime )
{
g_ClientGlobalVariables.frametime = frametime;
}
void CEngineTool::ForceUpdateDuringPause()
{
SV_ForceSend();
}
model_t *CEngineTool::GetModel( HTOOLHANDLE hEntity )
{
Assert( 0 );
return NULL;
}
studiohdr_t *CEngineTool::GetStudioModel( HTOOLHANDLE hEntity )
{
Assert( 0 );
return NULL;
}
void CEngineTool::Con_NPrintf( int pos, const char *fmt, ... )
{
char buf[ 1024 ];
va_list argptr;
va_start( argptr, fmt );
_vsnprintf( buf, sizeof( buf ) - 1, fmt, argptr );
va_end( argptr );
return ::Con_NPrintf( pos, "%s", buf );
}
void CEngineTool::Con_NXPrintf( const struct con_nprint_s *info, const char *fmt, ... )
{
char buf[ 1024 ];
va_list argptr;
va_start( argptr, fmt );
_vsnprintf( buf, sizeof( buf ) - 1, fmt, argptr );
va_end( argptr );
::Con_NXPrintf( info, "%s", buf );
}
void CEngineTool::GetGameDir( char *szGetGameDir, int maxlength )
{
Q_strncpy( szGetGameDir, com_gamedir, maxlength );
}
void CEngineTool::GetScreenSize( int& width, int &height )
{
CMatRenderContextPtr pRenderContext( materials );
pRenderContext->GetWindowSize( width, height );
}
//-----------------------------------------------------------------------------
// Purpose: Helpers for implementing a tool switching UI
// Input : -
// Output : int
//-----------------------------------------------------------------------------
int CEngineTool::GetToolCount() const
{
return toolframework->GetToolCount();
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : index -
// Output : char
//-----------------------------------------------------------------------------
const char *CEngineTool::GetToolName( int index ) const
{
return toolframework->GetToolName( index );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : index -
//-----------------------------------------------------------------------------
void CEngineTool::SwitchToTool( int index )
{
toolframework->SwitchToTool( index );
}
bool CEngineTool::IsTopmostTool( const IToolSystem *sys ) const
{
return toolframework->IsTopmostTool( sys );
}
IToolSystem *CEngineTool::GetTopmostTool()
{
return toolframework->GetTopmostTool();
}
const IToolSystem *CEngineTool::GetToolSystem( int index ) const
{
return toolframework->GetToolSystem( index );
}
// If module not already loaded, loads it and optionally switches to first tool in module. Returns false if load failed or tool already loaded
bool CEngineTool::LoadToolModule( char const *pToolModule, bool bSwitchToFirst )
{
return toolframework->LoadToolModule( pToolModule, bSwitchToFirst );
}
void CEngineTool::ValidateSoundCache( char const *pchSoundName )
{
S_ValidateSoundCache( pchSoundName );
}
void CEngineTool::PrefetchSound( char const *pchSoundName )
{
S_PrefetchSound( pchSoundName, false );
}
int CEngineTool::StartSound(
int iUserData,
bool staticsound,
int iEntIndex,
int iChannel,
const char *pSample,
float flVolume,
soundlevel_t iSoundlevel,
const Vector& origin,
const Vector& direction,
int iFlags /*= 0*/,
int iPitch /*= PITCH_NORM*/,
bool bUpdatePositions /*= true*/,
float delay /*= 0.0f*/,
int speakerentity /*= -1*/ )
{
StartSoundParams_t params;
params.userdata = iUserData;
params.staticsound = staticsound;
params.soundsource = iEntIndex;
params.entchannel = iChannel;
params.pSfx = S_PrecacheSound( pSample );
params.origin = origin;
params.direction = direction;
params.bUpdatePositions = bUpdatePositions;
params.fvol = flVolume;
params.soundlevel = iSoundlevel;
params.flags = iFlags;
params.pitch = iPitch;
params.fromserver = false;
params.delay = delay;
params.speakerentity = speakerentity;
params.bToolSound = true;
int guid = S_StartSound( params );
return guid;
}
void CEngineTool::StopSoundByGuid( int guid )
{
S_StopSoundByGuid( guid );
}
void CEngineTool::SetVolumeByGuid( int guid, float flVolume )
{
S_SetVolumeByGuid( guid, flVolume );
}
bool CEngineTool::IsSoundStillPlaying( int guid )
{
return S_IsSoundStillPlaying( guid );
}
float CEngineTool::GetSoundDuration( int guid )
{
return S_SoundDurationByGuid( guid );
}
float CEngineTool::GetSoundElapsedTime( int guid )
{
return S_GetElapsedTimeByGuid( guid );
}
void* CEngineTool::GetEngineHwnd()
{
return game->GetMainWindow();
}
float CEngineTool::GetSoundDuration( const char *pszName )
{
return AudioSource_GetSoundDuration( pszName );
}
void CEngineTool::ReloadSound( const char *pSample )
{
S_ReloadSound( pSample );
}
void CEngineTool::StopAllSounds( )
{
S_StopAllSounds( true );
}
bool CEngineTool::GetPreventSound( )
{
return S_GetPreventSound( );
}
// Returns if the sound is looping
bool CEngineTool::IsLoopingSound( int guid )
{
return S_IsLoopingSoundByGuid( guid );
}
void CEngineTool::TraceRay( const Ray_t &ray, unsigned int fMask, ITraceFilter *pTraceFilter, CBaseTrace *pTrace )
{
trace_t tempTrace;
g_pEngineTraceClient->TraceRay( ray, fMask, pTraceFilter, &tempTrace );
memcpy( pTrace, &tempTrace, sizeof ( CBaseTrace ) );
}
void CEngineTool::TraceRayServer( const Ray_t &ray, unsigned int fMask, ITraceFilter *pTraceFilter, CBaseTrace *pTrace )
{
trace_t tempTrace;
g_pEngineTraceServer->TraceRay( ray, fMask, pTraceFilter, &tempTrace );
memcpy( pTrace, &tempTrace, sizeof ( CBaseTrace ) );
}
void CEngineTool::SetAudioState( const AudioState_t &audioState )
{
Host_SetAudioState( audioState );
}
// Sets the location of the main view
void CEngineTool::SetMainView( const Vector &vecOrigin, const QAngle &angles )
{
g_EngineRenderer->SetMainView( vecOrigin, angles );
}
static 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;
}
// Gets the player view
bool CEngineTool::GetPlayerView( CViewSetup &viewSetup, int x, int y, int w, int h )
{
if ( g_ClientDLL )
{
if ( !g_ClientDLL->GetPlayerView( viewSetup ) )
return false;
// Initialize view setup given the desired rectangle
viewSetup.x = x;
viewSetup.y = y;
viewSetup.width = w;
viewSetup.height = h;
viewSetup.m_flAspectRatio = (viewSetup.height != 0) ? (float)viewSetup.width / (float)viewSetup.height : 4.0f / 3.0f;
viewSetup.m_bRenderToSubrectOfLargerScreen = true;
viewSetup.fov = ScaleFOVByWidthRatio( viewSetup.fov, viewSetup.m_flAspectRatio / ( 4.0f / 3.0f ) );
viewSetup.fovViewmodel = ScaleFOVByWidthRatio( viewSetup.fovViewmodel, viewSetup.m_flAspectRatio / ( 4.0f / 3.0f ) );
return true;
}
return false;
}
//-----------------------------------------------------------------------------
// From a location on the screen, figure out the vector into the world
//-----------------------------------------------------------------------------
void CEngineTool::CreatePickingRay( const CViewSetup &viewSetup, int x, int y, Vector& org, Vector& forward )
{
// Remap x and y into -1 to 1 normalized space
float xf, yf;
xf = ( 2.0f * (float)x / (float)viewSetup.width ) - 1.0f;
yf = ( 2.0f * (float)y / (float)viewSetup.height ) - 1.0f;
// Flip y axis
yf = -yf;
VMatrix worldToScreen;
GetWorldToScreenMatrixForView( viewSetup, &worldToScreen );
VMatrix screenToWorld;
MatrixInverseGeneral( worldToScreen, screenToWorld );
// Create two points at the normalized mouse x, y pos and at the near and far z planes (0 and 1 depth)
Vector v1, v2;
v1.Init( xf, yf, 0.0f );
v2.Init( xf, yf, 1.0f );
Vector o2;
// Transform the two points by the screen to world matrix
screenToWorld.V3Mul( v1, org ); // ray start origin
screenToWorld.V3Mul( v2, o2 ); // ray end origin
VectorSubtract( o2, org, forward );
forward.NormalizeInPlace();
}
//-----------------------------------------------------------------------------
// Purpose: Returns true if all handlers say we can quit the engine
//-----------------------------------------------------------------------------
bool CEngineTool::CanQuit()
{
int c = m_QuitHandlers.Count();
for ( int i = 0; i < c; ++i )
{
QuitHandler_t& qh = m_QuitHandlers[ i ];
FnQuitHandler func = qh.func;
if ( func )
{
if ( !func( qh.userdata ) )
{
return false;
}
}
}
return true;
}
void CEngineTool::InstallQuitHandler( void *pvUserData, FnQuitHandler func )
{
QuitHandler_t qh;
qh.userdata = pvUserData;
qh.func = func;
m_QuitHandlers.AddToTail( qh );
}
// precache methods
bool CEngineTool::PrecacheSound( const char *pName, bool bPreload )
{
if ( pName && TestSoundChar( pName, CHAR_SENTENCE ) )
return true;
bool bState = networkStringTableContainerServer->Lock( false );
int flags = bPreload ? RES_PRELOAD : 0;
int i = sv.PrecacheSound( pName, flags );
networkStringTableContainerServer->Lock( bState );
return i >= 0;
}
bool CEngineTool::PrecacheModel( const char *pName, bool bPreload )
{
int flags = bPreload ? RES_PRELOAD : 0;
bool bState = networkStringTableContainerServer->Lock( false );
int i = sv.PrecacheModel( pName, flags );
networkStringTableContainerServer->Lock( bState );
return i >= 0;
}
void CEngineTool::TakeTGAScreenShot( const char *filename, int width, int height )
{
Q_strncpy( m_szScreenshotFile, filename, sizeof( m_szScreenshotFile ) );
m_nScreenshotWidth = width;
m_nScreenshotHeight = height;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEngineTool::UpdateScreenshot()
{
if ( g_LostVideoMemory )
return;
if ( m_szScreenshotFile[0] )
{
g_ClientDLL->WriteSaveGameScreenshotOfSize( m_szScreenshotFile, m_nScreenshotWidth, m_nScreenshotHeight );
m_szScreenshotFile[0] = 0;
}
}
// Even if game is paused, force networking to update to get new server state down to client
void CEngineTool::ForceSend()
{
SV_ForceSend();
}
bool CEngineTool::IsRecordingMovie()
{
if ( m_bRecordingMovie )
{
Assert( CL_IsRecordingMovie() );
return true;
}
return false;
}
// NOTE: Params can contain file name, frame rate, output avi, output raw, and duration
void CEngineTool::StartMovieRecording( KeyValues *pMovieParams )
{
if ( CL_IsRecordingMovie() )
{
Warning( "Can't record movie, already recording!!!\n" );
return;
}
if ( m_bRecordingMovie )
return;
int jpeg_quality = DEFAULT_JPEG_QUALITY;
int flags = 0;
if ( pMovieParams->GetInt( "outputavi", 0 ) )
{
if ( pMovieParams->GetInt( "avisoundonly", 0 ) )
{
flags |= MovieInfo_t::FMOVIE_AVISOUND;
}
else
{
flags |= MovieInfo_t::FMOVIE_AVI | MovieInfo_t::FMOVIE_AVISOUND;
}
}
if ( pMovieParams->GetInt( "outputtga", 0 ) )
{
flags |= MovieInfo_t::FMOVIE_TGA;
}
if ( pMovieParams->GetInt( "outputjpg", 0 ) )
{
flags |= MovieInfo_t::FMOVIE_JPG;
jpeg_quality = pMovieParams->GetInt( "jpeg_quality" );
}
if ( pMovieParams->GetInt( "outputwav", 0 ) )
{
flags |= MovieInfo_t::FMOVIE_WAV;
}
const char *pFileName = pMovieParams->GetString( "filename", NULL );
if ( !pFileName )
{
Warning( "Output filename not specified!\n" );
return;
}
int nWidth = pMovieParams->GetInt( "width", videomode->GetModeWidth() );
int nHeight = pMovieParams->GetInt( "height", videomode->GetModeHeight() );
float flFrameRate = pMovieParams->GetFloat( "framerate", 30.0f );
m_bRecordingMovie = true;
CL_StartMovie( pFileName, flags, nWidth, nHeight, flFrameRate, jpeg_quality );
}
void CEngineTool::EndMovieRecording()
{
if ( !m_bRecordingMovie )
return;
CL_EndMovie();
m_bRecordingMovie = false;
}
void CEngineTool::CancelMovieRecording()
{
EndMovieRecording();
}
AVIHandle_t CEngineTool::GetRecordingAVIHandle()
{
if ( !CL_IsRecordingMovie() )
return AVIHANDLE_INVALID;
return g_hCurrentAVI;
}
bool CEngineTool::ShouldSuppressDeInit() const
{
return m_bSuppressDeInit;
}
void CEngineTool::StartRecordingVoiceToFile( const char *filename, const char *pPathID /*= 0*/ )
{
FileHandle_t fh = g_pFileSystem->Open( filename, "wb", pPathID );
if ( fh != FILESYSTEM_INVALID_HANDLE )
{
byte foo = 'b';
g_pFileSystem->Write( &foo, 1, fh );
g_pFileSystem->Close( fh );
}
g_pFileSystem->RelativePathToFullPath( filename, pPathID, m_szVoiceoverFile, sizeof( m_szVoiceoverFile ) );
g_pFileSystem->RemoveFile( filename, pPathID );
#if !defined( NO_VOICE )
if ( IsVoiceRecording() )
{
Voice_RecordStop();
}
m_bSuppressDeInit = true;
Voice_ForceInit();
Voice_RecordStart( m_szVoiceoverFile, NULL, NULL);
#endif
}
void CEngineTool::StopRecordingVoiceToFile()
{
#if !defined( NO_VOICE )
Voice_RecordStop();
m_bSuppressDeInit = false;
#endif
}
float CEngineTool::GetMono16Samples( const char *pszName, CUtlVector< short >& sampleList )
{
return S_GetMono16Samples( pszName, sampleList );
}
void CEngineTool::GetWorldToScreenMatrixForView( const CViewSetup &view, VMatrix *pVMatrix )
{
VMatrix worldToView, viewToProjection;
view.ComputeViewMatrices( &worldToView, &viewToProjection, pVMatrix );
}
SpatialPartitionHandle_t CEngineTool::CreatePartitionHandle( IHandleEntity *pEntity,
SpatialPartitionListMask_t listMask, const Vector& mins, const Vector& maxs )
{
return SpatialPartition()->CreateHandle( pEntity, listMask, mins, maxs );
}
void CEngineTool::DestroyPartitionHandle( SpatialPartitionHandle_t hPartition )
{
SpatialPartition()->DestroyHandle( hPartition );
}
void CEngineTool::InstallPartitionQueryCallback( IPartitionQueryCallback *pQuery )
{
SpatialPartition()->InstallQueryCallback( pQuery );
}
void CEngineTool::RemovePartitionQueryCallback( IPartitionQueryCallback *pQuery )
{
SpatialPartition()->RemoveQueryCallback( pQuery );
}
void CEngineTool::ElementMoved( SpatialPartitionHandle_t handle, const Vector& mins, const Vector& maxs )
{
SpatialPartition()->ElementMoved( handle, mins, maxs );
}
bool CEngineTool::IsVoiceRecording()
{
#if !defined( NO_VOICE )
return Voice_IsRecording();
#else
return false;
#endif
}
void CEngineTool::OnModeChanged( bool bGameMode )
{
EngineVGui()->OnToolModeChanged( bGameMode );
}
bool EngineTool_SuppressDeInit()
{
return g_EngineTool.ShouldSuppressDeInit();
}
void EngineTool_OverrideSampleRate( int& rate )
{
if ( EngineTool_SuppressDeInit() )
{
rate = 11025;
}
}
// Expose complex interface
EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CEngineTool, IEngineTool, VENGINETOOL_INTERFACE_VERSION, g_EngineTool );
// Expose simple interface
EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CEngineTool, IEngineToolFramework, VENGINETOOLFRAMEWORK_INTERFACE_VERSION, g_EngineTool );