diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /engine/cdll_engine_int.cpp | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'engine/cdll_engine_int.cpp')
| -rw-r--r-- | engine/cdll_engine_int.cpp | 2213 |
1 files changed, 2213 insertions, 0 deletions
diff --git a/engine/cdll_engine_int.cpp b/engine/cdll_engine_int.cpp new file mode 100644 index 0000000..f986a20 --- /dev/null +++ b/engine/cdll_engine_int.cpp @@ -0,0 +1,2213 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// 4-23-98 +// JOHN: implementation of interface between client-side DLL and game engine. +// The cdll shouldn't have to know anything about networking or file formats. +// This file is Win32-dependant +// +//=============================================================================// + +#include "client_pch.h" +#include "getintersectingsurfaces_struct.h" +#include "gl_model_private.h" +#include "surfinfo.h" +#include "vstdlib/random.h" +#include "cdll_int.h" +#include "cmodel_engine.h" +#include "tmessage.h" +#include "console.h" +#include "snd_audio_source.h" +#include <vgui_controls/Controls.h> +#include <vgui/IInput.h> +#include "iengine.h" +#include "keys.h" +#include "con_nprint.h" +#include "tier0/vprof.h" +#include "sound.h" +#include "gl_rmain.h" +#include "proto_version.h" +#include "client_class.h" +#include "gl_rsurf.h" +#include "server.h" +#include "r_local.h" +#include "lightcache.h" +#include "gl_matsysiface.h" +#include "materialsystem/imaterialsystemhardwareconfig.h" +#include "materialsystem/materialsystem_config.h" +#include "materialsystem/imaterial.h" +#include "materialsystem/imaterialvar.h" +#include "materialsystem/itexture.h" +#include "istudiorender.h" +#include "l_studio.h" +#include "voice.h" +#include "enginestats.h" +#include "testscriptmgr.h" +#include "r_areaportal.h" +#include "host.h" +#include "host_cmd.h" +#include "vox.h" +#include "iprediction.h" +#include "icliententitylist.h" +#include "eiface.h" +#include "ivguicenterprint.h" +#include "engine/IClientLeafSystem.h" +#include "dt_recv_eng.h" +#include <vgui/IVGui.h> +#include "sys_dll.h" +#include "vphysics_interface.h" +#include "materialsystem/imesh.h" +#include "IOcclusionSystem.h" +#include "filesystem_engine.h" +#include "tier0/icommandline.h" +#include "client_textmessage.h" +#include "host_saverestore.h" +#include "cl_main.h" +#include "demo.h" +#include "appframework/ilaunchermgr.h" +#include "vgui_baseui_interface.h" +#include "LocalNetworkBackdoor.h" +#include "lightcache.h" +#include "vgui/ISystem.h" +#include "ivideomode.h" +#include "icolorcorrectiontools.h" +#include "toolframework/itoolframework.h" +#include "engine/view_sharedv1.h" +#include "view.h" +#include "game/client/iclientrendertargets.h" +#include "tier2/tier2.h" +#include "matchmaking.h" +#include "inputsystem/iinputsystem.h" +#include "iachievementmgr.h" +#include "profile.h" +#include "cl_steamauth.h" +#include "download.h" +#include "replay/iclientreplay.h" +#include "demofile.h" +#include "igame.h" +#include "iclientvirtualreality.h" +#include "sourcevr/isourcevirtualreality.h" +#include "cl_check_process.h" +#include "enginethreads.h" + +#if defined( REPLAY_ENABLED ) +#include "replay_internal.h" +#include "replay/replaylib.h" +#endif + + + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//----------------------------------------------------------------------------- +// forward declarations +//----------------------------------------------------------------------------- +IMaterial* BrushModel_GetLightingAndMaterial( const Vector &start, + const Vector &end, Vector &diffuseLightColor, Vector &baseColor ); +const char *Key_NameForBinding( const char *pBinding ); +void CL_GetBackgroundLevelName( char *pszBackgroundName, int bufSize, bool bMapName ); +CreateInterfaceFn g_ClientFactory = NULL; +extern CGlobalVars g_ServerGlobalVariables; + +//----------------------------------------------------------------------------- +// globals +//----------------------------------------------------------------------------- +CSysModule *g_ClientDLLModule = NULL; // also used by materialproxyfactory.cpp +bool g_bClientGameDLLGreaterThanV13; + +void AddIntersectingLeafSurfaces( mleaf_t *pLeaf, GetIntersectingSurfaces_Struct *pStruct ) +{ + SurfaceHandle_t *pHandle = &host_state.worldbrush->marksurfaces[pLeaf->firstmarksurface]; + for ( int iSurf=0; iSurf < pLeaf->nummarksurfaces; iSurf++ ) + { + SurfaceHandle_t surfID = pHandle[iSurf]; + ASSERT_SURF_VALID( surfID ); + + if ( MSurf_Flags(surfID) & SURFDRAW_SKY ) + continue; + + // Make sure we haven't already processed this one. + bool foundSurf = false; + for(int iTest=0; iTest < pStruct->m_nSetInfos; iTest++) + { + if(pStruct->m_pInfos[iTest].m_pEngineData == (void *)surfID) + { + foundSurf = true; + break; + } + } + if ( foundSurf ) + continue; + + // Make sure there's output room. + if(pStruct->m_nSetInfos >= pStruct->m_nMaxInfos) + return; + SurfInfo *pOut = &pStruct->m_pInfos[pStruct->m_nSetInfos]; + pOut->m_nVerts = 0; + pOut->m_pEngineData = (void *)surfID; + + // Build vertex list and bounding box. + Vector vMin( 1000000.0f, 1000000.0f, 1000000.0f); + Vector vMax(-1000000.0f, -1000000.0f, -1000000.0f); + for(int iVert=0; iVert < MSurf_VertCount( surfID ); iVert++) + { + int vertIndex = pStruct->m_pModel->brush.pShared->vertindices[MSurf_FirstVertIndex( surfID ) + iVert]; + + pOut->m_Verts[pOut->m_nVerts] = pStruct->m_pModel->brush.pShared->vertexes[vertIndex].position; + vMin = vMin.Min(pOut->m_Verts[pOut->m_nVerts]); + vMax = vMax.Max(pOut->m_Verts[pOut->m_nVerts]); + + ++pOut->m_nVerts; + if(pOut->m_nVerts >= MAX_SURFINFO_VERTS) + break; + } + + // See if the sphere intersects the box. + int iDim=0; + for(; iDim < 3; iDim++) + { + if(((*pStruct->m_pCenter)[iDim]+pStruct->m_Radius) < vMin[iDim] || + ((*pStruct->m_pCenter)[iDim]-pStruct->m_Radius) > vMax[iDim]) + { + break; + } + } + + if(iDim == 3) + { + // (Couldn't reject the sphere in the loop above). + pOut->m_Plane = MSurf_GetForwardFacingPlane( surfID ); + ++pStruct->m_nSetInfos; + } + } +} + +void GetIntersectingSurfaces_R( + GetIntersectingSurfaces_Struct *pStruct, + mnode_t *pNode + ) +{ + if(pStruct->m_nSetInfos >= pStruct->m_nMaxInfos) + return; + + // Ok, this is a leaf. Check its surfaces. + if(pNode->contents >= 0) + { + mleaf_t *pLeaf = (mleaf_t*)pNode; + + if(pStruct->m_bOnlyVisible && pStruct->m_pCenterPVS) + { + if(pLeaf->cluster < 0) + return; + + if(!(pStruct->m_pCenterPVS[pLeaf->cluster>>3] & (1 << (pLeaf->cluster&7)))) + return; + } + + // First, add tris from displacements. + for ( int i = 0; i < pLeaf->dispCount; i++ ) + { + IDispInfo *pDispInfo = MLeaf_Disaplcement( pLeaf, i ); + pDispInfo->GetIntersectingSurfaces( pStruct ); + } + + // Next, add brush tris. + AddIntersectingLeafSurfaces( pLeaf, pStruct ); + return; + } + + // Recurse. + float dot; + cplane_t *plane = pNode->plane; + if ( plane->type < 3 ) + { + dot = (*pStruct->m_pCenter)[plane->type] - plane->dist; + } + else + { + dot = pStruct->m_pCenter->Dot(plane->normal) - plane->dist; + } + + // Recurse into child nodes. + if(dot > -pStruct->m_Radius) + GetIntersectingSurfaces_R(pStruct, pNode->children[SIDE_FRONT]); + + if(dot < pStruct->m_Radius) + GetIntersectingSurfaces_R(pStruct, pNode->children[SIDE_BACK]); +} + + +//----------------------------------------------------------------------------- +// slow routine to draw a physics model +// NOTE: very slow code!!! just for debugging! +//----------------------------------------------------------------------------- +void DebugDrawPhysCollide( const CPhysCollide *pCollide, IMaterial *pMaterial, matrix3x4_t& transform, const color32 &color, bool drawAxes ) +{ + if ( !pMaterial ) + { + pMaterial = materials->FindMaterial("shadertest/wireframevertexcolor", TEXTURE_GROUP_OTHER); + } + + CMatRenderContextPtr pRenderContext( materials ); + + Vector *outVerts; + int vertCount = physcollision->CreateDebugMesh( pCollide, &outVerts ); + if ( vertCount ) + { + IMesh *pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, pMaterial ); + + CMeshBuilder meshBuilder; + meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, vertCount/3 ); + + for ( int j = 0; j < vertCount; j++ ) + { + Vector out; + VectorTransform( outVerts[j].Base(), transform, out.Base() ); + meshBuilder.Position3fv( out.Base() ); + meshBuilder.Color4ub( color.r, color.g, color.b, color.a ); + meshBuilder.TexCoord2f( 0, 0, 0 ); + meshBuilder.AdvanceVertex(); + } + meshBuilder.End(); + pMesh->Draw(); + } + physcollision->DestroyDebugMesh( vertCount, outVerts ); + + // draw the axes + if ( drawAxes ) + { + Vector xaxis(10,0,0), yaxis(0,10,0), zaxis(0,0,10); + Vector center; + Vector out; + + MatrixGetColumn( transform, 3, center ); + IMesh *pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, pMaterial ); + CMeshBuilder meshBuilder; + meshBuilder.Begin( pMesh, MATERIAL_LINES, 3 ); + + // X + meshBuilder.Position3fv( center.Base() ); + meshBuilder.Color4ub( 255, 0, 0, 255 ); + meshBuilder.TexCoord2f( 0, 0, 0 ); + meshBuilder.AdvanceVertex(); + VectorTransform( xaxis.Base(), transform, out.Base() ); + meshBuilder.Position3fv( out.Base() ); + meshBuilder.Color4ub( 255, 0, 0, 255 ); + meshBuilder.TexCoord2f( 0, 0, 0 ); + meshBuilder.AdvanceVertex(); + + // Y + meshBuilder.Position3fv( center.Base() ); + meshBuilder.Color4ub( 0, 255, 0, 255 ); + meshBuilder.TexCoord2f( 0, 0, 0 ); + meshBuilder.AdvanceVertex(); + VectorTransform( yaxis.Base(), transform, out.Base() ); + meshBuilder.Position3fv( out.Base() ); + meshBuilder.Color4ub( 0, 255, 0, 255 ); + meshBuilder.TexCoord2f( 0, 0, 0 ); + meshBuilder.AdvanceVertex(); + + // Z + meshBuilder.Position3fv( center.Base() ); + meshBuilder.Color4ub( 0, 0, 255, 255 ); + meshBuilder.TexCoord2f( 0, 0, 0 ); + meshBuilder.AdvanceVertex(); + VectorTransform( zaxis.Base(), transform, out.Base() ); + meshBuilder.Position3fv( out.Base() ); + meshBuilder.Color4ub( 0, 0, 255, 255 ); + meshBuilder.TexCoord2f( 0, 0, 0 ); + meshBuilder.AdvanceVertex(); + meshBuilder.End(); + pMesh->Draw(); + } +} + +//----------------------------------------------------------------------------- +// +// implementation of IVEngineHud +// +//----------------------------------------------------------------------------- + +// UNDONE: Move this to hud export code, subsume previous functions +class CEngineClient : public IVEngineClient +{ +public: + CEngineClient(); + + int GetIntersectingSurfaces( + const model_t *model, + const Vector &vCenter, + const float radius, + const bool bOnlyVisible, + SurfInfo *pInfos, + const int nMaxInfos); + + Vector GetLightForPoint(const Vector &pos, bool bClamp); + Vector GetLightForPointFast(const Vector &pos, bool bClamp); + const char *ParseFile( const char *data, char *token, int maxlen ); + virtual bool CopyLocalFile( const char *source, const char *destination ); + void GetScreenSize( int& w, int &h ); + void ServerCmd( const char *szCmdString, bool bReliable ); + void ClientCmd( const char *szCmdString ); + void ClientCmd_Unrestricted( const char *szCmdString ); + void SetRestrictServerCommands( bool bRestrict ); + void SetRestrictClientCommands( bool bRestrict ); + bool GetPlayerInfo( int ent_num, player_info_t *pinfo ); + client_textmessage_t *TextMessageGet( const char *pName ); + bool Con_IsVisible( void ); + int GetLocalPlayer( void ); + float GetLastTimeStamp( void ); + const model_t *LoadModel( const char *pName, bool bProp ); + void UnloadModel( const model_t *model, bool bProp ); + CSentence *GetSentence( CAudioSource *pAudioSource ); + float GetSentenceLength( CAudioSource *pAudioSource ); + bool IsStreaming( CAudioSource *pAudioSource ) const; + void AddPhonemeFile( const char *pszPhonemeFile ); + + // FIXME, move entirely to client .dll + void GetViewAngles( QAngle& va ); + void SetViewAngles( QAngle& va ); + int GetMaxClients( void ); + void Key_Event( ButtonCode_t key, int down ); + const char *Key_LookupBinding( const char *pBinding ); + const char *Key_LookupBindingExact( const char *pBinding ); + const char *Key_BindingForKey( ButtonCode_t code ); + void StartKeyTrapMode( void ); + bool CheckDoneKeyTrapping( ButtonCode_t &key ); + bool IsInGame( void ); + bool IsConnected( void ); + bool IsDrawingLoadingImage( void ); + void Con_NPrintf( int pos, const char *fmt, ... ); + void Con_NXPrintf( const struct con_nprint_s *info, const char *fmt, ... ); + IMaterial *TraceLineMaterialAndLighting( const Vector &start, const Vector &end, + Vector &diffuseLightColor, Vector &baseColor ); + int IsBoxVisible( const Vector& mins, const Vector& maxs ); + int IsBoxInViewCluster( const Vector& mins, const Vector& maxs ); + + float Time(); + void Sound_ExtraUpdate( void ); + + bool CullBox ( const Vector& mins, const Vector& maxs ); + const char *GetGameDirectory( void ); + const VMatrix& WorldToScreenMatrix(); + const VMatrix& WorldToViewMatrix(); + + // Loads a game lump off disk + int GameLumpVersion( int lumpId ) const; + int GameLumpSize( int lumpId ) const; + bool LoadGameLump( int lumpId, void* pBuffer, int size ); + + // Returns the number of leaves in the level + int LevelLeafCount() const; + virtual ISpatialQuery* GetBSPTreeQuery(); + + // Convert texlight to gamma... + virtual void LinearToGamma( float* linear, float* gamma ); + + // Get the lightstyle value + virtual float LightStyleValue( int style ); + virtual void DrawPortals(); + + // Computes light due to dynamic lighting at a point + // If the normal isn't specified, then it'll return the maximum lighting + virtual void ComputeDynamicLighting( Vector const& pt, Vector const* pNormal, Vector& color ); + + // Computes light due to dynamic lighting at a point + // If the normal isn't specified, then it'll return the maximum lighting + // If pBoxColors is specified (it's an array of 6), then it'll copy the light contribution at each box side. + virtual void ComputeLighting( const Vector& pt, const Vector* pNormal, bool bClamp, Vector& color, Vector *pBoxColors ); + + // Returns the color of the ambient light + virtual void GetAmbientLightColor( Vector& color ); + + // Returns the dx support level + virtual int GetDXSupportLevel(); + + virtual bool SupportsHDR(); + virtual void Mat_Stub( IMaterialSystem *pMatSys ); + + // menu display + virtual void GetChapterName( char *pchBuff, int iMaxLength ); + virtual char const *GetLevelName( void ); + virtual int GetLevelVersion( void ); + virtual bool IsLevelMainMenuBackground( void ); + virtual void GetMainMenuBackgroundName( char *dest, int destlen ); + + // Occlusion system control + virtual void SetOcclusionParameters( const OcclusionParams_t ¶ms ); + + //----------------------------------------------------------------------------- + // Purpose: Takes a trackerID and returns which player slot that user is in + // returns 0 if no player found with that ID + //----------------------------------------------------------------------------- + virtual int GetPlayerForUserID(int userID); +#if !defined( NO_VOICE ) + virtual struct IVoiceTweak_s *GetVoiceTweakAPI( void ); +#endif + virtual void EngineStats_BeginFrame( void ); + virtual void EngineStats_EndFrame( void ); + virtual void FireEvents(); + virtual void CheckPoint( const char *pName ); + virtual int GetLeavesArea( int *pLeaves, int nLeaves ); + virtual bool DoesBoxTouchAreaFrustum( const Vector &mins, const Vector &maxs, int iArea ); + + // Sets the hearing origin + virtual void SetAudioState( const AudioState_t &audioState ); + + //----------------------------------------------------------------------------- + // + // Sentence API + // + //----------------------------------------------------------------------------- + + virtual int SentenceGroupPick( int groupIndex, char *name, int nameLen ); + virtual int SentenceGroupPickSequential( int groupIndex, char *name, int nameLen, int sentenceIndex, int reset ); + virtual int SentenceIndexFromName( const char *pSentenceName ); + virtual const char *SentenceNameFromIndex( int sentenceIndex ); + virtual int SentenceGroupIndexFromName( const char *pGroupName ); + virtual const char *SentenceGroupNameFromIndex( int groupIndex ); + virtual float SentenceLength( int sentenceIndex ); + virtual void DebugDrawPhysCollide( const CPhysCollide *pCollide, IMaterial *pMaterial, matrix3x4_t& transform, const color32 &color ); + + // Activates/deactivates an occluder... + virtual void ActivateOccluder( int nOccluderIndex, bool bActive ); + virtual bool IsOccluded( const Vector &vecAbsMins, const Vector &vecAbsMaxs ); + virtual void *SaveAllocMemory( size_t num, size_t size ); + virtual void SaveFreeMemory( void *pSaveMem ); + virtual INetChannelInfo *GetNetChannelInfo( void ); + virtual bool IsPlayingDemo( void ); + virtual bool IsRecordingDemo( void ); + virtual bool IsPlayingTimeDemo( void ); + virtual int GetDemoRecordingTick( void ); + virtual int GetDemoPlaybackTick( void ); + virtual int GetDemoPlaybackStartTick( void ); + virtual float GetDemoPlaybackTimeScale( void ); + virtual int GetDemoPlaybackTotalTicks( void ); + virtual bool IsPaused( void ); + virtual bool IsTakingScreenshot( void ); + virtual bool IsHLTV( void ); + virtual void GetVideoModes( int &nCount, vmode_s *&pModes ); + virtual void GetUILanguage( char *dest, int destlen ); + + // Can skybox be seen from a particular point? + virtual SkyboxVisibility_t IsSkyboxVisibleFromPoint( const Vector &vecPoint ); + + virtual const char* GetMapEntitiesString(); + virtual bool IsInEditMode( void ); + virtual bool IsInCommentaryMode( void ); + virtual float GetScreenAspectRatio(); + + virtual unsigned int GetEngineBuildNumber() { return PROTOCOL_VERSION; } + virtual const char * GetProductVersionString() { return GetSteamInfIDVersionInfo().szVersionString; } + virtual void GrabPreColorCorrectedFrame( int x, int y, int width, int height ); + virtual bool IsHammerRunning( ) const; + + // Stuffs the cmd into the buffer & executes it immediately (vs ClientCmd() which executes it next frame) + virtual void ExecuteClientCmd( const char *szCmdString ); + + virtual bool MapHasHDRLighting( void) ; + virtual int GetAppID(); + + virtual void SetOverlayBindProxy( int iOverlayID, void *pBindProxy ); + + virtual bool CopyFrameBufferToMaterial( const char *pMaterialName ); + + // Matchmaking + void ChangeTeam( const char *pTeamName ); + virtual void ReadConfiguration( const bool readDefault = false ); + + virtual void SetAchievementMgr( IAchievementMgr *pAchievementMgr ); + virtual IAchievementMgr *GetAchievementMgr(); + + virtual bool MapLoadFailed( void ); + virtual void SetMapLoadFailed( bool bState ); + + virtual bool IsLowViolence(); + virtual const char *GetMostRecentSaveGame( void ); + virtual void SetMostRecentSaveGame( const char *lpszFilename ); + + virtual void StartXboxExitingProcess(); + virtual bool IsSaveInProgress(); + + virtual uint OnStorageDeviceAttached( void ); + virtual void OnStorageDeviceDetached( void ); + + virtual void ResetDemoInterpolation( void ); + + virtual bool REMOVED_SteamRefreshLogin( const char *password, bool isSecure ) { return false; } + virtual bool REMOVED_SteamProcessCall( bool & finished ) { return false; } + + virtual void SetGamestatsData( CGamestatsData *pGamestatsData ); + virtual CGamestatsData *GetGamestatsData(); + +#if defined( USE_SDL ) + virtual void GetMouseDelta( int &x, int &y, bool bIgnoreNextMouseDelta ); +#endif + + virtual void ServerCmdKeyValues( KeyValues *pKeyValues ); + + virtual bool IsSkippingPlayback( void ); + virtual bool IsLoadingDemo( void ); + + virtual bool IsPlayingDemoALocallyRecordedDemo(); + + virtual uint GetProtocolVersion( void ); + + virtual bool IsWindowedMode( void ); + + virtual void FlashWindow(); + virtual int GetClientVersion() const; // engines build + virtual bool IsActiveApp(); + virtual void DisconnectInternal(); + + virtual int GetInstancesRunningCount( ); + + virtual float GetPausedExpireTime( void ) OVERRIDE; + + virtual bool StartDemoRecording( const char *pszFilename, const char *pszFolder = NULL ); + virtual void StopDemoRecording( void ); + virtual void TakeScreenshot( const char *pszFilename, const char *pszFolder = NULL ); +}; + + +//----------------------------------------------------------------------------- +// Singleton +//----------------------------------------------------------------------------- +static CEngineClient s_VEngineClient; +IVEngineClient *engineClient = &s_VEngineClient; +EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CEngineClient, IVEngineClient, VENGINE_CLIENT_INTERFACE_VERSION, s_VEngineClient ); +EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CEngineClient, IVEngineClient013, VENGINE_CLIENT_INTERFACE_VERSION_13, s_VEngineClient ); + + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- +CEngineClient::CEngineClient() +{ +} + +int CEngineClient::GetIntersectingSurfaces( + const model_t *model, + const Vector &vCenter, + const float radius, + const bool bOnlyVisible, + SurfInfo *pInfos, + const int nMaxInfos) +{ + if ( !model ) + return 0; + + byte pvs[MAX_MAP_LEAFS/8]; + GetIntersectingSurfaces_Struct theStruct; + theStruct.m_pModel = ( model_t * )model; + theStruct.m_pCenter = &vCenter; + theStruct.m_pCenterPVS = CM_Vis( pvs, sizeof(pvs), CM_LeafCluster( CM_PointLeafnum( vCenter ) ), DVIS_PVS ); + theStruct.m_Radius = radius; + theStruct.m_bOnlyVisible = bOnlyVisible; + theStruct.m_pInfos = pInfos; + theStruct.m_nMaxInfos = nMaxInfos; + theStruct.m_nSetInfos = 0; + + // Go down the BSP. + GetIntersectingSurfaces_R( + &theStruct, + &model->brush.pShared->nodes[ model->brush.firstnode ] ); + + return theStruct.m_nSetInfos; +} + +Vector CEngineClient::GetLightForPoint(const Vector &pos, bool bClamp) +{ + Vector vRet; + ComputeLighting( pos, NULL, bClamp, vRet, NULL ); + return vRet; +} + +Vector CEngineClient::GetLightForPointFast(const Vector &pos, bool bClamp) +{ + Vector vRet; + int leafIndex = CM_PointLeafnum(pos); + vRet.Init(); + Vector cube[6]; + Mod_LeafAmbientColorAtPos( cube, pos, leafIndex ); + for ( int i = 0; i < 6; i++ ) + { + vRet.x = fpmax(vRet.x, cube[i].x ); + vRet.y = fpmax(vRet.y, cube[i].y ); + vRet.z = fpmax(vRet.z, cube[i].z ); + } + if ( bClamp ) + { + if ( vRet.x > 1.0f ) + vRet.x = 1.0f; + if ( vRet.y > 1.0f ) + vRet.y = 1.0f; + if ( vRet.z > 1.0f ) + vRet.z = 1.0f; + } + return vRet; +} + +const char *CEngineClient::ParseFile( const char *data, char *token, int maxlen ) +{ + return ::COM_ParseFile( data, token, maxlen ); +} + +bool CEngineClient::CopyLocalFile( const char *source, const char *destination ) +{ + return ::COM_CopyFile( source, destination ); +} + +void CEngineClient::GetScreenSize( int& w, int &h ) +{ + CMatRenderContextPtr pRenderContext( materials ); + pRenderContext->GetWindowSize( w, h ); +} + +void CEngineClient::ServerCmd( const char *szCmdString, bool bReliable ) +{ + // info handling + char buf[255]; + Q_snprintf( buf, sizeof( buf ), "cmd %s", szCmdString ); + + CCommand args; + args.Tokenize( buf ); + Cmd_ForwardToServer( args, bReliable ); +} + +void CEngineClient::ClientCmd( const char *szCmdString ) +{ + // Check that we can add the two execution markers + if ( cl.m_bRestrictClientCommands && !Cbuf_HasRoomForExecutionMarkers( 2 ) ) + { + AssertMsg( false, "CEngineClient::ClientCmd called but there is no room for the execution markers. Ignoring command." ); + return; + } + + // Only let them run commands marked with FCVAR_CLIENTCMD_CAN_EXECUTE. + if ( cl.m_bRestrictClientCommands ) + Cbuf_AddTextWithMarkers( eCmdExecutionMarker_Enable_FCVAR_CLIENTCMD_CAN_EXECUTE, szCmdString, eCmdExecutionMarker_Disable_FCVAR_CLIENTCMD_CAN_EXECUTE ); + else + Cbuf_AddText( szCmdString ); +} + +void CEngineClient::ClientCmd_Unrestricted( const char *szCmdString ) +{ + Cbuf_AddText( szCmdString ); +} + +void CEngineClient::SetRestrictServerCommands( bool bRestrict ) +{ + cl.m_bRestrictServerCommands = bRestrict; +} + +void CEngineClient::SetRestrictClientCommands( bool bRestrict ) +{ + cl.m_bRestrictClientCommands = bRestrict; +} + +void CEngineClient::ExecuteClientCmd( const char *szCmdString ) +{ + Cbuf_AddText( szCmdString ); + Cbuf_Execute(); +} + +bool CEngineClient::GetPlayerInfo( int ent_num, player_info_t *pinfo ) +{ + ent_num--; // player list if offset by 1 from ents + + if ( ent_num >= cl.m_nMaxClients || ent_num < 0 ) + { + Q_memset( pinfo, 0, sizeof( player_info_t ) ); + return false; + } + + Assert( cl.m_pUserInfoTable ); + if ( !cl.m_pUserInfoTable ) + { + Q_memset( pinfo, 0, sizeof( player_info_t ) ); + return false; + } + + Assert( ent_num < cl.m_pUserInfoTable->GetNumStrings() ); + if ( ent_num >= cl.m_pUserInfoTable->GetNumStrings() ) + { + Q_memset( pinfo, 0, sizeof( player_info_t ) ); + return false; + } + + int cubPlayerInfo; + player_info_t *pi = (player_info_t*) cl.m_pUserInfoTable->GetStringUserData( ent_num, &cubPlayerInfo ); + + if ( !pi || cubPlayerInfo < sizeof( player_info_t ) ) + { + Q_memset( pinfo, 0, sizeof( player_info_t ) ); + return false; + } + + Q_memcpy( pinfo, pi, sizeof( player_info_t ) ); + + // Fixup from network order (little endian) + CByteswap byteswap; + byteswap.SetTargetBigEndian( false ); + byteswap.SwapFieldsToTargetEndian( pinfo ); + + return true; +} + +client_textmessage_t *CEngineClient::TextMessageGet( const char *pName ) +{ + return ::TextMessageGet( pName ); +} + +bool CEngineClient::Con_IsVisible( void ) +{ + return ::Con_IsVisible(); +} + +int CEngineClient::GetLocalPlayer( void ) +{ + return cl.m_nPlayerSlot + 1; +} + +float CEngineClient::GetLastTimeStamp( void ) +{ + return cl.m_flLastServerTickTime; +} + +bool CEngineClient::MapHasHDRLighting( void) +{ + return modelloader->LastLoadedMapHasHDRLighting(); +} + +const model_t *CEngineClient::LoadModel( const char *pName, bool bProp ) +{ + return modelloader->GetModelForName( pName, bProp ? IModelLoader::FMODELLOADER_DETAILPROP : IModelLoader::FMODELLOADER_CLIENTDLL ); +} + +CSentence *CEngineClient::GetSentence( CAudioSource *pAudioSource ) +{ + if (pAudioSource) + { + return pAudioSource->GetSentence(); + } + return NULL; +} + +void AddPhonemesFromFile( const char *pszFileName ); + +void CEngineClient::AddPhonemeFile( const char *pszPhonemeFile ) +{ + AddPhonemesFromFile( pszPhonemeFile ); +} + +float CEngineClient::GetSentenceLength( CAudioSource *pAudioSource ) +{ + if (pAudioSource && pAudioSource->SampleRate() > 0 ) + { + float length = (float)pAudioSource->SampleCount() / (float)pAudioSource->SampleRate(); + return length; + } + return 0.0f; +} + +bool CEngineClient::IsStreaming( CAudioSource *pAudioSource ) const +{ + if ( pAudioSource ) + { + return pAudioSource->IsStreaming(); + } + return false; +} + +// FIXME, move entirely to client .dll +void CEngineClient::GetViewAngles( QAngle& va ) +{ + VectorCopy( cl.viewangles, va ); +} + +void CEngineClient::SetViewAngles( QAngle& va ) +{ + cl.viewangles.x = AngleNormalize( va.x ); + cl.viewangles.y = AngleNormalize( va.y ); + cl.viewangles.z = AngleNormalize( va.z ); + Assert( !IS_NAN(cl.viewangles.x ) ); + Assert( !IS_NAN(cl.viewangles.y ) ); + Assert( !IS_NAN(cl.viewangles.z ) ); +} + +int CEngineClient::GetMaxClients( void ) +{ + return cl.m_nMaxClients; +} + +void CEngineClient::SetMapLoadFailed( bool bState ) +{ + g_ServerGlobalVariables.bMapLoadFailed = bState; +} + +bool CEngineClient::MapLoadFailed( void ) +{ + return g_ServerGlobalVariables.bMapLoadFailed; +} + +void CEngineClient::ReadConfiguration( const bool readDefault /*= false*/ ) +{ + Host_ReadConfiguration(); +} + +const char *CEngineClient::Key_LookupBinding( const char *pBinding ) +{ + return ::Key_NameForBinding( pBinding ); +} + +const char *CEngineClient::Key_LookupBindingExact( const char *pBinding ) +{ + return ::Key_NameForBindingExact( pBinding ); +} + +const char *CEngineClient::Key_BindingForKey( ButtonCode_t code ) +{ + return ::Key_BindingForKey( code ); +} + +void CEngineClient::StartKeyTrapMode( void ) +{ + Key_StartTrapMode(); +} + +bool CEngineClient::CheckDoneKeyTrapping( ButtonCode_t &code ) +{ + return Key_CheckDoneTrapping( code ); +} + +bool CEngineClient::IsInGame( void ) +{ + return cl.IsActive(); +} + +bool CEngineClient::IsConnected( void ) +{ + return cl.IsConnected(); +} + +bool CEngineClient::IsDrawingLoadingImage( void ) +{ + return scr_drawloading; +} + +void CEngineClient::Con_NPrintf( int pos, const char *fmt, ... ) +{ + va_list argptr; + char text[4096]; + va_start (argptr, fmt); + Q_vsnprintf(text, sizeof( text ), fmt, argptr); + va_end (argptr); + + ::Con_NPrintf( pos, "%s", text ); +} + +void CEngineClient::Con_NXPrintf( const struct con_nprint_s *info, const char *fmt, ... ) +{ + va_list argptr; + char text[4096]; + va_start (argptr, fmt); + Q_vsnprintf(text, sizeof( text ), fmt, argptr); + va_end (argptr); + + ::Con_NXPrintf( info, "%s", text ); +} + +IMaterial *CEngineClient::TraceLineMaterialAndLighting( const Vector &start, const Vector &end, + Vector &diffuseLightColor, Vector &baseColor ) +{ + return BrushModel_GetLightingAndMaterial( start, end, diffuseLightColor, baseColor ); +} + +int CEngineClient::IsBoxVisible( const Vector& mins, const Vector& maxs ) +{ + return CM_BoxVisible( mins, maxs, Map_VisCurrent(), CM_ClusterPVSSize() ); +} + +int CEngineClient::IsBoxInViewCluster( const Vector& mins, const Vector& maxs ) +{ + // See comments in Map_VisCurrentCluster for why we might get a negative number. + int curCluster = Map_VisCurrentCluster(); + if ( curCluster < 0 ) + return false; + + byte pvs[MAX_MAP_LEAFS/8]; + const byte *ppvs = CM_Vis( pvs, sizeof(pvs), curCluster, DVIS_PVS ); + return CM_BoxVisible(mins, maxs, ppvs, sizeof(pvs) ); +} + +float CEngineClient::Time() +{ + return Sys_FloatTime(); +} + +void CEngineClient::Sound_ExtraUpdate( void ) +{ + // On xbox this is not necessary except for long pauses, so unhook this one + if ( IsX360() ) + return; + + VPROF_BUDGET( "CEngineClient::Sound_ExtraUpdate()", VPROF_BUDGETGROUP_OTHER_SOUND ); + + S_ExtraUpdate(); +} + +bool CEngineClient::CullBox ( const Vector& mins, const Vector& maxs ) +{ + return R_CullBoxSkipNear( mins, maxs, g_Frustum ); +} + +const char *CEngineClient::GetGameDirectory( void ) +{ + return com_gamedir; +} + +const VMatrix& CEngineClient::WorldToScreenMatrix() +{ + // FIXME: this is only valid if we're currently rendering. If not, it should use the player, or it really should pass one in. + return g_EngineRenderer->WorldToScreenMatrix(); +} + +const VMatrix& CEngineClient::WorldToViewMatrix() +{ + // FIXME: this is only valid if we're currently rendering. If not, it should use the player, or it really should pass one in. + return g_EngineRenderer->ViewMatrix(); +} + +// Loads a game lump off disk +int CEngineClient::GameLumpVersion( int lumpId ) const +{ + return Mod_GameLumpVersion( lumpId ); +} + +int CEngineClient::GameLumpSize( int lumpId ) const +{ + return Mod_GameLumpSize( lumpId ); +} + +bool CEngineClient::LoadGameLump( int lumpId, void* pBuffer, int size ) +{ + return Mod_LoadGameLump( lumpId, pBuffer, size ); +} + +// Returns the number of leaves in the level +int CEngineClient::LevelLeafCount() const +{ + return host_state.worldbrush->numleafs; +} + +ISpatialQuery* CEngineClient::GetBSPTreeQuery() +{ + return g_pToolBSPTree; +} + +// Convert texlight to gamma... +void CEngineClient::LinearToGamma( float* linear, float* gamma ) +{ + gamma[0] = LinearToTexture( linear[0] ) / 255.0f; + gamma[1] = LinearToTexture( linear[1] ) / 255.0f; + gamma[2] = LinearToTexture( linear[2] ) / 255.0f; +} + +// Get the lightstyle value +float CEngineClient::LightStyleValue( int style ) +{ + return ::LightStyleValue( style ); +} + + +void CEngineClient::DrawPortals() +{ + R_DrawPortals(); +} + +// Computes light due to dynamic lighting at a point +// If the normal isn't specified, then it'll return the maximum lighting +void CEngineClient::ComputeDynamicLighting( Vector const& pt, Vector const* pNormal, Vector& color ) +{ + ::ComputeDynamicLighting( pt, pNormal, color ); +} + +// Computes light due to dynamic lighting at a point +// If the normal isn't specified, then it'll return the maximum lighting +void CEngineClient::ComputeLighting( const Vector& pt, const Vector* pNormal, bool bClamp, Vector& color, Vector *pBoxColors ) +{ + ::ComputeLighting( pt, pNormal, bClamp, color, pBoxColors ); +} + +// Returns the color of the ambient light +void CEngineClient::GetAmbientLightColor( Vector& color ) +{ + dworldlight_t* pWorldLight = FindAmbientLight(); + if (!pWorldLight) + color.Init( 0, 0, 0 ); + else + VectorCopy( pWorldLight->intensity, color ); +} + +// Returns the dx support level +int CEngineClient::GetDXSupportLevel() +{ + return g_pMaterialSystemHardwareConfig->GetDXSupportLevel(); +} + +bool CEngineClient::SupportsHDR() +{ + // deprecated. +// Assert( 0 ); + return false; +} + +void CEngineClient::Mat_Stub( IMaterialSystem *pMatSys ) +{ + materials = pMatSys; + + // Pass the call to the model renderer. + if ( g_pStudioRender ) + g_pStudioRender->Mat_Stub( pMatSys ); +} + +void CEngineClient::GetChapterName( char *pchBuff, int iMaxLength ) +{ + serverGameDLL->GetSaveComment( pchBuff, iMaxLength, 0.0f, 0.0f, true ); +} + +char const *CEngineClient::GetLevelName( void ) +{ + if ( sv.IsDedicated() ) + { + return "Dedicated Server"; + } + else if ( !cl.IsConnected() ) + { + return ""; + } + + return cl.m_szLevelFileName; +} + +int CEngineClient::GetLevelVersion( void ) +{ + return g_ServerGlobalVariables.mapversion; +} + +bool CEngineClient::IsLevelMainMenuBackground( void ) +{ + return sv.IsLevelMainMenuBackground(); +} + +void CEngineClient::GetMainMenuBackgroundName( char *dest, int destlen ) +{ + CL_GetBackgroundLevelName( dest, destlen, false ); +} + +// Occlusion system control +void CEngineClient::SetOcclusionParameters( const OcclusionParams_t ¶ms ) +{ + OcclusionSystem()->SetOcclusionParameters( params.m_flMaxOccludeeArea, params.m_flMinOccluderArea ); +} + +//----------------------------------------------------------------------------- +// Purpose: Takes a trackerID and returns which player slot that user is in +// returns 0 if no player found with that ID +//----------------------------------------------------------------------------- +int CEngineClient::GetPlayerForUserID(int userID) +{ + if ( !cl.m_pUserInfoTable ) + return 0; + + // We are occasionally getting crashes here where it looks like cl.m_nMaxClients + // is larger than the number of items in cl.m_pUserInfoTable. Callstack: + // engine.dll CEngineClient::GetPlayerForUserID + // client.dll CTFHudDeathNotice::OnGameEvent + // client.dll CHudBaseDeathNotice::FireGameEvent + // client.dll CTFHudDeathNotice::FireGameEvent + // engine.dll CGameEventManager::FireEventIntern + // engine.dll CGameEventManager::FireEventClientSide + // engine.dll CClientState::ProcessGameEvent + // So add check to make sure we don't go over m_pUserInfoTable size. + int nMaxClients = Min( cl.m_nMaxClients, cl.m_pUserInfoTable->GetNumStrings() ); + for ( int i = 0; i < nMaxClients; i++ ) + { + player_info_t *pi = (player_info_t*) cl.m_pUserInfoTable->GetStringUserData( i, NULL ); + + if ( !pi ) + continue; + + // Fixup from network order (little endian) + if ( LittleLong( pi->userID ) == userID ) + { + // return as entity index + return (i+1); + } + } + + return 0; +} + +#if !defined( NO_VOICE ) +struct IVoiceTweak_s *CEngineClient::GetVoiceTweakAPI( void ) +{ + return &g_VoiceTweakAPI; +} +#endif + +void CEngineClient::EngineStats_BeginFrame( void ) +{ + g_EngineStats.BeginFrame(); +} + +void CEngineClient::EngineStats_EndFrame( void ) +{ + g_EngineStats.EndFrame(); +} + +void CEngineClient::FireEvents() +{ + // Run any events queued up for this frame + CL_FireEvents(); +} + +void CEngineClient::CheckPoint( const char *pName ) +{ + GetTestScriptMgr()->CheckPoint( pName ); +} + +int CEngineClient::GetLeavesArea( int *pLeaves, int nLeaves ) +{ + if ( nLeaves == 0 ) + return -1; + + int iArea = host_state.worldbrush->leafs[pLeaves[0]].area; + for ( int i=1; i < nLeaves; i++ ) + { + int iTestArea = host_state.worldbrush->leafs[pLeaves[i]].area; + if ( iTestArea != iArea ) + return -1; + } + + return iArea; +} + +bool CEngineClient::DoesBoxTouchAreaFrustum( const Vector &mins, const Vector &maxs, int iArea ) +{ + const Frustum_t *pFrustum = GetAreaFrustum( iArea ); + return !R_CullBoxSkipNear( mins, maxs, *pFrustum ); +} + +//----------------------------------------------------------------------------- +// Sets the hearing origin +//----------------------------------------------------------------------------- +void CEngineClient::SetAudioState( const AudioState_t &audioState ) +{ + Host_SetAudioState( audioState ); +} + + +//----------------------------------------------------------------------------- +// +// Sentence API +// +//----------------------------------------------------------------------------- + +int CEngineClient::SentenceGroupPick( int groupIndex, char *name, int nameLen ) +{ + return VOX_GroupPick( groupIndex, name, nameLen ); +} + + +int CEngineClient::SentenceGroupPickSequential( int groupIndex, char *name, int nameLen, int sentenceIndex, int reset ) +{ + return VOX_GroupPickSequential( groupIndex, name, nameLen, sentenceIndex, reset ); +} + +int CEngineClient::SentenceIndexFromName( const char *pSentenceName ) +{ + int sentenceIndex = -1; + + VOX_LookupString( pSentenceName, &sentenceIndex ); + + return sentenceIndex; +} + +const char *CEngineClient::SentenceNameFromIndex( int sentenceIndex ) +{ + return VOX_SentenceNameFromIndex( sentenceIndex ); +} + + +int CEngineClient::SentenceGroupIndexFromName( const char *pGroupName ) +{ + return VOX_GroupIndexFromName( pGroupName ); +} + +const char *CEngineClient::SentenceGroupNameFromIndex( int groupIndex ) +{ + return VOX_GroupNameFromIndex( groupIndex ); +} + + +float CEngineClient::SentenceLength( int sentenceIndex ) +{ + return VOX_SentenceLength( sentenceIndex ); +} + +void CEngineClient::DebugDrawPhysCollide( const CPhysCollide *pCollide, IMaterial *pMaterial, matrix3x4_t& transform, const color32 &color ) +{ + ::DebugDrawPhysCollide( pCollide, pMaterial, transform, color, false ); +} + +// Activates/deactivates an occluder... +void CEngineClient::ActivateOccluder( int nOccluderIndex, bool bActive ) +{ + OcclusionSystem()->ActivateOccluder( nOccluderIndex, bActive ); +} + +bool CEngineClient::IsOccluded( const Vector &vecAbsMins, const Vector &vecAbsMaxs ) +{ + return OcclusionSystem()->IsOccluded( vecAbsMins, vecAbsMaxs ); +} + +void *CEngineClient::SaveAllocMemory( size_t num, size_t size ) +{ + return ::SaveAllocMemory( num, size ); +} + +void CEngineClient::SaveFreeMemory( void *pSaveMem ) +{ + ::SaveFreeMemory( pSaveMem ); +} + +INetChannelInfo *CEngineClient::GetNetChannelInfo( void ) +{ + return (INetChannelInfo*)cl.m_NetChannel; +} + +bool CEngineClient::IsPlayingDemo( void ) +{ + return demoplayer->IsPlayingBack(); +} + +bool CEngineClient::IsRecordingDemo( void ) +{ + return demorecorder->IsRecording(); +} + +bool CEngineClient::IsPlayingTimeDemo( void ) +{ + return demoplayer->IsPlayingTimeDemo(); +} + +bool CEngineClient::IsPaused( void ) +{ + return cl.IsPaused(); +} + +bool CEngineClient::IsTakingScreenshot( void ) +{ + return cl_takesnapshot; +} + +int CEngineClient::GetDemoRecordingTick( void ) +{ + return demorecorder->GetRecordingTick(); +} + +int CEngineClient::GetDemoPlaybackTick( void ) +{ + return demoplayer->GetPlaybackTick(); +} + +int CEngineClient::GetDemoPlaybackStartTick( void ) +{ + return demoplayer->GetPlaybackStartTick(); +} + +float CEngineClient::GetDemoPlaybackTimeScale( void ) +{ + return demoplayer->GetPlaybackTimeScale(); +} + +int CEngineClient::GetDemoPlaybackTotalTicks( void ) +{ + return demoplayer->GetTotalTicks(); +} + +bool CEngineClient::IsHLTV( void ) +{ + return cl.ishltv; +} + +void CEngineClient::GetVideoModes( int &nCount, vmode_s *&pModes ) +{ + nCount = videomode->GetModeCount(); + pModes = videomode->GetMode( 0 ); +} + +void CEngineClient::GetUILanguage( char *dest, int destlen ) +{ + const char *pStr = cl_language.GetString(); + if ( pStr ) + { + V_strncpy( dest, pStr, destlen ); + } + else if ( IsX360() ) + { + dest[0] = 0; + } +} + +//----------------------------------------------------------------------------- +// Can skybox be seen from a particular point? +//----------------------------------------------------------------------------- +SkyboxVisibility_t CEngineClient::IsSkyboxVisibleFromPoint( const Vector &vecPoint ) +{ + // In the mat_fullbright 1 case, it's always visible + // (we may have no lighting in the level, and vrad is where LEAF_FLAGS_SKY is computed) + if ( g_pMaterialSystemConfig->nFullbright == 1 ) + return SKYBOX_3DSKYBOX_VISIBLE; + + int nLeaf = CM_PointLeafnum( vecPoint ); + int nFlags = GetCollisionBSPData()->map_leafs[nLeaf].flags; + if ( nFlags & LEAF_FLAGS_SKY ) + return SKYBOX_3DSKYBOX_VISIBLE; + return ( nFlags & LEAF_FLAGS_SKY2D ) ? SKYBOX_2DSKYBOX_VISIBLE : SKYBOX_NOT_VISIBLE; +} + +const char* CEngineClient::GetMapEntitiesString() +{ + return CM_EntityString(); +} + +bool CEngineClient::IsInEditMode( void ) +{ + return g_bInEditMode; +} + +bool CEngineClient::IsInCommentaryMode( void ) +{ + return g_bInCommentaryMode; +} + +float CEngineClient::GetScreenAspectRatio() +{ + return GetScreenAspect( ); +} + +int CEngineClient::GetAppID() +{ + return GetSteamAppID(); +} + +void CEngineClient::SetOverlayBindProxy( int iOverlayID, void *pBindProxy ) +{ + OverlayMgr()->SetOverlayBindProxy( iOverlayID, pBindProxy ); +} + +void CEngineClient::ChangeTeam( const char *pTeamName ) +{ + g_pMatchmaking->ChangeTeam( pTeamName ); +} + +//----------------------------------------------------------------------------- +// Returns true if copy occured +//----------------------------------------------------------------------------- +bool CEngineClient::CopyFrameBufferToMaterial( const char *pMaterialName ) +{ + if ( !IsX360() ) + { + // not for PC + Assert( 0 ); + return false; + } + + IMaterial *pMaterial = materials->FindMaterial( pMaterialName, TEXTURE_GROUP_OTHER ); + if ( pMaterial->IsErrorMaterial() ) + { + // unknown material + return false; + } + + bool bFound; + IMaterialVar *pMaterialVar = pMaterial->FindVar( "$baseTexture", &bFound, false ); + if ( !bFound || pMaterialVar->GetType() != MATERIAL_VAR_TYPE_TEXTURE ) + { + // lack of expected $basetexture + return false; + } + + ITexture *pTexture = pMaterialVar->GetTextureValue(); + if ( !pTexture || !pTexture->IsRenderTarget() ) + { + // base texture is not a render target + return false; + } + + CMatRenderContextPtr pRenderContext( materials ); + + int width, height; + pRenderContext->GetRenderTargetDimensions( width, height ); + if ( width != pTexture->GetActualWidth() || height != pTexture->GetActualHeight() ) + { + // better be matched, not supporting a disparate blit in this context + // disparate blit may very well use same RT we are trying to copy into + return false; + } + + pRenderContext->CopyRenderTargetToTexture( pTexture ); + return true; +} + + +//----------------------------------------------------------------------------- +// Used by the color correction UI +//----------------------------------------------------------------------------- +void CEngineClient::GrabPreColorCorrectedFrame( int x, int y, int width, int height ) +{ + colorcorrectiontools->GrabPreColorCorrectedFrame( x, y, width, height ); +} + +//----------------------------------------------------------------------------- +// Is hammer running? +//----------------------------------------------------------------------------- +bool CEngineClient::IsHammerRunning( ) const +{ + return IsPC() ? InEditMode() : false; +} + +extern IAchievementMgr *g_pAchievementMgr; + +//----------------------------------------------------------------------------- +// Sets achievement mgr +//----------------------------------------------------------------------------- +void CEngineClient::SetAchievementMgr( IAchievementMgr *pAchievementMgr ) +{ + g_pAchievementMgr = pAchievementMgr; +} + +//----------------------------------------------------------------------------- +// Gets achievement mgr +//----------------------------------------------------------------------------- +IAchievementMgr *CEngineClient::GetAchievementMgr() +{ + return g_pAchievementMgr; +} + + +//----------------------------------------------------------------------------- +// Called by the client to determine violence settings for things like ragdoll +// fading. +//----------------------------------------------------------------------------- +bool CEngineClient::IsLowViolence() +{ + return g_bLowViolence; +} + +const char *CEngineClient::GetMostRecentSaveGame( void ) +{ + return saverestore->GetMostRecentlyLoadedFileName(); +} + +void CEngineClient::SetMostRecentSaveGame( const char *lpszFilename ) +{ + saverestore->SetMostRecentSaveGame( lpszFilename ); +} + +//----------------------------------------------------------------------------- +// Called by gameui to hint the engine that an exiting process has started. +// The Engine needs to stabilize to a safe quiet state. More frames are going +// to and have to run, but the true exit will occur. +//----------------------------------------------------------------------------- +void CEngineClient::StartXboxExitingProcess() +{ + if ( IsPC() ) + { + // not for PC + return; + } + + g_pInputSystem->StopRumble(); + + // save out the achievements + g_pAchievementMgr->SaveGlobalStateIfDirty( false ); + + S_StopAllSounds( true ); + + // Shutdown QMS, need to go back to single threaded + Host_AllowQueuedMaterialSystem( false ); +} + +bool CEngineClient::IsSaveInProgress() +{ + return saverestore->IsSaveInProgress(); +} + +extern IXboxSystem *g_pXboxSystem; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +uint CEngineClient::OnStorageDeviceAttached( void ) +{ + return g_pXboxSystem->OpenContainers(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CEngineClient::OnStorageDeviceDetached( void ) +{ + XBX_SetStorageDeviceId( XBX_INVALID_STORAGE_ID ); + g_pXboxSystem->CloseContainers(); +} + +void CEngineClient::ResetDemoInterpolation( void ) +{ + if( demorecorder->IsRecording() ) + demorecorder->ResetDemoInterpolation(); + if (demoplayer->IsPlayingBack() ) + demoplayer->ResetDemoInterpolation(); +} + + +extern CGamestatsData *g_pGamestatsData; +void CEngineClient::SetGamestatsData( CGamestatsData *pGamestatsData ) +{ + g_pGamestatsData = pGamestatsData; +} + +CGamestatsData *CEngineClient::GetGamestatsData() +{ + return g_pGamestatsData; +} + +//----------------------------------------------------------------------------- + +#if defined( USE_SDL ) + +void CEngineClient::GetMouseDelta( int &x, int &y, bool bIgnoreNextMouseDelta ) +{ + g_pLauncherMgr->GetMouseDelta( x, y, bIgnoreNextMouseDelta ); +} + +#endif + + +void CEngineClient::ServerCmdKeyValues( KeyValues *pKeyValues ) +{ + cl.SendServerCmdKeyValues( pKeyValues ); +} + +bool CEngineClient::IsSkippingPlayback( void ) +{ + return demoplayer->IsSkipping(); +} + +bool CEngineClient::IsLoadingDemo( void ) +{ + return demoplayer->IsLoading(); +} + +bool CEngineClient::IsPlayingDemoALocallyRecordedDemo() +{ + return IsPlayingDemo() && + demoplayer && + demoplayer->GetDemoFile() && + !V_strnicmp( demoplayer->GetDemoFile()->m_DemoHeader.servername, "localhost", 9 ); +} + +uint CEngineClient::GetProtocolVersion() +{ + if ( demoplayer && demoplayer->IsPlayingBack() ) + { + return demoplayer->GetProtocolVersion(); + } + return PROTOCOL_VERSION; +} + +bool CEngineClient::IsWindowedMode() +{ + return videomode->IsWindowedMode(); +} + +int CEngineClient::GetClientVersion() const +{ + return GetSteamInfIDVersionInfo().ClientVersion; +} + +bool CEngineClient::IsActiveApp( void ) +{ + return game->IsActiveApp(); +} + +//----------------------------------------------------------------------------- +// Previously ConCommand disconnect +//----------------------------------------------------------------------------- +void CEngineClient::DisconnectInternal( void ) +{ + Disconnect(); +} + +//----------------------------------------------------------------------------- +// The client DLL serves out this interface +//----------------------------------------------------------------------------- +IBaseClientDLL *g_ClientDLL = NULL; +IClientVirtualReality *g_pClientVR = NULL; +IPrediction *g_pClientSidePrediction = NULL; +IClientRenderTargets *g_pClientRenderTargets = NULL; +IClientEntityList *entitylist = NULL; +ICenterPrint *centerprint = NULL; +IClientLeafSystemEngine *clientleafsystem = NULL; +bool g_bClientLeafSystemV1; +ClientClass *g_pClientClassHead = NULL; +IClientReplay *g_pClientReplay = NULL; + +ClientClass *ClientDLL_GetAllClasses( void ) +{ + if ( g_ClientDLL ) + return g_ClientDLL->GetAllClasses(); + else + return g_pClientClassHead; +} + +static void ClientDLL_InitRecvTableMgr() +{ + // Register all the receive tables. + RecvTable *pRecvTables[MAX_DATATABLES]; + int nRecvTables = 0; + for ( ClientClass *pCur = ClientDLL_GetAllClasses(); pCur; pCur=pCur->m_pNext ) + { + ErrorIfNot( + nRecvTables < ARRAYSIZE( pRecvTables ), + ("ClientDLL_InitRecvTableMgr: overflowed MAX_DATATABLES") + ); + + pRecvTables[nRecvTables] = pCur->m_pRecvTable; + ++nRecvTables; + } + + RecvTable_Init( pRecvTables, nRecvTables ); +} + + +static void ClientDLL_ShutdownRecvTableMgr() +{ + RecvTable_Term(); +} + +CreateInterfaceFn ClientDLL_GetFactory( void ) +{ + return g_ClientFactory; +} + +//----------------------------------------------------------------------------- +// Purpose: Loads the client DLL +// Input : - +//----------------------------------------------------------------------------- +bool ClientDLL_Load() +{ + Assert ( !g_ClientDLLModule ); + + // Check the signature on the client dll. If this fails we load it anyway but put this client + // into insecure mode so it won't connect to secure servers and get VAC banned + if ( !Host_AllowLoadModule( "client.dll", "GAMEBIN", true ) ) + { + // not supposed to load this but we will anyway + Host_DisallowSecureServers(); + Host_AllowLoadModule( "client.dll","GAMEBIN", true ); + } + + g_ClientDLLModule = g_pFileSystem->LoadModule( "client", "GAMEBIN", false ); + if ( g_ClientDLLModule ) + { + g_ClientFactory = Sys_GetFactory( g_ClientDLLModule ); + if ( g_ClientFactory ) + { + g_ClientDLL = (IBaseClientDLL *)g_ClientFactory( CLIENT_DLL_INTERFACE_VERSION, NULL ); + // this is to ensure the old format of the string table is used for clients version 13 and older. + // when the client version gets revved, there will need to be an else that sets this bool to true + g_bClientGameDLLGreaterThanV13 = false; + if ( !g_ClientDLL ) + { + Sys_Error( "Could not get client.dll interface from library client" ); + } + + if( g_pSourceVR ) + { + g_pClientVR = (IClientVirtualReality *)g_ClientFactory( CLIENTVIRTUALREALITY_INTERFACE_VERSION, NULL ); + if( !g_pClientVR ) + { + Msg( "client.dll is not VR-compatible.\n" ); + } + } + } + else + { + Sys_Error( "Could not find factory interface in library client" ); + } + } + else + { + // tell Steam to do a quick verify of the install. Sys_Error doesn't return, so do this first. + if( Steam3Client().SteamApps() ) + Steam3Client().SteamApps()->MarkContentCorrupt( true ); + + // library failed to load + Sys_Error( "Could not load library client. Try restarting. If that doesn't work, verify the cache." ); + } + + // Load the client render targets interface from the client .dll + // NOTE: Its OK if this returns NULL, as some mods won't provide the interface and will just use the default behavior of the engine + g_pClientRenderTargets = (IClientRenderTargets *)g_ClientFactory( CLIENTRENDERTARGETS_INTERFACE_VERSION, NULL ); + + return true; +} + +void InitExtraClientCmdCanExecuteVars() +{ + // This can go away when we ship a client DLL with the FCVAR_CLIENTCMD_CAN_EXECUTE flag set on these cvars/concommands. + Cmd_AddClientCmdCanExecuteVar( "cancelselect" ); + Cmd_AddClientCmdCanExecuteVar( "menuselect" ); + Cmd_AddClientCmdCanExecuteVar( "playgamesound" ); + Cmd_AddClientCmdCanExecuteVar( "_cl_classmenuopen" ); + Cmd_AddClientCmdCanExecuteVar( "cl_buy_favorite" ); + Cmd_AddClientCmdCanExecuteVar( "voice_modenable" ); + Cmd_AddClientCmdCanExecuteVar( "togglescores" ); + + Cmd_AddClientCmdCanExecuteVar( "spec_next" ); + Cmd_AddClientCmdCanExecuteVar( "spec_prev" ); + Cmd_AddClientCmdCanExecuteVar( "spec_mode" ); + Cmd_AddClientCmdCanExecuteVar( "spec_menu" ); + Cmd_AddClientCmdCanExecuteVar( "spec_autodirector" ); + Cmd_AddClientCmdCanExecuteVar( "overview_zoom" ); + Cmd_AddClientCmdCanExecuteVar( "overview_mode" ); + Cmd_AddClientCmdCanExecuteVar( "overview_health" ); + Cmd_AddClientCmdCanExecuteVar( "overview_names" ); + Cmd_AddClientCmdCanExecuteVar( "overview_tracks" ); + Cmd_AddClientCmdCanExecuteVar( "overview_locked" ); + Cmd_AddClientCmdCanExecuteVar( "overview_alpha" ); + + Cmd_AddClientCmdCanExecuteVar( "playgamesound" ); +} + +//----------------------------------------------------------------------------- +// Purpose: Inits the client .dll +//----------------------------------------------------------------------------- +void ClientDLL_Init( void ) +{ + extern void CL_SetSteamCrashComment(); + + // Assert ClientDLL_Load successfully created these interfaces, as we need them to init properly + Assert ( g_ClientDLL ); + Assert ( g_ClientFactory ); + + // this will get updated after we load a map, but this gets video info if we sys_error() prior to loading a map + CL_SetSteamCrashComment(); + + if ( g_ClientDLL ) + { + COM_TimestampedLog( "g_ClientDLL->Init" ); + + if ( !g_ClientDLL->Init(g_AppSystemFactory, g_AppSystemFactory, &g_ClientGlobalVariables ) ) + { + Sys_Error("Client.dll Init() in library client failed."); + } + + if ( g_ClientFactory ) + { + COM_TimestampedLog( "g_pClientSidePrediction->Init" ); + + // Load the prediction interface from the client .dll + g_pClientSidePrediction = (IPrediction *)g_ClientFactory( VCLIENT_PREDICTION_INTERFACE_VERSION, NULL ); + if ( !g_pClientSidePrediction ) + { + Sys_Error( "Could not get IPrediction interface from library client" ); + } + g_pClientSidePrediction->Init(); + + entitylist = ( IClientEntityList *)g_ClientFactory( VCLIENTENTITYLIST_INTERFACE_VERSION, NULL ); + if ( !entitylist ) + { + Sys_Error( "Could not get client entity list interface from library client" ); + } + + centerprint = ( ICenterPrint * )g_ClientFactory( VCENTERPRINT_INTERFACE_VERSION, NULL ); + if ( !centerprint ) + { + Sys_Error( "Could not get centerprint interface from library client" ); + } + + clientleafsystem = ( IClientLeafSystemEngine *)g_ClientFactory( CLIENTLEAFSYSTEM_INTERFACE_VERSION, NULL ); + if ( clientleafsystem ) + { + g_bClientLeafSystemV1 = false; + } + else if ( !clientleafsystem ) + { + clientleafsystem = ( IClientLeafSystemEngine *)g_ClientFactory( CLIENTLEAFSYSTEM_INTERFACE_VERSION_1, NULL ); + if ( !clientleafsystem ) + { + Sys_Error( "Could not get client leaf system interface from library client" ); + } + else + { + g_bClientLeafSystemV1 = true; + } + } + +#if defined( REPLAY_ENABLED ) + if ( Replay_IsSupportedModAndPlatform() ) + { + // Replay dll should be loaded by this point + if ( !g_pReplay ) + { + Sys_Error( "Replay.dll was not loaded" ); + } + + // Get pointer to client-side replay interface implementation + g_pClientReplay = (IClientReplay *)g_ClientFactory( CLIENT_REPLAY_INTERFACE_VERSION, NULL ); + if ( !g_pClientReplay ) + { + Sys_Error( "Could not get the replay interface from library client" ); + } + + // Allow the client dll to setup pointers to replay interfaces + extern CreateInterfaceFn g_fnReplayFactory; + if ( !g_ClientDLL->ReplayInit( g_fnReplayFactory ) ) + { + Sys_Error( "Client ReplayInit() failed!" ); + } + + // Allow the replay dll to setup pointers to client interfaces + if ( !g_pReplay->CL_Init( g_ClientFactory ) ) + { + Sys_Error( "Replay system ClientInit() failed" ); + } + + if ( !g_ClientDLL->ReplayPostInit() ) + { + Sys_Error( "Client ReplayPostInit() failed!" ); + } + +#if !defined( DEDICATED ) + extern CGameServer sv; + if ( !sv.IsDedicated() ) + { + g_pClientReplayContext = g_pReplay->CL_GetContext(); + g_pReplayManager = g_pClientReplayContext->GetReplayManager(); + g_pReplayMovieManager = g_pClientReplayContext->GetMovieManager(); + g_pReplayMovieRenderer = g_pClientReplayContext->GetMovieRenderer(); + g_pReplayPerformanceManager = g_pClientReplayContext->GetPerformanceManager(); + g_pReplayPerformanceController = g_pClientReplayContext->GetPerformanceController(); + + ReplayLib_Init( com_gamedir, g_pClientReplayContext ); + } +#endif + } +#endif + + toolframework->ClientInit( g_ClientFactory ); + } + + // Don't want TF2 running less than DX 8 + if ( g_pMaterialSystemHardwareConfig && g_pMaterialSystemHardwareConfig->GetDXSupportLevel() < 80 ) + { + if ( ( Q_stricmp( COM_GetModDirectory(), "tf" ) == 0 ) || ( Q_stricmp( COM_GetModDirectory(), "ep2" ) == 0 ) || ( Q_stricmp( COM_GetModDirectory(), "portal" ) == 0 ) || ( Q_stricmp( COM_GetModDirectory(), "tf_beta" ) == 0 ) ) + { + Sys_Error( "Your graphics hardware must support at least pixel shader version 1.1 to run this game!" ); + } + } + } + + COM_TimestampedLog( "ClientDLL_InitRecvTableMgr" ); + + ClientDLL_InitRecvTableMgr(); + + InitExtraClientCmdCanExecuteVars(); +} + +//----------------------------------------------------------------------------- +// Purpose: Shuts down the client .dll +//----------------------------------------------------------------------------- +void ClientDLL_Shutdown( void ) +{ +#if defined( REPLAY_ENABLED ) + if ( g_pReplay ) + { + g_pReplay->CL_Shutdown(); + } +#endif + + toolframework->ClientShutdown(); + + ClientDLL_ShutdownRecvTableMgr(); + + vgui::ivgui()->RunFrame(); + + materials->UncacheAllMaterials(); + + vgui::ivgui()->RunFrame(); + + g_pClientSidePrediction->Shutdown(); + + entitylist = NULL; + g_pClientSidePrediction = NULL; + g_ClientFactory = NULL; + centerprint = NULL; + + g_ClientDLL->Shutdown(); +} + +//----------------------------------------------------------------------------- +// Purpose: Unloads the client .dll +// Input : - +//----------------------------------------------------------------------------- +void ClientDLL_Unload() +{ + FileSystem_UnloadModule( g_ClientDLLModule ); + + g_ClientDLL = NULL; + g_ClientDLLModule = NULL; + g_pClientRenderTargets = NULL; + +} + +//----------------------------------------------------------------------------- +// Purpose: Called when the game initializes and whenever the vid_mode is changed +// so the HUD can reinitialize itself. +//----------------------------------------------------------------------------- +void ClientDLL_HudVidInit( void ) +{ + g_ClientDLL->HudVidInit(); +} + +//----------------------------------------------------------------------------- +// Purpose: Allow client .dll to modify input data +//----------------------------------------------------------------------------- + +void ClientDLL_ProcessInput( void ) +{ + if ( !g_ClientDLL ) + return; + + VPROF("ClientDLL_ProcessInput"); + tmZoneFiltered( TELEMETRY_LEVEL0, 50, TMZF_NONE, "%s", __FUNCTION__ ); + g_ClientDLL->HudProcessInput( cl.IsConnected() ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void ClientDLL_FrameStageNotify( ClientFrameStage_t frameStage ) +{ + if ( !g_ClientDLL ) + return; + + tmZoneFiltered( TELEMETRY_LEVEL0, 50, TMZF_NONE, "%s", __FUNCTION__ ); + + g_ClientDLL->FrameStageNotify( frameStage ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Allow client .dll to think +//----------------------------------------------------------------------------- +void ClientDLL_Update( void ) +{ + if ( sv.IsDedicated() ) + return; + + if ( !g_ClientDLL ) + return; + + g_ClientDLL->HudUpdate( true ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void ClientDLL_VoiceStatus( int entindex, bool bTalking ) +{ + if( g_ClientDLL ) + g_ClientDLL->VoiceStatus( entindex, bTalking ); +} + + +#ifdef IS_WINDOWS_PC +#include "winlite.h" +#endif + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CEngineClient::FlashWindow() +{ +#ifndef USE_SDL + FLASHWINFO flashwinfo; + flashwinfo.cbSize = sizeof( flashwinfo ); + flashwinfo.hwnd = (HWND)game->GetMainWindow(); + flashwinfo.dwFlags = FLASHW_ALL; + flashwinfo.uCount = 5; + flashwinfo.dwTimeout = 0; + FlashWindowEx( &flashwinfo ); +#endif +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int CEngineClient::GetInstancesRunningCount( ) +{ + return CheckOtherInstancesRunning( ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +float CEngineClient::GetPausedExpireTime( void ) +{ + return cl.GetPausedExpireTime(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CEngineClient::StartDemoRecording( const char *pszFilename, const char *pszFolder /* = NULL */ ) +{ + bool bUseFolder = ( pszFolder && pszFolder[0] ); + + if ( demorecorder->IsRecording() ) + { + ConMsg( "Already recording.\n" ); + return false; + } + + if ( demoplayer->IsPlayingBack() ) + { + ConMsg( "Can't record during demo playback.\n" ); + return false; + } + + // check filename + if ( !COM_IsValidPath( pszFilename ) ) + { + ConMsg( "record %s: invalid filename.\n", pszFilename ); + return false; + } + + if ( bUseFolder ) + { + // check folder + if ( !COM_IsValidPath( pszFolder ) ) + { + ConMsg( "record %s: invalid folder.\n", pszFolder ); + return false; + } + } + + char szFinal[MAX_OSPATH]; + char szTemp[MAX_OSPATH]; + + if ( !g_ClientDLL->CanRecordDemo( szTemp, sizeof( szTemp ) ) ) + { + ConMsg( "%s\n", szTemp ); // re-use szTemp as the error string if the client prevents us from starting a demo + return false; + } + + if ( bUseFolder ) + { + V_sprintf_safe( szTemp, "%s%c%s", pszFolder, CORRECT_PATH_SEPARATOR, pszFilename ); + } + else + { + V_sprintf_safe( szTemp, "%s", pszFilename ); + } + + // remove .dem extension if it exists + Q_StripExtension( szTemp, szFinal, sizeof( szFinal ) ); + + // record it + demorecorder->StartRecording( szFinal, false ); + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CEngineClient::StopDemoRecording( void ) +{ + if ( !demorecorder->IsRecording() ) + { + ConDMsg( "Not recording a demo.\n" ); + return; + } + + demorecorder->StopRecording(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CEngineClient::TakeScreenshot( const char *pszFilename, const char *pszFolder /* = NULL */ ) +{ + bool bUseFolder = ( pszFolder && pszFolder[0] ); + + // check filename + if ( !COM_IsValidPath( pszFilename ) ) + { + ConMsg( "TakeScreenshot invalid filename: %s\n", pszFilename ); + return; + } + + if ( bUseFolder ) + { + // check folder + if ( !COM_IsValidPath( pszFolder ) ) + { + ConMsg( "TakeScreenshot invalid folder: %s\n", pszFolder ); + return; + } + } + + bool bReadPixelsFromFrontBuffer = g_pMaterialSystemHardwareConfig->ReadPixelsFromFrontBuffer(); + if ( bReadPixelsFromFrontBuffer ) + { + Shader_SwapBuffers(); + } + + // Disable threading for the duration of the screenshots, because we need to get pointers to the (complete) + // back buffer right now. + bool bEnabled = materials->AllowThreading( false, g_nMaterialSystemThread ); + + char szFinal[MAX_OSPATH] = {0}; + + if ( bUseFolder ) + { + V_sprintf_safe( szFinal, "%s%c%s", pszFolder, CORRECT_PATH_SEPARATOR, pszFilename ); + } + else + { + V_sprintf_safe( szFinal, "%s", pszFilename ); + } + + V_SetExtension( szFinal, ".tga", sizeof( szFinal ) ); + + videomode->TakeSnapshotTGA( szFinal ); + + // Restore threading if it was previously enabled (if it wasn't this will do nothing). + materials->AllowThreading( bEnabled, g_nMaterialSystemThread ); + + if ( !bReadPixelsFromFrontBuffer ) + { + Shader_SwapBuffers(); + } +} |