diff --git a/engine/GameEventManager.cpp b/engine/GameEventManager.cpp index 1d6d50fc8..766a22734 100644 --- a/engine/GameEventManager.cpp +++ b/engine/GameEventManager.cpp @@ -41,11 +41,11 @@ static ConVar net_showevents( "net_showevents", "0", FCVAR_CHEAT, "Dump game eve EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CGameEventManager, IGameEventManager2, INTERFACEVERSION_GAMEEVENTSMANAGER2, s_GameEventManager ); -CGameEvent::CGameEvent( CGameEventDescriptor *descriptor ) +CGameEvent::CGameEvent( CGameEventDescriptor *descriptor, const char *name ) { Assert( descriptor ); m_pDescriptor = descriptor; - m_pDataKeys = new KeyValues( descriptor->name ); + m_pDataKeys = new KeyValues( name ); } CGameEvent::~CGameEvent() @@ -63,6 +63,11 @@ int CGameEvent::GetInt( const char *keyName, int defaultValue) return m_pDataKeys->GetInt( keyName, defaultValue ); } +uint64 CGameEvent::GetUint64( const char *keyName, uint64 defaultValue) +{ + return m_pDataKeys->GetUint64( keyName, defaultValue ); +} + float CGameEvent::GetFloat( const char *keyName, float defaultValue ) { return m_pDataKeys->GetFloat( keyName, defaultValue ); @@ -83,6 +88,11 @@ void CGameEvent::SetInt( const char *keyName, int value ) m_pDataKeys->SetInt( keyName, value ); } +void CGameEvent::SetUint64( const char *keyName, uint64 value ) +{ + m_pDataKeys->SetUint64( keyName, value ); +} + void CGameEvent::SetFloat( const char *keyName, float value ) { m_pDataKeys->SetFloat( keyName, value ); @@ -158,8 +168,8 @@ void CGameEventManager::Reset() m_Listeners.PurgeAndDeleteElements(); m_EventFiles.RemoveAll(); m_EventFileNames.RemoveAll(); + m_EventMap.Purge(); m_bClientListenersChanged = true; - Assert( m_GameEvents.Count() == 0 ); } @@ -189,10 +199,12 @@ void CGameEventManager::WriteEventList(SVC_GameEventList *msg) Assert( descriptor.eventid >= 0 && descriptor.eventid < MAX_EVENT_NUMBER ); + const char *pName = m_EventMap.GetElementName( descriptor.elementIndex ); + msg->m_DataOut.WriteUBitLong( descriptor.eventid, MAX_EVENT_BITS ); - msg->m_DataOut.WriteString( descriptor.name ); - - KeyValues *key = descriptor.keys->GetFirstSubKey(); + msg->m_DataOut.WriteString( pName ); + + KeyValues *key = descriptor.keys->GetFirstSubKey(); while ( key ) { @@ -208,7 +220,6 @@ void CGameEventManager::WriteEventList(SVC_GameEventList *msg) } msg->m_DataOut.WriteUBitLong( TYPE_LOCAL, 3 ); // end marker - msg->m_nNumEvents++; } } @@ -296,7 +307,8 @@ void CGameEventManager::WriteListenEventList(CLC_ListenEvents *msg) if ( descriptor.eventid == -1 ) { - DevMsg("Warning! Client listens to event '%s' unknown by server.\n", descriptor.name ); + const char *pName = m_EventMap.GetElementName(descriptor.elementIndex); + DevMsg("Warning! Client listens to event '%s' unknown by server.\n", pName ); continue; } @@ -304,17 +316,17 @@ void CGameEventManager::WriteListenEventList(CLC_ListenEvents *msg) } } -IGameEvent *CGameEventManager::CreateEvent( CGameEventDescriptor *descriptor ) +IGameEvent *CGameEventManager::CreateEvent( CGameEventDescriptor *descriptor, const char *name ) { - return new CGameEvent ( descriptor ); + return new CGameEvent ( descriptor, name ); } -IGameEvent *CGameEventManager::CreateEvent( const char *name, bool bForce ) +IGameEvent *CGameEventManager::CreateEvent( const char *name, bool bForce, int *pCookie ) { if ( !name || !name[0] ) return NULL; - CGameEventDescriptor *descriptor = GetEventDescriptor( name ); + CGameEventDescriptor *descriptor = GetEventDescriptor( name, pCookie ); // check if this event name is known if ( !descriptor ) @@ -330,7 +342,7 @@ IGameEvent *CGameEventManager::CreateEvent( const char *name, bool bForce ) } // create & return the new event - return new CGameEvent ( descriptor ); + return new CGameEvent ( descriptor, name ); } bool CGameEventManager::FireEvent( IGameEvent *event, bool bServerOnly ) @@ -351,7 +363,8 @@ IGameEvent *CGameEventManager::DuplicateEvent( IGameEvent *event ) return NULL; // create new instance - CGameEvent *newEvent = new CGameEvent ( gameEvent->m_pDescriptor ); + const char *pName = m_EventMap.GetElementName(gameEvent->m_pDescriptor->elementIndex ); + CGameEvent *newEvent = new CGameEvent ( gameEvent->m_pDescriptor, pName ); // free keys newEvent->m_pDataKeys->deleteThis(); @@ -414,12 +427,16 @@ bool CGameEventManager::FireEventIntern( IGameEvent *event, bool bServerOnly, bo { if ( bClientOnly ) { - ConMsg( "Game event \"%s\", Tick %i:\n", descriptor->name, cl.GetClientTickCount() ); +#ifndef DEDICATED + const char *pName = m_EventMap.GetElementName(descriptor->elementIndex); + ConMsg( "Game event \"%s\", Tick %i:\n", pName, cl.GetClientTickCount() ); ConPrintEvent( event ); +#endif } else if ( net_showevents.GetInt() > 1 ) { - ConMsg( "Server event \"%s\", Tick %i:\n", descriptor->name, sv.GetTick() ); + const char *pName = m_EventMap.GetElementName(descriptor->elementIndex); + ConMsg( "Server event \"%s\", Tick %i:\n", pName, sv.GetTick() ); ConPrintEvent( event ); } } @@ -491,7 +508,8 @@ bool CGameEventManager::SerializeEvent( IGameEvent *event, bf_write* buf ) if ( net_showevents.GetInt() > 2 ) { - DevMsg("Serializing event '%s' (%i):\n", descriptor->name, descriptor->eventid ); + const char *pName = m_EventMap.GetElementName(descriptor->elementIndex); + DevMsg("Serializing event '%s' (%i):\n", pName, descriptor->eventid ); } while ( key ) @@ -545,11 +563,12 @@ IGameEvent *CGameEventManager::UnserializeEvent( bf_read *buf) } // create new event - IGameEvent *event = CreateEvent( descriptor ); + const char *pName = m_EventMap.GetElementName(descriptor->elementIndex); + IGameEvent *event = CreateEvent( descriptor, pName ); if ( !event ) { - DevMsg( "CGameEventManager::UnserializeEvent:: failed to create event %s.\n", descriptor->name ); + DevMsg( "CGameEventManager::UnserializeEvent:: failed to create event %i.\n", descriptor->eventid ); return NULL; } @@ -766,9 +785,7 @@ bool CGameEventManager::RegisterEvent( KeyValues * event) int index = m_GameEvents.AddToTail(); descriptor = &m_GameEvents.Element(index); - AssertMsg2( V_strlen( event->GetName() ) <= MAX_EVENT_NAME_LENGTH, "Event named '%s' exceeds maximum name length %d", event->GetName(), MAX_EVENT_NAME_LENGTH ); - - Q_strncpy( descriptor->name, event->GetName(), MAX_EVENT_NAME_LENGTH ); + descriptor->elementIndex = m_EventMap.Insert( event->GetName(), index ); } else { @@ -859,20 +876,34 @@ void CGameEventManager::FreeEvent( IGameEvent *event ) delete event; } -CGameEventDescriptor *CGameEventManager::GetEventDescriptor(const char * name) +CGameEventDescriptor *CGameEventManager::GetEventDescriptor(const char * name, int *pCookie) { + const uint32 cookieBit = 0x80000000; + const uint32 cookieMask = ~cookieBit; + if ( !name || !name[0] ) return NULL; - for (int i=0; i < m_GameEvents.Count(); i++ ) + if ( pCookie && *pCookie ) { - CGameEventDescriptor *descriptor = &m_GameEvents[i]; + int gameEventIndex = uint32(*pCookie) & cookieMask; + CGameEventDescriptor *pDescriptor = &m_GameEvents[gameEventIndex]; + if ( !V_stricmp( m_EventMap.GetElementName(pDescriptor->elementIndex), name ) ) + { + return pDescriptor; + } + } + int eventMapIndex = m_EventMap.Find( name ); + if ( eventMapIndex == m_EventMap.InvalidIndex() ) + return NULL; - if ( Q_strcmp( descriptor->name, name ) == 0 ) - return descriptor; + int gameEventIndex = m_EventMap[eventMapIndex]; + if ( pCookie ) + { + *pCookie = cookieBit | gameEventIndex; } - return NULL; + return &m_GameEvents[gameEventIndex]; } bool CGameEventManager::AddListenerAll( void *listener, int nListenerType ) diff --git a/engine/GameEventManager.h b/engine/GameEventManager.h index 02d247dc9..74ddafdab 100644 --- a/engine/GameEventManager.h +++ b/engine/GameEventManager.h @@ -13,6 +13,7 @@ #pragma once #endif +#include "utldict.h" #include #include #include @@ -34,16 +35,16 @@ class CGameEventDescriptor public: CGameEventDescriptor() { - name[0] = 0; eventid = -1; keys = NULL; local = false; reliable = true; + elementIndex = -1; } public: - char name[MAX_EVENT_NAME_LENGTH]; // name of this event - int eventid; // network index number, -1 = not networked + int eventid; // network index number, -1 = not networked + int elementIndex; KeyValues *keys; // KeyValue describing data types, if NULL only name bool local; // local event, never tell clients about that bool reliable; // send this event as reliable message @@ -54,7 +55,7 @@ class CGameEvent : public IGameEvent { public: - CGameEvent( CGameEventDescriptor *descriptor ); + CGameEvent( CGameEventDescriptor *descriptor, const char *name ); virtual ~CGameEvent(); const char *GetName() const; @@ -64,11 +65,13 @@ class CGameEvent : public IGameEvent bool GetBool( const char *keyName = NULL, bool defaultValue = false ); int GetInt( const char *keyName = NULL, int defaultValue = 0 ); + uint64 GetUint64( const char *keyName = NULL, uint64 defaultValue = 0 ); float GetFloat( const char *keyName = NULL, float defaultValue = 0.0f ); const char *GetString( const char *keyName = NULL, const char *defaultValue = "" ); void SetBool( const char *keyName, bool value ); void SetInt( const char *keyName, int value ); + void SetUint64( const char *keyName, uint64 value ); void SetFloat( const char *keyName, float value ); void SetString( const char *keyName, const char *value ); @@ -111,8 +114,9 @@ class CGameEventManager : public IGameEventManager2 bool AddListener( IGameEventListener2 *listener, const char *name, bool bServerSide ); bool FindListener( IGameEventListener2 *listener, const char *name ); void RemoveListener( IGameEventListener2 *listener); - - IGameEvent *CreateEvent( const char *name, bool bForce = false ); + + IGameEvent *CreateEvent( const char *name, bool bForce = false, int *pCookie = NULL ); + IGameEvent *DuplicateEvent( IGameEvent *event); bool FireEvent( IGameEvent *event, bool bDontBroadcast = false ); bool FireEventClientSide( IGameEvent *event ); @@ -127,7 +131,7 @@ class CGameEventManager : public IGameEventManager2 void ReloadEventDefinitions(); // called by server on new map bool AddListener( void *listener, CGameEventDescriptor *descriptor, int nListenerType ); - CGameEventDescriptor *GetEventDescriptor( const char *name ); + CGameEventDescriptor *GetEventDescriptor( const char *name, int *pCookie = NULL ); CGameEventDescriptor *GetEventDescriptor( IGameEvent *event ); CGameEventDescriptor *GetEventDescriptor( int eventid ); @@ -145,13 +149,14 @@ class CGameEventManager : public IGameEventManager2 protected: - IGameEvent *CreateEvent( CGameEventDescriptor *descriptor ); + IGameEvent *CreateEvent( CGameEventDescriptor *descriptor, const char *name ); bool RegisterEvent( KeyValues * keys ); void UnregisterEvent(int index); bool FireEventIntern( IGameEvent *event, bool bServerSide, bool bClientOnly ); CGameEventCallback* FindEventListener( void* listener ); CUtlVector m_GameEvents; // list of all known events + CUtlDict m_EventMap; CUtlVector m_Listeners; // list of all registered listeners CUtlSymbolTable m_EventFiles; // list of all loaded event files CUtlVector m_EventFileNames; diff --git a/engine/baseclient.cpp b/engine/baseclient.cpp index 4ec466525..cd87b8fae 100644 --- a/engine/baseclient.cpp +++ b/engine/baseclient.cpp @@ -66,10 +66,13 @@ CBaseClient::CBaseClient() m_bReportFakeClient = true; m_iTracing = 0; m_bPlayerNameLocked = false; + + m_nDebugID = EVENT_DEBUG_ID_INIT; } CBaseClient::~CBaseClient() { + m_nDebugID = EVENT_DEBUG_ID_SHUTDOWN; } @@ -670,6 +673,11 @@ void CBaseClient::FireGameEvent( IGameEvent *event ) } } +int CBaseClient::GetEventDebugID( void ) +{ + return m_nDebugID; +} + bool CBaseClient::SendServerInfo( void ) { COM_TimestampedLog( " CBaseClient::SendServerInfo" ); diff --git a/engine/baseclient.h b/engine/baseclient.h index b399f9e6b..21ea47ee3 100644 --- a/engine/baseclient.h +++ b/engine/baseclient.h @@ -144,6 +144,8 @@ class CBaseClient : public IGameEventListener2, public IClient, public IClientMe public: // IGameEventListener virtual void FireGameEvent( IGameEvent *event ); + int m_nDebugID; + virtual int GetEventDebugID( void ); public: diff --git a/engine/cdll_engine_int.cpp b/engine/cdll_engine_int.cpp index f986a207b..0b2c7154a 100644 --- a/engine/cdll_engine_int.cpp +++ b/engine/cdll_engine_int.cpp @@ -539,6 +539,8 @@ class CEngineClient : public IVEngineClient virtual bool REMOVED_SteamRefreshLogin( const char *password, bool isSecure ) { return false; } virtual bool REMOVED_SteamProcessCall( bool & finished ) { return false; } + virtual ISPSharedMemory *GetSinglePlayerSharedMemorySpace( const char *handle, int ent_num = MAX_EDICTS ); + virtual void SetGamestatsData( CGamestatsData *pGamestatsData ); virtual CGamestatsData *GetGamestatsData(); @@ -1568,6 +1570,13 @@ void CEngineClient::OnStorageDeviceDetached( void ) g_pXboxSystem->CloseContainers(); } + +ISPSharedMemory *CEngineClient::GetSinglePlayerSharedMemorySpace( const char *szName, int ent_num ) +{ + // TODO(nillerusr): it this necessary? Implement later if so + return NULL; //g_pSinglePlayerSharedMemoryManager->GetSharedMemory( szName, ent_num ); +} + void CEngineClient::ResetDemoInterpolation( void ) { if( demorecorder->IsRecording() ) diff --git a/engine/cmodel.cpp b/engine/cmodel.cpp index 373eea3ae..22eaab691 100644 --- a/engine/cmodel.cpp +++ b/engine/cmodel.cpp @@ -50,47 +50,28 @@ csurface_t *CCollisionBSPData::GetSurfaceAtIndex( unsigned short surfaceIndex ) return &map_surfaces[surfaceIndex]; } -#if TEST_TRACE_POOL -CTSPool g_TraceInfoPool; -#else -class CTraceInfoPool : public CTSList -{ -public: - CTraceInfoPool() = default; -}; - -CTraceInfoPool g_TraceInfoPool; -#endif +static TraceInfo_t g_TraceInfo; TraceInfo_t *BeginTrace() { -#if TEST_TRACE_POOL - TraceInfo_t *pTraceInfo = g_TraceInfoPool.GetObject(); -#else - TraceInfo_t *pTraceInfo; - if ( !g_TraceInfoPool.PopItem( &pTraceInfo ) ) + if ( g_TraceInfo.m_BrushCounters[0].Count() != GetCollisionBSPData()->numbrushes + 1 ) { - pTraceInfo = new TraceInfo_t; - } -#endif - if ( pTraceInfo->m_BrushCounters[0].Count() != GetCollisionBSPData()->numbrushes + 1 ) - { - memset( pTraceInfo->m_Count, 0, sizeof( pTraceInfo->m_Count ) ); - pTraceInfo->m_nCheckDepth = -1; + memset( g_TraceInfo.m_Count, 0, sizeof( g_TraceInfo.m_Count ) ); + g_TraceInfo.m_nCheckDepth = -1; for ( int i = 0; i < MAX_CHECK_COUNT_DEPTH; i++ ) { - pTraceInfo->m_BrushCounters[i].SetCount( GetCollisionBSPData()->numbrushes + 1 ); - pTraceInfo->m_DispCounters[i].SetCount( g_DispCollTreeCount ); + g_TraceInfo.m_BrushCounters[i].SetCount( GetCollisionBSPData()->numbrushes + 1 ); + g_TraceInfo.m_DispCounters[i].SetCount( g_DispCollTreeCount ); - memset( pTraceInfo->m_BrushCounters[i].Base(), 0, pTraceInfo->m_BrushCounters[i].Count() * sizeof(TraceCounter_t) ); - memset( pTraceInfo->m_DispCounters[i].Base(), 0, pTraceInfo->m_DispCounters[i].Count() * sizeof(TraceCounter_t) ); + memset( g_TraceInfo.m_BrushCounters[i].Base(), 0, g_TraceInfo.m_BrushCounters[i].Count() * sizeof(TraceCounter_t) ); + memset( g_TraceInfo.m_DispCounters[i].Base(), 0, g_TraceInfo.m_DispCounters[i].Count() * sizeof(TraceCounter_t) ); } } - PushTraceVisits( pTraceInfo ); + PushTraceVisits( &g_TraceInfo ); - return pTraceInfo; + return &g_TraceInfo; } void PushTraceVisits( TraceInfo_t *pTraceInfo ) @@ -114,16 +95,9 @@ void PopTraceVisits( TraceInfo_t *pTraceInfo ) Assert( pTraceInfo->m_nCheckDepth >= -1 ); } -void EndTrace( TraceInfo_t *&pTraceInfo ) +void EndTrace( TraceInfo_t *pTraceInfo ) { PopTraceVisits( pTraceInfo ); - Assert( pTraceInfo->m_nCheckDepth == -1 ); -#if TEST_TRACE_POOL - g_TraceInfoPool.PutObject( pTraceInfo ); -#else - g_TraceInfoPool.PushItem( pTraceInfo ); -#endif - pTraceInfo = NULL; } static ConVar map_noareas( "map_noareas", "0", 0, "Disable area to area connection testing." ); diff --git a/engine/cmodel_private.h b/engine/cmodel_private.h index 5bf52eeef..0f3975340 100644 --- a/engine/cmodel_private.h +++ b/engine/cmodel_private.h @@ -158,7 +158,7 @@ struct cnode_t TraceInfo_t *BeginTrace(); void PushTraceVisits( TraceInfo_t *pTraceInfo ); void PopTraceVisits( TraceInfo_t *pTraceInfo ); -void EndTrace( TraceInfo_t *&pTraceInfo ); +void EndTrace( TraceInfo_t *pTraceInfo ); //----------------------------------------------------------------------------- diff --git a/engine/hltvserver.cpp b/engine/hltvserver.cpp index 0b4d86912..069ab3f04 100644 --- a/engine/hltvserver.cpp +++ b/engine/hltvserver.cpp @@ -475,6 +475,8 @@ CHLTVServer::CHLTVServer() m_nGlobalSlots = 0; m_nGlobalClients = 0; m_nGlobalProxies = 0; + + m_nDebugID = EVENT_DEBUG_ID_INIT; } CHLTVServer::~CHLTVServer() @@ -488,6 +490,8 @@ CHLTVServer::~CHLTVServer() // make sure everything was destroyed Assert( m_CurrentFrame == NULL ); Assert( CountClientFrames() == 0 ); + + m_nDebugID = EVENT_DEBUG_ID_SHUTDOWN; } void CHLTVServer::SetMaxClients( int number ) @@ -1015,9 +1019,13 @@ void CHLTVServer::FireGameEvent(IGameEvent *event) } } -bool CHLTVServer::ShouldUpdateMasterServer() +int CHLTVServer::GetEventDebugID( void ) { + return m_nDebugID; +} +bool CHLTVServer::ShouldUpdateMasterServer() +{ // If the main game server is active, then we let it update Steam with the server info. return !sv.IsActive(); } diff --git a/engine/hltvserver.h b/engine/hltvserver.h index fa5a657a5..91fc058d1 100644 --- a/engine/hltvserver.h +++ b/engine/hltvserver.h @@ -115,6 +115,8 @@ friend class CHLTVClientState; public: void FireGameEvent(IGameEvent *event); + int m_nDebugID; + int GetEventDebugID( void ); public: // IHLTVServer interface: IServer *GetBaseServer( void ); diff --git a/engine/sv_log.cpp b/engine/sv_log.cpp index f04d17da7..c50c396df 100644 --- a/engine/sv_log.cpp +++ b/engine/sv_log.cpp @@ -262,11 +262,13 @@ CON_COMMAND( logaddress_list, "List all addresses currently being used by logadd CLog::CLog() { Reset(); + m_nDebugID = EVENT_DEBUG_ID_INIT; + } CLog::~CLog() { - + m_nDebugID = EVENT_DEBUG_ID_SHUTDOWN; } void CLog::Reset( void ) // reset all logging streams @@ -644,6 +646,11 @@ void CLog::FireGameEvent( IGameEvent *event ) } } +int CLog::GetEventDebugID( void ) +{ + return m_nDebugID; +} + struct TempFilename_t { bool IsGzip; diff --git a/engine/sv_log.h b/engine/sv_log.h index 42f051135..86771e1e2 100644 --- a/engine/sv_log.h +++ b/engine/sv_log.h @@ -24,7 +24,8 @@ class CLog : public IGameEventListener2 public: // IGameEventListener Interface void FireGameEvent( IGameEvent *event ); - + int m_nDebugID; + int GetEventDebugID( void ); public: bool IsActive( void ); // true if logging is "on" diff --git a/engine/vengineserver_impl.cpp b/engine/vengineserver_impl.cpp index 37dc07c6f..39cbf2987 100644 --- a/engine/vengineserver_impl.cpp +++ b/engine/vengineserver_impl.cpp @@ -1595,6 +1595,12 @@ class CVEngineServer : public IVEngineServer return sv.GetPlayerInfo( (ent_num-1), pinfo ); } + virtual ISPSharedMemory *GetSinglePlayerSharedMemorySpace( const char *szName, int ent_num = MAX_EDICTS ) + { + // TODO(nillerusr): it this necessary? Implement later if so + return NULL; //return g_pSinglePlayerSharedMemoryManager->GetSharedMemory( szName, ent_num ); + } + bool IsClientFullyAuthenticated( edict_t *pEdict ) { int entnum = NUM_FOR_EDICT( pEdict ); diff --git a/game/client/AnimateSpecificTextureProxy.cpp b/game/client/AnimateSpecificTextureProxy.cpp index e4fe742ff..effab3103 100644 --- a/game/client/AnimateSpecificTextureProxy.cpp +++ b/game/client/AnimateSpecificTextureProxy.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: Acts exactly like "AnimatedTexture", but ONLY if the texture // it's working on matches the desired texture to work on. @@ -8,14 +8,15 @@ // $NoKeywords: $ //=============================================================================// #include "cbase.h" -#include "materialsystem/imaterialproxy.h" -#include "materialsystem/imaterialvar.h" -#include "materialsystem/imaterial.h" -#include "materialsystem/itexture.h" -#include "baseanimatedtextureproxy.h" +#include "materialsystem/IMaterialProxy.h" +#include "materialsystem/IMaterialVar.h" +#include "materialsystem/IMaterial.h" +#include "materialsystem/ITexture.h" +#include "BaseAnimatedTextureProxy.h" #include "utlstring.h" #include +#include "imaterialproxydict.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -50,4 +51,4 @@ void CAnimateSpecificTexture::OnBind( void *pC_BaseEntity ) //else do nothing } -EXPOSE_INTERFACE( CAnimateSpecificTexture, IMaterialProxy, "AnimateSpecificTexture" IMATERIAL_PROXY_INTERFACE_VERSION ); \ No newline at end of file +EXPOSE_MATERIAL_PROXY( CAnimateSpecificTexture, AnimateSpecificTexture ); \ No newline at end of file diff --git a/game/client/C_Env_Projected_Texture.h b/game/client/C_Env_Projected_Texture.h deleted file mode 100644 index b15ea6ef7..000000000 --- a/game/client/C_Env_Projected_Texture.h +++ /dev/null @@ -1,65 +0,0 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -// $NoKeywords: $ -//=============================================================================// - -#ifndef C_ENVPROJECTEDTEXTURE_H -#define C_ENVPROJECTEDTEXTURE_H -#ifdef _WIN32 -#pragma once -#endif - -#include "c_baseentity.h" -#include "basetypes.h" - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -class C_EnvProjectedTexture : public C_BaseEntity -{ - DECLARE_CLASS( C_EnvProjectedTexture, C_BaseEntity ); -public: - DECLARE_CLIENTCLASS(); - - C_EnvProjectedTexture(); - ~C_EnvProjectedTexture(); - - virtual void OnDataChanged( DataUpdateType_t updateType ); - void ShutDownLightHandle( void ); - - virtual void Simulate(); - - void UpdateLight( bool bForceUpdate ); - - bool ShadowsEnabled(); - - float GetFOV(); - -private: - - ClientShadowHandle_t m_LightHandle; - - EHANDLE m_hTargetEntity; - - bool m_bState; - float m_flLightFOV; - bool m_bEnableShadows; - bool m_bLightOnlyTarget; - bool m_bLightWorld; - bool m_bCameraSpace; - color32 m_cLightColor; - float m_flAmbient; - char m_SpotlightTextureName[ MAX_PATH ]; - int m_nSpotlightTextureFrame; - int m_nShadowQuality; - bool m_bCurrentShadow; - -public: - C_EnvProjectedTexture *m_pNext; -}; - -C_EnvProjectedTexture* GetEnvProjectedTextureList(); - -#endif // C_ENVPROJECTEDTEXTURE_H diff --git a/game/client/C_MaterialModifyControl.cpp b/game/client/C_MaterialModifyControl.cpp index f038022ed..e7ffc5e6f 100644 --- a/game/client/C_MaterialModifyControl.cpp +++ b/game/client/C_MaterialModifyControl.cpp @@ -1,19 +1,19 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: Material Modify control entity. // //=============================================================================// #include "cbase.h" -#include "proxyentity.h" -#include "materialsystem/imaterial.h" -#include "materialsystem/imaterialvar.h" -#include "materialsystem/itexture.h" +#include "ProxyEntity.h" +#include "materialsystem/IMaterial.h" +#include "materialsystem/IMaterialVar.h" +#include "materialsystem/ITexture.h" #include "iviewrender.h" #include "texture_group_names.h" -#include "baseanimatedtextureproxy.h" -#include "toolframework_client.h" +#include "BaseAnimatedTextureProxy.h" +#include "imaterialproxydict.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -29,9 +29,6 @@ enum MaterialModifyMode_t MATERIAL_MODIFY_MODE_FLOAT_LERP = 3, }; -// forward declarations -void ToolFramework_RecordMaterialParams( IMaterial *pMaterial ); - ConVar debug_materialmodifycontrol_client( "debug_materialmodifycontrol_client", "0" ); struct materialanimcommands_t @@ -328,11 +325,6 @@ void CMaterialModifyProxy::OnBind( void *pEntity ) } } } - - if ( ToolsEnabled() ) - { - ToolFramework_RecordMaterialParams( GetMaterial() ); - } } IMaterial *CMaterialModifyProxy::GetMaterial() @@ -753,11 +745,6 @@ void CMaterialModifyAnimatedProxy::OnBind( void *pEntity ) } m_AnimatedTextureFrameNumVar->SetIntValue( intFrame ); - - if ( ToolsEnabled() ) - { - ToolFramework_RecordMaterialParams( GetMaterial() ); - } } //----------------------------------------------------------------------------- @@ -794,5 +781,5 @@ void CMaterialModifyAnimatedProxy::AnimationWrapped( void* pArg ) } -EXPOSE_INTERFACE( CMaterialModifyProxy, IMaterialProxy, "MaterialModify" IMATERIAL_PROXY_INTERFACE_VERSION ); -EXPOSE_INTERFACE( CMaterialModifyAnimatedProxy, IMaterialProxy, "MaterialModifyAnimated" IMATERIAL_PROXY_INTERFACE_VERSION ); +EXPOSE_MATERIAL_PROXY( CMaterialModifyProxy, MaterialModify ); +EXPOSE_MATERIAL_PROXY( CMaterialModifyAnimatedProxy, MaterialModifyAnimated ); diff --git a/game/client/C_WaterLODControl.cpp b/game/client/C_WaterLODControl.cpp index 2e27ffb23..f77e7fd29 100644 --- a/game/client/C_WaterLODControl.cpp +++ b/game/client/C_WaterLODControl.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: Water LOD control entity. // diff --git a/game/client/EffectsClient.cpp b/game/client/EffectsClient.cpp index f7b6ffff0..bcd0dacef 100644 --- a/game/client/EffectsClient.cpp +++ b/game/client/EffectsClient.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: Utility code. // diff --git a/game/client/IsNPCProxy.cpp b/game/client/IsNPCProxy.cpp index 819cbd98c..6fdfb2e11 100644 --- a/game/client/IsNPCProxy.cpp +++ b/game/client/IsNPCProxy.cpp @@ -1,19 +1,16 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2007, Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ //=============================================================================// #include "cbase.h" -#include "functionproxy.h" -#include "toolframework_client.h" +#include "FunctionProxy.h" +#include "imaterialproxydict.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" -// forward declarations -void ToolFramework_RecordMaterialParams( IMaterial *pMaterial ); - //----------------------------------------------------------------------------- // Returns the player health (from 0 to 1) //----------------------------------------------------------------------------- @@ -52,12 +49,8 @@ void CProxyIsNPC::OnBind( void *pC_BaseEntity ) { SetFloatResult( 0.0f ); } - if ( ToolsEnabled() ) - { - ToolFramework_RecordMaterialParams( GetMaterial() ); - } } -EXPOSE_INTERFACE( CProxyIsNPC, IMaterialProxy, "IsNPC" IMATERIAL_PROXY_INTERFACE_VERSION ); +EXPOSE_MATERIAL_PROXY( CProxyIsNPC, IsNPC ); diff --git a/game/client/MonitorMaterialProxy.cpp b/game/client/MonitorMaterialProxy.cpp index 1352f2da3..fc052e4ad 100644 --- a/game/client/MonitorMaterialProxy.cpp +++ b/game/client/MonitorMaterialProxy.cpp @@ -1,13 +1,18 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ //=============================================================================// + #include "cbase.h" -#include "materialsystem/imaterialproxy.h" -#include "materialsystem/imaterial.h" -#include "materialsystem/imaterialvar.h" +#include "materialsystem/IMaterialProxy.h" +#include "materialsystem/IMaterial.h" +#include "materialsystem/IMaterialVar.h" + +// NOTE: This has to be the last file included! +#include "tier0/memdbgon.h" + // $monitorTextureVar class CMonitorMaterialProxy : public IMaterialProxy @@ -57,4 +62,4 @@ void CMonitorMaterialProxy::OnBind( void *pC_BaseEntity ) } } -EXPOSE_INTERFACE( CMonitorMaterialProxy, IMaterialProxy, "Monitor" IMATERIAL_PROXY_INTERFACE_VERSION ); +EXPOSE_MATERIAL_PROXY( CMonitorMaterialProxy, Monitor ); diff --git a/game/client/NPSClient.h b/game/client/NPSClient.h new file mode 100644 index 000000000..88e7e41ea --- /dev/null +++ b/game/client/NPSClient.h @@ -0,0 +1,101 @@ +// ******************************************************************************* +// * +// * Module Name: +// * NPSClient.h +// * +// * Abstract: +// * Header for NaturalPoint Simple Game Client API. +// * +// * Environment: +// * Microsoft Windows -- User mode +// * +// ******************************************************************************* + +#ifndef _NPSCLIENT_H_DEFINED_ +#define _NPSCLIENT_H_DEFINED_ + +#pragma pack( push, npsclient_h ) // Save current pack value +#pragma pack(1) + +#ifdef __cplusplus +extern "C"{ +#endif + +////////////////// +/// Typedefs ///////////////////////////////////////////////////////////////////// +///////////////// + +#ifndef _NPCLIENT_H_DEFINED_ + +// NPESULT values are returned from the Game Client API functions. +// +typedef enum tagNPResult +{ + NP_OK = 0, + NP_ERR_DEVICE_NOT_PRESENT, + NP_ERR_UNSUPPORTED_OS, + NP_ERR_INVALID_ARG, + NP_ERR_DLL_NOT_FOUND, + NP_ERR_NO_DATA, + NP_ERR_INTERNAL_DATA, + NP_ERR_ALREADY_REGISTERED, // a window handle or game ID is already registered + NP_ERR_UNKNOWN_ID, // unknown game ID registered + NP_ERR_READ_ONLY, // parameter is read only + +} NPRESULT; + +typedef struct tagTrackIRData +{ + unsigned short wNPStatus; + unsigned short wPFrameSignature; + unsigned long dwNPIOData; + + float fNPRoll; + float fNPPitch; + float fNPYaw; + float fNPX; + float fNPY; + float fNPZ; + float fNPRawX; + float fNPRawY; + float fNPRawZ; + float fNPDeltaX; + float fNPDeltaY; + float fNPDeltaZ; + float fNPSmoothX; + float fNPSmoothY; + float fNPSmoothZ; + +} TRACKIRDATA, *LPTRACKIRDATA; + +#endif + +typedef NPRESULT (__stdcall *PF_NPS_INIT)( HWND ); +typedef NPRESULT (__stdcall *PF_NPS_SHUTDOWN)( void ); +typedef NPRESULT (__stdcall *PF_NPS_GETDATA)( LPTRACKIRDATA ); + +//// Function Prototypes /////////////////////////////////////////////// +// +// Functions exported from game client API DLL ( note __stdcall calling convention +// is used for ease of interface to clients of differing implementations including +// C, C++, Pascal (Delphi) and VB. ) +// +NPRESULT __stdcall NPS_Init( HWND hWnd ); +NPRESULT __stdcall NPS_Shutdown( void ); +NPRESULT __stdcall NPS_GetData( LPTRACKIRDATA pTID ); + +///////////////////////////////////////////////////////////////////////// + +#ifdef __cplusplus +} +#endif + +#pragma pack( pop, npsclient_h ) // Ensure previous pack value is restored + +#endif // #ifdef NPCLIENT_H_DEFINED_ + +// +// *** End of file: NPSClient.h *** +// + + diff --git a/game/client/NextBot/C_NextBot.cpp b/game/client/NextBot/C_NextBot.cpp deleted file mode 100644 index 13d55012f..000000000 --- a/game/client/NextBot/C_NextBot.cpp +++ /dev/null @@ -1,245 +0,0 @@ -// C_NextBot.cpp -// Client-side implementation of Next generation bot system -// Author: Michael Booth, April 2005 -//========= Copyright Valve Corporation, All rights reserved. ============// - -#include "cbase.h" -#include "C_NextBot.h" -#include "debugoverlay_shared.h" -#include -#include "viewrender.h" - -// memdbgon must be the last include file in a .cpp file!!! -#include "tier0/memdbgon.h" - -#undef NextBot - -ConVar NextBotShadowDist( "nb_shadow_dist", "400" ); - -//----------------------------------------------------------------------------- -IMPLEMENT_CLIENTCLASS_DT( C_NextBotCombatCharacter, DT_NextBot, NextBotCombatCharacter ) -END_RECV_TABLE() - - -//----------------------------------------------------------------------------- -C_NextBotCombatCharacter::C_NextBotCombatCharacter() -{ - // Left4Dead have surfaces too steep for IK to work properly - m_EntClientFlags |= ENTCLIENTFLAG_DONTUSEIK; - - m_shadowType = SHADOWS_SIMPLE; - m_forcedShadowType = SHADOWS_NONE; - m_bForceShadowType = false; - - TheClientNextBots().Register( this ); -} - - -//----------------------------------------------------------------------------- -C_NextBotCombatCharacter::~C_NextBotCombatCharacter() -{ - TheClientNextBots().UnRegister( this ); -} - - -//----------------------------------------------------------------------------- -void C_NextBotCombatCharacter::Spawn( void ) -{ - BaseClass::Spawn(); -} - - -//----------------------------------------------------------------------------- -void C_NextBotCombatCharacter::UpdateClientSideAnimation() -{ - if (IsDormant()) - { - return; - } - - BaseClass::UpdateClientSideAnimation(); -} - - -//-------------------------------------------------------------------------------------------------------- -void C_NextBotCombatCharacter::UpdateShadowLOD( void ) -{ - ShadowType_t oldShadowType = m_shadowType; - - if ( m_bForceShadowType ) - { - m_shadowType = m_forcedShadowType; - } - else - { -#ifdef NEED_SPLITSCREEN_INTEGRATION - FOR_EACH_VALID_SPLITSCREEN_PLAYER( hh ) - { - C_BasePlayer *pl = C_BasePlayer::GetLocalPlayer(hh); - if ( pl ) - { - Vector delta = GetAbsOrigin() - C_BasePlayer::GetLocalPlayer(hh)->GetAbsOrigin(); -#else - { - if ( C_BasePlayer::GetLocalPlayer() ) - { - Vector delta = GetAbsOrigin() - C_BasePlayer::GetLocalPlayer()->GetAbsOrigin(); -#endif - if ( delta.IsLengthLessThan( NextBotShadowDist.GetFloat() ) ) - { - m_shadowType = SHADOWS_RENDER_TO_TEXTURE_DYNAMIC; - } - else - { - m_shadowType = SHADOWS_SIMPLE; - } - } - else - { - m_shadowType = SHADOWS_SIMPLE; - } - } - } - - if ( oldShadowType != m_shadowType ) - { - DestroyShadow(); - } -} - - -//-------------------------------------------------------------------------------------------------------- -ShadowType_t C_NextBotCombatCharacter::ShadowCastType( void ) -{ - if ( !IsVisible() ) - return SHADOWS_NONE; - - if ( m_shadowTimer.IsElapsed() ) - { - m_shadowTimer.Start( 0.15f ); - UpdateShadowLOD(); - } - - return m_shadowType; -} - - -//-------------------------------------------------------------------------------------------------------- -bool C_NextBotCombatCharacter::GetForcedShadowCastType( ShadowType_t* pForcedShadowType ) const -{ - if ( pForcedShadowType ) - { - *pForcedShadowType = m_forcedShadowType; - } - return m_bForceShadowType; -} - -//-------------------------------------------------------------------------------------------------------- -/** - * Singleton accessor. - * By returning a reference, we guarantee construction of the - * instance before its first use. - */ -C_NextBotManager &TheClientNextBots( void ) -{ - static C_NextBotManager manager; - return manager; -} - - -//-------------------------------------------------------------------------------------------------------- -C_NextBotManager::C_NextBotManager( void ) -{ -} - - -//-------------------------------------------------------------------------------------------------------- -C_NextBotManager::~C_NextBotManager() -{ -} - - -//-------------------------------------------------------------------------------------------------------- -void C_NextBotManager::Register( C_NextBotCombatCharacter *bot ) -{ - m_botList.AddToTail( bot ); -} - - -//-------------------------------------------------------------------------------------------------------- -void C_NextBotManager::UnRegister( C_NextBotCombatCharacter *bot ) -{ - m_botList.FindAndRemove( bot ); -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -bool C_NextBotManager::SetupInFrustumData( void ) -{ -#ifdef ENABLE_AFTER_INTEGRATION - // Done already this frame. - if ( IsInFrustumDataValid() ) - return true; - - // Can we use the view data yet? - if ( !FrustumCache()->IsValid() ) - return false; - - // Get the number of active bots. - int nBotCount = m_botList.Count(); - - // Reset. - for ( int iBot = 0; iBot < nBotCount; ++iBot ) - { - // Get the current bot. - C_NextBotCombatCharacter *pBot = m_botList[iBot]; - if ( !pBot ) - continue; - - pBot->InitFrustumData(); - } - - FOR_EACH_VALID_SPLITSCREEN_PLAYER( iSlot ) - { - ACTIVE_SPLITSCREEN_PLAYER_GUARD( iSlot ); - // Get the active local player. - C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); - if ( !pPlayer ) - continue; - - for ( int iBot = 0; iBot < nBotCount; ++iBot ) - { - // Get the current bot. - C_NextBotCombatCharacter *pBot = m_botList[iBot]; - if ( !pBot ) - continue; - - // Are we in the view frustum? - Vector vecMin, vecMax; - pBot->CollisionProp()->WorldSpaceAABB( &vecMin, &vecMax ); - bool bInFrustum = !FrustumCache()->m_Frustums[iSlot].CullBox( vecMin, vecMax ); - - if ( bInFrustum ) - { - Vector vecSegment; - VectorSubtract( pBot->GetAbsOrigin(), pPlayer->GetAbsOrigin(), vecSegment ); - float flDistance = vecSegment.LengthSqr(); - if ( flDistance < pBot->GetInFrustumDistanceSqr() ) - { - pBot->SetInFrustumDistanceSqr( flDistance ); - } - - pBot->SetInFrustum( true ); - } - } - } - - // Mark as setup this frame. - m_nInFrustumFrame = gpGlobals->framecount; -#endif - - return true; -} - -//-------------------------------------------------------------------------------------------------------- diff --git a/game/client/NextBot/C_NextBot.h b/game/client/NextBot/C_NextBot.h deleted file mode 100644 index c26d7b9b9..000000000 --- a/game/client/NextBot/C_NextBot.h +++ /dev/null @@ -1,134 +0,0 @@ -// C_NextBot.h -// Next generation bot system -// Author: Michael Booth, April 2005 -//========= Copyright Valve Corporation, All rights reserved. ============// - -#ifndef _C_NEXT_BOT_H_ -#define _C_NEXT_BOT_H_ - -#include "c_ai_basenpc.h" - -//---------------------------------------------------------------------------------------------------------------- -/** -* The interface holding IBody information -*/ -class IBodyClient -{ -public: - enum ActivityType - { - MOTION_CONTROLLED_XY = 0x0001, // XY position and orientation of the bot is driven by the animation. - MOTION_CONTROLLED_Z = 0x0002, // Z position of the bot is driven by the animation. - ACTIVITY_UNINTERRUPTIBLE= 0x0004, // activity can't be changed until animation finishes - ACTIVITY_TRANSITORY = 0x0008, // a short animation that takes over from the underlying animation momentarily, resuming it upon completion - ENTINDEX_PLAYBACK_RATE = 0x0010, // played back at different rates based on entindex - }; -}; - - -//-------------------------------------------------------------------------------------------------------- -/** - * The client-side implementation of the NextBot - */ -class C_NextBotCombatCharacter : public C_BaseCombatCharacter -{ -public: - DECLARE_CLASS( C_NextBotCombatCharacter, C_BaseCombatCharacter ); - DECLARE_CLIENTCLASS(); - - C_NextBotCombatCharacter(); - virtual ~C_NextBotCombatCharacter(); - -public: - virtual void Spawn( void ); - virtual void UpdateClientSideAnimation( void ); - virtual ShadowType_t ShadowCastType( void ); - virtual bool IsNextBot() { return true; } - void ForceShadowCastType( bool bForce, ShadowType_t forcedShadowType = SHADOWS_NONE ) { m_bForceShadowType = bForce; m_forcedShadowType = forcedShadowType; } - bool GetForcedShadowCastType( ShadowType_t* pForcedShadowType ) const; - - // Local In View Data. - void InitFrustumData( void ) { m_bInFrustum = false; m_flFrustumDistanceSqr = FLT_MAX; m_nInFrustumFrame = gpGlobals->framecount; } - bool IsInFrustumValid( void ) { return ( m_nInFrustumFrame == gpGlobals->framecount ); } - void SetInFrustum( bool bInFrustum ) { m_bInFrustum = bInFrustum; } - bool IsInFrustum( void ) { return m_bInFrustum; } - void SetInFrustumDistanceSqr( float flDistance ) { m_flFrustumDistanceSqr = flDistance; } - float GetInFrustumDistanceSqr( void ) { return m_flFrustumDistanceSqr; } - -private: - ShadowType_t m_shadowType; // Are we LOD'd to simple shadows? - CountdownTimer m_shadowTimer; // Timer to throttle checks for shadow LOD - ShadowType_t m_forcedShadowType; - bool m_bForceShadowType; - void UpdateShadowLOD( void ); - - // Local In View Data. - int m_nInFrustumFrame; - bool m_bInFrustum; - float m_flFrustumDistanceSqr; - -private: - C_NextBotCombatCharacter( const C_NextBotCombatCharacter & ); // not defined, not accessible -}; - -//-------------------------------------------------------------------------------------------------------- -/** - * The C_NextBotManager manager - */ -class C_NextBotManager -{ -public: - C_NextBotManager( void ); - ~C_NextBotManager(); - - /** - * Execute functor for each NextBot in the system. - * If a functor returns false, stop iteration early - * and return false. - */ - template < typename Functor > - bool ForEachCombatCharacter( Functor &func ) - { - for( int i=0; i < m_botList.Count(); ++i ) - { - C_NextBotCombatCharacter *character = m_botList[i]; - if ( character->IsPlayer() ) - { - continue; - } - - if ( character->IsDormant() ) - { - continue; - } - - if ( !func( character ) ) - { - return false; - } - } - - return true; - } - - int GetActiveCount() { return m_botList.Count(); } - - bool SetupInFrustumData( void ); - bool IsInFrustumDataValid( void ) { return ( m_nInFrustumFrame == gpGlobals->framecount ); } - -private: - friend class C_NextBotCombatCharacter; - - void Register( C_NextBotCombatCharacter *bot ); - void UnRegister( C_NextBotCombatCharacter *bot ); - - CUtlVector< C_NextBotCombatCharacter * > m_botList; ///< list of all active NextBots - - int m_nInFrustumFrame; -}; - -// singleton accessor -extern C_NextBotManager &TheClientNextBots( void ); - - -#endif // _C_NEXT_BOT_H_ diff --git a/game/client/ProxyHealth.cpp b/game/client/ProxyHealth.cpp index 954c87dda..d39682357 100644 --- a/game/client/ProxyHealth.cpp +++ b/game/client/ProxyHealth.cpp @@ -1,19 +1,16 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ //=============================================================================// #include "cbase.h" -#include "functionproxy.h" -#include "toolframework_client.h" +#include "FunctionProxy.h" +#include "imaterialproxydict.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" -// forward declarations -void ToolFramework_RecordMaterialParams( IMaterial *pMaterial ); - //----------------------------------------------------------------------------- // Returns the player health (from 0 to 1) //----------------------------------------------------------------------------- @@ -47,13 +44,8 @@ void CProxyHealth::OnBind( void *pC_BaseEntity ) Assert( m_pResult ); SetFloatResult( pEntity->HealthFraction() * m_Factor.GetFloat() ); - - if ( ToolsEnabled() ) - { - ToolFramework_RecordMaterialParams( GetMaterial() ); - } } -EXPOSE_INTERFACE( CProxyHealth, IMaterialProxy, "Health" IMATERIAL_PROXY_INTERFACE_VERSION ); +EXPOSE_MATERIAL_PROXY( CProxyHealth, Health ); diff --git a/game/client/ScreenSpaceEffects.cpp b/game/client/ScreenSpaceEffects.cpp index 327939b80..c1e0d2014 100644 --- a/game/client/ScreenSpaceEffects.cpp +++ b/game/client/ScreenSpaceEffects.cpp @@ -1,15 +1,14 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// #include "cbase.h" -#include "KeyValues.h" +#include "keyvalues.h" #include "cdll_client_int.h" #include "view_scene.h" #include "viewrender.h" #include "tier0/icommandline.h" -#include "materialsystem/imesh.h" -#include "materialsystem/imaterial.h" -#include "materialsystem/imaterialsystemhardwareconfig.h" -#include "materialsystem/imaterialvar.h" +#include "materialsystem/IMesh.h" +#include "materialsystem/IMaterial.h" +#include "materialsystem/IMaterialSystemHardwareConfig.h" +#include "materialsystem/IMaterialVar.h" #include "ScreenSpaceEffects.h" diff --git a/game/client/ScreenSpaceEffects.h b/game/client/ScreenSpaceEffects.h index a93fa2297..346fd974b 100644 --- a/game/client/ScreenSpaceEffects.h +++ b/game/client/ScreenSpaceEffects.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // diff --git a/game/client/TeamBitmapImage.cpp b/game/client/TeamBitmapImage.cpp index 5333c888b..e50604dc6 100644 --- a/game/client/TeamBitmapImage.cpp +++ b/game/client/TeamBitmapImage.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: This is a panel which is rendered image on top of an entity // @@ -6,11 +6,11 @@ // $NoKeywords: $ //=============================================================================// #include "cbase.h" -#include "TeamBitmapImage.h" +#include "teambitmapimage.h" #include -#include "vgui_bitmapimage.h" -#include "panelmetaclassmgr.h" -#include "VGuiMatSurface/IMatSystemSurface.h" +#include "vgui_BitmapImage.h" +#include "PanelMetaClassMgr.h" +#include "vguimatsurface/IMatSystemSurface.h" #include // memdbgon must be the last include file in a .cpp file!!! @@ -42,14 +42,14 @@ CTeamBitmapImage::~CTeamBitmapImage() //----------------------------------------------------------------------------- bool CTeamBitmapImage::Init( vgui::Panel *pParent, KeyValues* pInitData, C_BaseEntity* pEntity ) { - static const char *pRelativeTeamNames[BITMAP_COUNT] = + static char *pRelativeTeamNames[BITMAP_COUNT] = { "NoTeam", "MyTeam", "EnemyTeam", }; - static const char *pAbsoluteTeamNames[BITMAP_COUNT] = + static char *pAbsoluteTeamNames[BITMAP_COUNT] = { "Team0", "Team1", @@ -59,7 +59,7 @@ bool CTeamBitmapImage::Init( vgui::Panel *pParent, KeyValues* pInitData, C_BaseE m_pEntity = pEntity; m_bRelativeTeams = (pInitData->GetInt( "relativeteam" ) != 0); - const char **ppTeamNames = m_bRelativeTeams ? pRelativeTeamNames : pAbsoluteTeamNames; + char **ppTeamNames = m_bRelativeTeams ? pRelativeTeamNames : pAbsoluteTeamNames; int i; for ( i = 0 ; i < BITMAP_COUNT; ++i ) diff --git a/game/client/TeamBitmapImage.h b/game/client/TeamBitmapImage.h index 5039698dc..6bbaff843 100644 --- a/game/client/TeamBitmapImage.h +++ b/game/client/TeamBitmapImage.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: This is a panel which is rendered image on top of an entity // diff --git a/game/client/ViewConeImage.cpp b/game/client/ViewConeImage.cpp index 095a3e9cd..64b64dad5 100644 --- a/game/client/ViewConeImage.cpp +++ b/game/client/ViewConeImage.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: This is a panel which is rendered image on top of an entity // @@ -9,7 +9,7 @@ #include "ViewConeImage.h" #include #include -#include "VGuiMatSurface/IMatSystemSurface.h" +#include "vguimatsurface/IMatSystemSurface.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" diff --git a/game/client/ViewConeImage.h b/game/client/ViewConeImage.h index cfa2ea159..7010e4358 100644 --- a/game/client/ViewConeImage.h +++ b/game/client/ViewConeImage.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: This is a panel which draws a viewcone // @@ -10,7 +10,7 @@ #define VIEWCONEIMAGE_H #include "shareddefs.h" -#include "vgui_bitmapimage.h" +#include "VGUI_BitmapImage.h" namespace vgui { diff --git a/game/client/WaterLODMaterialProxy.cpp b/game/client/WaterLODMaterialProxy.cpp index 61480ad79..c15fb3fb0 100644 --- a/game/client/WaterLODMaterialProxy.cpp +++ b/game/client/WaterLODMaterialProxy.cpp @@ -1,22 +1,19 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ //=============================================================================// #include "cbase.h" -#include "materialsystem/imaterialproxy.h" -#include "materialsystem/imaterial.h" -#include "materialsystem/imaterialvar.h" +#include "materialsystem/IMaterialProxy.h" +#include "materialsystem/IMaterial.h" +#include "materialsystem/IMaterialVar.h" #include "iviewrender.h" -#include "toolframework_client.h" +#include "imaterialproxydict.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" -// forward declarations -void ToolFramework_RecordMaterialParams( IMaterial *pMaterial ); - // no inputs, assumes that the results go into $CHEAPWATERSTARTDISTANCE and $CHEAPWATERENDDISTANCE class CWaterLODMaterialProxy : public IMaterialProxy { @@ -68,11 +65,6 @@ void CWaterLODMaterialProxy::OnBind( void *pC_BaseEntity ) view->GetWaterLODParams( start, end ); m_pCheapWaterStartDistanceVar->SetFloatValue( start ); m_pCheapWaterEndDistanceVar->SetFloatValue( end ); - - if ( ToolsEnabled() ) - { - ToolFramework_RecordMaterialParams( GetMaterial() ); - } } IMaterial *CWaterLODMaterialProxy::GetMaterial() @@ -80,4 +72,4 @@ IMaterial *CWaterLODMaterialProxy::GetMaterial() return m_pCheapWaterStartDistanceVar->GetOwningMaterial(); } -EXPOSE_INTERFACE( CWaterLODMaterialProxy, IMaterialProxy, "WaterLOD" IMATERIAL_PROXY_INTERFACE_VERSION ); +EXPOSE_MATERIAL_PROXY( CWaterLODMaterialProxy, WaterLOD ); diff --git a/game/client/WorldDimsProxy.cpp b/game/client/WorldDimsProxy.cpp index 0e0449f70..9895f7e80 100644 --- a/game/client/WorldDimsProxy.cpp +++ b/game/client/WorldDimsProxy.cpp @@ -1,22 +1,19 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // //=============================================================================// #include "cbase.h" -#include "materialsystem/imaterialproxy.h" -#include "materialsystem/imaterial.h" -#include "materialsystem/imaterialvar.h" +#include "materialsystem/IMaterialProxy.h" +#include "materialsystem/IMaterial.h" +#include "materialsystem/IMaterialVar.h" #include "c_world.h" -#include "toolframework_client.h" +#include "imaterialproxydict.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" -// forward declarations -void ToolFramework_RecordMaterialParams( IMaterial *pMaterial ); - class CWorldDimsProxy : public IMaterialProxy { public: @@ -61,11 +58,6 @@ void CWorldDimsProxy::OnBind( void *pC_BaseEntity ) m_pMaxsVar->SetVecValue( (const float*)&pWorld->m_WorldMaxs, 3 ); } } - - if ( ToolsEnabled() ) - { - ToolFramework_RecordMaterialParams( GetMaterial() ); - } } IMaterial *CWorldDimsProxy::GetMaterial() @@ -73,6 +65,6 @@ IMaterial *CWorldDimsProxy::GetMaterial() return m_pMinsVar->GetOwningMaterial(); } -EXPOSE_INTERFACE( CWorldDimsProxy, IMaterialProxy, "WorldDims" IMATERIAL_PROXY_INTERFACE_VERSION ); +EXPOSE_MATERIAL_PROXY( CWorldDimsProxy, WorldDims ); diff --git a/game/client/achievement_notification_panel.cpp b/game/client/achievement_notification_panel.cpp index 43fe0583a..b16923c01 100644 --- a/game/client/achievement_notification_panel.cpp +++ b/game/client/achievement_notification_panel.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ // // Purpose: // @@ -13,7 +13,7 @@ #include "ienginevgui.h" #include #include -#include +#include #include #include #include @@ -33,14 +33,14 @@ using namespace vgui; // Purpose: //----------------------------------------------------------------------------- -DECLARE_HUDELEMENT_DEPTH( CAchievementNotificationPanel, 100 ); +// DECLARE_HUDELEMENT_DEPTH( CAchievementNotificationPanel, 100 ); //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CAchievementNotificationPanel::CAchievementNotificationPanel( const char *pElementName ) : CHudElement( pElementName ), BaseClass( NULL, "AchievementNotificationPanel" ) { - Panel *pParent = g_pClientMode->GetViewport(); + Panel *pParent = GetClientMode()->GetViewport(); SetParent( pParent ); m_flHideTime = 0; @@ -85,7 +85,7 @@ void CAchievementNotificationPanel::PerformLayout( void ) SetBgColor( Color( 0, 0, 0, 0 ) ); m_pLabelHeading->SetBgColor( Color( 0, 0, 0, 0 ) ); m_pLabelTitle->SetBgColor( Color( 0, 0, 0, 0 ) ); - m_pPanelBackground->SetBgColor( Color( 128, 128, 128, 128 ) ); + m_pPanelBackground->SetBgColor( Color( 62,70,55, 200 ) ); } //----------------------------------------------------------------------------- @@ -94,14 +94,13 @@ void CAchievementNotificationPanel::PerformLayout( void ) void CAchievementNotificationPanel::FireGameEvent( IGameEvent * event ) { const char *name = event->GetName(); - if ( Q_strcmp( name, "achievement_event" ) == 0 ) + if ( 0 == Q_strcmp( name, "achievement_event" ) ) { const char *pchName = event->GetString( "achievement_name" ); int iCur = event->GetInt( "cur_val" ); int iMax = event->GetInt( "max_val" ); wchar_t szLocalizedName[256]=L""; -#ifndef DISABLE_STEAM if ( IsPC() ) { // shouldn't ever get achievement progress if steam not running and user logged in, but check just in case @@ -109,14 +108,13 @@ void CAchievementNotificationPanel::FireGameEvent( IGameEvent * event ) { Msg( "Steam not running, achievement progress notification not displayed\n" ); } - else + else { // use Steam to show achievement progress UI steamapicontext->SteamUserStats()->IndicateAchievementProgress( pchName, iCur, iMax ); } } - else -#endif + else { // on X360 we need to show our own achievement progress UI @@ -127,17 +125,10 @@ void CAchievementNotificationPanel::FireGameEvent( IGameEvent * event ) Q_wcsncpy( szLocalizedName, pchLocalizedName, sizeof( szLocalizedName ) ); // this is achievement progress, compose the message of form: " (<#>/)" - wchar_t szText[512]=L""; wchar_t szFmt[128]=L""; + wchar_t szText[512]=L""; wchar_t szNumFound[16]=L""; wchar_t szNumTotal[16]=L""; - - if( iCur >= iMax ) - { - AddNotification( pchName, g_pVGuiLocalize->Find( "#GameUI_Achievement_Awarded" ), szLocalizedName ); - return; - } - _snwprintf( szNumFound, ARRAYSIZE( szNumFound ), L"%i", iCur ); _snwprintf( szNumTotal, ARRAYSIZE( szNumTotal ), L"%i", iMax ); @@ -147,8 +138,7 @@ void CAchievementNotificationPanel::FireGameEvent( IGameEvent * event ) Q_wcsncpy( szFmt, pchFmt, sizeof( szFmt ) ); g_pVGuiLocalize->ConstructString( szText, sizeof( szText ), szFmt, 3, szLocalizedName, szNumFound, szNumTotal ); - - AddNotification( pchName, g_pVGuiLocalize->Find( "#GameUI_Achievement_Progress" ), szText ); + AddNotification( pchName, g_pVGuiLocalize->FindSafe( "#GameUI_Achievement_Progress" ), szText ); } } } @@ -255,13 +245,13 @@ void CAchievementNotificationPanel::SetXAndWide( Panel *pPanel, int x, int wide pPanel->SetWide( wide ); } -CON_COMMAND( achievement_notification_test, "Test the hud notification UI" ) +CON_COMMAND_F( achievement_notification_test, "Test the hud notification UI", FCVAR_CHEAT | FCVAR_DEVELOPMENTONLY ) { static int iCount=0; CAchievementNotificationPanel *pPanel = GET_HUDELEMENT( CAchievementNotificationPanel ); if ( pPanel ) - { + { pPanel->AddNotification( "HL2_KILL_ODESSAGUNSHIP", L"Achievement Progress", ( 0 == ( iCount % 2 ) ? L"Test Notification Message A (1/10)" : L"Test Message B" ) ); } diff --git a/game/client/achievement_notification_panel.h b/game/client/achievement_notification_panel.h index 2af9f109e..141446294 100644 --- a/game/client/achievement_notification_panel.h +++ b/game/client/achievement_notification_panel.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2006, Valve Corporation, All rights reserved. ============// // // Purpose: // diff --git a/game/client/alphamaterialproxy.cpp b/game/client/alphamaterialproxy.cpp deleted file mode 100644 index ecb1679ea..000000000 --- a/game/client/alphamaterialproxy.cpp +++ /dev/null @@ -1,62 +0,0 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -// $NoKeywords: $ -//=============================================================================// -#include "cbase.h" -#include "proxyentity.h" -#include "materialsystem/imaterial.h" -#include "materialsystem/imaterialvar.h" - -// memdbgon must be the last include file in a .cpp file!!! -#include "tier0/memdbgon.h" - -// $sineVar : name of variable that controls the alpha level (float) -class CAlphaMaterialProxy : public CEntityMaterialProxy -{ -public: - CAlphaMaterialProxy(); - virtual ~CAlphaMaterialProxy(); - virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues ); - virtual void OnBind( C_BaseEntity *pEntity ); - virtual IMaterial *GetMaterial(); - -private: - IMaterialVar *m_AlphaVar; -}; - -CAlphaMaterialProxy::CAlphaMaterialProxy() -{ - m_AlphaVar = NULL; -} - -CAlphaMaterialProxy::~CAlphaMaterialProxy() -{ -} - - -bool CAlphaMaterialProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues ) -{ - bool foundVar; - m_AlphaVar = pMaterial->FindVar( "$alpha", &foundVar, false ); - return foundVar; -} - -void CAlphaMaterialProxy::OnBind( C_BaseEntity *pEnt ) -{ - if (m_AlphaVar) - { - m_AlphaVar->SetFloatValue( pEnt->m_clrRender->a ); - } -} - -IMaterial *CAlphaMaterialProxy::GetMaterial() -{ - if ( !m_AlphaVar ) - return NULL; - - return m_AlphaVar->GetOwningMaterial(); -} - -EXPOSE_INTERFACE( CAlphaMaterialProxy, IMaterialProxy, "Alpha" IMATERIAL_PROXY_INTERFACE_VERSION ); diff --git a/game/client/animatedentitytextureproxy.cpp b/game/client/animatedentitytextureproxy.cpp index 47c7a629d..d7017170d 100644 --- a/game/client/animatedentitytextureproxy.cpp +++ b/game/client/animatedentitytextureproxy.cpp @@ -1,12 +1,13 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ //=============================================================================// #include "cbase.h" -#include "baseanimatedtextureproxy.h" +#include "BaseAnimatedTextureProxy.h" +#include "imaterialproxydict.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -21,7 +22,7 @@ class CAnimatedEntityTextureProxy : public CBaseAnimatedTextureProxy }; -EXPOSE_INTERFACE( CAnimatedEntityTextureProxy, IMaterialProxy, "AnimatedEntityTexture" IMATERIAL_PROXY_INTERFACE_VERSION ); +EXPOSE_MATERIAL_PROXY( CAnimatedEntityTextureProxy, AnimatedEntityTexture ); float CAnimatedEntityTextureProxy::GetAnimationStartTime( void* pArg ) { diff --git a/game/client/animatedoffsettextureproxy.cpp b/game/client/animatedoffsettextureproxy.cpp index bfe9facd5..63255cd15 100644 --- a/game/client/animatedoffsettextureproxy.cpp +++ b/game/client/animatedoffsettextureproxy.cpp @@ -1,12 +1,13 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // //=============================================================================// #include "cbase.h" -#include "baseanimatedtextureproxy.h" +#include "BaseAnimatedTextureProxy.h" +#include "imaterialproxydict.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -25,7 +26,7 @@ class CAnimatedOffsetTextureProxy : public CBaseAnimatedTextureProxy float m_flFrameOffset; }; -EXPOSE_INTERFACE( CAnimatedOffsetTextureProxy, IMaterialProxy, "AnimatedOffsetTexture" IMATERIAL_PROXY_INTERFACE_VERSION ); +EXPOSE_MATERIAL_PROXY( CAnimatedOffsetTextureProxy, AnimatedOffsetTexture ); //----------------------------------------------------------------------------- // Purpose: diff --git a/game/client/animatedtextureproxy.cpp b/game/client/animatedtextureproxy.cpp index 1d86bd8fc..bce6fc4bf 100644 --- a/game/client/animatedtextureproxy.cpp +++ b/game/client/animatedtextureproxy.cpp @@ -1,12 +1,13 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ //=============================================================================// #include "cbase.h" -#include "baseanimatedtextureproxy.h" +#include "BaseAnimatedTextureProxy.h" +#include "imaterialproxydict.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -18,7 +19,7 @@ class CAnimatedTextureProxy : public CBaseAnimatedTextureProxy virtual float GetAnimationStartTime( void* pBaseEntity ); }; -EXPOSE_INTERFACE( CAnimatedTextureProxy, IMaterialProxy, "AnimatedTexture" IMATERIAL_PROXY_INTERFACE_VERSION ); +EXPOSE_MATERIAL_PROXY( CAnimatedTextureProxy, AnimatedTexture ); #pragma warning (disable : 4100) diff --git a/game/client/animationlayer.h b/game/client/animationlayer.h index 4ac356349..5465f5320 100644 --- a/game/client/animationlayer.h +++ b/game/client/animationlayer.h @@ -1,8 +1,8 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // -//=============================================================================// +//===========================================================================// #ifndef ANIMATIONLAYER_H #define ANIMATIONLAYER_H @@ -12,8 +12,11 @@ #include "rangecheckedvar.h" -#include "lerp_functions.h" -#include "networkvar.h" +#include "tier1/lerp_functions.h" + +#ifdef CLIENT_DLL +class C_BaseAnimatingOverlay; +#endif class C_AnimationLayer { @@ -25,60 +28,135 @@ class C_AnimationLayer C_AnimationLayer(); void Reset(); +#ifdef CLIENT_DLL + void SetOwner( C_BaseAnimatingOverlay *pOverlay ); + C_BaseAnimatingOverlay *GetOwner() const; +#endif + void SetOrder( int order ); + bool IsActive( void ); + float GetFadeout( float flCurTime ); -public: + void SetSequence( int nSequence ); + void SetCycle( float flCycle ); + void SetPrevCycle( float flCycle ); + void SetPlaybackRate( float flPlaybackRate ); + void SetWeight( float flWeight ); - bool IsActive( void ); + int GetOrder() const; + int GetSequence( ) const; + float GetCycle( ) const; + float GetPrevCycle( ) const; + float GetPlaybackRate( ) const; + float GetWeight( ) const; + +#ifdef CLIENT_DLL + // If the weights, cycle or sequence #s changed due to interpolation then + // we'll need to recompute the bbox + int GetInvalidatePhysicsBits() const; + void SetInvalidatePhysicsBits( int iBit ) { m_nInvalidatePhysicsBits = iBit; } +#endif + +public: + float m_flLayerAnimtime; + float m_flLayerFadeOuttime; - CRangeCheckedVar m_nSequence; - CRangeCheckedVar m_flPrevCycle; - CRangeCheckedVar m_flWeight; +private: int m_nOrder; + CRangeCheckedVar m_nSequence; + CRangeCheckedVar m_flPrevCycle; + CRangeCheckedVar m_flWeight; // used for automatic crossfades between sequence changes CRangeCheckedVar m_flPlaybackRate; CRangeCheckedVar m_flCycle; - float GetFadeout( float flCurTime ); - - void BlendWeight(); - - float m_flLayerAnimtime; - float m_flLayerFadeOuttime; - - float m_flBlendIn; - float m_flBlendOut; +#ifdef CLIENT_DLL + C_BaseAnimatingOverlay *m_pOwner; + int m_nInvalidatePhysicsBits; +#endif - bool m_bClientBlend; + friend class C_BaseAnimatingOverlay; + friend C_AnimationLayer LoopingLerp( float flPercent, C_AnimationLayer& from, C_AnimationLayer& to ); + friend C_AnimationLayer Lerp( float flPercent, const C_AnimationLayer& from, const C_AnimationLayer& to ); + friend C_AnimationLayer LoopingLerp_Hermite( const C_AnimationLayer& current, float flPercent, C_AnimationLayer& prev, C_AnimationLayer& from, C_AnimationLayer& to ); + friend C_AnimationLayer Lerp_Hermite( const C_AnimationLayer& current, float flPercent, const C_AnimationLayer& prev, const C_AnimationLayer& from, const C_AnimationLayer& to ); + friend void Lerp_Clamp( C_AnimationLayer &val ); + friend int CheckForSequenceBoxChanges( const C_AnimationLayer& newLayer, const C_AnimationLayer& oldLayer ); }; + #ifdef CLIENT_DLL #define CAnimationLayer C_AnimationLayer #endif + inline C_AnimationLayer::C_AnimationLayer() { +#ifdef CLIENT_DLL + m_pOwner = NULL; + m_nInvalidatePhysicsBits = 0; +#endif + Reset(); } -inline void C_AnimationLayer::Reset() +#ifdef GAME_DLL + +inline void C_AnimationLayer::SetSequence( int nSequence ) +{ + m_nSequence = nSequence; +} + +inline void C_AnimationLayer::SetCycle( float flCycle ) +{ + m_flCycle = flCycle; +} + +inline void C_AnimationLayer::SetWeight( float flWeight ) +{ + m_flWeight = flWeight; +} + +#endif // GAME_DLL + +FORCEINLINE void C_AnimationLayer::SetPrevCycle( float flPrevCycle ) +{ + m_flPrevCycle = flPrevCycle; +} + +FORCEINLINE void C_AnimationLayer::SetPlaybackRate( float flPlaybackRate ) +{ + m_flPlaybackRate = flPlaybackRate; +} + +FORCEINLINE int C_AnimationLayer::GetSequence( ) const +{ + return m_nSequence; +} + +FORCEINLINE float C_AnimationLayer::GetCycle( ) const +{ + return m_flCycle; +} + +FORCEINLINE float C_AnimationLayer::GetPrevCycle( ) const +{ + return m_flPrevCycle; +} + +FORCEINLINE float C_AnimationLayer::GetPlaybackRate( ) const { - m_nSequence = 0; - m_flPrevCycle = 0; - m_flWeight = 0; - m_flPlaybackRate = 0; - m_flCycle = 0; - m_flLayerAnimtime = 0; - m_flLayerFadeOuttime = 0; - m_flBlendIn = 0; - m_flBlendOut = 0; - m_bClientBlend = false; + return m_flPlaybackRate; } +FORCEINLINE float C_AnimationLayer::GetWeight( ) const +{ + return m_flWeight; +} -inline void C_AnimationLayer::SetOrder( int order ) +FORCEINLINE int C_AnimationLayer::GetOrder() const { - m_nOrder = order; + return m_nOrder; } inline float C_AnimationLayer::GetFadeout( float flCurTime ) @@ -107,9 +185,19 @@ inline float C_AnimationLayer::GetFadeout( float flCurTime ) return s; } +#ifdef CLIENT_DLL +FORCEINLINE int C_AnimationLayer::GetInvalidatePhysicsBits() const +{ + return m_nInvalidatePhysicsBits; +} +#endif inline C_AnimationLayer LoopingLerp( float flPercent, C_AnimationLayer& from, C_AnimationLayer& to ) { +#ifdef CLIENT_DLL + Assert( from.GetOwner() == to.GetOwner() ); +#endif + C_AnimationLayer output; output.m_nSequence = to.m_nSequence; @@ -120,11 +208,18 @@ inline C_AnimationLayer LoopingLerp( float flPercent, C_AnimationLayer& from, C_ output.m_flLayerAnimtime = to.m_flLayerAnimtime; output.m_flLayerFadeOuttime = to.m_flLayerFadeOuttime; +#ifdef CLIENT_DLL + output.SetOwner( to.GetOwner() ); +#endif return output; } inline C_AnimationLayer Lerp( float flPercent, const C_AnimationLayer& from, const C_AnimationLayer& to ) { +#ifdef CLIENT_DLL + Assert( from.GetOwner() == to.GetOwner() ); +#endif + C_AnimationLayer output; output.m_nSequence = to.m_nSequence; @@ -135,37 +230,85 @@ inline C_AnimationLayer Lerp( float flPercent, const C_AnimationLayer& from, con output.m_flLayerAnimtime = to.m_flLayerAnimtime; output.m_flLayerFadeOuttime = to.m_flLayerFadeOuttime; +#ifdef CLIENT_DLL + output.SetOwner( to.GetOwner() ); +#endif return output; } -inline C_AnimationLayer LoopingLerp_Hermite( float flPercent, C_AnimationLayer& prev, C_AnimationLayer& from, C_AnimationLayer& to ) +inline int CheckForSequenceBoxChanges( const C_AnimationLayer& newLayer, const C_AnimationLayer& oldLayer ) +{ + int nChangeFlags = 0; + + bool bOldIsZero = ( oldLayer.GetWeight() == 0.0f ); + bool bNewIsZero = ( newLayer.GetWeight() == 0.0f ); + + if ( ( newLayer.GetSequence() != oldLayer.GetSequence() ) || + ( bNewIsZero != bOldIsZero ) ) + { + nChangeFlags |= SEQUENCE_CHANGED | BOUNDS_CHANGED; + } + + if ( newLayer.GetCycle() != oldLayer.GetCycle() ) + { + nChangeFlags |= ANIMATION_CHANGED; + } + + if ( newLayer.GetOrder() != oldLayer.GetOrder() ) + { + nChangeFlags |= BOUNDS_CHANGED; + } + + return nChangeFlags; +} + +inline C_AnimationLayer LoopingLerp_Hermite( const C_AnimationLayer& current, float flPercent, C_AnimationLayer& prev, C_AnimationLayer& from, C_AnimationLayer& to ) { +#ifdef CLIENT_DLL + Assert( prev.GetOwner() == from.GetOwner() ); + Assert( from.GetOwner() == to.GetOwner() ); +#endif + C_AnimationLayer output; output.m_nSequence = to.m_nSequence; - output.m_flCycle = LoopingLerp_Hermite( flPercent, (float)prev.m_flCycle, (float)from.m_flCycle, (float)to.m_flCycle ); + output.m_flCycle = LoopingLerp_Hermite( (float)current.m_flCycle, flPercent, (float)prev.m_flCycle, (float)from.m_flCycle, (float)to.m_flCycle ); output.m_flPrevCycle = to.m_flPrevCycle; output.m_flWeight = Lerp( flPercent, from.m_flWeight, to.m_flWeight ); output.m_nOrder = to.m_nOrder; output.m_flLayerAnimtime = to.m_flLayerAnimtime; output.m_flLayerFadeOuttime = to.m_flLayerFadeOuttime; + +#ifdef CLIENT_DLL + output.SetOwner( to.GetOwner() ); + output.m_nInvalidatePhysicsBits = CheckForSequenceBoxChanges( output, current ); +#endif return output; } // YWB: Specialization for interpolating euler angles via quaternions... -inline C_AnimationLayer Lerp_Hermite( float flPercent, const C_AnimationLayer& prev, const C_AnimationLayer& from, const C_AnimationLayer& to ) +inline C_AnimationLayer Lerp_Hermite( const C_AnimationLayer& current, float flPercent, const C_AnimationLayer& prev, const C_AnimationLayer& from, const C_AnimationLayer& to ) { +#ifdef CLIENT_DLL + Assert( prev.GetOwner() == from.GetOwner() ); + Assert( from.GetOwner() == to.GetOwner() ); +#endif + C_AnimationLayer output; output.m_nSequence = to.m_nSequence; - output.m_flCycle = Lerp_Hermite( flPercent, prev.m_flCycle, from.m_flCycle, to.m_flCycle ); + output.m_flCycle = Lerp_Hermite( (float)current.m_flCycle, flPercent, (float)prev.m_flCycle, (float)from.m_flCycle, (float)to.m_flCycle ); output.m_flPrevCycle = to.m_flPrevCycle; output.m_flWeight = Lerp( flPercent, from.m_flWeight, to.m_flWeight ); output.m_nOrder = to.m_nOrder; output.m_flLayerAnimtime = to.m_flLayerAnimtime; output.m_flLayerFadeOuttime = to.m_flLayerFadeOuttime; +#ifdef CLIENT_DLL + output.SetOwner( to.GetOwner() ); + output.m_nInvalidatePhysicsBits = CheckForSequenceBoxChanges( output, current ); +#endif return output; } @@ -180,34 +323,4 @@ inline void Lerp_Clamp( C_AnimationLayer &val ) Lerp_Clamp( val.m_flLayerFadeOuttime ); } -inline void C_AnimationLayer::BlendWeight() -{ - if ( !m_bClientBlend ) - return; - - m_flWeight = 1; - - // blend in? - if ( m_flBlendIn != 0.0f ) - { - if (m_flCycle < m_flBlendIn) - { - m_flWeight = m_flCycle / m_flBlendIn; - } - } - - // blend out? - if ( m_flBlendOut != 0.0f ) - { - if (m_flCycle > 1.0 - m_flBlendOut) - { - m_flWeight = (1.0 - m_flCycle) / m_flBlendOut; - } - } - - m_flWeight = 3.0 * m_flWeight * m_flWeight - 2.0 * m_flWeight * m_flWeight * m_flWeight; - if (m_nSequence == 0) - m_flWeight = 0; -} - #endif // ANIMATIONLAYER_H diff --git a/game/client/baseanimatedtextureproxy.cpp b/game/client/baseanimatedtextureproxy.cpp index 4365e8666..25a24090f 100644 --- a/game/client/baseanimatedtextureproxy.cpp +++ b/game/client/baseanimatedtextureproxy.cpp @@ -1,23 +1,19 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ //=============================================================================// #include "cbase.h" -#include "baseanimatedtextureproxy.h" -#include "materialsystem/imaterial.h" -#include "materialsystem/imaterialvar.h" -#include "materialsystem/itexture.h" +#include "BaseAnimatedTextureProxy.h" +#include "materialsystem/IMaterial.h" +#include "materialsystem/IMaterialVar.h" +#include "materialsystem/ITexture.h" #include "tier1/KeyValues.h" -#include "toolframework_client.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" -// forward declarations -void ToolFramework_RecordMaterialParams( IMaterial *pMaterial ); - //----------------------------------------------------------------------------- // Constructor, destructor: //----------------------------------------------------------------------------- @@ -125,11 +121,6 @@ void CBaseAnimatedTextureProxy::OnBind( void *pEntity ) } m_AnimatedTextureFrameNumVar->SetIntValue( intFrame ); - - if ( ToolsEnabled() ) - { - ToolFramework_RecordMaterialParams( GetMaterial() ); - } } IMaterial *CBaseAnimatedTextureProxy::GetMaterial() diff --git a/game/client/baseanimatedtextureproxy.h b/game/client/baseanimatedtextureproxy.h index fe6a5e593..1f6704f6c 100644 --- a/game/client/baseanimatedtextureproxy.h +++ b/game/client/baseanimatedtextureproxy.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // @@ -8,7 +8,7 @@ #ifndef BASEANIMATEDTEXTUREPROXY #define BASEANIMATEDTEXTUREPROXY -#include "materialsystem/imaterialproxy.h" +#include "materialsystem/IMaterialProxy.h" class IMaterial; class IMaterialVar; diff --git a/game/client/baseclientrendertargets.cpp b/game/client/baseclientrendertargets.cpp index 3aa642cf0..cba3d2d4c 100644 --- a/game/client/baseclientrendertargets.cpp +++ b/game/client/baseclientrendertargets.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: Implementation for CBaseClientRenderTargets class. // Provides Init functions for common render textures used by the engine. @@ -9,10 +9,20 @@ #include "cbase.h" #include "baseclientrendertargets.h" // header #include "materialsystem/imaterialsystemhardwareconfig.h" // Hardware config checks +#include "materialsystem/itexture.h" // Hardware config checks #include "tier0/icommandline.h" +#ifdef GAMEUI_UISYSTEM2_ENABLED +#include "gameui.h" +#endif + +// NOTE: This has to be the last file included! +#include "tier0/memdbgon.h" + +ConVar cl_disable_water_render_targets( "cl_disable_water_render_targets", "0" ); ITexture* CBaseClientRenderTargets::CreateWaterReflectionTexture( IMaterialSystem* pMaterialSystem, int iSize ) { + iSize = CommandLine()->ParmValue( "-reflectionTextureSize", iSize ); return pMaterialSystem->CreateNamedRenderTargetTextureEx2( "_rt_WaterReflection", iSize, iSize, RT_SIZE_PICMIP, @@ -24,6 +34,7 @@ ITexture* CBaseClientRenderTargets::CreateWaterReflectionTexture( IMaterialSyste ITexture* CBaseClientRenderTargets::CreateWaterRefractionTexture( IMaterialSystem* pMaterialSystem, int iSize ) { + iSize = CommandLine()->ParmValue( "-reflectionTextureSize", iSize ); return pMaterialSystem->CreateNamedRenderTargetTextureEx2( "_rt_WaterRefraction", iSize, iSize, RT_SIZE_PICMIP, @@ -36,6 +47,7 @@ ITexture* CBaseClientRenderTargets::CreateWaterRefractionTexture( IMaterialSyste ITexture* CBaseClientRenderTargets::CreateCameraTexture( IMaterialSystem* pMaterialSystem, int iSize ) { + iSize = CommandLine()->ParmValue( "-monitorTextureSize", iSize ); return pMaterialSystem->CreateNamedRenderTargetTextureEx2( "_rt_Camera", iSize, iSize, RT_SIZE_DEFAULT, @@ -45,6 +57,7 @@ ITexture* CBaseClientRenderTargets::CreateCameraTexture( IMaterialSystem* pMater CREATERENDERTARGETFLAGS_HDR ); } + //----------------------------------------------------------------------------- // Purpose: Called by the engine in material system init and shutdown. // Clients should override this in their inherited version, but the base @@ -52,14 +65,41 @@ ITexture* CBaseClientRenderTargets::CreateCameraTexture( IMaterialSystem* pMater // Input : pMaterialSystem - the engine's material system (our singleton is not yet inited at the time this is called) // pHardwareConfig - the user hardware config, useful for conditional render target setup //----------------------------------------------------------------------------- -void CBaseClientRenderTargets::InitClientRenderTargets( IMaterialSystem* pMaterialSystem, IMaterialSystemHardwareConfig* pHardwareConfig, int iWaterTextureSize, int iCameraTextureSize ) +void CBaseClientRenderTargets::SetupClientRenderTargets( IMaterialSystem* pMaterialSystem, IMaterialSystemHardwareConfig* pHardwareConfig, int iWaterTextureSize, int iCameraTextureSize ) { + IMaterialSystem *pSave = materials; + + // Make sure our config is loaded before we try to init rendertargets + ConfigureCurrentSystemLevel(); + // Water effects - m_WaterReflectionTexture.Init( CreateWaterReflectionTexture( pMaterialSystem, iWaterTextureSize ) ); - m_WaterRefractionTexture.Init( CreateWaterRefractionTexture( pMaterialSystem, iWaterTextureSize ) ); + materials = pMaterialSystem; // in case not initted yet for mat system util + g_pMaterialSystem = pMaterialSystem; + g_pMaterialSystemHardwareConfig = pHardwareConfig; + if ( iWaterTextureSize && !cl_disable_water_render_targets.GetBool() ) + { + m_WaterReflectionTexture.Init( CreateWaterReflectionTexture( pMaterialSystem, iWaterTextureSize ) ); + m_WaterRefractionTexture.Init( CreateWaterRefractionTexture( pMaterialSystem, iWaterTextureSize ) ); + } // Monitors - m_CameraTexture.Init( CreateCameraTexture( pMaterialSystem, iCameraTextureSize ) ); + if ( iCameraTextureSize ) + m_CameraTexture.Init( CreateCameraTexture( pMaterialSystem, iCameraTextureSize ) ); + + ITexture *pGlintTexture = pMaterialSystem->CreateNamedRenderTargetTextureEx2( + "_rt_eyeglint", 32, 32, RT_SIZE_NO_CHANGE, IMAGE_FORMAT_BGRA8888, MATERIAL_RT_DEPTH_NONE ); + pGlintTexture->IncrementReferenceCount(); + g_pClientShadowMgr->InitRenderTargets(); +#ifdef GAMEUI_UISYSTEM2_ENABLED + g_pGameUIGameSystem->InitRenderTargets(); +#endif + + materials = pSave; +} + +void CBaseClientRenderTargets::InitClientRenderTargets( IMaterialSystem* pMaterialSystem, IMaterialSystemHardwareConfig* pHardwareConfig ) +{ + SetupClientRenderTargets( pMaterialSystem, pHardwareConfig ); } //----------------------------------------------------------------------------- @@ -75,4 +115,11 @@ void CBaseClientRenderTargets::ShutdownClientRenderTargets() // Monitors m_CameraTexture.Shutdown(); -} \ No newline at end of file + + g_pClientShadowMgr->ShutdownRenderTargets(); + +} + +static CBaseClientRenderTargets g_BaseClientRenderTargets; +EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CBaseClientRenderTargets, IClientRenderTargets, + CLIENTRENDERTARGETS_INTERFACE_VERSION, g_BaseClientRenderTargets ); diff --git a/game/client/baseclientrendertargets.h b/game/client/baseclientrendertargets.h index a4c84d8a8..c2927cce4 100644 --- a/game/client/baseclientrendertargets.h +++ b/game/client/baseclientrendertargets.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: Has init functions for all the standard render targets used by most games. // Mods who wish to make their own render targets can inherit from this class @@ -14,7 +14,7 @@ // $Workfile: $ // $Date: $ // $NoKeywords: $ -//=============================================================================// +//===========================================================================// #ifndef CLIENTRENDERTARTETS_H_ #define CLIENTRENDERTARTETS_H_ #ifdef _WIN32 @@ -35,12 +35,13 @@ class CBaseClientRenderTargets : public IClientRenderTargets DECLARE_CLASS_GAMEROOT( CBaseClientRenderTargets, IClientRenderTargets ); public: // Interface called by engine during material system startup. - virtual void InitClientRenderTargets ( IMaterialSystem* pMaterialSystem, IMaterialSystemHardwareConfig* pHardwareConfig, int iWaterTextureSize = 1024, int iCameraTextureSize = 256 ); + virtual void InitClientRenderTargets ( IMaterialSystem* pMaterialSystem, IMaterialSystemHardwareConfig* pHardwareConfig ); // Shutdown all custom render targets here. virtual void ShutdownClientRenderTargets ( void ); protected: - + void SetupClientRenderTargets( IMaterialSystem* pMaterialSystem, IMaterialSystemHardwareConfig* pHardwareConfig, int iWaterTextureSize = 1024, int iCameraTextureSize = 256 ); + // Standard render textures used by most mods-- Classes inheriting from // this can choose to init these or not depending on their needs. @@ -51,9 +52,6 @@ class CBaseClientRenderTargets : public IClientRenderTargets // Used for monitors CTextureReference m_CameraTexture; - // Used for the HUD in stereo and head tracking mode - CTextureReference m_UITexture; - // Init functions for the common render targets ITexture* CreateWaterReflectionTexture( IMaterialSystem* pMaterialSystem, int iSize = 1024 ); ITexture* CreateWaterRefractionTexture( IMaterialSystem* pMaterialSystem, int iSize = 1024 ); diff --git a/game/client/basepresence.cpp b/game/client/basepresence.cpp deleted file mode 100644 index ce4c7c7b7..000000000 --- a/game/client/basepresence.cpp +++ /dev/null @@ -1,94 +0,0 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// -// -// Purpose: Base presence implementation for PC -// -//=====================================================================================// - -#include "cbase.h" -#include "basepresence.h" - -// memdbgon must be the last include file in a .cpp file!!! -#include "tier0/memdbgon.h" - -// Default global singleton. Mods should override this. -static CBasePresence s_basePresence; -IPresence *presence = NULL; - -//----------------------------------------------------------------------------- -// Steam version of Rich Presence is a WIP, so PC implementation is stubbed for now. -//----------------------------------------------------------------------------- -bool CBasePresence::Init( void ) -{ - if ( !presence ) - { - // Mod didn't override, default to base implementation - presence = &s_basePresence; - } - return true; -} -void CBasePresence::Shutdown( void ) -{ - // TODO: Implement for PC -} -void CBasePresence::Update( float frametime ) -{ - // TODO: Implement for PC -} -void CBasePresence::UserSetContext( unsigned int nUserIndex, unsigned int nContextId, unsigned int nContextValue, bool bAsync ) -{ - // TODO: Implement for PC -} -void CBasePresence::UserSetProperty( unsigned int nUserIndex, unsigned int nPropertyId, unsigned int nBytes, const void *pvValue, bool bAsync ) -{ - // TODO: Implement for PC -} -void CBasePresence::SetupGameProperties( CUtlVector< XUSER_CONTEXT > &contexts, CUtlVector< XUSER_PROPERTY > &properties ) -{ - // TODO: Implement for PC -} -unsigned int CBasePresence::GetPresenceID( const char *pIDName ) -{ - return 0; -} -const char *CBasePresence::GetPropertyIdString( const uint id ) -{ - return NULL; -} -void CBasePresence::GetPropertyDisplayString( uint id, uint value, char *pOutput, int nBytes ) -{ -} -void CBasePresence::StartStatsReporting( HANDLE handle, bool bArbitrated ) -{ -} -void CBasePresence::SetStat( uint iPropertyId, int iPropertyValue, int dataType ) -{ -} -void CBasePresence::UploadStats() -{ -} - -//--------------------------------------------------------- -// Debug support -//--------------------------------------------------------- -void CBasePresence::DebugUserSetContext( const CCommand &args ) -{ - if ( args.ArgC() == 3 ) - { - UserSetContext( 0, atoi( args.Arg( 1 ) ), atoi( args.Arg( 2 ) ) ); - } - else - { - Warning( "user_context \n" ); - } -} -void CBasePresence::DebugUserSetProperty( const CCommand &args ) -{ - if ( args.ArgC() == 3 ) - { - UserSetProperty( 0, strtoul( args.Arg( 1 ), NULL, 0 ), sizeof(int), args.Arg( 2 ) ); - } - else - { - Warning( "user_property \n" ); - } -} diff --git a/game/client/basepresence.h b/game/client/basepresence.h deleted file mode 100644 index c23a33cb1..000000000 --- a/game/client/basepresence.h +++ /dev/null @@ -1,55 +0,0 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// -// -// Purpose: Base implementation of the IPresence interface -// -//============================================================================= - -#ifndef BASEPRESENCE_H -#define BASEPRESENCE_H -#ifdef _WIN32 -#pragma once -#endif - -#include "ipresence.h" -#include "igamesystem.h" - -//----------------------------------------------------------------------------- -// Purpose: Common implementation for setting user contexts and properties. -// Each client should inherit from this to implement mod-specific presence info. -//----------------------------------------------------------------------------- -class CBasePresence : public IPresence, public CAutoGameSystemPerFrame -{ -public: - // CBaseGameSystemPerFrame overrides - virtual bool Init( void ); - virtual void Shutdown( void ); - virtual void Update( float frametime ); - virtual char const *Name( void ) { return "presence"; } - - // IPresence Interface - virtual void UserSetContext( unsigned int nUserIndex, unsigned int nContextId, unsigned int nContextValue, bool bAsync = false ); - virtual void UserSetProperty( unsigned int nUserIndex, unsigned int nPropertyId, unsigned int nBytes, const void *pvValue, bool bAsync = false ); - virtual void SetupGameProperties( CUtlVector< XUSER_CONTEXT > &contexts, CUtlVector< XUSER_PROPERTY > &properties ); - virtual uint GetPresenceID( const char *pIdName ); - virtual void GetPropertyDisplayString( uint id, uint value, char *pOutput, int nBytes ); - virtual const char *GetPropertyIdString( const uint id ); - - // Stats reporting - virtual void StartStatsReporting( HANDLE handle, bool bArbitrated ); - virtual void SetStat( uint iPropertyId, int iPropertyValue, int dataType ); - virtual void UploadStats(); - -protected: - bool m_bArbitrated; - bool m_bReportingStats; - HANDLE m_hSession; - CUtlVector< XUSER_PROPERTY > m_PlayerStats; - - //--------------------------------------------------------- - // Debug support - //--------------------------------------------------------- - CON_COMMAND_MEMBER_F( CBasePresence, "user_context", DebugUserSetContext, "Set a Rich Presence Context: user_context ", 0 ) - CON_COMMAND_MEMBER_F( CBasePresence, "user_property", DebugUserSetProperty, "Set a Rich Presence Property: user_property ", 0 ) -}; - -#endif // BASEPRESENCE_H diff --git a/game/client/basepresence_xbox.cpp b/game/client/basepresence_xbox.cpp deleted file mode 100644 index 96adca98a..000000000 --- a/game/client/basepresence_xbox.cpp +++ /dev/null @@ -1,167 +0,0 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// -// -// Purpose: Base rich presence implementation for Xbox360 -// -//=====================================================================================// - -#include "cbase.h" -#include "basepresence.h" -#include "cdll_client_int.h" -#include "ixboxsystem.h" - -// memdbgon must be the last include file in a .cpp file!!! -#include "tier0/memdbgon.h" - -// Default global instance. Mods should override this. -static CBasePresence s_basePresence; -IPresence *presence = NULL; - -//----------------------------------------------------------------------------- -// Purpose: Init -//----------------------------------------------------------------------------- -bool CBasePresence::Init( void ) -{ - if ( !presence ) - { - // Mod didn't override, default to base implementation - presence = &s_basePresence; - } - return true; -} - - -//----------------------------------------------------------------------------- -// Purpose: Shutdown -//----------------------------------------------------------------------------- -void CBasePresence::Shutdown( void ) -{ - // Do nothing -} - - -//----------------------------------------------------------------------------- -// Purpose: Per-frame update -//----------------------------------------------------------------------------- -void CBasePresence::Update( float frametime ) -{ - // Do nothing -} - - -//----------------------------------------------------------------------------- -// Contexts are strings that describe the current state of the game. -//----------------------------------------------------------------------------- -void CBasePresence::UserSetContext( unsigned int nUserIndex, unsigned int nContextId, unsigned int nContextValue, bool bAsync ) -{ - if ( !xboxsystem->UserSetContext( nUserIndex, nContextId, nContextValue, bAsync ) ) - { - Warning( "CBasePresence: UserSetContext failed.\n" ); - } -} - - -//----------------------------------------------------------------------------- -// Properties are (usually) numeric values that can be insterted into context strings. -//----------------------------------------------------------------------------- -void CBasePresence::UserSetProperty( unsigned int nUserIndex, unsigned int nPropertyId, unsigned int nBytes, const void *pvValue, bool bAsync ) -{ - if ( !xboxsystem->UserSetProperty( nUserIndex, nPropertyId, nBytes, pvValue, bAsync ) ) - { - Warning( "CBasePresence: UserSetProperty failed.\n" ); - } -} - -//----------------------------------------------------------------------------- -// Get game session properties from matchmaking. -//----------------------------------------------------------------------------- -void CBasePresence::SetupGameProperties( CUtlVector< XUSER_CONTEXT > &contexts, CUtlVector< XUSER_PROPERTY > &properties ) -{ - Assert( 0 ); -} - -//----------------------------------------------------------------------------- -// Convert a string to a presence ID. -//----------------------------------------------------------------------------- -uint CBasePresence::GetPresenceID( const char *pIdName ) -{ - Assert( 0 ); - return 0; -} - -//----------------------------------------------------------------------------- -// Convert a presence ID to a string. -//----------------------------------------------------------------------------- -const char *CBasePresence::GetPropertyIdString( const uint id ) -{ - Assert( 0 ); - return NULL; -} - -//----------------------------------------------------------------------------- -// Get display string for a game property. -//----------------------------------------------------------------------------- -void CBasePresence::GetPropertyDisplayString( uint id, uint value, char *pOutput, int nBytes ) -{ - Assert( 0 ); -} - -//----------------------------------------------------------------------------- -// Set up for reporting stats to Live. -//----------------------------------------------------------------------------- -void CBasePresence::StartStatsReporting( HANDLE handle, bool bArbitrated ) -{ - m_bArbitrated = bArbitrated; - m_hSession = handle; - m_bReportingStats = true; - m_PlayerStats.RemoveAll(); -} - -//----------------------------------------------------------------------------- -// Set a specific stat property. -//----------------------------------------------------------------------------- -void CBasePresence::SetStat( uint iPropertyId, int iPropertyValue, int dataType ) -{ - if ( m_bReportingStats ) - { - XUSER_PROPERTY prop; - prop.dwPropertyId = iPropertyId; - prop.value.nData = iPropertyValue; - prop.value.type = dataType; - m_PlayerStats.AddToTail( prop ); - } -} - -//----------------------------------------------------------------------------- -// Upload the stats to Live. -//----------------------------------------------------------------------------- -void CBasePresence::UploadStats() -{ - Assert( 0 ); -} - -//--------------------------------------------------------- -// Debug support -//--------------------------------------------------------- -void CBasePresence::DebugUserSetContext( const CCommand &args ) -{ - if ( args.ArgC() == 3 ) - { - UserSetContext( XBX_GetPrimaryUserId(), atoi( args.Arg( 1 ) ), atoi( args.Arg( 2 ) ) ); - } - else - { - Warning( "user_context \n" ); - } -} -void CBasePresence::DebugUserSetProperty( const CCommand &args ) -{ - if ( args.ArgC() == 3 ) - { - int value = atoi( args.Arg( 2 ) ); - UserSetProperty( XBX_GetPrimaryUserId(), strtoul( args.Arg( 1 ), NULL, 0 ), sizeof(int), &value ); - } - else - { - Warning( "user_property \n" ); - } -} diff --git a/game/client/beamdraw.cpp b/game/client/beamdraw.cpp index 8fc7d4995..006eacd34 100644 --- a/game/client/beamdraw.cpp +++ b/game/client/beamdraw.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // @@ -9,7 +9,7 @@ #include "cbase.h" #include "beamdraw.h" #include "enginesprite.h" -#include "iviewrender_beams.h" +#include "IViewRender_Beams.h" #include "view.h" #include "iviewrender.h" #include "engine/ivmodelinfo.h" @@ -47,7 +47,7 @@ CEngineSprite *Draw_SetSpriteTexture( const model_t *pSpriteModel, int frame, in if ( ShouldDrawInWireFrameMode() || r_DrawBeams.GetInt() == 2 ) { if ( !g_pBeamWireframeMaterial ) - g_pBeamWireframeMaterial = materials->FindMaterial( "shadertest/wireframevertexcolor", TEXTURE_GROUP_OTHER ); + g_pBeamWireframeMaterial = materials->FindMaterial( "debug/debugwireframevertexcolor", TEXTURE_GROUP_OTHER ); pRenderContext->Bind( g_pBeamWireframeMaterial, NULL ); return psprite; } @@ -320,7 +320,7 @@ void DrawSegs( int noise_divisions, float *prgNoise, const model_t* spritemodel, float fadeFraction = fadeLength/ delta.Length(); // BUGBUG: This code generates NANs when fadeFraction is zero! REVIST! - fadeFraction = clamp(fadeFraction,1.e-6f,1.f); + fadeFraction = clamp(fadeFraction,1e-6,1); // Choose two vectors that are perpendicular to the beam Vector perp1; @@ -335,7 +335,6 @@ void DrawSegs( int noise_divisions, float *prgNoise, const model_t* spritemodel, { Assert( noiseIndex < (noise_divisions<<16) ); BeamSeg_t curSeg; - curSeg.m_flAlpha = 1; fraction = i * div; @@ -371,7 +370,9 @@ void DrawSegs( int noise_divisions, float *prgNoise, const model_t* spritemodel, brightness = 1; } - VectorScale( *((Vector*)color), brightness, curSeg.m_vColor ); + Vector vecTemp; + VectorScale( *((Vector*)color), brightness, vecTemp ); + curSeg.SetColor( vecTemp, 1.0f ); // UNDONE: Make this a spline instead of just a line? VectorMA( source, fraction, delta, curSeg.m_vPos ); @@ -450,9 +451,9 @@ void CalcSegOrigin( Vector *vecOut, int iPoint, int noise_divisions, float *prgN { float s, c; SinCos( fraction*M_PI*length + freq, &s, &c ); - VectorMA( *vecOut, factor * s, MainViewUp(), *vecOut ); + VectorMA( *vecOut, factor * s, CurrentViewUp(), *vecOut ); // Rotate the noise along the perpendicular axis a bit to keep the bolt from looking diagonal - VectorMA( *vecOut, factor * c, MainViewRight(), *vecOut ); + VectorMA( *vecOut, factor * c, CurrentViewRight(), *vecOut ); } else { @@ -522,7 +523,7 @@ void DrawTeslaSegs( int noise_divisions, float *prgNoise, const model_t* spritem float fadeFraction = fadeLength/ delta.Length(); // BUGBUG: This code generates NANs when fadeFraction is zero! REVIST! - fadeFraction = clamp(fadeFraction,1.e-6f,1.f); + fadeFraction = clamp(fadeFraction,1e-6,1); Vector perp; ComputeBeamPerpendicular( delta, &perp ); @@ -542,7 +543,6 @@ void DrawTeslaSegs( int noise_divisions, float *prgNoise, const model_t* spritem for ( i = 0; i < segments; i++ ) { BeamSeg_t curSeg; - curSeg.m_flAlpha = 1; fraction = i * div; @@ -578,7 +578,9 @@ void DrawTeslaSegs( int noise_divisions, float *prgNoise, const model_t* spritem brightness = 1; } - VectorScale( *((Vector*)color), brightness, curSeg.m_vColor ); + Vector vecTemp; + VectorScale( *((Vector*)color), brightness, vecTemp ); + curSeg.SetColor( vecTemp, 1.0f ); CalcSegOrigin( &curSeg.m_vPos, i, noise_divisions, prgNoise, source, delta, perp, segments, freq, scale, fraction, flags ); @@ -589,7 +591,7 @@ void DrawTeslaSegs( int noise_divisions, float *prgNoise, const model_t* spritem curSeg.m_flWidth = ((fraction*(endWidth-startWidth))+startWidth) * 2; // Reduce the width by the current number of branches we've had - for ( int j = 0; j < iBranches; j++ ) + for ( int j = 0; i < iBranches; j++ ) { curSeg.m_flWidth *= 0.5; } @@ -614,12 +616,12 @@ void DrawTeslaSegs( int noise_divisions, float *prgNoise, const model_t* spritem // Get an endpoint for the new branch vecStart = curSeg.m_vPos; - vecEnd = source + delta + (MainViewUp() * 32) + (MainViewRight() * 32); + vecEnd = source + delta + (CurrentViewUp() * 32) + (CurrentViewRight() * 32); vecEnd -= vecStart; // Reduce the end width by the current number of branches we've had flEndWidth = endWidth; - for ( int j = 0; j < iBranches; j++ ) + for ( int j = 0; i < iBranches; j++ ) { flEndWidth *= 0.5; } @@ -798,10 +800,9 @@ void DrawSplineSegs( int noise_divisions, float *prgNoise, brightness = 0; BeamSeg_t seg; - seg.m_flAlpha = 1; VectorScale( color, brightness, scaledColor ); - seg.m_vColor.Init( scaledColor[0], scaledColor[1], scaledColor[2] ); + seg.SetColor( scaledColor[0], scaledColor[1], scaledColor[2], 1.0f ); // ------------------------------------------------- @@ -1495,7 +1496,6 @@ void DrawBeamQuadratic( const Vector &start, const Vector &control, const Vector beamDraw.Start( pRenderContext, subdivisions+1, NULL ); BeamSeg_t seg; - seg.m_flAlpha = 1.0; seg.m_flWidth = width; float t = 0; @@ -1513,11 +1513,12 @@ void DrawBeamQuadratic( const Vector &start, const Vector &control, const Vector if ( i == 0 || i == subdivisions ) { // HACK: fade out the ends a bit - seg.m_vColor = vec3_origin; + seg.m_color.r = seg.m_color.g = seg.m_color.b = 0; + seg.m_color.a = 255; } else { - seg.m_vColor = color; + seg.SetColor( color, 1.0f ); } beamDraw.NextSeg( &seg ); } diff --git a/game/client/beamdraw.h b/game/client/beamdraw.h index c4a0e6eb9..24111cd70 100644 --- a/game/client/beamdraw.h +++ b/game/client/beamdraw.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // @@ -41,10 +41,7 @@ class Beam_t : public CDefaultClientRenderable virtual const matrix3x4_t &RenderableToWorldTransform(); virtual void GetRenderBounds( Vector& mins, Vector& maxs ); virtual bool ShouldDraw( void ); - virtual bool IsTransparent( void ); - virtual int DrawModel( int flags ); - virtual void ComputeFxBlend( ); - virtual int GetFxBlend( ); + virtual int DrawModel( int flags, const RenderableInstance_t &instance ); // Resets the beam state void Reset(); @@ -121,10 +118,7 @@ class Beam_t : public CDefaultClientRenderable float m_flHDRColorScale; -#ifdef PORTAL - bool m_bDrawInMainRender; - bool m_bDrawInPortalRender; -#endif //#ifdef PORTAL + }; diff --git a/game/client/bone_merge_cache.cpp b/game/client/bone_merge_cache.cpp index 6ef767ead..41238d512 100644 --- a/game/client/bone_merge_cache.cpp +++ b/game/client/bone_merge_cache.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // @@ -22,7 +22,6 @@ CBoneMergeCache::CBoneMergeCache() m_pOwner = NULL; m_pFollow = NULL; m_pFollowHdr = NULL; - m_pFollowRenderHdr = NULL; m_pOwnerHdr = NULL; m_nFollowBoneSetupMask = 0; } @@ -32,52 +31,40 @@ void CBoneMergeCache::Init( C_BaseAnimating *pOwner ) m_pOwner = pOwner; m_pFollow = NULL; m_pFollowHdr = NULL; - m_pFollowRenderHdr = NULL; m_pOwnerHdr = NULL; m_nFollowBoneSetupMask = 0; } void CBoneMergeCache::UpdateCache() { - CStudioHdr *pOwnerHdr = m_pOwner ? m_pOwner->GetModelPtr() : NULL; + if ( !m_pOwner ) + return; + + CStudioHdr *pOwnerHdr = m_pOwner->GetModelPtr(); if ( !pOwnerHdr ) - { - if ( m_pOwnerHdr ) - { - // Owner's model got swapped out - m_MergedBones.Purge(); - m_BoneMergeBits.Purge(); - m_pFollow = NULL; - m_pFollowHdr = NULL; - m_pFollowRenderHdr = NULL; - m_pOwnerHdr = NULL; - m_nFollowBoneSetupMask = 0; - } return; - } C_BaseAnimating *pTestFollow = m_pOwner->FindFollowedEntity(); CStudioHdr *pTestHdr = (pTestFollow ? pTestFollow->GetModelPtr() : NULL); - const studiohdr_t *pTestStudioHDR = (pTestHdr ? pTestHdr->GetRenderHdr() : NULL); - if ( pTestFollow != m_pFollow || pTestHdr != m_pFollowHdr || pTestStudioHDR != m_pFollowRenderHdr || pOwnerHdr != m_pOwnerHdr ) + // if the follow parent has changed, or any of the underlying models has changed, reset the MergedBones list + if ( pTestFollow != m_pFollow || pTestHdr != m_pFollowHdr || pOwnerHdr != m_pOwnerHdr ) { m_MergedBones.Purge(); - m_BoneMergeBits.Purge(); // Update the cache. if ( pTestFollow && pTestHdr && pOwnerHdr ) { m_pFollow = pTestFollow; m_pFollowHdr = pTestHdr; - m_pFollowRenderHdr = pTestStudioHDR; m_pOwnerHdr = pOwnerHdr; - m_BoneMergeBits.SetSize( pOwnerHdr->numbones() / 8 + 1 ); - memset( m_BoneMergeBits.Base(), 0, m_BoneMergeBits.Count() ); + m_BoneMergeBits.Resize( pOwnerHdr->numbones() ); + m_BoneMergeBits.ClearAll(); mstudiobone_t *pOwnerBones = m_pOwnerHdr->pBone( 0 ); m_nFollowBoneSetupMask = BONE_USED_BY_BONE_MERGE; + const bool bDeveloperDebugPrints = developer.GetBool(); for ( int i = 0; i < m_pOwnerHdr->numbones(); i++ ) { int parentBoneIndex = Studio_BoneIndexByName( m_pFollowHdr, pOwnerBones[i].pszName() ); @@ -89,14 +76,32 @@ void CBoneMergeCache::UpdateCache() mergedBone.m_iMyBone = i; mergedBone.m_iParentBone = parentBoneIndex; m_MergedBones.AddToTail( mergedBone ); + m_BoneMergeBits.Set( i ); - m_BoneMergeBits[i>>3] |= ( 1 << ( i & 7 ) ); - + // Warn for performance-negative ad hoc bone merges. They're bad. Don't do them. if ( ( m_pFollowHdr->boneFlags( parentBoneIndex ) & BONE_USED_BY_BONE_MERGE ) == 0 ) { - m_nFollowBoneSetupMask = BONE_USED_BY_ANYTHING; -// Warning("Performance warning: Merge with '%s'. Mark bone '%s' in model '%s' as being used by bone merge in the .qc!\n", -// pOwnerHdr->pszName(), m_pFollowHdr->pBone( parentBoneIndex )->pszName(), m_pFollowHdr->pszName() ); + // go ahead and mark the bone and its parents + int n = parentBoneIndex; + while (n != -1) + { + m_pFollowHdr->setBoneFlags( n, BONE_USED_BY_BONE_MERGE ); + n = m_pFollowHdr->boneParent( n ); + } + // dump out a warning + if ( bDeveloperDebugPrints ) + { + char sz[ 256 ]; + Q_snprintf( sz, sizeof( sz ), "Performance warning: Add $bonemerge \"%s\" to QC that builds \"%s\"\n", + m_pFollowHdr->pBone( parentBoneIndex )->pszName(), m_pFollowHdr->pszName() ); + + static CUtlSymbolTableMT s_FollowerWarnings; + if ( UTL_INVAL_SYMBOL == s_FollowerWarnings.Find( sz ) ) + { + s_FollowerWarnings.AddString( sz ); + Warning( "%s", sz ); + } + } } } @@ -110,19 +115,13 @@ void CBoneMergeCache::UpdateCache() { m_pFollow = NULL; m_pFollowHdr = NULL; - m_pFollowRenderHdr = NULL; m_pOwnerHdr = NULL; m_nFollowBoneSetupMask = 0; } } } - -#ifdef STAGING_ONLY -ConVar r_captain_canteen_is_angry ( "r_captain_canteen_is_angry", "1" ); -#endif - -void CBoneMergeCache::MergeMatchingBones( int boneMask ) +void CBoneMergeCache::MergeMatchingBones( int boneMask, CBoneBitList &boneComputed ) { UpdateCache(); @@ -131,66 +130,7 @@ void CBoneMergeCache::MergeMatchingBones( int boneMask ) return; // Have the entity we're following setup its bones. - bool bWorked = m_pFollow->SetupBones( NULL, -1, m_nFollowBoneSetupMask, gpGlobals->curtime ); - // We suspect there's some cases where SetupBones couldn't do its thing, and then this causes Captain Canteen. - Assert ( bWorked ); - if ( !bWorked ) - { - // Usually this means your parent is invisible or gone or whatever. - // This routine has no way to tell its caller not to draw itself unfortunately. - // But we can shrink all the bones down to zero size. - // But it might still spawn particle systems? :-( - matrix3x4_t NewBone; - MatrixScaleByZero ( NewBone ); - MatrixSetTranslation ( Vector ( 0.0f, 0.0f, 0.0f ), NewBone ); -#ifdef STAGING_ONLY - if ( r_captain_canteen_is_angry.GetBool() ) - { - // We actually want to see when Captain Canteen happened, and make it really obvious that (a) he was here and (b) this code would have fixed him. - float HowAngry = 20.0f; // Leon's getting larger! - MatrixSetColumn ( Vector ( HowAngry, 0.0f, 0.0f ), 0, NewBone ); - MatrixSetColumn ( Vector ( 0.0f, HowAngry, 0.0f ), 1, NewBone ); - MatrixSetColumn ( Vector ( 0.0f, 0.0f, HowAngry ), 2, NewBone ); - } -#endif - - for ( int i=0; i < m_MergedBones.Count(); i++ ) - { - int iOwnerBone = m_MergedBones[i].m_iMyBone; - - // Only update bones reference by the bone mask. - if ( !( m_pOwnerHdr->boneFlags( iOwnerBone ) & boneMask ) ) - continue; - - m_pOwner->GetBoneForWrite( iOwnerBone ) = NewBone; - } - } - else - { - // Now copy the bone matrices. - for ( int i=0; i < m_MergedBones.Count(); i++ ) - { - int iOwnerBone = m_MergedBones[i].m_iMyBone; - int iParentBone = m_MergedBones[i].m_iParentBone; - - // Only update bones reference by the bone mask. - if ( !( m_pOwnerHdr->boneFlags( iOwnerBone ) & boneMask ) ) - continue; - - MatrixCopy( m_pFollow->GetBone( iParentBone ), m_pOwner->GetBoneForWrite( iOwnerBone ) ); - } - } -} - - - // copy bones instead of matrices -void CBoneMergeCache::CopyParentToChild( const Vector parentPos[], const Quaternion parentQ[], Vector childPos[], Quaternion childQ[], int boneMask ) -{ - UpdateCache(); - - // If this is set, then all the other cache data is set. - if ( !m_pOwnerHdr || m_MergedBones.Count() == 0 ) - return; + m_pFollow->SetupBones( NULL, -1, m_nFollowBoneSetupMask, gpGlobals->curtime ); // Now copy the bone matrices. for ( int i=0; i < m_MergedBones.Count(); i++ ) @@ -198,41 +138,19 @@ void CBoneMergeCache::CopyParentToChild( const Vector parentPos[], const Quatern int iOwnerBone = m_MergedBones[i].m_iMyBone; int iParentBone = m_MergedBones[i].m_iParentBone; - if ( m_pOwnerHdr->boneParent( iOwnerBone ) == -1 || m_pFollowHdr->boneParent( iParentBone ) == -1 ) - continue; - // Only update bones reference by the bone mask. if ( !( m_pOwnerHdr->boneFlags( iOwnerBone ) & boneMask ) ) continue; - childPos[ iOwnerBone ] = parentPos[ iParentBone ]; - childQ[ iOwnerBone ] = parentQ[ iParentBone ]; - } -} - -void CBoneMergeCache::CopyChildToParent( const Vector childPos[], const Quaternion childQ[], Vector parentPos[], Quaternion parentQ[], int boneMask ) -{ - UpdateCache(); - - // If this is set, then all the other cache data is set. - if ( !m_pOwnerHdr || m_MergedBones.Count() == 0 ) - return; - - // Now copy the bone matrices. - for ( int i=0; i < m_MergedBones.Count(); i++ ) - { - int iOwnerBone = m_MergedBones[i].m_iMyBone; - int iParentBone = m_MergedBones[i].m_iParentBone; - - if ( m_pOwnerHdr->boneParent( iOwnerBone ) == -1 || m_pFollowHdr->boneParent( iParentBone ) == -1 ) - continue; - - // Only update bones reference by the bone mask. - if ( !( m_pOwnerHdr->boneFlags( iOwnerBone ) & boneMask ) ) - continue; +#ifdef SWARM_DLL + matrix3x4_t matPitchUp; + AngleMatrix( QAngle( 15, 0, 0 ), matPitchUp ); + ConcatTransforms( m_pFollow->GetBone( iParentBone ), matPitchUp, m_pOwner->GetBoneForWrite( iOwnerBone ) ); +#else + MatrixCopy(m_pFollow->GetBone(iParentBone), m_pOwner->GetBoneForWrite(iOwnerBone)); +#endif - parentPos[ iParentBone ] = childPos[ iOwnerBone ]; - parentQ[ iParentBone ] = childQ[ iOwnerBone ]; + boneComputed.Set( i ); } } @@ -255,6 +173,7 @@ bool CBoneMergeCache::GetAimEntOrigin( Vector *pAbsOrigin, QAngle *pAbsAngles ) // all over the place, then this won't get the right results. // Get mFollowBone. + ACTIVE_SPLITSCREEN_PLAYER_GUARD( 0 ); m_pFollow->SetupBones( NULL, -1, m_nFollowBoneSetupMask, gpGlobals->curtime ); const matrix3x4_t &mFollowBone = m_pFollow->GetBone( m_MergedBones[0].m_iParentBone ); @@ -271,18 +190,3 @@ bool CBoneMergeCache::GetAimEntOrigin( Vector *pAbsOrigin, QAngle *pAbsAngles ) return true; } -bool CBoneMergeCache::GetRootBone( matrix3x4_t &rootBone ) -{ - UpdateCache(); - - // If this is set, then all the other cache data is set. - if ( !m_pOwnerHdr || m_MergedBones.Count() == 0 ) - return false; - - // Get mFollowBone. - m_pFollow->SetupBones( NULL, -1, m_nFollowBoneSetupMask, gpGlobals->curtime ); - rootBone = m_pFollow->GetBone( m_MergedBones[0].m_iParentBone ); - return true; -} - - diff --git a/game/client/bone_merge_cache.h b/game/client/bone_merge_cache.h index 6123c9b4a..112c00eac 100644 --- a/game/client/bone_merge_cache.h +++ b/game/client/bone_merge_cache.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // @@ -13,7 +13,7 @@ class C_BaseAnimating; class CStudioHdr; - +class CBoneBitList; #include "mathlib/vector.h" @@ -31,11 +31,7 @@ class CBoneMergeCache // This copies the transform from all bones in the followed entity that have // names that match our bones. - void MergeMatchingBones( int boneMask ); - - // copy bones instead of matrices - void CopyParentToChild( const Vector parentPos[], const Quaternion parentQ[], Vector childPos[], Quaternion childQ[], int boneMask ); - void CopyChildToParent( const Vector childPos[], const Quaternion childQ[], Vector parentPos[], Quaternion parentQ[], int boneMask ); + virtual void MergeMatchingBones( int boneMask, CBoneBitList &boneComputed ); // Returns true if the specified bone is one that gets merged in MergeMatchingBones. int IsBoneMerged( int iBone ) const; @@ -43,9 +39,8 @@ class CBoneMergeCache // Gets the origin for the first merge bone on the parent. bool GetAimEntOrigin( Vector *pAbsOrigin, QAngle *pAbsAngles ); - bool GetRootBone( matrix3x4_t &rootBone ); -private: +protected: // This is the entity that we're keeping the cache updated for. C_BaseAnimating *m_pOwner; @@ -54,7 +49,6 @@ class CBoneMergeCache // These are either all valid pointers or all NULL. C_BaseAnimating *m_pFollow; CStudioHdr *m_pFollowHdr; - const studiohdr_t *m_pFollowRenderHdr; CStudioHdr *m_pOwnerHdr; // This is the mask we need to use to set up bones on the followed entity to do the bone merge @@ -69,14 +63,14 @@ class CBoneMergeCache }; CUtlVector m_MergedBones; - CUtlVector m_BoneMergeBits; // One bit for each bone. The bit is set if the bone gets merged. + CVarBitVec m_BoneMergeBits; // One bit for each bone. The bit is set if the bone gets merged. }; inline int CBoneMergeCache::IsBoneMerged( int iBone ) const { if ( m_pOwnerHdr ) - return m_BoneMergeBits[iBone >> 3] & ( 1 << ( iBone & 7 ) ); + return m_BoneMergeBits.Get( iBone ); else return 0; } diff --git a/game/client/bonetoworldarray.h b/game/client/bonetoworldarray.h index ce3486b1e..90596ee3a 100644 --- a/game/client/bonetoworldarray.h +++ b/game/client/bonetoworldarray.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========== Copyright © 2006, Valve Corporation, All rights reserved. ======== // // Purpose: // diff --git a/game/client/c_ai_basehumanoid.cpp b/game/client/c_ai_basehumanoid.cpp index cf21a2587..af802401d 100644 --- a/game/client/c_ai_basehumanoid.cpp +++ b/game/client/c_ai_basehumanoid.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // diff --git a/game/client/c_ai_basenpc.cpp b/game/client/c_ai_basenpc.cpp index 1b1e2e65e..ab701b595 100644 --- a/game/client/c_ai_basenpc.cpp +++ b/game/client/c_ai_basenpc.cpp @@ -1,12 +1,12 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ //=============================================================================// #include "cbase.h" -#include "c_ai_basenpc.h" -#include "engine/ivdebugoverlay.h" +#include "c_AI_BaseNPC.h" +#include "engine/IVDebugOverlay.h" #if defined( HL2_DLL ) || defined( HL2_EPISODIC ) #include "c_basehlplayer.h" @@ -37,8 +37,7 @@ extern ConVar cl_npc_speedmod_intime; bool NPC_IsImportantNPC( C_BaseAnimating *pAnimating ) { - C_AI_BaseNPC *pBaseNPC = dynamic_cast < C_AI_BaseNPC* > ( pAnimating ); - + C_AI_BaseNPC *pBaseNPC = pAnimating->MyNPCPointer(); if ( pBaseNPC == NULL ) return false; @@ -153,7 +152,7 @@ void C_AI_BaseNPC::OnDataChanged( DataUpdateType_t type ) } } -void C_AI_BaseNPC::GetRagdollInitBoneArrays( matrix3x4_t *pDeltaBones0, matrix3x4_t *pDeltaBones1, matrix3x4_t *pCurrentBones, float boneDt ) +void C_AI_BaseNPC::GetRagdollInitBoneArrays( matrix3x4a_t *pDeltaBones0, matrix3x4a_t *pDeltaBones1, matrix3x4a_t *pCurrentBones, float boneDt ) { ForceSetupBonesAtTime( pDeltaBones0, gpGlobals->curtime - boneDt ); GetRagdollCurSequenceWithDeathPose( this, pDeltaBones1, gpGlobals->curtime, m_iDeathPose, m_iDeathFrame ); diff --git a/game/client/c_ai_basenpc.h b/game/client/c_ai_basenpc.h index 64636c451..d98fb225e 100644 --- a/game/client/c_ai_basenpc.h +++ b/game/client/c_ai_basenpc.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // @@ -29,7 +29,7 @@ class C_AI_BaseNPC : public C_BaseCombatCharacter bool ShouldAvoidObstacle( void ){ return m_bPerformAvoidance; } virtual bool AddRagdollToFadeQueue( void ) { return m_bFadeCorpse; } - virtual void GetRagdollInitBoneArrays( matrix3x4_t *pDeltaBones0, matrix3x4_t *pDeltaBones1, matrix3x4_t *pCurrentBones, float boneDt ); + virtual void GetRagdollInitBoneArrays( matrix3x4a_t *pDeltaBones0, matrix3x4a_t *pDeltaBones1, matrix3x4a_t *pCurrentBones, float boneDt ); int GetDeathPose( void ) { return m_iDeathPose; } diff --git a/game/client/c_baseanimating.cpp b/game/client/c_baseanimating.cpp index d66339e53..32eb949ac 100644 --- a/game/client/c_baseanimating.cpp +++ b/game/client/c_baseanimating.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // @@ -6,7 +6,7 @@ //===========================================================================// #include "cbase.h" #include "c_baseanimating.h" -#include "c_sprite.h" +#include "c_Sprite.h" #include "model_types.h" #include "bone_setup.h" #include "ivrenderview.h" @@ -19,10 +19,9 @@ #include "activitylist.h" #include "animation.h" #include "tier0/vprof.h" -#include "clienteffectprecachesystem.h" -#include "IEffects.h" +#include "ieffects.h" #include "engine/ivmodelinfo.h" -#include "engine/ivdebugoverlay.h" +#include "engine/IVDebugOverlay.h" #include "c_te_effect_dispatch.h" #include #include "c_rope.h" @@ -40,24 +39,28 @@ #include "c_fire_smoke.h" #include "input.h" #include "soundinfo.h" +#include "shaderapi/ishaderapi.h" #include "tools/bonelist.h" #include "toolframework/itoolframework.h" #include "datacache/idatacache.h" #include "gamestringpool.h" +#include "engine/IVDebugOverlay.h" #include "jigglebones.h" #include "toolframework_client.h" #include "vstdlib/jobthread.h" #include "bonetoworldarray.h" #include "posedebugger.h" -#include "tier0/icommandline.h" +#include "tier0/ICommandLine.h" +#include #include "prediction.h" -#include "replay/replay_ragdoll.h" -#include "studio_stats.h" -#include "tier1/callqueue.h" +#include "c_entityflame.h" +#include "npcevent.h" +#include "replay_ragdoll.h" -#ifdef TF_CLIENT_DLL -#include "c_tf_player.h" -#include "c_baseobject.h" +#include "clientalphaproperty.h" + +#ifdef DEMOPOLISH_ENABLED +#include "demo_polish/demo_polish.h" #endif // memdbgon must be the last include file in a .cpp file!!! @@ -65,6 +68,13 @@ static ConVar cl_SetupAllBones( "cl_SetupAllBones", "0" ); ConVar r_sequence_debug( "r_sequence_debug", "" ); +ConVar r_debug_sequencesets( "r_debug_sequencesets", "-2" ); +ConVar r_jiggle_bones( "r_jiggle_bones", "1" ); +ConVar RagdollImpactStrength( "z_ragdoll_impact_strength", "500" ); +ConVar cl_disable_ragdolls( "cl_disable_ragdolls", "0", FCVAR_CHEAT ); + +ConVar cl_ejectbrass( "cl_ejectbrass", "1" ); + // If an NPC is moving faster than this, he should play the running footstep sound const float RUN_SPEED_ESTIMATE_SQR = 150.0f * 150.0f; @@ -74,63 +84,27 @@ const float RUN_SPEED_ESTIMATE_SQR = 150.0f * 150.0f; #undef CBaseAnimating #endif +ConVar sfm_record_hz( "sfm_record_hz", "30" ); -#ifdef DEBUG -static ConVar dbganimmodel( "dbganimmodel", "" ); -#endif +static bool g_bInThreadedBoneSetup; mstudioevent_t *GetEventIndexForSequence( mstudioseqdesc_t &seqdesc ); -C_EntityDissolve *DissolveEffect( C_BaseEntity *pTarget, float flTime ); +C_EntityDissolve *DissolveEffect( C_BaseAnimating *pTarget, float flTime ); C_EntityFlame *FireEffect( C_BaseAnimating *pTarget, C_BaseEntity *pServerFire, float *flScaleEnd, float *flTimeStart, float *flTimeEnd ); bool NPC_IsImportantNPC( C_BaseAnimating *pAnimating ); void VCollideWireframe_ChangeCallback( IConVar *pConVar, char const *pOldString, float flOldValue ); ConVar vcollide_wireframe( "vcollide_wireframe", "0", FCVAR_CHEAT, "Render physics collision models in wireframe", VCollideWireframe_ChangeCallback ); +ConVar enable_skeleton_draw( "enable_skeleton_draw", "0", FCVAR_CHEAT, "Render skeletons in wireframe" ); + +extern ConVar r_shadow_deferred; bool C_AnimationLayer::IsActive( void ) { return (m_nOrder != C_BaseAnimatingOverlay::MAX_OVERLAYS); } -//----------------------------------------------------------------------------- -// Relative lighting entity -//----------------------------------------------------------------------------- -class C_InfoLightingRelative : public C_BaseEntity -{ -public: - DECLARE_CLASS( C_InfoLightingRelative, C_BaseEntity ); - DECLARE_CLIENTCLASS(); - - void GetLightingOffset( matrix3x4_t &offset ); - -private: - EHANDLE m_hLightingLandmark; -}; - -IMPLEMENT_CLIENTCLASS_DT(C_InfoLightingRelative, DT_InfoLightingRelative, CInfoLightingRelative) - RecvPropEHandle(RECVINFO(m_hLightingLandmark)), -END_RECV_TABLE() - - -//----------------------------------------------------------------------------- -// Relative lighting entity -//----------------------------------------------------------------------------- -void C_InfoLightingRelative::GetLightingOffset( matrix3x4_t &offset ) -{ - if ( m_hLightingLandmark.Get() ) - { - matrix3x4_t matWorldToLandmark; - MatrixInvert( m_hLightingLandmark->EntityToWorldTransform(), matWorldToLandmark ); - ConcatTransforms( EntityToWorldTransform(), matWorldToLandmark, offset ); - } - else - { - SetIdentityMatrix( offset ); - } -} - - //----------------------------------------------------------------------------- // Base Animating //----------------------------------------------------------------------------- @@ -165,6 +139,14 @@ void RecvProxy_Sequence( const CRecvProxyData *pData, void *pStruct, void *pOut // render bounds may have changed pAnimating->UpdateVisibility(); + + /* + if (r_sequence_debug.GetInt() == pAnimating->entindex() ) + { + DevMsgRT( "%d : RecvProxy_Sequence( %d:%s )\n", pAnimating->entindex(), pAnimating->GetSequence(), pAnimating->GetSequenceName( pAnimating->GetSequence() ) ); + Assert( 1 ); + } + */ } IMPLEMENT_CLIENTCLASS_DT(C_BaseAnimating, DT_BaseAnimating, CBaseAnimating) @@ -174,9 +156,7 @@ IMPLEMENT_CLIENTCLASS_DT(C_BaseAnimating, DT_BaseAnimating, CBaseAnimating) RecvPropInt(RECVINFO(m_nSkin)), RecvPropInt(RECVINFO(m_nBody)), RecvPropInt(RECVINFO(m_nHitboxSet)), - RecvPropFloat(RECVINFO(m_flModelScale)), - RecvPropFloat(RECVINFO_NAME(m_flModelScale, m_flModelWidthScale)), // for demo compatibility only // RecvPropArray(RecvPropFloat(RECVINFO(m_flPoseParameter[0])), m_flPoseParameter), RecvPropArray3(RECVINFO_ARRAY(m_flPoseParameter), RecvPropFloat(RECVINFO(m_flPoseParameter[0])) ), @@ -187,19 +167,17 @@ IMPLEMENT_CLIENTCLASS_DT(C_BaseAnimating, DT_BaseAnimating, CBaseAnimating) RecvPropInt( RECVINFO( m_bClientSideAnimation )), RecvPropInt( RECVINFO( m_bClientSideFrameReset )), + RecvPropBool( RECVINFO( m_bClientSideRagdoll )), RecvPropInt( RECVINFO( m_nNewSequenceParity )), RecvPropInt( RECVINFO( m_nResetEventsParity )), RecvPropInt( RECVINFO( m_nMuzzleFlashParity ) ), RecvPropEHandle(RECVINFO(m_hLightingOrigin)), - RecvPropEHandle(RECVINFO(m_hLightingOriginRelative)), RecvPropDataTable( "serveranimdata", 0, 0, &REFERENCE_RECV_TABLE( DT_ServerAnimationData ) ), - RecvPropFloat( RECVINFO( m_fadeMinDist ) ), - RecvPropFloat( RECVINFO( m_fadeMaxDist ) ), - RecvPropFloat( RECVINFO( m_flFadeScale ) ), + RecvPropFloat( RECVINFO( m_flFrozen ) ), END_RECV_TABLE() @@ -228,7 +206,6 @@ BEGIN_PREDICTION_DATA( C_BaseAnimating ) //DEFINE_FIELD( m_nOldMuzzleFlashParity, FIELD_CHARACTER ), //DEFINE_FIELD( m_nPrevNewSequenceParity, FIELD_INTEGER ), - //DEFINE_FIELD( m_nPrevResetEventsParity, FIELD_INTEGER ), // DEFINE_PRED_FIELD( m_vecForce, FIELD_VECTOR, FTYPEDESC_INSENDTABLE ), // DEFINE_PRED_FIELD( m_nForceBone, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ), @@ -240,7 +217,7 @@ BEGIN_PREDICTION_DATA( C_BaseAnimating ) // DEFINE_FIELD( m_pActualAttachmentAngles, FIELD_VECTOR ), // DEFINE_FIELD( m_pActualAttachmentOrigin, FIELD_VECTOR ), - // DEFINE_FIELD( m_animationQueue, CUtlVector < C_AnimationLayer > ), + // DEFINE_FIELD( m_animationQueue, CUtlVector < CAnimationLayer > ), // DEFINE_FIELD( m_pIk, CIKContext ), // DEFINE_FIELD( m_bLastClientSideFrameReset, FIELD_BOOLEAN ), // DEFINE_FIELD( hdr, studiohdr_t ), @@ -276,9 +253,19 @@ BEGIN_DATADESC( C_ClientRagdoll ) DEFINE_AUTO_ARRAY( m_flScaleTimeEnd, FIELD_FLOAT ), DEFINE_EMBEDDEDBYREF( m_pRagdoll ), + DEFINE_AUTO_ARRAY( m_flScaleEnd, FIELD_FLOAT ), + DEFINE_AUTO_ARRAY( m_flScaleTimeStart, FIELD_FLOAT ), + DEFINE_AUTO_ARRAY( m_flScaleTimeEnd, FIELD_FLOAT ), + //DEFINE_EMBEDDEDBYREF( m_pRagdoll ), // TODO: FIX: This is dynamically-typed + END_DATADESC() -C_ClientRagdoll::C_ClientRagdoll( bool bRestoring ) +BEGIN_ENT_SCRIPTDESC( C_BaseAnimating, C_BaseEntity, "Animating models client-side" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptSetPoseParameter, "SetPoseParameter", "Set the specified pose parameter to the specified value" ) + DEFINE_SCRIPTFUNC( IsSequenceFinished, "Ask whether the main sequence is done playing" ) +END_SCRIPTDESC(); + +C_ClientRagdoll::C_ClientRagdoll( bool bRestoring , bool fullInit) { m_iCurrentFriction = 0; m_iFrictionAnimState = RAGDOLL_FRICTION_NONE; @@ -286,16 +273,20 @@ C_ClientRagdoll::C_ClientRagdoll( bool bRestoring ) m_bFadeOut = false; m_bFadingOut = false; m_bImportant = false; - m_bNoModelParticles = false; - - SetClassname("client_ragdoll"); - if ( bRestoring == true ) + if(fullInit) { - m_pRagdoll = new CRagdoll; + SetClassname("client_ragdoll"); + + if ( bRestoring == true ) + { + m_pRagdoll = new CRagdoll; + } } } + + void C_ClientRagdoll::OnSave( void ) { } @@ -357,7 +348,7 @@ void C_ClientRagdoll::OnRestore( void ) // UNDONE: The shadow & leaf system cleanup should probably be in C_BaseEntity::OnRestore() // this must be recomputed because the model was NULL when this was set up RemoveFromLeafSystem(); - AddToLeafSystem( RENDER_GROUP_OPAQUE_ENTITY ); + AddToLeafSystem( false ); DestroyShadow(); CreateShadow(); @@ -376,7 +367,7 @@ void C_ClientRagdoll::OnRestore( void ) RagdollMoved(); } -void C_ClientRagdoll::ImpactTrace( trace_t *pTrace, int iDamageType, const char *pCustomImpactName ) +void C_ClientRagdoll::ImpactTrace( trace_t *pTrace, int iDamageType, char *pCustomImpactName ) { VPROF( "C_ClientRagdoll::ImpactTrace" ); @@ -385,9 +376,12 @@ void C_ClientRagdoll::ImpactTrace( trace_t *pTrace, int iDamageType, const char if( !pPhysicsObject ) return; + if ( !pPhysicsObject->IsCollisionEnabled() ) + return; + Vector dir = pTrace->endpos - pTrace->startpos; - if ( iDamageType == DMG_BLAST ) + if ( iDamageType & DMG_BLAST ) { dir *= 500; // adjust impact strenght @@ -401,7 +395,7 @@ void C_ClientRagdoll::ImpactTrace( trace_t *pTrace, int iDamageType, const char VectorMA( pTrace->startpos, pTrace->fraction, dir, hitpos ); VectorNormalize( dir ); - dir *= 4000; // adjust impact strenght + dir *= RagdollImpactStrength.GetFloat(); // adjust impact strength // apply force where we hit it pPhysicsObject->ApplyForceOffset( dir, hitpos ); @@ -434,14 +428,14 @@ void C_ClientRagdoll::HandleAnimatedFriction( void ) { case RAGDOLL_FRICTION_NONE: { - m_iMinFriction = pRagdollT->animfriction.iMinAnimatedFriction; - m_iMaxFriction = pRagdollT->animfriction.iMaxAnimatedFriction; + m_iMinFriction = pRagdollT->animfriction.minFriction; + m_iMaxFriction = pRagdollT->animfriction.maxFriction; if ( m_iMinFriction != 0 || m_iMaxFriction != 0 ) { m_iFrictionAnimState = RAGDOLL_FRICTION_IN; - m_flFrictionModTime = pRagdollT->animfriction.flFrictionTimeIn; + m_flFrictionModTime = pRagdollT->animfriction.timeIn; m_flFrictionTime = gpGlobals->curtime + m_flFrictionModTime; m_iCurrentFriction = m_iMinFriction; @@ -462,7 +456,7 @@ void C_ClientRagdoll::HandleAnimatedFriction( void ) if ( flDeltaTime <= 0.0f ) { - m_flFrictionModTime = pRagdollT->animfriction.flFrictionTimeHold; + m_flFrictionModTime = pRagdollT->animfriction.timeHold; m_flFrictionTime = gpGlobals->curtime + m_flFrictionModTime; m_iFrictionAnimState = RAGDOLL_FRICTION_HOLD; } @@ -473,7 +467,7 @@ void C_ClientRagdoll::HandleAnimatedFriction( void ) { if ( m_flFrictionTime < gpGlobals->curtime ) { - m_flFrictionModTime = pRagdollT->animfriction.flFrictionTimeOut; + m_flFrictionModTime = pRagdollT->animfriction.timeOut; m_flFrictionTime = gpGlobals->curtime + m_flFrictionModTime; m_iFrictionAnimState = RAGDOLL_FRICTION_OUT; } @@ -532,13 +526,13 @@ void C_ClientRagdoll::FadeOut( void ) return; } - int iAlpha = GetRenderColor().a; + int iAlpha = GetRenderAlpha(); int iFadeSpeed = ( g_RagdollLVManager.IsLowViolence() ) ? g_ragdoll_lvfadespeed.GetInt() : g_ragdoll_fadespeed.GetInt(); iAlpha = MAX( iAlpha - ( iFadeSpeed * gpGlobals->frametime ), 0 ); SetRenderMode( kRenderTransAlpha ); - SetRenderColorA( iAlpha ); + SetRenderAlpha( iAlpha ); if ( iAlpha == 0 ) { @@ -552,11 +546,11 @@ void C_ClientRagdoll::SUB_Remove( void ) SetNextClientThink( CLIENT_THINK_ALWAYS ); } +//-------------------------------------------------------------------------------------------------------- void C_ClientRagdoll::ClientThink( void ) { if ( m_bReleaseRagdoll == true ) { - DestroyBoneAttachments(); Release(); return; } @@ -586,6 +580,24 @@ float C_ClientRagdoll::LastBoneChangedTime() } +//---------------------------------------------------------------------------- +// Hooks into the fast path render system +//---------------------------------------------------------------------------- +IClientModelRenderable* C_ClientRagdoll::GetClientModelRenderable() +{ + if ( !BaseClass::GetClientModelRenderable() ) + return NULL; + + // NOTE: This is because of code in SetupWeights, which calls SetViewTarget. + // The view target is a per-instance piece of state which is not yet + // supported by the model fast path. Once it is, we can eliminate this + // code and make it so ragdolls always use the fast path + if ( m_iEyeAttachment > 0 ) + return NULL; + return this; +} + + //----------------------------------------------------------------------------- // Purpose: clear out any face/eye values stored in the material system //----------------------------------------------------------------------------- @@ -600,8 +612,11 @@ void C_ClientRagdoll::SetupWeights( const matrix3x4_t *pBoneToWorld, int nFlexWe int nFlexDescCount = hdr->numflexdesc(); if ( nFlexDescCount ) { - Assert( !pFlexDelayedWeights ); memset( pFlexWeights, 0, nFlexWeightCount * sizeof(float) ); + if ( pFlexDelayedWeights ) + { + memset( pFlexDelayedWeights, 0, nFlexWeightCount * sizeof(float) ); + } } if ( m_iEyeAttachment > 0 ) @@ -623,7 +638,7 @@ void C_ClientRagdoll::Release( void ) if ( pChild && pChild->IsMarkedForDeletion() == false ) { - pChild->Release(); + UTIL_Remove( pChild ); } if ( GetThinkHandle() != INVALID_THINK_HANDLE ) @@ -667,17 +682,22 @@ C_BaseAnimating::C_BaseAnimating() : m_iv_flPoseParameter( "C_BaseAnimating::m_iv_flPoseParameter" ), m_iv_flEncodedController("C_BaseAnimating::m_iv_flEncodedController") { + m_iEjectBrassAttachment = -1; + m_vecForce.Init(); m_nForceBone = -1; - + SetGlobalFadeScale( 1.0f ); + m_ClientSideAnimationListHandle = INVALID_CLIENTSIDEANIMATION_LIST_HANDLE; + m_bCanUseFastPath = false; + m_bIsUsingRelativeLighting = false; + m_bIsStaticProp = false; m_nPrevSequence = -1; m_nRestoreSequence = -1; - m_pRagdoll = NULL; + m_pRagdoll = NULL; + m_pClientsideRagdoll = NULL; m_builtRagdoll = false; - m_hitboxBoneCacheHandle = 0; - m_nHitboxSet = 0; int i; for ( i = 0; i < ARRAYSIZE( m_flEncodedController ); i++ ) @@ -690,14 +710,13 @@ C_BaseAnimating::C_BaseAnimating() : m_iMostRecentModelBoneCounter = 0xFFFFFFFF; m_iMostRecentBoneSetupRequest = g_iPreviousBoneCounter - 1; m_flLastBoneSetupTime = -FLT_MAX; + m_pNextForThreadedBoneSetup = NULL; m_vecPreRagdollMins = vec3_origin; m_vecPreRagdollMaxs = vec3_origin; m_bStoreRagdollInfo = false; m_pRagdollInfo = NULL; - m_pJiggleBones = NULL; - m_pBoneMergeCache = NULL; m_flPlaybackRate = 1.0f; @@ -725,19 +744,14 @@ C_BaseAnimating::C_BaseAnimating() : m_hStudioHdr = MDLHANDLE_INVALID; m_bReceivedSequence = false; - - m_boneIndexAttached = -1; + m_bBonePolishSetup = false; + m_prevClientCycle = 0; + m_prevClientAnimTime = 0; m_flOldModelScale = 0.0f; - m_pAttachedTo = NULL; - - m_bDynamicModelAllowed = false; - m_bDynamicModelPending = false; - m_bResetSequenceInfoOnLoad = false; - - Q_memset(&m_mouth, 0, sizeof(m_mouth)); - m_flCycle = 0; - m_flOldCycle = 0; + m_pJiggleBones = NULL; + m_isJiggleBonesEnabled = true; + AddToEntityList(ENTITY_LIST_SIMULATE); } //----------------------------------------------------------------------------- @@ -745,9 +759,19 @@ C_BaseAnimating::C_BaseAnimating() : //----------------------------------------------------------------------------- C_BaseAnimating::~C_BaseAnimating() { - int i = g_PreviousBoneSetups.Find( this ); - if ( i != -1 ) - g_PreviousBoneSetups.FastRemove( i ); + Assert( !g_bInThreadedBoneSetup ); + if ( m_iMostRecentBoneSetupRequest == g_iPreviousBoneCounter ) + { + int i = g_PreviousBoneSetups.Find( this ); + Assert( i != -1 ); + if ( i != -1 ) + g_PreviousBoneSetups.FastRemove( i ); + } + else + { + Assert( g_PreviousBoneSetups.Find( this ) == -1 ); + } + RemoveFromClientSideAnimationList(); TermRopes(); @@ -755,24 +779,22 @@ C_BaseAnimating::~C_BaseAnimating() Assert(!m_pRagdoll); delete m_pIk; delete m_pBoneMergeCache; - Studio_DestroyBoneCache( m_hitboxBoneCacheHandle ); - delete m_pJiggleBones; - InvalidateMdlCache(); - - // Kill off anything bone attached to us. - DestroyBoneAttachments(); - - // If we are bone attached to something, remove us from the list. - if ( m_pAttachedTo ) + UnlockStudioHdr(); + delete m_pStudioHdr; + if ( m_pJiggleBones ) { - m_pAttachedTo->RemoveBoneAttachment( this ); - m_pAttachedTo = NULL; + delete m_pJiggleBones; + m_pJiggleBones = NULL; } } -bool C_BaseAnimating::UsesPowerOfTwoFrameBufferTexture( void ) +int C_BaseAnimating::GetRenderFlags( void ) { - return modelinfo->IsUsingFBTexture( GetModel(), GetSkin(), GetBody(), GetClientRenderable() ); + int nRet = 0; + if ( modelinfo->IsUsingFBTexture( GetModel(), GetSkin(), GetBody(), GetClientRenderable() ) ) + nRet |= ERENDERFLAGS_NEEDS_POWER_OF_TWO_FB; + return nRet; + } //----------------------------------------------------------------------------- @@ -854,9 +876,9 @@ void C_BaseAnimating::UseClientSideAnimation() void C_BaseAnimating::UpdateRelevantInterpolatedVars() { - MDLCACHE_CRITICAL_SECTION(); // Remove any interpolated vars that need to be removed. - if ( !GetPredictable() && !IsClientCreated() && GetModelPtr() && GetModelPtr()->SequencesAvailable() ) + MDLCACHE_CRITICAL_SECTION(); + if ( !GetPredictable() && !IsClientCreated() && GetModelPtr() && GetModelPtr()->SequencesAvailable() && WantsInterpolatedVars() ) { AddBaseAnimatingInterpolatedVars(); } @@ -870,12 +892,12 @@ void C_BaseAnimating::UpdateRelevantInterpolatedVars() void C_BaseAnimating::AddBaseAnimatingInterpolatedVars() { AddVar( m_flEncodedController, &m_iv_flEncodedController, LATCH_ANIMATION_VAR, true ); - AddVar( m_flPoseParameter, &m_iv_flPoseParameter, LATCH_ANIMATION_VAR, true ); int flags = LATCH_ANIMATION_VAR; if ( m_bClientSideAnimation ) flags |= EXCLUDE_AUTO_INTERPOLATE; + AddVar( m_flPoseParameter, &m_iv_flPoseParameter, flags, true ); AddVar( &m_flCycle, &m_iv_flCycle, flags, true ); } @@ -883,113 +905,79 @@ void C_BaseAnimating::RemoveBaseAnimatingInterpolatedVars() { RemoveVar( m_flEncodedController, false ); RemoveVar( m_flPoseParameter, false ); - -#ifdef HL2MP - // HACK: Don't want to remove interpolation for predictables in hl2dm, though - // The animation state stuff sets the pose parameters -- so they should interp - // but m_flCycle is not touched, so it's only set during prediction (which occurs on tick boundaries) - // and so needs to continue to be interpolated for smooth rendering of the lower body of the local player in third person, etc. - if ( !GetPredictable() ) -#endif - { - RemoveVar( &m_flCycle, false ); - } + RemoveVar( &m_flCycle, false ); } void C_BaseAnimating::LockStudioHdr() { - Assert( m_hStudioHdr == MDLHANDLE_INVALID && m_pStudioHdr == NULL ); - AUTO_LOCK( m_StudioHdrInitLock ); - - if ( m_hStudioHdr != MDLHANDLE_INVALID || m_pStudioHdr != NULL ) - { - Assert( m_pStudioHdr ? m_pStudioHdr->GetRenderHdr() == mdlcache->GetStudioHdr(m_hStudioHdr) : m_hStudioHdr == MDLHANDLE_INVALID ); - return; - } - const model_t *mdl = GetModel(); - if ( !mdl ) - return; - - m_hStudioHdr = modelinfo->GetCacheHandle( mdl ); - if ( m_hStudioHdr == MDLHANDLE_INVALID ) - return; - - const studiohdr_t *pStudioHdr = mdlcache->LockStudioHdr( m_hStudioHdr ); - if ( !pStudioHdr ) + if (mdl) { - m_hStudioHdr = MDLHANDLE_INVALID; - return; - } + m_hStudioHdr = modelinfo->GetCacheHandle( mdl ); + if ( m_hStudioHdr != MDLHANDLE_INVALID ) + { + const studiohdr_t *pStudioHdr = mdlcache->LockStudioHdr( m_hStudioHdr ); + CStudioHdr *pStudioHdrContainer = NULL; + if ( !m_pStudioHdr ) + { + if ( pStudioHdr ) + { + pStudioHdrContainer = new CStudioHdr; + pStudioHdrContainer->Init( pStudioHdr, mdlcache ); + } + else + { + m_hStudioHdr = MDLHANDLE_INVALID; + } + } + else + { + pStudioHdrContainer = m_pStudioHdr; + } - CStudioHdr *pNewWrapper = new CStudioHdr; - pNewWrapper->Init( pStudioHdr, mdlcache ); - Assert( pNewWrapper->IsValid() ); - - if ( pNewWrapper->GetVirtualModel() ) - { - MDLHandle_t hVirtualModel = VoidPtrToMDLHandle( pStudioHdr->VirtualModel() ); - mdlcache->LockStudioHdr( hVirtualModel ); - } + Assert( ( pStudioHdr == NULL && pStudioHdrContainer == NULL ) || pStudioHdrContainer->GetRenderHdr() == pStudioHdr ); - m_pStudioHdr = pNewWrapper; // must be last to ensure virtual model correctly set up + if ( pStudioHdrContainer && pStudioHdrContainer->GetVirtualModel() ) + { + MDLHandle_t hVirtualModel = (MDLHandle_t)(int)(pStudioHdrContainer->GetRenderHdr()->virtualModel)&0xffff; + mdlcache->LockStudioHdr( hVirtualModel ); + } + m_pStudioHdr = pStudioHdrContainer; // must be last to ensure virtual model correctly set up + } + } } void C_BaseAnimating::UnlockStudioHdr() { - if ( m_hStudioHdr != MDLHANDLE_INVALID ) + if ( m_pStudioHdr ) { - studiohdr_t *pStudioHdr = mdlcache->GetStudioHdr( m_hStudioHdr ); - Assert( m_pStudioHdr && m_pStudioHdr->GetRenderHdr() == pStudioHdr ); - -#if 0 - // XXX need to figure out where to flush the queue on map change to not crash - if ( ICallQueue *pCallQueue = materials->GetRenderContext()->GetCallQueue() ) - { - // Parallel rendering: don't unlock model data until end of rendering - if ( pStudioHdr->GetVirtualModel() ) - { - MDLHandle_t hVirtualModel = VoidPtrToMDLHandle( m_pStudioHdr->GetRenderHdr()->VirtualModel() ); - pCallQueue->QueueCall( mdlcache, &IMDLCache::UnlockStudioHdr, hVirtualModel ); - } - pCallQueue->QueueCall( mdlcache, &IMDLCache::UnlockStudioHdr, m_hStudioHdr ); - } - else -#endif + const model_t *mdl = GetModel(); + if (mdl) { - // Immediate-mode rendering, can unlock immediately - if ( pStudioHdr->GetVirtualModel() ) + mdlcache->UnlockStudioHdr( m_hStudioHdr ); + if ( m_pStudioHdr->GetVirtualModel() ) { - MDLHandle_t hVirtualModel = VoidPtrToMDLHandle( m_pStudioHdr->GetRenderHdr()->VirtualModel() ); + MDLHandle_t hVirtualModel = (MDLHandle_t)(int)m_pStudioHdr->GetRenderHdr()->virtualModel&0xffff; mdlcache->UnlockStudioHdr( hVirtualModel ); } - mdlcache->UnlockStudioHdr( m_hStudioHdr ); } - m_hStudioHdr = MDLHANDLE_INVALID; } } -void C_BaseAnimating::OnModelLoadComplete( const model_t* pModel ) -{ - Assert( m_bDynamicModelPending && pModel == GetModel() ); - if ( m_bDynamicModelPending && pModel == GetModel() ) - { - m_bDynamicModelPending = false; - OnNewModel(); - UpdateVisibility(); - } -} -void C_BaseAnimating::ValidateModelIndex() -{ - BaseClass::ValidateModelIndex(); - Assert( m_nModelIndex == 0 || m_AutoRefModelIndex.Get() ); -} CStudioHdr *C_BaseAnimating::OnNewModel() { - InvalidateMdlCache(); + BaseClass::OnNewModel(); + m_bCanUseFastPath = false; + + if (m_pStudioHdr) + { + UnlockStudioHdr(); + delete m_pStudioHdr; + m_pStudioHdr = NULL; + } // remove transition animations playback m_SequenceTransitioner.RemoveAll(); @@ -1000,45 +988,20 @@ CStudioHdr *C_BaseAnimating::OnNewModel() m_pJiggleBones = NULL; } - if ( m_bDynamicModelPending ) - { - modelinfo->UnregisterModelLoadCallback( -1, this ); - m_bDynamicModelPending = false; - } - - m_AutoRefModelIndex.Clear(); - - if ( !GetModel() || modelinfo->GetModelType( GetModel() ) != mod_studio ) + if ( !GetModel() ) return NULL; - // Reference (and thus start loading) dynamic model - int nNewIndex = m_nModelIndex; - if ( modelinfo->GetModel( nNewIndex ) != GetModel() ) - { - // XXX what's authoritative? the model pointer or the model index? what a mess. - nNewIndex = modelinfo->GetModelIndex( modelinfo->GetModelName( GetModel() ) ); - Assert( nNewIndex < 0 || modelinfo->GetModel( nNewIndex ) == GetModel() ); - if ( nNewIndex < 0 ) - nNewIndex = m_nModelIndex; - } - - m_AutoRefModelIndex = nNewIndex; - if ( IsDynamicModelIndex( nNewIndex ) && modelinfo->IsDynamicModelLoading( nNewIndex ) ) - { - m_bDynamicModelPending = true; - modelinfo->RegisterModelLoadCallback( nNewIndex, this ); - } + LockStudioHdr(); - if ( IsDynamicModelLoading() ) - { - // Called while dynamic model still loading -> new model, clear deferred state - m_bResetSequenceInfoOnLoad = false; - return NULL; - } + UpdateRelevantInterpolatedVars(); CStudioHdr *hdr = GetModelPtr(); if (hdr == NULL) return NULL; + m_bIsStaticProp = ( hdr->flags() & STUDIOHDR_FLAGS_STATIC_PROP ) ? true : false; + + // Can we use the model fast path? + m_bCanUseFastPath = !modelinfo->ModelHasMaterialProxy( GetModel() ); InvalidateBoneCache(); if ( m_pBoneMergeCache ) @@ -1048,9 +1011,6 @@ CStudioHdr *C_BaseAnimating::OnNewModel() // recreated in BuildTransformations } - Studio_DestroyBoneCache( m_hitboxBoneCacheHandle ); - m_hitboxBoneCacheHandle = 0; - // Make sure m_CachedBones has space. if ( m_CachedBoneData.Count() != hdr->numbones() ) { @@ -1090,7 +1050,7 @@ CStudioHdr *C_BaseAnimating::OnNewModel() Assert( hdr->GetNumPoseParameters() <= ARRAYSIZE( m_flPoseParameter ) ); - m_iv_flPoseParameter.SetMaxCount( hdr->GetNumPoseParameters() ); + m_iv_flPoseParameter.SetMaxCount( gpGlobals->curtime, hdr->GetNumPoseParameters() ); int i; for ( i = 0; i < hdr->GetNumPoseParameters() ; i++ ) @@ -1108,7 +1068,7 @@ CStudioHdr *C_BaseAnimating::OnNewModel() int boneControllerCount = MIN( hdr->numbonecontrollers(), ARRAYSIZE( m_flEncodedController ) ); - m_iv_flEncodedController.SetMaxCount( boneControllerCount ); + m_iv_flEncodedController.SetMaxCount( gpGlobals->curtime, boneControllerCount ); for ( i = 0; i < boneControllerCount ; i++ ) { @@ -1124,7 +1084,7 @@ CStudioHdr *C_BaseAnimating::OnNewModel() // If we didn't have a model before, then we might need to go in the interpolation list now. if ( ShouldInterpolate() ) - AddToInterpolationList(); + AddToEntityList( ENTITY_LIST_INTERPOLATE ); // objects with attachment points need to be queryable even if they're not solid if ( hdr->GetNumAttachments() != 0 ) @@ -1132,31 +1092,18 @@ CStudioHdr *C_BaseAnimating::OnNewModel() AddEFlags( EFL_USE_PARTITION_WHEN_NOT_SOLID ); } - // Most entities clear out their sequences when they change models on the server, but // not all entities network down their m_nSequence (like multiplayer game player entities), - // so we may need to clear it out here. Force a SetSequence call no matter what, though. - int forceSequence = ShouldResetSequenceOnNewModel() ? 0 : m_nSequence; - - if ( GetSequence() >= hdr->GetNumSeq() ) + // so we need to clear it out here. + if ( ShouldResetSequenceOnNewModel() ) { - forceSequence = 0; + SetSequence(0); } - m_nSequence = -1; - SetSequence( forceSequence ); - - if ( m_bResetSequenceInfoOnLoad ) - { - m_bResetSequenceInfoOnLoad = false; - ResetSequenceInfo(); - } - - UpdateRelevantInterpolatedVars(); - return hdr; } + //----------------------------------------------------------------------------- // Purpose: Returns index number of a given named bone // Input : name of a bone @@ -1181,51 +1128,35 @@ void C_BaseAnimating::GetBonePosition ( int iBone, Vector &origin, QAngle &angle void C_BaseAnimating::GetBoneTransform( int iBone, matrix3x4_t &pBoneToWorld ) { - Assert( GetModelPtr() && iBone >= 0 && iBone < GetModelPtr()->numbones() ); - CBoneCache *pcache = GetBoneCache( NULL ); - - matrix3x4_t *pmatrix = pcache->GetCachedBone( iBone ); - - if ( !pmatrix ) - { - MatrixCopy( EntityToWorldTransform(), pBoneToWorld ); - return; - } - - Assert( pmatrix ); - - // FIXME - MatrixCopy( *pmatrix, pBoneToWorld ); -} -//============================================================================= -// HPE_BEGIN: -// [menglish] Finds the bone associated with the given hitbox -//============================================================================= - -int C_BaseAnimating::GetHitboxBone( int hitboxIndex ) -{ - CStudioHdr *pStudioHdr = GetModelPtr(); - if ( pStudioHdr ) + CStudioHdr *hdr = GetModelPtr(); + bool bWrote = false; + if ( hdr && iBone >= 0 && iBone < hdr->numbones() ) { - mstudiohitboxset_t *set =pStudioHdr->pHitboxSet( m_nHitboxSet ); - if ( set && hitboxIndex < set->numhitboxes ) + const int boneMask = BONE_USED_BY_HITBOX; + if ( hdr->boneFlags(iBone) & boneMask ) { - return set->pHitbox( hitboxIndex )->bone; + if ( !IsBoneCacheValid() ) + { + SetupBones( NULL, -1, boneMask, gpGlobals->curtime ); + } + GetCachedBoneMatrix( iBone, pBoneToWorld ); + bWrote = true; } } - return 0; + if ( !bWrote ) + { + MatrixCopy( EntityToWorldTransform(), pBoneToWorld ); + } + Assert( GetModelPtr() && iBone >= 0 && iBone < GetModelPtr()->numbones() ); } -//============================================================================= -// HPE_END -//============================================================================= - //----------------------------------------------------------------------------- // Purpose: Setup to initialize our model effects once the model's loaded //----------------------------------------------------------------------------- void C_BaseAnimating::InitModelEffects( void ) { m_bInitModelEffects = true; + AddToEntityList(ENTITY_LIST_SIMULATE); TermRopes(); } @@ -1240,30 +1171,84 @@ void C_BaseAnimating::DelayedInitModelEffects( void ) KeyValues * modelKeyValues = new KeyValues(""); if ( modelKeyValues->LoadFromBuffer( modelinfo->GetModelName( GetModel() ), modelinfo->GetModelKeyValueText( GetModel() ) ) ) { - // Do we have a cables section? - KeyValues *pkvAllCables = modelKeyValues->FindKey("Cables"); - if ( pkvAllCables ) + ParseModelEffects( modelKeyValues ); + } + modelKeyValues->deleteThis(); +} + +void C_BaseAnimating::ParseModelEffects( KeyValues *modelKeyValues ) +{ + // Do we have a cables section? + KeyValues *pkvAllCables = modelKeyValues->FindKey("Cables"); + if ( pkvAllCables ) + { + // Start grabbing the sounds and slotting them in + for ( KeyValues *pSingleCable = pkvAllCables->GetFirstSubKey(); pSingleCable; pSingleCable = pSingleCable->GetNextKey() ) { - // Start grabbing the sounds and slotting them in - for ( KeyValues *pSingleCable = pkvAllCables->GetFirstSubKey(); pSingleCable; pSingleCable = pSingleCable->GetNextKey() ) - { - C_RopeKeyframe *pRope = C_RopeKeyframe::CreateFromKeyValues( this, pSingleCable ); - m_Ropes.AddToTail( pRope ); - } + C_RopeKeyframe *pRope = C_RopeKeyframe::CreateFromKeyValues( this, pSingleCable ); + m_Ropes.AddToTail( pRope ); } + } - if ( !m_bNoModelParticles ) + // Do we have a particles section? + KeyValues *pkvAllParticleEffects = modelKeyValues->FindKey("Particles"); + if ( pkvAllParticleEffects ) + { + // Start grabbing the sounds and slotting them in + for ( KeyValues *pSingleEffect = pkvAllParticleEffects->GetFirstSubKey(); pSingleEffect; pSingleEffect = pSingleEffect->GetNextKey() ) { - // Do we have a particles section? - KeyValues *pkvAllParticleEffects = modelKeyValues->FindKey("Particles"); - if ( pkvAllParticleEffects ) + const char *pszParticleEffect = pSingleEffect->GetString( "name", "" ); + const char *pszAttachment = pSingleEffect->GetString( "attachment_point", "" ); + const char *pszAttachType = pSingleEffect->GetString( "attachment_type", "" ); + const char *pszAttachOffset = pSingleEffect->GetString( "attachment_offset", "" ); + + // Convert attach type + int iAttachType = GetAttachTypeFromString( pszAttachType ); + if ( iAttachType == -1 ) { - // Start grabbing the sounds and slotting them in - for ( KeyValues *pSingleEffect = pkvAllParticleEffects->GetFirstSubKey(); pSingleEffect; pSingleEffect = pSingleEffect->GetNextKey() ) + Warning("Invalid attach type specified for particle effect in model '%s' keyvalues section. Trying to spawn effect '%s' with attach type of '%s'\n", GetModelName(), pszParticleEffect, pszAttachType ); + return; + } + + // Convert attachment point + int iAttachment = atoi(pszAttachment); + // See if we can find any attachment points matching the name + if ( pszAttachment[0] != '0' && iAttachment == 0 ) + { + iAttachment = LookupAttachment( pszAttachment ); + if ( iAttachment == -1 ) + { + Warning("Failed to find attachment point specified for particle effect in model '%s' keyvalues section. Trying to spawn effect '%s' on attachment named '%s'\n", GetModelName(), pszParticleEffect, pszAttachment ); + return; + } + } + + Vector vecOffset = vec3_origin; + + if ( pszAttachOffset ) + { + float flVec[3]; + UTIL_StringToVector( flVec, pszAttachOffset ); + vecOffset = Vector( flVec[0], flVec[1], flVec[2] ); + } + + CUtlReference hModelEffect; + // Spawn the particle effectw + hModelEffect = ParticleProp()->Create( pszParticleEffect, (ParticleAttachment_t)iAttachType, iAttachment, vecOffset ); + + KeyValues *pkvAllControlPoints = pSingleEffect->FindKey("ControlPoints"); + if ( pkvAllControlPoints ) + { + // Start grabbing the CPs and slotting them in + for ( KeyValues *pSingleCP = pkvAllControlPoints->GetFirstSubKey(); pSingleCP; pSingleCP = pSingleCP->GetNextKey() ) { - const char *pszParticleEffect = pSingleEffect->GetString( "name", "" ); - const char *pszAttachment = pSingleEffect->GetString( "attachment_point", "" ); - const char *pszAttachType = pSingleEffect->GetString( "attachment_type", "" ); + const char *pszControlPoint = pSingleCP->GetString( "cp_number", "" ); + const char *pszAttachment = pSingleCP->GetString( "attachment_point", "" ); + const char *pszAttachType = pSingleCP->GetString( "attachment_type", "" ); + const char *pszAttachOffset = pSingleCP->GetString( "attachment_offset", "" ); + + // Convert control point + int iControlPoint = atoi(pszControlPoint); // Convert attach type int iAttachType = GetAttachTypeFromString( pszAttachType ); @@ -1273,56 +1258,37 @@ void C_BaseAnimating::DelayedInitModelEffects( void ) return; } - // Convert attachment point - int iAttachment = atoi(pszAttachment); - // See if we can find any attachment points matching the name - if ( pszAttachment[0] != '0' && iAttachment == 0 ) + Vector vecOffset = vec3_origin; + + if ( pszAttachOffset ) { - iAttachment = LookupAttachment( pszAttachment ); - if ( iAttachment <= 0 ) - { - Warning("Failed to find attachment point specified for particle effect in model '%s' keyvalues section. Trying to spawn effect '%s' on attachment named '%s'\n", GetModelName(), pszParticleEffect, pszAttachment ); - return; - } + float flVec[3]; + UTIL_StringToVector( flVec, pszAttachOffset ); + vecOffset = Vector( flVec[0], flVec[1], flVec[2] ); } - #ifdef TF_CLIENT_DLL - // Halloween Hack for Sentry Rockets - if ( !V_strcmp( "sentry_rocket", pszParticleEffect ) ) + + // Add the control point if we already have the effect + if ( hModelEffect ) { - // Halloween Spell Effect Check - int iHalloweenSpell = 0; - // if the owner is a Sentry, Check its owner - CBaseObject *pSentry = dynamic_cast( GetOwnerEntity() ); - if ( pSentry ) - { - CALL_ATTRIB_HOOK_INT_ON_OTHER( pSentry->GetOwner(), iHalloweenSpell, halloween_pumpkin_explosions ); - } + if ( iAttachType == PATTACH_WORLDORIGIN ) + ParticleProp()->AddControlPoint( hModelEffect, iControlPoint, NULL, (ParticleAttachment_t)iAttachType, NULL, vecOffset ); else - { - CALL_ATTRIB_HOOK_INT_ON_OTHER( GetOwnerEntity(), iHalloweenSpell, halloween_pumpkin_explosions ); - } - - if ( iHalloweenSpell > 0 ) - { - pszParticleEffect = "halloween_rockettrail"; - } + ParticleProp()->AddControlPoint( hModelEffect, iControlPoint, this, (ParticleAttachment_t)iAttachType, pszAttachment, vecOffset ); } - #endif - // Spawn the particle effect - ParticleProp()->Create( pszParticleEffect, (ParticleAttachment_t)iAttachType, iAttachment ); + } } } } - - modelKeyValues->deleteThis(); } void C_BaseAnimating::TermRopes() { FOR_EACH_LL( m_Ropes, i ) - m_Ropes[i]->Release(); + { + UTIL_Remove( m_Ropes[i] ); + } m_Ropes.Purge(); } @@ -1339,7 +1305,7 @@ void C_BaseAnimating::GetBoneControllers(float controllers[MAXSTUDIOBONECTRLS]) } } -float C_BaseAnimating::GetPoseParameter( int iPoseParameter ) +float C_BaseAnimating::GetPoseParameterRaw( int iPoseParameter ) { CStudioHdr *pStudioHdr = GetModelPtr(); @@ -1370,7 +1336,7 @@ void C_BaseAnimating::GetPoseParameters( CStudioHdr *pStudioHdr, float poseParam #if 0 // _DEBUG - if (/* Q_stristr( pStudioHdr->pszName(), r_sequence_debug.GetString()) != NULL || */ r_sequence_debug.GetInt() == entindex()) + if (r_sequence_debug.GetInt() == entindex()) { DevMsgRT( "%s\n", pStudioHdr->pszName() ); DevMsgRT( "%6.2f : ", gpGlobals->curtime ); @@ -1405,30 +1371,86 @@ float C_BaseAnimating::ClampCycle( float flCycle, bool isLooping ) } -void C_BaseAnimating::GetCachedBoneMatrix( int boneIndex, matrix3x4_t &out ) +void C_BaseAnimating::EnableJiggleBones( void ) { - MatrixCopy( GetBone( boneIndex ), out ); + m_isJiggleBonesEnabled = true; } -//----------------------------------------------------------------------------- -// Purpose: move position and rotation transforms into global matrices -//----------------------------------------------------------------------------- -void C_BaseAnimating::BuildTransformations( CStudioHdr *hdr, Vector *pos, Quaternion *q, const matrix3x4_t &cameraTransform, int boneMask, CBoneBitList &boneComputed ) +void C_BaseAnimating::DisableJiggleBones( void ) { - VPROF_BUDGET( "C_BaseAnimating::BuildTransformations", VPROF_BUDGETGROUP_CLIENT_ANIMATION ); + m_isJiggleBonesEnabled = false; - if ( !hdr ) + // clear old data so any jiggle bones don't pop if they're enabled again + if ( m_pJiggleBones ) + { + delete m_pJiggleBones; + m_pJiggleBones = NULL; + } +} + +void C_BaseAnimating::ScriptSetPoseParameter( const char *szName, float fValue ) +{ + CStudioHdr *pHdr = GetModelPtr(); + if ( pHdr == NULL ) return; - matrix3x4_t bonematrix; - bool boneSimulated[MAXSTUDIOBONES]; + int iPoseParam = LookupPoseParameter( pHdr, szName ); + SetPoseParameter( pHdr, iPoseParam, fValue ); +} - // no bones have been simulated - memset( boneSimulated, 0, sizeof(boneSimulated) ); - mstudiobone_t *pbones = hdr->pBone( 0 ); +void C_BaseAnimating::GetCachedBoneMatrix( int boneIndex, matrix3x4_t &out ) +{ + MatrixCopy( GetBone( boneIndex ), out ); +} - if ( m_pRagdoll ) + +//----------------------------------------------------------------------------- +// Purpose: Merge shared bones over from "followed" entity +//----------------------------------------------------------------------------- + +void C_BaseAnimating::CalcBoneMerge( CStudioHdr *hdr, int boneMask, CBoneBitList &boneComputed ) +{ + // For EF_BONEMERGE entities, copy the bone matrices for any bones that have matching names. + bool boneMerge = IsEffectActive(EF_BONEMERGE); + if ( boneMerge || m_pBoneMergeCache ) + { + if ( boneMerge ) + { + if ( !m_pBoneMergeCache ) + { + m_pBoneMergeCache = new CBoneMergeCache; + m_pBoneMergeCache->Init( this ); + } + m_pBoneMergeCache->MergeMatchingBones( boneMask, boneComputed ); + } + else + { + delete m_pBoneMergeCache; + m_pBoneMergeCache = NULL; + } + } +} + + +//----------------------------------------------------------------------------- +// Purpose: move position and rotation transforms into global matrices +//----------------------------------------------------------------------------- +void C_BaseAnimating::BuildTransformations( CStudioHdr *hdr, Vector *pos, Quaternion *q, const matrix3x4_t &cameraTransform, int boneMask, CBoneBitList &boneComputed ) +{ + VPROF_BUDGET( "C_BaseAnimating::BuildTransformations", ( !g_bInThreadedBoneSetup ) ? VPROF_BUDGETGROUP_CLIENT_ANIMATION : "Client_Animation_Threaded" ); + + if ( !hdr ) + return; + + matrix3x4a_t bonematrix; + bool boneSimulated[MAXSTUDIOBONES]; + + // no bones have been simulated + memset( boneSimulated, 0, sizeof(boneSimulated) ); + mstudiobone_t *pbones = hdr->pBone( 0 ); + bool bFixupSimulatedPositions = false; + if ( m_pRagdoll ) { // simulate bones and update flags int oldWritableBones = m_BoneAccessor.GetWritableBones(); @@ -1436,8 +1458,8 @@ void C_BaseAnimating::BuildTransformations( CStudioHdr *hdr, Vector *pos, Quater m_BoneAccessor.SetWritableBones( BONE_USED_BY_ANYTHING ); m_BoneAccessor.SetReadableBones( BONE_USED_BY_ANYTHING ); -#if defined( REPLAY_ENABLED ) // If we're playing back a demo, override the ragdoll bones with cached version if available - otherwise, simulate. +#if defined( REPLAY_ENABLED ) if ( ( !engine->IsPlayingDemo() && !engine->IsPlayingTimeDemo() ) || !CReplayRagdollCache::Instance().IsInitialized() || !CReplayRagdollCache::Instance().GetFrame( this, engine->GetDemoPlaybackTick(), boneSimulated, &m_BoneAccessor ) ) @@ -1448,52 +1470,44 @@ void C_BaseAnimating::BuildTransformations( CStudioHdr *hdr, Vector *pos, Quater m_BoneAccessor.SetWritableBones( oldWritableBones ); m_BoneAccessor.SetReadableBones( oldReadableBones ); + bFixupSimulatedPositions = !m_pRagdoll->GetRagdoll()->allowStretch; } // For EF_BONEMERGE entities, copy the bone matrices for any bones that have matching names. - bool boneMerge = IsEffectActive(EF_BONEMERGE); - if ( boneMerge || m_pBoneMergeCache ) - { - if ( boneMerge ) - { - if ( !m_pBoneMergeCache ) - { - m_pBoneMergeCache = new CBoneMergeCache; - m_pBoneMergeCache->Init( this ); - } - m_pBoneMergeCache->MergeMatchingBones( boneMask ); - } - else - { - delete m_pBoneMergeCache; - m_pBoneMergeCache = NULL; - } - } + CalcBoneMerge( hdr, boneMask, boneComputed ); for (int i = 0; i < hdr->numbones(); i++) { // Only update bones reference by the bone mask. if ( !( hdr->boneFlags( i ) & boneMask ) ) - { continue; - } - if ( m_pBoneMergeCache && m_pBoneMergeCache->IsBoneMerged( i ) ) - continue; + PREFETCH360( &GetBoneForWrite( i ), 0 ); - // animate all non-simulated bones - if ( boneSimulated[i] || CalcProceduralBone( hdr, i, m_BoneAccessor )) + // skip bones that are already setup + if (boneComputed.IsBoneMarked( i )) + { + // dummy operation, just used to verify in debug that this should have happened + GetBoneForWrite( i ); + } + else if ( boneSimulated[i] ) { + ApplyBoneMatrixTransform( GetBoneForWrite( i ) ); + if ( bFixupSimulatedPositions && pbones[i].parent != -1 ) + { + Vector boneOrigin; + VectorTransform( pos[i], GetBone(pbones[i].parent), boneOrigin ); + PositionMatrix( boneOrigin, GetBoneForWrite( i ) ); + } continue; } - // skip bones that the IK has already setup - else if (boneComputed.IsBoneMarked( i )) + else if ( CalcProceduralBone( hdr, i, m_BoneAccessor )) { - // dummy operation, just used to verify in debug that this should have happened - GetBoneForWrite( i ); + continue; } else { + // animate all non-simulated bones QuaternionMatrix( q[i], pos[i], bonematrix ); Assert( fabs( pos[i].x ) < 100000 ); @@ -1501,7 +1515,19 @@ void C_BaseAnimating::BuildTransformations( CStudioHdr *hdr, Vector *pos, Quater Assert( fabs( pos[i].z ) < 100000 ); if ( (hdr->boneFlags( i ) & BONE_ALWAYS_PROCEDURAL) && - (hdr->pBone( i )->proctype & STUDIO_PROC_JIGGLE) ) + (hdr->pBone( i )->proctype & STUDIO_PROC_JIGGLE) && + !r_jiggle_bones.GetBool() ) + { + if ( m_pJiggleBones ) + { + delete m_pJiggleBones; + m_pJiggleBones = NULL; + } + } + + if ( (hdr->boneFlags( i ) & BONE_ALWAYS_PROCEDURAL) && + (hdr->pBone( i )->proctype & STUDIO_PROC_JIGGLE) && + r_jiggle_bones.GetBool() && m_isJiggleBonesEnabled ) { // // Physics-based "jiggle" bone @@ -1510,7 +1536,7 @@ void C_BaseAnimating::BuildTransformations( CStudioHdr *hdr, Vector *pos, Quater // // compute desired bone orientation - matrix3x4_t goalMX; + matrix3x4a_t goalMX; if (pbones[i].parent == -1) { @@ -1518,7 +1544,7 @@ void C_BaseAnimating::BuildTransformations( CStudioHdr *hdr, Vector *pos, Quater } else { - ConcatTransforms( GetBone( pbones[i].parent ), bonematrix, goalMX ); + ConcatTransforms_Aligned( GetBone( pbones[i].parent ), bonematrix, goalMX ); } // get jiggle properties from QC data @@ -1530,7 +1556,7 @@ void C_BaseAnimating::BuildTransformations( CStudioHdr *hdr, Vector *pos, Quater } // do jiggle physics - m_pJiggleBones->BuildJiggleTransformations( i, gpGlobals->realtime, jiggleInfo, goalMX, GetBoneForWrite( i ) ); + m_pJiggleBones->BuildJiggleTransformations( i, gpGlobals->curtime, jiggleInfo, goalMX, GetBoneForWrite( i ) ); } else if (hdr->boneParent(i) == -1) @@ -1539,7 +1565,7 @@ void C_BaseAnimating::BuildTransformations( CStudioHdr *hdr, Vector *pos, Quater } else { - ConcatTransforms( GetBone( hdr->boneParent(i) ), bonematrix, GetBoneForWrite( i ) ); + ConcatTransforms_Aligned( GetBone( hdr->boneParent(i) ), bonematrix, GetBoneForWrite( i ) ); } } @@ -1549,8 +1575,6 @@ void C_BaseAnimating::BuildTransformations( CStudioHdr *hdr, Vector *pos, Quater ApplyBoneMatrixTransform( GetBoneForWrite( i ) ); } } - - } //----------------------------------------------------------------------------- @@ -1559,56 +1583,17 @@ void C_BaseAnimating::BuildTransformations( CStudioHdr *hdr, Vector *pos, Quater //----------------------------------------------------------------------------- void C_BaseAnimating::ApplyBoneMatrixTransform( matrix3x4_t& transform ) { - switch( m_nRenderFX ) - { - case kRenderFxDistort: - case kRenderFxHologram: - if ( RandomInt(0,49) == 0 ) - { - int axis = RandomInt(0,1); - if ( axis == 1 ) // Choose between x & z - axis = 2; - VectorScale( transform[axis], RandomFloat(1,1.484), transform[axis] ); - } - else if ( RandomInt(0,49) == 0 ) - { - float offset; - int axis = RandomInt(0,1); - if ( axis == 1 ) // Choose between x & z - axis = 2; - offset = RandomFloat(-10,10); - transform[RandomInt(0,2)][3] += offset; - } - break; - case kRenderFxExplode: - { - float scale; - - scale = 1.0 + (gpGlobals->curtime - m_flAnimTime) * 10.0; - if ( scale > 2 ) // Don't blow up more than 200% - scale = 2; - transform[0][1] *= scale; - transform[1][1] *= scale; - transform[2][1] *= scale; - } - break; - default: - break; - - } - - if ( IsModelScaled() ) + float scale = GetModelScale(); + if ( scale > 1.0f+FLT_EPSILON || scale < 1.0f-FLT_EPSILON ) { // The bone transform is in worldspace, so to scale this, we need to translate it back - float scale = GetModelScale(); - Vector pos; MatrixGetColumn( transform, 3, pos ); pos -= GetRenderOrigin(); pos *= scale; pos += GetRenderOrigin(); MatrixSetColumn( pos, 3, transform ); - + VectorScale( transform[0], scale, transform[0] ); VectorScale( transform[1], scale, transform[1] ); VectorScale( transform[2], scale, transform[2] ); @@ -1776,7 +1761,7 @@ void C_BaseAnimating::MaintainSequenceTransitions( IBoneSetup &boneSetup, float boneSetup.GetStudioHdr(), GetSequence(), m_nNewSequenceParity != m_nPrevNewSequenceParity, - !IsNoInterpolationFrame() + !IsEffectActive(EF_NOINTERP) ); m_nPrevNewSequenceParity = m_nNewSequenceParity; @@ -1786,7 +1771,7 @@ void C_BaseAnimating::MaintainSequenceTransitions( IBoneSetup &boneSetup, float boneSetup.GetStudioHdr(), GetSequence(), flCycle, - m_flPlaybackRate, + GetPlaybackRate(), gpGlobals->curtime ); @@ -1794,20 +1779,20 @@ void C_BaseAnimating::MaintainSequenceTransitions( IBoneSetup &boneSetup, float // process previous sequences for (int i = m_SequenceTransitioner.m_animationQueue.Count() - 2; i >= 0; i--) { - C_AnimationLayer *blend = &m_SequenceTransitioner.m_animationQueue[i]; + CAnimationLayer *blend = &m_SequenceTransitioner.m_animationQueue[i]; float dt = (gpGlobals->curtime - blend->m_flLayerAnimtime); - flCycle = blend->m_flCycle + dt * blend->m_flPlaybackRate * GetSequenceCycleRate( boneSetup.GetStudioHdr(), blend->m_nSequence ); - flCycle = ClampCycle( flCycle, IsSequenceLooping( boneSetup.GetStudioHdr(), blend->m_nSequence ) ); + flCycle = blend->GetCycle() + dt * blend->GetPlaybackRate() * GetSequenceCycleRate( boneSetup.GetStudioHdr(), blend->GetSequence() ); + flCycle = ClampCycle( flCycle, IsSequenceLooping( boneSetup.GetStudioHdr(), blend->GetSequence() ) ); #if 1 // _DEBUG - if (/*Q_stristr( hdr->pszName(), r_sequence_debug.GetString()) != NULL || */ r_sequence_debug.GetInt() == entindex()) + if (r_sequence_debug.GetInt() == entindex()) { - DevMsgRT( "%8.4f : %30s : %5.3f : %4.2f +\n", gpGlobals->curtime, boneSetup.GetStudioHdr()->pSeqdesc( blend->m_nSequence ).pszLabel(), flCycle, (float)blend->m_flWeight ); + DevMsgRT( "%8.4f : %30s : %5.3f : %4.2f +\n", gpGlobals->curtime, boneSetup.GetStudioHdr()->pSeqdesc( blend->GetSequence() ).pszLabel(), flCycle, (float)blend->GetWeight() ); } #endif - boneSetup.AccumulatePose( pos, q, blend->m_nSequence, flCycle, blend->m_flWeight, gpGlobals->curtime, m_pIk ); + boneSetup.AccumulatePose( pos, q, blend->GetSequence(), flCycle, blend->GetWeight(), gpGlobals->curtime, m_pIk ); } } @@ -1851,53 +1836,11 @@ void C_BaseAnimating::AccumulateLayers( IBoneSetup &boneSetup, Vector pos[], Qua // Nothing here } -void C_BaseAnimating::ChildLayerBlend( Vector pos[], Quaternion q[], float currentTime, int boneMask ) -{ - return; - - Vector childPos[MAXSTUDIOBONES]; - Quaternion childQ[MAXSTUDIOBONES]; - float childPoseparam[MAXSTUDIOPOSEPARAM]; - - // go through all children - for ( C_BaseEntity *pChild = FirstMoveChild(); pChild; pChild = pChild->NextMovePeer() ) - { - C_BaseAnimating *pChildAnimating = pChild->GetBaseAnimating(); - - if ( pChildAnimating ) - { - CStudioHdr *pChildHdr = pChildAnimating->GetModelPtr(); - - // FIXME: needs a new type of EF_BONEMERGE (EF_CHILDMERGE?) - if ( pChildHdr && pChild->IsEffectActive( EF_BONEMERGE ) && pChildHdr->SequencesAvailable() && pChildAnimating->m_pBoneMergeCache ) - { - // FIXME: these should Inherit from the parent - GetPoseParameters( pChildHdr, childPoseparam ); - - IBoneSetup childBoneSetup( pChildHdr, boneMask, childPoseparam ); - childBoneSetup.InitPose( childPos, childQ ); - - // set up the child into the parent's current pose - pChildAnimating->m_pBoneMergeCache->CopyParentToChild( pos, q, childPos, childQ, boneMask ); - - // FIXME: needs some kind of sequence - // merge over whatever bones the childs sequence modifies - childBoneSetup.AccumulatePose( childPos, childQ, 0, GetCycle(), 1.0, currentTime, NULL ); - - // copy the result back into the parents bones - pChildAnimating->m_pBoneMergeCache->CopyChildToParent( childPos, childQ, pos, q, boneMask ); - - // probably needs an IK merge system of some sort =( - } - } - } -} - //----------------------------------------------------------------------------- // Purpose: Do the default sequence blending rules as done in HL1 //----------------------------------------------------------------------------- -void C_BaseAnimating::StandardBlendingRules( CStudioHdr *hdr, Vector pos[], Quaternion q[], float currentTime, int boneMask ) +void C_BaseAnimating::StandardBlendingRules( CStudioHdr *hdr, Vector pos[], QuaternionAligned q[], float currentTime, int boneMask ) { VPROF( "C_BaseAnimating::StandardBlendingRules" ); @@ -1915,6 +1858,19 @@ void C_BaseAnimating::StandardBlendingRules( CStudioHdr *hdr, Vector pos[], Quat { SetSequence( 0 ); } + +#ifdef DEMOPOLISH_ENABLED + if ( IsDemoPolishPlaying() && IsPlayer() ) + { + float const flDemoPlaybackTime = DemoPolish_GetController().GetAdjustedPlaybackTime(); + int const iSequenceOverride = DemoPolish_GetController().GetSequenceOverride( entindex(), flDemoPlaybackTime ); + if ( iSequenceOverride >= 0 ) + { + // Override. + SetSequence( iSequenceOverride ); + } + } +#endif GetPoseParameters( hdr, poseparam ); @@ -1922,9 +1878,9 @@ void C_BaseAnimating::StandardBlendingRules( CStudioHdr *hdr, Vector pos[], Quat float fCycle = GetCycle(); #if 1 //_DEBUG - if (/* Q_stristr( hdr->pszName(), r_sequence_debug.GetString()) != NULL || */ r_sequence_debug.GetInt() == entindex()) + if (r_sequence_debug.GetInt() == entindex()) { - DevMsgRT( "%8.4f : %30s : %5.3f : %4.2f\n", currentTime, hdr->pSeqdesc( GetSequence() ).pszLabel(), fCycle, 1.0 ); + DevMsgRT( "%8.4f : %30s(%d) : %5.3f : %4.2f\n", currentTime, hdr->pSeqdesc( GetSequence() ).pszLabel(), GetSequence(), fCycle, 1.0 ); } #endif @@ -1948,20 +1904,18 @@ void C_BaseAnimating::StandardBlendingRules( CStudioHdr *hdr, Vector pos[], Quat GetBoneControllers(controllers); boneSetup.CalcBoneAdj( pos, q, controllers ); } - - ChildLayerBlend( pos, q, currentTime, boneMask ); - UnragdollBlend( hdr, pos, q, currentTime ); #ifdef STUDIO_ENABLE_PERF_COUNTERS #if _DEBUG - if (Q_stristr( hdr->pszName(), r_sequence_debug.GetString()) != NULL) + /* + if (r_sequence_debug.GetInt() == entindex() ) { DevMsgRT( "layers %4d : bones %4d : animated %4d\n", hdr->m_nPerfAnimationLayers, hdr->m_nPerfUsedBones, hdr->m_nPerfAnimatedBones ); } + */ #endif #endif - } @@ -1998,6 +1952,17 @@ bool C_BaseAnimating::PutAttachment( int number, const matrix3x4_t &attachmentTo return true; } +// when hierarchy changes, these are no longer valid for comparison. munge the frame counter so they +// get ignored +void C_BaseAnimating::InvalidateAttachments() +{ + int frameCount = -1; + for ( int i = 0; i < m_Attachments.Count(); i++ ) + { + m_Attachments[i].m_nLastFramecount = frameCount; + } +} + void C_BaseAnimating::SetupBones_AttachmentHelper( CStudioHdr *hdr ) { @@ -2021,7 +1986,7 @@ void C_BaseAnimating::SetupBones_AttachmentHelper( CStudioHdr *hdr ) VectorTransform( vecLocalBonePos, GetBone( iBone ), vecWorldBonePos ); SetIdentityMatrix( world ); - MatrixSetColumn( vecWorldBonePos, 3, world ); + PositionMatrix( vecWorldBonePos, world ); } // FIXME: this shouldn't be here, it should client side on-demand only and hooked into the bone cache!! @@ -2177,19 +2142,6 @@ bool C_BaseAnimating::GetAttachmentLocal( int iAttachment, Vector &origin ) return false; } -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -bool C_BaseAnimating::GetRootBone( matrix3x4_t &rootBone ) -{ - Assert( !IsDynamicModelLoading() ); - - if ( IsEffectActive( EF_BONEMERGE ) && GetMoveParent() && m_pBoneMergeCache ) - return m_pBoneMergeCache->GetRootBone( rootBone ); - - GetBoneTransform( 0, rootBone ); - return true; -} //----------------------------------------------------------------------------- // Purpose: Move sound location to center of body @@ -2224,62 +2176,16 @@ bool C_BaseAnimating::IsViewModel() const return false; } -bool C_BaseAnimating::IsMenuModel() const +bool C_BaseAnimating::IsViewModelOrAttachment() const { return false; } -// UNDONE: Seems kind of silly to have this when we also have the cached bones in C_BaseAnimating -CBoneCache *C_BaseAnimating::GetBoneCache( CStudioHdr *pStudioHdr ) +bool C_BaseAnimating::IsMenuModel() const { - int boneMask = BONE_USED_BY_HITBOX; - CBoneCache *pcache = Studio_GetBoneCache( m_hitboxBoneCacheHandle ); - if ( pcache ) - { - if ( pcache->IsValid( gpGlobals->curtime, 0.0 ) ) - { - // in memory and still valid, use it! - return pcache; - } - // in memory, but not the same bone set, destroy & rebuild - if ( (pcache->m_boneMask & boneMask) != boneMask ) - { - Studio_DestroyBoneCache( m_hitboxBoneCacheHandle ); - m_hitboxBoneCacheHandle = 0; - pcache = NULL; - } - } - - if ( !pStudioHdr ) - pStudioHdr = GetModelPtr( ); - Assert(pStudioHdr); - - C_BaseAnimating::PushAllowBoneAccess( true, false, "GetBoneCache" ); - SetupBones( NULL, -1, boneMask, gpGlobals->curtime ); - C_BaseAnimating::PopBoneAccess( "GetBoneCache" ); - - if ( pcache ) - { - // still in memory but out of date, refresh the bones. - pcache->UpdateBones( m_CachedBoneData.Base(), pStudioHdr->numbones(), gpGlobals->curtime ); - } - else - { - bonecacheparams_t params; - params.pStudioHdr = pStudioHdr; - // HACKHACK: We need the pointer to all bones here - params.pBoneToWorld = m_CachedBoneData.Base(); - params.curtime = gpGlobals->curtime; - params.boneMask = boneMask; - - m_hitboxBoneCacheHandle = Studio_CreateBoneCache( params ); - pcache = Studio_GetBoneCache( m_hitboxBoneCacheHandle ); - } - Assert(pcache); - return pcache; + return false; } - class CTraceFilterSkipNPCsAndPlayers : public CTraceFilterSimple { public: @@ -2296,8 +2202,13 @@ class CTraceFilterSkipNPCsAndPlayers : public CTraceFilterSimple if ( !pEntity ) return true; - if ( pEntity->IsNPC() || pEntity->IsPlayer() ) - return false; + do + { + if ( pEntity->IsNPC() || pEntity->IsPlayer() ) + { + return false; + } + } while ( ( pEntity = pEntity->GetMoveParent() ) != NULL ); return true; } @@ -2535,7 +2446,7 @@ void C_BaseAnimating::CalculateIKLocks( float currentTime ) // FIXME: make entity finding sticky! // FIXME: what should the radius check be? - for ( CEntitySphereQuery sphere( pTarget->est.pos, 64 ); ( pEntity = sphere.GetCurrentEntity() ) != NULL; sphere.NextEntity() ) + for ( CEntitySphereQuery sphere( pTarget->est.pos, 64, 0, PARTITION_CLIENT_IK_ATTACHMENT ); ( pEntity = sphere.GetCurrentEntity() ) != NULL; sphere.NextEntity() ) { C_BaseAnimating *pAnim = pEntity->GetBaseAnimating( ); if (!pAnim) @@ -2647,73 +2558,177 @@ CMouthInfo *C_BaseAnimating::GetMouth( void ) #ifdef DEBUG_BONE_SETUP_THREADING ConVar cl_warn_thread_contested_bone_setup("cl_warn_thread_contested_bone_setup", "0" ); #endif -ConVar cl_threaded_bone_setup("cl_threaded_bone_setup", "0", 0, "Enable parallel processing of C_BaseAnimating::SetupBones()" ); +ConVar cl_threaded_bone_setup("cl_threaded_bone_setup", ( IsX360() ) ? "1" : "0", 0, "Enable parallel processing of C_BaseAnimating::SetupBones()" ); //----------------------------------------------------------------------------- // Purpose: Do the default sequence blending rules as done in HL1 //----------------------------------------------------------------------------- -static void SetupBonesOnBaseAnimating( C_BaseAnimating *&pBaseAnimating ) +#ifdef DEBUG_BONE_SETUP_THREADING +CThreadLocalInt<> *pCount; +#endif + +void C_BaseAnimating::SetupBonesOnBaseAnimating( C_BaseAnimating *&pBaseAnimating ) { - if ( !pBaseAnimating->GetMoveParent() ) - pBaseAnimating->SetupBones( NULL, -1, -1, gpGlobals->curtime ); + C_BaseAnimating *pCurrent = pBaseAnimating; + C_BaseAnimating *pNext; + while ( pCurrent ) + { + pNext = pCurrent->m_pNextForThreadedBoneSetup; + pCurrent->m_pNextForThreadedBoneSetup = NULL; + pCurrent->SetupBones( NULL, -1, -1, gpGlobals->curtime ); + pCurrent = pNext; + } + +#ifdef DEBUG_BONE_SETUP_THREADING + (*pCount)++; +#endif } static void PreThreadedBoneSetup() { + mdlcache->BeginCoarseLock(); mdlcache->BeginLock(); } static void PostThreadedBoneSetup() { mdlcache->EndLock(); + mdlcache->EndCoarseLock(); +#ifdef DEBUG_BONE_SETUP_THREADING + Msg( " %x done, %d\n", ThreadGetCurrentId(), (int)(*pCount) ); + (*pCount) = 0; +#endif } -static bool g_bInThreadedBoneSetup; static bool g_bDoThreadedBoneSetup; +IThreadPool *g_pBoneSetupThreadPool; void C_BaseAnimating::InitBoneSetupThreadPool() { +#ifdef DEBUG_BONE_SETUP_THREADING + pCount = new CThreadLocalInt<>; +#endif + if ( IsX360() ) + { +#ifdef _X360 + g_pBoneSetupThreadPool = g_pAlternateThreadPool; +#endif + } + else + { + g_pBoneSetupThreadPool = g_pThreadPool; + } } void C_BaseAnimating::ShutdownBoneSetupThreadPool() { } +void C_BaseAnimating::MarkForThreadedBoneSetup() +{ + if ( g_bDoThreadedBoneSetup && !g_bInThreadedBoneSetup && m_iMostRecentBoneSetupRequest != g_iPreviousBoneCounter ) + { + if ( !IsViewModel() ) + { + // This function is protected by m_BoneSetupLock (see SetupBones) + if ( m_iMostRecentBoneSetupRequest != g_iPreviousBoneCounter ) + { + m_iMostRecentBoneSetupRequest = g_iPreviousBoneCounter; + LOCAL_THREAD_LOCK(); + Assert( g_PreviousBoneSetups.Find( this ) == -1 ); + g_PreviousBoneSetups.AddToTail( this ); + } + } + } +} + void C_BaseAnimating::ThreadedBoneSetup() { - g_bDoThreadedBoneSetup = cl_threaded_bone_setup.GetBool(); + g_bDoThreadedBoneSetup = ( g_pBoneSetupThreadPool && g_pBoneSetupThreadPool->NumThreads() && cl_threaded_bone_setup.GetInt() ); if ( g_bDoThreadedBoneSetup ) { int nCount = g_PreviousBoneSetups.Count(); if ( nCount > 1 ) { - g_bInThreadedBoneSetup = true; + VPROF_BUDGET( "C_BaseAnimating::ThreadedBoneSetup", "Client_Animation_Threaded" ); - ParallelProcess( "C_BaseAnimating::ThreadedBoneSetup", g_PreviousBoneSetups.Base(), nCount, &SetupBonesOnBaseAnimating, &PreThreadedBoneSetup, &PostThreadedBoneSetup ); +#ifdef DEBUG_BONE_SETUP_THREADING + Msg( "{\n" ); +#endif + // This loop is here rather than the mark function so we don't have to worry about the list being threadsafe, or worry about entity destruction +#ifdef _DEBUG + CUtlVector test; + test.AddVectorToTail( g_PreviousBoneSetups ); +#endif + for ( int i = g_PreviousBoneSetups.Count() - 1; i >= 0; i-- ) + { + C_BaseAnimating *pAnimating = g_PreviousBoneSetups[i]; + C_BaseAnimating *pParent; + if ( pAnimating->GetMoveParent() && ( pParent = pAnimating->GetMoveParent()->GetBaseAnimating() ) != NULL ) + { + Assert( pAnimating->m_pNextForThreadedBoneSetup == NULL ); + C_BaseAnimating *pNextParent; + while ( pParent->GetMoveParent() && ( pNextParent = pParent->GetMoveParent()->GetBaseAnimating() ) != NULL ) + { + pParent = pNextParent; + } + + pAnimating->m_pNextForThreadedBoneSetup = pParent->m_pNextForThreadedBoneSetup; + pParent->m_pNextForThreadedBoneSetup = pAnimating; + g_PreviousBoneSetups.FastRemove( i ); + if ( pParent->m_iMostRecentBoneSetupRequest != g_iPreviousBoneCounter ) + { + Assert( g_PreviousBoneSetups.Find( pParent ) == -1 ); + pParent->m_iMostRecentBoneSetupRequest = g_iPreviousBoneCounter; + g_PreviousBoneSetups.AddToTail( pParent ); + } + } + } + nCount = g_PreviousBoneSetups.Count(); + g_bInThreadedBoneSetup = true; + if ( cl_threaded_bone_setup.GetInt() == 1 ) + { + CParallelProcessor, 2 > processor; + processor.m_ItemProcessor.Init( &SetupBonesOnBaseAnimating, &PreThreadedBoneSetup, &PostThreadedBoneSetup ); + processor.Run( g_PreviousBoneSetups.Base(), nCount, 1, INT_MAX, g_pBoneSetupThreadPool ); + } + else + { + for ( int i = 0; i < nCount; i++ ) + { + SetupBonesOnBaseAnimating( g_PreviousBoneSetups[i] ); + } + } g_bInThreadedBoneSetup = false; + +#ifdef _DEBUG + for ( int i = test.Count() - 1; i > 0; i-- ) + { + Assert( test[i]->m_pNextForThreadedBoneSetup == NULL ); + } +#endif + +#ifdef DEBUG_BONE_SETUP_THREADING + Msg( "} \n" ); +#endif } } g_iPreviousBoneCounter++; g_PreviousBoneSetups.RemoveAll(); } -bool C_BaseAnimating::SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime ) +bool C_BaseAnimating::InThreadedBoneSetup() { - VPROF_BUDGET( "C_BaseAnimating::SetupBones", VPROF_BUDGETGROUP_CLIENT_ANIMATION ); + return g_bInThreadedBoneSetup; +} - //============================================================================= - // HPE_BEGIN: - // [pfreese] Added the check for pBoneToWorldOut != NULL in this debug warning - // code. SetupBones is called in the CSS anytime an attachment wants its - // parent's transform, hence this warning is hit extremely frequently. - // I'm not actually sure if this is the right "fix" for this, as the bones are - // actually accessed as part of the setup process, but since I'm not clear on the - // purpose of this dev warning, I'm including this comment block. - //============================================================================= +bool C_BaseAnimating::SetupBones( matrix3x4a_t *pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime ) +{ + VPROF_BUDGET( "C_BaseAnimating::SetupBones", ( !g_bInThreadedBoneSetup ) ? VPROF_BUDGETGROUP_CLIENT_ANIMATION : "Client_Animation_Threaded" ); - if ( pBoneToWorldOut != NULL && !IsBoneAccessAllowed() ) + if ( !IsBoneAccessAllowed() ) { static float lastWarning = 0.0f; @@ -2748,12 +2763,42 @@ bool C_BaseAnimating::SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, i boneMask |= BONE_USED_BY_ANYTHING; } + // Or lastly if demo polish recording +#ifdef DEMOPOLISH_ENABLED + if ( IsDemoPolishRecording() && IsPlayer() ) + { + boneMask |= BONE_USED_BY_ANYTHING; + } +#endif // DEMO_POLISH + if ( g_bInThreadedBoneSetup ) { +// boneMask |= ( BONE_USED_BY_ATTACHMENT | BONE_USED_BY_BONE_MERGE | BONE_USED_BY_HITBOX ); + if ( !m_BoneSetupLock.TryLock() ) { + // someone else is handling return false; } + // else, we have the lock + } + else + { + m_BoneSetupLock.Lock(); + } + + // If we're setting up LOD N, we have set up all lower LODs also + // because lower LODs always use subsets of the bones of higher LODs. + int nLOD = 0; + int nMask = BONE_USED_BY_VERTEX_LOD0; + for( ; nLOD < MAX_NUM_LODS; ++nLOD, nMask <<= 1 ) + { + if ( boneMask & nMask ) + break; + } + for( ; nLOD < MAX_NUM_LODS; ++nLOD, nMask <<= 1 ) + { + boneMask |= nMask; } #ifdef DEBUG_BONE_SETUP_THREADING @@ -2768,20 +2813,22 @@ bool C_BaseAnimating::SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, i m_BoneSetupLock.Unlock(); } } -#endif - - AUTO_LOCK( m_BoneSetupLock ); +#endif - if ( g_bInThreadedBoneSetup ) + // A bit of a hack, but this way when in prediction we use the "correct" gpGlobals->curtime -- rather than the + // one that the player artificially advances + if ( GetPredictable() && + prediction->InPrediction() ) { - m_BoneSetupLock.Unlock(); + currentTime = prediction->GetSavedTime(); } if ( m_iMostRecentModelBoneCounter != g_iModelBoneCounter ) { // Clear out which bones we've touched this frame if this is // the first time we've seen this object this frame. - if ( LastBoneChangedTime() >= m_flLastBoneSetupTime ) + // BUGBUG: Time can go backward due to prediction, catch that here until a better solution is found + if ( LastBoneChangedTime() >= m_flLastBoneSetupTime || currentTime < m_flLastBoneSetupTime ) { m_BoneAccessor.SetReadableBones( 0 ); m_BoneAccessor.SetWritableBones( 0 ); @@ -2799,16 +2846,14 @@ bool C_BaseAnimating::SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, i #endif } - int nBoneCount = m_CachedBoneData.Count(); - if ( g_bDoThreadedBoneSetup && !g_bInThreadedBoneSetup && ( nBoneCount >= 16 ) && !GetMoveParent() && m_iMostRecentBoneSetupRequest != g_iPreviousBoneCounter ) - { - m_iMostRecentBoneSetupRequest = g_iPreviousBoneCounter; - Assert( g_PreviousBoneSetups.Find( this ) == -1 ); - g_PreviousBoneSetups.AddToTail( this ); - } + MarkForThreadedBoneSetup(); // Keep track of everthing asked for over the entire frame - m_iAccumulatedBoneMask |= boneMask; + // But not those things asked for during bone setup +// if ( !g_bInThreadedBoneSetup ) + { + m_iAccumulatedBoneMask |= boneMask; + } // Make sure that we know that we've already calculated some bone stuff this time around. m_iMostRecentModelBoneCounter = g_iModelBoneCounter; @@ -2820,10 +2865,13 @@ bool C_BaseAnimating::SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, i CStudioHdr *hdr = GetModelPtr(); if ( !hdr || !hdr->SequencesAvailable() ) + { + m_BoneSetupLock.Unlock(); return false; + } // Setup our transform based on render angles and origin. - matrix3x4_t parentTransform; + ALIGN16 matrix3x4_t parentTransform; AngleMatrix( GetRenderAngles(), GetRenderOrigin(), parentTransform ); // Load the boneMask with the total of what was asked for last frame. @@ -2834,13 +2882,30 @@ bool C_BaseAnimating::SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, i m_BoneAccessor.SetWritableBones( m_BoneAccessor.GetReadableBones() | boneMask ); m_BoneAccessor.SetReadableBones( m_BoneAccessor.GetWritableBones() ); + // label the entities if we're trying to figure out who is who + if ( r_sequence_debug.GetInt() == -1) + { + Vector theMins, theMaxs; + GetRenderBounds( theMins, theMaxs ); + debugoverlay->AddTextOverlay( GetAbsOrigin() + (theMins + theMaxs) * 0.5f, 0, 0.0f, "%d:%s", entindex(), hdr->name() ); + } + if (hdr->flags() & STUDIOHDR_FLAGS_STATIC_PROP) { MatrixCopy( parentTransform, GetBoneForWrite( 0 ) ); } else { - TrackBoneSetupEnt( this ); +#ifdef DEBUG_BONE_SETUP_THREADING + if ( !g_bInThreadedBoneSetup ) + { + Msg("!%x\n", this ); + } +#endif + if ( !g_bInThreadedBoneSetup ) + { + TrackBoneSetupEnt( this ); + } // This is necessary because it's possible that CalculateIKLocks will trigger our move children // to call GetAbsOrigin(), and they'll use our OLD bone transforms to get their attachments @@ -2849,40 +2914,24 @@ bool C_BaseAnimating::SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, i // Setting this flag forces move children to keep their abs transform invalidated. AddFlag( EFL_SETTING_UP_BONES ); - // NOTE: For model scaling, we need to opt out of IK because it will mark the bones as already being calculated - if ( !IsModelScaled() ) +// NOTE: For model scaling, we need to opt out of IK because it will mark the bones as already being calculated +#if defined( INFESTED ) + // only allocate an ik block if the npc can use it + if ( !m_pIk && hdr->numikchains() > 0 && !(m_EntClientFlags & ENTCLIENTFLAG_DONTUSEIK) ) + m_pIk = new CIKContext; +#endif + + Vector pos[MAXSTUDIOBONES]; + QuaternionAligned q[MAXSTUDIOBONES]; + + int bonesMaskNeedRecalc = boneMask | oldReadableBones; // Hack to always recalc bones, to fix the arm jitter in the new CS player anims until Ken makes the real fix + + if ( m_pIk ) { - // only allocate an ik block if the npc can use it - if ( !m_pIk && hdr->numikchains() > 0 && !(m_EntClientFlags & ENTCLIENTFLAG_DONTUSEIK) ) + if (Teleported() || IsEffectActive(EF_NOINTERP)) { - m_pIk = new CIKContext; + m_pIk->ClearTargets(); } - } - else - { - // Reset the IK - if ( m_pIk ) - { - delete m_pIk; - m_pIk = NULL; - } - } - - Vector pos[MAXSTUDIOBONES]; - Quaternion q[MAXSTUDIOBONES]; -#if defined(FP_EXCEPTIONS_ENABLED) || defined(DBGFLAG_ASSERT) - // Having these uninitialized means that some bugs are very hard - // to reproduce. A memset of 0xFF is a simple way of getting NaNs. - memset( pos, 0xFF, sizeof(pos) ); - memset( q, 0xFF, sizeof(q) ); -#endif - - int bonesMaskNeedRecalc = boneMask | oldReadableBones; // Hack to always recalc bones, to fix the arm jitter in the new CS player anims until Ken makes the real fix - - if ( m_pIk ) - { - if (Teleported() || IsNoInterpolationFrame()) - m_pIk->ClearTargets(); m_pIk->Init( hdr, GetRenderAngles(), GetRenderOrigin(), currentTime, gpGlobals->framecount, bonesMaskNeedRecalc ); } @@ -2893,6 +2942,15 @@ bool C_BaseAnimating::SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, i StandardBlendingRules( hdr, pos, q, currentTime, bonesMaskNeedRecalc ); CBoneBitList boneComputed; + +#ifdef DEMOPOLISH_ENABLED + bool const bShouldPolish = IsDemoPolishEnabled() && IsPlayer(); + if ( bShouldPolish && engine->IsPlayingDemo() ) + { + DemoPolish_GetController().MakeLocalAdjustments( entindex(), hdr, boneMask, pos, q, boneComputed ); + } +#endif + // don't calculate IK on ragdolls if ( m_pIk && !IsRagdoll() ) { @@ -2904,8 +2962,29 @@ bool C_BaseAnimating::SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, i m_pIk->SolveDependencies( pos, q, m_BoneAccessor.GetBoneArrayForWrite(), boneComputed ); } +#ifdef DEMOPOLISH_ENABLED + if ( m_bBonePolishSetup && bShouldPolish && engine->IsRecordingDemo() ) + { + DemoPolish_GetRecorder().RecordAnimData( entindex(), hdr, GetCycle(), parentTransform, pos, q, boneMask, m_BoneAccessor ); + } +#endif + BuildTransformations( hdr, pos, q, parentTransform, bonesMaskNeedRecalc, boneComputed ); - + +#ifdef DEMOPOLISH_ENABLED + // Override bones? + if ( bShouldPolish && engine->IsPlayingDemo() ) + { + DemoPolish_GetController().MakeGlobalAdjustments( entindex(), hdr, boneMask, m_BoneAccessor ); + } +#endif + + // Draw skeleton? + if ( enable_skeleton_draw.GetBool() ) + { + DrawSkeleton( hdr, boneMask ); + } + RemoveFlag( EFL_SETTING_UP_BONES ); ControlMouth( hdr ); } @@ -2922,15 +3001,17 @@ bool C_BaseAnimating::SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, i { if ( nMaxBones >= m_CachedBoneData.Count() ) { - memcpy( pBoneToWorldOut, m_CachedBoneData.Base(), sizeof( matrix3x4_t ) * m_CachedBoneData.Count() ); + Plat_FastMemcpy( pBoneToWorldOut, m_CachedBoneData.Base(), sizeof( matrix3x4_t ) * m_CachedBoneData.Count() ); } else { Warning( "SetupBones: invalid bone array size (%d - needs %d)\n", nMaxBones, m_CachedBoneData.Count() ); + m_BoneSetupLock.Unlock(); return false; } } + m_BoneSetupLock.Unlock(); return true; } @@ -2998,6 +3079,11 @@ static BoneAccess g_BoneAcessBase; bool C_BaseAnimating::IsBoneAccessAllowed() const { + if ( !ThreadInMainThread() ) + { + return true; + } + if ( IsViewModel() ) return g_BoneAcessBase.bAllowBoneAccessForViewModels; else @@ -3007,6 +3093,10 @@ bool C_BaseAnimating::IsBoneAccessAllowed() const // (static function) void C_BaseAnimating::PushAllowBoneAccess( bool bAllowForNormalModels, bool bAllowForViewModels, char const *tagPush ) { + if ( !ThreadInMainThread() ) + { + return; + } BoneAccess save = g_BoneAcessBase; g_BoneAccessStack.AddToTail( save ); @@ -3018,6 +3108,10 @@ void C_BaseAnimating::PushAllowBoneAccess( bool bAllowForNormalModels, bool bAll void C_BaseAnimating::PopBoneAccess( char const *tagPop ) { + if ( !ThreadInMainThread() ) + { + return; + } // Validate that pop matches the push Assert( ( g_BoneAcessBase.tag == tagPop ) || ( g_BoneAcessBase.tag && g_BoneAcessBase.tag != ( char const * ) 1 && tagPop && tagPop != ( char const * ) 1 && !strcmp( g_BoneAcessBase.tag, tagPop ) ) ); int lastIndex = g_BoneAccessStack.Count() - 1; @@ -3046,10 +3140,6 @@ void C_BaseAnimating::InvalidateBoneCaches() g_iModelBoneCounter++; } -bool C_BaseAnimating::ShouldDraw() -{ - return !IsDynamicModelLoading() && BaseClass::ShouldDraw(); -} ConVar r_drawothermodels( "r_drawothermodels", "1", FCVAR_CHEAT, "0=Off, 1=Normal, 2=Wireframe" ); @@ -3057,7 +3147,7 @@ ConVar r_drawothermodels( "r_drawothermodels", "1", FCVAR_CHEAT, "0=Off, 1=Norma // Purpose: Draws the object // Input : flags - //----------------------------------------------------------------------------- -int C_BaseAnimating::DrawModel( int flags ) +int C_BaseAnimating::DrawModel( int flags, const RenderableInstance_t &instance ) { VPROF_BUDGET( "C_BaseAnimating::DrawModel", VPROF_BUDGETGROUP_MODEL_RENDERING ); if ( !m_bReadyToDraw ) @@ -3065,10 +3155,6 @@ int C_BaseAnimating::DrawModel( int flags ) int drawn = 0; -#ifdef TF_CLIENT_DLL - ValidateModelIndex(); -#endif - if ( r_drawothermodels.GetInt() ) { MDLCACHE_CRITICAL_SECTION(); @@ -3084,15 +3170,14 @@ int C_BaseAnimating::DrawModel( int flags ) extraFlags |= STUDIO_SHADOWDEPTHTEXTURE; } - if ( flags & STUDIO_SSAODEPTHTEXTURE ) + if ( flags & STUDIO_DONOTMODIFYSTENCILSTATE ) { - extraFlags |= STUDIO_SSAODEPTHTEXTURE; + extraFlags |= STUDIO_DONOTMODIFYSTENCILSTATE; } - if ( ( flags & ( STUDIO_SSAODEPTHTEXTURE | STUDIO_SHADOWDEPTHTEXTURE ) ) == 0 && - g_pStudioStatsEntity != NULL && g_pStudioStatsEntity == GetClientRenderable() ) + if ( flags & STUDIO_SKIP_DECALS ) { - extraFlags |= STUDIO_GENERATE_STATS; + extraFlags |= STUDIO_SKIP_DECALS; } // Necessary for lighting blending @@ -3100,7 +3185,7 @@ int C_BaseAnimating::DrawModel( int flags ) if ( !IsFollowingEntity() ) { - drawn = InternalDrawModel( flags|extraFlags ); + drawn = InternalDrawModel( flags|extraFlags, instance ); } else { @@ -3109,14 +3194,14 @@ int C_BaseAnimating::DrawModel( int flags ) if ( follow ) { // recompute master entity bone structure - int baseDrawn = follow->DrawModel( 0 ); + int baseDrawn = follow->DrawModel( 0, instance ); // draw entity // FIXME: Currently only draws if aiment is drawn. // BUGBUG: Fixup bbox and do a separate cull for follow object if ( baseDrawn ) { - drawn = InternalDrawModel( STUDIO_RENDER|extraFlags ); + drawn = InternalDrawModel( STUDIO_RENDER|extraFlags, instance ); } } } @@ -3128,29 +3213,66 @@ int C_BaseAnimating::DrawModel( int flags ) return drawn; } +//----------------------------------------------------------------------------- +// Purpose: Draw skeleton topology & coordinate systems +//----------------------------------------------------------------------------- +void C_BaseAnimating::DrawSkeleton( CStudioHdr const* pHdr, int iBoneMask ) const +{ + if ( !pHdr ) + return; + + Vector from, to; + for ( int i = 0; i < pHdr->numbones(); ++i ) + { + if ( !(pHdr->boneFlags( i ) & iBoneMask) ) + continue; + + debugoverlay->AddCoordFrameOverlay( m_BoneAccessor[ i ], 3.0f ); + + int const iParentIndex = pHdr->boneParent( i ); + if ( iParentIndex < 0 ) + continue; + + MatrixPosition( m_BoneAccessor[ i ], from ); + MatrixPosition( m_BoneAccessor[ iParentIndex ], to ); + + debugoverlay->AddLineOverlay( from, to, 0, 255, 255, true, 0.0f ); + } +} + //----------------------------------------------------------------------------- // Gets the hitbox-to-world transforms, returns false if there was a problem //----------------------------------------------------------------------------- bool C_BaseAnimating::HitboxToWorldTransforms( matrix3x4_t *pHitboxToWorld[MAXSTUDIOBONES] ) { - MDLCACHE_CRITICAL_SECTION(); + if ( !IsBoneCacheValid() ) + { + MDLCACHE_CRITICAL_SECTION(); - if ( !GetModel() ) - return false; + if ( !GetModel() ) + return false; - CStudioHdr *pStudioHdr = GetModelPtr(); - if (!pStudioHdr) - return false; + CStudioHdr *pStudioHdr = GetModelPtr(); + if (!pStudioHdr) + return false; - mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( GetHitboxSet() ); - if ( !set ) - return false; + mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( GetHitboxSet() ); + if ( !set ) + return false; - if ( !set->numhitboxes ) - return false; + if ( !set->numhitboxes ) + return false; + + SetupBones( NULL, -1, BONE_USED_BY_HITBOX, gpGlobals->curtime ); + } + + for ( int i = 0; i < m_CachedBoneData.Count(); i++ ) + { + // UNDONE: Some of these bones haven't been set up. Is it necessary to check each + // one for membership in the hitbox set and NULL it if it isn't present? + pHitboxToWorld[i] = &m_CachedBoneData[i]; + } - CBoneCache *pCache = GetBoneCache( pStudioHdr ); - pCache->ReadCachedBonePointers( pHitboxToWorld, pStudioHdr->numbones() ); return true; } @@ -3162,25 +3284,65 @@ bool C_BaseAnimating::OnPostInternalDrawModel( ClientModelRenderInfo_t *pInfo ) return true; } +//---------------------------------------------------------------------------- +// Hooks into the fast path render system +//---------------------------------------------------------------------------- +static ConVar r_drawmodelstatsoverlay( "r_drawmodelstatsoverlay", "0", FCVAR_CHEAT ); + +IClientModelRenderable* C_BaseAnimating::GetClientModelRenderable() +{ + // Cannot participate if it has a render clip plane + if ( !m_bCanUseFastPath || m_bIsUsingRelativeLighting || !IsVisible() ) + return NULL; + + if ( r_drawothermodels.GetInt() != 1 || r_drawmodelstatsoverlay.GetInt() != 0 || mat_wireframe.GetInt() != 0 ) + return NULL; + + if ( IsFollowingEntity() && !FindFollowedEntity() ) + return NULL; + + + + return this; +} + + +//---------------------------------------------------------------------------- +// Hooks into the fast path render system +//---------------------------------------------------------------------------- +bool C_BaseAnimating::GetRenderData( void *pData, ModelDataCategory_t nCategory ) +{ + switch ( nCategory ) + { + case MODEL_DATA_LIGHTING_MODEL: + // Necessary for lighting blending + CreateModelInstance(); + *(RenderableLightingModel_t*)pData = LIGHTING_MODEL_STANDARD; + return true; + + case MODEL_DATA_STENCIL: + return ComputeStencilState( (ShaderStencilState_t*)pData ); + + default: + return false; +// return BaseClass::GetRenderData( pData, nCategory ); + } +} + + //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- bool C_BaseAnimating::OnInternalDrawModel( ClientModelRenderInfo_t *pInfo ) { - if ( m_hLightingOriginRelative.Get() ) - { - C_InfoLightingRelative *pInfoLighting = assert_cast( m_hLightingOriginRelative.Get() ); - pInfoLighting->GetLightingOffset( pInfo->lightingOffset ); - pInfo->pLightingOffset = &pInfo->lightingOffset; - } if ( m_hLightingOrigin ) { pInfo->pLightingOrigin = &(m_hLightingOrigin->GetAbsOrigin()); } - return true; } + //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- @@ -3219,11 +3381,60 @@ void C_BaseAnimating::DoInternalDrawModel( ClientModelRenderInfo_t *pInfo, DrawM } + +//---------------------------------------------------------------------------- +// Computes stencil settings +//---------------------------------------------------------------------------- +bool C_BaseAnimating::ComputeStencilState( ShaderStencilState_t *pStencilState ) +{ +#if defined( _X360 ) + if ( !r_shadow_deferred.GetBool() ) + { + // Early out if we don't care about deferred shadow masks + return false; + } + + uint32 mask = 0x0; + uint32 nRef = mask; + + mask |= 1 << 2; // Stencil for masking deferred shadows uses 0x4 + bool bCastsShadows = ( ShadowCastType() != SHADOWS_NONE ); + nRef |= bCastsShadows << 2; + + pStencilState->m_bEnable = true; + pStencilState->m_nTestMask = 0xFFFFFFFF; + pStencilState->m_nWriteMask = mask; + pStencilState->m_nReferenceValue = nRef; + pStencilState->m_CompareFunc = SHADER_STENCILFUNC_ALWAYS; + pStencilState->m_PassOp = SHADER_STENCILOP_SET_TO_REFERENCE; + pStencilState->m_FailOp = SHADER_STENCILOP_KEEP; + pStencilState->m_ZFailOp = SHADER_STENCILOP_KEEP; + + // Deferred shadow rendering: + // set or clear hi-stencil depending on shadow cast type + pStencilState->m_bHiStencilEnable = false; + pStencilState->m_bHiStencilWriteEnable = true; + pStencilState->m_HiStencilCompareFunc = SHADER_HI_STENCILFUNC_NOTEQUAL; + pStencilState->m_nHiStencilReferenceValue = 0; + /* + // The old hi-stencil state, that unmasked too many tiles for things receiving shadows + pStencilState->m_HiStencilCompareFunc = bCastsShadows ? SHADER_HI_STENCILFUNC_NOTEQUAL : SHADER_HI_STENCILFUNC_EQUAL; + pStencilState->m_nHiStencilReferenceValue = bCastsShadows ? 0 : 1; + */ + + return true; +#else + return false; +#endif +} + + + //----------------------------------------------------------------------------- // Purpose: Draws the object // Input : flags - //----------------------------------------------------------------------------- -int C_BaseAnimating::InternalDrawModel( int flags ) +int C_BaseAnimating::InternalDrawModel( int flags, const RenderableInstance_t &instance ) { VPROF( "C_BaseAnimating::InternalDrawModel" ); @@ -3234,18 +3445,23 @@ int C_BaseAnimating::InternalDrawModel( int flags ) // SetModel with the wrong type of model, this could occur. if ( modelinfo->GetModelType( GetModel() ) != mod_studio ) { - return BaseClass::DrawModel( flags ); + return BaseClass::DrawModel( flags, instance ); } // Make sure hdr is valid for drawing if ( !GetModelPtr() ) return 0; - UpdateBoneAttachments( ); - - if ( IsEffectActive( EF_ITEM_BLINK ) ) + bool bUsingStencil = false; + CMatRenderContextPtr pRenderContext( materials ); + if ( !( flags & STUDIO_DONOTMODIFYSTENCILSTATE ) && !( flags & STUDIO_SHADOWDEPTHTEXTURE ) && ( flags & STUDIO_RENDER ) ) { - flags |= STUDIO_ITEM_BLINK; + ShaderStencilState_t state; + bUsingStencil = ComputeStencilState( &state ); + if ( bUsingStencil ) + { + pRenderContext->SetStencilState( state ); + } } ClientModelRenderInfo_t info; @@ -3261,42 +3477,55 @@ int C_BaseAnimating::InternalDrawModel( int flags ) pInfo->origin = GetRenderOrigin(); pInfo->angles = GetRenderAngles(); pInfo->skin = GetSkin(); - pInfo->body = GetBody(); + pInfo->body = m_nBody; pInfo->hitboxset = m_nHitboxSet; - if ( !OnInternalDrawModel( pInfo ) ) + bool bMarkAsDrawn = false; + if ( OnInternalDrawModel( pInfo ) ) { - return 0; - } + Assert( !pInfo->pModelToWorld); + if ( !pInfo->pModelToWorld ) + { + pInfo->pModelToWorld = &pInfo->modelToWorld; - Assert( !pInfo->pModelToWorld); - if ( !pInfo->pModelToWorld ) - { - pInfo->pModelToWorld = &pInfo->modelToWorld; + // Turns the origin + angles into a matrix + AngleMatrix( pInfo->angles, pInfo->origin, pInfo->modelToWorld ); + } - // Turns the origin + angles into a matrix - AngleMatrix( pInfo->angles, pInfo->origin, pInfo->modelToWorld ); - } + // Suppress unlocking + CMatRenderDataReference rd( pRenderContext ); + DrawModelState_t state; + matrix3x4_t *pBoneToWorld; + bMarkAsDrawn = modelrender->DrawModelSetup( *pInfo, &state, &pBoneToWorld ); - DrawModelState_t state; - matrix3x4_t *pBoneToWorld = NULL; - bool bMarkAsDrawn = modelrender->DrawModelSetup( *pInfo, &state, NULL, &pBoneToWorld ); - - // Scale the base transform if we don't have a bone hierarchy - if ( IsModelScaled() ) - { - CStudioHdr *pHdr = GetModelPtr(); - if ( pHdr && pBoneToWorld && pHdr->numbones() == 1 ) + // Scale the base transform if we don't have a bone hierarchy + if ( GetModelScale() > 1.0f+FLT_EPSILON || GetModelScale() < 1.0f-FLT_EPSILON ) { - // Scale the bone to world at this point - const float flScale = GetModelScale(); - VectorScale( (*pBoneToWorld)[0], flScale, (*pBoneToWorld)[0] ); - VectorScale( (*pBoneToWorld)[1], flScale, (*pBoneToWorld)[1] ); - VectorScale( (*pBoneToWorld)[2], flScale, (*pBoneToWorld)[2] ); + CStudioHdr *pHdr = GetModelPtr(); + if ( pHdr && pBoneToWorld && pHdr->numbones() == 1 ) + { + // Scale the bone to world at this point + const float flScale = GetModelScale(); + VectorScale( (*pBoneToWorld)[0], flScale, (*pBoneToWorld)[0] ); + VectorScale( (*pBoneToWorld)[1], flScale, (*pBoneToWorld)[1] ); + VectorScale( (*pBoneToWorld)[2], flScale, (*pBoneToWorld)[2] ); + } } + + DoInternalDrawModel( pInfo, ( bMarkAsDrawn && ( pInfo->flags & STUDIO_RENDER ) ) ? &state : NULL, pBoneToWorld ); } - DoInternalDrawModel( pInfo, ( bMarkAsDrawn && ( pInfo->flags & STUDIO_RENDER ) ) ? &state : NULL, pBoneToWorld ); + if ( bUsingStencil ) + { + ShaderStencilState_t state; + state.m_bEnable = false; + #if defined( _X360 ) + // Deferred shadow rendering: Disable Hi-Stencil + state.m_bHiStencilEnable = false; + state.m_bHiStencilWriteEnable = false; + #endif + pRenderContext->SetStencilState( state ); + } OnPostInternalDrawModel( pInfo ); @@ -3336,14 +3565,7 @@ void C_BaseAnimating::ProcessMuzzleFlashEvent() //----------------------------------------------------------------------------- void C_BaseAnimating::DoAnimationEvents( CStudioHdr *pStudioHdr ) { - if ( !pStudioHdr ) - return; - -#ifdef DEBUG - bool watch = dbganimmodel.GetString()[0] && V_stristr( pStudioHdr->pszName(), dbganimmodel.GetString() ); -#else - bool watch = false; // Q_strstr( hdr->name, "rifle" ) ? true : false; -#endif + bool watch = false;//IsPlayer(); // Q_strstr( hdr->name, "rifle" ) ? true : false; //Adrian: eh? This should never happen. if ( GetSequence() == -1 ) @@ -3353,8 +3575,7 @@ void C_BaseAnimating::DoAnimationEvents( CStudioHdr *pStudioHdr ) float flEventCycle = GetCycle(); // If we're invisible, don't draw the muzzle flash - bool bIsInvisible = !IsVisible() && !IsViewModel() && !IsMenuModel(); - + bool bIsInvisible = !IsVisibleToAnyPlayer() && !IsViewModel() && !IsMenuModel(); if ( bIsInvisible && !clienttools->IsInRecordingMode() ) return; @@ -3370,24 +3591,7 @@ void C_BaseAnimating::DoAnimationEvents( CStudioHdr *pStudioHdr ) if ( bIsInvisible ) return; - // If we don't have any sequences, don't do anything - int nStudioNumSeq = pStudioHdr->GetNumSeq(); - if ( nStudioNumSeq < 1 ) - { - Warning( "%s[%d]: no sequences?\n", GetDebugName(), entindex() ); - Assert( nStudioNumSeq >= 1 ); - return; - } - - int nSeqNum = GetSequence(); - if ( nSeqNum >= nStudioNumSeq ) - { - // This can happen e.g. while reloading Heavy's shotgun, switch to the minigun. - Warning( "%s[%d]: Playing sequence %d but there's only %d in total?\n", GetDebugName(), entindex(), nSeqNum, nStudioNumSeq ); - return; - } - - mstudioseqdesc_t &seqdesc = pStudioHdr->pSeqdesc( nSeqNum ); + mstudioseqdesc_t &seqdesc = pStudioHdr->pSeqdesc( GetSequence() ); if (seqdesc.numevents == 0) return; @@ -3463,7 +3667,7 @@ void C_BaseAnimating::DoAnimationEvents( CStudioHdr *pStudioHdr ) if ( !( pevent[i].type & AE_TYPE_CLIENT ) ) continue; } - else if ( pevent[i].event < 5000 ) //Adrian - Support the old event system + else if ( pevent[i].Event_OldSystem() < EVENT_CLIENT ) //Adrian - Support the old event system continue; if ( pevent[i].cycle <= m_flPrevEventCycle ) @@ -3473,7 +3677,7 @@ void C_BaseAnimating::DoAnimationEvents( CStudioHdr *pStudioHdr ) { Msg( "%i FE %i Looped cycle %f, prev %f ev %f (time %.3f)\n", gpGlobals->tickcount, - pevent[i].event, + pevent[i].Event(), pevent[i].cycle, m_flPrevEventCycle, flEventCycle, @@ -3481,7 +3685,7 @@ void C_BaseAnimating::DoAnimationEvents( CStudioHdr *pStudioHdr ) } - FireEvent( GetAbsOrigin(), GetAbsAngles(), pevent[ i ].event, pevent[ i ].pszOptions() ); + FireEvent( GetAbsOrigin(), GetAbsAngles(), pevent[ i ].Event(), pevent[ i ].pszOptions() ); } // Necessary to get the next loop working @@ -3495,24 +3699,26 @@ void C_BaseAnimating::DoAnimationEvents( CStudioHdr *pStudioHdr ) if ( !( pevent[i].type & AE_TYPE_CLIENT ) ) continue; } - else if ( pevent[i].event < 5000 ) //Adrian - Support the old event system + else if ( pevent[i].Event_OldSystem() < EVENT_CLIENT ) //Adrian - Support the old event system continue; if ( (pevent[i].cycle > m_flPrevEventCycle && pevent[i].cycle <= flEventCycle) ) { if ( watch ) { - Msg( "%i (seq: %d) FE %i Normal cycle %f, prev %f ev %f (time %.3f)\n", + Msg( "%i (seq: %d/%s) FE %i Normal cycle %f, prev %f ev %f (time %.3f) (options %s)\n", gpGlobals->tickcount, GetSequence(), - pevent[i].event, + GetSequenceActivityName( GetSequence() ), + pevent[i].Event(), pevent[i].cycle, m_flPrevEventCycle, flEventCycle, - gpGlobals->curtime ); + gpGlobals->curtime, + pevent[ i ].pszOptions() ); } - FireEvent( GetAbsOrigin(), GetAbsAngles(), pevent[ i ].event, pevent[ i ].pszOptions() ); + FireEvent( GetAbsOrigin(), GetAbsAngles(), pevent[ i ].Event(), pevent[ i ].pszOptions() ); } } @@ -3645,11 +3851,11 @@ void MaterialFootstepSound( C_BaseAnimating *pEnt, bool bLeftFoot, float flVolum EmitSound_t params; if( bLeftFoot ) { - params.m_pSoundName = physprops->GetString(psurf->sounds.stepleft); + params.m_pSoundName = physprops->GetString(psurf->sounds.runStepLeft); } else { - params.m_pSoundName = physprops->GetString(psurf->sounds.stepright); + params.m_pSoundName = physprops->GetString(psurf->sounds.runStepRight); } CPASAttenuationFilter filter( pEnt, params.m_pSoundName ); @@ -3662,6 +3868,29 @@ void MaterialFootstepSound( C_BaseAnimating *pEnt, bool bLeftFoot, float flVolum } } + +//----------------------------------------------------------------------------- +// Purpose: Creates a particle effect and ejects a single shell. If +// the effect is already active, it just restarts it to eject another shell. +//----------------------------------------------------------------------------- +void C_BaseAnimating::EjectParticleBrass( const char *pEffectName, const int iAttachment ) +{ + if ( cl_ejectbrass.GetBool() == false ) + return; + + // TODO: Can we change the attachment for an active particle system? + if ( !m_ejectBrassEffect || m_iEjectBrassAttachment != iAttachment ) + { + m_iEjectBrassAttachment = iAttachment; + m_ejectBrassEffect = ParticleProp()->Create( pEffectName, PATTACH_POINT_FOLLOW, iAttachment ); + } + else + { + m_ejectBrassEffect->Restart(); + } +} + + //----------------------------------------------------------------------------- // Purpose: // Input : *origin - @@ -3682,6 +3911,8 @@ void C_BaseAnimating::FireEvent( const Vector& origin, const QAngle& angles, int { int iAttachment = -1; int iAttachType = PATTACH_ABSORIGIN_FOLLOW; + int iAttachmentCP1 = -1; + int iAttachTypeCP1 = PATTACH_ABSORIGIN_FOLLOW; char token[256]; char szParticleEffect[256]; @@ -3690,10 +3921,7 @@ void C_BaseAnimating::FireEvent( const Vector& origin, const QAngle& angles, int p = nexttoken(token, p, ' '); if ( token ) { - const char* mtoken = ModifyEventParticles( token ); - if ( !mtoken || mtoken[0] == '\0' ) - return; - Q_strncpy( szParticleEffect, mtoken, sizeof(szParticleEffect) ); + Q_strncpy( szParticleEffect, token, sizeof(szParticleEffect) ); } // Get the attachment type @@ -3718,16 +3946,133 @@ void C_BaseAnimating::FireEvent( const Vector& origin, const QAngle& angles, int if ( token[0] != '0' && iAttachment == 0 ) { iAttachment = LookupAttachment( token ); - if ( iAttachment <= 0 ) + if ( iAttachment == -1 ) { - Warning( "Failed to find attachment point specified for particle effect anim event. Trying to spawn effect '%s' on attachment named '%s'\n", szParticleEffect, token ); + Warning("Failed to find attachment point specified for particle effect anim event. Trying to spawn effect '%s' on attachment named '%s'\n", szParticleEffect, token ); return; } } } // Spawn the particle effect - ParticleProp()->Create( szParticleEffect, (ParticleAttachment_t)iAttachType, iAttachment ); + CNewParticleEffect *pEffect = ParticleProp()->Create( szParticleEffect, (ParticleAttachment_t)iAttachType, iAttachment ); + + // Get the attachment type for CP1 + p = nexttoken(token, p, ' '); + if ( !p ) + return; + if ( token ) + { + iAttachTypeCP1 = GetAttachTypeFromString( token ); + if ( iAttachTypeCP1 == -1 ) + { + Warning("Invalid attach type specified for particle effect anim event. Trying to spawn effect '%s' with attach type of '%s'\n", szParticleEffect, token ); + return; + } + } + + // Get the attachment point index + p = nexttoken(token, p, ' '); + if ( token ) + { + iAttachmentCP1 = atoi(token); + + // See if we can find any attachment points matching the name + if ( token[0] != '0' && iAttachmentCP1 == 0 ) + { + iAttachmentCP1 = LookupAttachment( token ); + if ( iAttachmentCP1 == -1 ) + { + Warning("Failed to find attachment point specified for particle effect anim event. Trying to spawn effect '%s' on attachment named '%s'\n", szParticleEffect, token ); + return; + } + } + + ParticleProp()->AddControlPoint( pEffect, 1, this, (ParticleAttachment_t)iAttachTypeCP1, token ); + } + } + break; + case AE_CL_STOP_PARTICLE_EFFECT: + { + char token[256]; + char szParticleEffect[256]; + + // Get the particle effect name + const char *p = options; + p = nexttoken(token, p, ' '); + if ( token ) + { + Q_strncpy( szParticleEffect, token, sizeof(szParticleEffect) ); + } + + // Get the attachment point index + p = nexttoken(token, p, ' '); + bool bStopInstantly = ( token && !Q_stricmp( token, "instantly" ) ); + + ParticleProp()->StopParticlesNamed( szParticleEffect, bStopInstantly ); + } + break; + + case AE_CL_ADD_PARTICLE_EFFECT_CP: + { + int iControlPoint = 1; + int iAttachment = -1; + int iAttachType = PATTACH_ABSORIGIN_FOLLOW; + int iEffectIndex = -1; + char token[256]; + char szParticleEffect[256]; + + // Get the particle effect name + const char *p = options; + p = nexttoken(token, p, ' '); + if ( token ) + { + Q_strncpy( szParticleEffect, token, sizeof(szParticleEffect) ); + } + + // Get the control point number + p = nexttoken(token, p, ' '); + if ( token ) + { + iControlPoint = atoi( token ); + } + + // Get the attachment type + p = nexttoken(token, p, ' '); + if ( token ) + { + iAttachType = GetAttachTypeFromString( token ); + if ( iAttachType == -1 ) + { + Warning("Invalid attach type specified for particle effect anim event. Trying to spawn effect '%s' with attach type of '%s'\n", szParticleEffect, token ); + return; + } + } + + // Get the attachment point index + p = nexttoken(token, p, ' '); + if ( token ) + { + iAttachment = atoi(token); + + // See if we can find any attachment points matching the name + if ( token[0] != '0' && iAttachment == 0 ) + { + iAttachment = LookupAttachment( token ); + if ( iAttachment == -1 ) + { + Warning("Failed to find attachment point specified for particle effect anim event. Trying to spawn effect '%s' on attachment named '%s'\n", szParticleEffect, token ); + return; + } + } + } + iEffectIndex = ParticleProp()->FindEffect( szParticleEffect ); + if ( iEffectIndex == -1 ) + { + Warning("Failed to find specified particle effect. Trying to add CP to '%s' on attachment named '%s'\n", szParticleEffect, token ); + return; + } + ParticleProp()->AddControlPoint( iEffectIndex, iControlPoint, this, (ParticleAttachment_t)iAttachType, iAttachment ); } break; @@ -3754,7 +4099,6 @@ void C_BaseAnimating::FireEvent( const Vector& origin, const QAngle& angles, int case CL_EVENT_FOOTSTEP_LEFT: { -#ifndef HL2MP char pSoundName[256]; if ( !options || !options[0] ) { @@ -3774,13 +4118,11 @@ void C_BaseAnimating::FireEvent( const Vector& origin, const QAngle& angles, int Q_snprintf( pSoundName, 256, "%s.FootstepLeft", options ); } EmitSound( pSoundName ); -#endif } break; case CL_EVENT_FOOTSTEP_RIGHT: { -#ifndef HL2MP char pSoundName[256]; if ( !options || !options[0] ) { @@ -3799,7 +4141,6 @@ void C_BaseAnimating::FireEvent( const Vector& origin, const QAngle& angles, int Q_snprintf( pSoundName, 256, "%s.FootstepRight", options ); } EmitSound( pSoundName ); -#endif } break; @@ -3831,16 +4172,7 @@ void C_BaseAnimating::FireEvent( const Vector& origin, const QAngle& angles, int case CL_EVENT_EJECTBRASS1: if ( m_Attachments.Count() > 0 ) { - if ( MainViewOrigin().DistToSqr( GetAbsOrigin() ) < (256 * 256) ) - { - Vector attachOrigin; - QAngle attachAngles; - - if( GetAttachment( 2, attachOrigin, attachAngles ) ) - { - tempents->EjectBrass( attachOrigin, attachAngles, GetAbsAngles(), atoi( options ) ); - } - } + DevWarning( "Unhandled eject brass animevent\n" ); } break; @@ -3972,7 +4304,14 @@ void C_BaseAnimating::FireObsoleteEvent( const Vector& origin, const QAngle& ang if( token ) { - iAttachment = atoi(token); + if ( isdigit( *token ) ) + { + iAttachment = atoi(token); + } + else + { + iAttachment = LookupAttachment( token ); + } } p = nexttoken(token, p, ' '); @@ -4227,7 +4566,6 @@ bool C_BaseAnimating::Interpolate( float flCurrentTime ) Vector oldOrigin; QAngle oldAngles; - Vector oldVel; float flOldCycle = GetCycle(); int nChangeFlags = 0; @@ -4235,11 +4573,11 @@ bool C_BaseAnimating::Interpolate( float flCurrentTime ) m_iv_flCycle.SetLooping( IsSequenceLooping( GetSequence() ) ); int bNoMoreChanges; - int retVal = BaseInterpolatePart1( flCurrentTime, oldOrigin, oldAngles, oldVel, bNoMoreChanges ); + int retVal = BaseInterpolatePart1( flCurrentTime, oldOrigin, oldAngles, bNoMoreChanges ); if ( retVal == INTERPOLATE_STOP ) { if ( bNoMoreChanges ) - RemoveFromInterpolationList(); + RemoveFromEntityList(ENTITY_LIST_INTERPOLATE); return true; } @@ -4249,9 +4587,9 @@ bool C_BaseAnimating::Interpolate( float flCurrentTime ) nChangeFlags |= ANIMATION_CHANGED; if ( bNoMoreChanges ) - RemoveFromInterpolationList(); + RemoveFromEntityList(ENTITY_LIST_INTERPOLATE); - BaseInterpolatePart2( oldOrigin, oldAngles, oldVel, nChangeFlags ); + BaseInterpolatePart2( oldOrigin, oldAngles, nChangeFlags ); return true; } @@ -4261,31 +4599,7 @@ bool C_BaseAnimating::Interpolate( float flCurrentTime ) //----------------------------------------------------------------------------- bool C_BaseAnimating::IsRagdoll() const { - return m_pRagdoll && (m_nRenderFX == kRenderFxRagdoll); -} - -//----------------------------------------------------------------------------- -// returns true if we're currently being ragdolled -//----------------------------------------------------------------------------- -bool C_BaseAnimating::IsAboutToRagdoll() const -{ - return (m_nRenderFX == kRenderFxRagdoll); -} - - -//----------------------------------------------------------------------------- -// Lets us check our sequence number after a network update -//----------------------------------------------------------------------------- -int C_BaseAnimating::RestoreData( const char *context, int slot, int type ) -{ - int retVal = BaseClass::RestoreData( context, slot, type ); - CStudioHdr *pHdr = GetModelPtr(); - if( pHdr && m_nSequence >= pHdr->GetNumSeq() ) - { - // Don't let a network update give us an invalid sequence - m_nSequence = 0; - } - return retVal; + return m_pRagdoll && m_bClientSideRagdoll; } @@ -4298,6 +4612,9 @@ void C_BaseAnimating::GetRenderBounds( Vector& theMins, Vector& theMaxs ) if ( IsRagdoll() ) { m_pRagdoll->GetRagdollBounds( theMins, theMaxs ); + Vector vecBloat( 5.0f, 5.0f, 5.0f ); + theMins -= vecBloat; + theMaxs += vecBloat; } else if ( GetModel() ) { @@ -4343,27 +4660,36 @@ void C_BaseAnimating::GetRenderBounds( Vector& theMins, Vector& theMaxs ) //----------------------------------------------------------------------------- const Vector& C_BaseAnimating::GetRenderOrigin( void ) { - if ( IsRagdoll() ) +#ifdef DEMOPOLISH_ENABLED + if ( DemoPolish_ShouldReplaceRoot( entindex() ) ) { - return m_pRagdoll->GetRagdollOrigin(); + return DemoPolish_GetController().GetRenderOrigin( entindex() ); } else +#endif + if ( IsRagdoll() ) { - return BaseClass::GetRenderOrigin(); + return m_pRagdoll->GetRagdollOrigin(); } + + return BaseClass::GetRenderOrigin(); } const QAngle& C_BaseAnimating::GetRenderAngles( void ) { - if ( IsRagdoll() ) +#ifdef DEMOPOLISH_ENABLED + if ( DemoPolish_ShouldReplaceRoot( entindex() ) ) { - return vec3_angle; - + return DemoPolish_GetController().GetRenderAngles( entindex() ); } else +#endif + if ( IsRagdoll() ) { - return BaseClass::GetRenderAngles(); + return vec3_angle; } + + return BaseClass::GetRenderAngles(); } void C_BaseAnimating::RagdollMoved( void ) @@ -4376,7 +4702,7 @@ void C_BaseAnimating::RagdollMoved( void ) SetCollisionBounds( mins, maxs ); // If the ragdoll moves, its render-to-texture shadow is dirty - InvalidatePhysicsRecursive( ANIMATION_CHANGED ); + InvalidatePhysicsRecursive( BOUNDS_CHANGED ); } @@ -4390,7 +4716,6 @@ void C_BaseAnimating::VPhysicsUpdate( IPhysicsObject *pPhysics ) if (IsRagdoll()) { m_pRagdoll->VPhysicsUpdate( pPhysics ); - RagdollMoved(); return; @@ -4406,8 +4731,6 @@ void C_BaseAnimating::VPhysicsUpdate( IPhysicsObject *pPhysics ) //----------------------------------------------------------------------------- void C_BaseAnimating::PreDataUpdate( DataUpdateType_t updateType ) { - VPROF( "C_BaseAnimating::PreDataUpdate" ); - m_flOldCycle = GetCycle(); m_nOldSequence = GetSequence(); m_flOldModelScale = GetModelScale(); @@ -4486,7 +4809,16 @@ void C_BaseAnimating::PostDataUpdate( DataUpdateType_t updateType ) bool bScaleChanged = ( m_flOldModelScale != GetModelScale() ); if ( bAnimationChanged || bSequenceChanged || bScaleChanged ) { - InvalidatePhysicsRecursive( ANIMATION_CHANGED ); + int nFlags = bAnimationChanged ? ANIMATION_CHANGED : 0; + if ( bSequenceChanged ) + { + nFlags |= BOUNDS_CHANGED | SEQUENCE_CHANGED; + } + if ( bScaleChanged ) + { + nFlags |= BOUNDS_CHANGED; + } + InvalidatePhysicsRecursive( nFlags ); } if ( bAnimationChanged || bSequenceChanged ) @@ -4507,7 +4839,7 @@ void C_BaseAnimating::PostDataUpdate( DataUpdateType_t updateType ) CStudioHdr *hdr = GetModelPtr(); if ( hdr && !( hdr->flags() & STUDIOHDR_FLAGS_STATIC_PROP ) ) { - m_iv_flCycle.Reset(); + m_iv_flCycle.Reset( gpGlobals->curtime ); } } } @@ -4520,10 +4852,12 @@ void C_BaseAnimating::OnPreDataChanged( DataUpdateType_t updateType ) { BaseClass::OnPreDataChanged( updateType ); + m_nPrevBody = GetBody(); + m_nPrevSkin = GetSkin(); m_bLastClientSideFrameReset = m_bClientSideFrameReset; } -void C_BaseAnimating::ForceSetupBonesAtTime( matrix3x4_t *pBonesOut, float flTime ) +void C_BaseAnimating::ForceSetupBonesAtTime( matrix3x4a_t *pBonesOut, float flTime ) { // blow the cached prev bones InvalidateBoneCache(); @@ -4531,11 +4865,29 @@ void C_BaseAnimating::ForceSetupBonesAtTime( matrix3x4_t *pBonesOut, float flTim // reset root position to flTime Interpolate( flTime ); - // Setup bone state at the given time - SetupBones( pBonesOut, MAXSTUDIOBONES, BONE_USED_BY_ANYTHING, flTime ); + if ( m_bClientSideAnimation ) + { + float saveCycle = GetCycle(); + float oldCycle = m_prevClientCycle; + if ( oldCycle > saveCycle ) + { + oldCycle -= 1.0f; + } + float cycleInterp = RemapVal( flTime, m_prevClientAnimTime, m_flAnimTime, oldCycle, saveCycle ); + cycleInterp = clamp( cycleInterp, 0.0f, 1.0f ); + SetCycle( cycleInterp ); + // Setup bone state at the given time + SetupBones( pBonesOut, MAXSTUDIOBONES, BONE_USED_BY_ANYTHING, flTime ); + SetCycle( saveCycle ); + } + else + { + // Setup bone state at the given time + SetupBones( pBonesOut, MAXSTUDIOBONES, BONE_USED_BY_ANYTHING, flTime ); + } } -void C_BaseAnimating::GetRagdollInitBoneArrays( matrix3x4_t *pDeltaBones0, matrix3x4_t *pDeltaBones1, matrix3x4_t *pCurrentBones, float boneDt ) +void C_BaseAnimating::GetRagdollInitBoneArrays( matrix3x4a_t *pDeltaBones0, matrix3x4a_t *pDeltaBones1, matrix3x4a_t *pCurrentBones, float boneDt ) { ForceSetupBonesAtTime( pDeltaBones0, gpGlobals->curtime - boneDt ); ForceSetupBonesAtTime( pDeltaBones1, gpGlobals->curtime ); @@ -4550,16 +4902,22 @@ void C_BaseAnimating::GetRagdollInitBoneArrays( matrix3x4_t *pDeltaBones0, matri } else { - memcpy( pCurrentBones, m_CachedBoneData.Base(), sizeof( matrix3x4_t ) * m_CachedBoneData.Count() ); + Plat_FastMemcpy( pCurrentBones, m_CachedBoneData.Base(), sizeof( matrix3x4a_t ) * m_CachedBoneData.Count() ); } } +C_ClientRagdoll *C_BaseAnimating::CreateClientRagdoll( bool bRestoring ) +{ + DevMsg( "Creating ragdoll at tick %d\n", gpGlobals->tickcount ); + return new C_ClientRagdoll( bRestoring ); +} + C_BaseAnimating *C_BaseAnimating::CreateRagdollCopy() { //Adrian: We now create a separate entity that becomes this entity's ragdoll. //That way the server side version of this entity can go away. //Plus we can hook save/restore code to these ragdolls so they don't fall on restore anymore. - C_ClientRagdoll *pRagdoll = new C_ClientRagdoll( false ); + C_ClientRagdoll *pRagdoll = CreateClientRagdoll( false ); if ( pRagdoll == NULL ) return NULL; @@ -4568,7 +4926,7 @@ C_BaseAnimating *C_BaseAnimating::CreateRagdollCopy() const model_t *model = GetModel(); const char *pModelName = modelinfo->GetModelName( model ); - if ( pRagdoll->InitializeAsClientEntity( pModelName, RENDER_GROUP_OPAQUE_ENTITY ) == false ) + if ( pRagdoll->InitializeAsClientEntity( pModelName, false ) == false ) { pRagdoll->Release(); return NULL; @@ -4600,37 +4958,56 @@ C_BaseAnimating *C_BaseAnimating::CreateRagdollCopy() pRagdoll->AddEffects( EF_NOSHADOW ); } - pRagdoll->m_nRenderFX = kRenderFxRagdoll; + pRagdoll->m_bClientSideRagdoll = true; pRagdoll->SetRenderMode( GetRenderMode() ); - pRagdoll->SetRenderColor( GetRenderColor().r, GetRenderColor().g, GetRenderColor().b, GetRenderColor().a ); + pRagdoll->SetRenderColor( GetRenderColor().r, GetRenderColor().g, GetRenderColor().b ); + pRagdoll->SetRenderAlpha( GetRenderAlpha() ); + pRagdoll->SetGlobalFadeScale( GetGlobalFadeScale() ); - pRagdoll->m_nBody = m_nBody; - pRagdoll->m_nSkin = GetSkin(); + pRagdoll->SetBody( GetBody() ); + pRagdoll->SetSkin( GetSkin() ); pRagdoll->m_vecForce = m_vecForce; pRagdoll->m_nForceBone = m_nForceBone; pRagdoll->SetNextClientThink( CLIENT_THINK_ALWAYS ); pRagdoll->SetModelName( AllocPooledString(pModelName) ); - pRagdoll->SetModelScale( GetModelScale() ); + pRagdoll->CopySequenceTransitions(this); + pRagdoll->SetModelScale( this->GetModelScale() ); return pRagdoll; } +void C_BaseAnimating::CopySequenceTransitions( C_BaseAnimating *pCopyFrom ) +{ + m_SequenceTransitioner.m_animationQueue.RemoveAll(); + int count = pCopyFrom->m_SequenceTransitioner.m_animationQueue.Count(); + m_SequenceTransitioner.m_animationQueue.EnsureCount(count); + for ( int i = 0; i < count; i++ ) + { + m_SequenceTransitioner.m_animationQueue[i] = pCopyFrom->m_SequenceTransitioner.m_animationQueue[i]; + } +} + + C_BaseAnimating *C_BaseAnimating::BecomeRagdollOnClient() { MoveToLastReceivedPosition( true ); GetAbsOrigin(); - C_BaseAnimating *pRagdoll = CreateRagdollCopy(); + m_pClientsideRagdoll = CreateRagdollCopy(); + if ( !m_pClientsideRagdoll ) + return NULL; - matrix3x4_t boneDelta0[MAXSTUDIOBONES]; - matrix3x4_t boneDelta1[MAXSTUDIOBONES]; - matrix3x4_t currentBones[MAXSTUDIOBONES]; + matrix3x4a_t boneDelta0[MAXSTUDIOBONES]; + matrix3x4a_t boneDelta1[MAXSTUDIOBONES]; + matrix3x4a_t currentBones[MAXSTUDIOBONES]; const float boneDt = 0.1f; GetRagdollInitBoneArrays( boneDelta0, boneDelta1, currentBones, boneDt ); - pRagdoll->InitAsClientRagdoll( boneDelta0, boneDelta1, currentBones, boneDt ); - return pRagdoll; + m_pClientsideRagdoll->InitAsClientRagdoll( boneDelta0, boneDelta1, currentBones, boneDt ); + return m_pClientsideRagdoll; } -bool C_BaseAnimating::InitAsClientRagdoll( const matrix3x4_t *pDeltaBones0, const matrix3x4_t *pDeltaBones1, const matrix3x4_t *pCurrentBonePosition, float boneDt, bool bFixedConstraints ) + + +bool C_BaseAnimating::InitAsClientRagdoll( const matrix3x4_t *pDeltaBones0, const matrix3x4_t *pDeltaBones1, const matrix3x4_t *pCurrentBonePosition, float boneDt ) { CStudioHdr *hdr = GetModelPtr(); if ( !hdr || m_pRagdoll || m_builtRagdoll ) @@ -4650,7 +5027,7 @@ bool C_BaseAnimating::InitAsClientRagdoll( const matrix3x4_t *pDeltaBones0, cons // HACKHACK: force time to last interpolation position m_flPlaybackRate = 1; - m_pRagdoll = CreateRagdoll( this, hdr, m_vecForce, m_nForceBone, pDeltaBones0, pDeltaBones1, pCurrentBonePosition, boneDt, bFixedConstraints ); + m_pRagdoll = CreateRagdoll( this, hdr, m_vecForce, m_nForceBone, pDeltaBones0, pDeltaBones1, pCurrentBonePosition, boneDt ); // Cause the entity to recompute its shadow type and make a // version which only updates when physics state changes @@ -4683,9 +5060,9 @@ bool C_BaseAnimating::InitAsClientRagdoll( const matrix3x4_t *pDeltaBones0, cons UpdateVisibility(); #if defined( REPLAY_ENABLED ) - // If Replay is enabled on server, add an entry to the ragdoll recorder for this entity + // If replay is enabled on server, add an entry to the ragdoll recorder for this entity ConVar* pReplayEnable = (ConVar*)cvar->FindVar( "replay_enable" ); - if ( m_pRagdoll && pReplayEnable && pReplayEnable->GetInt() && !engine->IsPlayingDemo() && !engine->IsPlayingTimeDemo() ) + if ( pReplayEnable && pReplayEnable->GetInt() && !engine->IsPlayingDemo() && !engine->IsPlayingTimeDemo() ) { CReplayRagdollRecorder& RagdollRecorder = CReplayRagdollRecorder::Instance(); int nStartTick = TIME_TO_TICKS( engine->GetLastTimeStamp() ); @@ -4719,12 +5096,12 @@ void C_BaseAnimating::OnDataChanged( DataUpdateType_t updateType ) if (updateType == DATA_UPDATE_CREATED) { + // Now that the data has come down from the server, double-check that the clientside animation variables are handled properly + UpdateRelevantInterpolatedVars(); m_nPrevSequence = -1; m_nRestoreSequence = -1; } - - bool modelchanged = false; // UNDONE: The base class does this as well. So this is kind of ugly @@ -4738,6 +5115,11 @@ void C_BaseAnimating::OnDataChanged( DataUpdateType_t updateType ) BaseClass::OnDataChanged( updateType ); + if ( m_nPrevBody != GetBody() || m_nPrevSkin != GetSkin() ) + { + OnTranslucencyTypeChanged(); + } + if ( (updateType == DATA_UPDATE_CREATED) || modelchanged ) { ResetLatched(); @@ -4748,10 +5130,15 @@ void C_BaseAnimating::OnDataChanged( DataUpdateType_t updateType ) } } + if ( GetSequence() != m_nPrevSequence ) + { + OnNewSequence(); + } + // If there's a significant change, make sure the shadow updates if ( modelchanged || (GetSequence() != m_nPrevSequence)) { - InvalidatePhysicsRecursive( ANIMATION_CHANGED ); + InvalidatePhysicsRecursive( BOUNDS_CHANGED | SEQUENCE_CHANGED ); m_nPrevSequence = GetSequence(); } @@ -4761,54 +5148,51 @@ void C_BaseAnimating::OnDataChanged( DataUpdateType_t updateType ) // Check to see if we should reset our frame if ( m_bClientSideFrameReset != m_bLastClientSideFrameReset ) { - ResetClientsideFrame(); + SetCycle( 0 ); } } // build a ragdoll if necessary - if ( m_nRenderFX == kRenderFxRagdoll && !m_builtRagdoll ) + if ( m_bClientSideRagdoll && !m_builtRagdoll ) { - BecomeRagdollOnClient(); + if ( !cl_disable_ragdolls.GetBool() ) + { + if ( !BecomeRagdollOnClient() ) + { + AddEffects( EF_NODRAW ); + } + } } //HACKHACK!!! - if ( m_nRenderFX == kRenderFxRagdoll && m_builtRagdoll == true ) + if ( m_bClientSideRagdoll && m_builtRagdoll == true ) { if ( m_pRagdoll == NULL ) - AddEffects( EF_NODRAW ); + AddEffects( EF_NODRAW ); } - if ( m_pRagdoll && m_nRenderFX != kRenderFxRagdoll ) + if ( m_pRagdoll && !m_bClientSideRagdoll || !m_bClientSideRagdoll && m_builtRagdoll ) { ClearRagdoll(); } // If ragdolling and get EF_NOINTERP, we probably were dead and are now respawning, // don't do blend out of ragdoll at respawn spot. - if ( IsNoInterpolationFrame() && - m_pRagdollInfo && - m_pRagdollInfo->m_bActive ) - { - Msg( "delete ragdoll due to nointerp\n" ); - // Remove ragdoll info - delete m_pRagdollInfo; - m_pRagdollInfo = NULL; - } -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void C_BaseAnimating::AddEntity( void ) -{ - // Server says don't interpolate this frame, so set previous info to new info. - if ( IsNoInterpolationFrame() ) + if ( IsEffectActive( EF_NOINTERP ) ) { - ResetLatched(); + if ( m_pRagdollInfo && m_pRagdollInfo->m_bActive ) + { + Msg( "delete ragdoll due to nointerp\n" ); + // Remove ragdoll info + delete m_pRagdollInfo; + m_pRagdollInfo = NULL; + } + AddToEntityList(ENTITY_LIST_SIMULATE); } - BaseClass::AddEntity(); + m_bIsUsingRelativeLighting = ( m_hLightingOrigin.Get() != NULL ); } + //----------------------------------------------------------------------------- // Purpose: Get the index of the attachment point with the specified name //----------------------------------------------------------------------------- @@ -4859,7 +5243,7 @@ void C_BaseAnimating::ClientSideAnimationChanged() GetModelPtr(), GetSequence(), m_nNewSequenceParity != m_nPrevNewSequenceParity, - !IsNoInterpolationFrame() + !IsEffectActive(EF_NOINTERP) ); } @@ -4876,10 +5260,12 @@ void C_BaseAnimating::UpdateClientSideAnimation() Assert( m_ClientSideAnimationListHandle != INVALID_CLIENTSIDEANIMATION_LIST_HANDLE ); if ( GetSequence() != -1 ) { - // latch old values - OnLatchInterpolatedVariables( LATCH_ANIMATION_VAR ); - // move frame forward - FrameAdvance( 0.0f ); // 0 means to use the time we last advanced instead of a constant + { + // latch old values + OnLatchInterpolatedVariables( LATCH_ANIMATION_VAR ); + // move frame forward + FrameAdvance( 0.0f ); // 0 means to use the time we last advanced instead of a constant + } } } else @@ -4889,8 +5275,10 @@ void C_BaseAnimating::UpdateClientSideAnimation() } -void C_BaseAnimating::Simulate() +bool C_BaseAnimating::Simulate() { + bool bRet = !m_bIsStaticProp; // static prop defaults to false + if ( m_bInitModelEffects ) { DelayedInitModelEffects(); @@ -4898,17 +5286,35 @@ void C_BaseAnimating::Simulate() if ( gpGlobals->frametime != 0.0f ) { - DoAnimationEvents( GetModelPtr() ); + CStudioHdr *pStudio = GetModelPtr(); + if ( pStudio && pStudio->SequencesAvailable() ) + { + if ( pStudio->GetRenderHdr()->flags & STUDIOHDR_FLAGS_NO_ANIM_EVENTS ) + { + bRet = false; + } + else + { + DoAnimationEvents( pStudio ); + } + } + } + + if ( BaseClass::Simulate() ) + { + bRet = true; } - BaseClass::Simulate(); - if ( IsNoInterpolationFrame() ) + // Server says don't interpolate this frame, so set previous info to new info. + if ( IsEffectActive(EF_NOINTERP) ) { ResetLatched(); } - if ( GetSequence() != -1 && m_pRagdoll && ( m_nRenderFX != kRenderFxRagdoll ) ) + + if ( GetSequence() != -1 && m_pRagdoll && ( !m_bClientSideRagdoll ) ) { ClearRagdoll(); } + return bRet; } @@ -4961,9 +5367,8 @@ bool C_BaseAnimating::TestHitboxes( const Ray_t &ray, unsigned int fContentsMask // This *has* to be true for the existing code to function correctly. Assert( ray.m_StartOffset == vec3_origin ); - CBoneCache *pCache = GetBoneCache( pStudioHdr ); matrix3x4_t *hitboxbones[MAXSTUDIOBONES]; - pCache->ReadCachedBonePointers( hitboxbones, pStudioHdr->numbones() ); + HitboxToWorldTransforms( hitboxbones ); if ( TraceToStudio( physprops, ray, pStudioHdr, set, hitboxbones, fContentsMask, GetRenderOrigin(), GetModelScale(), tr ) ) { @@ -4971,7 +5376,8 @@ bool C_BaseAnimating::TestHitboxes( const Ray_t &ray, unsigned int fContentsMask mstudiobone_t *pBone = pStudioHdr->pBone(pbox->bone); tr.surface.name = "**studio**"; tr.surface.flags = SURF_HITBOX; - tr.surface.surfaceProps = physprops->GetSurfaceIndex( pBone->pszSurfaceProp() ); + tr.surface.surfaceProps = pBone->GetSurfaceProp(); + if ( IsRagdoll() ) { IPhysicsObject *pReplace = m_pRagdoll->GetElement( tr.physicsbone ); @@ -5016,8 +5422,33 @@ void C_BaseAnimating::SetCycle( float flCycle ) { if ( m_flCycle != flCycle ) { + Assert( IsFinite( flCycle ) ); m_flCycle = flCycle; InvalidatePhysicsRecursive( ANIMATION_CHANGED ); + + /* + if (r_sequence_debug.GetInt() == entindex() ) + { + DevMsgRT("%d : SetCycle %s:%.3f\n", entindex(), GetSequenceName( GetSequence() ), flCycle ); + } + */ + } +} + +//----------------------------------------------------------------------------- +// Reset any global fields that are dependant on the sequence +//----------------------------------------------------------------------------- +void C_BaseAnimating::OnNewSequence( void ) +{ + CStudioHdr *pStudioHdr = GetModelPtr(); + // Assert( pStudioHdr ); + if ( pStudioHdr ) + { + m_bSequenceLoops = ((GetSequenceFlags( pStudioHdr, GetSequence() ) & STUDIO_LOOPING) != 0); + m_flGroundSpeed = GetSequenceGroundSpeed( pStudioHdr, GetSequence() ); + + // FIXME: why is this called here? Nothing should have changed to make this nessesary + SetEventIndexForSequence( pStudioHdr->pSeqdesc( GetSequence() ) ); } } @@ -5037,15 +5468,40 @@ void C_BaseAnimating::SetSequence( int nSequence ) } */ + if (r_debug_sequencesets.GetInt() == entindex()) + { + Msg("%s : %s : SetSequence\n", GetClassname(), GetSequenceName( GetSequence() )); + } + m_nSequence = nSequence; - InvalidatePhysicsRecursive( ANIMATION_CHANGED ); + InvalidatePhysicsRecursive( BOUNDS_CHANGED | SEQUENCE_CHANGED ); if ( m_bClientSideAnimation ) { ClientSideAnimationChanged(); } + + OnNewSequence(); + /* + if (r_sequence_debug.GetInt() == entindex() ) + { + DevMsgRT("%d : SetSequence %s\n", entindex(), GetSequenceName( GetSequence() ) ); + } + */ } } +//----------------------------------------------------------------------------- +// Extracts the bounding box +//----------------------------------------------------------------------------- +void C_BaseAnimating::ExtractBbox( int nSequence, Vector &mins, Vector &maxs ) +{ + CStudioHdr *pStudioHdr = GetModelPtr(); + Assert( pStudioHdr ); + + ::ExtractBbox( pStudioHdr, nSequence, mins, maxs ); +} + + //========================================================= // StudioFrameAdvance - advance the animation frame up some interval (default 0.1) into the future @@ -5059,11 +5515,7 @@ void C_BaseAnimating::StudioFrameAdvance() if ( !hdr ) return; -#ifdef DEBUG - bool watch = dbganimmodel.GetString()[0] && V_stristr( hdr->pszName(), dbganimmodel.GetString() ); -#else - bool watch = false; // Q_strstr( hdr->name, "rifle" ) ? true : false; -#endif + bool watch = false; //Q_strstr( hdr->name(), "grip" ) ? true : false; //if (!anim.prevanimtime) //{ @@ -5079,10 +5531,8 @@ void C_BaseAnimating::StudioFrameAdvance() return; } - UpdateModelScale(); - //anim.prevanimtime = m_flAnimTime; - float cycleAdvance = flInterval * GetSequenceCycleRate( hdr, GetSequence() ) * m_flPlaybackRate; + float cycleAdvance = flInterval * GetSequenceCycleRate( hdr, GetSequence() ) * GetPlaybackRate(); float flNewCycle = GetCycle() + cycleAdvance; m_flAnimTime = gpGlobals->curtime; @@ -5107,7 +5557,7 @@ void C_BaseAnimating::StudioFrameAdvance() SetCycle( flNewCycle ); - m_flGroundSpeed = GetSequenceGroundSpeed( hdr, GetSequence() ) * GetModelScale(); + m_flGroundSpeed = GetSequenceGroundSpeed( hdr, GetSequence() ); #if 0 // I didn't have a test case for this, but it seems like the right thing to do. Check multi-player! @@ -5118,7 +5568,7 @@ void C_BaseAnimating::StudioFrameAdvance() if ( watch ) { - Msg("%s : %s : %5.1f\n", GetClassname(), GetSequenceName( GetSequence() ), GetCycle() ); + Msg("%s : %s : %1.3f\n", GetClassname(), GetSequenceName( GetSequence() ), GetCycle() ); } } @@ -5165,29 +5615,146 @@ void C_BaseAnimating::GetSequenceLinearMotion( int iSequence, Vector *pVec ) ::GetSequenceLinearMotion( GetModelPtr(), iSequence, m_flPoseParameter, pVec ); } +float C_BaseAnimating::GetSequenceLinearMotionAndDuration( int iSequence, Vector *pVec ) +{ + return ::GetSequenceLinearMotionAndDuration( GetModelPtr(), iSequence, m_flPoseParameter, pVec ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : +//----------------------------------------------------------------------------- +bool C_BaseAnimating::GetSequenceMovement( int nSequence, float fromCycle, float toCycle, Vector &deltaPosition, QAngle &deltaAngles ) +{ + CStudioHdr *pstudiohdr = GetModelPtr( ); + if (! pstudiohdr) + return false; + + return Studio_SeqMovement( pstudiohdr, nSequence, fromCycle, toCycle, m_flPoseParameter, deltaPosition, deltaAngles ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// +// Input : *pVec - +//----------------------------------------------------------------------------- void C_BaseAnimating::GetBlendedLinearVelocity( Vector *pVec ) { Vector vecDist; - float flDuration; + float flDuration = GetSequenceLinearMotionAndDuration( GetSequence(), &vecDist ); + VectorScale( vecDist, 1.0 / flDuration, *pVec ); + + Vector tmp; + for (int i = m_SequenceTransitioner.m_animationQueue.Count() - 2; i >= 0; i--) + { + CAnimationLayer *blend = &m_SequenceTransitioner.m_animationQueue[i]; + float flWeight = blend->GetFadeout( gpGlobals->curtime ); + if ( flWeight == 0.0f ) + continue; + + flDuration = GetSequenceLinearMotionAndDuration( blend->GetSequence(), &vecDist ); + VectorScale( vecDist, 1.0 / flDuration, tmp ); + *pVec = Lerp( flWeight, *pVec, tmp ); + } +} + + + +//----------------------------------------------------------------------------- +// Purpose: convert local movement into pose parameters that take account of blending +// Input: vecLocalVelocity - local velocity in right-hand-rule coordinates +// iMoveX, iMoveY - pose parameter indexes for movement +// Output : +//----------------------------------------------------------------------------- + +#define MOVEMENT_ERROR_LIMIT 1.0 + +void C_BaseAnimating::SetMovementPoseParams( const Vector &vecLocalVelocity, int iMoveX, int iMoveY, int iXSign, int iYSign ) +{ + CStudioHdr *pStudioHdr = GetModelPtr( ); + if (! pStudioHdr) + return; + + Vector2D vecCurrentPose( 0.0f, 0.0f ); + // set the pose parameters to the correct direction, but not value + if ( vecLocalVelocity.x != 0.0f && fabs( vecLocalVelocity.x ) > fabs( vecLocalVelocity.y ) ) + { + vecCurrentPose.x = ((vecLocalVelocity.x < 0.0) ? -iXSign : iXSign); + vecCurrentPose.y = iYSign * (vecLocalVelocity.y / fabs( vecLocalVelocity.x )); + } + else if (vecLocalVelocity.y != 0.0f) + { + vecCurrentPose.x = iXSign * (vecLocalVelocity.x / fabs( vecLocalVelocity.y )); + vecCurrentPose.y = ((vecLocalVelocity.y < 0.0) ? -iYSign : iYSign); + } + + if (vecCurrentPose.x == 0.0f && vecCurrentPose.y == 0.0f) + { + SetPoseParameter( pStudioHdr, iMoveX, vecCurrentPose.x ); + SetPoseParameter( pStudioHdr, iMoveY, vecCurrentPose.y ); + return; + } + + // refine pose parameters to be more accurate + int i = 0; + float dx, dy; + Vector vecAnimVelocity; + + // Set the initial 9-way blend movement pose parameters. + SetPoseParameter( pStudioHdr, iMoveX, vecCurrentPose.x ); + SetPoseParameter( pStudioHdr, iMoveY, vecCurrentPose.y ); + + /* + if ( r_sequence_debug.GetInt() == entindex() ) + { + DevMsgRT("%d (%d) : %.2f %.2f : %.2f %.2f : %.3f %.3f\n", entindex(), -1, vecLocalVelocity.x, vecLocalVelocity.y, vecAnimVelocity.x, vecAnimVelocity.y, vecCurrentPose.x, vecCurrentPose.y ); + } + */ + + bool retry = true; + do + { + GetBlendedLinearVelocity( &vecAnimVelocity ); + + // adjust X pose parameter based on movement error + if (fabs( vecAnimVelocity.x ) > 0.001) + { + vecCurrentPose.x *= vecLocalVelocity.x / vecAnimVelocity.x; + } + else + { + // too slow, set to zero so it can optimized out during bone setup + vecCurrentPose.x = 0; + } + SetPoseParameter( pStudioHdr, iMoveX, vecCurrentPose.x ); - GetSequenceLinearMotion( GetSequence(), &vecDist ); - flDuration = SequenceDuration( GetSequence() ); + // adjust Y pose parameter based on movement error + if (fabs( vecAnimVelocity.y ) > 0.001) + { + vecCurrentPose.y *= vecLocalVelocity.y / vecAnimVelocity.y; + } + else + { + // too slow, set to zero so it can optimized out during bone setup + vecCurrentPose.y = 0; + } + SetPoseParameter( pStudioHdr, iMoveY, vecCurrentPose.y ); - VectorScale( vecDist, 1.0 / flDuration, *pVec ); + /* + if ( r_sequence_debug.GetInt() == entindex() ) + { + DevMsgRT("%d (%d) : %.2f %.2f : %.2f %.2f : %.3f %.3f\n", entindex(), i, vecLocalVelocity.x, vecLocalVelocity.y, vecAnimVelocity.x, vecAnimVelocity.y, vecCurrentPose.x, vecCurrentPose.y ); + } + */ - Vector tmp; - for (int i = m_SequenceTransitioner.m_animationQueue.Count() - 2; i >= 0; i--) - { - C_AnimationLayer *blend = &m_SequenceTransitioner.m_animationQueue[i]; - - GetSequenceLinearMotion( blend->m_nSequence, &vecDist ); - flDuration = SequenceDuration( blend->m_nSequence ); + dx = vecLocalVelocity.x - vecAnimVelocity.x; + dy = vecLocalVelocity.y - vecAnimVelocity.y; - VectorScale( vecDist, 1.0 / flDuration, tmp ); + retry = (vecCurrentPose.x < 1.0 && vecCurrentPose.x > -1.0) && (dx < -MOVEMENT_ERROR_LIMIT || dx > MOVEMENT_ERROR_LIMIT); + retry = retry || ((vecCurrentPose.y < 1.0 && vecCurrentPose.y > -1.0) && (dy < -MOVEMENT_ERROR_LIMIT || dy > MOVEMENT_ERROR_LIMIT)); - float flWeight = blend->GetFadeout( gpGlobals->curtime ); - *pVec = Lerp( flWeight, *pVec, tmp ); - } + } while (i++ < 5 && retry); } //----------------------------------------------------------------------------- @@ -5201,11 +5768,7 @@ float C_BaseAnimating::FrameAdvance( float flInterval ) if ( !hdr ) return 0.0f; -#ifdef DEBUG - bool bWatch = dbganimmodel.GetString()[0] && V_stristr( hdr->pszName(), dbganimmodel.GetString() ); -#else - bool bWatch = false; // Q_strstr( hdr->name, "medkit_large" ) ? true : false; -#endif + bool bWatch = false; // Q_strstr( hdr->name, "commando" ) ? true : false; float curtime = gpGlobals->curtime; @@ -5224,7 +5787,10 @@ float C_BaseAnimating::FrameAdvance( float flInterval ) } float cyclerate = GetSequenceCycleRate( hdr, GetSequence() ); - float addcycle = flInterval * cyclerate * m_flPlaybackRate; + float addcycle = flInterval * cyclerate * GetPlaybackRate(); + + m_prevClientCycle = GetCycle(); + m_prevClientAnimTime = m_flAnimTime; if( GetServerIntendedCycle() != -1.0f ) { @@ -5266,6 +5832,11 @@ float C_BaseAnimating::FrameAdvance( float flInterval ) if ( (flNewCycle < 0.0f) || (flNewCycle >= 1.0f) ) { + if (flNewCycle >= 1.0f) + { + ReachedEndOfSequence(); + } + if ( IsSequenceLooping( hdr, GetSequence() ) ) { flNewCycle -= (int)(flNewCycle); @@ -5278,6 +5849,9 @@ float C_BaseAnimating::FrameAdvance( float flInterval ) } SetCycle( flNewCycle ); + InvalidatePhysicsRecursive( ANIMATION_CHANGED ); + + m_flGroundSpeed = GetSequenceGroundSpeed( hdr, GetSequence() ); return flInterval; } @@ -5290,27 +5864,24 @@ void C_BaseAnimating::ResetSequenceInfo( void ) SetSequence( 0 ); } - if ( IsDynamicModelLoading() ) + /* + if (r_sequence_debug.GetInt() == entindex() ) { - m_bResetSequenceInfoOnLoad = true; - return; + DevMsgRT("%d : client reset %s\n", entindex(), GetSequenceName( GetSequence() ) ); } + */ - CStudioHdr *pStudioHdr = GetModelPtr(); - m_flGroundSpeed = GetSequenceGroundSpeed( pStudioHdr, GetSequence() ) * GetModelScale(); - m_bSequenceLoops = ((GetSequenceFlags( pStudioHdr, GetSequence() ) & STUDIO_LOOPING) != 0); - // m_flAnimTime = gpGlobals->time; m_flPlaybackRate = 1.0; m_bSequenceFinished = false; m_flLastEventCheck = 0; - m_nNewSequenceParity = ( m_nNewSequenceParity + 1 ) & EF_PARITY_MASK; - m_nResetEventsParity = ( m_nResetEventsParity + 1 ) & EF_PARITY_MASK; - - // FIXME: why is this called here? Nothing should have changed to make this nessesary - SetEventIndexForSequence( pStudioHdr->pSeqdesc( GetSequence() ) ); + if ( !IsPlayer() ) + { + m_nNewSequenceParity = ( ++m_nNewSequenceParity ) & EF_PARITY_MASK; + } + m_nResetEventsParity = ( ++m_nResetEventsParity ) & EF_PARITY_MASK; } - + //========================================================= //========================================================= @@ -5358,53 +5929,78 @@ int C_BaseAnimating::FindTransitionSequence( int iCurrentSequence, int iGoalSequ } +void C_BaseAnimating::SetSkin( int iSkin ) +{ + if ( m_nSkin != iSkin ) + { + m_nSkin = iSkin; + OnTranslucencyTypeChanged(); + } +} + +void C_BaseAnimating::SetBody( int iBody ) +{ + if ( m_nBody != iBody ) + { + m_nBody = iBody; + OnTranslucencyTypeChanged(); + } +} + void C_BaseAnimating::SetBodygroup( int iGroup, int iValue ) { - // SetBodygroup is not supported on pending dynamic models. Wait for it to load! - // XXX TODO we could buffer up the group and value if we really needed to. -henryg Assert( GetModelPtr() ); + + int nOldBody = m_nBody; ::SetBodygroup( GetModelPtr( ), m_nBody, iGroup, iValue ); + if ( nOldBody != m_nBody ) + { + OnTranslucencyTypeChanged(); + } } int C_BaseAnimating::GetBodygroup( int iGroup ) { - Assert( IsDynamicModelLoading() || GetModelPtr() ); - return IsDynamicModelLoading() ? 0 : ::GetBodygroup( GetModelPtr( ), m_nBody, iGroup ); + Assert( GetModelPtr() ); + + return ::GetBodygroup( GetModelPtr( ), m_nBody, iGroup ); } const char *C_BaseAnimating::GetBodygroupName( int iGroup ) { - Assert( IsDynamicModelLoading() || GetModelPtr() ); - return IsDynamicModelLoading() ? "" : ::GetBodygroupName( GetModelPtr( ), iGroup ); + Assert( GetModelPtr() ); + + return ::GetBodygroupName( GetModelPtr( ), iGroup ); } int C_BaseAnimating::FindBodygroupByName( const char *name ) { - Assert( IsDynamicModelLoading() || GetModelPtr() ); - return IsDynamicModelLoading() ? -1 : ::FindBodygroupByName( GetModelPtr( ), name ); + Assert( GetModelPtr() ); + + return ::FindBodygroupByName( GetModelPtr( ), name ); } int C_BaseAnimating::GetBodygroupCount( int iGroup ) { - Assert( IsDynamicModelLoading() || GetModelPtr() ); - return IsDynamicModelLoading() ? 0 : ::GetBodygroupCount( GetModelPtr( ), iGroup ); + Assert( GetModelPtr() ); + + return ::GetBodygroupCount( GetModelPtr( ), iGroup ); } int C_BaseAnimating::GetNumBodyGroups( void ) { - Assert( IsDynamicModelLoading() || GetModelPtr() ); - return IsDynamicModelLoading() ? 0 : ::GetNumBodyGroups( GetModelPtr( ) ); + Assert( GetModelPtr() ); + + return ::GetNumBodyGroups( GetModelPtr( ) ); } + //----------------------------------------------------------------------------- // Purpose: // Input : setnum - //----------------------------------------------------------------------------- void C_BaseAnimating::SetHitboxSet( int setnum ) { - if ( IsDynamicModelLoading() ) - return; - #ifdef _DEBUG CStudioHdr *pStudioHdr = GetModelPtr(); if ( !pStudioHdr ) @@ -5432,9 +6028,6 @@ void C_BaseAnimating::SetHitboxSet( int setnum ) //----------------------------------------------------------------------------- void C_BaseAnimating::SetHitboxSetByName( const char *setname ) { - if ( IsDynamicModelLoading() ) - return; - m_nHitboxSet = FindHitboxSetByName( GetModelPtr(), setname ); } @@ -5453,9 +6046,6 @@ int C_BaseAnimating::GetHitboxSet( void ) //----------------------------------------------------------------------------- const char *C_BaseAnimating::GetHitboxSetName( void ) { - if ( IsDynamicModelLoading() ) - return ""; - return ::GetHitboxSetName( GetModelPtr(), m_nHitboxSet ); } @@ -5465,9 +6055,6 @@ const char *C_BaseAnimating::GetHitboxSetName( void ) //----------------------------------------------------------------------------- int C_BaseAnimating::GetHitboxSetCount( void ) { - if ( IsDynamicModelLoading() ) - return 0; - return ::GetHitboxSetCount( GetModelPtr() ); } @@ -5531,16 +6118,23 @@ int C_BaseAnimating::SelectWeightedSequence ( int activity ) { Assert( activity != ACT_INVALID ); - return ::SelectWeightedSequence( GetModelPtr(), activity ); + return ::SelectWeightedSequence( GetModelPtr(), activity, -1 ); } +int C_BaseAnimating::SelectWeightedSequenceFromModifiers( Activity activity, CUtlSymbol *pActivityModifiers, int iModifierCount ) +{ + Assert( activity != ACT_INVALID ); + Assert( GetModelPtr() ); + return GetModelPtr()->SelectWeightedSequenceFromModifiers( activity, pActivityModifiers, iModifierCount ); +} + //========================================================= //========================================================= int C_BaseAnimating::LookupPoseParameter( CStudioHdr *pstudiohdr, const char *szName ) { if ( !pstudiohdr ) - return 0; + return -1; for (int i = 0; i < pstudiohdr->GetNumPoseParameters(); i++) { @@ -5569,7 +6163,9 @@ float C_BaseAnimating::SetPoseParameter( CStudioHdr *pStudioHdr, int iParameter, return flValue; } - if (iParameter >= 0) + Assert( IsFinite( flValue ) ); + + if ( iParameter >= 0 ) { float flNewValue; flValue = Studio_SetPoseParameter( pStudioHdr, iParameter, flValue, flNewValue ); @@ -5579,6 +6175,28 @@ float C_BaseAnimating::SetPoseParameter( CStudioHdr *pStudioHdr, int iParameter, return flValue; } + +float C_BaseAnimating::GetPoseParameter( int iParameter ) +{ + CStudioHdr *pStudioHdr = GetModelPtr(); + + if ( pStudioHdr == NULL ) + return 0.0f; + + if ( !pStudioHdr ) + { + Assert(!"C_BaseAnimating::SetPoseParameter: model missing"); + return 0.0f; + } + + if ( iParameter >= 0 ) + { + return Studio_GetPoseParameter( pStudioHdr, iParameter, m_flPoseParameter[ iParameter ] ); + } + + return 0.0f; +} + //----------------------------------------------------------------------------- // Purpose: // Input : *label - @@ -5598,13 +6216,7 @@ void C_BaseAnimating::Release() void C_BaseAnimating::Clear( void ) { - InvalidateMdlCache(); Q_memset(&m_mouth, 0, sizeof(m_mouth)); - m_flCycle = 0; - m_flOldCycle = 0; - m_bResetSequenceInfoOnLoad = false; - m_bDynamicModelPending = false; - m_AutoRefModelIndex.Clear(); BaseClass::Clear(); } @@ -5704,7 +6316,7 @@ void C_BaseAnimating::GetAimEntOrigin( IClientEntity *pAttachedTo, Vector *pAbsO if ( IsEffectActive( EF_BONEMERGE ) && IsEffectActive( EF_BONEMERGE_FASTCULL ) && (pMoveParent = GetMoveParent()) != NULL ) { // Doing this saves a lot of CPU. - *pAbsOrigin = pMoveParent->WorldSpaceCenter(); + *pAbsOrigin = pMoveParent->GetRenderOrigin(); *pAbsAngles = pMoveParent->GetRenderAngles(); } else @@ -5749,26 +6361,6 @@ Activity C_BaseAnimating::GetSequenceActivity( int iSequence ) } - -//----------------------------------------------------------------------------- -// returns the sequence keyvalue text as a KeyValues pointer -//----------------------------------------------------------------------------- -KeyValues *C_BaseAnimating::GetSequenceKeyValues( int iSequence ) -{ - const char *szText = Studio_GetKeyValueText( GetModelPtr(), iSequence ); - - if (szText) - { - KeyValues *seqKeyValues = new KeyValues(""); - if ( seqKeyValues->LoadFromBuffer( modelinfo->GetModelName( GetModel() ), szText ) ) - { - return seqKeyValues; - } - seqKeyValues->deleteThis(); - } - return NULL; -} - //----------------------------------------------------------------------------- // Computes a box that surrounds all hitboxes //----------------------------------------------------------------------------- @@ -5787,9 +6379,8 @@ bool C_BaseAnimating::ComputeHitboxSurroundingBox( Vector *pVecWorldMins, Vector if ( !set || !set->numhitboxes ) return false; - CBoneCache *pCache = GetBoneCache( pStudioHdr ); matrix3x4_t *hitboxbones[MAXSTUDIOBONES]; - pCache->ReadCachedBonePointers( hitboxbones, pStudioHdr->numbones() ); + HitboxToWorldTransforms( hitboxbones ); // Compute a box in world space that surrounds this entity pVecWorldMins->Init( FLT_MAX, FLT_MAX, FLT_MAX ); @@ -5825,9 +6416,8 @@ bool C_BaseAnimating::ComputeEntitySpaceHitboxSurroundingBox( Vector *pVecWorldM if ( !set || !set->numhitboxes ) return false; - CBoneCache *pCache = GetBoneCache( pStudioHdr ); matrix3x4_t *hitboxbones[MAXSTUDIOBONES]; - pCache->ReadCachedBonePointers( hitboxbones, pStudioHdr->numbones() ); + HitboxToWorldTransforms( hitboxbones ); // Compute a box in world space that surrounds this entity pVecWorldMins->Init( FLT_MAX, FLT_MAX, FLT_MAX ); @@ -5853,61 +6443,13 @@ bool C_BaseAnimating::ComputeEntitySpaceHitboxSurroundingBox( Vector *pVecWorldM // Purpose: // Input : scale - //----------------------------------------------------------------------------- -void C_BaseAnimating::SetModelScale( float scale, float change_duration /*= 0.0f*/ ) +void C_BaseAnimating::SetModelScale( float scale ) { - if ( change_duration > 0.0f ) - { - ModelScale *mvs = ( ModelScale * )CreateDataObject( MODELSCALE ); - mvs->m_flModelScaleStart = m_flModelScale; - mvs->m_flModelScaleGoal = scale; - mvs->m_flModelScaleStartTime = gpGlobals->curtime; - mvs->m_flModelScaleFinishTime = mvs->m_flModelScaleStartTime + change_duration; - } - else + if ( m_flModelScale != scale ) { m_flModelScale = scale; - RefreshCollisionBounds(); - - if ( HasDataObjectType( MODELSCALE ) ) - { - DestroyDataObject( MODELSCALE ); - } - } -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void C_BaseAnimating::UpdateModelScale() -{ - ModelScale *mvs = ( ModelScale * )GetDataObject( MODELSCALE ); - if ( !mvs ) - { - return; - } - - float dt = mvs->m_flModelScaleFinishTime - mvs->m_flModelScaleStartTime; - Assert( dt > 0.0f ); - - float frac = ( gpGlobals->curtime - mvs->m_flModelScaleStartTime ) / dt; - frac = clamp( frac, 0.0f, 1.0f ); - - if ( gpGlobals->curtime >= mvs->m_flModelScaleFinishTime ) - { - m_flModelScale = mvs->m_flModelScaleGoal; - DestroyDataObject( MODELSCALE ); - } - else - { - m_flModelScale = Lerp( frac, mvs->m_flModelScaleStart, mvs->m_flModelScaleGoal ); + InvalidatePhysicsRecursive( BOUNDS_CHANGED ); } - - RefreshCollisionBounds(); -} - -void C_BaseAnimating::RefreshCollisionBounds( void ) -{ - CollisionProp()->RefreshScaledCollisionBounds(); } //----------------------------------------------------------------------------- @@ -5925,7 +6467,7 @@ class C_BoneFollower : public C_BaseEntity } bool ShouldDraw( void ); - int DrawModel( int flags ); + int DrawModel( int flags, const RenderableInstance_t &instance ); bool TestCollision( const Ray_t &ray, unsigned int mask, trace_t& trace ); private: @@ -5957,7 +6499,7 @@ bool C_BoneFollower::ShouldDraw( void ) //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- -int C_BoneFollower::DrawModel( int flags ) +int C_BoneFollower::DrawModel( int flags, const RenderableInstance_t &instance ) { vcollide_t *pCollide = modelinfo->GetVCollide( m_modelIndex ); if ( pCollide ) @@ -5974,6 +6516,11 @@ bool C_BoneFollower::TestCollision( const Ray_t &ray, unsigned int mask, trace_t { vcollide_t *pCollide = modelinfo->GetVCollide( m_modelIndex ); Assert( pCollide && pCollide->solidCount > m_solidIndex ); + if ( !pCollide ) + { + DevWarning("Failed to get collision model (%d, %d), %s (%s)\n", m_modelIndex, m_solidIndex, modelinfo->GetModelName(modelinfo->GetModel(m_modelIndex)), IsDormant() ? "dormant" : "active" ); + return false; + } physcollision->TraceBox( ray, pCollide->solids[m_solidIndex], GetAbsOrigin(), GetAbsAngles(), &trace ); @@ -6005,7 +6552,7 @@ void C_BaseAnimating::DoMuzzleFlash() //----------------------------------------------------------------------------- void DevMsgRT( char const* pMsg, ... ) { - if (gpGlobals->frametime != 0.0f) + if (!engine->Con_IsVisible()) { va_list argptr; va_start( argptr, pMsg ); @@ -6037,8 +6584,6 @@ void C_BaseAnimating::AddToClientSideAnimationList() clientanimating_t list( this, 0 ); m_ClientSideAnimationListHandle = g_ClientSideAnimationList.AddToTail( list ); ClientSideAnimationChanged(); - - UpdateRelevantInterpolatedVars(); } void C_BaseAnimating::RemoveFromClientSideAnimationList() @@ -6071,8 +6616,6 @@ void C_BaseAnimating::RemoveFromClientSideAnimationList() // Invalidate our handle no matter what. m_ClientSideAnimationListHandle = INVALID_CLIENTSIDEANIMATION_LIST_HANDLE; - - UpdateRelevantInterpolatedVars(); } @@ -6096,7 +6639,7 @@ CBoneList *C_BaseAnimating::RecordBones( CStudioHdr *hdr, matrix3x4_t *pBoneStat { if ( !ToolsEnabled() ) return NULL; - + VPROF_BUDGET( "C_BaseAnimating::RecordBones", VPROF_BUDGETGROUP_TOOLS ); // Possible optimization: Instead of inverting everything while recording, record the pos/q stuff into a structure instead? @@ -6106,8 +6649,9 @@ CBoneList *C_BaseAnimating::RecordBones( CStudioHdr *hdr, matrix3x4_t *pBoneStat matrix3x4_t parentTransform; AngleMatrix( GetRenderAngles(), GetRenderOrigin(), parentTransform ); - CBoneList *boneList = CBoneList::Alloc(); - Assert( boneList ); + Assert( !m_bBoneListInUse ); + CBoneList *boneList = m_bBoneListInUse ? CBoneList::Alloc() : &m_recordingBoneList; + m_bBoneListInUse = true; boneList->m_nBones = hdr->numbones(); @@ -6155,7 +6699,7 @@ void C_BaseAnimating::GetToolRecordingState( KeyValues *msg ) // Force the animation to drive bones CStudioHdr *hdr = GetModelPtr(); - matrix3x4_t *pBones = (matrix3x4_t*)_alloca( ( hdr ? hdr->numbones() : 1 ) * sizeof(matrix3x4_t) ); + matrix3x4a_t *pBones = (matrix3x4a_t*)stackalloc( ( hdr ? hdr->numbones() : 1 ) * sizeof(matrix3x4_t) ); if ( hdr ) { SetupBones( pBones, hdr->numbones(), BONE_USED_BY_ANYTHING, gpGlobals->curtime ); @@ -6168,16 +6712,22 @@ void C_BaseAnimating::GetToolRecordingState( KeyValues *msg ) BaseClass::GetToolRecordingState( msg ); static BaseAnimatingRecordingState_t state; + state.m_nSkin = GetSkin(); - state.m_nBody = m_nBody; + state.m_nBody = GetBody(); state.m_nSequence = m_nSequence; - state.m_pBoneList = NULL; + state.m_pBoneList = hdr ? RecordBones( hdr, pBones ) : NULL; msg->SetPtr( "baseanimating", &state ); - msg->SetInt( "viewmodel", IsViewModel() ? 1 : 0 ); + msg->SetBool( "viewmodel", IsViewModelOrAttachment() ); - if ( hdr ) + if ( IsViewModel() ) { - state.m_pBoneList = RecordBones( hdr, pBones ); + C_BaseViewModel *pViewModel = assert_cast< C_BaseViewModel* >( this ); + C_BaseCombatWeapon *pWeapon = pViewModel->GetOwningWeapon(); + if ( pWeapon ) + { + pWeapon->GetToolViewModelState( msg ); + } } } @@ -6185,11 +6735,19 @@ void C_BaseAnimating::CleanupToolRecordingState( KeyValues *msg ) { if ( !ToolsEnabled() ) return; - + BaseAnimatingRecordingState_t *pState = (BaseAnimatingRecordingState_t*)msg->GetPtr( "baseanimating" ); if ( pState && pState->m_pBoneList ) { - pState->m_pBoneList->Release(); + if ( pState->m_pBoneList != &m_recordingBoneList ) + { + pState->m_pBoneList->Release(); + } + else + { + Assert( m_bBoneListInUse ); + m_bBoneListInUse = false; + } } BaseClass::CleanupToolRecordingState( msg ); @@ -6237,14 +6795,6 @@ const char *C_BaseAnimating::GetFlexControllerType( LocalFlexController_t iFlexC return pflexcontroller->pszType( ); } -//----------------------------------------------------------------------------- -// Purpose: Returns the fade scale of the entity in question -// Output : unsigned char - 0 - 255 alpha value -//----------------------------------------------------------------------------- -unsigned char C_BaseAnimating::GetClientSideFade( void ) -{ - return UTIL_ComputeEntityFade( this, m_fadeMinDist, m_fadeMaxDist, m_flFadeScale ); -} //----------------------------------------------------------------------------- // Purpose: Note that we've been transmitted a sequence @@ -6262,176 +6812,5 @@ bool C_BaseAnimating::ShouldResetSequenceOnNewModel( void ) return ( m_bReceivedSequence == false ); } -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void C_BaseAnimating::UpdateBoneAttachments( void ) -{ - if ( !m_pAttachedTo ) - return; - -// Assert( IsFollowingEntity() ); -// Assert( m_boneIndexAttached >= 0 ); - - C_BaseAnimating *follow = FindFollowedEntity(); - if ( follow && (m_boneIndexAttached >= 0) ) - { - matrix3x4_t boneToWorld, localSpace; - follow->GetCachedBoneMatrix( m_boneIndexAttached, boneToWorld ); - AngleMatrix( m_boneAngles, m_bonePosition, localSpace ); - ConcatTransforms( boneToWorld, localSpace, GetBoneForWrite( 0 ) ); - - Vector absOrigin; - MatrixGetColumn( GetBone( 0 ), 3, absOrigin ); - SetAbsOrigin( absOrigin ); - - QAngle absAngle; - MatrixAngles( GetBone( 0 ), absAngle ); - SetAbsAngles( absAngle); - } -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void C_BaseAnimating::AttachEntityToBone( C_BaseAnimating* attachTarget, int boneIndexAttached, Vector bonePosition, QAngle boneAngles ) -{ - if ( !attachTarget ) - return; - - SetCollisionGroup( COLLISION_GROUP_DEBRIS ); - - FollowEntity( attachTarget ); - SetOwnerEntity( attachTarget ); - -// Assert( boneIndexAttached >= 0 ); // We should be attaching to a bone. - - if ( boneIndexAttached >= 0 ) - { - m_boneIndexAttached = boneIndexAttached; - m_bonePosition = bonePosition; - m_boneAngles = boneAngles; - } - - m_BoneAccessor.SetReadableBones( BONE_USED_BY_ANYTHING ); - m_BoneAccessor.SetWritableBones( BONE_USED_BY_ANYTHING ); - - attachTarget->AddBoneAttachment( this ); - - NotifyBoneAttached( attachTarget ); -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void C_BaseAnimating::NotifyBoneAttached( C_BaseAnimating* attachTarget ) -{ - // If we're already attached to something, remove us from it. - if ( m_pAttachedTo ) - { - m_pAttachedTo->RemoveBoneAttachment( this ); - m_pAttachedTo = NULL; - } - - // Remember the new attach target. - m_pAttachedTo = attachTarget; - - // Special case: if we just attached to the local player and he is hidden, hide us as well. - C_BasePlayer *pPlayer = dynamic_cast(attachTarget); - if ( pPlayer && pPlayer->IsLocalPlayer() ) - { - if ( !C_BasePlayer::ShouldDrawLocalPlayer() ) - { - AddEffects( EF_NODRAW ); - } - } - else - { - RemoveEffects( EF_NODRAW ); - } -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void C_BaseAnimating::AddBoneAttachment( C_BaseAnimating* newBoneAttachment ) -{ - if ( !newBoneAttachment ) - return; - - m_BoneAttachments.AddToTail( newBoneAttachment ); -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void C_BaseAnimating::RemoveBoneAttachment( C_BaseAnimating* boneAttachment ) -{ - if ( !boneAttachment ) - return; - - m_BoneAttachments.FindAndRemove( boneAttachment ); -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -int C_BaseAnimating::GetNumBoneAttachments() -{ - return m_BoneAttachments.Count(); -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -C_BaseAnimating* C_BaseAnimating::GetBoneAttachment( int i ) -{ - if ( m_BoneAttachments.IsValidIndex(i) ) - { - return m_BoneAttachments[i]; - } - return NULL; -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void C_BaseAnimating::DestroyBoneAttachments() -{ - while ( GetNumBoneAttachments() ) - { - C_BaseAnimating *pAttachment = GetBoneAttachment(0); - if ( pAttachment ) - { - pAttachment->Release(); - } - else - { - m_BoneAttachments.Remove(0); - } - } -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void C_BaseAnimating::MoveBoneAttachments( C_BaseAnimating* attachTarget ) -{ - if ( !attachTarget ) - return; - - // Move all of our bone attachments to this new object. - // Preserves the specific bone and attachment location information. - while ( GetNumBoneAttachments() ) - { - C_BaseAnimating *pAttachment = GetBoneAttachment(0); - if ( pAttachment ) - { - pAttachment->AttachEntityToBone( attachTarget ); - } - else - { - m_BoneAttachments.Remove(0); - } - } -} +bool C_BaseAnimating::m_bBoneListInUse = false; +CBoneList C_BaseAnimating::m_recordingBoneList; diff --git a/game/client/c_baseanimating.h b/game/client/c_baseanimating.h index f91745ef1..c6b8106eb 100644 --- a/game/client/c_baseanimating.h +++ b/game/client/c_baseanimating.h @@ -1,10 +1,10 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // // $Workfile: $ // $NoKeywords: $ -//=============================================================================// +//===========================================================================// #ifndef C_BASEANIMATING_H #define C_BASEANIMATING_H @@ -14,18 +14,19 @@ #include "c_baseentity.h" #include "studio.h" -#include "utlvector.h" +#include "UtlVector.h" #include "ragdoll.h" #include "mouthinfo.h" // Shared activities #include "ai_activity.h" #include "animationlayer.h" -#include "sequence_Transitioner.h" +#include "sequence_transitioner.h" #include "bone_accessor.h" #include "bone_merge_cache.h" #include "ragdoll_shared.h" #include "tier0/threadtools.h" #include "datacache/idatacache.h" +#include "toolframework/itoolframework.h" #define LIPSYNC_POSEPARAM_NAME "mouth" #define NUM_HITBOX_FIRES 10 @@ -38,6 +39,7 @@ class C_BaseClientShader */ class IRagdoll; +class C_ClientRagdoll; class CIKContext; class CIKState; class ConVar; @@ -51,7 +53,7 @@ FORWARD_DECLARE_HANDLE( memhandle_t ); typedef unsigned short MDLHandle_t; extern ConVar vcollide_wireframe; - +extern IDataCache *datacache; struct ClientModelRenderInfo_t : public ModelRenderInfo_t { @@ -88,13 +90,15 @@ typedef unsigned int ClientSideAnimationListHandle_t; #define INVALID_CLIENTSIDEANIMATION_LIST_HANDLE (ClientSideAnimationListHandle_t)~0 -class C_BaseAnimating : public C_BaseEntity, private IModelLoadCallback +class C_BaseAnimating : public C_BaseEntity, public IClientModelRenderable { public: DECLARE_CLASS( C_BaseAnimating, C_BaseEntity ); DECLARE_CLIENTCLASS(); DECLARE_PREDICTABLE(); DECLARE_INTERPOLATION(); + DECLARE_FRIEND_DATADESC_ACCESS(); + DECLARE_ENT_SCRIPTDESC(); enum { @@ -102,21 +106,28 @@ class C_BaseAnimating : public C_BaseEntity, private IModelLoadCallback NUM_BONECTRLS = 4 }; + // Inherited from IClientUnknown +public: + virtual IClientModelRenderable* GetClientModelRenderable(); + + // Inherited from IClientModelRenderable +public: + virtual bool GetRenderData( void *pData, ModelDataCategory_t nCategory ); + +public: C_BaseAnimating(); ~C_BaseAnimating(); virtual C_BaseAnimating* GetBaseAnimating() { return this; } - bool UsesPowerOfTwoFrameBufferTexture( void ); + int GetRenderFlags( void ); virtual bool Interpolate( float currentTime ); - virtual void Simulate(); + virtual bool Simulate(); virtual void Release(); float GetAnimTimeInterval( void ) const; - virtual unsigned char GetClientSideFade( void ); - // Get bone controller values. virtual void GetBoneControllers(float controllers[MAXSTUDIOBONECTRLS]); virtual float SetBoneController ( int iController, float flValue ); @@ -138,17 +149,18 @@ class C_BaseAnimating : public C_BaseEntity, private IModelLoadCallback // base model functionality float ClampCycle( float cycle, bool isLooping ); virtual void GetPoseParameters( CStudioHdr *pStudioHdr, float poseParameter[MAXSTUDIOPOSEPARAM] ); + virtual void CalcBoneMerge( CStudioHdr *hdr, int boneMask, CBoneBitList &boneComputed ); virtual void BuildTransformations( CStudioHdr *pStudioHdr, Vector *pos, Quaternion q[], const matrix3x4_t& cameraTransform, int boneMask, CBoneBitList &boneComputed ); + void BuildJiggleTransformations( int boneIndex, const mstudiojigglebone_t *jiggleParams, const matrix3x4_t &goalMX ); virtual void ApplyBoneMatrixTransform( matrix3x4_t& transform ); virtual int VPhysicsGetObjectList( IPhysicsObject **pList, int listMax ); // model specific - virtual bool SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime ); + virtual bool SetupBones( matrix3x4a_t *pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime ); virtual void UpdateIKLocks( float currentTime ); virtual void CalculateIKLocks( float currentTime ); - virtual bool ShouldDraw(); - virtual int DrawModel( int flags ); - virtual int InternalDrawModel( int flags ); + virtual int DrawModel( int flags, const RenderableInstance_t &instance ); + virtual int InternalDrawModel( int flags, const RenderableInstance_t &instance ); virtual bool OnInternalDrawModel( ClientModelRenderInfo_t *pInfo ); virtual bool OnPostInternalDrawModel( ClientModelRenderInfo_t *pInfo ); void DoInternalDrawModel( ClientModelRenderInfo_t *pInfo, DrawModelState_t *pState, matrix3x4_t *pBoneToWorldArray = NULL ); @@ -161,34 +173,32 @@ class C_BaseAnimating : public C_BaseEntity, private IModelLoadCallback virtual void DoAnimationEvents( CStudioHdr *pStudio ); virtual void FireEvent( const Vector& origin, const QAngle& angles, int event, const char *options ); virtual void FireObsoleteEvent( const Vector& origin, const QAngle& angles, int event, const char *options ); - virtual const char* ModifyEventParticles( const char* token ) { return token; } // Parses and distributes muzzle flash events virtual bool DispatchMuzzleEffect( const char *options, bool isFirstPerson ); + virtual void EjectParticleBrass( const char *pEffectName, const int iAttachment ); // virtual void AllocateMaterials( void ); // virtual void FreeMaterials( void ); - virtual void ValidateModelIndex( void ); virtual CStudioHdr *OnNewModel( void ); CStudioHdr *GetModelPtr() const; void InvalidateMdlCache(); virtual void SetPredictable( bool state ); void UseClientSideAnimation(); + bool IsUsingClientSideAnimation() { return m_bClientSideAnimation; } // C_BaseClientShader **p_ClientShaders; - virtual void StandardBlendingRules( CStudioHdr *pStudioHdr, Vector pos[], Quaternion q[], float currentTime, int boneMask ); + virtual void StandardBlendingRules( CStudioHdr *pStudioHdr, Vector pos[], QuaternionAligned q[], float currentTime, int boneMask ); void UnragdollBlend( CStudioHdr *hdr, Vector pos[], Quaternion q[], float currentTime ); void MaintainSequenceTransitions( IBoneSetup &boneSetup, float flCycle, Vector pos[], Quaternion q[] ); virtual void AccumulateLayers( IBoneSetup &boneSetup, Vector pos[], Quaternion q[], float currentTime ); - virtual void ChildLayerBlend( Vector pos[], Quaternion q[], float currentTime, int boneMask ); - // Attachments - int LookupAttachment( const char *pAttachmentName ); + virtual int LookupAttachment( const char *pAttachmentName ); int LookupRandomAttachment( const char *pAttachmentNameSubstring ); int LookupPoseParameter( CStudioHdr *pStudioHdr, const char *szName ); @@ -198,49 +208,25 @@ class C_BaseAnimating : public C_BaseEntity, private IModelLoadCallback inline float SetPoseParameter( const char *szName, float flValue ) { return SetPoseParameter( GetModelPtr(), szName, flValue ); } float SetPoseParameter( CStudioHdr *pStudioHdr, int iParameter, float flValue ); inline float SetPoseParameter( int iParameter, float flValue ) { return SetPoseParameter( GetModelPtr(), iParameter, flValue ); } + float GetPoseParameter( int iParameter ); - float GetPoseParameter( int iPoseParameter ); - + float GetPoseParameterRaw( int iPoseParameter ); // returns raw 0..1 value bool GetPoseParameterRange( int iPoseParameter, float &minValue, float &maxValue ); int LookupBone( const char *szName ); void GetBonePosition( int iBone, Vector &origin, QAngle &angles ); void GetBoneTransform( int iBone, matrix3x4_t &pBoneToWorld ); - - //============================================================================= - // HPE_BEGIN: - // [menglish] Finds the bone associated with the given hitbox - //============================================================================= - - int GetHitboxBone( int hitboxIndex ); - - //============================================================================= - // HPE_END - //============================================================================= - - // Bone attachments - virtual void AttachEntityToBone( C_BaseAnimating* attachTarget, int boneIndexAttached=-1, Vector bonePosition=Vector(0,0,0), QAngle boneAngles=QAngle(0,0,0) ); - void AddBoneAttachment( C_BaseAnimating* newBoneAttachment ); - void RemoveBoneAttachment( C_BaseAnimating* boneAttachment ); - void RemoveBoneAttachments(); - void DestroyBoneAttachments(); - void MoveBoneAttachments( C_BaseAnimating* attachTarget ); - int GetNumBoneAttachments(); - C_BaseAnimating* GetBoneAttachment( int i ); - virtual void NotifyBoneAttached( C_BaseAnimating* attachTarget ); - virtual void UpdateBoneAttachments( void ); - + + void CopySequenceTransitions( C_BaseAnimating *pCopyFrom ); //bool solveIK(float a, float b, const Vector &Foot, const Vector &Knee1, Vector &Knee2); //void DebugIK( mstudioikchain_t *pikchain ); virtual void PreDataUpdate( DataUpdateType_t updateType ); virtual void PostDataUpdate( DataUpdateType_t updateType ); - virtual int RestoreData( const char *context, int slot, int type ); - + virtual void NotifyShouldTransmit( ShouldTransmitState_t state ); virtual void OnPreDataChanged( DataUpdateType_t updateType ); virtual void OnDataChanged( DataUpdateType_t updateType ); - virtual void AddEntity( void ); // This can be used to force client side animation to be on. Only use if you know what you're doing! // Normally, the server entity should set this. @@ -268,14 +254,13 @@ class C_BaseAnimating : public C_BaseEntity, private IModelLoadCallback virtual bool GetAttachment( int number, Vector &origin, QAngle &angles ); virtual bool GetAttachment( int number, matrix3x4_t &matrix ); virtual bool GetAttachmentVelocity( int number, Vector &originVel, Quaternion &angleVel ); + virtual void InvalidateAttachments(); // Returns the attachment in local space bool GetAttachmentLocal( int iAttachment, matrix3x4_t &attachmentToLocal ); bool GetAttachmentLocal( int iAttachment, Vector &origin, QAngle &angles ); bool GetAttachmentLocal( int iAttachment, Vector &origin ); - bool GetRootBone( matrix3x4_t &rootBone ); - // Should this object cast render-to-texture shadows? virtual ShadowType_t ShadowCastType(); @@ -285,12 +270,15 @@ class C_BaseAnimating : public C_BaseEntity, private IModelLoadCallback virtual bool TestCollision( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr ); virtual bool TestHitboxes( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr ); + // returns true if we are of type C_ClientRagdoll + virtual bool IsClientRagdoll() const { return false; } + // returns true if we're currently being ragdolled bool IsRagdoll() const; - bool IsAboutToRagdoll() const; virtual C_BaseAnimating *BecomeRagdollOnClient(); + virtual C_ClientRagdoll *CreateClientRagdoll( bool bRestoring = false ); C_BaseAnimating *CreateRagdollCopy(); - bool InitAsClientRagdoll( const matrix3x4_t *pDeltaBones0, const matrix3x4_t *pDeltaBones1, const matrix3x4_t *pCurrentBonePosition, float boneDt, bool bFixedConstraints=false ); + bool InitAsClientRagdoll( const matrix3x4_t *pDeltaBones0, const matrix3x4_t *pDeltaBones1, const matrix3x4_t *pCurrentBonePosition, float boneDt ); void IgniteRagdoll( C_BaseAnimating *pSource ); void TransferDissolveFrom( C_BaseAnimating *pSource ); virtual void SaveRagdollInfo( int numbones, const matrix3x4_t &cameraTransform, CBoneAccessor &pBoneToWorld ); @@ -298,42 +286,44 @@ class C_BaseAnimating : public C_BaseEntity, private IModelLoadCallback virtual void Clear( void ); void ClearRagdoll(); void CreateUnragdollInfo( C_BaseAnimating *pRagdoll ); - void ForceSetupBonesAtTime( matrix3x4_t *pBonesOut, float flTime ); - virtual void GetRagdollInitBoneArrays( matrix3x4_t *pDeltaBones0, matrix3x4_t *pDeltaBones1, matrix3x4_t *pCurrentBones, float boneDt ); + void ForceSetupBonesAtTime( matrix3x4a_t *pBonesOut, float flTime ); + virtual void GetRagdollInitBoneArrays( matrix3x4a_t *pDeltaBones0, matrix3x4a_t *pDeltaBones1, matrix3x4a_t *pCurrentBones, float boneDt ); // For shadows rendering the correct body + sequence... virtual int GetBody() { return m_nBody; } virtual int GetSkin() { return m_nSkin; } - bool IsOnFire() { return ( (GetFlags() & FL_ONFIRE) != 0 ); } + bool IsOnFire() { return ( (GetFlags() & FL_ONFIRE) != 0 ); } + float GetFrozenAmount() { return m_flFrozen; } - inline float GetPlaybackRate(); + inline float GetPlaybackRate() const; inline void SetPlaybackRate( float rate ); - void SetModelScale( float scale, float change_duration = 0.0f ); - float GetModelScale() const { return m_flModelScale; } + void SetModelScale( float scale ); + inline float GetModelScale() const { return m_flModelScale; } inline bool IsModelScaleFractional() const; /// very fast way to ask if the model scale is < 1.0f (faster than if (GetModelScale() < 1.0f) ) - inline bool IsModelScaled() const; - void UpdateModelScale( void ); - virtual void RefreshCollisionBounds( void ); int GetSequence(); - virtual void SetSequence(int nSequence); + void SetSequence(int nSequence); inline void ResetSequence(int nSequence); + void OnNewSequence( ); float GetSequenceGroundSpeed( CStudioHdr *pStudioHdr, int iSequence ); inline float GetSequenceGroundSpeed( int iSequence ) { return GetSequenceGroundSpeed(GetModelPtr(), iSequence); } bool IsSequenceLooping( CStudioHdr *pStudioHdr, int iSequence ); inline bool IsSequenceLooping( int iSequence ) { return IsSequenceLooping(GetModelPtr(),iSequence); } float GetSequenceMoveDist( CStudioHdr *pStudioHdr, int iSequence ); void GetSequenceLinearMotion( int iSequence, Vector *pVec ); + float GetSequenceLinearMotionAndDuration( int iSequence, Vector *pVec ); + bool GetSequenceMovement( int nSequence, float fromCycle, float toCycle, Vector &deltaPosition, QAngle &deltaAngles ); void GetBlendedLinearVelocity( Vector *pVec ); + void SetMovementPoseParams( const Vector &vecLocalVelocity, int iMoveX, int iMoveY, int iXSign = 1, int iYSign = 1 ); int LookupSequence ( const char *label ); int LookupActivity( const char *label ); char const *GetSequenceName( int iSequence ); char const *GetSequenceActivityName( int iSequence ); Activity GetSequenceActivity( int iSequence ); - KeyValues *GetSequenceKeyValues( int iSequence ); virtual void StudioFrameAdvance(); // advance animation frame to some time in the future + void ExtractBbox( int nSequence, Vector &mins, Vector &maxs ); // Clientside animation virtual float FrameAdvance( float flInterval = 0.0f ); @@ -341,8 +331,8 @@ class C_BaseAnimating : public C_BaseEntity, private IModelLoadCallback virtual void UpdateClientSideAnimation(); void ClientSideAnimationChanged(); virtual unsigned int ComputeClientSideAnimationFlags(); - - virtual void ResetClientsideFrame( void ) { SetCycle( 0 ); } + float GetGroundSpeed( void ) { return m_flGroundSpeed; } + virtual void ReachedEndOfSequence() { return; } void SetCycle( float flCycle ); float GetCycle() const; @@ -350,18 +340,21 @@ class C_BaseAnimating : public C_BaseEntity, private IModelLoadCallback void SetBodygroup( int iGroup, int iValue ); int GetBodygroup( int iGroup ); + void SetSkin( int iSkin ); + void SetBody( int iBody ); + const char *GetBodygroupName( int iGroup ); int FindBodygroupByName( const char *name ); int GetBodygroupCount( int iGroup ); int GetNumBodyGroups( void ); - class CBoneCache *GetBoneCache( CStudioHdr *pStudioHdr ); void SetHitboxSet( int setnum ); void SetHitboxSetByName( const char *setname ); int GetHitboxSet( void ); char const *GetHitboxSetName( void ); int GetHitboxSetCount( void ); void DrawClientHitboxes( float duration = 0.0f, bool monocolor = false ); + void DrawSkeleton( CStudioHdr const* pHdr, int iBoneMask ) const; C_BaseAnimating* FindFollowedEntity(); @@ -385,8 +378,9 @@ class C_BaseAnimating : public C_BaseEntity, private IModelLoadCallback void GetCachedBoneMatrix( int boneIndex, matrix3x4_t &out ); // Wrappers for CBoneAccessor. - const matrix3x4_t& GetBone( int iBone ) const; - matrix3x4_t& GetBoneForWrite( int iBone ); + const matrix3x4a_t& GetBone( int iBone ) const; + matrix3x4a_t& GetBoneForWrite( int iBone ); + matrix3x4a_t* GetBoneArrayForWrite(); // Used for debugging. Will produce asserts if someone tries to setup bones or // attachments before it's allowed. @@ -400,8 +394,11 @@ class C_BaseAnimating : public C_BaseEntity, private IModelLoadCallback static void PushAllowBoneAccess( bool bAllowForNormalModels, bool bAllowForViewModels, char const *tagPush ); static void PopBoneAccess( char const *tagPop ); static void ThreadedBoneSetup(); + static bool InThreadedBoneSetup(); static void InitBoneSetupThreadPool(); static void ShutdownBoneSetupThreadPool(); + void MarkForThreadedBoneSetup(); + static void SetupBonesOnBaseAnimating( C_BaseAnimating *&pBaseAnimating ); // Invalidate bone caches so all SetupBones() calls force bone transforms to be regenerated. static void InvalidateBoneCaches(); @@ -424,11 +421,12 @@ class C_BaseAnimating : public C_BaseEntity, private IModelLoadCallback void InitModelEffects( void ); // Sometimes the server wants to update the client's cycle to get the two to run in sync (for proper hit detection) - virtual void SetServerIntendedCycle( float intended ) { (void)intended; } + virtual void SetServerIntendedCycle( float intended ) { intended; } virtual float GetServerIntendedCycle( void ) { return -1.0f; } // For prediction int SelectWeightedSequence ( int activity ); + int SelectWeightedSequenceFromModifiers( Activity activity, CUtlSymbol *pActivityModifiers, int iModifierCount ); void ResetSequenceInfo( void ); float SequenceDuration( void ); float SequenceDuration( CStudioHdr *pStudioHdr, int iSequence ); @@ -443,15 +441,23 @@ class C_BaseAnimating : public C_BaseEntity, private IModelLoadCallback void SetReceivedSequence( void ); virtual bool ShouldResetSequenceOnNewModel( void ); + // View models say yes to this. virtual bool IsViewModel() const; + // viewmodel or viewmodelattachmentmodel or lowerbody + virtual bool IsViewModelOrAttachment() const; + + void EnableJiggleBones( void ); + void DisableJiggleBones( void ); + + void ScriptSetPoseParameter( const char *szName, float fValue ); + protected: // View models scale their attachment positions to account for FOV. To get the unmodified // attachment position (like if you're rendering something else during the view model's DrawModel call), // use TransformViewModelAttachmentToWorld. virtual void FormatViewModelAttachment( int nAttachment, matrix3x4_t &attachmentToWorld ) {} - // View models say yes to this. bool IsBoneAccessAllowed() const; CMouthInfo& MouthInfo(); @@ -463,6 +469,12 @@ class C_BaseAnimating : public C_BaseEntity, private IModelLoadCallback virtual bool CalcAttachments(); + virtual bool ComputeStencilState( ShaderStencilState_t *pStencilState ); + + virtual bool WantsInterpolatedVars() { return true; } + + virtual void ResetSequenceLooping() { m_bSequenceFinished = false; } + private: // This method should return true if the bones have changed + SetupBones needs to be called virtual float LastBoneChangedTime() { return FLT_MAX; } @@ -473,32 +485,58 @@ class C_BaseAnimating : public C_BaseEntity, private IModelLoadCallback void TermRopes(); void DelayedInitModelEffects( void ); + void ParseModelEffects( KeyValues *modelKeyValues ); void UpdateRelevantInterpolatedVars(); void AddBaseAnimatingInterpolatedVars(); void RemoveBaseAnimatingInterpolatedVars(); -public: - CRagdoll *m_pRagdoll; - // Texture group to use - int m_nSkin; + void LockStudioHdr(); + void UnlockStudioHdr(); - // Object bodygroup - int m_nBody; +public: + CRagdoll *m_pRagdoll; + CBaseAnimating *m_pClientsideRagdoll; // Hitbox set to use (default 0) int m_nHitboxSet; CSequenceTransitioner m_SequenceTransitioner; +private: + +// BEGIN PREDICTION DATA COMPACTION (these fields are together to allow for faster copying in prediction system) +// FTYPEDESC_INSENDTABLE STUFF + int m_nPrevSequence; +protected: + + //float m_flCycle; + // This needs to be ranged checked because some interpolation edge cases + // can assign it to values far out of range. Interpolation vars will only + // clamp range checked vars. + CRangeCheckedVar m_flCycle; + float m_flPlaybackRate;// Animation playback framerate + +// FTYPEDESC_INSENDTABLE STUFF (end) + int m_nSkin;// Texture group to use + int m_nBody;// Object bodygroup + int m_nNewSequenceParity; + int m_nResetEventsParity; + int m_nPrevNewSequenceParity; + int m_nPrevResetEventsParity; + + float m_flEncodedController[MAXSTUDIOBONECTRLS]; +private: + // This is compared against m_nOldMuzzleFlashParity to determine if the entity should muzzle flash. + unsigned char m_nMuzzleFlashParity; +// END PREDICTION DATA COMPACTION + protected: CIKContext *m_pIk; int m_iEyeAttachment; - // Animation playback framerate - float m_flPlaybackRate; // Decomposed ragdoll info bool m_bStoreRagdollInfo; @@ -510,6 +548,7 @@ class C_BaseAnimating : public C_BaseEntity, private IModelLoadCallback // bone transformation matrix unsigned long m_iMostRecentModelBoneCounter; unsigned long m_iMostRecentBoneSetupRequest; + C_BaseAnimating * m_pNextForThreadedBoneSetup; int m_iPrevBoneMask; int m_iAccumulatedBoneMask; @@ -521,38 +560,26 @@ class C_BaseAnimating : public C_BaseEntity, private IModelLoadCallback // Client-side animation bool m_bClientSideFrameReset; - // Bone attachments. Used for attaching one BaseAnimating to another's bones. - // Client side only. - CUtlVector > m_BoneAttachments; - int m_boneIndexAttached; - Vector m_bonePosition; - QAngle m_boneAngles; - CHandle m_pAttachedTo; - protected: - float m_fadeMinDist; - float m_fadeMaxDist; - float m_flFadeScale; + float m_flFrozen; -private: + // Can we use the fast rendering path? + bool m_bCanUseFastPath; +private: float m_flGroundSpeed; // computed linear movement rate for current sequence float m_flLastEventCheck; // cycle index of when events were last checked bool m_bSequenceFinished;// flag set when StudioAdvanceFrame moves across a frame boundry bool m_bSequenceLoops; // true if the sequence loops + bool m_bIsUsingRelativeLighting; + // Mouth lipsync/envelope following values CMouthInfo m_mouth; CNetworkVar( float, m_flModelScale ); - - // Animation blending factors - float m_flPoseParameter[MAXSTUDIOPOSEPARAM]; - CInterpolatedVarArray< float, MAXSTUDIOPOSEPARAM > m_iv_flPoseParameter; - float m_flOldPoseParameters[MAXSTUDIOPOSEPARAM]; - - int m_nPrevSequence; + int m_nRestoreSequence; // Ropes that got spawned when the model was created. @@ -562,7 +589,11 @@ class C_BaseAnimating : public C_BaseEntity, private IModelLoadCallback float m_flPrevEventCycle; int m_nEventSequence; - float m_flEncodedController[MAXSTUDIOBONECTRLS]; + // Animation blending factors + float m_flPoseParameter[MAXSTUDIOPOSEPARAM]; + CInterpolatedVarArray< float, MAXSTUDIOPOSEPARAM > m_iv_flPoseParameter; + float m_flOldPoseParameters[MAXSTUDIOPOSEPARAM]; + CInterpolatedVarArray< float, MAXSTUDIOBONECTRLS > m_iv_flEncodedController; float m_flOldEncodedController[MAXSTUDIOBONECTRLS]; @@ -570,37 +601,40 @@ class C_BaseAnimating : public C_BaseEntity, private IModelLoadCallback bool m_bClientSideAnimation; bool m_bLastClientSideFrameReset; - int m_nNewSequenceParity; - int m_nResetEventsParity; - - int m_nPrevNewSequenceParity; - int m_nPrevResetEventsParity; - - bool m_builtRagdoll; Vector m_vecPreRagdollMins; Vector m_vecPreRagdollMaxs; + bool m_builtRagdoll; + bool m_bReceivedSequence; + bool m_bIsStaticProp; // Current animation sequence int m_nSequence; - bool m_bReceivedSequence; // Current cycle location from server protected: - float m_flCycle; - CInterpolatedVar< float > m_iv_flCycle; + CInterpolatedVar< CRangeCheckedVar > m_iv_flCycle; + //CInterpolatedVar< float > m_iv_flCycle; float m_flOldCycle; - bool m_bNoModelParticles; + float m_prevClientCycle; + float m_prevClientAnimTime; + + // True if bone setup should latch bones for demo polish subsystem + bool m_bBonePolishSetup; + + CBoneMergeCache *m_pBoneMergeCache; // This caches the strcmp lookups that it has to do + // when merg private: + int m_nPrevBody; + int m_nPrevSkin; + float m_flOldModelScale; int m_nOldSequence; - CBoneMergeCache *m_pBoneMergeCache; // This caches the strcmp lookups that it has to do - // when merg - CUtlVector< matrix3x4_t > m_CachedBoneData; // never access this directly. Use m_BoneAccessor. - memhandle_t m_hitboxBoneCacheHandle; + CUtlVector< matrix3x4a_t, CUtlMemoryAligned > m_CachedBoneData; // never access this directly. Use m_BoneAccessor. float m_flLastBoneSetupTime; CJiggleBones *m_pJiggleBones; + bool m_isJiggleBonesEnabled; // Calculated attachment points CUtlVector m_Attachments; @@ -608,31 +642,21 @@ class C_BaseAnimating : public C_BaseEntity, private IModelLoadCallback void SetupBones_AttachmentHelper( CStudioHdr *pStudioHdr ); EHANDLE m_hLightingOrigin; - EHANDLE m_hLightingOriginRelative; - // These are compared against each other to determine if the entity should muzzle flash. - CNetworkVar( unsigned char, m_nMuzzleFlashParity ); - unsigned char m_nOldMuzzleFlashParity; + unsigned char m_nOldMuzzleFlashParity; bool m_bInitModelEffects; - // Dynamic models - bool m_bDynamicModelAllowed; - bool m_bDynamicModelPending; - bool m_bResetSequenceInfoOnLoad; - CRefCountedModelIndex m_AutoRefModelIndex; -public: - void EnableDynamicModels() { m_bDynamicModelAllowed = true; } - bool IsDynamicModelLoading() const { return m_bDynamicModelPending; } -private: - virtual void OnModelLoadComplete( const model_t* pModel ); + static bool m_bBoneListInUse; + static CBoneList m_recordingBoneList; private: - void LockStudioHdr(); - void UnlockStudioHdr(); mutable CStudioHdr *m_pStudioHdr; mutable MDLHandle_t m_hStudioHdr; CThreadFastMutex m_StudioHdrInitLock; + + CUtlReference m_ejectBrassEffect; + int m_iEjectBrassAttachment; }; enum @@ -646,18 +670,21 @@ enum class C_ClientRagdoll : public C_BaseAnimating, public IPVSNotify { - public: - C_ClientRagdoll( bool bRestoring = true ); + C_ClientRagdoll( bool bRestoring = true , bool fullInit = true); +public: DECLARE_CLASS( C_ClientRagdoll, C_BaseAnimating ); DECLARE_DATADESC(); + // inherited from IClientUnknown + virtual IClientModelRenderable* GetClientModelRenderable(); + // inherited from IPVSNotify virtual void OnPVSStatusChanged( bool bInPVS ); virtual void Release( void ); virtual void SetupWeights( const matrix3x4_t *pBoneToWorld, int nFlexWeightCount, float *pFlexWeights, float *pFlexDelayedWeights ); - virtual void ImpactTrace( trace_t *pTrace, int iDamageType, const char *pCustomImpactName ); + virtual void ImpactTrace( trace_t *pTrace, int iDamageType, char *pCustomImpactName ); void ClientThink( void ); void ReleaseRagdoll( void ) { m_bReleaseRagdoll = true; } bool ShouldSavePhysics( void ) { return true; } @@ -672,10 +699,18 @@ class C_ClientRagdoll : public C_BaseAnimating, public IPVSNotify void FadeOut( void ); virtual float LastBoneChangedTime(); + inline bool IsFadingOut() { return m_bFadingOut; } + bool m_bFadeOut; bool m_bImportant; float m_flEffectTime; + // returns true if we are of type C_ClientRagdoll + virtual bool IsClientRagdoll() const { return true; } + +protected: + bool m_bReleaseRagdoll; + private: int m_iCurrentFriction; int m_iMinFriction; @@ -684,7 +719,6 @@ class C_ClientRagdoll : public C_BaseAnimating, public IPVSNotify float m_flFrictionTime; int m_iFrictionAnimState; - bool m_bReleaseRagdoll; bool m_bFadingOut; @@ -702,9 +736,9 @@ inline void C_BaseAnimating::ResetSequence(int nSequence) ResetSequenceInfo(); } -inline float C_BaseAnimating::GetPlaybackRate() +inline float C_BaseAnimating::GetPlaybackRate() const { - return m_flPlaybackRate; + return m_flPlaybackRate * clamp( 1.0f - m_flFrozen, 0.0f, 1.0f ); } inline void C_BaseAnimating::SetPlaybackRate( float rate ) @@ -712,16 +746,20 @@ inline void C_BaseAnimating::SetPlaybackRate( float rate ) m_flPlaybackRate = rate; } -inline const matrix3x4_t& C_BaseAnimating::GetBone( int iBone ) const +inline const matrix3x4a_t& C_BaseAnimating::GetBone( int iBone ) const { return m_BoneAccessor.GetBone( iBone ); } -inline matrix3x4_t& C_BaseAnimating::GetBoneForWrite( int iBone ) +inline matrix3x4a_t& C_BaseAnimating::GetBoneForWrite( int iBone ) { return m_BoneAccessor.GetBoneForWrite( iBone ); } +inline matrix3x4a_t* C_BaseAnimating::GetBoneArrayForWrite() +{ + return m_BoneAccessor.GetBoneArrayForWrite(); +} inline bool C_BaseAnimating::ShouldMuzzleFlash() const { @@ -739,28 +777,27 @@ inline float C_BaseAnimating::GetCycle() const inline CStudioHdr *C_BaseAnimating::GetModelPtr() const { - if ( IsDynamicModelLoading() ) - return NULL; - #ifdef _DEBUG - // GetModelPtr() is often called before OnNewModel() so go ahead and set it up first chance. -// static IDataCacheSection *pModelCache = datacache->FindSection( "ModelData" ); -// AssertOnce( pModelCache->IsFrameLocking() ); +#ifndef _X360 + // 360's don't need to lock the modeldata cache since it never flushes + static IDataCacheSection *pModelCache = g_pDataCache->FindSection( "ModelData" ); + AssertOnce( pModelCache->IsFrameLocking() ); +#endif #endif - if ( !m_pStudioHdr ) + // GetModelPtr() is often called before OnNewModel() so go ahead and set it up first chance. + if ( !m_pStudioHdr && GetModel() ) { const_cast(this)->LockStudioHdr(); } - Assert( m_pStudioHdr ? m_pStudioHdr->GetRenderHdr() == mdlcache->GetStudioHdr(m_hStudioHdr) : m_hStudioHdr == MDLHANDLE_INVALID ); - return m_pStudioHdr; + return ( m_pStudioHdr && m_pStudioHdr->IsValid() ) ? m_pStudioHdr : NULL; } inline void C_BaseAnimating::InvalidateMdlCache() { - if ( m_pStudioHdr ) + UnlockStudioHdr(); + if ( m_pStudioHdr != NULL ) { - UnlockStudioHdr(); delete m_pStudioHdr; m_pStudioHdr = NULL; } @@ -773,11 +810,6 @@ inline bool C_BaseAnimating::IsModelScaleFractional() const /// very fast way return *((const int *) &m_flModelScale) < 0x3f800000; } -inline bool C_BaseAnimating::IsModelScaled() const -{ - return ( m_flModelScale > 1.0f+FLT_EPSILON || m_flModelScale < 1.0f-FLT_EPSILON ); -} - //----------------------------------------------------------------------------- // Sequence access //----------------------------------------------------------------------------- @@ -813,6 +845,6 @@ void SetColumn( Vector &src, int column, matrix3x4_t& dest ); EXTERN_RECV_TABLE(DT_BaseAnimating); -extern void DevMsgRT( PRINTF_FORMAT_STRING char const* pMsg, ... ); +extern void DevMsgRT( char const* pMsg, ... ); #endif // C_BASEANIMATING_H diff --git a/game/client/c_baseanimatingoverlay.cpp b/game/client/c_baseanimatingoverlay.cpp index d9aa8fb2e..53282adaa 100644 --- a/game/client/c_baseanimatingoverlay.cpp +++ b/game/client/c_baseanimatingoverlay.cpp @@ -1,17 +1,19 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // // $NoKeywords: $ -//=============================================================================// +//===========================================================================// #include "cbase.h" #include "c_baseanimatingoverlay.h" +#include "animation.h" #include "bone_setup.h" #include "tier0/vprof.h" -#include "engine/ivdebugoverlay.h" +#include "engine/IVDebugOverlay.h" #include "datacache/imdlcache.h" #include "eventlist.h" +#include "toolframework_client.h" #include "dt_utlvector_recv.h" @@ -20,14 +22,96 @@ extern ConVar r_sequence_debug; +template class CInterpolatedVar; + + +mstudioevent_for_client_server_t *GetEventIndexForSequence( mstudioseqdesc_t &seqdesc ); + + +void C_AnimationLayer::SetOwner( C_BaseAnimatingOverlay *pOverlay ) +{ + m_pOwner = pOverlay; +} + +C_BaseAnimatingOverlay *C_AnimationLayer::GetOwner() const +{ + return m_pOwner; +} + +void C_AnimationLayer::Reset() +{ + if ( m_pOwner ) + { + int nFlags = 0; + if ( m_nSequence != 0 || m_flWeight != 0.0f ) + { + nFlags |= BOUNDS_CHANGED; + } + if ( m_flCycle != 0.0f ) + { + nFlags |= ANIMATION_CHANGED; + } + if ( nFlags ) + { + m_pOwner->InvalidatePhysicsRecursive( nFlags ); + } + } + + m_nSequence = 0; + m_flPrevCycle = 0; + m_flWeight = 0; + m_flPlaybackRate = 0; + m_flCycle = 0; + m_flLayerAnimtime = 0; + m_flLayerFadeOuttime = 0; +} + +void C_AnimationLayer::SetSequence( int nSequence ) +{ + if ( m_pOwner && m_nSequence != nSequence ) + { + m_pOwner->InvalidatePhysicsRecursive( BOUNDS_CHANGED ); + } + m_nSequence = nSequence; +} + +void C_AnimationLayer::SetCycle( float flCycle ) +{ + if ( m_pOwner && m_flCycle != flCycle ) + { + m_pOwner->InvalidatePhysicsRecursive( ANIMATION_CHANGED ); + } + m_flCycle = flCycle; +} + +void C_AnimationLayer::SetOrder( int order ) +{ + if ( m_pOwner && ( m_nOrder != order ) ) + { + if ( m_nOrder == C_BaseAnimatingOverlay::MAX_OVERLAYS || order == C_BaseAnimatingOverlay::MAX_OVERLAYS ) + { + m_pOwner->InvalidatePhysicsRecursive( BOUNDS_CHANGED ); + } + } + m_nOrder = order; +} + + +void C_AnimationLayer::SetWeight( float flWeight ) +{ + if ( m_pOwner && m_flWeight != flWeight ) + { + if ( m_flWeight == 0.0f || flWeight == 0.0f ) + { + m_pOwner->InvalidatePhysicsRecursive( BOUNDS_CHANGED ); + } + } + m_flWeight = flWeight; +} + C_BaseAnimatingOverlay::C_BaseAnimatingOverlay() { - // FIXME: where does this initialization go now? - //for ( int i=0; i < MAX_OVERLAYS; i++ ) - //{ - // memset( &m_Layer[i], 0, sizeof(m_Layer[0]) ); - // m_Layer[i].m_nOrder = MAX_OVERLAYS; - //} + // NOTE: We zero the memory in the max capacity m_Layer vector in dt_ultvector_common.h // FIXME: where does this initialization go now? // AddVar( m_Layer, &m_iv_AnimOverlay, LATCH_ANIMATION_VAR ); @@ -36,13 +120,36 @@ C_BaseAnimatingOverlay::C_BaseAnimatingOverlay() #undef CBaseAnimatingOverlay +void RecvProxy_SequenceChanged( const CRecvProxyData *pData, void *pStruct, void *pOut ) +{ + CAnimationLayer *pLayer = (CAnimationLayer *)pStruct; + pLayer->SetSequence( pData->m_Value.m_Int ); +} + +void RecvProxy_WeightChanged( const CRecvProxyData *pData, void *pStruct, void *pOut ) +{ + CAnimationLayer *pLayer = (CAnimationLayer *)pStruct; + pLayer->SetWeight( pData->m_Value.m_Float ); +} + +void RecvProxy_CycleChanged( const CRecvProxyData *pData, void *pStruct, void *pOut ) +{ + CAnimationLayer *pLayer = (CAnimationLayer *)pStruct; + pLayer->SetCycle( pData->m_Value.m_Float ); +} + +void RecvProxy_OrderChanged( const CRecvProxyData *pData, void *pStruct, void *pOut ) +{ + CAnimationLayer *pLayer = (CAnimationLayer *)pStruct; + pLayer->SetOrder( pData->m_Value.m_Int ); +} BEGIN_RECV_TABLE_NOBASE(CAnimationLayer, DT_Animationlayer) - RecvPropInt( RECVINFO_NAME(m_nSequence, m_nSequence)), - RecvPropFloat( RECVINFO_NAME(m_flCycle, m_flCycle)), + RecvPropInt( RECVINFO_NAME(m_nSequence, m_nSequence), 0, RecvProxy_SequenceChanged ), + RecvPropFloat( RECVINFO_NAME(m_flCycle, m_flCycle), 0, RecvProxy_CycleChanged ), RecvPropFloat( RECVINFO_NAME(m_flPrevCycle, m_flPrevCycle)), - RecvPropFloat( RECVINFO_NAME(m_flWeight, m_flWeight)), - RecvPropInt( RECVINFO_NAME(m_nOrder, m_nOrder)) + RecvPropFloat( RECVINFO_NAME(m_flWeight, m_flWeight), 0, RecvProxy_WeightChanged ), + RecvPropInt( RECVINFO_NAME(m_nOrder, m_nOrder), 0, RecvProxy_OrderChanged ) END_RECV_TABLE() const char *s_m_iv_AnimOverlayNames[C_BaseAnimatingOverlay::MAX_OVERLAYS] = @@ -67,47 +174,60 @@ const char *s_m_iv_AnimOverlayNames[C_BaseAnimatingOverlay::MAX_OVERLAYS] = void ResizeAnimationLayerCallback( void *pStruct, int offsetToUtlVector, int len ) { C_BaseAnimatingOverlay *pEnt = (C_BaseAnimatingOverlay*)pStruct; - CUtlVector < C_AnimationLayer > *pVec = &pEnt->m_AnimOverlay; - CUtlVector< CInterpolatedVar< C_AnimationLayer > > *pVecIV = &pEnt->m_iv_AnimOverlay; + CUtlVector < CAnimationLayer > *pVec = &pEnt->m_AnimOverlay; + CUtlVector< CInterpolatedVar< CAnimationLayer > > *pVecIV = &pEnt->m_iv_AnimOverlay; Assert( (char*)pVec - (char*)pEnt == offsetToUtlVector ); Assert( pVec->Count() == pVecIV->Count() ); Assert( pVec->Count() <= C_BaseAnimatingOverlay::MAX_OVERLAYS ); int diff = len - pVec->Count(); + if ( diff != 0 ) + { + // remove all entries + for ( int i=0; i < pVec->Count(); i++ ) + { + pEnt->RemoveVar( &pVec->Element( i ) ); + } - - - if ( diff == 0 ) - return; + pEnt->InvalidatePhysicsRecursive( BOUNDS_CHANGED ); - // remove all entries - for ( int i=0; i < pVec->Count(); i++ ) - { - pEnt->RemoveVar( &pVec->Element( i ) ); - } + // adjust vector sizes + if ( diff > 0 ) + { + for ( int i = 0; i < diff; ++i ) + { + int j = pVec->AddToTail( ); + (*pVec)[j].SetOwner( pEnt ); + } + pVecIV->AddMultipleToTail( diff ); + } + else + { + pVec->RemoveMultiple( len, -diff ); + pVecIV->RemoveMultiple( len, -diff ); + } - // adjust vector sizes - if ( diff > 0 ) - { - pVec->AddMultipleToTail( diff ); - pVecIV->AddMultipleToTail( diff ); - } - else - { - pVec->RemoveMultiple( len, -diff ); - pVecIV->RemoveMultiple( len, -diff ); + // Rebind all the variables in the ent's list. + for ( int i=0; i < len; i++ ) + { + IInterpolatedVar *pWatcher = &pVecIV->Element( i ); + pWatcher->SetDebugName( s_m_iv_AnimOverlayNames[i] ); + pEnt->AddVar( &pVec->Element( i ), pWatcher, LATCH_ANIMATION_VAR, true ); + } } - // Rebind all the variables in the ent's list. - for ( int i=0; i < len; i++ ) - { - IInterpolatedVar *pWatcher = &pVecIV->Element( i ); - pWatcher->SetDebugName( s_m_iv_AnimOverlayNames[i] ); - pEnt->AddVar( &pVec->Element( i ), pWatcher, LATCH_ANIMATION_VAR, true ); - } // FIXME: need to set historical values of nOrder in pVecIV to MAX_OVERLAY - + + // Ensure capacity + pVec->EnsureCapacity( len ); + + int nNumAllocated = pVec->NumAllocated(); + + // This is important to do because EnsureCapacity doesn't actually call the constructors + // on the elements, but we need them to be initialized, otherwise it'll have out-of-range + // values which will piss off the datatable encoder. + UtlVector_InitializeAllocatedElements( pVec->Base() + pVec->Count(), nNumAllocated - pVec->Count() ); } @@ -146,7 +266,7 @@ BEGIN_PREDICTION_DATA( C_BaseAnimatingOverlay ) END_PREDICTION_DATA() -C_AnimationLayer* C_BaseAnimatingOverlay::GetAnimOverlay( int i ) +CAnimationLayer* C_BaseAnimatingOverlay::GetAnimOverlay( int i ) { Assert( i >= 0 && i < MAX_OVERLAYS ); return &m_AnimOverlay[i]; @@ -157,12 +277,28 @@ void C_BaseAnimatingOverlay::SetNumAnimOverlays( int num ) { if ( m_AnimOverlay.Count() < num ) { - m_AnimOverlay.AddMultipleToTail( num - m_AnimOverlay.Count() ); + int nCountToAdd = num - m_AnimOverlay.Count(); + for ( int i = 0; i < nCountToAdd; ++i ) + { + int j = m_AnimOverlay.AddToTail( ); + m_AnimOverlay[j].SetOwner( this ); + } } else if ( m_AnimOverlay.Count() > num ) { m_AnimOverlay.RemoveMultiple( num, m_AnimOverlay.Count() - num ); + InvalidatePhysicsRecursive( BOUNDS_CHANGED ); } + + // Ensure capacity + m_AnimOverlay.EnsureCapacity( C_BaseAnimatingOverlay::MAX_OVERLAYS ); + + int nNumAllocated = m_AnimOverlay.NumAllocated(); + + // This is important to do because EnsureCapacity doesn't actually call the constructors + // on the elements, but we need them to be initialized, otherwise it'll have out-of-range + // values which will piss off the datatable encoder. + UtlVector_InitializeAllocatedElements( m_AnimOverlay.Base() + m_AnimOverlay.Count(), nNumAllocated - m_AnimOverlay.Count() ); } @@ -171,44 +307,46 @@ int C_BaseAnimatingOverlay::GetNumAnimOverlays() const return m_AnimOverlay.Count(); } - void C_BaseAnimatingOverlay::GetRenderBounds( Vector& theMins, Vector& theMaxs ) { BaseClass::GetRenderBounds( theMins, theMaxs ); - if ( !IsRagdoll() ) - { - CStudioHdr *pStudioHdr = GetModelPtr(); - if ( !pStudioHdr || !pStudioHdr->SequencesAvailable() ) - return; + if ( IsRagdoll() ) + return; - int nSequences = pStudioHdr->GetNumSeq(); + CStudioHdr *pStudioHdr = GetModelPtr(); + if ( !pStudioHdr || !pStudioHdr->SequencesAvailable() ) + return; - int i; - for (i = 0; i < m_AnimOverlay.Count(); i++) + int nSequences = pStudioHdr->GetNumSeq(); + + int i; + for (i = 0; i < m_AnimOverlay.Count(); i++) + { + if ( m_AnimOverlay[i].m_flWeight > 0.0 && m_AnimOverlay[i].m_nOrder != MAX_OVERLAYS ) { - if (m_AnimOverlay[i].m_flWeight > 0.0) - { - if ( m_AnimOverlay[i].m_nSequence >= nSequences ) - { - continue; - } + if ( m_AnimOverlay[i].m_nSequence >= nSequences ) + continue; - mstudioseqdesc_t &seqdesc = pStudioHdr->pSeqdesc( m_AnimOverlay[i].m_nSequence ); - VectorMin( seqdesc.bbmin, theMins, theMins ); - VectorMax( seqdesc.bbmax, theMaxs, theMaxs ); - } + mstudioseqdesc_t &seqdesc = pStudioHdr->pSeqdesc( m_AnimOverlay[i].m_nSequence ); + VectorMin( seqdesc.bbmin, theMins, theMins ); + VectorMax( seqdesc.bbmax, theMaxs, theMaxs ); } } } +bool C_BaseAnimatingOverlay::Interpolate( float flCurrentTime ) +{ + bool bOk = BaseClass::Interpolate( flCurrentTime ); + CheckForLayerPhysicsInvalidate(); + + return bOk; +} void C_BaseAnimatingOverlay::CheckForLayerChanges( CStudioHdr *hdr, float currentTime ) { CDisableRangeChecks disableRangeChecks; - - bool bLayersChanged = false; // FIXME: damn, there has to be a better way than this. int i; @@ -221,78 +359,69 @@ void C_BaseAnimatingOverlay::CheckForLayerChanges( CStudioHdr *hdr, float curren // fake up previous cycle values. float t0; - C_AnimationLayer *pHead = m_iv_AnimOverlay[i].GetHistoryValue( iHead, t0 ); + CAnimationLayer *pHead = m_iv_AnimOverlay[i].GetHistoryValue( iHead, t0 ); // reset previous float t1; - C_AnimationLayer *pPrev1 = m_iv_AnimOverlay[i].GetHistoryValue( iPrev1, t1 ); + CAnimationLayer *pPrev1 = m_iv_AnimOverlay[i].GetHistoryValue( iPrev1, t1 ); // reset previous previous float t2; - C_AnimationLayer *pPrev2 = m_iv_AnimOverlay[i].GetHistoryValue( iPrev2, t2 ); + CAnimationLayer *pPrev2 = m_iv_AnimOverlay[i].GetHistoryValue( iPrev2, t2 ); + + if ( !pHead || !pPrev1 || pHead->m_nSequence == pPrev1->m_nSequence ) + continue; - if ( pHead && pPrev1 && pHead->m_nSequence != pPrev1->m_nSequence ) +#if 1 // _DEBUG + if (r_sequence_debug.GetInt() == entindex()) { - bLayersChanged = true; - #if 1 // _DEBUG - if (/* Q_stristr( hdr->pszName(), r_sequence_debug.GetString()) != NULL || */ r_sequence_debug.GetInt() == entindex()) - { - DevMsgRT( "(%7.4f : %30s : %5.3f : %4.2f : %1d)\n", t0, hdr->pSeqdesc( pHead->m_nSequence ).pszLabel(), (float)pHead->m_flCycle, (float)pHead->m_flWeight, i ); - DevMsgRT( "(%7.4f : %30s : %5.3f : %4.2f : %1d)\n", t1, hdr->pSeqdesc( pPrev1->m_nSequence ).pszLabel(), (float)pPrev1->m_flCycle, (float)pPrev1->m_flWeight, i ); - if (pPrev2) - DevMsgRT( "(%7.4f : %30s : %5.3f : %4.2f : %1d)\n", t2, hdr->pSeqdesc( pPrev2->m_nSequence ).pszLabel(), (float)pPrev2->m_flCycle, (float)pPrev2->m_flWeight, i ); - } - #endif + DevMsgRT( "(%7.4f : %30s : %5.3f : %4.2f : %1d)\n", t0, hdr->pSeqdesc( pHead->m_nSequence ).pszLabel(), (float)pHead->m_flCycle, (float)pHead->m_flWeight, i ); + DevMsgRT( "(%7.4f : %30s : %5.3f : %4.2f : %1d)\n", t1, hdr->pSeqdesc( pPrev1->m_nSequence ).pszLabel(), (float)pPrev1->m_flCycle, (float)pPrev1->m_flWeight, i ); + if (pPrev2) + DevMsgRT( "(%7.4f : %30s : %5.3f : %4.2f : %1d)\n", t2, hdr->pSeqdesc( pPrev2->m_nSequence ).pszLabel(), (float)pPrev2->m_flCycle, (float)pPrev2->m_flWeight, i ); + } +#endif - if (pPrev1) - { - pPrev1->m_nSequence = pHead->m_nSequence; - pPrev1->m_flCycle = pHead->m_flPrevCycle; - pPrev1->m_flWeight = pHead->m_flWeight; - } + pPrev1->m_nSequence = pHead->m_nSequence; + pPrev1->m_flCycle = pHead->m_flPrevCycle; + pPrev1->m_flWeight = pHead->m_flWeight; - if (pPrev2) - { - float num = 0; - if ( fabs( t0 - t1 ) > 0.001f ) - num = (t2 - t1) / (t0 - t1); + if (pPrev2) + { + float num = 0; + if ( fabs( t0 - t1 ) > 0.001f ) + num = (t2 - t1) / (t0 - t1); - pPrev2->m_nSequence = pHead->m_nSequence; - float flTemp; - if (IsSequenceLooping( hdr, pHead->m_nSequence )) - { - flTemp = LoopingLerp( num, (float)pHead->m_flPrevCycle, (float)pHead->m_flCycle ); - } - else - { - flTemp = Lerp( num, (float)pHead->m_flPrevCycle, (float)pHead->m_flCycle ); - } - pPrev2->m_flCycle = flTemp; - pPrev2->m_flWeight = pHead->m_flWeight; + pPrev2->m_nSequence = pHead->m_nSequence; + float flTemp; + if (IsSequenceLooping( hdr, pHead->m_nSequence )) + { + flTemp = LoopingLerp( num, (float)pHead->m_flPrevCycle, (float)pHead->m_flCycle ); } - - /* - if (stricmp( r_seq_overlay_debug.GetString(), hdr->name ) == 0) + else { - DevMsgRT( "(%30s %6.2f : %6.2f : %6.2f)\n", hdr->pSeqdesc( pHead->nSequence ).pszLabel(), (float)pPrev2->m_flCycle, (float)pPrev1->m_flCycle, (float)pHead->m_flCycle ); + flTemp = Lerp( num, (float)pHead->m_flPrevCycle, (float)pHead->m_flCycle ); } - */ - - m_iv_AnimOverlay[i].SetLooping( IsSequenceLooping( hdr, pHead->m_nSequence ) ); - m_iv_AnimOverlay[i].Interpolate( currentTime ); + pPrev2->m_flCycle = flTemp; + pPrev2->m_flWeight = pHead->m_flWeight; + } - // reset event indexes - m_flOverlayPrevEventCycle[i] = pHead->m_flPrevCycle - 0.01; + /* + if (stricmp( r_seq_overlay_debug.GetString(), hdr->name ) == 0) + { + DevMsgRT( "(%30s %6.2f : %6.2f : %6.2f)\n", hdr->pSeqdesc( pHead->nSequence ).pszLabel(), (float)pPrev2->m_flCycle, (float)pPrev1->m_flCycle, (float)pHead->m_flCycle ); } - } + */ - if (bLayersChanged) - { - // render bounds may have changed - UpdateVisibility(); + m_iv_AnimOverlay[i].SetLooping( IsSequenceLooping( hdr, pHead->m_nSequence ) ); + m_iv_AnimOverlay[i].Interpolate( currentTime ); + + // reset event indexes + m_flOverlayPrevEventCycle[i] = pHead->m_flPrevCycle - 0.01; } } +//#define DEBUG_TF2_OVERLAYS void C_BaseAnimatingOverlay::AccumulateLayers( IBoneSetup &boneSetup, Vector pos[], Quaternion q[], float currentTime ) { BaseClass::AccumulateLayers( boneSetup, pos, q, currentTime ); @@ -304,6 +433,7 @@ void C_BaseAnimatingOverlay::AccumulateLayers( IBoneSetup &boneSetup, Vector pos { layer[i] = MAX_OVERLAYS; } + for (i = 0; i < m_AnimOverlay.Count(); i++) { if (m_AnimOverlay[i].m_nOrder < MAX_OVERLAYS) @@ -313,9 +443,9 @@ void C_BaseAnimatingOverlay::AccumulateLayers( IBoneSetup &boneSetup, Vector pos layer[m_AnimOverlay[i].m_nOrder] = i; */ // hacky code until initialization of new layers is finished - if (layer[m_AnimOverlay[i].m_nOrder] != MAX_OVERLAYS) + if ( layer[m_AnimOverlay[i].m_nOrder] != MAX_OVERLAYS ) { - m_AnimOverlay[i].m_nOrder = MAX_OVERLAYS; + m_AnimOverlay[i].SetOrder( MAX_OVERLAYS ); } else { @@ -333,106 +463,101 @@ void C_BaseAnimatingOverlay::AccumulateLayers( IBoneSetup &boneSetup, Vector pos for (j = 0; j < MAX_OVERLAYS; j++) { i = layer[ j ]; - if (i < m_AnimOverlay.Count()) + if ( i >= m_AnimOverlay.Count() ) { - if ( m_AnimOverlay[i].m_nSequence >= nSequences ) - { - continue; - } - - /* - DevMsgRT( 1 , "%.3f %.3f %.3f\n", currentTime, fWeight, dadt ); - debugoverlay->AddTextOverlay( GetAbsOrigin() + Vector( 0, 0, 64 ), -j - 1, 0, - "%2d(%s) : %6.2f : %6.2f", - m_AnimOverlay[i].m_nSequence, - hdr->pSeqdesc( m_AnimOverlay[i].m_nSequence )->pszLabel(), - m_AnimOverlay[i].m_flCycle, - m_AnimOverlay[i].m_flWeight - ); - */ - - m_AnimOverlay[i].BlendWeight(); +#if defined( DEBUG_TF2_OVERLAYS ) + engine->Con_NPrintf( 10 + j, "%30s %6.2f : %6.2f : %1d", " ", 0.f, 0.f, i ); +#endif + continue; + } - float fWeight = m_AnimOverlay[i].m_flWeight; + if ( m_AnimOverlay[i].m_nSequence >= nSequences ) + continue; - if (fWeight > 0) - { - // check to see if the sequence changed - // FIXME: move this to somewhere more reasonable - // do a nice spline interpolation of the values - // if ( m_AnimOverlay[i].m_nSequence != m_iv_AnimOverlay.GetPrev( i )->nSequence ) - float fCycle = m_AnimOverlay[ i ].m_flCycle; + /* + DevMsgRT( 1 , "%.3f %.3f %.3f\n", currentTime, fWeight, dadt ); + debugoverlay->AddTextOverlay( GetAbsOrigin() + Vector( 0, 0, 64 ), -j - 1, 0, + "%2d(%s) : %6.2f : %6.2f", + m_AnimOverlay[i].m_nSequence, + boneSetup.GetStudioHdr()->pSeqdesc( m_AnimOverlay[i].m_nSequence )->pszLabel(), + m_AnimOverlay[i].m_flCycle, + m_AnimOverlay[i].m_flWeight + ); + */ + + float fWeight = m_AnimOverlay[i].m_flWeight; + if ( fWeight <= 0.0f ) + { +#if defined( DEBUG_TF2_OVERLAYS ) + engine->Con_NPrintf( 10 + j, "%30s %6.2f : %6.2f : %1d", " ", 0.f, 0.f, i ); +#endif + continue; + } - fCycle = ClampCycle( fCycle, IsSequenceLooping( m_AnimOverlay[i].m_nSequence ) ); + // check to see if the sequence changed + // FIXME: move this to somewhere more reasonable + // do a nice spline interpolation of the values + // if ( m_AnimOverlay[i].m_nSequence != m_iv_AnimOverlay.GetPrev( i )->nSequence ) + float fCycle = m_AnimOverlay[ i ].m_flCycle; + fCycle = ClampCycle( fCycle, IsSequenceLooping( m_AnimOverlay[i].m_nSequence ) ); - if (fWeight > 1) - fWeight = 1; + if (fWeight > 1.0f) + { + fWeight = 1.0f; + } - boneSetup.AccumulatePose( pos, q, m_AnimOverlay[i].m_nSequence, fCycle, fWeight, currentTime, m_pIk ); + boneSetup.AccumulatePose( pos, q, m_AnimOverlay[i].m_nSequence, fCycle, fWeight, currentTime, m_pIk ); -#if 1 // _DEBUG - if (/* Q_stristr( hdr->pszName(), r_sequence_debug.GetString()) != NULL || */ r_sequence_debug.GetInt() == entindex()) - { - if (1) - { - DevMsgRT( "%8.4f : %30s : %5.3f : %4.2f : %1d\n", currentTime, boneSetup.GetStudioHdr()->pSeqdesc( m_AnimOverlay[i].m_nSequence ).pszLabel(), fCycle, fWeight, i ); - } - else - { - int iHead, iPrev1, iPrev2; - m_iv_AnimOverlay[i].GetInterpolationInfo( currentTime, &iHead, &iPrev1, &iPrev2 ); - - // fake up previous cycle values. - float t0; - C_AnimationLayer *pHead = m_iv_AnimOverlay[i].GetHistoryValue( iHead, t0 ); - // reset previous - float t1; - C_AnimationLayer *pPrev1 = m_iv_AnimOverlay[i].GetHistoryValue( iPrev1, t1 ); - // reset previous previous - float t2; - C_AnimationLayer *pPrev2 = m_iv_AnimOverlay[i].GetHistoryValue( iPrev2, t2 ); - - if ( pHead && pPrev1 && pPrev2 ) - { - DevMsgRT( "%6.2f : %30s %6.2f (%6.2f:%6.2f:%6.2f) : %6.2f (%6.2f:%6.2f:%6.2f) : %1d\n", currentTime, boneSetup.GetStudioHdr()->pSeqdesc( m_AnimOverlay[i].m_nSequence ).pszLabel(), - fCycle, (float)pPrev2->m_flCycle, (float)pPrev1->m_flCycle, (float)pHead->m_flCycle, - fWeight, (float)pPrev2->m_flWeight, (float)pPrev1->m_flWeight, (float)pHead->m_flWeight, - i ); - } - else - { - DevMsgRT( "%6.2f : %30s %6.2f : %6.2f : %1d\n", currentTime, boneSetup.GetStudioHdr()->pSeqdesc( m_AnimOverlay[i].m_nSequence ).pszLabel(), fCycle, fWeight, i ); - } - - } - } +#if defined( DEBUG_TF2_OVERLAYS ) + engine->Con_NPrintf( 10 + j, "%30s %6.2f : %6.2f : %1d", boneSetup.GetStudioHdr()->pSeqdesc( m_AnimOverlay[i].m_nSequence ).pszLabel(), fCycle, fWeight, i ); #endif -//#define DEBUG_TF2_OVERLAYS -#if defined( DEBUG_TF2_OVERLAYS ) - engine->Con_NPrintf( 10 + j, "%30s %6.2f : %6.2f : %1d", boneSetup.GetStudioHdr()->pSeqdesc( m_AnimOverlay[i].m_nSequence ).pszLabel(), fCycle, fWeight, i ); +#if 1 // _DEBUG + if (r_sequence_debug.GetInt() == entindex()) + { + if (1) + { + DevMsgRT( "%8.4f : %30s : %5.3f : %4.2f : %1d\n", currentTime, boneSetup.GetStudioHdr()->pSeqdesc( m_AnimOverlay[i].m_nSequence ).pszLabel(), fCycle, fWeight, i ); } else { - engine->Con_NPrintf( 10 + j, "%30s %6.2f : %6.2f : %1d", " ", 0.f, 0.f, i ); -#endif + int iHead, iPrev1, iPrev2; + m_iv_AnimOverlay[i].GetInterpolationInfo( currentTime, &iHead, &iPrev1, &iPrev2 ); + + // fake up previous cycle values. + float t0; + CAnimationLayer *pHead = m_iv_AnimOverlay[i].GetHistoryValue( iHead, t0 ); + // reset previous + float t1; + CAnimationLayer *pPrev1 = m_iv_AnimOverlay[i].GetHistoryValue( iPrev1, t1 ); + // reset previous previous + float t2; + CAnimationLayer *pPrev2 = m_iv_AnimOverlay[i].GetHistoryValue( iPrev2, t2 ); + + if ( pHead && pPrev1 && pPrev2 ) + { + DevMsgRT( "%6.2f : %30s %6.2f (%6.2f:%6.2f:%6.2f) : %6.2f (%6.2f:%6.2f:%6.2f) : %1d\n", currentTime, boneSetup.GetStudioHdr()->pSeqdesc( m_AnimOverlay[i].m_nSequence ).pszLabel(), + fCycle, (float)pPrev2->m_flCycle, (float)pPrev1->m_flCycle, (float)pHead->m_flCycle, + fWeight, (float)pPrev2->m_flWeight, (float)pPrev1->m_flWeight, (float)pHead->m_flWeight, + i ); + } + else + { + DevMsgRT( "%6.2f : %30s %6.2f : %6.2f : %1d\n", currentTime, boneSetup.GetStudioHdr()->pSeqdesc( m_AnimOverlay[i].m_nSequence ).pszLabel(), fCycle, fWeight, i ); + } + } } -#if defined( DEBUG_TF2_OVERLAYS ) - else - { - engine->Con_NPrintf( 10 + j, "%30s %6.2f : %6.2f : %1d", " ", 0.f, 0.f, i ); - } #endif } } void C_BaseAnimatingOverlay::DoAnimationEvents( CStudioHdr *pStudioHdr ) { + MDLCACHE_CRITICAL_SECTION(); if ( !pStudioHdr || !pStudioHdr->SequencesAvailable() ) return; - MDLCACHE_CRITICAL_SECTION(); int nSequences = pStudioHdr->GetNumSeq(); @@ -450,6 +575,12 @@ void C_BaseAnimatingOverlay::DoAnimationEvents( CStudioHdr *pStudioHdr ) continue; } + // Don't bother with 0-weight layers + if ( m_AnimOverlay[j].m_flWeight == 0.0f || m_AnimOverlay[j].m_nOrder == MAX_OVERLAYS ) + { + continue; + } + mstudioseqdesc_t &seqdesc = pStudioHdr->pSeqdesc( m_AnimOverlay[j].m_nSequence ); if ( seqdesc.numevents == 0 ) continue; @@ -479,7 +610,7 @@ void C_BaseAnimatingOverlay::DoAnimationEvents( CStudioHdr *pStudioHdr ) } } - mstudioevent_t *pevent = seqdesc.pEvent( 0 ); + mstudioevent_t *pevent = GetEventIndexForSequence( seqdesc ); // This makes sure events that occur at the end of a sequence occur are // sent before events that occur at the beginning of a sequence. @@ -490,10 +621,10 @@ void C_BaseAnimatingOverlay::DoAnimationEvents( CStudioHdr *pStudioHdr ) // ignore all non-client-side events if ( pevent[i].type & AE_TYPE_NEWEVENTSYSTEM ) { - if ( !( pevent[i].type & AE_TYPE_CLIENT ) ) + if ( !(pevent[i].type & AE_TYPE_CLIENT) ) continue; } - else if ( pevent[i].event < 5000 ) //Adrian - Support the old event system + else if ( pevent[i].Event_OldSystem() < EVENT_CLIENT ) //Adrian - Support the old event system continue; if ( pevent[i].cycle <= m_flOverlayPrevEventCycle[j] ) @@ -503,15 +634,15 @@ void C_BaseAnimatingOverlay::DoAnimationEvents( CStudioHdr *pStudioHdr ) { Msg( "%i FE %i Looped cycle %f, prev %f ev %f (time %.3f)\n", gpGlobals->tickcount, - pevent[i].event, + pevent[i].Event(), pevent[i].cycle, - m_flOverlayPrevEventCycle[j], + (float)m_flOverlayPrevEventCycle[j], (float)m_AnimOverlay[j].m_flCycle, gpGlobals->curtime ); } - FireEvent( GetAbsOrigin(), GetAbsAngles(), pevent[ i ].event, pevent[ i ].pszOptions() ); + FireEvent( GetAbsOrigin(), GetAbsAngles(), pevent[ i ].Event(), pevent[ i ].pszOptions() ); } // Necessary to get the next loop working @@ -522,27 +653,29 @@ void C_BaseAnimatingOverlay::DoAnimationEvents( CStudioHdr *pStudioHdr ) { if ( pevent[i].type & AE_TYPE_NEWEVENTSYSTEM ) { - if ( !( pevent[i].type & AE_TYPE_CLIENT ) ) + if ( !(pevent[i].type & AE_TYPE_CLIENT) ) continue; } - else if ( pevent[i].event < 5000 ) //Adrian - Support the old event system + else if ( pevent[i].Event_OldSystem() < EVENT_CLIENT ) //Adrian - Support the old event system continue; - if ( (pevent[i].cycle > m_flOverlayPrevEventCycle[j] && pevent[i].cycle <= m_AnimOverlay[j].m_flCycle) ) + bool bStartedSequence = ( m_flOverlayPrevEventCycle[j] > m_AnimOverlay[j].m_flCycle || m_flOverlayPrevEventCycle[j] == 0 ); + + if ( ( ( pevent[i].cycle > m_flOverlayPrevEventCycle[j] || bStartedSequence && pevent[i].cycle == 0 ) && pevent[i].cycle <= m_AnimOverlay[j].m_flCycle) ) { if ( watch ) { Msg( "%i (seq: %d) FE %i Normal cycle %f, prev %f ev %f (time %.3f)\n", gpGlobals->tickcount, - m_AnimOverlay[j].m_nSequence.GetRaw(), - pevent[i].event, - pevent[i].cycle, - m_flOverlayPrevEventCycle[j], + (int)m_AnimOverlay[j].m_nSequence, + (int)pevent[i].Event(), + (float)pevent[i].cycle, + (float)m_flOverlayPrevEventCycle[j], (float)m_AnimOverlay[j].m_flCycle, gpGlobals->curtime ); } - FireEvent( GetAbsOrigin(), GetAbsAngles(), pevent[ i ].event, pevent[ i ].pszOptions() ); + FireEvent( GetAbsOrigin(), GetAbsAngles(), pevent[ i ].Event(), pevent[ i ].pszOptions() ); } } @@ -550,6 +683,7 @@ void C_BaseAnimatingOverlay::DoAnimationEvents( CStudioHdr *pStudioHdr ) } } + //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- @@ -566,3 +700,54 @@ CStudioHdr *C_BaseAnimatingOverlay::OnNewModel() return hdr; } + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_BaseAnimatingOverlay::CheckInterpChanges( void ) +{ + CDisableRangeChecks disableRangeChecks; + + for (int i = 0; i < m_AnimOverlay.Count(); i++) + { + int iHead, iPrev1, iPrev2; + m_iv_AnimOverlay[i].GetInterpolationInfo( gpGlobals->curtime, &iHead, &iPrev1, &iPrev2 ); + + float t0; + CAnimationLayer *pHead = m_iv_AnimOverlay[i].GetHistoryValue( iHead, t0 ); + + float t1; + CAnimationLayer *pPrev = m_iv_AnimOverlay[i].GetHistoryValue( iPrev1, t1 ); + + if ( !pHead || !pPrev ) + continue; + + m_AnimOverlay[ i ].m_nInvalidatePhysicsBits = CheckForSequenceBoxChanges( *pHead, *pPrev ); + } + + CheckForLayerPhysicsInvalidate(); +} + +void C_BaseAnimatingOverlay::CheckForLayerPhysicsInvalidate( void ) +{ + // When the layers interpolate they may change the animation or bbox so we + // have them accumulate the changes and call InvalidatePhysicsRecursive if any + // changes are needed. + int nInvalidatePhysicsChangeBits = 0; + + int nLayerCount = m_AnimOverlay.Count(); + for ( int i = 0; i < nLayerCount; ++i ) + { + int nChangeBits = m_AnimOverlay[ i ].m_nInvalidatePhysicsBits; + if ( nChangeBits ) + { + nInvalidatePhysicsChangeBits |= nChangeBits; + continue; + } + } + + if ( nInvalidatePhysicsChangeBits ) + { + InvalidatePhysicsRecursive( nInvalidatePhysicsChangeBits ); + } +} \ No newline at end of file diff --git a/game/client/c_baseanimatingoverlay.h b/game/client/c_baseanimatingoverlay.h index de0067dd2..c21c62570 100644 --- a/game/client/c_baseanimatingoverlay.h +++ b/game/client/c_baseanimatingoverlay.h @@ -1,16 +1,17 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // // $NoKeywords: $ // -//=============================================================================// +//===========================================================================// #ifndef C_BASEANIMATINGOVERLAY_H #define C_BASEANIMATINGOVERLAY_H #pragma once #include "c_baseanimating.h" +#include "toolframework/itoolframework.h" // For shared code. #define CBaseAnimatingOverlay C_BaseAnimatingOverlay @@ -18,45 +19,54 @@ class C_BaseAnimatingOverlay : public C_BaseAnimating { -public: DECLARE_CLASS( C_BaseAnimatingOverlay, C_BaseAnimating ); DECLARE_CLIENTCLASS(); DECLARE_PREDICTABLE(); DECLARE_INTERPOLATION(); - - C_BaseAnimatingOverlay(); - - virtual CStudioHdr *OnNewModel(); - - C_AnimationLayer* GetAnimOverlay( int i ); - void SetNumAnimOverlays( int num ); // This makes sure there is space for this # of layers. - int GetNumAnimOverlays() const; - + // Inherited from C_BaseAnimating +public: + virtual void AccumulateLayers( IBoneSetup &boneSetup, Vector pos[], Quaternion q[], float currentTime ); + virtual void DoAnimationEvents( CStudioHdr *pStudioHdr ); virtual void GetRenderBounds( Vector& theMins, Vector& theMaxs ); + virtual CStudioHdr *OnNewModel(); - void CheckForLayerChanges( CStudioHdr *hdr, float currentTime ); - - // model specific - virtual void AccumulateLayers( IBoneSetup &boneSetup, Vector pos[], Quaternion q[], float currentTime ); - virtual void DoAnimationEvents( CStudioHdr *pStudioHdr ); + virtual bool Interpolate( float flCurrentTime ); +public: enum { MAX_OVERLAYS = 15, }; - CUtlVector < C_AnimationLayer > m_AnimOverlay; + C_BaseAnimatingOverlay(); + CAnimationLayer* GetAnimOverlay( int i ); + void SetNumAnimOverlays( int num ); // This makes sure there is space for this # of layers. + int GetNumAnimOverlays() const; + void SetOverlayPrevEventCycle( int nSlot, float flValue ); + + void CheckInterpChanges( void ); + void CheckForLayerPhysicsInvalidate( void ); + +private: + void CheckForLayerChanges( CStudioHdr *hdr, float currentTime ); - CUtlVector < CInterpolatedVar< C_AnimationLayer > > m_iv_AnimOverlay; + CUtlVector < CAnimationLayer > m_AnimOverlay; + CUtlVector < CInterpolatedVar< CAnimationLayer > > m_iv_AnimOverlay; float m_flOverlayPrevEventCycle[ MAX_OVERLAYS ]; -private: C_BaseAnimatingOverlay( const C_BaseAnimatingOverlay & ); // not defined, not accessible + + friend void ResizeAnimationLayerCallback( void *pStruct, int offsetToUtlVector, int len ); }; +inline void C_BaseAnimatingOverlay::SetOverlayPrevEventCycle( int nSlot, float flValue ) +{ + m_flOverlayPrevEventCycle[nSlot] = flValue; +} + EXTERN_RECV_TABLE(DT_BaseAnimatingOverlay); diff --git a/game/client/c_basecombatcharacter.cpp b/game/client/c_basecombatcharacter.cpp index fee631181..02f18a4a3 100644 --- a/game/client/c_basecombatcharacter.cpp +++ b/game/client/c_basecombatcharacter.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: Client's C_BaseCombatCharacter entity // @@ -12,7 +12,6 @@ //=============================================================================// #include "cbase.h" #include "c_basecombatcharacter.h" - // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -26,15 +25,7 @@ C_BaseCombatCharacter::C_BaseCombatCharacter() { for ( int i=0; i < m_iAmmo.Count(); i++ ) - { m_iAmmo.Set( i, 0 ); - } - -#ifdef GLOWS_ENABLE - m_pGlowEffect = NULL; - m_bGlowEnabled = false; - m_bOldGlowEnabled = false; -#endif // GLOWS_ENABLE } //----------------------------------------------------------------------------- @@ -42,9 +33,6 @@ C_BaseCombatCharacter::C_BaseCombatCharacter() //----------------------------------------------------------------------------- C_BaseCombatCharacter::~C_BaseCombatCharacter() { -#ifdef GLOWS_ENABLE - DestroyGlowEffect(); -#endif // GLOWS_ENABLE } /* @@ -57,33 +45,6 @@ int C_BaseCombatCharacter::GetAmmoCount( char *szName ) const } */ -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void C_BaseCombatCharacter::OnPreDataChanged( DataUpdateType_t updateType ) -{ - BaseClass::OnPreDataChanged( updateType ); - -#ifdef GLOWS_ENABLE - m_bOldGlowEnabled = m_bGlowEnabled; -#endif // GLOWS_ENABLE -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void C_BaseCombatCharacter::OnDataChanged( DataUpdateType_t updateType ) -{ - BaseClass::OnDataChanged( updateType ); - -#ifdef GLOWS_ENABLE - if ( m_bOldGlowEnabled != m_bGlowEnabled ) - { - UpdateGlowEffect(); - } -#endif // GLOWS_ENABLE -} - //----------------------------------------------------------------------------- // Purpose: Overload our muzzle flash and send it to any actively held weapon //----------------------------------------------------------------------------- @@ -101,71 +62,26 @@ void C_BaseCombatCharacter::DoMuzzleFlash() BaseClass::DoMuzzleFlash(); } } - -#ifdef GLOWS_ENABLE -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void C_BaseCombatCharacter::GetGlowEffectColor( float *r, float *g, float *b ) -{ - *r = 0.76f; - *g = 0.76f; - *b = 0.76f; -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void C_BaseCombatCharacter::UpdateGlowEffect( void ) -{ - // destroy the existing effect - if ( m_pGlowEffect ) - { - DestroyGlowEffect(); - } - - // create a new effect - if ( m_bGlowEnabled ) - { - float r, g, b; - GetGlowEffectColor( &r, &g, &b ); - - m_pGlowEffect = new CGlowObject( this, Vector( r, g, b ), 1.0, true ); - } -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void C_BaseCombatCharacter::DestroyGlowEffect( void ) -{ - if ( m_pGlowEffect ) - { - delete m_pGlowEffect; - m_pGlowEffect = NULL; - } -} -#endif // GLOWS_ENABLE - IMPLEMENT_CLIENTCLASS(C_BaseCombatCharacter, DT_BaseCombatCharacter, CBaseCombatCharacter); // Only send active weapon index to local player BEGIN_RECV_TABLE_NOBASE( C_BaseCombatCharacter, DT_BCCLocalPlayerExclusive ) RecvPropTime( RECVINFO( m_flNextAttack ) ), + + + RecvPropArray3( RECVINFO_ARRAY(m_hMyWeapons), RecvPropEHandle( RECVINFO( m_hMyWeapons[0] ) ) ), + + END_RECV_TABLE(); BEGIN_RECV_TABLE(C_BaseCombatCharacter, DT_BaseCombatCharacter) RecvPropDataTable( "bcc_localdata", 0, 0, &REFERENCE_RECV_TABLE(DT_BCCLocalPlayerExclusive) ), RecvPropEHandle( RECVINFO( m_hActiveWeapon ) ), - RecvPropArray3( RECVINFO_ARRAY(m_hMyWeapons), RecvPropEHandle( RECVINFO( m_hMyWeapons[0] ) ) ), -#ifdef GLOWS_ENABLE - RecvPropBool( RECVINFO( m_bGlowEnabled ) ), -#endif // GLOWS_ENABLE -#ifdef INVASION_CLIENT_DLL - RecvPropInt( RECVINFO( m_iPowerups ) ), -#endif + + + END_RECV_TABLE() diff --git a/game/client/c_basecombatcharacter.h b/game/client/c_basecombatcharacter.h index 1d84e4ce7..867cfe6d6 100644 --- a/game/client/c_basecombatcharacter.h +++ b/game/client/c_basecombatcharacter.h @@ -1,9 +1,9 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: Defines the client-side representation of CBaseCombatCharacter. // // $NoKeywords: $ -//=============================================================================// +//===========================================================================// #ifndef C_BASECOMBATCHARACTER_H #define C_BASECOMBATCHARACTER_H @@ -14,15 +14,12 @@ #include "shareddefs.h" #include "c_baseflex.h" -#ifdef GLOWS_ENABLE -#include "glow_outline_effect.h" -#endif // GLOWS_ENABLE + +#define BCC_DEFAULT_LOOK_TOWARDS_TOLERANCE 0.9f class C_BaseCombatWeapon; class C_WeaponCombatShield; -#define BCC_DEFAULT_LOOK_TOWARDS_TOLERANCE 0.9f - class C_BaseCombatCharacter : public C_BaseFlex { DECLARE_CLASS( C_BaseCombatCharacter, C_BaseFlex ); @@ -33,9 +30,6 @@ class C_BaseCombatCharacter : public C_BaseFlex C_BaseCombatCharacter( void ); virtual ~C_BaseCombatCharacter( void ); - virtual void OnPreDataChanged( DataUpdateType_t updateType ); - virtual void OnDataChanged( DataUpdateType_t updateType ); - virtual bool IsBaseCombatCharacter( void ) { return true; }; virtual C_BaseCombatCharacter *MyCombatCharacterPointer( void ) { return this; } @@ -60,7 +54,6 @@ class C_BaseCombatCharacter : public C_BaseFlex virtual bool IsLineOfSightClear( CBaseEntity *entity, LineOfSightCheckType checkType = IGNORE_NOTHING ) const;// strictly LOS check with no other considerations virtual bool IsLineOfSightClear( const Vector &pos, LineOfSightCheckType checkType = IGNORE_NOTHING, CBaseEntity *entityToIgnore = NULL ) const; - // ----------------------- // Ammo // ----------------------- @@ -70,7 +63,8 @@ class C_BaseCombatCharacter : public C_BaseFlex int GetAmmoCount( int iAmmoIndex ) const; int GetAmmoCount( char *szName ) const; - C_BaseCombatWeapon* Weapon_OwnsThisType( const char *pszWeapon, int iSubType = 0 ) const; // True if already owns a weapon of this class + virtual C_BaseCombatWeapon* Weapon_OwnsThisType( const char *pszWeapon, int iSubType = 0 ) const; // True if already owns a weapon of this class + virtual int Weapon_GetSlot( const char *pszWeapon, int iSubType = 0 ) const; // Returns -1 if they don't have one virtual bool Weapon_Switch( C_BaseCombatWeapon *pWeapon, int viewmodelindex = 0 ); virtual bool Weapon_CanSwitchTo(C_BaseCombatWeapon *pWeapon); @@ -78,8 +72,8 @@ class C_BaseCombatCharacter : public C_BaseFlex bool SwitchToNextBestWeapon(C_BaseCombatWeapon *pCurrent); virtual C_BaseCombatWeapon *GetActiveWeapon( void ) const; - int WeaponCount() const; - C_BaseCombatWeapon *GetWeapon( int i ) const; + int WeaponCount() const; + virtual C_BaseCombatWeapon *GetWeapon( int i ) const; // This is a sort of hack back-door only used by physgun! void SetAmmoCount( int iCount, int iAmmoIndex ); @@ -92,85 +86,47 @@ class C_BaseCombatCharacter : public C_BaseFlex // Blood color (see BLOOD_COLOR_* macros in baseentity.h) void SetBloodColor( int nBloodColor ); - virtual void DoMuzzleFlash(); - -#ifdef GLOWS_ENABLE - CGlowObject *GetGlowObject( void ){ return m_pGlowEffect; } - virtual void GetGlowEffectColor( float *r, float *g, float *b ); -#endif // GLOWS_ENABLE + virtual void DoMuzzleFlash(); public: +// BEGIN PREDICTION DATA COMPACTION (these fields are together to allow for faster copying in prediction system) float m_flNextAttack; -protected: - -#ifdef GLOWS_ENABLE - virtual void UpdateGlowEffect( void ); - virtual void DestroyGlowEffect( void ); -#endif // GLOWS_ENABLE - - int m_bloodColor; // color of blood particless - private: - bool ComputeLOS( const Vector &vecEyePosition, const Vector &vecTarget ) const; + bool ComputeLOS( const Vector &vecEyePosition, const Vector &vecTarget ) const; +private: CNetworkArray( int, m_iAmmo, MAX_AMMO_TYPES ); - CHandle m_hMyWeapons[MAX_WEAPONS]; CHandle< C_BaseCombatWeapon > m_hActiveWeapon; -#ifdef GLOWS_ENABLE - bool m_bGlowEnabled; - bool m_bOldGlowEnabled; - CGlowObject *m_pGlowEffect; -#endif // GLOWS_ENABLE +// END PREDICTION DATA COMPACTION + +protected: + + int m_bloodColor; // color of blood particless + private: - C_BaseCombatCharacter( const C_BaseCombatCharacter & ); // not defined, not accessible -//----------------------- -#ifdef INVASION_CLIENT_DLL -public: - virtual void Release( void ); - virtual void SetDormant( bool bDormant ); - virtual void OnPreDataChanged( DataUpdateType_t updateType ); - virtual void OnDataChanged( DataUpdateType_t updateType ); - virtual void ClientThink( void ); - // TF2 Powerups - virtual bool CanBePoweredUp( void ) { return true; } - bool HasPowerup( int iPowerup ) { return ( m_iPowerups & (1 << iPowerup) ) != 0; }; - virtual void PowerupStart( int iPowerup, bool bInitial ); - virtual void PowerupEnd( int iPowerup ); - void RemoveAllPowerups( void ); +private: + C_BaseCombatCharacter( const C_BaseCombatCharacter & ); // not defined, not accessible - // Powerup effects - void AddEMPEffect( float flSize ); - void AddBuffEffect( float flSize ); - C_WeaponCombatShield *GetShield( void ); +//----------------------- -public: - int m_iPowerups; - int m_iPrevPowerups; -#endif }; inline C_BaseCombatCharacter *ToBaseCombatCharacter( C_BaseEntity *pEntity ) { - if ( !pEntity || !pEntity->IsBaseCombatCharacter() ) - return NULL; - -#if _DEBUG - return dynamic_cast( pEntity ); -#else - return static_cast( pEntity ); -#endif + return pEntity ? pEntity->MyCombatCharacterPointer() : NULL; } + //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- @@ -179,16 +135,6 @@ inline int C_BaseCombatCharacter::WeaponCount() const return MAX_WEAPONS; } -//----------------------------------------------------------------------------- -// Purpose: -// Input : i - -//----------------------------------------------------------------------------- -inline C_BaseCombatWeapon *C_BaseCombatCharacter::GetWeapon( int i ) const -{ - Assert( (i >= 0) && (i < MAX_WEAPONS) ); - return m_hMyWeapons[i].Get(); -} - EXTERN_RECV_TABLE(DT_BaseCombatCharacter); #endif // C_BASECOMBATCHARACTER_H diff --git a/game/client/c_basecombatweapon.cpp b/game/client/c_basecombatweapon.cpp index 55d21b391..9276076d8 100644 --- a/game/client/c_basecombatweapon.cpp +++ b/game/client/c_basecombatweapon.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: Client side implementation of CBaseCombatWeapon. // @@ -20,26 +20,13 @@ // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" -//----------------------------------------------------------------------------- -// Purpose: Gets the local client's active weapon, if any. -//----------------------------------------------------------------------------- -C_BaseCombatWeapon *GetActiveWeapon( void ) -{ - C_BasePlayer *player = C_BasePlayer::GetLocalPlayer(); - - if ( !player ) - return NULL; - - return player->GetActiveWeapon(); -} - //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void C_BaseCombatWeapon::SetDormant( bool bDormant ) { // If I'm going from active to dormant and I'm carried by another player, holster me. - if ( !IsDormant() && bDormant && GetOwner() && !IsCarriedByLocalPlayer() ) + if ( !IsDormant() && bDormant && !IsCarriedByLocalPlayer() ) { Holster( NULL ); } @@ -75,16 +62,13 @@ void C_BaseCombatWeapon::NotifyShouldTransmit( ShouldTransmitState_t state ) } -//----------------------------------------------------------------------------- -// Purpose: To wrap PORTAL mod specific functionality into one place -//----------------------------------------------------------------------------- -static inline bool ShouldDrawLocalPlayerViewModel( void ) + +static inline bool ShouldDrawLocalPlayer( C_BasePlayer *pl ) { -#if defined( PORTAL ) - return false; -#else - return !C_BasePlayer::ShouldDrawLocalPlayer(); -#endif + + Assert( pl ); + return pl->ShouldDrawLocalPlayer(); + } //----------------------------------------------------------------------------- @@ -96,7 +80,7 @@ void C_BaseCombatWeapon::OnRestore() // if the player is holding this weapon, // mark it as just restored so it won't show as a new pickup - if (GetOwner() == C_BasePlayer::GetLocalPlayer()) + if ( C_BasePlayer::IsLocalPlayer( GetOwner() ) ) { m_bJustRestored = true; } @@ -104,17 +88,6 @@ void C_BaseCombatWeapon::OnRestore() int C_BaseCombatWeapon::GetWorldModelIndex( void ) { - if ( GameRules() ) - { - const char *pBaseName = modelinfo->GetModelName( modelinfo->GetModel( m_iWorldModelIndex ) ); - const char *pTranslatedName = GameRules()->TranslateEffectForVisionFilter( "weapons", pBaseName ); - - if ( pTranslatedName != pBaseName ) - { - return modelinfo->GetModelIndex( pTranslatedName ); - } - } - return m_iWorldModelIndex; } @@ -124,22 +97,23 @@ int C_BaseCombatWeapon::GetWorldModelIndex( void ) //----------------------------------------------------------------------------- void C_BaseCombatWeapon::OnDataChanged( DataUpdateType_t updateType ) { - BaseClass::OnDataChanged(updateType); - - CHandle< C_BaseCombatWeapon > handle = this; + BaseClass::OnDataChanged( updateType ); // If it's being carried by the *local* player, on the first update, // find the registered weapon for this ID - C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); C_BaseCombatCharacter *pOwner = GetOwner(); + C_BasePlayer *pPlayer = ToBasePlayer( pOwner ); // check if weapon is carried by local player - bool bIsLocalPlayer = pPlayer && pPlayer == pOwner; - if ( bIsLocalPlayer && ShouldDrawLocalPlayerViewModel() ) // TODO: figure out the purpose of the ShouldDrawLocalPlayer() test. + bool bIsLocalPlayer = C_BasePlayer::IsLocalPlayer( pPlayer ); + if ( bIsLocalPlayer ) { + ACTIVE_SPLITSCREEN_PLAYER_GUARD( C_BasePlayer::GetSplitScreenSlotForPlayer( pPlayer ) ); + // If I was just picked up, or created & immediately carried, add myself to this client's list of weapons - if ( (m_iState != WEAPON_NOT_CARRIED ) && (m_iOldState == WEAPON_NOT_CARRIED) ) + if ( ( m_iState != WEAPON_NOT_CARRIED ) && + ( m_iOldState == WEAPON_NOT_CARRIED ) ) { // Tell the HUD this weapon's been picked up if ( ShouldDrawPickup() ) @@ -154,15 +128,7 @@ void C_BaseCombatWeapon::OnDataChanged( DataUpdateType_t updateType ) } } } - else // weapon carried by other player or not at all - { - int overrideModelIndex = CalcOverrideModelIndex(); - if( overrideModelIndex != -1 && overrideModelIndex != GetModelIndex() ) - { - SetModelIndex( overrideModelIndex ); - } - } - + UpdateVisibility(); m_iOldState = m_iState; @@ -200,10 +166,10 @@ ShadowType_t C_BaseCombatWeapon::ShadowCastType() if (!IsBeingCarried()) return SHADOWS_RENDER_TO_TEXTURE; - if (IsCarriedByLocalPlayer() && !C_BasePlayer::ShouldDrawLocalPlayer()) + if (IsCarriedByLocalPlayer()) return SHADOWS_NONE; - return SHADOWS_RENDER_TO_TEXTURE; + return (m_iState != WEAPON_IS_CARRIED_BY_PLAYER) ? SHADOWS_RENDER_TO_TEXTURE : SHADOWS_NONE; } //----------------------------------------------------------------------------- @@ -212,24 +178,24 @@ ShadowType_t C_BaseCombatWeapon::ShadowCastType() //----------------------------------------------------------------------------- void C_BaseCombatWeapon::Redraw() { - if ( g_pClientMode->ShouldDrawCrosshair() ) + if ( GetClientMode()->ShouldDrawCrosshair() ) { DrawCrosshair(); } // ammo drawing has been moved into hud_ammo.cpp } - //----------------------------------------------------------------------------- // Purpose: Draw the weapon's crosshair //----------------------------------------------------------------------------- void C_BaseCombatWeapon::DrawCrosshair() { +#ifndef INFESTED_DLL C_BasePlayer *player = C_BasePlayer::GetLocalPlayer(); if ( !player ) return; - Color clr = gHUD.m_clrNormal; + Color clr = GetHud().m_clrNormal; /* // TEST: if the thing under your crosshair is on a different team, light the crosshair with a different color. @@ -263,7 +229,7 @@ void C_BaseCombatWeapon::DrawCrosshair() return; // Find out if this weapon's auto-aimed onto a target - bool bOnTarget = ( m_iState == WEAPON_IS_ONTARGET ); + bool bOnTarget = ( m_iState == WEAPON_IS_ACTIVE ) && player->m_fOnTarget; if ( player->GetFOV() >= 90 ) { @@ -296,8 +262,8 @@ void C_BaseCombatWeapon::DrawCrosshair() else crosshair->ResetCrosshair(); } + #endif } - //----------------------------------------------------------------------------- // Purpose: This weapon is the active weapon, and the viewmodel for it was just drawn. //----------------------------------------------------------------------------- @@ -313,20 +279,9 @@ bool C_BaseCombatWeapon::IsCarriedByLocalPlayer( void ) if ( !GetOwner() ) return false; - return ( GetOwner() == C_BasePlayer::GetLocalPlayer() ); + return ( C_BasePlayer::IsLocalPlayer( GetOwner() ) ); } - -//----------------------------------------------------------------------------- -// Purpose: Returns true if this client is carrying this weapon and is -// using the view models -//----------------------------------------------------------------------------- -bool C_BaseCombatWeapon::ShouldDrawUsingViewModel( void ) -{ - return IsCarriedByLocalPlayer() && !C_BasePlayer::ShouldDrawLocalPlayer(); -} - - //----------------------------------------------------------------------------- // Purpose: Returns true if this weapon is the local client's currently wielded weapon //----------------------------------------------------------------------------- @@ -360,10 +315,17 @@ bool C_BaseCombatWeapon::GetShootPosition( Vector &vOrigin, QAngle &vAngles ) vAngles.Init(); } + C_BasePlayer *player = ToBasePlayer( pEnt ); + bool bUseViewModel = false; + if ( C_BasePlayer::IsLocalPlayer( pEnt ) ) + { + ACTIVE_SPLITSCREEN_PLAYER_GUARD_ENT( pEnt ); + bUseViewModel = !player->ShouldDrawLocalPlayer(); + } + QAngle vDummy; - if ( IsActiveByLocalPlayer() && ShouldDrawLocalPlayerViewModel() ) + if ( IsActiveByLocalPlayer() && bUseViewModel ) { - C_BasePlayer *player = ToBasePlayer( pEnt ); C_BaseViewModel *vm = player ? player->GetViewModel( 0 ) : NULL; if ( vm ) { @@ -411,7 +373,6 @@ bool C_BaseCombatWeapon::ShouldDraw( void ) return true; bool bIsActive = ( m_iState == WEAPON_IS_ACTIVE ); - C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer(); // carried by local player? @@ -421,15 +382,8 @@ bool C_BaseCombatWeapon::ShouldDraw( void ) if ( !bIsActive ) return false; - if ( !pOwner->ShouldDraw() ) - { - // Our owner is invisible. - // This also tests whether the player is zoomed in, in which case you don't want to draw the weapon. - return false; - } - - // 3rd person mode? - if ( !ShouldDrawLocalPlayerViewModel() ) + // 3rd person mode + if ( pLocalPlayer->ShouldDrawLocalPlayer() ) return true; // don't draw active weapon if not in some kind of 3rd person mode, the viewmodel will do that @@ -462,11 +416,40 @@ bool C_BaseCombatWeapon::ShouldDrawPickup( void ) return true; } + +//---------------------------------------------------------------------------- +// Hooks into the fast path render system +//---------------------------------------------------------------------------- +IClientModelRenderable* C_BaseCombatWeapon::GetClientModelRenderable() +{ + if ( !m_bReadyToDraw ) + return 0; + + // check if local player chases owner of this weapon in first person + C_BasePlayer *localplayer = C_BasePlayer::GetLocalPlayer(); + if ( localplayer && localplayer->IsObserver() && GetOwner() ) + { + // don't draw weapon if chasing this guy as spectator + // we don't check that in ShouldDraw() since this may change + // without notification + if ( localplayer->GetObserverMode() == OBS_MODE_IN_EYE && + localplayer->GetObserverTarget() == GetOwner() ) + return NULL; + } + + if ( !BaseClass::GetClientModelRenderable() ) + return NULL; + + EnsureCorrectRenderingModel(); + return this; +} + + //----------------------------------------------------------------------------- // Purpose: Render the weapon. Draw the Viewmodel if the weapon's being carried // by this player, otherwise draw the worldmodel. //----------------------------------------------------------------------------- -int C_BaseCombatWeapon::DrawModel( int flags ) +int C_BaseCombatWeapon::DrawModel( int flags, const RenderableInstance_t &instance ) { VPROF_BUDGET( "C_BaseCombatWeapon::DrawModel", VPROF_BUDGETGROUP_MODEL_RENDERING ); if ( !m_bReadyToDraw ) @@ -489,32 +472,40 @@ int C_BaseCombatWeapon::DrawModel( int flags ) return false; } - return BaseClass::DrawModel( flags ); -} + // See comment below + EnsureCorrectRenderingModel(); + return BaseClass::DrawModel( flags, instance ); +} -//----------------------------------------------------------------------------- -// Allows the client-side entity to override what the network tells it to use for -// a model. This is used for third person mode, specifically in HL2 where the -// the weapon timings are on the view model and not the world model. That means the -// server needs to use the view model, but the client wants to use the world model. -//----------------------------------------------------------------------------- -int C_BaseCombatWeapon::CalcOverrideModelIndex() -{ +// If the local player is visible (thirdperson mode, tf2 taunts, etc., then make sure that we are using the +// w_ (world) model not the v_ (view) model or else the model can flicker, etc. +// Otherwise, if we're not the local player, always use the world model +void C_BaseCombatWeapon::EnsureCorrectRenderingModel() +{ C_BasePlayer *localplayer = C_BasePlayer::GetLocalPlayer(); if ( localplayer && localplayer == GetOwner() && - ShouldDrawLocalPlayerViewModel() ) + !localplayer->ShouldDrawLocalPlayer() ) { - return BaseClass::CalcOverrideModelIndex(); + return; } - else + + // BRJ 10/14/02 + // FIXME: Remove when Yahn's client-side prediction is done + // It's a hacky workaround for the model indices fighting + // (GetRenderBounds uses the model index, which is for the view model) + SetModelIndex( GetWorldModelIndex() ); + + // Validate our current sequence just in case ( in theory the view and weapon models should have the same sequences for sequences that overlap at least ) + CStudioHdr *pStudioHdr = GetModelPtr(); + if ( pStudioHdr && + GetSequence() >= pStudioHdr->GetNumSeq() ) { - return GetWorldModelIndex(); + SetSequence( 0 ); } } - //----------------------------------------------------------------------------- // tool recording //----------------------------------------------------------------------------- diff --git a/game/client/c_basecombatweapon.h b/game/client/c_basecombatweapon.h index 1523bd07b..75bb0eb3b 100644 --- a/game/client/c_basecombatweapon.h +++ b/game/client/c_basecombatweapon.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: Client's CBaseCombatWeapon entity // @@ -19,8 +19,4 @@ class CViewSetup; class C_BaseViewModel; -// Accessors for local weapons -C_BaseCombatWeapon *GetActiveWeapon( void ); - - #endif // C_BASECOMBATWEAPON \ No newline at end of file diff --git a/game/client/c_basedoor.cpp b/game/client/c_basedoor.cpp index 4b3800def..aa591be3e 100644 --- a/game/client/c_basedoor.cpp +++ b/game/client/c_basedoor.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // diff --git a/game/client/c_basedoor.h b/game/client/c_basedoor.h index 852f2deda..91fe3b4ed 100644 --- a/game/client/c_basedoor.h +++ b/game/client/c_basedoor.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // @@ -11,15 +11,16 @@ #endif #include "c_baseentity.h" +#include "c_basetoggle.h" #if defined( CLIENT_DLL ) #define CBaseDoor C_BaseDoor #endif -class C_BaseDoor : public C_BaseEntity +class C_BaseDoor : public C_BaseToggle { public: - DECLARE_CLASS( C_BaseDoor, C_BaseEntity ); + DECLARE_CLASS( C_BaseDoor, C_BaseToggle ); DECLARE_CLIENTCLASS(); C_BaseDoor( void ); @@ -29,4 +30,4 @@ class C_BaseDoor : public C_BaseEntity float m_flWaveHeight; }; -#endif // C_BASEDOOR_H \ No newline at end of file +#endif // C_BASEDOOR_H diff --git a/game/client/c_baseentity.cpp b/game/client/c_baseentity.cpp index 9e65f3884..4ff451a81 100644 --- a/game/client/c_baseentity.cpp +++ b/game/client/c_baseentity.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // @@ -22,11 +22,11 @@ #include "tier0/vprof.h" #include "fx_line.h" #include "interface.h" -#include "materialsystem/imaterialsystem.h" +#include "materialsystem/IMaterialSystem.h" #include "soundinfo.h" #include "mathlib/vmatrix.h" #include "isaverestore.h" -#include "interval.h" +#include "tier2/interval.h" #include "engine/ivdebugoverlay.h" #include "c_ai_basenpc.h" #include "apparent_velocity_helper.h" @@ -39,7 +39,9 @@ #include "decals.h" #include "cdll_bounded_cvars.h" #include "inetchannelinfo.h" -#include "proto_version.h" +#include "clientalphaproperty.h" +#include "cellcoord.h" +#include "gamestringpool.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -54,6 +56,8 @@ static bool g_bWasSkipping = (bool)-1; static bool g_bWasThreaded =(bool)-1; static int g_nThreadModeTicks = 0; +static ConVar cl_interp_threadmodeticks( "cl_interp_threadmodeticks", "0", 0, "Additional interpolation ticks to use when interpolating with threaded engine mode set." ); + void cc_cl_interp_all_changed( IConVar *pConVar, const char *pOldString, float flOldValue ) { @@ -66,15 +70,15 @@ void cc_cl_interp_all_changed( IConVar *pConVar, const char *pOldString, float f { if ( pEnt->ShouldInterpolate() ) { - pEnt->AddToInterpolationList(); + pEnt->AddToEntityList(ENTITY_LIST_INTERPOLATE); } } } } - +static ConVar report_cliententitysim( "report_cliententitysim", "0", FCVAR_CHEAT, "List all clientside simulations and time - will report and turn itself off." ); static ConVar cl_extrapolate( "cl_extrapolate", "1", FCVAR_CHEAT, "Enable/disable extrapolation if interpolation history runs out." ); -static ConVar cl_interp_npcs( "cl_interp_npcs", "0.0", FCVAR_USERINFO, "Interpolate NPC positions starting this many seconds in past (or cl_interp, if greater)" ); +static ConVar cl_interp_npcs( "cl_interp_npcs", "0.0", 0, "Interpolate NPC positions starting this many seconds in past (or cl_interp, if greater)" ); static ConVar cl_interp_all( "cl_interp_all", "0", 0, "Disable interpolation list optimizations.", 0, 0, 0, 0, cc_cl_interp_all_changed ); ConVar r_drawmodeldecals( "r_drawmodeldecals", "1" ); extern ConVar cl_showerror; @@ -92,39 +96,25 @@ static bool g_bAbsRecomputationStack[8]; static unsigned short g_iAbsRecomputationStackPos = 0; // All the entities that want Interpolate() called on them. -static CUtlLinkedList g_InterpolationList; -static CUtlLinkedList g_TeleportList; +static CUtlLinkedList g_EntityLists[NUM_ENTITY_LISTS]; +static bool s_bImmediateRemovesAllowed = true; #if !defined( NO_ENTITY_PREDICTION ) -//----------------------------------------------------------------------------- -// Purpose: Maintains a list of predicted or client created entities -//----------------------------------------------------------------------------- -class CPredictableList : public IPredictableList -{ -public: - virtual C_BaseEntity *GetPredictable( int slot ); - virtual int GetPredictableCount( void ); - -protected: - void AddToPredictableList( ClientEntityHandle_t add ); - void RemoveFromPredictablesList( ClientEntityHandle_t remove ); - -private: - CUtlVector< ClientEntityHandle_t > m_Predictables; - - friend class C_BaseEntity; -}; // Create singleton -static CPredictableList g_Predictables; -IPredictableList *predictables = &g_Predictables; +static CPredictableList g_Predictables[ MAX_SPLITSCREEN_PLAYERS ]; +CPredictableList *GetPredictables( int nSlot ) +{ + AssertMsg1( nSlot >= 0, "Tried to get prediction slot for player %d. This probably means you are predicting something that isn't local. Crash ensues.", nSlot ); + return &g_Predictables[ nSlot ]; +} //----------------------------------------------------------------------------- // Purpose: Add entity to list // Input : add - // Output : int //----------------------------------------------------------------------------- -void CPredictableList::AddToPredictableList( ClientEntityHandle_t add ) +void CPredictableList::AddToPredictableList( C_BaseEntity *add ) { // This is a hack to remap slot to index if ( m_Predictables.Find( add ) != m_Predictables.InvalidIndex() ) @@ -132,75 +122,19 @@ void CPredictableList::AddToPredictableList( ClientEntityHandle_t add ) return; } - // Add to general list - m_Predictables.AddToTail( add ); - - // Maintain sort order by entindex - int count = m_Predictables.Size(); - if ( count < 2 ) - return; - - int i, j; - for ( i = 0; i < count; i++ ) - { - for ( j = i + 1; j < count; j++ ) - { - ClientEntityHandle_t h1 = m_Predictables[ i ]; - ClientEntityHandle_t h2 = m_Predictables[ j ]; - - C_BaseEntity *p1 = cl_entitylist->GetBaseEntityFromHandle( h1 ); - C_BaseEntity *p2 = cl_entitylist->GetBaseEntityFromHandle( h2 ); - - if ( !p1 || !p2 ) - { - Assert( 0 ); - continue; - } - - if ( p1->entindex() != -1 && - p2->entindex() != -1 ) - { - if ( p1->entindex() < p2->entindex() ) - continue; - } - - if ( p2->entindex() == -1 ) - continue; - - m_Predictables[ i ] = h2; - m_Predictables[ j ] = h1; - } - } + // Add to general sorted list + m_Predictables.Insert( add ); } //----------------------------------------------------------------------------- // Purpose: // Input : remove - //----------------------------------------------------------------------------- -void CPredictableList::RemoveFromPredictablesList( ClientEntityHandle_t remove ) +void CPredictableList::RemoveFromPredictablesList( C_BaseEntity *remove ) { m_Predictables.FindAndRemove( remove ); } -//----------------------------------------------------------------------------- -// Purpose: -// Input : slot - -// Output : C_BaseEntity -//----------------------------------------------------------------------------- -C_BaseEntity *CPredictableList::GetPredictable( int slot ) -{ - return cl_entitylist->GetBaseEntityFromHandle( m_Predictables[ slot ] ); -} - -//----------------------------------------------------------------------------- -// Purpose: -// Output : int -//----------------------------------------------------------------------------- -int CPredictableList::GetPredictableCount( void ) -{ - return m_Predictables.Count(); -} - //----------------------------------------------------------------------------- // Purpose: Searc predictables for previously created entity (by testId) // Input : testId - @@ -208,22 +142,26 @@ int CPredictableList::GetPredictableCount( void ) //----------------------------------------------------------------------------- static C_BaseEntity *FindPreviouslyCreatedEntity( CPredictableId& testId ) { - int c = predictables->GetPredictableCount(); - - int i; - for ( i = 0; i < c; i++ ) +#if defined( USE_PREDICTABLEID ) + FOR_EACH_VALID_SPLITSCREEN_PLAYER( hh ) { - C_BaseEntity *e = predictables->GetPredictable( i ); - if ( !e || !e->IsClientCreated() ) - continue; + int c = GetPredictables( hh )->GetPredictableCount(); - // Found it, note use of operator == - if ( testId == e->m_PredictableID ) + int i; + for ( i = 0; i < c; i++ ) { - return e; + C_BaseEntity *e = GetPredictables( hh )->GetPredictable( i ); + if ( !e || !e->IsClientCreated() ) + continue; + + // Found it, note use of operator == + if ( testId == e->m_PredictableID ) + { + return e; + } } } - +#endif return NULL; } #endif @@ -299,9 +237,35 @@ int CRecordingList::Count() return m_Recording.Count(); } +// Helper object implementation +CCurTimeScopeGuard::CCurTimeScopeGuard( float flNewCurTime, bool bOptionalCondition /*= true*/ ) +{ + m_bActive = bOptionalCondition; + if ( m_bActive ) + { + m_flSavedTime = gpGlobals->curtime; + gpGlobals->curtime = flNewCurTime; + } + else + { + m_flSavedTime = 0.0f; + } +} + +CCurTimeScopeGuard::~CCurTimeScopeGuard() +{ + if ( m_bActive ) + { + gpGlobals->curtime = m_flSavedTime; + } +} + // Should these be somewhere else? #define PITCH 0 +// HACK HACK: 3/28/02 ywb Had to proxy around this or interpolation is borked in multiplayer, not sure what +// the issue is, just a global optimizer bug I presume +#pragma optimize( "g", off ) //----------------------------------------------------------------------------- // Purpose: Decodes animtime and notes when it changes // Input : *pStruct - ( C_BaseEntity * ) used to flag animtime is changine @@ -365,6 +329,128 @@ void RecvProxy_SimulationTime( const CRecvProxyData *pData, void *pStruct, void pEntity->m_flSimulationTime = ( t * TICK_INTERVAL ); } +void C_BaseEntity::RecvProxy_CellBits( const CRecvProxyData *pData, void *pStruct, void *pOut ) +{ + CBaseEntity *pEnt = (CBaseEntity *)pStruct; + + if ( pEnt->SetCellBits( pData->m_Value.m_Int ) ) + { + if ( pEnt->ShouldRegenerateOriginFromCellBits() ) + { + pEnt->m_vecNetworkOrigin.x = CoordFromCell( pEnt->m_cellwidth, pEnt->m_cellX, pEnt->m_vecCellOrigin.x ); + pEnt->m_vecNetworkOrigin.y = CoordFromCell( pEnt->m_cellwidth, pEnt->m_cellY, pEnt->m_vecCellOrigin.y ); + pEnt->m_vecNetworkOrigin.z = CoordFromCell( pEnt->m_cellwidth, pEnt->m_cellZ, pEnt->m_vecCellOrigin.z ); + } + } +} + +void C_BaseEntity::RecvProxy_CellX( const CRecvProxyData *pData, void *pStruct, void *pOut ) +{ + CBaseEntity *pEnt = (CBaseEntity *)pStruct; + + int *cellX = (int *)pOut; + Assert( cellX == &pEnt->m_cellX ); + + *cellX = pData->m_Value.m_Int; + + // Cell changed, update world position + if ( pEnt->ShouldRegenerateOriginFromCellBits() ) + { + pEnt->m_vecNetworkOrigin.x = CoordFromCell( pEnt->m_cellwidth, pEnt->m_cellX, pEnt->m_vecCellOrigin.x ); + } +} + +void C_BaseEntity::RecvProxy_CellY( const CRecvProxyData *pData, void *pStruct, void *pOut ) +{ + CBaseEntity *pEnt = (CBaseEntity *)pStruct; + + int *cellY = (int *)pOut; + Assert( cellY == &pEnt->m_cellY ); + + *cellY = pData->m_Value.m_Int; + + // Cell changed, update world position + if ( pEnt->ShouldRegenerateOriginFromCellBits() ) + { + pEnt->m_vecNetworkOrigin.y = CoordFromCell( pEnt->m_cellwidth, pEnt->m_cellY, pEnt->m_vecCellOrigin.y ); + } +} + +void C_BaseEntity::RecvProxy_CellZ( const CRecvProxyData *pData, void *pStruct, void *pOut ) +{ + CBaseEntity *pEnt = (CBaseEntity *)pStruct; + + int *cellZ = (int *)pOut; + Assert( cellZ == &pEnt->m_cellZ ); + + *cellZ = pData->m_Value.m_Int; + + // Cell changed, update world position + if ( pEnt->ShouldRegenerateOriginFromCellBits() ) + { + pEnt->m_vecNetworkOrigin.z = CoordFromCell( pEnt->m_cellwidth, pEnt->m_cellZ, pEnt->m_vecCellOrigin.z ); + } +} + +void C_BaseEntity::RecvProxy_CellOrigin( const CRecvProxyData *pData, void *pStruct, void *pOut ) +{ + CBaseEntity *pEnt = (CBaseEntity *)pStruct; + + Vector *vecNetworkOrigin = (Vector *)pOut; + + Assert( vecNetworkOrigin == &pEnt->m_vecNetworkOrigin ); + + pEnt->m_vecCellOrigin.x = pData->m_Value.m_Vector[0]; + pEnt->m_vecCellOrigin.y = pData->m_Value.m_Vector[1]; + pEnt->m_vecCellOrigin.z = pData->m_Value.m_Vector[2]; + + if ( pEnt->ShouldRegenerateOriginFromCellBits() ) + { + register int const cellwidth = pEnt->m_cellwidth; // Load it into a register + vecNetworkOrigin->x = CoordFromCell( cellwidth, pEnt->m_cellX, pData->m_Value.m_Vector[0] ); + vecNetworkOrigin->y = CoordFromCell( cellwidth, pEnt->m_cellY, pData->m_Value.m_Vector[1] ); + vecNetworkOrigin->z = CoordFromCell( cellwidth, pEnt->m_cellZ, pData->m_Value.m_Vector[2] ); + } +} + +void C_BaseEntity::RecvProxy_CellOriginXY( const CRecvProxyData *pData, void *pStruct, void *pOut ) +{ + CBaseEntity *pEnt = (CBaseEntity *)pStruct; + + Vector *vecNetworkOrigin = (Vector *)pOut; + + Assert( vecNetworkOrigin == &pEnt->m_vecNetworkOrigin ); + + pEnt->m_vecCellOrigin.x = pData->m_Value.m_Vector[0]; + pEnt->m_vecCellOrigin.y = pData->m_Value.m_Vector[1]; + + register int const cellwidth = pEnt->m_cellwidth; // Load it into a register + + if ( pEnt->ShouldRegenerateOriginFromCellBits() ) + { + vecNetworkOrigin->x = CoordFromCell( cellwidth, pEnt->m_cellX, pData->m_Value.m_Vector[0] ); + vecNetworkOrigin->y = CoordFromCell( cellwidth, pEnt->m_cellY, pData->m_Value.m_Vector[1] ); + } +} + +void C_BaseEntity::RecvProxy_CellOriginZ( const CRecvProxyData *pData, void *pStruct, void *pOut ) +{ + CBaseEntity *pEnt = (CBaseEntity *)pStruct; + + float *vecNetworkOriginZ = (float *)pOut; + + Assert( vecNetworkOriginZ == &pEnt->m_vecNetworkOrigin[2] ); + + pEnt->m_vecCellOrigin.z = pData->m_Value.m_Float; + + register int const cellwidth = pEnt->m_cellwidth; // Load it into a register + + if ( pEnt->ShouldRegenerateOriginFromCellBits() ) + { + *vecNetworkOriginZ = CoordFromCell( cellwidth, pEnt->m_cellZ, pData->m_Value.m_Float ); + } +} + void RecvProxy_LocalVelocity( const CRecvProxyData *pData, void *pStruct, void *pOut ) { CBaseEntity *pEnt = (CBaseEntity *)pStruct; @@ -387,6 +473,8 @@ void RecvProxy_ToolRecording( const CRecvProxyData *pData, void *pStruct, void * pEnt->SetToolRecording( pData->m_Value.m_Int != 0 ); } +#pragma optimize( "g", on ) + // Expose it to the engine. IMPLEMENT_CLIENTCLASS(C_BaseEntity, DT_BaseEntity, CBaseEntity); @@ -415,42 +503,58 @@ void RecvProxy_EffectFlags( const CRecvProxyData *pData, void *pStruct, void *pO ((C_BaseEntity*)pStruct)->SetEffects( pData->m_Value.m_Int ); } +void RecvProxy_ClrRender( const CRecvProxyData *pData, void *pStruct, void *pOut ) +{ + // This proxy will cause the alpha modulation to get updated correctly + C_BaseEntity *pEnt = (C_BaseEntity*)pStruct; + uint32 color = LittleDWord((uint32)pData->m_Value.m_Int); + color32 c = *(color32*)( &color ); + pEnt->SetRenderColor( c.r, c.g, c.b ); + pEnt->SetRenderAlpha( c.a ); +} BEGIN_RECV_TABLE_NOBASE( C_BaseEntity, DT_AnimTimeMustBeFirst ) RecvPropInt( RECVINFO(m_flAnimTime), 0, RecvProxy_AnimTime ), END_RECV_TABLE() +BEGIN_ENT_SCRIPTDESC_ROOT( C_BaseEntity, "Root class of all client-side entities" ) + DEFINE_SCRIPTFUNC_NAMED( GetAbsOrigin, "GetOrigin", "" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptGetForward, "GetForwardVector", "Get the forward vector of the entity" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptGetLeft, "GetLeftVector", "Get the left vector of the entity" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptGetUp, "GetUpVector", "Get the up vector of the entity" ) + DEFINE_SCRIPTFUNC( GetTeamNumber, "Gets this entity's team" ) +END_SCRIPTDESC(); -#ifndef NO_ENTITY_PREDICTION + +#if !defined( NO_ENTITY_PREDICTION ) && defined( USE_PREDICTABLEID ) BEGIN_RECV_TABLE_NOBASE( C_BaseEntity, DT_PredictableId ) RecvPropPredictableId( RECVINFO( m_PredictableID ) ), RecvPropInt( RECVINFO( m_bIsPlayerSimulated ) ), END_RECV_TABLE() #endif - BEGIN_RECV_TABLE_NOBASE(C_BaseEntity, DT_BaseEntity) RecvPropDataTable( "AnimTimeMustBeFirst", 0, 0, &REFERENCE_RECV_TABLE(DT_AnimTimeMustBeFirst) ), RecvPropInt( RECVINFO(m_flSimulationTime), 0, RecvProxy_SimulationTime ), - RecvPropInt( RECVINFO( m_ubInterpolationFrame ) ), - - RecvPropVector( RECVINFO_NAME( m_vecNetworkOrigin, m_vecOrigin ) ), + RecvPropFloat( RECVINFO( m_flCreateTime ) ), + + RecvPropInt( RECVINFO( m_cellbits ), 0, C_BaseEntity::RecvProxy_CellBits ), +// RecvPropArray( RecvPropInt( RECVINFO(m_cellXY[0]) ), m_cellXY ), + RecvPropInt( RECVINFO( m_cellX ), 0, C_BaseEntity::RecvProxy_CellX ), + RecvPropInt( RECVINFO( m_cellY ), 0, C_BaseEntity::RecvProxy_CellY ), + RecvPropInt( RECVINFO( m_cellZ ), 0, C_BaseEntity::RecvProxy_CellZ ), + RecvPropVector( RECVINFO_NAME( m_vecNetworkOrigin, m_vecOrigin ), 0, C_BaseEntity::RecvProxy_CellOrigin ), #if PREDICTION_ERROR_CHECK_LEVEL > 1 RecvPropVector( RECVINFO_NAME( m_angNetworkAngles, m_angRotation ) ), #else RecvPropQAngles( RECVINFO_NAME( m_angNetworkAngles, m_angRotation ) ), #endif - -#ifdef DEMO_BACKWARDCOMPATABILITY - RecvPropInt( RECVINFO(m_nModelIndex), 0, RecvProxy_IntToModelIndex16_BackCompatible ), -#else - RecvPropInt( RECVINFO(m_nModelIndex) ), -#endif + RecvPropInt(RECVINFO(m_nModelIndex) ), RecvPropInt(RECVINFO(m_fEffects), 0, RecvProxy_EffectFlags ), RecvPropInt(RECVINFO(m_nRenderMode)), RecvPropInt(RECVINFO(m_nRenderFX)), - RecvPropInt(RECVINFO(m_clrRender)), + RecvPropInt(RECVINFO(m_clrRender), 0, RecvProxy_ClrRender ), RecvPropInt(RECVINFO(m_iTeamNum)), RecvPropInt(RECVINFO(m_CollisionGroup)), RecvPropFloat(RECVINFO(m_flElasticity)), @@ -460,12 +564,20 @@ BEGIN_RECV_TABLE_NOBASE(C_BaseEntity, DT_BaseEntity) RecvPropInt( RECVINFO_NAME(m_hNetworkMoveParent, moveparent), 0, RecvProxy_IntToMoveParent ), RecvPropInt( RECVINFO( m_iParentAttachment ) ), + RecvPropString( RECVINFO( m_iName ) ), + + + RecvPropInt( "movetype", 0, SIZEOF_IGNORE, 0, RecvProxy_MoveType ), RecvPropInt( "movecollide", 0, SIZEOF_IGNORE, 0, RecvProxy_MoveCollide ), RecvPropDataTable( RECVINFO_DT( m_Collision ), 0, &REFERENCE_RECV_TABLE(DT_CollisionProperty) ), RecvPropInt( RECVINFO ( m_iTextureFrameIndex ) ), -#if !defined( NO_ENTITY_PREDICTION ) + + + +#if !defined( NO_ENTITY_PREDICTION ) && defined( USE_PREDICTABLEID ) + RecvPropEHandle (RECVINFO(m_hPlayerSimulationOwner)), RecvPropDataTable( "predictable_id", 0, 0, &REFERENCE_RECV_TABLE( DT_PredictableId ) ), #endif @@ -473,8 +585,16 @@ BEGIN_RECV_TABLE_NOBASE(C_BaseEntity, DT_BaseEntity) RecvPropInt ( RECVINFO( m_bAnimatedEveryTick ), 0, RecvProxy_InterpolationAmountChanged ), RecvPropBool ( RECVINFO( m_bAlternateSorting ) ), -#ifdef TF_CLIENT_DLL - RecvPropArray3( RECVINFO_ARRAY(m_nModelIndexOverrides), RecvPropInt( RECVINFO(m_nModelIndexOverrides[0]) ) ), + RecvPropFloat( RECVINFO( m_fadeMinDist ) ), + RecvPropFloat( RECVINFO( m_fadeMaxDist ) ), + RecvPropFloat( RECVINFO( m_flFadeScale ) ), + +#if 1 +// #ifndef _X360 -- X360 client and Win32 XLSP dedicated server need equivalent SendTables + RecvPropInt( RECVINFO( m_nMinCPULevel ) ), + RecvPropInt( RECVINFO( m_nMaxCPULevel ) ), + RecvPropInt( RECVINFO( m_nMinGPULevel ) ), + RecvPropInt( RECVINFO( m_nMaxGPULevel ) ), #endif END_RECV_TABLE() @@ -491,7 +611,7 @@ BEGIN_PREDICTION_DATA_NO_BASE( C_BaseEntity ) DEFINE_FIELD( m_vecAbsVelocity, FIELD_VECTOR ), DEFINE_PRED_FIELD_TOL( m_vecVelocity, FIELD_VECTOR, FTYPEDESC_INSENDTABLE, 0.5f ), -// DEFINE_PRED_FIELD( m_fEffects, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_fEffects, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ), DEFINE_PRED_FIELD( m_nRenderMode, FIELD_CHARACTER, FTYPEDESC_INSENDTABLE ), DEFINE_PRED_FIELD( m_nRenderFX, FIELD_CHARACTER, FTYPEDESC_INSENDTABLE ), // DEFINE_PRED_FIELD( m_flAnimTime, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ), @@ -501,6 +621,9 @@ BEGIN_PREDICTION_DATA_NO_BASE( C_BaseEntity ) DEFINE_PRED_FIELD( m_nModelIndex, FIELD_SHORT, FTYPEDESC_INSENDTABLE | FTYPEDESC_MODELINDEX ), DEFINE_PRED_FIELD( m_flFriction, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ), DEFINE_PRED_FIELD( m_iTeamNum, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ), +#ifndef INFESTED_DLL // alien swarm is temporarily unpredicting health to see if prediction is cause of a bug + DEFINE_FIELD( m_iHealth, FIELD_INTEGER ), +#endif DEFINE_PRED_FIELD( m_hOwnerEntity, FIELD_EHANDLE, FTYPEDESC_INSENDTABLE ), // DEFINE_FIELD( m_nSimulationTick, FIELD_INTEGER ), @@ -524,13 +647,17 @@ BEGIN_PREDICTION_DATA_NO_BASE( C_BaseEntity ) DEFINE_FIELD( m_vecAngVelocity, FIELD_VECTOR ), // DEFINE_FIELD( m_vecAbsAngVelocity, FIELD_VECTOR ), +// DEFINE_FIELD( m_nMinCPULevel, FIELD_CHARACTER ), +// DEFINE_FIELD( m_nMaxCPULevel, FIELD_CHARACTER ), +// DEFINE_FIELD( m_nMinGPULevel, FIELD_CHARACTER ), +// DEFINE_FIELD( m_nMaxGPULevel, FIELD_CHARACTER ), // DEFINE_FIELD( model, FIELD_INTEGER ), // writing pointer literally // DEFINE_FIELD( index, FIELD_INTEGER ), // DEFINE_FIELD( m_ClientHandle, FIELD_SHORT ), // DEFINE_FIELD( m_Partition, FIELD_SHORT ), // DEFINE_FIELD( m_hRender, FIELD_SHORT ), - DEFINE_FIELD( m_bDormant, FIELD_BOOLEAN ), +// DEFINE_FIELD( m_bDormant, FIELD_BOOLEAN ), // DEFINE_FIELD( current_position, FIELD_INTEGER ), // DEFINE_FIELD( m_flLastMessageTime, FIELD_FLOAT ), DEFINE_FIELD( m_vecBaseVelocity, FIELD_VECTOR ), @@ -539,8 +666,11 @@ BEGIN_PREDICTION_DATA_NO_BASE( C_BaseEntity ) // DEFINE_FIELD( m_ModelInstance, FIELD_SHORT ), DEFINE_FIELD( m_flProxyRandomValue, FIELD_FLOAT ), +#if defined( USE_PREDICTABLEID ) + DEFINE_PRED_FIELD( m_hPlayerSimulationOwner, FIELD_EHANDLE, FTYPEDESC_INSENDTABLE ), // DEFINE_FIELD( m_PredictableID, FIELD_INTEGER ), // DEFINE_FIELD( m_pPredictionContext, FIELD_POINTER ), +#endif // Stuff specific to rendering and therefore not to be copied back and forth // DEFINE_PRED_FIELD( m_clrRender, color32, FTYPEDESC_INSENDTABLE ), // DEFINE_FIELD( m_bReadyToDraw, FIELD_BOOLEAN ), @@ -807,13 +937,10 @@ void C_BaseEntity::Interp_SetupMappings( VarMapping_t *map ) void C_BaseEntity::Interp_RestoreToLastNetworked( VarMapping_t *map ) { - VPROF( "C_BaseEntity::Interp_RestoreToLastNetworked" ); - PREDICTION_TRACKVALUECHANGESCOPE_ENTITY( this, "restoretolastnetworked" ); Vector oldOrigin = GetLocalOrigin(); QAngle oldAngles = GetLocalAngles(); - Vector oldVel = GetLocalVelocity(); int c = map->m_Entries.Count(); for ( int i = 0; i < c; i++ ) @@ -823,7 +950,7 @@ void C_BaseEntity::Interp_RestoreToLastNetworked( VarMapping_t *map ) watcher->RestoreToLastNetworked(); } - BaseInterpolatePart2( oldOrigin, oldAngles, oldVel, 0 ); + BaseInterpolatePart2( oldOrigin, oldAngles, 0 ); } void C_BaseEntity::Interp_UpdateInterpolationAmounts( VarMapping_t *map ) @@ -889,24 +1016,24 @@ inline int C_BaseEntity::Interp_Interpolate( VarMapping_t *map, float currentTim //----------------------------------------------------------------------------- C_BaseEntity::C_BaseEntity() : m_iv_vecOrigin( "C_BaseEntity::m_iv_vecOrigin" ), - m_iv_angRotation( "C_BaseEntity::m_iv_angRotation" ), - m_iv_vecVelocity( "C_BaseEntity::m_iv_vecVelocity" ) + m_iv_angRotation( "C_BaseEntity::m_iv_angRotation" ) { AddVar( &m_vecOrigin, &m_iv_vecOrigin, LATCH_SIMULATION_VAR ); AddVar( &m_angRotation, &m_iv_angRotation, LATCH_SIMULATION_VAR ); - // Removing this until we figure out why velocity introduces view hitching. - // One possible fix is removing the player->ResetLatched() call in CGameMovement::FinishDuck(), - // but that re-introduces a third-person hitching bug. One possible cause is the abrupt change - // in player size/position that occurs when ducking, and how prediction tries to work through that. - // - // AddVar( &m_vecVelocity, &m_iv_vecVelocity, LATCH_SIMULATION_VAR ); + m_nMinCPULevel = m_nMaxCPULevel = 0; + m_nMinGPULevel = m_nMaxGPULevel = 0; + + m_flFadeScale = 0.0f; + m_fadeMinDist = m_fadeMaxDist = 0.0f; + m_pClientAlphaProperty = NULL; + m_nSplitUserPlayerPredictionSlot = 0; m_DataChangeEventRef = -1; m_EntClientFlags = 0; - m_bEnableRenderingClipPlane = false; - + m_bRenderWithViewModels = false; + m_bDisableCachedRenderBounds = false; m_iParentAttachment = 0; - m_nRenderFXBlend = 255; + m_bIsValidIKAttachment = false; SetPredictionEligible( false ); m_bPredictable = false; @@ -930,7 +1057,7 @@ C_BaseEntity::C_BaseEntity() : m_iCurrentThinkContext = NO_THINK_CONTEXT; #endif - + SetIdentityMatrix( m_rgflCoordinateFrame ); m_nSimulationTick = -1; // Assume drawing everything @@ -938,17 +1065,18 @@ C_BaseEntity::C_BaseEntity() : m_flProxyRandomValue = 0.0f; m_fBBoxVisFlags = 0; -#if !defined( NO_ENTITY_PREDICTION ) +#if !defined( NO_ENTITY_PREDICTION ) && defined( USE_PREDICTABLEID ) m_pPredictionContext = NULL; #endif - //NOTE: not virtual! we are in the constructor! - C_BaseEntity::Clear(); + + for ( int i = 0; i < NUM_ENTITY_LISTS; i++ ) + { + m_ListEntry[i] = 0xFFFF; + } + AddToEntityList( ENTITY_LIST_PRERENDER ); - SetModelName( NULL_STRING ); - m_iClassname = NULL_STRING; - m_InterpolationListEntry = 0xFFFF; - m_TeleportListEntry = 0xFFFF; + Clear(); #ifndef NO_TOOLFRAMEWORK m_bEnabledInToolView = true; @@ -958,13 +1086,24 @@ C_BaseEntity::C_BaseEntity() : m_bRecordInTools = true; #endif -#ifdef TF_CLIENT_DLL - m_bValidatedOwner = false; - m_bDeemedInvalid = false; - m_bWasDeemedInvalid = false; -#endif - ParticleProp()->Init( this ); + + m_spawnflags = 0; + + m_flCreateTime = 0.0f; +} + + +//----------------------------------------------------------------------------- +// Deallocates the alpha property +//----------------------------------------------------------------------------- +void C_BaseEntity::CleanUpAlphaProperty() +{ + if ( m_pClientAlphaProperty ) + { + g_pClientAlphaPropertyMgr->DestroyClientAlphaProperty( m_pClientAlphaProperty ); + m_pClientAlphaProperty = NULL; + } } @@ -976,17 +1115,21 @@ C_BaseEntity::C_BaseEntity() : C_BaseEntity::~C_BaseEntity() { Term(); + CleanUpAlphaProperty(); ClearDataChangedEvent( m_DataChangeEventRef ); -#if !defined( NO_ENTITY_PREDICTION ) +#if !defined( NO_ENTITY_PREDICTION ) && defined( USE_PREDICTABLEID ) delete m_pPredictionContext; #endif - RemoveFromInterpolationList(); - RemoveFromTeleportList(); + for ( int i = 0; i < NUM_ENTITY_LISTS; i++ ) + { + RemoveFromEntityList(entity_list_ids_t(i)); + } } void C_BaseEntity::Clear( void ) { m_bDormant = true; + m_nCreationTick = -1; m_RefEHandle.Term(); m_ModelInstance = MODEL_INSTANCE_INVALID; @@ -997,10 +1140,11 @@ void C_BaseEntity::Clear( void ) index = -1; m_Collision.Init( this ); + CleanUpAlphaProperty(); + m_pClientAlphaProperty = static_cast< CClientAlphaProperty * >( g_pClientAlphaPropertyMgr->CreateClientAlphaProperty( this ) ); SetLocalOrigin( vec3_origin ); SetLocalAngles( vec3_angle ); model = NULL; - m_pOriginalData = NULL; m_vecAbsOrigin.Init(); m_angAbsRotation.Init(); m_vecVelocity.Init(); @@ -1019,8 +1163,9 @@ void C_BaseEntity::Clear( void ) m_iEFlags = 0; m_nRenderMode = 0; m_nOldRenderMode = 0; - SetRenderColor( 255, 255, 255, 255 ); - m_nRenderFX = 0; + SetRenderColor( 255, 255, 255 ); + SetRenderAlpha( 255 ); + SetRenderFX( kRenderFxNone ); m_flFriction = 0.0f; m_flGravity = 0.0f; SetCheckUntouch( false ); @@ -1028,13 +1173,13 @@ void C_BaseEntity::Clear( void ) m_nLastThinkTick = gpGlobals->tickcount; -#if defined(SIXENSE) + // TrackIR m_vecEyeOffset.Init(); m_EyeAngleOffset.Init(); -#endif + // TrackIR // Remove prediction context if it exists -#if !defined( NO_ENTITY_PREDICTION ) +#if !defined( NO_ENTITY_PREDICTION ) && defined( USE_PREDICTABLEID ) delete m_pPredictionContext; m_pPredictionContext = NULL; #endif @@ -1045,6 +1190,15 @@ void C_BaseEntity::Clear( void ) UpdateVisibility(); } +//----------------------------------------------------------------------------- +// IClientUnknown +//----------------------------------------------------------------------------- +IClientAlphaProperty* C_BaseEntity::GetClientAlphaProperty() +{ + return m_pClientAlphaProperty; +} + + //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- @@ -1083,22 +1237,27 @@ bool C_BaseEntity::Init( int entnum, int iSerialNum ) Assert( entnum >= 0 && entnum < NUM_ENT_ENTRIES ); index = entnum; + m_pClientAlphaProperty->SetDesyncOffset( index ); cl_entitylist->AddNetworkableEntity( GetIClientUnknown(), entnum, iSerialNum ); CollisionProp()->CreatePartitionHandle(); + InitSharedVars(); + Interp_SetupMappings( GetVarMapping() ); m_nCreationTick = gpGlobals->tickcount; + m_hScriptInstance = NULL; + return true; } - + //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- -bool C_BaseEntity::InitializeAsClientEntity( const char *pszModelName, RenderGroup_t renderGroup ) +bool C_BaseEntity::InitializeAsClientEntity( const char *pszModelName, bool bRenderWithViewModels ) { int nModelIndex; @@ -1120,29 +1279,30 @@ bool C_BaseEntity::InitializeAsClientEntity( const char *pszModelName, RenderGro Interp_SetupMappings( GetVarMapping() ); - return InitializeAsClientEntityByIndex( nModelIndex, renderGroup ); + return InitializeAsClientEntityByIndex( nModelIndex, bRenderWithViewModels ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- -bool C_BaseEntity::InitializeAsClientEntityByIndex( int iIndex, RenderGroup_t renderGroup ) +bool C_BaseEntity::InitializeAsClientEntityByIndex( int iIndex, bool bRenderWithViewModels ) { - index = -1; - // Setup model data. + RenderWithViewModels( bRenderWithViewModels ); + + // NOTE: This will add the client entity to the renderable "leaf system" (Renderable) SetModelByIndex( iIndex ); // Add the client entity to the master entity list. cl_entitylist->AddNonNetworkableEntity( GetIClientUnknown() ); Assert( GetClientHandle() != ClientEntityList().InvalidHandle() ); - // Add the client entity to the renderable "leaf system." (Renderable) - AddToLeafSystem( renderGroup ); - // Add the client entity to the spatial partition. (Collidable) CollisionProp()->CreatePartitionHandle(); + index = -1; + m_pClientAlphaProperty->SetDesyncOffset( rand() % 1024 ); + SpawnClientEntity(); return true; @@ -1159,13 +1319,16 @@ void C_BaseEntity::Term() // Remove from the predictables list if ( GetPredictable() || IsClientCreated() ) { - g_Predictables.RemoveFromPredictablesList( GetClientHandle() ); + for ( int i = 0; i < MAX_SPLITSCREEN_PLAYERS; ++i ) + { + GetPredictables( i )->RemoveFromPredictablesList( this ); + } } // If it's play simulated, remove from simulation list if the player still exists... - if ( IsPlayerSimulated() && C_BasePlayer::GetLocalPlayer() ) + if ( IsPlayerSimulated() ) { - C_BasePlayer::GetLocalPlayer()->RemoveFromPlayerSimulationList( this ); + UnsetPlayerSimulated(); } #endif @@ -1198,6 +1361,12 @@ void C_BaseEntity::Term() RemoveFromLeafSystem(); RemoveFromAimEntsList(); + + if ( m_hScriptInstance ) + { + g_pScriptVM->RemoveInstance( m_hScriptInstance ); + m_hScriptInstance = NULL; + } } @@ -1268,6 +1437,79 @@ void C_BaseEntity::SetRemovalFlag( bool bRemove ) } +//----------------------------------------------------------------------------- +// Alpha +//----------------------------------------------------------------------------- +void C_BaseEntity::SetRenderAlpha( byte a ) +{ + if ( m_clrRender.GetA() != a ) + { + m_clrRender.SetA( a ); + m_pClientAlphaProperty->SetAlphaModulation( a ); + } +} + +byte C_BaseEntity::GetRenderAlpha() const +{ + return m_pClientAlphaProperty->GetAlphaModulation( ); +} + + +//----------------------------------------------------------------------------- +// Methods related to fade scale +//----------------------------------------------------------------------------- +float C_BaseEntity::GetMinFadeDist( ) const +{ + return m_fadeMinDist; +} + +float C_BaseEntity::GetMaxFadeDist( ) const +{ + return m_fadeMaxDist; +} + +void C_BaseEntity::SetDistanceFade( float flMinDist, float flMaxDist ) +{ + m_fadeMinDist = flMinDist; + m_fadeMaxDist = flMaxDist; + + // NOTE: Setting the fade will not necessarily produce the same values + // as what was passed in. I'm deliberately choosing not to grab them back out + // because I'm not sure what client logic depends on them being negative, for example + + // Specifically, I'm certain the loading logic in C_PhysPropClientside, + // as well as code inside of C_PhysPropClientside::Initialize + // will definitely not work unless I'm doing it the way I'm currently doing it. + AlphaProp()->SetFade( m_flFadeScale, m_fadeMinDist, m_fadeMaxDist ); +} + +void C_BaseEntity::SetGlobalFadeScale( float flFadeScale ) +{ + m_flFadeScale = flFadeScale; + int modelType = modelinfo->GetModelType( model ); + if ( modelType == mod_studio ) + { + MDLCACHE_CRITICAL_SECTION(); + MDLHandle_t hStudioHdr = modelinfo->GetCacheHandle( model ); + if ( hStudioHdr != MDLHANDLE_INVALID ) + { + const studiohdr_t *pStudioHdr = mdlcache->LockStudioHdr( hStudioHdr ); + if ( pStudioHdr->flags & STUDIOHDR_FLAGS_NO_FORCED_FADE ) + { + flFadeScale = 0.0f; + } + mdlcache->UnlockStudioHdr( hStudioHdr ); + } + } + AlphaProp()->SetFade( flFadeScale, m_fadeMinDist, m_fadeMaxDist ); +} + +float C_BaseEntity::GetGlobalFadeScale( ) const +{ + return m_flFadeScale; +} + + //----------------------------------------------------------------------------- // VPhysics objects.. //----------------------------------------------------------------------------- @@ -1344,59 +1586,79 @@ void C_BaseEntity::GetVectors(Vector* pForward, Vector* pRight, Vector* pUp) con } } -void C_BaseEntity::UpdateVisibility() + +void C_BaseEntity::UpdateVisibilityAllEntities() { -#ifdef TF_CLIENT_DLL - // TF prevents drawing of any entity attached to players that aren't items in the inventory of the player. - // This is to prevent servers creating fake cosmetic items and attaching them to players. - if ( !engine->IsPlayingDemo() ) + C_BaseEntityIterator iterator; + C_BaseEntity *pEnt; + while ( (pEnt = iterator.Next()) != NULL ) { - static bool bIsStaging = ( engine->GetAppID() == 810 ); - if ( !m_bValidatedOwner ) - { - bool bRetry = false; + pEnt->UpdateVisibility(); + } +} - // Check it the first time we call update visibility (Source TV doesn't bother doing validation) - m_bDeemedInvalid = engine->IsHLTV() ? false : !ValidateEntityAttachedToPlayer( bRetry ); - m_bValidatedOwner = !bRetry; - } +// (static function) +CON_COMMAND( cl_updatevisibility, "Updates visibility bits." ) +{ + C_BaseEntity::UpdateVisibilityAllEntities(); +} + +void C_BaseEntity::RenderWithViewModels( bool bEnable ) +{ + m_bRenderWithViewModels = bEnable; + g_pClientLeafSystem->RenderWithViewModels( m_hRender, bEnable ); +} - if ( m_bDeemedInvalid ) - { - if ( bIsStaging ) - { - if ( !m_bWasDeemedInvalid ) - { - m_PreviousRenderMode = GetRenderMode(); - m_PreviousRenderColor = GetRenderColor(); - m_bWasDeemedInvalid = true; - } +bool C_BaseEntity::IsRenderingWithViewModels() const +{ + Assert( ( m_hRender == INVALID_CLIENT_RENDER_HANDLE ) || + ( m_bRenderWithViewModels == g_pClientLeafSystem->IsRenderingWithViewModels( m_hRender ) ) ); + return m_bRenderWithViewModels; +} - SetRenderMode( kRenderTransColor ); - SetRenderColor( 255, 0, 0, 200 ); +void C_BaseEntity::DisableCachedRenderBounds( bool bDisabled ) +{ + m_bDisableCachedRenderBounds = bDisabled; + g_pClientLeafSystem->DisableCachedRenderBounds( m_hRender, bDisabled ); +} - } - else - { - RemoveFromLeafSystem(); - return; - } - } - else if ( m_bWasDeemedInvalid ) - { - if ( bIsStaging ) - { - // We need to fix up the rendering. - SetRenderMode( m_PreviousRenderMode ); - SetRenderColor( m_PreviousRenderColor.r, m_PreviousRenderColor.g, m_PreviousRenderColor.b, m_PreviousRenderColor.a ); - } +bool C_BaseEntity::IsCachedRenderBoundsDisabled() const +{ + return m_bDisableCachedRenderBounds; +} + +void C_BaseEntity::UpdateVisibility() +{ +#if MAX_SPLITSCREEN_PLAYERS > 1 + uint32 nPreviousValue = m_VisibilityBits.GetDWord( 0 ); +#endif - m_bWasDeemedInvalid = false; + m_VisibilityBits.ClearAll(); + int nBitsSet = 0; + + C_BasePlayer::SetRemoteSplitScreenPlayerViewsAreLocalPlayer( true ); + IterateRemoteSplitScreenViewSlots_Push( true ); + FOR_EACH_VALID_SPLITSCREEN_PLAYER( hh ) + { + ACTIVE_SPLITSCREEN_PLAYER_GUARD( hh ); + bool bDraw = ( ShouldDraw() && !IsDormant() && ( !ToolsEnabled() || IsEnabledInToolView() ) ); + if ( bDraw ) + { + m_VisibilityBits.Set( hh ); + ++nBitsSet; } } + IterateRemoteSplitScreenViewSlots_Pop(); + C_BasePlayer::SetRemoteSplitScreenPlayerViewsAreLocalPlayer( false ); + +#if MAX_SPLITSCREEN_PLAYERS > 1 + if ( nPreviousValue != m_VisibilityBits.GetDWord( 0 ) ) + { + OnSplitscreenRenderingChanged(); + } #endif - if ( ShouldDraw() && !IsDormant() && ( !ToolsEnabled() || IsEnabledInToolView() ) ) + if ( nBitsSet > 0 ) { // add/update leafsystem AddToLeafSystem(); @@ -1408,22 +1670,37 @@ void C_BaseEntity::UpdateVisibility() } } +bool C_BaseEntity::ShouldDrawForSplitScreenUser( int nSlot ) +{ + return m_VisibilityBits.IsBitSet( nSlot ); +} + //----------------------------------------------------------------------------- // Purpose: Returns whether object should render. //----------------------------------------------------------------------------- bool C_BaseEntity::ShouldDraw() { -// Only test this in tf2 -#if defined( INVASION_CLIENT_DLL ) - // Let the client mode (like commander mode) reject drawing entities. - if (g_pClientMode && !g_pClientMode->ShouldDrawEntity(this) ) - return false; -#endif + // Some rendermodes prevent rendering if ( m_nRenderMode == kRenderNone ) return false; + if ( !IsX360() ) + { + CPULevel_t nCPULevel = GetCPULevel(); + bool bNoDraw = ( m_nMinCPULevel && m_nMinCPULevel-1 > nCPULevel ); + bNoDraw = bNoDraw || ( m_nMaxCPULevel && m_nMaxCPULevel-1 < nCPULevel ); + if ( bNoDraw ) + return false; + + GPULevel_t nGPULevel = GetGPULevel(); + bNoDraw = ( m_nMinGPULevel && m_nMinGPULevel-1 > nGPULevel ); + bNoDraw = bNoDraw || ( m_nMaxGPULevel && m_nMaxGPULevel-1 < nGPULevel ); + if ( bNoDraw ) + return false; + } + return (model != 0) && !IsEffectActive(EF_NODRAW) && (index != 0); } @@ -1547,9 +1824,9 @@ bool C_BaseEntity::ShouldReceiveProjectedTextures( int flags ) if ( IsEffectActive( EF_NODRAW ) ) return false; - if( flags & SHADOW_FLAGS_FLASHLIGHT ) + if( ( flags & ( SHADOW_FLAGS_FLASHLIGHT | SHADOW_FLAGS_SIMPLE_PROJECTION ) ) != 0 ) { - if ( GetRenderMode() > kRenderNormal && GetRenderColor().a == 0 ) + if ( GetRenderMode() > kRenderNormal && GetRenderAlpha() == 0 ) return false; return true; @@ -1710,7 +1987,7 @@ void C_BaseEntity::GetShadowRenderBounds( Vector &mins, Vector &maxs, ShadowType //----------------------------------------------------------------------------- const Vector& C_BaseEntity::GetAbsOrigin( void ) const { - //Assert( s_bAbsQueriesValid ); + Assert( s_bAbsQueriesValid ); const_cast(this)->CalcAbsolutePosition(); return m_vecAbsOrigin; } @@ -1722,7 +1999,7 @@ const Vector& C_BaseEntity::GetAbsOrigin( void ) const //----------------------------------------------------------------------------- const QAngle& C_BaseEntity::GetAbsAngles( void ) const { - //Assert( s_bAbsQueriesValid ); + Assert( s_bAbsQueriesValid ); const_cast(this)->CalcAbsolutePosition(); return m_angAbsRotation; } @@ -1745,6 +2022,46 @@ void C_BaseEntity::SetNetworkAngles( const QAngle& ang ) m_angNetworkAngles = ang; } +//----------------------------------------------------------------------------- +// Purpose: +// Output : const Vector& +//----------------------------------------------------------------------------- +const Vector& C_BaseEntity::GetNetworkOrigin() const +{ + return m_vecNetworkOrigin; +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Output : const QAngle& +//----------------------------------------------------------------------------- +const QAngle& C_BaseEntity::GetNetworkAngles() const +{ + return m_angNetworkAngles; +} + + +//----------------------------------------------------------------------------- +// Purpose: Get current model pointer for this entity +// Output : const struct model_s +//----------------------------------------------------------------------------- +const model_t *C_BaseEntity::GetModel( void ) const +{ + return model; +} + + + +//----------------------------------------------------------------------------- +// Purpose: Get model index for this entity +// Output : int - model index +//----------------------------------------------------------------------------- +int C_BaseEntity::GetModelIndex( void ) const +{ + return m_nModelIndex; +} + //----------------------------------------------------------------------------- // Purpose: // Input : index - @@ -1763,7 +2080,6 @@ void C_BaseEntity::SetModelPointer( const model_t *pModel ) DestroyModelInstance(); model = pModel; OnNewModel(); - UpdateVisibility(); } } @@ -1794,35 +2110,46 @@ void C_BaseEntity::SetMoveCollide( MoveCollide_t val ) //----------------------------------------------------------------------------- -// Purpose: Get rendermode -// Output : int - the render mode +// Default implementation of compute translucency type //----------------------------------------------------------------------------- -bool C_BaseEntity::IsTransparent( void ) +RenderableTranslucencyType_t C_BaseEntity::ComputeTranslucencyType() { - bool modelIsTransparent = modelinfo->IsTranslucent(model); - return modelIsTransparent || (m_nRenderMode != kRenderNormal); + if ( m_bIsBlurred ) + return RENDERABLE_IS_TRANSLUCENT; + return modelinfo->ComputeTranslucencyType( model, GetSkin(), GetBody() ); } -bool C_BaseEntity::IsTwoPass( void ) -{ - return modelinfo->IsTranslucentTwoPass( GetModel() ); -} -bool C_BaseEntity::UsesPowerOfTwoFrameBufferTexture() +//----------------------------------------------------------------------------- +// Client code should call this under any circumstances where translucency type may change +//----------------------------------------------------------------------------- +void C_BaseEntity::OnTranslucencyTypeChanged() { - return false; + if ( m_hRender != INVALID_CLIENT_RENDER_HANDLE ) + { + g_pClientLeafSystem->SetTranslucencyType( m_hRender, ComputeTranslucencyType() ); + } } -bool C_BaseEntity::UsesFullFrameBufferTexture() + +//----------------------------------------------------------------------------- +// Client code should call this under any circumstances where splitscreen rendering may change +//----------------------------------------------------------------------------- +void C_BaseEntity::OnSplitscreenRenderingChanged() { - return false; + if ( IsSplitScreenSupported() && ( m_hRender != INVALID_CLIENT_RENDER_HANDLE ) ) + { + g_pClientLeafSystem->EnableSplitscreenRendering( m_hRender, ComputeSplitscreenRenderingFlags( this ) ); + } } -bool C_BaseEntity::IgnoresZBuffer( void ) const + +int C_BaseEntity::GetRenderFlags( void ) { - return m_nRenderMode == kRenderGlow || m_nRenderMode == kRenderWorldGlow; + return 0; } + //----------------------------------------------------------------------------- // Purpose: Get pointer to CMouthInfo data // Output : CMouthInfo @@ -1933,34 +2260,19 @@ float *C_BaseEntity::GetRenderClipPlane( void ) //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- -int C_BaseEntity::DrawBrushModel( bool bDrawingTranslucency, int nFlags, bool bTwoPass ) +int C_BaseEntity::DrawBrushModel( bool bSort, bool bShadowDepth ) { VPROF_BUDGET( "C_BaseEntity::DrawBrushModel", VPROF_BUDGETGROUP_BRUSHMODEL_RENDERING ); // Identity brushes are drawn in view->DrawWorld as an optimization Assert ( modelinfo->GetModelType( model ) == mod_brush ); - ERenderDepthMode DepthMode = DEPTH_MODE_NORMAL; - if ( ( nFlags & STUDIO_SSAODEPTHTEXTURE ) != 0 ) - { - DepthMode = DEPTH_MODE_SSA0; - } - else if ( ( nFlags & STUDIO_SHADOWDEPTHTEXTURE ) != 0 ) - { - DepthMode = DEPTH_MODE_SHADOW; - } - - if ( DepthMode != DEPTH_MODE_NORMAL ) + if ( bShadowDepth ) { - render->DrawBrushModelShadowDepth( this, (model_t *)model, GetAbsOrigin(), GetAbsAngles(), DepthMode ); + render->DrawBrushModelShadowDepth( this, (model_t *)model, GetAbsOrigin(), GetAbsAngles(), bSort ); } else { - DrawBrushModelMode_t mode = DBM_DRAW_ALL; - if ( bTwoPass ) - { - mode = bDrawingTranslucency ? DBM_DRAW_TRANSLUCENT_ONLY : DBM_DRAW_OPAQUE_ONLY; - } - render->DrawBrushModelEx( this, (model_t *)model, GetAbsOrigin(), GetAbsAngles(), mode ); + render->DrawBrushModel( this, (model_t *)model, GetAbsOrigin(), GetAbsAngles(), bSort ); } return 1; @@ -1970,7 +2282,7 @@ int C_BaseEntity::DrawBrushModel( bool bDrawingTranslucency, int nFlags, bool bT // Purpose: Draws the object // Input : flags - //----------------------------------------------------------------------------- -int C_BaseEntity::DrawModel( int flags ) +int C_BaseEntity::DrawModel( int flags, const RenderableInstance_t &instance ) { if ( !m_bReadyToDraw ) return 0; @@ -1985,7 +2297,8 @@ int C_BaseEntity::DrawModel( int flags ) switch ( modelType ) { case mod_brush: - drawn = DrawBrushModel( flags & STUDIO_TRANSPARENCY ? true : false, flags, ( flags & STUDIO_TWOPASS ) ? true : false ); + render->SetBlend( ( flags & STUDIO_SHADOWDEPTHTEXTURE ) ? 1.0f : (float)instance.m_nAlpha * ( 1.0f / 255.0f ) ); + drawn = DrawBrushModel( flags & STUDIO_TRANSPARENCY ? true : false, flags & STUDIO_SHADOWDEPTHTEXTURE ? true : false ); break; case mod_studio: // All studio models must be derived from C_BaseAnimating. Issue warning. @@ -2009,7 +2322,7 @@ int C_BaseEntity::DrawModel( int flags ) //----------------------------------------------------------------------------- // Purpose: Setup the bones for drawing //----------------------------------------------------------------------------- -bool C_BaseEntity::SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime ) +bool C_BaseEntity::SetupBones( matrix3x4a_t *pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime ) { return true; } @@ -2042,8 +2355,13 @@ void C_BaseEntity::UpdatePartitionListEntry() else if (shouldCollide == ENTITY_SHOULD_RESPOND) list |= PARTITION_CLIENT_RESPONSIVE_EDICTS; + if ( m_bIsValidIKAttachment ) + { + list |= PARTITION_CLIENT_IK_ATTACHMENT; + } + // add the entity to the KD tree so we will collide against it - partition->RemoveAndInsert( PARTITION_CLIENT_SOLID_EDICTS | PARTITION_CLIENT_RESPONSIVE_EDICTS | PARTITION_CLIENT_NON_STATIC_EDICTS, list, CollisionProp()->GetPartitionHandle() ); + partition->RemoveAndInsert( PARTITION_CLIENT_SOLID_EDICTS | PARTITION_CLIENT_RESPONSIVE_EDICTS | PARTITION_CLIENT_NON_STATIC_EDICTS | PARTITION_CLIENT_IK_ATTACHMENT, list, CollisionProp()->GetPartitionHandle() ); } @@ -2063,7 +2381,7 @@ void C_BaseEntity::NotifyShouldTransmit( ShouldTransmitState_t state ) UpdatePartitionListEntry(); -#if !defined( NO_ENTITY_PREDICTION ) +#if !defined( NO_ENTITY_PREDICTION ) && defined( USE_PREDICTABLEID ) // Note that predictables get a chance to hook up to their server counterparts here if ( m_PredictableID.IsActive() ) { @@ -2125,8 +2443,6 @@ void C_BaseEntity::MarkMessageReceived() //----------------------------------------------------------------------------- void C_BaseEntity::PreDataUpdate( DataUpdateType_t updateType ) { - VPROF( "C_BaseEntity::PreDataUpdate" ); - // Register for an OnDataChanged call and call OnPreDataChanged(). if ( AddDataChangeEvent( this, updateType, &m_DataChangeEventRef ) ) { @@ -2171,8 +2487,6 @@ void C_BaseEntity::PreDataUpdate( DataUpdateType_t updateType ) { ClientLeafSystem()->EnableAlternateSorting( m_hRender, m_bAlternateSorting ); } - - m_ubOldInterpolationFrame = m_ubInterpolationFrame; } const Vector& C_BaseEntity::GetOldOrigin() @@ -2378,9 +2692,23 @@ void C_BaseEntity::HierarchySetParent( C_BaseEntity *pNewParent ) InvalidatePhysicsRecursive( POSITION_CHANGED | ANGLES_CHANGED | VELOCITY_CHANGED ); -#ifdef TF_CLIENT_DLL - m_bValidatedOwner = false; -#endif + // iterate the hierarchy using a ring buffer + CBaseEntity *list[1024]; // assume power of 2 elements + int listReadIndex = 0; + int listWriteIndex = 1; + list[0] = this; + + while ( listReadIndex != listWriteIndex ) + { + CBaseEntity *pParent = list[listReadIndex]; + pParent->InvalidateAttachments(); + listReadIndex = (listReadIndex+1) & (ARRAYSIZE(list)-1); + for (CBaseEntity *pChild = pParent->FirstMoveChild(); pChild; pChild = pChild->NextMovePeer()) + { + list[listWriteIndex] = pChild; + listWriteIndex = (listWriteIndex+1) & (ARRAYSIZE(list)-1); + } + } } @@ -2412,11 +2740,6 @@ void C_BaseEntity::SetParent( C_BaseEntity *pParentEntity, int iParentAttachment LinkChild( pParentEntity, this ); } - if ( !IsServerEntity() ) - { - m_hNetworkMoveParent = pParentEntity; - } - m_iParentAttachment = iParentAttachment; m_vecAbsOrigin.Init( FLT_MAX, FLT_MAX, FLT_MAX ); @@ -2469,57 +2792,24 @@ void C_BaseEntity::UnlinkFromHierarchy() //----------------------------------------------------------------------------- void C_BaseEntity::ValidateModelIndex( void ) { -#ifdef TF_CLIENT_DLL - if ( m_nModelIndexOverrides[VISION_MODE_NONE] > 0 ) - { - if ( IsLocalPlayerUsingVisionFilterFlags( TF_VISION_FILTER_HALLOWEEN ) ) - { - if ( m_nModelIndexOverrides[VISION_MODE_HALLOWEEN] > 0 ) - { - SetModelByIndex( m_nModelIndexOverrides[VISION_MODE_HALLOWEEN] ); - return; - } - } - - if ( IsLocalPlayerUsingVisionFilterFlags( TF_VISION_FILTER_PYRO ) ) - { - if ( m_nModelIndexOverrides[VISION_MODE_PYRO] > 0 ) - { - SetModelByIndex( m_nModelIndexOverrides[VISION_MODE_PYRO] ); - return; - } - } - - if ( IsLocalPlayerUsingVisionFilterFlags( TF_VISION_FILTER_ROME ) ) - { - if ( m_nModelIndexOverrides[VISION_MODE_ROME] > 0 ) - { - SetModelByIndex( m_nModelIndexOverrides[VISION_MODE_ROME] ); - return; - } - } - - SetModelByIndex( m_nModelIndexOverrides[VISION_MODE_NONE] ); - - return; - } -#endif - SetModelByIndex( m_nModelIndex ); } +bool C_BaseEntity::IsParentChanging() +{ + return ( m_hNetworkMoveParent.ToInt() != m_pMoveParent.ToInt() ); +} + //----------------------------------------------------------------------------- // Purpose: Entity data has been parsed and unpacked. Now do any necessary decoding, munging // Input : bnewentity - was this entity new in this update packet? //----------------------------------------------------------------------------- void C_BaseEntity::PostDataUpdate( DataUpdateType_t updateType ) { - MDLCACHE_CRITICAL_SECTION(); - PREDICTION_TRACKVALUECHANGESCOPE_ENTITY( this, "postdataupdate" ); // NOTE: This *has* to happen first. Otherwise, Origin + angles may be wrong - if ( m_nRenderFX == kRenderFxRagdoll && updateType == DATA_UPDATE_CREATED ) + if ( m_bClientSideRagdoll && updateType == DATA_UPDATE_CREATED ) { MoveToLastReceivedPosition( true ); } @@ -2598,16 +2888,13 @@ void C_BaseEntity::PostDataUpdate( DataUpdateType_t updateType ) CheckInitPredictable( "PostDataUpdate" ); +#if !defined( NO_ENTITY_PREDICTION ) // It's possible that a new entity will need to be forceably added to the // player simulation list. If so, do this here -#if !defined( NO_ENTITY_PREDICTION ) - C_BasePlayer *local = C_BasePlayer::GetLocalPlayer(); - if ( IsPlayerSimulated() && - ( NULL != local ) && - ( local == m_hOwnerEntity ) ) + if ( IsPlayerSimulated() && C_BasePlayer::IsLocalPlayer( m_hPlayerSimulationOwner ) ) { // Make sure player is driving simulation (field is only ever sent to local player) - SetPlayerSimulated( local ); + SetPlayerSimulated( ToBasePlayer( m_hPlayerSimulationOwner ) ); } #endif @@ -2616,8 +2903,8 @@ void C_BaseEntity::PostDataUpdate( DataUpdateType_t updateType ) // Add the entity to the nointerp list. if ( !IsClientCreated() ) { - if ( Teleported() || IsNoInterpolationFrame() ) - AddToTeleportList(); + if ( Teleported() || IsEffectActive(EF_NOINTERP) ) + AddToEntityList(ENTITY_LIST_TELEPORT); } // if we changed parents, recalculate visibility @@ -2634,24 +2921,34 @@ void C_BaseEntity::PostDataUpdate( DataUpdateType_t updateType ) void C_BaseEntity::CheckInitPredictable( const char *context ) { #if !defined( NO_ENTITY_PREDICTION ) + if ( !ShouldPredict() ) + return; + // Prediction is disabled if ( !cl_predict->GetInt() ) return; - C_BasePlayer *player = C_BasePlayer::GetLocalPlayer(); - - if ( !player ) + if ( !C_BasePlayer::HasAnyLocalPlayer() ) return; if ( !GetPredictionEligible() ) { - if ( m_PredictableID.IsActive() && - ( player->index - 1 ) == m_PredictableID.GetPlayer() ) + bool bOkay = false; +#if defined( USE_PREDICTABLEID ) + FOR_EACH_VALID_SPLITSCREEN_PLAYER( i ) { - // If it comes through with an ID, it should be eligible - SetPredictionEligible( true ); + int nIndex = engine->GetSplitScreenPlayer( i ); + + if ( m_PredictableID.IsActive() && + ( nIndex - 1 ) == m_PredictableID.GetPlayer() ) + { + // If it comes through with an ID, it should be eligible + SetPredictionEligible( true ); + bOkay = true; + } } - else +#endif + if ( !bOkay ) { return; } @@ -2660,18 +2957,42 @@ void C_BaseEntity::CheckInitPredictable( const char *context ) if ( IsClientCreated() ) return; - if ( !ShouldPredict() ) - return; - if ( IsIntermediateDataAllocated() ) return; // Msg( "Predicting init %s at %s\n", GetClassname(), context ); - InitPredictable(); + // It's either a player, a weapon or a view model + C_BasePlayer *pOwner = GetPredictionOwner(); + Assert( pOwner ); + if ( !pOwner ) + return; + + InitPredictable( pOwner ); #endif } +//----------------------------------------------------------------------------- +// Purpose: Return the player who will predict this entity +//----------------------------------------------------------------------------- +C_BasePlayer* C_BaseEntity::GetPredictionOwner() +{ + C_BasePlayer *pOwner = ToBasePlayer( this ); + if ( !pOwner ) + { + pOwner = ToBasePlayer( GetOwnerEntity() ); + if ( !pOwner ) + { + C_BaseViewModel *vm = ToBaseViewModel(this); + if ( vm ) + { + pOwner = ToBasePlayer( vm->GetOwner() ); + } + } + } + return pOwner; +} + bool C_BaseEntity::IsSelfAnimating() { return true; @@ -2727,7 +3048,7 @@ void C_BaseEntity::OnStoreLastNetworkedValue() // Kind of a hack, but we want to latch the actual networked value for origin/angles, not what's sitting in m_vecOrigin in the // ragdoll case where we don't copy it over in MoveToLastNetworkOrigin - if ( m_nRenderFX == kRenderFxRagdoll && GetPredictable() ) + if ( m_bClientSideRagdoll && GetPredictable() ) { bRestore = true; savePos = GetLocalOrigin(); @@ -2785,17 +3106,17 @@ void C_BaseEntity::OnLatchInterpolatedVariables( int flags ) if ( type & EXCLUDE_AUTO_LATCH ) continue; - if ( watcher->NoteChanged( changetime, bUpdateLastNetworkedValue ) ) + if ( watcher->NoteChanged( gpGlobals->curtime, changetime, bUpdateLastNetworkedValue ) ) e->m_bNeedsToInterpolate = true; } if ( ShouldInterpolate() ) { - AddToInterpolationList(); + AddToEntityList(ENTITY_LIST_INTERPOLATE); } } -int CBaseEntity::BaseInterpolatePart1( float ¤tTime, Vector &oldOrigin, QAngle &oldAngles, Vector &oldVel, int &bNoMoreChanges ) +int CBaseEntity::BaseInterpolatePart1( float ¤tTime, Vector &oldOrigin, QAngle &oldAngles, int &bNoMoreChanges ) { // Don't mess with the world!!! bNoMoreChanges = 1; @@ -2812,7 +3133,9 @@ int CBaseEntity::BaseInterpolatePart1( float ¤tTime, Vector &oldOrigin, QA if ( GetPredictable() || IsClientCreated() ) { - C_BasePlayer *localplayer = C_BasePlayer::GetLocalPlayer(); + int slot = GetSplitUserPlayerPredictionSlot(); + Assert( slot != -1 ); + C_BasePlayer *localplayer = C_BasePlayer::GetLocalPlayer( slot ); if ( localplayer && currentTime == gpGlobals->curtime ) { currentTime = localplayer->GetFinalPredictedTime(); @@ -2823,7 +3146,6 @@ int CBaseEntity::BaseInterpolatePart1( float ¤tTime, Vector &oldOrigin, QA oldOrigin = m_vecOrigin; oldAngles = m_angRotation; - oldVel = m_vecVelocity; bNoMoreChanges = Interp_Interpolate( GetVarMapping(), currentTime ); if ( cl_interp_all.GetInt() || (m_EntClientFlags & ENTCLIENTFLAG_ALWAYS_INTERPOLATE) ) @@ -2832,11 +3154,7 @@ int CBaseEntity::BaseInterpolatePart1( float ¤tTime, Vector &oldOrigin, QA return INTERPOLATE_CONTINUE; } -#if 0 -static ConVar cl_watchplayer( "cl_watchplayer", "-1", 0 ); -#endif - -void C_BaseEntity::BaseInterpolatePart2( Vector &oldOrigin, QAngle &oldAngles, Vector &oldVel, int nChangeFlags ) +void C_BaseEntity::BaseInterpolatePart2( Vector &oldOrigin, QAngle &oldAngles, int nChangeFlags ) { if ( m_vecOrigin != oldOrigin ) { @@ -2848,22 +3166,10 @@ void C_BaseEntity::BaseInterpolatePart2( Vector &oldOrigin, QAngle &oldAngles, V nChangeFlags |= ANGLES_CHANGED; } - if ( m_vecVelocity != oldVel ) - { - nChangeFlags |= VELOCITY_CHANGED; - } - if ( nChangeFlags != 0 ) { InvalidatePhysicsRecursive( nChangeFlags ); } - -#if 0 - if ( index == 1 ) - { - SpewInterpolatedVar( &m_iv_vecOrigin, gpGlobals->curtime, GetInterpolationAmount( LATCH_SIMULATION_VAR ), true ); - } -#endif } @@ -2877,31 +3183,30 @@ bool C_BaseEntity::Interpolate( float currentTime ) Vector oldOrigin; QAngle oldAngles; - Vector oldVel; int bNoMoreChanges; - int retVal = BaseInterpolatePart1( currentTime, oldOrigin, oldAngles, oldVel, bNoMoreChanges ); + int retVal = BaseInterpolatePart1( currentTime, oldOrigin, oldAngles, bNoMoreChanges ); // If all the Interpolate() calls returned that their values aren't going to // change anymore, then get us out of the interpolation list. if ( bNoMoreChanges ) - RemoveFromInterpolationList(); + RemoveFromEntityList(ENTITY_LIST_INTERPOLATE); if ( retVal == INTERPOLATE_STOP ) return true; int nChangeFlags = 0; - BaseInterpolatePart2( oldOrigin, oldAngles, oldVel, nChangeFlags ); + BaseInterpolatePart2( oldOrigin, oldAngles, nChangeFlags ); return true; } CStudioHdr *C_BaseEntity::OnNewModel() { -#ifdef TF_CLIENT_DLL - m_bValidatedOwner = false; -#endif - + OnTranslucencyTypeChanged(); + g_pClientLeafSystem->SetModelType( m_hRender ); + InvalidatePhysicsRecursive( BOUNDS_CHANGED | SEQUENCE_CHANGED ); + SetGlobalFadeScale( GetGlobalFadeScale() ); return NULL; } @@ -2910,6 +3215,11 @@ void C_BaseEntity::OnNewParticleEffect( const char *pszParticleName, CNewParticl return; } +void C_BaseEntity::OnParticleEffectDeleted( CNewParticleEffect *pParticleEffect ) +{ + return; +} + // Above this velocity and we'll assume a warp/teleport #define MAX_INTERPOLATE_VELOCITY 4000.0f #define MAX_INTERPOLATE_VELOCITY_PLAYER 1250.0f @@ -2950,36 +3260,40 @@ bool C_BaseEntity::IsSubModel( void ) //----------------------------------------------------------------------------- // Purpose: Create entity lighting effects //----------------------------------------------------------------------------- -void C_BaseEntity::CreateLightEffects( void ) +bool C_BaseEntity::CreateLightEffects( void ) { dlight_t *dl; + bool bHasLightEffects = false; // Is this for player flashlights only, if so move to linkplayers? - if ( index == render->GetViewEntity() ) - return; - - if (IsEffectActive(EF_BRIGHTLIGHT)) + if ( !IsViewEntity() ) { - dl = effects->CL_AllocDlight ( index ); - dl->origin = GetAbsOrigin(); - dl->origin[2] += 16; - dl->color.r = dl->color.g = dl->color.b = 250; - dl->radius = random->RandomFloat(400,431); - dl->die = gpGlobals->curtime + 0.001; - } - if (IsEffectActive(EF_DIMLIGHT)) - { - dl = effects->CL_AllocDlight ( index ); - dl->origin = GetAbsOrigin(); - dl->color.r = dl->color.g = dl->color.b = 100; - dl->radius = random->RandomFloat(200,231); - dl->die = gpGlobals->curtime + 0.001; + if (IsEffectActive(EF_BRIGHTLIGHT)) + { + bHasLightEffects = true; + dl = effects->CL_AllocDlight ( index ); + dl->origin = GetAbsOrigin(); + dl->origin[2] += 16; + dl->color.r = dl->color.g = dl->color.b = 250; + dl->radius = random->RandomFloat(400,431); + dl->die = gpGlobals->curtime + 0.001; + } + if (IsEffectActive(EF_DIMLIGHT)) + { + bHasLightEffects = true; + dl = effects->CL_AllocDlight ( index ); + dl->origin = GetAbsOrigin(); + dl->color.r = dl->color.g = dl->color.b = 100; + dl->radius = random->RandomFloat(200,231); + dl->die = gpGlobals->curtime + 0.001; + } } + return bHasLightEffects; } void C_BaseEntity::MoveToLastReceivedPosition( bool force ) { - if ( force || ( m_nRenderFX != kRenderFxRagdoll ) ) + if ( force || ( !m_bClientSideRagdoll ) ) { SetLocalOrigin( GetNetworkOrigin() ); SetLocalAngles( GetNetworkAngles() ); @@ -2988,15 +3302,18 @@ void C_BaseEntity::MoveToLastReceivedPosition( bool force ) bool C_BaseEntity::ShouldInterpolate() { - if ( render->GetViewEntity() == index ) + if ( IsViewEntity() ) return true; if ( index == 0 || !GetModel() ) return false; // always interpolate if visible - if ( IsVisible() ) + if ( INVALID_CLIENT_RENDER_HANDLE != m_hRender && + !m_VisibilityBits.IsAllClear() ) + { return true; + } // if any movement child needs interpolation, we have to interpolate too C_BaseEntity *pChild = FirstMoveChild(); @@ -3016,13 +3333,13 @@ bool C_BaseEntity::ShouldInterpolate() void C_BaseEntity::ProcessTeleportList() { int iNext; - for ( int iCur=g_TeleportList.Head(); iCur != g_TeleportList.InvalidIndex(); iCur=iNext ) + for ( int iCur=g_EntityLists[ENTITY_LIST_TELEPORT].Head(); iCur != g_EntityLists[ENTITY_LIST_TELEPORT].InvalidIndex(); iCur=iNext ) { - iNext = g_TeleportList.Next( iCur ); - C_BaseEntity *pCur = g_TeleportList[iCur]; + iNext = g_EntityLists[ENTITY_LIST_TELEPORT].Next( iCur ); + C_BaseEntity *pCur = g_EntityLists[ENTITY_LIST_TELEPORT].Element(iCur); bool teleport = pCur->Teleported(); - bool ef_nointerp = pCur->IsNoInterpolationFrame(); + bool ef_nointerp = pCur->IsEffectActive(EF_NOINTERP); if ( teleport || ef_nointerp ) { @@ -3036,12 +3353,11 @@ void C_BaseEntity::ProcessTeleportList() else { // Get it out of the list as soon as we can. - pCur->RemoveFromTeleportList(); + pCur->RemoveFromEntityList(ENTITY_LIST_TELEPORT); } } } - void C_BaseEntity::CheckInterpolatedVarParanoidMeasurement() { // What we're doing here is to check all the entities that were not in the interpolation @@ -3052,7 +3368,7 @@ void C_BaseEntity::CheckInterpolatedVarParanoidMeasurement() for ( int i=0; i <= iHighest; i++ ) { C_BaseEntity *pEnt = ClientEntityList().GetBaseEntity( i ); - if ( !pEnt || pEnt->m_InterpolationListEntry != 0xFFFF || !pEnt->ShouldInterpolate() ) + if ( !pEnt || pEnt->m_ListEntry[ENTITY_LIST_INTERPOLATE] != 0xFFFF || !pEnt->ShouldInterpolate() ) continue; // Player angles always generates this error when the console is up. @@ -3061,7 +3377,7 @@ void C_BaseEntity::CheckInterpolatedVarParanoidMeasurement() // View models tend to screw up this test unnecesarily because they modify origin, // angles, and - if ( dynamic_cast( pEnt ) ) + if ( ToBaseViewModel( pEnt ) ) continue; g_bRestoreInterpolatedVarValues = true; @@ -3086,30 +3402,16 @@ void C_BaseEntity::ProcessInterpolatedList() // Interpolate the minimal set of entities that need it. int iNext; - for ( int iCur=g_InterpolationList.Head(); iCur != g_InterpolationList.InvalidIndex(); iCur=iNext ) + for ( int iCur=g_EntityLists[ENTITY_LIST_INTERPOLATE].Head(); iCur != g_EntityLists[ENTITY_LIST_INTERPOLATE].InvalidIndex(); iCur=iNext ) { - iNext = g_InterpolationList.Next( iCur ); - C_BaseEntity *pCur = g_InterpolationList[iCur]; + iNext = g_EntityLists[ENTITY_LIST_INTERPOLATE].Next( iCur ); + C_BaseEntity *pCur = g_EntityLists[ENTITY_LIST_INTERPOLATE].Element(iCur); pCur->m_bReadyToDraw = pCur->Interpolate( gpGlobals->curtime ); } } -//----------------------------------------------------------------------------- -// Purpose: Add entity to visibile entities list -//----------------------------------------------------------------------------- -void C_BaseEntity::AddEntity( void ) -{ - // Don't ever add the world, it's drawn separately - if ( index == 0 ) - return; - - // Create flashlight effects, etc. - CreateLightEffects(); -} - - //----------------------------------------------------------------------------- // Returns the aiment render origin + angles //----------------------------------------------------------------------------- @@ -3167,41 +3469,37 @@ void C_BaseEntity::ClientThink() { } -void C_BaseEntity::Simulate() -{ - AddEntity(); // Legacy support. Once-per-frame stuff should go in Simulate(). -} - // Defined in engine static ConVar cl_interpolate( "cl_interpolate", "1.0f", FCVAR_USERINFO | FCVAR_DEVELOPMENTONLY ); - // (static function) void C_BaseEntity::InterpolateServerEntities() { VPROF_BUDGET( "C_BaseEntity::InterpolateServerEntities", VPROF_BUDGETGROUP_INTERPOLATION ); + bool bPrevInterpolate = s_bInterpolate; + s_bInterpolate = cl_interpolate.GetBool(); - // Don't interpolate during timedemo playback + // Don't interpolate during timedemo playback or when engine is paused if ( engine->IsPlayingTimeDemo() || engine->IsPaused() ) { s_bInterpolate = false; } - if ( !engine->IsPlayingDemo() ) + // Don't interpolate, either, if we are timing out + INetChannelInfo *nci = engine->GetNetChannelInfo(); + if ( nci && nci->GetTimeSinceLastReceived() > 0.5f ) { - // Don't interpolate, either, if we are timing out - INetChannelInfo *nci = engine->GetNetChannelInfo(); - if ( nci && nci->GetTimeSinceLastReceived() > 0.5f ) - { - s_bInterpolate = false; - } + s_bInterpolate = false; } - if ( IsSimulatingOnAlternateTicks() != g_bWasSkipping || IsEngineThreaded() != g_bWasThreaded ) + if ( IsSimulatingOnAlternateTicks() != g_bWasSkipping || + IsEngineThreaded() != g_bWasThreaded || + cl_interp_threadmodeticks.GetInt() != g_nThreadModeTicks ) { g_bWasSkipping = IsSimulatingOnAlternateTicks(); g_bWasThreaded = IsEngineThreaded(); + g_nThreadModeTicks = cl_interp_threadmodeticks.GetInt(); C_BaseEntityIterator iterator; C_BaseEntity *pEnt; @@ -3219,6 +3517,17 @@ void C_BaseEntity::InterpolateServerEntities() context.EnableExtrapolation( true ); } + if ( bPrevInterpolate != s_bInterpolate && !s_bInterpolate ) + { + // Clear interp history when we disable interpolation + C_BaseEntityIterator iterator; + C_BaseEntity *pEnt; + while ( (pEnt = iterator.Next()) != NULL ) + { + pEnt->ResetLatched(); + } + } + // Smoothly interpolate position for server entities. ProcessTeleportList(); ProcessInterpolatedList(); @@ -3228,29 +3537,32 @@ void C_BaseEntity::InterpolateServerEntities() // (static function) void C_BaseEntity::AddVisibleEntities() { -#if !defined( NO_ENTITY_PREDICTION ) +#if !defined( NO_ENTITY_PREDICTION ) && defined( USE_PREDICTABLEID ) VPROF_BUDGET( "C_BaseEntity::AddVisibleEntities", VPROF_BUDGETGROUP_WORLD_RENDERING ); // Let non-dormant client created predictables get added, too - int c = predictables->GetPredictableCount(); - for ( int i = 0 ; i < c ; i++ ) + FOR_EACH_VALID_SPLITSCREEN_PLAYER( hh ) { - C_BaseEntity *pEnt = predictables->GetPredictable( i ); - if ( !pEnt ) - continue; + int c = GetPredictables( hh )->GetPredictableCount(); + for ( int i = 0 ; i < c ; i++ ) + { + C_BaseEntity *pEnt = GetPredictables( hh )->GetPredictable( i ); + if ( !pEnt ) + continue; - if ( !pEnt->IsClientCreated() ) - continue; + if ( !pEnt->IsClientCreated() ) + continue; - // Only draw until it's ack'd since that means a real entity has arrived - if ( pEnt->m_PredictableID.GetAcknowledged() ) - continue; + // Only draw until it's ack'd since that means a real entity has arrived + if ( pEnt->m_PredictableID.GetAcknowledged() ) + continue; - // Don't draw if dormant - if ( pEnt->IsDormantPredictable() ) - continue; + // Don't draw if dormant + if ( pEnt->IsDormantPredictable() ) + continue; - pEnt->UpdateVisibility(); + pEnt->UpdateVisibility(); + } } #endif } @@ -3278,6 +3590,13 @@ void C_BaseEntity::OnDataChanged( DataUpdateType_t type ) { UpdateVisibility(); } + + // These may have changed in the network update + AlphaProp()->SetRenderFX( GetRenderFX(), GetRenderMode() ); + AlphaProp()->SetDesyncOffset( index ); + + // Copy in fade parameters + AlphaProp()->SetFade( m_flFadeScale, m_fadeMinDist, m_fadeMaxDist ); } ClientThinkHandle_t C_BaseEntity::GetThinkHandle() @@ -3293,257 +3612,26 @@ void C_BaseEntity::SetThinkHandle( ClientThinkHandle_t hThink ) //----------------------------------------------------------------------------- -// Purpose: This routine modulates renderamt according to m_nRenderFX's value -// This is a client side effect and will not be in-sync on machines across a -// network game. -// Input : origin - -// alpha - -// Output : int +// Determine the color modulation amount //----------------------------------------------------------------------------- -void C_BaseEntity::ComputeFxBlend( void ) +void C_BaseEntity::GetColorModulation( float* color ) { - // Don't recompute if we've already computed this frame - if ( m_nFXComputeFrame == gpGlobals->framecount ) - return; + color[0] = m_clrRender->r / 255.0f; + color[1] = m_clrRender->g / 255.0f; + color[2] = m_clrRender->b / 255.0f; +} - MDLCACHE_CRITICAL_SECTION(); - int blend=0; - float offset; - offset = ((int)index) * 363.0;// Use ent index to de-sync these fx +//----------------------------------------------------------------------------- +// Returns true if we should add this to the collision list +//----------------------------------------------------------------------------- +CollideType_t C_BaseEntity::GetCollideType( void ) +{ + if ( !m_nModelIndex || !model ) + return ENTITY_SHOULD_NOT_COLLIDE; - switch( m_nRenderFX ) - { - case kRenderFxPulseSlowWide: - blend = m_clrRender->a + 0x40 * sin( gpGlobals->curtime * 2 + offset ); - break; - - case kRenderFxPulseFastWide: - blend = m_clrRender->a + 0x40 * sin( gpGlobals->curtime * 8 + offset ); - break; - - case kRenderFxPulseFastWider: - blend = ( 0xff * fabs(sin( gpGlobals->curtime * 12 + offset ) ) ); - break; - - case kRenderFxPulseSlow: - blend = m_clrRender->a + 0x10 * sin( gpGlobals->curtime * 2 + offset ); - break; - - case kRenderFxPulseFast: - blend = m_clrRender->a + 0x10 * sin( gpGlobals->curtime * 8 + offset ); - break; - - // JAY: HACK for now -- not time based - case kRenderFxFadeSlow: - if ( m_clrRender->a > 0 ) - { - SetRenderColorA( m_clrRender->a - 1 ); - } - else - { - SetRenderColorA( 0 ); - } - blend = m_clrRender->a; - break; - - case kRenderFxFadeFast: - if ( m_clrRender->a > 3 ) - { - SetRenderColorA( m_clrRender->a - 4 ); - } - else - { - SetRenderColorA( 0 ); - } - blend = m_clrRender->a; - break; - - case kRenderFxSolidSlow: - if ( m_clrRender->a < 255 ) - { - SetRenderColorA( m_clrRender->a + 1 ); - } - else - { - SetRenderColorA( 255 ); - } - blend = m_clrRender->a; - break; - - case kRenderFxSolidFast: - if ( m_clrRender->a < 252 ) - { - SetRenderColorA( m_clrRender->a + 4 ); - } - else - { - SetRenderColorA( 255 ); - } - blend = m_clrRender->a; - break; - - case kRenderFxStrobeSlow: - blend = 20 * sin( gpGlobals->curtime * 4 + offset ); - if ( blend < 0 ) - { - blend = 0; - } - else - { - blend = m_clrRender->a; - } - break; - - case kRenderFxStrobeFast: - blend = 20 * sin( gpGlobals->curtime * 16 + offset ); - if ( blend < 0 ) - { - blend = 0; - } - else - { - blend = m_clrRender->a; - } - break; - - case kRenderFxStrobeFaster: - blend = 20 * sin( gpGlobals->curtime * 36 + offset ); - if ( blend < 0 ) - { - blend = 0; - } - else - { - blend = m_clrRender->a; - } - break; - - case kRenderFxFlickerSlow: - blend = 20 * (sin( gpGlobals->curtime * 2 ) + sin( gpGlobals->curtime * 17 + offset )); - if ( blend < 0 ) - { - blend = 0; - } - else - { - blend = m_clrRender->a; - } - break; - - case kRenderFxFlickerFast: - blend = 20 * (sin( gpGlobals->curtime * 16 ) + sin( gpGlobals->curtime * 23 + offset )); - if ( blend < 0 ) - { - blend = 0; - } - else - { - blend = m_clrRender->a; - } - break; - - case kRenderFxHologram: - case kRenderFxDistort: - { - Vector tmp; - float dist; - - VectorCopy( GetAbsOrigin(), tmp ); - VectorSubtract( tmp, CurrentViewOrigin(), tmp ); - dist = DotProduct( tmp, CurrentViewForward() ); - - // Turn off distance fade - if ( m_nRenderFX == kRenderFxDistort ) - { - dist = 1; - } - if ( dist <= 0 ) - { - blend = 0; - } - else - { - SetRenderColorA( 180 ); - if ( dist <= 100 ) - blend = m_clrRender->a; - else - blend = (int) ((1.0 - (dist - 100) * (1.0 / 400.0)) * m_clrRender->a); - blend += random->RandomInt(-32,31); - } - } - break; - - case kRenderFxNone: - case kRenderFxClampMinScale: - default: - if (m_nRenderMode == kRenderNormal) - blend = 255; - else - blend = m_clrRender->a; - break; - - } - - blend = clamp( blend, 0, 255 ); - - // Look for client-side fades - unsigned char nFadeAlpha = GetClientSideFade(); - if ( nFadeAlpha != 255 ) - { - float flBlend = blend / 255.0f; - float flFade = nFadeAlpha / 255.0f; - blend = (int)( flBlend * flFade * 255.0f + 0.5f ); - blend = clamp( blend, 0, 255 ); - } - - m_nRenderFXBlend = blend; - m_nFXComputeFrame = gpGlobals->framecount; - - // Update the render group - if ( GetRenderHandle() != INVALID_CLIENT_RENDER_HANDLE ) - { - ClientLeafSystem()->SetRenderGroup( GetRenderHandle(), GetRenderGroup() ); - } - - // Tell our shadow - if ( m_ShadowHandle != CLIENTSHADOW_INVALID_HANDLE ) - { - g_pClientShadowMgr->SetFalloffBias( m_ShadowHandle, (255 - m_nRenderFXBlend) ); - } -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -int C_BaseEntity::GetFxBlend( void ) -{ - Assert( m_nFXComputeFrame == gpGlobals->framecount ); - return m_nRenderFXBlend; -} - -//----------------------------------------------------------------------------- -// Determine the color modulation amount -//----------------------------------------------------------------------------- - -void C_BaseEntity::GetColorModulation( float* color ) -{ - color[0] = m_clrRender->r / 255.0f; - color[1] = m_clrRender->g / 255.0f; - color[2] = m_clrRender->b / 255.0f; -} - - -//----------------------------------------------------------------------------- -// Returns true if we should add this to the collision list -//----------------------------------------------------------------------------- -CollideType_t C_BaseEntity::GetCollideType( void ) -{ - if ( !m_nModelIndex || !model ) - return ENTITY_SHOULD_NOT_COLLIDE; - - if ( !IsSolid( ) ) - return ENTITY_SHOULD_NOT_COLLIDE; + if ( !IsSolid( ) ) + return ENTITY_SHOULD_NOT_COLLIDE; // If the model is a bsp or studio (i.e. it can collide with the player if ( ( modelinfo->GetModelType( model ) != mod_brush ) && ( modelinfo->GetModelType( model ) != mod_studio ) ) @@ -3614,48 +3702,6 @@ void C_BaseEntity::AddStudioDecal( const Ray_t& ray, int hitbox, int decalIndex, } } -//----------------------------------------------------------------------------- -void C_BaseEntity::AddColoredStudioDecal( const Ray_t& ray, int hitbox, int decalIndex, - bool doTrace, trace_t& tr, Color cColor, int maxLODToDecal ) -{ - if (doTrace) - { - enginetrace->ClipRayToEntity( ray, MASK_SHOT, this, &tr ); - - // Trace the ray against the entity - if (tr.fraction == 1.0f) - return; - - // Set the trace index appropriately... - tr.m_pEnt = this; - } - - // Exit out after doing the trace so any other effects that want to happen can happen. - if ( !r_drawmodeldecals.GetBool() ) - return; - - // Found the point, now lets apply the decals - CreateModelInstance(); - - // FIXME: Pass in decal up? - Vector up(0, 0, 1); - - if (doTrace && (GetSolid() == SOLID_VPHYSICS) && !tr.startsolid && !tr.allsolid) - { - // Choose a more accurate normal direction - // Also, since we have more accurate info, we can avoid pokethru - Vector temp; - VectorSubtract( tr.endpos, tr.plane.normal, temp ); - Ray_t betterRay; - betterRay.Init( tr.endpos, temp ); - modelrender->AddColoredDecal( m_ModelInstance, betterRay, up, decalIndex, GetStudioBody(), cColor, true, maxLODToDecal ); - } - else - { - modelrender->AddColoredDecal( m_ModelInstance, ray, up, decalIndex, GetStudioBody(), cColor, false, maxLODToDecal ); - } -} - //----------------------------------------------------------------------------- // This method works when we've got a brush model @@ -3663,15 +3709,23 @@ void C_BaseEntity::AddColoredStudioDecal( const Ray_t& ray, int hitbox, int deca void C_BaseEntity::AddBrushModelDecal( const Ray_t& ray, const Vector& decalCenter, int decalIndex, bool doTrace, trace_t& tr ) { + Vector vecNormal; if ( doTrace ) { enginetrace->ClipRayToEntity( ray, MASK_SHOT, this, &tr ); if ( tr.fraction == 1.0f ) return; + vecNormal = tr.plane.normal; + } + else + { + vecNormal = ray.m_Delta; + VectorNormalize( vecNormal ); + vecNormal *= -1.0f; } effects->DecalShoot( decalIndex, index, - model, GetAbsOrigin(), GetAbsAngles(), decalCenter, 0, 0 ); + model, GetAbsOrigin(), GetAbsAngles(), decalCenter, NULL, 0, &vecNormal ); } @@ -3706,56 +3760,6 @@ void C_BaseEntity::AddDecal( const Vector& rayStart, const Vector& rayEnd, } } -//----------------------------------------------------------------------------- -void C_BaseEntity::AddColoredDecal( const Vector& rayStart, const Vector& rayEnd, - const Vector& decalCenter, int hitbox, int decalIndex, bool doTrace, trace_t& tr, Color cColor, int maxLODToDecal ) -{ - Ray_t ray; - ray.Init( rayStart, rayEnd ); - - // FIXME: Better bloat? - // Bloat a little bit so we get the intersection - ray.m_Delta *= 1.1f; - - int modelType = modelinfo->GetModelType( model ); - if ( doTrace ) - { - enginetrace->ClipRayToEntity( ray, MASK_SHOT, this, &tr ); - switch ( modelType ) - { - case mod_studio: - tr.m_pEnt = this; - break; - case mod_brush: - if ( tr.fraction == 1.0f ) - return; // Explicitly end - default: - // By default, no collision - tr.fraction = 1.0f; - break; - } - } - - switch ( modelType ) - { - case mod_studio: - AddColoredStudioDecal( ray, hitbox, decalIndex, doTrace, tr, cColor, maxLODToDecal ); - break; - - case mod_brush: - { - color32 cColor32 = { (uint8)cColor.r(), (uint8)cColor.g(), (uint8)cColor.b(), (uint8)cColor.a() }; - effects->DecalColorShoot( decalIndex, index, model, GetAbsOrigin(), GetAbsAngles(), decalCenter, 0, 0, cColor32 ); - } - break; - - default: - // By default, no collision - tr.fraction = 1.0f; - break; - } -} - //----------------------------------------------------------------------------- // A method to remove all decals from an entity //----------------------------------------------------------------------------- @@ -3797,7 +3801,7 @@ void *C_BaseEntity::operator new( size_t stAllocateBlock ) { Assert( stAllocateBlock != 0 ); MEM_ALLOC_CREDIT(); - void *pMem = MemAlloc_Alloc( stAllocateBlock ); + void *pMem = malloc( stAllocateBlock ); memset( pMem, 0, stAllocateBlock ); return pMem; } @@ -3806,7 +3810,7 @@ void *C_BaseEntity::operator new[]( size_t stAllocateBlock ) { Assert( stAllocateBlock != 0 ); MEM_ALLOC_CREDIT(); - void *pMem = MemAlloc_Alloc( stAllocateBlock ); + void *pMem = malloc( stAllocateBlock ); memset( pMem, 0, stAllocateBlock ); return pMem; } @@ -3834,8 +3838,14 @@ void *C_BaseEntity::operator new[]( size_t stAllocateBlock, int nBlockUse, const //----------------------------------------------------------------------------- void C_BaseEntity::operator delete( void *pMem ) { +#ifdef _DEBUG + // set the memory to a known value + int size = g_pMemAlloc->GetSize( pMem ); + Q_memset( pMem, 0xdd, size ); +#endif + // get the engine to free the memory - MemAlloc_Free( pMem ); + g_pMemAlloc->Free( pMem ); } #include "tier0/memdbgon.h" @@ -3893,22 +3903,27 @@ void C_BaseEntity::SetNextClientThink( float nextThinkTime ) void C_BaseEntity::AddToLeafSystem() { - AddToLeafSystem( GetRenderGroup() ); + AddToLeafSystem( IsRenderingWithViewModels() ); } -void C_BaseEntity::AddToLeafSystem( RenderGroup_t group ) +void C_BaseEntity::AddToLeafSystem( bool bRenderWithViewModels ) { + m_bRenderWithViewModels = bRenderWithViewModels; if( m_hRender == INVALID_CLIENT_RENDER_HANDLE ) { // create new renderer handle - ClientLeafSystem()->AddRenderable( this, group ); + ClientLeafSystem()->AddRenderable( this, bRenderWithViewModels, ComputeTranslucencyType(), RENDERABLE_MODEL_UNKNOWN_TYPE, ComputeSplitscreenRenderingFlags( this ) ); ClientLeafSystem()->EnableAlternateSorting( m_hRender, m_bAlternateSorting ); + ClientLeafSystem()->DisableCachedRenderBounds( m_hRender, m_bDisableCachedRenderBounds ); } else { // handle already exists, just update group & origin - ClientLeafSystem()->SetRenderGroup( m_hRender, group ); - ClientLeafSystem()->RenderableChanged( m_hRender ); + ClientLeafSystem()->RenderWithViewModels( m_hRender, bRenderWithViewModels ); + // this should already be edge detected, no need to do it per frame + // ClientLeafSystem()->SetTranslucencyType( m_hRender, ComputeTranslucencyType() ); + ClientLeafSystem()->SetModelType( m_hRender ); + ClientLeafSystem()->DisableCachedRenderBounds( m_hRender, m_bDisableCachedRenderBounds ); } } @@ -3918,21 +3933,53 @@ void C_BaseEntity::AddToLeafSystem( RenderGroup_t group ) //----------------------------------------------------------------------------- void C_BaseEntity::CreateShadow() { - ShadowType_t shadowType = ShadowCastType(); - if (shadowType == SHADOWS_NONE) + CBitVec< MAX_SPLITSCREEN_PLAYERS > bvPrevBits; + bvPrevBits.Copy( m_ShadowBits ); + m_ShadowBits.ClearAll(); + + ShadowType_t typeSeen = SHADOWS_NONE; + ShadowType_t shadowType[ MAX_SPLITSCREEN_PLAYERS ]; + FOR_EACH_VALID_SPLITSCREEN_PLAYER( hh ) + { + ACTIVE_SPLITSCREEN_PLAYER_GUARD( hh ); + shadowType[ hh ]= ShadowCastType(); + if ( shadowType[ hh ] != SHADOWS_NONE ) + { + m_ShadowBits.Set( hh ); + + // This check is to make sure that if the shadow gets drawn for an entity that it's always the + // same type for each split screen viewport (or SHADOWS_NONE if not visible in one of the viewports!) + // For now, we just pick the "best" (highest enum type) shadow + if ( shadowType[ hh ] > typeSeen ) + { + typeSeen = shadowType[ hh ]; + } + } + } + + if ( m_ShadowBits.IsAllClear() || + !m_ShadowBits.Compare( bvPrevBits ) ) { DestroyShadow(); } - else + + if ( !m_ShadowBits.IsAllClear() ) { - if (m_ShadowHandle == CLIENTSHADOW_INVALID_HANDLE) + if ( m_ShadowHandle == CLIENTSHADOW_INVALID_HANDLE ) { + Assert( typeSeen != SHADOWS_NONE ); int flags = SHADOW_FLAGS_SHADOW; - if (shadowType != SHADOWS_SIMPLE) + if (typeSeen != SHADOWS_SIMPLE) flags |= SHADOW_FLAGS_USE_RENDER_TO_TEXTURE; - if (shadowType == SHADOWS_RENDER_TO_TEXTURE_DYNAMIC) + if (typeSeen == SHADOWS_RENDER_TO_TEXTURE_DYNAMIC || typeSeen == SHADOWS_RENDER_TO_TEXTURE_DYNAMIC_CUSTOM) flags |= SHADOW_FLAGS_ANIMATING_SOURCE; - m_ShadowHandle = g_pClientShadowMgr->CreateShadow(GetClientHandle(), flags); + if (typeSeen == SHADOWS_RENDER_TO_TEXTURE_DYNAMIC_CUSTOM) + flags |= SHADOW_FLAGS_ANIMATING_SOURCE | SHADOW_FLAGS_CUSTOM_DRAW; + m_ShadowHandle = g_pClientShadowMgr->CreateShadow(GetClientHandle(), entindex(), flags, &m_ShadowBits ); + } + else + { + Assert( m_ShadowBits.Compare( bvPrevBits ) ); } } } @@ -3982,6 +4029,9 @@ void C_BaseEntity::SetDormant( bool bDormant ) UpdateVisibility(); ParticleProp()->OwnerSetDormantTo( bDormant ); + + OnSetDormant( bDormant ); + cl_entitylist->SetDormant(index, bDormant); } //----------------------------------------------------------------------------- @@ -4031,7 +4081,7 @@ void C_BaseEntity::SetAbsOrigin( const Vector& absOrigin ) C_BaseEntity *pMoveParent = GetMoveParent(); - if (!pMoveParent) + if ( !pMoveParent ) { m_vecOrigin = absOrigin; return; @@ -4353,12 +4403,12 @@ void C_BaseEntity::CalcAbsolutePosition( ) // Construct the entity-to-world matrix // Start with making an entity-to-parent matrix - matrix3x4_t matEntityToParent; + ALIGN16 matrix3x4_t matEntityToParent; AngleMatrix( GetLocalAngles(), matEntityToParent ); MatrixSetColumn( GetLocalOrigin(), 3, matEntityToParent ); // concatenate with our parent's transform - matrix3x4_t scratchMatrix; + ALIGN16 matrix3x4_t scratchMatrix; ConcatTransforms( GetParentToWorldTransform( scratchMatrix ), matEntityToParent, m_rgflCoordinateFrame ); // pull our absolute position out of the matrix @@ -4381,7 +4431,7 @@ void C_BaseEntity::CalcAbsolutePosition( ) // // So here, we keep our absorigin invalidated. It means we're returning an origin that is a frame old to CalculateIKLocks, // but we'll still render with the right origin. - if ( m_iParentAttachment != 0 && (m_pMoveParent->GetEFlags() & EFL_SETTING_UP_BONES) ) + if ( m_iParentAttachment != 0 && (m_pMoveParent->GetFlags() & EFL_SETTING_UP_BONES) ) { m_iEFlags |= EFL_DIRTY_ABSTRANSFORM; } @@ -4510,7 +4560,10 @@ void C_BaseEntity::ShutdownPredictable( void ) #if !defined( NO_ENTITY_PREDICTION ) Assert( GetPredictable() ); - g_Predictables.RemoveFromPredictablesList( GetClientHandle() ); + for ( int i = 0; i < MAX_SPLITSCREEN_PLAYERS; ++i ) + { + GetPredictables( i )->RemoveFromPredictablesList( this ); + } DestroyIntermediateData(); SetPredictable( false ); #endif @@ -4519,17 +4572,22 @@ void C_BaseEntity::ShutdownPredictable( void ) //----------------------------------------------------------------------------- // Purpose: Turn entity into something the predicts locally //----------------------------------------------------------------------------- -void C_BaseEntity::InitPredictable( void ) +void C_BaseEntity::InitPredictable( C_BasePlayer *pOwner ) { #if !defined( NO_ENTITY_PREDICTION ) Assert( !GetPredictable() ); + Assert( pOwner ); // Mark as predictable SetPredictable( true ); + + int slot = C_BasePlayer::GetSplitScreenSlotForPlayer( pOwner ); + ACTIVE_SPLITSCREEN_PLAYER_GUARD( slot ); + m_nSplitUserPlayerPredictionSlot = slot; // Allocate buffers into which we copy data AllocateIntermediateData(); // Add to list of predictables - g_Predictables.AddToPredictableList( GetClientHandle() ); + GetPredictables( slot )->AddToPredictableList( this ); // Copy everything from "this" into the original_state_data // object. Don't care about client local stuff, so pull from slot 0 which @@ -4596,6 +4654,7 @@ void C_BaseEntity::PreEntityPacketReceived( int commands_acknowledged ) // Unpacked and OnDataChanged will fill in any changed, networked fields. // That networked data will be copied forward into the starting slot for the next prediction round + #endif } @@ -4611,9 +4670,6 @@ void C_BaseEntity::PostEntityPacketReceived( void ) Assert( GetPredictable() ); Assert( cl_predict->GetInt() ); - // Always mark as changed - AddDataChangeEvent( this, DATA_UPDATE_DATATABLE_CHANGED, &m_DataChangeEventRef ); - // Save networked fields into "original data" store SaveData( "PostEntityPacketReceived", SLOT_ORIGINALDATA, PC_NETWORKED_ONLY ); #endif @@ -4652,26 +4708,18 @@ bool C_BaseEntity::PostNetworkDataReceived( int commands_acknowledged ) if ( errorcheck ) { - void *predicted_state_data = GetPredictedFrame( commands_acknowledged - 1 ); + byte *predicted_state_data = (byte *)GetPredictedFrame( commands_acknowledged - 1 ); Assert( predicted_state_data ); - const void *original_state_data = GetOriginalNetworkDataObject(); + const byte *original_state_data = (const byte *)GetOriginalNetworkDataObject(); Assert( original_state_data ); - bool counterrors = true; - bool reporterrors = showthis; - bool copydata = false; - CPredictionCopy errorCheckHelper( PC_NETWORKED_ONLY, - predicted_state_data, PC_DATA_PACKED, - original_state_data, PC_DATA_PACKED, - counterrors, reporterrors, copydata ); - // Suppress debugging output - int ecount = errorCheckHelper.TransferData( "", -1, GetPredDescMap() ); - if ( ecount > 0 ) - { - haderrors = true; - // Msg( "%i errors %i on entity %i %s\n", gpGlobals->tickcount, ecount, index, IsClientCreated() ? "true" : "false" ); - } + predicted_state_data, TD_OFFSET_PACKED, + original_state_data, TD_OFFSET_PACKED, + showthis ? + CPredictionCopy::TRANSFERDATA_ERRORCHECK_SPEW : + CPredictionCopy::TRANSFERDATA_ERRORCHECK_NOSPEW ); + haderrors = errorCheckHelper.TransferData( "", entindex(), GetPredDescMap() ) > 0 ? true : false; } #endif return haderrors; @@ -4699,14 +4747,22 @@ int C_BaseEntity::PrecacheModel( const char *name ) //----------------------------------------------------------------------------- void C_BaseEntity::Remove( ) { + if ( IsMarkedForDeletion( ) ) + return; + AddEFlags( EFL_KILLME ); // Make sure to ignore further calls into here or UTIL_Remove. + // Nothing for now, if it's a predicted entity, could flag as "delete" or dormant if ( GetPredictable() || IsClientCreated() ) { // Make it solid AddSolidFlags( FSOLID_NOT_SOLID ); SetMoveType( MOVETYPE_NONE ); + } - AddEFlags( EFL_KILLME ); // Make sure to ignore further calls into here or UTIL_Remove. + if ( !s_bImmediateRemovesAllowed ) + { + AddToEntityList( ENTITY_LIST_DELETE ); + return; } Release(); @@ -4745,7 +4801,7 @@ C_BaseEntity *C_BaseEntity::Instance( int iEnt ) #ifdef WIN32 #pragma warning( push ) -#include +#include #pragma warning( pop ) #endif @@ -4764,7 +4820,7 @@ const char *C_BaseEntity::GetClassname( void ) const char *mapname = GetClassMap().Lookup( GetPredDescMap()->dataClassName ); if ( mapname && mapname[ 0 ] ) { - Q_strncpy( outstr, mapname, sizeof( outstr ) ); + Q_snprintf( outstr, sizeof( outstr ), "%s", mapname ); gotname = true; } } @@ -4843,7 +4899,7 @@ CON_COMMAND_F( dlight_debug, "Creates a dlight in front of the player", FCVAR_CH //----------------------------------------------------------------------------- bool C_BaseEntity::IsClientCreated( void ) const { -#ifndef NO_ENTITY_PREDICTION +#if !defined( NO_ENTITY_PREDICTION ) && defined( USE_PREDICTABLEID ) if ( m_pPredictionContext != NULL ) { // For now can't be both @@ -4863,9 +4919,12 @@ bool C_BaseEntity::IsClientCreated( void ) const //----------------------------------------------------------------------------- C_BaseEntity *C_BaseEntity::CreatePredictedEntityByName( const char *classname, const char *module, int line, bool persist /*= false */ ) { -#if !defined( NO_ENTITY_PREDICTION ) +#if !defined( NO_ENTITY_PREDICTION ) && defined( USE_PREDICTABLEID ) C_BasePlayer *player = C_BaseEntity::GetPredictionPlayer(); + int slot = C_BasePlayer::GetSplitScreenSlotForPlayer( player ); + ACTIVE_SPLITSCREEN_PLAYER_GUARD( slot ); + Assert( player ); Assert( player->m_pCurrentCommand ); Assert( prediction->InPrediction() ); @@ -4905,7 +4964,7 @@ C_BaseEntity *C_BaseEntity::CreatePredictedEntityByName( const char *classname, } // It's predictable - ent->SetPredictionEligible( true ); + ent->SetPredictionEligible( true ); // Set up "shared" id number ent->m_PredictableID.SetRaw( testId.GetRaw() ); @@ -4919,12 +4978,13 @@ C_BaseEntity *C_BaseEntity::CreatePredictedEntityByName( const char *classname, // Attach to entity ent->m_pPredictionContext = context; + ent->m_nSplitUserPlayerPredictionSlot = slot; // Add to client entity list ClientEntityList().AddNonNetworkableEntity( ent ); // and predictables - g_Predictables.AddToPredictableList( ent->GetClientHandle() ); + GetPredictables( slot )->AddToPredictableList( ent ); // Duhhhh..., but might as well be safe Assert( !ent->GetPredictable() ); @@ -4956,7 +5016,7 @@ C_BaseEntity *C_BaseEntity::CreatePredictedEntityByName( const char *classname, //----------------------------------------------------------------------------- bool C_BaseEntity::OnPredictedEntityRemove( bool isbeingremoved, C_BaseEntity *predicted ) { -#if !defined( NO_ENTITY_PREDICTION ) +#if !defined( NO_ENTITY_PREDICTION ) && defined( USE_PREDICTABLEID ) // Nothing right now, but in theory you could look at the error in origins and set // up something to smooth out the error PredictionContext *ctx = predicted->m_pPredictionContext; @@ -5195,13 +5255,13 @@ void C_BaseEntity::ShiftIntermediateDataForward( int slots_to_remove, int number Assert( number_of_commands_run >= slots_to_remove ); // Just moving pointers, yeah - CUtlVector< unsigned char * > saved; + byte *saved[ MULTIPLAYER_BACKUP ]; // Remember first slots int i = 0; for ( ; i < slots_to_remove; i++ ) { - saved.AddToTail( m_pIntermediateData[ i ] ); + saved[ i ] = m_pIntermediateData[ i ]; } // Move rest of slots forward up to last slot @@ -5264,15 +5324,9 @@ void C_BaseEntity::ComputePackedOffsets( void ) { #if !defined( NO_ENTITY_PREDICTION ) datamap_t *map = GetPredDescMap(); - if ( !map ) + if ( !map || map->m_pOptimizedDataMap ) return; - - if ( map->packed_offsets_computed ) - return; - - ComputePackedSize_R( map ); - - Assert( map->packed_offsets_computed ); + CPredictionCopy::PrepareDataMap( map ); #endif } @@ -5287,9 +5341,9 @@ int C_BaseEntity::GetIntermediateDataSize( void ) const datamap_t *map = GetPredDescMap(); - Assert( map->packed_offsets_computed ); + Assert( map->m_pOptimizedDataMap ); - int size = map->packed_size; + int size = map->m_nPackedSize; Assert( size > 0 ); @@ -5300,164 +5354,6 @@ int C_BaseEntity::GetIntermediateDataSize( void ) #endif } -static int g_FieldSizes[FIELD_TYPECOUNT] = -{ - FIELD_SIZE( FIELD_VOID ), - FIELD_SIZE( FIELD_FLOAT ), - FIELD_SIZE( FIELD_STRING ), - FIELD_SIZE( FIELD_VECTOR ), - FIELD_SIZE( FIELD_QUATERNION ), - FIELD_SIZE( FIELD_INTEGER ), - FIELD_SIZE( FIELD_BOOLEAN ), - FIELD_SIZE( FIELD_SHORT ), - FIELD_SIZE( FIELD_CHARACTER ), - FIELD_SIZE( FIELD_COLOR32 ), - FIELD_SIZE( FIELD_EMBEDDED ), - FIELD_SIZE( FIELD_CUSTOM ), - - FIELD_SIZE( FIELD_CLASSPTR ), - FIELD_SIZE( FIELD_EHANDLE ), - FIELD_SIZE( FIELD_EDICT ), - - FIELD_SIZE( FIELD_POSITION_VECTOR ), - FIELD_SIZE( FIELD_TIME ), - FIELD_SIZE( FIELD_TICK ), - FIELD_SIZE( FIELD_MODELNAME ), - FIELD_SIZE( FIELD_SOUNDNAME ), - - FIELD_SIZE( FIELD_INPUT ), - FIELD_SIZE( FIELD_FUNCTION ), - FIELD_SIZE( FIELD_VMATRIX ), - FIELD_SIZE( FIELD_VMATRIX_WORLDSPACE ), - FIELD_SIZE( FIELD_MATRIX3X4_WORLDSPACE ), - FIELD_SIZE( FIELD_INTERVAL ), - FIELD_SIZE( FIELD_MODELINDEX ), - FIELD_SIZE( FIELD_MATERIALINDEX ), - - FIELD_SIZE( FIELD_VECTOR2D ), - FIELD_SIZE( FIELD_INTEGER64 ), - FIELD_SIZE( FIELD_POINTER ), -}; - -//----------------------------------------------------------------------------- -// Purpose: -// Input : *map - -// Output : int -//----------------------------------------------------------------------------- -int C_BaseEntity::ComputePackedSize_R( datamap_t *map ) -{ - if ( !map ) - { - Assert( 0 ); - return 0; - } - - // Already computed - if ( map->packed_offsets_computed ) - { - return map->packed_size; - } - - int current_position = 0; - - // Recurse to base classes first... - if ( map->baseMap ) - { - current_position += ComputePackedSize_R( map->baseMap ); - } - - int c = map->dataNumFields; - int i; - typedescription_t *field; - - for ( i = 0; i < c; i++ ) - { - field = &map->dataDesc[ i ]; - - // Always descend into embedded types... - if ( field->fieldType != FIELD_EMBEDDED ) - { - // Skip all private fields - if ( field->flags & FTYPEDESC_PRIVATE ) - continue; - } - - switch ( field->fieldType ) - { - default: - case FIELD_MODELINDEX: - case FIELD_MODELNAME: - case FIELD_SOUNDNAME: - case FIELD_TIME: - case FIELD_TICK: - case FIELD_CUSTOM: - case FIELD_CLASSPTR: - case FIELD_EDICT: - case FIELD_POSITION_VECTOR: - case FIELD_FUNCTION: - Assert( 0 ); - break; - - case FIELD_EMBEDDED: - { - Assert( field->td != NULL ); - - int embeddedsize = ComputePackedSize_R( field->td ); - - field->fieldOffset[ TD_OFFSET_PACKED ] = current_position; - - current_position += embeddedsize; - } - break; - - case FIELD_FLOAT: - case FIELD_VECTOR: - case FIELD_QUATERNION: - case FIELD_INTEGER: - case FIELD_EHANDLE: - { - // These should be dword aligned - current_position = (current_position + 3) & ~3; - field->fieldOffset[ TD_OFFSET_PACKED ] = current_position; - Assert( field->fieldSize >= 1 ); - current_position += g_FieldSizes[ field->fieldType ] * field->fieldSize; - } - break; - - case FIELD_SHORT: - { - // This should be word aligned - current_position = (current_position + 1) & ~1; - field->fieldOffset[ TD_OFFSET_PACKED ] = current_position; - Assert( field->fieldSize >= 1 ); - current_position += g_FieldSizes[ field->fieldType ] * field->fieldSize; - } - break; - - case FIELD_STRING: - case FIELD_COLOR32: - case FIELD_BOOLEAN: - case FIELD_CHARACTER: - { - field->fieldOffset[ TD_OFFSET_PACKED ] = current_position; - Assert( field->fieldSize >= 1 ); - current_position += g_FieldSizes[ field->fieldType ] * field->fieldSize; - } - break; - case FIELD_VOID: - { - // Special case, just skip it - } - break; - } - } - - map->packed_size = current_position; - map->packed_offsets_computed = true; - - return current_position; -} - // Convenient way to delay removing oneself void C_BaseEntity::SUB_Remove( void ) { @@ -5504,6 +5400,14 @@ static void RemoveDecals_f( void ) static ConCommand cl_removedecals( "cl_removedecals", RemoveDecals_f, "Remove the decals from the entity under the crosshair.", FCVAR_CHEAT ); +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_BaseEntity::ClearBBoxVisualization( void ) +{ + m_fBBoxVisFlags = 0; +} + //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- @@ -5607,64 +5511,28 @@ void C_BaseEntity::DrawBBoxVisualizations( void ) //----------------------------------------------------------------------------- void C_BaseEntity::SetRenderMode( RenderMode_t nRenderMode, bool bForceUpdate ) { - m_nRenderMode = nRenderMode; -} - - -//----------------------------------------------------------------------------- -// Purpose: -// Output : RenderGroup_t -//----------------------------------------------------------------------------- -RenderGroup_t C_BaseEntity::GetRenderGroup() -{ - // Don't sort things that don't need rendering - if ( m_nRenderMode == kRenderNone ) - return RENDER_GROUP_OPAQUE_ENTITY; - - // When an entity has a material proxy, we have to recompute - // translucency here because the proxy may have changed it. - if (modelinfo->ModelHasMaterialProxy( GetModel() )) + if ( nRenderMode != m_nRenderMode ) { - modelinfo->RecomputeTranslucency( const_cast(GetModel()), GetSkin(), GetBody(), GetClientRenderable() ); + m_nRenderMode = nRenderMode; + m_pClientAlphaProperty->SetRenderFX( GetRenderFX(), nRenderMode ); } +} - // NOTE: Bypassing the GetFXBlend protection logic because we want this to - // be able to be called from AddToLeafSystem. - int nTempComputeFrame = m_nFXComputeFrame; - m_nFXComputeFrame = gpGlobals->framecount; - - int nFXBlend = GetFxBlend(); - - m_nFXComputeFrame = nTempComputeFrame; - - // Don't need to sort invisible stuff - if ( nFXBlend == 0 ) - return RENDER_GROUP_OPAQUE_ENTITY; - - // Figure out its RenderGroup. - int modelType = modelinfo->GetModelType( model ); - RenderGroup_t renderGroup = (modelType == mod_brush) ? RENDER_GROUP_OPAQUE_BRUSH : RENDER_GROUP_OPAQUE_ENTITY; - if ( ( nFXBlend != 255 ) || IsTransparent() ) +void CBaseEntity::SetRenderFX( RenderFx_t nRenderFX, float flStartTime, float flDuration ) +{ + bool bStartTimeUnspecified = ( flStartTime == FLT_MAX ); + if ( nRenderFX != m_nRenderFX || !bStartTimeUnspecified ) { - if ( m_nRenderMode != kRenderEnvironmental ) + if ( bStartTimeUnspecified ) { - renderGroup = RENDER_GROUP_TRANSLUCENT_ENTITY; + flStartTime = gpGlobals->curtime; } - else - { - renderGroup = RENDER_GROUP_OTHER; - } - } - - if ( ( renderGroup == RENDER_GROUP_TRANSLUCENT_ENTITY ) && - ( modelinfo->IsTranslucentTwoPass( model ) ) ) - { - renderGroup = RENDER_GROUP_TWOPASS; + m_nRenderFX = nRenderFX; + m_pClientAlphaProperty->SetRenderFX( nRenderFX, GetRenderMode(), flStartTime, flDuration ); } - - return renderGroup; } + //----------------------------------------------------------------------------- // Purpose: Copy from this entity into one of the save slots (original or intermediate) // Input : slot - @@ -5676,41 +5544,21 @@ RenderGroup_t C_BaseEntity::GetRenderGroup() // NULL - // Output : int //----------------------------------------------------------------------------- -int C_BaseEntity::SaveData( const char *context, int slot, int type ) +void C_BaseEntity::SaveData( const char *context, int slot, int type ) { #if !defined( NO_ENTITY_PREDICTION ) VPROF( "C_BaseEntity::SaveData" ); void *dest = ( slot == SLOT_ORIGINALDATA ) ? GetOriginalNetworkDataObject() : GetPredictedFrame( slot ); Assert( dest ); - - char sz[ 64 ]; - sz[0] = 0; - // don't build debug strings per entity per frame, unless we are watching the entity - static ConVarRef pwatchent( "pwatchent" ); - if ( pwatchent.GetInt() == entindex() ) - { - if ( slot == SLOT_ORIGINALDATA ) - { - Q_snprintf( sz, sizeof( sz ), "%s SaveData(original)", context ); - } - else - { - Q_snprintf( sz, sizeof( sz ), "%s SaveData(slot %02i)", context, slot ); - } - } - if ( slot != SLOT_ORIGINALDATA ) { // Remember high water mark so that we can detect below if we are reading from a slot not yet predicted into... m_nIntermediateDataCount = slot; } - CPredictionCopy copyHelper( type, dest, PC_DATA_PACKED, this, PC_DATA_NORMAL ); - int error_count = copyHelper.TransferData( sz, entindex(), GetPredDescMap() ); - return error_count; -#else - return 0; + CPredictionCopy copyHelper( type, (byte *)dest, TD_OFFSET_PACKED, (const byte *)this, TD_OFFSET_NORMAL, CPredictionCopy::TRANSFERDATA_COPYONLY ); + copyHelper.TransferData( "C_BaseEntity::SaveData", entindex(), GetPredDescMap() ); #endif } @@ -5725,65 +5573,24 @@ int C_BaseEntity::SaveData( const char *context, int slot, int type ) // NULL - // Output : int //----------------------------------------------------------------------------- -int C_BaseEntity::RestoreData( const char *context, int slot, int type ) +void C_BaseEntity::RestoreData( const char *context, int slot, int type ) { #if !defined( NO_ENTITY_PREDICTION ) VPROF( "C_BaseEntity::RestoreData" ); const void *src = ( slot == SLOT_ORIGINALDATA ) ? GetOriginalNetworkDataObject() : GetPredictedFrame( slot ); Assert( src ); - - // This assert will fire if the server ack'd a CUserCmd which we hadn't predicted yet... - // In that case, we'd be comparing "old" data from this "unused" slot with the networked data and reporting all kinds of prediction errors possibly. - Assert( slot == SLOT_ORIGINALDATA || slot <= m_nIntermediateDataCount ); - - char sz[ 64 ]; - sz[0] = 0; - // don't build debug strings per entity per frame, unless we are watching the entity - static ConVarRef pwatchent( "pwatchent" ); - if ( pwatchent.GetInt() == entindex() ) - { - if ( slot == SLOT_ORIGINALDATA ) - { - Q_snprintf( sz, sizeof( sz ), "%s RestoreData(original)", context ); - } - else - { - Q_snprintf( sz, sizeof( sz ), "%s RestoreData(slot %02i)", context, slot ); - } - } - + // some flags shouldn't be predicted - as we find them, add them to the savedEFlagsMask - const int savedEFlagsMask = EFL_DIRTY_SHADOWUPDATE; + const int savedEFlagsMask = EFL_DIRTY_SHADOWUPDATE | EFL_DIRTY_SPATIAL_PARTITION; int savedEFlags = GetEFlags() & savedEFlagsMask; - // model index needs to be set manually for dynamic model refcounting purposes - int oldModelIndex = m_nModelIndex; - - CPredictionCopy copyHelper( type, this, PC_DATA_NORMAL, src, PC_DATA_PACKED ); - int error_count = copyHelper.TransferData( sz, entindex(), GetPredDescMap() ); + CPredictionCopy copyHelper( type, (byte *)this, TD_OFFSET_NORMAL, (const byte *)src, TD_OFFSET_PACKED, CPredictionCopy::TRANSFERDATA_COPYONLY ); + copyHelper.TransferData( "C_BaseEntity::RestoreData", entindex(), GetPredDescMap() ); // set non-predicting flags back to their prior state RemoveEFlags( savedEFlagsMask ); AddEFlags( savedEFlags ); - - // restore original model index and change via SetModelIndex - int newModelIndex = m_nModelIndex; - m_nModelIndex = oldModelIndex; - int overrideModelIndex = CalcOverrideModelIndex(); - if( overrideModelIndex != -1 ) - newModelIndex = overrideModelIndex; - if ( oldModelIndex != newModelIndex ) - { - MDLCACHE_CRITICAL_SECTION(); // ??? - SetModelIndex( newModelIndex ); - } - - OnPostRestoreData(); - - return error_count; -#else - return 0; #endif } @@ -5799,8 +5606,6 @@ void C_BaseEntity::OnPostRestoreData() } // If our model index has changed, then make sure it's reflected in our model pointer. - // (Mostly superseded by new modelindex delta check in RestoreData, but I'm leaving it - // because it might be band-aiding any other missed calls to SetModelByIndex --henryg) if ( GetModel() != modelinfo->GetModel( GetModelIndex() ) ) { MDLCACHE_CRITICAL_SECTION(); @@ -5815,9 +5620,8 @@ void C_BaseEntity::OnPostRestoreData() //----------------------------------------------------------------------------- void C_BaseEntity::EstimateAbsVelocity( Vector& vel ) { - if ( this == C_BasePlayer::GetLocalPlayer() ) + if ( C_BasePlayer::IsLocalPlayer( this ) ) { - // This is interpolated and networked vel = GetAbsVelocity(); return; } @@ -5836,7 +5640,7 @@ void C_BaseEntity::Interp_Reset( VarMapping_t *map ) VarMapEntry_t *e = &map->m_Entries[ i ]; IInterpolatedVar *watcher = e->watcher; - watcher->Reset(); + watcher->Reset( gpGlobals->curtime ); } } @@ -5891,20 +5695,17 @@ float C_BaseEntity::GetInterpolationAmount( int flags ) return TICK_INTERVAL * serverTickMultiple; } - // Always fully interpolate during multi-player or during demo playback, if the recorded - // demo was recorded locally. - const bool bPlayingDemo = engine->IsPlayingDemo(); - const bool bPlayingMultiplayer = !bPlayingDemo && ( gpGlobals->maxClients > 1 ); - const bool bPlayingNonLocallyRecordedDemo = bPlayingDemo && !engine->IsPlayingDemoALocallyRecordedDemo(); - if ( bPlayingMultiplayer || bPlayingNonLocallyRecordedDemo ) + // Always fully interpolate during multi-player or during demo playback... + if ( ( gpGlobals->maxClients > 1 ) || + engine->IsPlayingDemo() ) { - return AdjustInterpolationAmount( this, TICKS_TO_TIME( TIME_TO_TICKS( GetClientInterpAmount() ) + serverTickMultiple ) ); + return AdjustInterpolationAmount( this, TICKS_TO_TIME ( TIME_TO_TICKS( GetClientInterpAmount() ) + serverTickMultiple ) ); } int expandedServerTickMultiple = serverTickMultiple; if ( IsEngineThreaded() ) { - expandedServerTickMultiple += g_nThreadModeTicks; + expandedServerTickMultiple += cl_interp_threadmodeticks.GetInt(); } if ( IsAnimatedEveryTick() && IsSimulatedEveryTick() ) @@ -5921,7 +5722,7 @@ float C_BaseEntity::GetInterpolationAmount( int flags ) return TICK_INTERVAL * expandedServerTickMultiple; } - return AdjustInterpolationAmount( this, TICKS_TO_TIME( TIME_TO_TICKS( GetClientInterpAmount() ) + serverTickMultiple ) ); + return AdjustInterpolationAmount( this, TICK_INTERVAL * ( TIME_TO_TICKS( GetClientInterpAmount() ) + serverTickMultiple ) ); } @@ -6167,26 +5968,29 @@ void C_BaseEntity::GetToolRecordingState( KeyValues *msg ) C_BaseEntity *pOwner = m_hOwnerEntity; static BaseEntityRecordingState_t state; + state.m_flTime = gpGlobals->curtime; state.m_pModelName = modelinfo->GetModelName( GetModel() ); state.m_nOwner = pOwner ? pOwner->entindex() : -1; - state.m_nEffects = m_fEffects; + state.m_fEffects = m_fEffects; state.m_bVisible = ShouldDraw() && !IsDormant(); state.m_bRecordFinalVisibleSample = false; state.m_vecRenderOrigin = GetRenderOrigin(); state.m_vecRenderAngles = GetRenderAngles(); + state.m_numEffects = 0; + state.m_pEffects = NULL; // use EF_NOINTERP if the owner or a hierarchical parent has NO_INTERP - if ( pOwner && pOwner->IsNoInterpolationFrame() ) + if ( pOwner && pOwner->IsEffectActive( EF_NOINTERP ) ) { - state.m_nEffects |= EF_NOINTERP; + state.m_fEffects |= EF_NOINTERP; } C_BaseEntity *pParent = GetMoveParent(); while ( pParent ) { - if ( pParent->IsNoInterpolationFrame() ) + if ( pParent->IsEffectActive( EF_NOINTERP ) ) { - state.m_nEffects |= EF_NOINTERP; + state.m_fEffects |= EF_NOINTERP; break; } @@ -6242,82 +6046,30 @@ void C_BaseEntity::ToolRecordEntities() } } +#ifdef _DEBUG +static entity_list_ids_t s_nSuppressChanges = NUM_ENTITY_LISTS; +#endif -void C_BaseEntity::AddToInterpolationList() -{ - if ( m_InterpolationListEntry == 0xFFFF ) - m_InterpolationListEntry = g_InterpolationList.AddToTail( this ); -} - - -void C_BaseEntity::RemoveFromInterpolationList() +void C_BaseEntity::AddToEntityList( entity_list_ids_t listId ) { - if ( m_InterpolationListEntry != 0xFFFF ) + Assert(listId < NUM_ENTITY_LISTS); + if ( m_ListEntry[listId] == 0xFFFF ) { - g_InterpolationList.Remove( m_InterpolationListEntry ); - m_InterpolationListEntry = 0xFFFF; + m_ListEntry[listId] = g_EntityLists[listId].AddToTail( this ); } } - -void C_BaseEntity::AddToTeleportList() +void C_BaseEntity::RemoveFromEntityList( entity_list_ids_t listId ) { - if ( m_TeleportListEntry == 0xFFFF ) - m_TeleportListEntry = g_TeleportList.AddToTail( this ); -} - - -void C_BaseEntity::RemoveFromTeleportList() -{ - if ( m_TeleportListEntry != 0xFFFF ) + Assert( s_nSuppressChanges != listId ); + Assert( listId < NUM_ENTITY_LISTS ); + if ( m_ListEntry[listId] != 0xFFFF ) { - g_TeleportList.Remove( m_TeleportListEntry ); - m_TeleportListEntry = 0xFFFF; + g_EntityLists[listId].Remove( m_ListEntry[listId] ); + m_ListEntry[listId] = 0xFFFF; } } -#ifdef TF_CLIENT_DLL -bool C_BaseEntity::ValidateEntityAttachedToPlayer( bool &bShouldRetry ) -{ - bShouldRetry = false; - C_BaseEntity *pParent = GetRootMoveParent(); - if ( pParent == this ) - return true; - - // Some wearables parent to the view model - C_BasePlayer *pPlayer = ToBasePlayer( pParent ); - if ( pPlayer && pPlayer->GetViewModel() == this ) - { - return true; - } - - // always allow the briefcase model - const char *pszModel = modelinfo->GetModelName( GetModel() ); - if ( pszModel && pszModel[0] ) - { - if ( FStrEq( pszModel, "models/flag/briefcase.mdl" ) ) - return true; - - if ( FStrEq( pszModel, "models/props_doomsday/australium_container.mdl" ) ) - return true; - - // Temp for MVM testing - if ( FStrEq( pszModel, "models/buildables/sapper_placement_sentry1.mdl" ) ) - return true; - - if ( FStrEq( pszModel, "models/props_td/atom_bomb.mdl" ) ) - return true; - - if ( FStrEq( pszModel, "models/props_lakeside_event/bomb_temp_hat.mdl" ) ) - return true; - } - - // Any entity that's not an item parented to a player is invalid. - // This prevents them creating some other entity to pretend to be a cosmetic item. - return !pParent->IsPlayer(); -} -#endif // TF_CLIENT_DLL - void C_BaseEntity::AddVar( void *data, IInterpolatedVar *watcher, int type, bool bSetup ) { @@ -6426,6 +6178,202 @@ int C_BaseEntity::GetCreationTick() const return m_nCreationTick; } +// static method +void C_BaseEntity::SimulateEntities() +{ + s_bImmediateRemovesAllowed = false; + + if ( !report_cliententitysim.GetBool() ) + { + int iNext; + for ( int iCur = g_EntityLists[ENTITY_LIST_SIMULATE].Head(); iCur != g_EntityLists[ENTITY_LIST_SIMULATE].InvalidIndex(); iCur = iNext ) + { + iNext = g_EntityLists[ENTITY_LIST_SIMULATE].Next( iCur ); + C_BaseEntity *pCur = g_EntityLists[ENTITY_LIST_SIMULATE].Element(iCur); + if ( pCur->IsEFlagSet( EFL_KILLME ) ) + continue; + +#ifdef _DEBUG + s_nSuppressChanges = ENTITY_LIST_SIMULATE; +#endif + bool bRemove = !pCur->Simulate(); +#ifdef _DEBUG + s_nSuppressChanges = NUM_ENTITY_LISTS; +#endif + if ( bRemove ) + { + pCur->RemoveFromEntityList(ENTITY_LIST_SIMULATE); + } + } + } + else + { + CFastTimer fastTimer; + + int iNext; + for ( int iCur = g_EntityLists[ENTITY_LIST_SIMULATE].Head(); iCur != g_EntityLists[ENTITY_LIST_SIMULATE].InvalidIndex(); iCur = iNext ) + { + iNext = g_EntityLists[ENTITY_LIST_SIMULATE].Next( iCur ); + C_BaseEntity *pCur = g_EntityLists[ENTITY_LIST_SIMULATE].Element(iCur); + if ( pCur->IsEFlagSet( EFL_KILLME ) ) + continue; + + fastTimer.Start(); +#ifdef _DEBUG + s_nSuppressChanges = ENTITY_LIST_SIMULATE; +#endif + bool bRemove = !pCur->Simulate(); +#ifdef _DEBUG + s_nSuppressChanges = NUM_ENTITY_LISTS; +#endif + if ( bRemove ) + { + pCur->RemoveFromEntityList(ENTITY_LIST_SIMULATE); + } + fastTimer.End(); + Msg( "Entity(%d): %s - %f\n", pCur->entindex(), pCur->GetDebugName(), fastTimer.GetDuration().GetMillisecondsF() ); + } + + // Report only once per turn on. + report_cliententitysim.SetValue( 0 ); + } + + s_bImmediateRemovesAllowed = true; + PurgeRemovedEntities(); +} + +// static method +void C_BaseEntity::PurgeRemovedEntities() +{ + int iNext; + for ( int iCur = g_EntityLists[ENTITY_LIST_DELETE].Head(); iCur != g_EntityLists[ENTITY_LIST_DELETE].InvalidIndex(); iCur = iNext ) + { + iNext = g_EntityLists[ENTITY_LIST_DELETE].Next( iCur ); + C_BaseEntity *pCur = g_EntityLists[ENTITY_LIST_DELETE].Element(iCur); + pCur->Release(); + } + g_EntityLists[ENTITY_LIST_DELETE].RemoveAll(); +} + +// static method +// This is the per-viewport setup hook +void C_BaseEntity::PreRenderEntities( int nSplitScreenPlayerSlot ) +{ + MDLCACHE_CRITICAL_SECTION(); + int iNext; + for ( int iCur = g_EntityLists[ENTITY_LIST_PRERENDER].Head(); iCur != g_EntityLists[ENTITY_LIST_PRERENDER].InvalidIndex(); iCur = iNext ) + { + iNext = g_EntityLists[ENTITY_LIST_PRERENDER].Next( iCur ); + C_BaseEntity *pCur = g_EntityLists[ENTITY_LIST_PRERENDER].Element(iCur); + +#ifdef _DEBUG + s_nSuppressChanges = ENTITY_LIST_PRERENDER; +#endif + bool bRemove = !pCur->PreRender(nSplitScreenPlayerSlot); +#ifdef _DEBUG + s_nSuppressChanges = NUM_ENTITY_LISTS; +#endif + if ( bRemove ) + { + pCur->RemoveFromEntityList(ENTITY_LIST_PRERENDER); + } + } + +} + + +bool C_BaseEntity::PreRender( int nSplitScreenPlayerSlot ) +{ + bool bNeedsPrerender = false; + + // Create flashlight effects, etc. + if ( CreateLightEffects() ) + { + bNeedsPrerender = true; + } + return bNeedsPrerender; +} + +bool C_BaseEntity::IsViewEntity() const +{ + return render->IsViewEntity( entindex() ); +} + +bool C_BaseEntity::IsAbleToHaveFireEffect( void ) const +{ + return !UTIL_IsLowViolence(); +} + + +void C_BaseEntity::SetBlurState( bool bShouldBlur ) +{ + if( bShouldBlur != m_bIsBlurred ) + { + m_bIsBlurred = bShouldBlur; + OnTranslucencyTypeChanged(); + } +} + +bool C_BaseEntity::IsBlurred( void ) +{ + return m_bIsBlurred; +} + +void C_BaseEntity::OnParseMapDataFinished() +{ +} + +//----------------------------------------------------------------------------- +// Adjust the number of cell bits +//----------------------------------------------------------------------------- +bool C_BaseEntity::SetCellBits( int cellbits ) +{ + if ( m_cellbits == cellbits ) + return false; + + m_cellbits = cellbits; + m_cellwidth = ( 1 << cellbits ); + return true; +} + + +bool C_BaseEntity::ShouldRegenerateOriginFromCellBits() const +{ + return true; +} + + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +HSCRIPT C_BaseEntity::GetScriptInstance() +{ + if ( !m_hScriptInstance ) + { + if ( m_iszScriptId == NULL_STRING ) + { + char *szName = (char *)stackalloc( 1024 ); + g_pScriptVM->GenerateUniqueKey( ( m_iName != NULL_STRING ) ? STRING(GetEntityName()) : GetClassname(), szName, 1024 ); + m_iszScriptId = AllocPooledString( szName ); + } + + m_hScriptInstance = g_pScriptVM->RegisterInstance( GetScriptDesc(), this ); + g_pScriptVM->SetInstanceUniqeId( m_hScriptInstance, STRING(m_iszScriptId) ); + } + return m_hScriptInstance; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : IResponseSystem +//----------------------------------------------------------------------------- +IResponseSystem *CBaseEntity::GetResponseSystem() +{ + extern IResponseSystem *g_pResponseSystem; + return g_pResponseSystem; +} + //------------------------------------------------------------------------------ void CC_CL_Find_Ent( const CCommand& args ) { diff --git a/game/client/c_baseentity.h b/game/client/c_baseentity.h index c62b732f0..6914e3542 100644 --- a/game/client/c_baseentity.h +++ b/game/client/c_baseentity.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: A base class for the client-side representation of entities. // @@ -16,11 +16,10 @@ #endif #include "mathlib/vector.h" -#include "icliententityinternal.h" -#include "engine/ivmodelinfo.h" -#include "engine/ivmodelrender.h" +#include "IClientEntityInternal.h" +#include "engine/IVModelRender.h" #include "client_class.h" -#include "iclientshadowmgr.h" +#include "IClientShadowMgr.h" #include "ehandle.h" #include "iclientunknown.h" #include "client_thinklist.h" @@ -30,12 +29,16 @@ #include "soundflags.h" #include "shareddefs.h" #include "networkvar.h" -#include "interpolatedvar.h" +#include "sharedvar.h" +#include "tier1/interpolatedvar.h" #include "collisionproperty.h" #include "particle_property.h" #include "toolframework/itoolentity.h" #include "tier0/threadtools.h" +#include "vscript/ivscript.h" +#include "vscript_shared.h" + class C_Team; class IPhysicsObject; class IClientVehicle; @@ -57,15 +60,23 @@ class CTakeDamageInfo; class C_BaseCombatCharacter; class CEntityMapData; class ConVar; -class CDmgAccumulator; - +class CClientAlphaProperty; struct CSoundParameters; typedef unsigned int AimEntsListHandle_t; +#ifndef AI_CriteriaSet +#define AI_CriteriaSet ResponseRules::CriteriaSet +#endif +namespace ResponseRules +{ + class CriteriaSet; + class IResponseSystem; +}; +using ResponseRules::IResponseSystem; + #define INVALID_AIMENTS_LIST_HANDLE (AimEntsListHandle_t)~0 -extern void RecvProxy_IntToColor32( const CRecvProxyData *pData, void *pStruct, void *pOut ); extern void RecvProxy_LocalVelocity( const CRecvProxyData *pData, void *pStruct, void *pOut ); enum CollideType_t @@ -105,7 +116,7 @@ struct VarMapping_t // How many data slots to use when in multiplayer. -#define MULTIPLAYER_BACKUP 90 +#define MULTIPLAYER_BACKUP 150 struct serialentity_t; @@ -121,7 +132,7 @@ typedef C_BaseEntity* (*DISPATCHFUNCTION)( void ); #include "touchlink.h" #include "groundlink.h" -#if !defined( NO_ENTITY_PREDICTION ) +#if !defined( NO_ENTITY_PREDICTION ) && defined( USE_PREDICTABLEID ) //----------------------------------------------------------------------------- // Purpose: For fully client side entities we use this information to determine // authoritatively if the server has acknowledged creating this entity, etc. @@ -168,6 +179,17 @@ struct thinkfunc_t #define ENTCLIENTFLAG_DONTUSEIK 0x0002 // Don't use IK on this entity even if its model has IK. #define ENTCLIENTFLAG_ALWAYS_INTERPOLATE 0x0004 // Used by view models. +enum entity_list_ids_t +{ + ENTITY_LIST_INTERPOLATE = 0, + ENTITY_LIST_TELEPORT, + ENTITY_LIST_PRERENDER, + ENTITY_LIST_SIMULATE, + ENTITY_LIST_DELETE, + + NUM_ENTITY_LISTS +}; + //----------------------------------------------------------------------------- // Purpose: Base client side entity object //----------------------------------------------------------------------------- @@ -183,22 +205,29 @@ class C_BaseEntity : public IClientEntity DECLARE_DATADESC(); DECLARE_CLIENTCLASS(); DECLARE_PREDICTABLE(); + // script description + DECLARE_ENT_SCRIPTDESC(); C_BaseEntity(); + +protected: + // Use UTIL_Remove to delete! virtual ~C_BaseEntity(); +public: static C_BaseEntity *CreatePredictedEntityByName( const char *classname, const char *module, int line, bool persist = false ); - + static void UpdateVisibilityAllEntities(); + virtual void ModifyOrAppendCriteria( AI_CriteriaSet& set ); + // FireBullets uses shared code for prediction. virtual void FireBullets( const FireBulletsInfo_t &info ); - virtual void ModifyFireBulletsDamage( CTakeDamageInfo* dmgInfo ) {} virtual bool ShouldDrawUnderwaterBulletBubbles(); virtual bool ShouldDrawWaterImpacts( void ) { return true; } virtual bool HandleShotImpactingWater( const FireBulletsInfo_t &info, const Vector &vecEnd, ITraceFilter *pTraceFilter, Vector *pVecTracerDest ); virtual ITraceFilter* GetBeamTraceFilter( void ); - virtual void DispatchTraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator = NULL ); - virtual void TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator = NULL ); + virtual void DispatchTraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr ); + virtual void TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr ); virtual void DoImpactEffect( trace_t &tr, int nDamageType ); virtual void MakeTracer( const Vector &vecTracerSrc, const trace_t &tr, int iTracerType ); virtual int GetTracerAttachment( void ); @@ -207,14 +236,19 @@ class C_BaseEntity : public IClientEntity virtual int BloodColor(); virtual const char* GetTracerType(); + // called when entity is damaged by predicted attacks + virtual void TakeDamage( const CTakeDamageInfo &info ) { } + virtual void Spawn( void ); virtual void SpawnClientEntity( void ); virtual void Precache( void ); virtual void Activate(); - virtual void ParseMapData( CEntityMapData *mapData ); + void ParseMapData( CEntityMapData *mapData ); + virtual void OnParseMapDataFinished(); virtual bool KeyValue( const char *szKeyName, const char *szValue ); virtual bool KeyValue( const char *szKeyName, float flValue ); + virtual bool KeyValue( const char *szKeyName, int nValue ); virtual bool KeyValue( const char *szKeyName, const Vector &vecValue ); virtual bool GetKeyValue( const char *szKeyName, char *szValue, int iMaxLen ); @@ -226,6 +260,8 @@ class C_BaseEntity : public IClientEntity bool IsAIWalkable( void ); + virtual void InitSharedVars( void ) {}; + void Interp_SetupMappings( VarMapping_t *map ); // Returns 1 if there are no more changes (ie: we could call RemoveFromInterpolationList). @@ -254,8 +290,15 @@ class C_BaseEntity : public IClientEntity virtual C_BaseAnimating* GetBaseAnimating() { return NULL; } virtual void SetClassname( const char *className ); + virtual Class_T Classify( void ) { return CLASS_NONE; } + string_t m_iClassname; + HSCRIPT GetScriptInstance(); + + HSCRIPT m_hScriptInstance; + string_t m_iszScriptId; + // IClientUnknown overrides. public: @@ -277,15 +320,20 @@ class C_BaseEntity : public IClientEntity void DontRecordInTools(); bool ShouldRecordInTools() const; + virtual ResponseRules::IResponseSystem *GetResponseSystem(); + +protected: virtual void Release(); + +public: virtual ICollideable* GetCollideable() { return &m_Collision; } virtual IClientNetworkable* GetClientNetworkable() { return this; } virtual IClientRenderable* GetClientRenderable() { return this; } virtual IClientEntity* GetIClientEntity() { return this; } virtual C_BaseEntity* GetBaseEntity() { return this; } virtual IClientThinkable* GetClientThinkable() { return this; } - - + virtual IClientModelRenderable* GetClientModelRenderable() { return NULL; } + virtual IClientAlphaProperty* GetClientAlphaProperty(); // Methods of IClientRenderable public: @@ -293,15 +341,9 @@ class C_BaseEntity : public IClientEntity virtual const QAngle& GetRenderAngles( void ); virtual Vector GetObserverCamOrigin( void ) { return GetRenderOrigin(); } // Return the origin for player observers tracking this target virtual const matrix3x4_t & RenderableToWorldTransform(); - virtual bool IsTransparent( void ); - virtual bool IsTwoPass( void ); - virtual bool UsesPowerOfTwoFrameBufferTexture(); - virtual bool UsesFullFrameBufferTexture(); - virtual bool IgnoresZBuffer( void ) const; + virtual int GetRenderFlags( void ); virtual const model_t *GetModel( void ) const; - virtual int DrawModel( int flags ); - virtual void ComputeFxBlend( void ); - virtual int GetFxBlend( void ); + virtual int DrawModel( int flags, const RenderableInstance_t &instance ); virtual bool LODTest() { return true; } // NOTE: UNUSED virtual void GetRenderBounds( Vector& mins, Vector& maxs ); virtual IPVSNotify* GetPVSNotifyInterface(); @@ -324,6 +366,8 @@ class C_BaseEntity : public IClientEntity C_BaseEntity *GetEffectEntity( void ) const; void SetEffectEntity( C_BaseEntity *pEffectEnt ); + bool IsAbleToHaveFireEffect( void ) const; + // This function returns a value that scales all damage done by this entity. // Use CDamageModifier to hook in damage modifiers on a guy. virtual float GetAttackDamageScale( void ); @@ -342,6 +386,8 @@ class C_BaseEntity : public IClientEntity virtual void SetDormant( bool bDormant ); virtual bool IsDormant( void ); + virtual void OnSetDormant( bool bDormant ) {} + // Tells the entity that it's about to be destroyed due to the client receiving // an uncompressed update that's caused it to destroy all entities & recreate them. virtual void SetDestroyedOnRecreateEntities( void ); @@ -390,6 +436,8 @@ class C_BaseEntity : public IClientEntity const CCollisionProperty*CollisionProp() const; CParticleProperty *ParticleProp(); const CParticleProperty *ParticleProp() const; + CClientAlphaProperty *AlphaProp(); + const CClientAlphaProperty *AlphaProp() const; // Simply here for game shared bool IsFloating(); @@ -410,11 +458,6 @@ class C_BaseEntity : public IClientEntity int SaveDataDescBlock( ISave &save, datamap_t *dmap ); int RestoreDataDescBlock( IRestore &restore, datamap_t *dmap ); - // Called after restoring data into prediction slots. This function is used in place of proxies - // on the variables, so if some variable like m_nModelIndex needs to update other state (like - // the model pointer), it is done here. - void OnPostRestoreData(); - public: // Called after spawn, and in the case of self-managing objects, after load @@ -448,16 +491,16 @@ class C_BaseEntity : public IClientEntity // IClientEntity implementation. public: - virtual bool SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime ); + virtual bool SetupBones( matrix3x4a_t *pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime ); virtual void SetupWeights( const matrix3x4_t *pBoneToWorld, int nFlexWeightCount, float *pFlexWeights, float *pFlexDelayedWeights ); virtual bool UsesFlexDelayedWeights() { return false; } virtual void DoAnimationEvents( void ); - // Add entity to visible entities list? - virtual void AddEntity( void ); - virtual const Vector& GetAbsOrigin( void ) const; - virtual const QAngle& GetAbsAngles( void ) const; + virtual const QAngle& GetAbsAngles( void ) const; // see also GetVectors() + inline Vector Forward() const; ///< get my forward (+x) vector + inline Vector Left() const; ///< get my left (+y) vector + inline Vector Up() const; ///< get my up (+z) vector const Vector& GetNetworkOrigin() const; const QAngle& GetNetworkAngles() const; @@ -485,7 +528,6 @@ class C_BaseEntity : public IClientEntity int GetModelIndex( void ) const; void SetModelIndex( int index ); - virtual int CalcOverrideModelIndex() { return -1; } // These methods return a *world-aligned* box relative to the absorigin of the entity. // This is used for collision purposes and is *not* guaranteed @@ -544,6 +586,12 @@ class C_BaseEntity : public IClientEntity int GetFlags( void ) const; void ClearFlags(); + void SetDistanceFade( float flMinDist, float flMaxDist ); + void SetGlobalFadeScale( float flFadeScale ); + float GetMinFadeDist( ) const; + float GetMaxFadeDist( ) const; + float GetGlobalFadeScale( ) const; + MoveType_t GetMoveType( void ) const; MoveCollide_t GetMoveCollide( void ) const; virtual SolidType_t GetSolid( void ) const; @@ -567,6 +615,7 @@ class C_BaseEntity : public IClientEntity virtual bool GetAttachment( int number, Vector &origin ); virtual bool GetAttachment( int number, Vector &origin, QAngle &angles ); virtual bool GetAttachmentVelocity( int number, Vector &originVel, Quaternion &angleVel ); + virtual void InvalidateAttachments() {} // Team handling virtual C_Team *GetTeam( void ); @@ -578,11 +627,9 @@ class C_BaseEntity : public IClientEntity // ID Target handling virtual bool IsValidIDTarget( void ) { return false; } - virtual const char *GetIDString( void ) { return ""; }; + virtual char *GetIDString( void ) { return ""; }; // See CSoundEmitterSystem - virtual void ModifyEmitSoundParams( EmitSound_t ¶ms ); - void EmitSound( const char *soundname, float soundtime = 0.0f, float *duration = NULL ); // Override for doing the general case of CPASAttenuationFilter( this ), and EmitSound( filter, entindex(), etc. ); void EmitSound( const char *soundname, HSOUNDSCRIPTHANDLE& handle, float soundtime = 0.0f, float *duration = NULL ); // Override for doing the general case of CPASAttenuationFilter( this ), and EmitSound( filter, entindex(), etc. ); void StopSound( const char *soundname ); @@ -603,7 +650,7 @@ class C_BaseEntity : public IClientEntity static void EmitSound( IRecipientFilter& filter, int iEntIndex, const EmitSound_t & params ); static void EmitSound( IRecipientFilter& filter, int iEntIndex, const EmitSound_t & params, HSOUNDSCRIPTHANDLE& handle ); - static void StopSound( int iEntIndex, int iChannel, const char *pSample ); + static void StopSound( int iEntIndex, int iChannel, const char *pSample, bool bIsStoppingSpeakerSound = false ); static void EmitAmbientSound( int entindex, const Vector& origin, const char *soundname, int flags = 0, float soundtime = 0.0f, float *duration = NULL ); @@ -627,22 +674,26 @@ class C_BaseEntity : public IClientEntity static bool IsSimulatingOnAlternateTicks(); +public: + static bool sm_bAccurateTriggerBboxChecks; // SOLID_BBOX entities do a fully accurate trigger vs bbox check when this is set + // C_BaseEntity local functions public: - void UpdatePartitionListEntry(); + virtual void UpdatePartitionListEntry(); // This can be used to setup the entity as a client-only entity. // Override this to perform per-entity clientside setup - virtual bool InitializeAsClientEntity( const char *pszModelName, RenderGroup_t renderGroup ); + virtual bool InitializeAsClientEntity( const char *pszModelName, bool bRenderWithViewModels ); - // This function gets called on all client entities once per simulation phase. - // It dispatches events like OnDataChanged(), and calls the legacy function AddEntity(). - virtual void Simulate(); + // This function gets called on all client entities once per simulation phase. If the entity + // is in the simulate list. It dispatches events like OnDataChanged() + // return false if this entity no longer needs to simulate, true otherwise + virtual bool Simulate() { return false; } // This event is triggered during the simulation phase if an entity's data has changed. It is @@ -675,7 +726,23 @@ class C_BaseEntity : public IClientEntity inline ClientEntityHandle_t GetClientHandle() const { return ClientEntityHandle_t( m_RefEHandle ); } inline bool IsServerEntity( void ); - virtual RenderGroup_t GetRenderGroup(); + void RenderWithViewModels( bool bEnable ); + bool IsRenderingWithViewModels() const; + void DisableCachedRenderBounds( bool bDisabled ); + bool IsCachedRenderBoundsDisabled() const; + + // NOTE: The goal of this function is different from IsTranslucent(). + // Here, we need to determine whether a renderable is inherently translucent + // when run-time alpha modulation or any other game code is not taken into account + virtual RenderableTranslucencyType_t ComputeTranslucencyType( ); + virtual uint8 OverrideAlphaModulation( uint8 nAlpha ) { return nAlpha; } + virtual uint8 OverrideShadowAlphaModulation( uint8 nAlpha ) { return nAlpha; } + + // Client code should call this under any circumstances where translucency type may change + void OnTranslucencyTypeChanged(); + + // Client code should call this under any circumstances where splitscreen rendering may change + void OnSplitscreenRenderingChanged(); virtual void GetToolRecordingState( KeyValues *msg ); virtual void CleanupToolRecordingState( KeyValues *msg ); @@ -685,7 +752,8 @@ class C_BaseEntity : public IClientEntity virtual CollideType_t GetCollideType( void ); virtual bool ShouldDraw(); - inline bool IsVisible() const { return m_hRender != INVALID_CLIENT_RENDER_HANDLE; } + inline bool IsVisible() const; + inline bool IsVisibleToAnyPlayer() const; void UpdateVisibility(); // Returns true if the entity changes its position every frame on the server but it doesn't @@ -701,6 +769,7 @@ class C_BaseEntity : public IClientEntity // Initialize things given a new model. virtual CStudioHdr *OnNewModel(); virtual void OnNewParticleEffect( const char *pszParticleName, CNewParticleEffect *pNewParticleEffect ); + virtual void OnParticleEffectDeleted( CNewParticleEffect *pParticleEffect ); bool IsSimulatedEveryTick() const; bool IsAnimatedEveryTick() const; @@ -710,7 +779,7 @@ class C_BaseEntity : public IClientEntity void Interp_Reset( VarMapping_t *map ); virtual void ResetLatched(); - float GetInterpolationAmount( int flags ); + virtual float GetInterpolationAmount( int flags ); float GetLastChangeTime( int flags ); // Interpolate the position for rendering @@ -721,7 +790,7 @@ class C_BaseEntity : public IClientEntity // Is this a submodel of the world ( *1 etc. in name ) ( brush models only ) virtual bool IsSubModel( void ); // Deal with EF_* flags - virtual void CreateLightEffects( void ); + virtual bool CreateLightEffects( void ); void AddToAimEntsList(); void RemoveFromAimEntsList(); @@ -729,7 +798,7 @@ class C_BaseEntity : public IClientEntity // Reset internal fields virtual void Clear( void ); // Helper to draw raw brush models - virtual int DrawBrushModel( bool bTranslucent, int nFlags, bool bTwoPass ); + virtual int DrawBrushModel( bool bSort, bool bShadowDepth ); // returns the material animation start time virtual float GetTextureAnimationStartTime(); @@ -743,7 +812,6 @@ class C_BaseEntity : public IClientEntity virtual void SetHealth(int iHealth) {} virtual int GetHealth() const { return 0; } virtual int GetMaxHealth() const { return 1; } - virtual bool IsVisibleToTargetID( void ) { return false; } // Returns the health fraction float HealthFraction() const; @@ -763,17 +831,13 @@ class C_BaseEntity : public IClientEntity // Sets up a render handle so the leaf system will draw this entity. void AddToLeafSystem(); - void AddToLeafSystem( RenderGroup_t group ); + void AddToLeafSystem( bool bRenderWithViewModels ); // remove entity form leaf system again void RemoveFromLeafSystem(); // A method to apply a decal to an entity virtual void AddDecal( const Vector& rayStart, const Vector& rayEnd, const Vector& decalCenter, int hitbox, int decalIndex, bool doTrace, trace_t& tr, int maxLODToDecal = ADDDECAL_TO_ALL_LODS ); - - virtual void AddColoredDecal( const Vector& rayStart, const Vector& rayEnd, - const Vector& decalCenter, int hitbox, int decalIndex, bool doTrace, trace_t& tr, Color cColor, int maxLODToDecal = ADDDECAL_TO_ALL_LODS ); - // A method to remove all decals from an entity void RemoveAllDecals( void ); @@ -795,6 +859,7 @@ class C_BaseEntity : public IClientEntity // Prediction stuff ///////////////// void CheckInitPredictable( const char *context ); + virtual C_BasePlayer *GetPredictionOwner( void ); void AllocateIntermediateData( void ); void DestroyIntermediateData( void ); @@ -804,8 +869,9 @@ class C_BaseEntity : public IClientEntity void *GetOriginalNetworkDataObject( void ); bool IsIntermediateDataAllocated( void ) const; - void InitPredictable( void ); + virtual void InitPredictable( C_BasePlayer *pOwner ); void ShutdownPredictable( void ); + int GetSplitUserPlayerPredictionSlot(); virtual void SetPredictable( bool state ); bool GetPredictable( void ) const; @@ -820,12 +886,17 @@ class C_BaseEntity : public IClientEntity SLOT_ORIGINALDATA = -1, }; - int SaveData( const char *context, int slot, int type ); - virtual int RestoreData( const char *context, int slot, int type ); + void SaveData( const char *context, int slot, int type ); + void RestoreData( const char *context, int slot, int type ); + + // Called after restoring data into prediction slots. This function is used in place of proxies + // on the variables, so if some variable like m_nModelIndex needs to update other state (like + // the model pointer), it is done here. + void OnPostRestoreData(); virtual char const * DamageDecal( int bitsDamageType, int gameMaterial ); virtual void DecalTrace( trace_t *pTrace, char const *decalName ); - virtual void ImpactTrace( trace_t *pTrace, int iDamageType, const char *pCustomImpactName ); + virtual void ImpactTrace( trace_t *pTrace, int iDamageType, char *pCustomImpactName ); virtual bool ShouldPredict( void ) { return false; }; // interface function pointers @@ -850,19 +921,27 @@ class C_BaseEntity : public IClientEntity VISUALIZE_RENDER_BOUNDS = 0x4, }; + void ClearBBoxVisualization( void ); void ToggleBBoxVisualization( int fVisFlags ); void DrawBBoxVisualizations( void ); + virtual bool PreRender( int nSplitScreenPlayerSlot ); + + bool IsViewEntity() const; + // Methods implemented on both client and server public: void SetSize( const Vector &vecMin, const Vector &vecMax ); // UTIL_SetSize( pev, mins, maxs ); - char const *GetClassname( void ); + virtual char const *GetClassname( void ); char const *GetDebugName( void ); + virtual const char *GetPlayerName() const { return NULL; } static int PrecacheModel( const char *name ); static bool PrecacheSound( const char *name ); static void PrefetchSound( const char *name ); void Remove( ); // UTIL_Remove( this ); + + public: // Returns the attachment point index on our parent that our transform is relative to. @@ -880,7 +959,7 @@ class C_BaseEntity : public IClientEntity void DestroyAllDataObjects( void ); // Determine approximate velocity based on updates from server - void EstimateAbsVelocity( Vector& vel ); + virtual void EstimateAbsVelocity( Vector& vel ); #if !defined( NO_ENTITY_PREDICTION ) // The player drives simulation of this entity @@ -922,6 +1001,7 @@ class C_BaseEntity : public IClientEntity void PhysicsImpact( C_BaseEntity *other, trace_t &trace ); void PhysicsMarkEntitiesAsTouching( C_BaseEntity *other, trace_t &trace ); void PhysicsMarkEntitiesAsTouchingEventDriven( C_BaseEntity *other, trace_t &trace ); + void PhysicsTouchTriggers( const Vector *pPrevAbsOrigin = NULL ); // Physics helper static void PhysicsRemoveTouchedList( C_BaseEntity *ent ); @@ -954,6 +1034,7 @@ class C_BaseEntity : public IClientEntity void SetGroundEntity( C_BaseEntity *ground ); C_BaseEntity *GetGroundEntity( void ); + C_BaseEntity *GetGroundEntity( void ) const { return const_cast(this)->GetGroundEntity(); } void PhysicsPushEntity( const Vector& push, trace_t *pTrace ); void PhysicsCheckWaterTransition( void ); @@ -996,20 +1077,29 @@ class C_BaseEntity : public IClientEntity bool IsInWorld( void ) { return true; } - bool IsWorld() { return entindex() == 0; } + bool IsWorld() const { return entindex() == 0; } ///////////////// + virtual bool ShouldRegenerateOriginFromCellBits() const; + virtual bool IsPlayer( void ) const { return false; }; virtual bool IsBaseCombatCharacter( void ) { return false; }; virtual C_BaseCombatCharacter *MyCombatCharacterPointer( void ) { return NULL; } virtual bool IsNPC( void ) { return false; } C_AI_BaseNPC *MyNPCPointer( void ); - virtual bool IsNextBot() { return false; } + + virtual bool IsSprite( void ) const { return false; } + virtual bool IsProp( void ) const { return false; } + // TF2 specific virtual bool IsBaseObject( void ) const { return false; } virtual bool IsBaseCombatWeapon( void ) const { return false; } virtual class C_BaseCombatWeapon *MyCombatWeaponPointer() { return NULL; } - virtual bool IsCombatItem( void ) const { return false; } + + // Entities like the player, weapon models, and view models have special logic per-view port related to visibility and the model to be used, etc. + virtual bool ShouldDrawForSplitScreenUser( int nSlot ); + void SetBlurState( bool bShouldBlur ); + virtual bool IsBlurred( void ); virtual bool IsBaseTrain( void ) const { return false; } @@ -1039,12 +1129,11 @@ class C_BaseEntity : public IClientEntity void SetModelByIndex( int nModelIndex ); // Set model... (NOTE: Should only be used by client-only entities - // Returns false if the model name is bogus or otherwise can't be loaded + // Returns false if the model name is bogus bool SetModel( const char *pModelName ); void SetModelPointer( const model_t *pModel ); - // Access movetype and solid. void SetMoveType( MoveType_t val, MoveCollide_t moveCollide = MOVECOLLIDE_DEFAULT ); // Set to one of the MOVETYPE_ defines. void SetMoveCollide( MoveCollide_t val ); // Set to one of the MOVECOLLIDE_ defines. @@ -1075,13 +1164,15 @@ class C_BaseEntity : public IClientEntity virtual const Vector &GetViewOffset() const; virtual void SetViewOffset( const Vector& v ); -#ifdef SIXENSE + virtual void GetGroundVelocityToApply( Vector &vecGroundVel ) { vecGroundVel = vec3_origin; } + + // TrackIR const Vector& GetEyeOffset() const; void SetEyeOffset( const Vector& v ); const QAngle & GetEyeAngleOffset() const; void SetEyeAngleOffset( const QAngle & qa ); -#endif + // TrackIR // Invalidates the abs state of all children void InvalidatePhysicsRecursive( int nChangeFlags ); @@ -1090,6 +1181,8 @@ class C_BaseEntity : public IClientEntity void SetRemovalFlag( bool bRemove ); + bool HasSpawnFlags( int nFlags ) const; + // Effects... bool IsEffectActive( int nEffectMask ) const; void AddEffects( int nEffects ); @@ -1114,6 +1207,11 @@ class C_BaseEntity : public IClientEntity virtual int GetBody() { return 0; } virtual int GetSkin() { return 0; } + const Vector &ScriptGetForward( void ) { static Vector vecForward; GetVectors( &vecForward, NULL, NULL ); return vecForward; } + const Vector &ScriptGetLeft( void ) { static Vector vecLeft; GetVectors( NULL, &vecLeft, NULL ); return vecLeft; } + const Vector &ScriptGetUp( void ) { static Vector vecUp; GetVectors( NULL, NULL, &vecUp ); return vecUp; } + + // Stubs on client void NetworkStateManualMode( bool activate ) { } void NetworkStateChanged() { } @@ -1193,9 +1291,6 @@ class C_BaseEntity : public IClientEntity // For non-players int PhysicsClipVelocity (const Vector& in, const Vector& normal, Vector& out, float overbounce ); - // Allow entities to perform client-side fades - virtual unsigned char GetClientSideFade() { return 255; } - protected: // Two part guts of Interpolate(). Shared with C_BaseAnimating. enum @@ -1206,8 +1301,8 @@ class C_BaseEntity : public IClientEntity // Returns INTERPOLATE_STOP or INTERPOLATE_CONTINUE. // bNoMoreChanges is set to 1 if you can call RemoveFromInterpolationList on the entity. - int BaseInterpolatePart1( float ¤tTime, Vector &oldOrigin, QAngle &oldAngles, Vector &oldVel, int &bNoMoreChanges ); - void BaseInterpolatePart2( Vector &oldOrigin, QAngle &oldAngles, Vector &oldVel, int nChangeFlags ); + int BaseInterpolatePart1( float ¤tTime, Vector &oldOrigin, QAngle &oldAngles, int &bNoMoreChanges ); + void BaseInterpolatePart2( Vector &oldOrigin, QAngle &oldAngles, int nChangeFlags ); public: @@ -1244,41 +1339,141 @@ class C_BaseEntity : public IClientEntity static bool IsAbsRecomputationsEnabled( void ); + static void PreRenderEntities( int nSplitScreenPlayerSlot ); + static void PurgeRemovedEntities(); + static void SimulateEntities(); // Bloat the culling bbox past the parent ent's bbox in local space if EF_BONEMERGE_FASTCULL is set. virtual void BoneMergeFastCullBloat( Vector &localMins, Vector &localMaxs, const Vector &thisEntityMins, const Vector &thisEntityMaxs ) const; // Accessors for color. - const color32 GetRenderColor() const; + const color24 GetRenderColor() const; + byte GetRenderColorR() const; + byte GetRenderColorG() const; + byte GetRenderColorB() const; + byte GetRenderAlpha() const; void SetRenderColor( byte r, byte g, byte b ); - void SetRenderColor( byte r, byte g, byte b, byte a ); void SetRenderColorR( byte r ); void SetRenderColorG( byte g ); void SetRenderColorB( byte b ); - void SetRenderColorA( byte a ); + void SetRenderAlpha( byte a ); void SetRenderMode( RenderMode_t nRenderMode, bool bForceUpdate = false ); RenderMode_t GetRenderMode() const; + void SetRenderFX( RenderFx_t nRenderFX, float flStartTime = FLT_MAX, float flDuration = 0.0f ); + RenderFx_t GetRenderFX() const; + + // Returns true if there was a change. + bool SetCellBits( int cellbits = CELL_BASEENTITY_ORIGIN_CELL_BITS ); + + static void RecvProxy_CellBits( const CRecvProxyData *pData, void *pStruct, void *pOut ); + static void RecvProxy_CellX( const CRecvProxyData *pData, void *pStruct, void *pOut ); + static void RecvProxy_CellY( const CRecvProxyData *pData, void *pStruct, void *pOut ); + static void RecvProxy_CellZ( const CRecvProxyData *pData, void *pStruct, void *pOut ); + static void RecvProxy_CellOrigin( const CRecvProxyData *pData, void *pStruct, void *pOut ); + static void RecvProxy_CellOriginXY( const CRecvProxyData *pData, void *pStruct, void *pOut ); + static void RecvProxy_CellOriginZ( const CRecvProxyData *pData, void *pStruct, void *pOut ); + + const char *GetEntityName(); + public: // Determine what entity this corresponds to int index; - // Render information - unsigned char m_nRenderFX; - unsigned char m_nRenderFXBlend; - // Entity flags that are only for the client (ENTCLIENTFLAG_ defines). unsigned short m_EntClientFlags; - CNetworkColor32( m_clrRender ); - private: // Model for rendering - const model_t *model; + const model_t *model; + CNetworkColor32( m_clrRender ); + +public: +protected: // Cell data is available to derived classes for RecvProxy issues + int m_cellbits; + int m_cellwidth; + int m_cellX; + int m_cellY; + int m_cellZ; + Vector m_vecCellOrigin; // cached cell offset position +// BEGIN PREDICTION DATA COMPACTION (these fields are together to allow for faster copying in prediction system) +// FTYPEDESC_INSENDTABLE STUFF +private: + Vector m_vecAbsVelocity; + Vector m_vecAbsOrigin; + Vector m_vecOrigin; + + QAngle m_vecAngVelocity; + QAngle m_angAbsRotation; + QAngle m_angRotation; + + float m_flGravity; + // A random value used by material proxies for each model instance. + float m_flProxyRandomValue; + + int m_iEFlags; // entity flags EFL_* + + unsigned char m_nWaterType; + // For client/server entities, true if the entity goes outside the PVS. + // Unused for client only entities. + bool m_bDormant; + +// FTYPEDESC_INSENDTABLE STUFF (end) +private: + // Effects to apply + int m_fEffects; +public: + // Team Handling + int m_iTeamNum; + int m_nNextThinkTick; + int m_iHealth; +private: + int m_fFlags; // Behavior flags +protected: + // Object eye position + Vector m_vecViewOffset; +private: + // Object velocity + Vector m_vecVelocity; + Vector m_vecBaseVelocity; // Base velocity + + QAngle m_angNetworkAngles; + + // Last values to come over the wire. Used for interpolation. + Vector m_vecNetworkOrigin; + + // Friction. + float m_flFriction; + + // The moveparent received from networking data + CHandle m_hNetworkMoveParent; + // The owner! + EHANDLE m_hOwnerEntity; + EHANDLE m_hGroundEntity; + + char m_iName[MAX_PATH]; + + + +public: + // Object model index + short m_nModelIndex; +private: + unsigned char m_nRenderFX; + unsigned char m_nRenderMode; + unsigned char m_MoveType; + unsigned char m_MoveCollide; + unsigned char m_nWaterLevel; + +public: + char m_lifeState; + +// END PREDICTION DATA COMPACTION +public: public: // Time animation sequence or frame was last changed @@ -1290,53 +1485,38 @@ class C_BaseEntity : public IClientEntity float m_flCreateTime; - byte m_ubInterpolationFrame; - byte m_ubOldInterpolationFrame; - private: - // Effects to apply - int m_fEffects; - unsigned char m_nRenderMode; unsigned char m_nOldRenderMode; public: // Used to store the state we were added to the BSP as, so it can // reinsert the entity if the state changes. ClientRenderHandle_t m_hRender; // link into spatial partition + CBitVec< MAX_SPLITSCREEN_PLAYERS > m_VisibilityBits; // Interpolation says don't draw yet bool m_bReadyToDraw; + bool m_bClientSideRagdoll; // Should we be interpolating? static bool IsInterpolationEnabled(); - // Should we interpolate this tick? (Used to be EF_NOINTERP) - bool IsNoInterpolationFrame(); // - int m_nNextThinkTick; - int m_nLastThinkTick; - // Object model index - short m_nModelIndex; + int m_nLastThinkTick; -#ifdef TF_CLIENT_DLL - int m_nModelIndexOverrides[MAX_VISION_MODES]; -#endif char m_takedamage; - char m_lifeState; - int m_iHealth; + + // was pev->speed float m_flSpeed; - // Team Handling - int m_iTeamNum; - -#if !defined( NO_ENTITY_PREDICTION ) // Certain entities (projectiles) can be created on the client +#if !defined( NO_ENTITY_PREDICTION ) && defined( USE_PREDICTABLEID ) CPredictableId m_PredictableID; PredictionContext *m_pPredictionContext; #endif @@ -1378,11 +1558,17 @@ class C_BaseEntity : public IClientEntity // used by SourceTV since move-parents may be missing when child spawns. void HierarchyUpdateMoveParent(); - virtual bool IsDeflectable() { return false; } + void SetCPULevels( int nMinCPULevel, int nMaxCPULevel ); + void SetGPULevels( int nMinGPULevel, int nMaxGPULevel ); + int GetMinCPULevel( ) const; + int GetMaxCPULevel( ) const; + int GetMinGPULevel( ) const; + int GetMaxGPULevel( ) const; -protected: - int m_nFXComputeFrame; + + +protected: // FIXME: Should I move the functions handling these out of C_ClientEntity // and into C_BaseEntity? Then we could make these private. // Client handle @@ -1413,24 +1599,28 @@ class C_BaseEntity : public IClientEntity CUtlVector< thinkfunc_t > m_aThinkFunctions; int m_iCurrentThinkContext; - // Object eye position - Vector m_vecViewOffset; -#if defined(SIXENSE) + // TrackIR Vector m_vecEyeOffset; QAngle m_EyeAngleOffset; -#endif + + // TrackIR + int m_spawnflags; + // Allow studio models to tell us what their m_nBody value is virtual int GetStudioBody( void ) { return 0; } + // call this in postdataupdate to detect hierarchy changes + bool IsParentChanging(); + -public: - // This can be used to setup the entity as a client-only entity. It gets an entity handle, - // a render handle, and is put into the spatial partition. - bool InitializeAsClientEntityByIndex( int iIndex, RenderGroup_t renderGroup ); private: friend void OnRenderStart(); + // This can be used to setup the entity as a client-only entity. It gets an entity handle, + // a render handle, and is put into the spatial partition. + bool InitializeAsClientEntityByIndex( int iIndex, bool bRenderWithViewModels ); + // Figure out the smoothly interpolated origin for all server entities. Happens right before // letting all entities simulate. static void InterpolateServerEntities(); @@ -1468,11 +1658,9 @@ class C_BaseEntity : public IClientEntity // methods related to decal adding void AddStudioDecal( const Ray_t& ray, int hitbox, int decalIndex, bool doTrace, trace_t& tr, int maxLODToDecal = ADDDECAL_TO_ALL_LODS ); - void AddColoredStudioDecal( const Ray_t& ray, int hitbox, int decalIndex, bool doTrace, trace_t& tr, Color cColor, int maxLODToDecal ); void AddBrushModelDecal( const Ray_t& ray, const Vector& decalCenter, int decalIndex, bool doTrace, trace_t& tr ); void ComputePackedOffsets( void ); - int ComputePackedSize_R( datamap_t *map ); int GetIntermediateDataSize( void ); void UnlinkChild( C_BaseEntity *pParent, C_BaseEntity *pChild ); @@ -1495,16 +1683,7 @@ class C_BaseEntity : public IClientEntity float GetNextThink( int nContextIndex ) const; int GetNextThinkTick( int nContextIndex ) const; - // Object velocity - Vector m_vecVelocity; - CInterpolatedVar< Vector > m_iv_vecVelocity; - - Vector m_vecAbsVelocity; - - // was pev->avelocity - QAngle m_vecAngVelocity; - -// QAngle m_vecAbsAngVelocity; + void CleanUpAlphaProperty(); #if !defined( NO_ENTITY_PREDICTION ) // It's still in the list for "fixup purposes" and simulation, but don't try to render it any more... @@ -1520,54 +1699,45 @@ class C_BaseEntity : public IClientEntity // Timestamp of message arrival float m_flLastMessageTime; - // Base velocity - Vector m_vecBaseVelocity; - - // Gravity multiplier - float m_flGravity; + // Model instance data.. ModelInstanceHandle_t m_ModelInstance; // Shadow data ClientShadowHandle_t m_ShadowHandle; + CBitVec< MAX_SPLITSCREEN_PLAYERS > m_ShadowBits; // Per-splitscreen user shadow visibility bits - // A random value used by material proxies for each model instance. - float m_flProxyRandomValue; + // Fades + float m_fadeMinDist; + float m_fadeMaxDist; + float m_flFadeScale; ClientThinkHandle_t m_hThink; - int m_iEFlags; // entity flags EFL_* - - // Object movetype - unsigned char m_MoveType; - unsigned char m_MoveCollide; unsigned char m_iParentAttachment; // 0 if we're relative to the parent's absorigin and absangles. unsigned char m_iOldParentAttachment; - unsigned char m_nWaterLevel; - unsigned char m_nWaterType; - // For client/server entities, true if the entity goes outside the PVS. - // Unused for client only entities. - bool m_bDormant; + + // Prediction system bool m_bPredictable; - + bool m_bRenderWithViewModels; + bool m_bDisableCachedRenderBounds; + int m_nSplitUserPlayerPredictionSlot; // Hierarchy CHandle m_pMoveParent; CHandle m_pMoveChild; CHandle m_pMovePeer; CHandle m_pMovePrevPeer; - - // The moveparent received from networking data - CHandle m_hNetworkMoveParent; CHandle m_hOldMoveParent; string_t m_ModelName; CNetworkVarEmbedded( CCollisionProperty, m_Collision ); CNetworkVarEmbedded( CParticleProperty, m_Particles ); + CClientAlphaProperty *m_pClientAlphaProperty; // Physics state float m_flElasticity; @@ -1575,36 +1745,21 @@ class C_BaseEntity : public IClientEntity float m_flShadowCastDistance; EHANDLE m_ShadowDirUseOtherEntity; - EHANDLE m_hGroundEntity; float m_flGroundChangeTime; - // Friction. - float m_flFriction; - - Vector m_vecAbsOrigin; - // Object orientation - QAngle m_angAbsRotation; Vector m_vecOldOrigin; QAngle m_vecOldAngRotation; - Vector m_vecOrigin; + CInterpolatedVar< Vector > m_iv_vecOrigin; - QAngle m_angRotation; CInterpolatedVar< QAngle > m_iv_angRotation; // Specifies the entity-to-world transform matrix3x4_t m_rgflCoordinateFrame; - // Last values to come over the wire. Used for interpolation. - Vector m_vecNetworkOrigin; - QAngle m_angNetworkAngles; - - // Behavior flags - int m_fFlags; - // used to cull collision tests int m_CollisionGroup; @@ -1621,12 +1776,19 @@ class C_BaseEntity : public IClientEntity CNetworkVar( bool, m_bAnimatedEveryTick ); CNetworkVar( bool, m_bAlternateSorting ); + unsigned char m_nMinCPULevel; + unsigned char m_nMaxCPULevel; + unsigned char m_nMinGPULevel; + unsigned char m_nMaxGPULevel; + //Adrian unsigned char m_iTextureFrameIndex; // Bbox visualization unsigned char m_fBBoxVisFlags; + bool m_bIsValidIKAttachment; + // The list that holds OnDataChanged events uses this to make sure we don't get multiple // OnDataChanged calls in the same frame if the client receives multiple packets. int m_DataChangeEventRef; @@ -1636,8 +1798,7 @@ class C_BaseEntity : public IClientEntity CHandle< CBasePlayer > m_hPlayerSimulationOwner; #endif - // The owner! - EHANDLE m_hOwnerEntity; + EHANDLE m_hEffectEntity; // This is a random seed used by the networking code to allow client - side prediction code @@ -1663,30 +1824,15 @@ class C_BaseEntity : public IClientEntity protected: - void AddToInterpolationList(); - void RemoveFromInterpolationList(); - unsigned short m_InterpolationListEntry; // Entry into g_InterpolationList (or g_InterpolationList.InvalidIndex if not in the list). + void AddToEntityList( entity_list_ids_t listId ); + void RemoveFromEntityList( entity_list_ids_t listId ); + unsigned short m_ListEntry[NUM_ENTITY_LISTS]; // Entry into each g_EntityList (or InvalidIndex() if not in the list). - void AddToTeleportList(); - void RemoveFromTeleportList(); - unsigned short m_TeleportListEntry; - CThreadFastMutex m_CalcAbsolutePositionMutex; CThreadFastMutex m_CalcAbsoluteVelocityMutex; -#ifdef TF_CLIENT_DLL - // TF prevents drawing of any entity attached to players that aren't items in the inventory of the player. - // This is to prevent servers creating fake cosmetic items and attaching them to players. -public: - virtual bool ValidateEntityAttachedToPlayer( bool &bShouldRetry ); - bool EntityDeemedInvalid( void ) { return (m_bValidatedOwner && m_bDeemedInvalid); } -protected: - bool m_bValidatedOwner; - bool m_bDeemedInvalid; - bool m_bWasDeemedInvalid; - RenderMode_t m_PreviousRenderMode; - color32 m_PreviousRenderColor; -#endif +private: + bool m_bIsBlurred; }; EXTERN_RECV_TABLE(DT_BaseEntity); @@ -1725,6 +1871,16 @@ inline const CCollisionProperty *C_BaseEntity::CollisionProp() const return &m_Collision; } +inline CClientAlphaProperty *C_BaseEntity::AlphaProp() +{ + return m_pClientAlphaProperty; +} + +inline const CClientAlphaProperty *C_BaseEntity::AlphaProp() const +{ + return m_pClientAlphaProperty; +} + //----------------------------------------------------------------------------- // An inline version the game code can use //----------------------------------------------------------------------------- @@ -1763,26 +1919,6 @@ inline const matrix3x4_t &C_BaseEntity::EntityToWorldTransform() const return m_rgflCoordinateFrame; } -inline const Vector& C_BaseEntity::GetNetworkOrigin() const -{ - return m_vecNetworkOrigin; -} - -inline const QAngle& C_BaseEntity::GetNetworkAngles() const -{ - return m_angNetworkAngles; -} - -inline const model_t *C_BaseEntity::GetModel( void ) const -{ - return model; -} - -inline int C_BaseEntity::GetModelIndex( void ) const -{ - return m_nModelIndex; -} - //----------------------------------------------------------------------------- // Some helper methods that transform a point from entity space to world space + back //----------------------------------------------------------------------------- @@ -1966,7 +2102,7 @@ inline void C_BaseEntity::SetBaseVelocity( const Vector& v ) inline void C_BaseEntity::SetFriction( float flFriction ) { - m_flFriction = flFriction; + m_flFriction = flFriction; } inline void C_BaseEntity::SetGravity( float flGravity ) @@ -1994,48 +2130,92 @@ inline float C_BaseEntity::GetElasticity( void ) const return m_flElasticity; } -inline const color32 CBaseEntity::GetRenderColor() const +inline const color24 CBaseEntity::GetRenderColor() const { - return m_clrRender.Get(); + color24 c = { m_clrRender->r, m_clrRender->g, m_clrRender->b }; + return c; } -inline void C_BaseEntity::SetRenderColor( byte r, byte g, byte b ) +inline byte C_BaseEntity::GetRenderColorR() const { - color32 clr = { r, g, b, m_clrRender->a }; - m_clrRender = clr; + return m_clrRender->r; } -inline void C_BaseEntity::SetRenderColor( byte r, byte g, byte b, byte a ) +inline byte C_BaseEntity::GetRenderColorG() const +{ + return m_clrRender->g; +} + +inline byte C_BaseEntity::GetRenderColorB() const +{ + return m_clrRender->b; +} + +inline void C_BaseEntity::SetRenderColor( byte r, byte g, byte b ) { - color32 clr = { r, g, b, a }; - m_clrRender = clr; + m_clrRender.SetR( r ); + m_clrRender.SetG( g ); + m_clrRender.SetB( b ); } inline void C_BaseEntity::SetRenderColorR( byte r ) { - SetRenderColor( r, GetRenderColor().g, GetRenderColor().b ); + m_clrRender.SetR( r ); } inline void C_BaseEntity::SetRenderColorG( byte g ) { - SetRenderColor( GetRenderColor().r, g, GetRenderColor().b ); + m_clrRender.SetG( g ); } inline void C_BaseEntity::SetRenderColorB( byte b ) { - SetRenderColor( GetRenderColor().r, GetRenderColor().g, b ); + m_clrRender.SetB( b ); } -inline void C_BaseEntity::SetRenderColorA( byte a ) +inline RenderMode_t C_BaseEntity::GetRenderMode() const { - SetRenderColor( GetRenderColor().r, GetRenderColor().g, GetRenderColor().b, a ); + return (RenderMode_t)m_nRenderMode; } -inline RenderMode_t CBaseEntity::GetRenderMode() const +inline RenderFx_t C_BaseEntity::GetRenderFX() const { - return (RenderMode_t)m_nRenderMode; + return (RenderFx_t)m_nRenderFX; +} + +inline void C_BaseEntity::SetCPULevels( int nMinCPULevel, int nMaxCPULevel ) +{ + m_nMinCPULevel = nMinCPULevel; + m_nMaxCPULevel = nMaxCPULevel; +} + +inline void C_BaseEntity::SetGPULevels( int nMinGPULevel, int nMaxGPULevel ) +{ + m_nMinGPULevel = nMinGPULevel; + m_nMaxGPULevel = nMaxGPULevel; +} + +inline int C_BaseEntity::GetMinCPULevel( ) const +{ + return m_nMinCPULevel; } +inline int C_BaseEntity::GetMaxCPULevel( ) const +{ + return m_nMaxCPULevel; +} + +inline int C_BaseEntity::GetMinGPULevel( ) const +{ + return m_nMinGPULevel; +} + +inline int C_BaseEntity::GetMaxGPULevel( ) const +{ + return m_nMaxGPULevel; +} + + //----------------------------------------------------------------------------- // checks to see if the entity is marked for deletion //----------------------------------------------------------------------------- @@ -2074,8 +2254,7 @@ inline ClientRenderHandle_t& CBaseEntity::RenderHandle() return m_hRender; } -#ifdef SIXENSE - +// TrackIR inline const Vector& CBaseEntity::GetEyeOffset() const { return m_vecEyeOffset; @@ -2095,8 +2274,7 @@ inline void CBaseEntity::SetEyeAngleOffset( const QAngle & qa ) { m_EyeAngleOffset = qa; } - -#endif +// TrackIR //----------------------------------------------------------------------------- // Methods to cast away const @@ -2126,6 +2304,7 @@ inline VarMapping_t* C_BaseEntity::GetVarMapping() return &m_VarMap; } + //----------------------------------------------------------------------------- // Should we be interpolating? //----------------------------------------------------------------------------- @@ -2134,14 +2313,6 @@ inline bool C_BaseEntity::IsInterpolationEnabled() return s_bInterpolate; } -//----------------------------------------------------------------------------- -// Should we be interpolating during this frame? (was EF_NOINTERP) -//----------------------------------------------------------------------------- -inline bool C_BaseEntity::IsNoInterpolationFrame() -{ - return m_ubOldInterpolationFrame != m_ubInterpolationFrame; -} - //----------------------------------------------------------------------------- // Purpose: // Input : handle - @@ -2180,6 +2351,16 @@ inline bool C_BaseEntity::IsEnabledInToolView() const #endif } + +//----------------------------------------------------------------------------- +// Client version of UTIL_Remove +//----------------------------------------------------------------------------- +inline void UTIL_Remove( C_BaseEntity *pEntity ) +{ + pEntity->Remove(); +} + + //----------------------------------------------------------------------------- // Purpose: // Input : - @@ -2194,6 +2375,134 @@ inline bool C_BaseEntity::ShouldRecordInTools() const #endif } +inline bool C_BaseEntity::IsVisible() const +{ + ASSERT_LOCAL_PLAYER_RESOLVABLE(); + if ( INVALID_CLIENT_RENDER_HANDLE == m_hRender ) + return false; + return m_VisibilityBits.IsBitSet( GET_ACTIVE_SPLITSCREEN_SLOT() ); +} + +inline bool C_BaseEntity::IsVisibleToAnyPlayer() const +{ + return !m_VisibilityBits.IsAllClear(); +} + +inline bool C_BaseEntity::HasSpawnFlags( int nFlags ) const +{ + return (m_spawnflags & nFlags) != 0; +} + +//----------------------------------------------------------------------------- +// Inline methods +//----------------------------------------------------------------------------- +inline const char *C_BaseEntity::GetEntityName() +{ + return m_iName; +} + + + +class CAbsQueryScopeGuard +{ +public: + CAbsQueryScopeGuard( bool state ) + { + m_bSavedState = C_BaseEntity::IsAbsQueriesValid(); + C_BaseEntity::SetAbsQueriesValid( state ); + } + ~CAbsQueryScopeGuard() + { + C_BaseEntity::SetAbsQueriesValid( m_bSavedState ); + } +private: + bool m_bSavedState; +}; + +#define ABS_QUERY_GUARD( state ) CAbsQueryScopeGuard s_AbsQueryGuard( state ); + C_BaseEntity *CreateEntityByName( const char *className ); +#if !defined( NO_ENTITY_PREDICTION ) + +class CEntIndexLessFunc +{ +public: + bool Less( C_BaseEntity * const & lhs, C_BaseEntity * const & rhs, void *pContext ) + { + int e1 = lhs->entindex(); + int e2 = rhs->entindex(); + + // if an entity has an invalid entity index, then put it at the end of the list + e1 = ( e1 == -1 ) ? MAX_EDICTS : e1; + e2 = ( e2 == -1 ) ? MAX_EDICTS : e2; + + return e1 < e2; + } +}; + + +//----------------------------------------------------------------------------- +// Purpose: Maintains a list of predicted or client created entities +//----------------------------------------------------------------------------- +class CPredictableList +{ +public: + C_BaseEntity *GetPredictable( int slot ); + int GetPredictableCount( void ) const; + +protected: + void AddToPredictableList( C_BaseEntity *add ); + void RemoveFromPredictablesList( C_BaseEntity *remove ); + +private: + CUtlSortVector< C_BaseEntity *, CEntIndexLessFunc > m_Predictables; + + friend class C_BaseEntity; +}; + +//----------------------------------------------------------------------------- +// Purpose: +// Input : slot - +// Output : C_BaseEntity +//----------------------------------------------------------------------------- +FORCEINLINE C_BaseEntity *CPredictableList::GetPredictable( int slot ) +{ + return m_Predictables[ slot ]; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : int +//----------------------------------------------------------------------------- +FORCEINLINE int CPredictableList::GetPredictableCount( void ) const +{ + return m_Predictables.Count(); +} + +FORCEINLINE int C_BaseEntity::GetSplitUserPlayerPredictionSlot() +{ +#if defined( USE_PREDICTABLEID ) + Assert( m_bPredictable || m_pPredictionContext ); +#else + Assert( m_bPredictable ); +#endif + return m_nSplitUserPlayerPredictionSlot; +} + +extern CPredictableList *GetPredictables( int nSlot ); + +// To temporarily muck with gpGlobals->curtime +class CCurTimeScopeGuard +{ +public: + CCurTimeScopeGuard( float flNewCurTime, bool bOptionalCondition = true ); + ~CCurTimeScopeGuard(); +private: + + float m_flSavedTime; + bool m_bActive; +}; +#endif + #endif // C_BASEENTITY_H diff --git a/game/client/c_baseflex.cpp b/game/client/c_baseflex.cpp index b18168401..25f5393c2 100644 --- a/game/client/c_baseflex.cpp +++ b/game/client/c_baseflex.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // @@ -36,6 +36,8 @@ ConVar g_CV_FlexSmooth("flex_smooth", "1", 0, "Applies smoothing/decay curve to #undef CBaseFlex #endif +static int g_iFlexCounter = 0; + IMPLEMENT_CLIENTCLASS_DT(C_BaseFlex, DT_BaseFlex, CBaseFlex) RecvPropArray3( RECVINFO_ARRAY(m_flexWeight), RecvPropFloat(RECVINFO(m_flexWeight[0]))), RecvPropInt(RECVINFO(m_blinktoggle)), @@ -137,7 +139,8 @@ C_BaseFlex::C_BaseFlex() : SetupMappings( "phonemes" ); m_flFlexDelayedWeight = NULL; - m_cFlexDelayedWeight = 0; + + m_iMostRecentFlexCounter = 0xFFFFFFFF; /// Make sure size is correct Assert( PHONEME_CLASS_STRONG + 1 == NUM_PHONEME_CLASSES ); @@ -151,7 +154,11 @@ C_BaseFlex::C_BaseFlex() : C_BaseFlex::~C_BaseFlex() { - delete[] m_flFlexDelayedWeight; + if ( m_flFlexDelayedWeight ) + { + delete[] m_flFlexDelayedWeight; + m_flFlexDelayedWeight = NULL; + } m_SceneEvents.RemoveAll(); m_LocalToGlobal.RemoveAll(); } @@ -185,10 +192,28 @@ void C_BaseFlex::SetupMappings( char const *pchFileRoot ) Q_snprintf( strong->classname, sizeof( strong->classname ), "%s_strong", pchFileRoot ); } + +//---------------------------------------------------------------------------- +// Hooks into the fast path render system +//---------------------------------------------------------------------------- +IClientModelRenderable* C_BaseFlex::GetClientModelRenderable() +{ + // Cannot participate if it has a render clip plane + if ( !BaseClass::GetClientModelRenderable() ) + return NULL; + + // No flexes allowed for fast path atm + CStudioHdr *hdr = GetModelPtr(); + if ( !hdr || ( hdr->numflexcontrollers() != 0 ) ) + return NULL; + + return this; +} + + //----------------------------------------------------------------------------- // Purpose: initialize fast lookups when model changes //----------------------------------------------------------------------------- - CStudioHdr *C_BaseFlex::OnNewModel() { CStudioHdr *hdr = BaseClass::OnNewModel(); @@ -197,34 +222,42 @@ CStudioHdr *C_BaseFlex::OnNewModel() m_iBlink = -1; m_iEyeUpdown = LocalFlexController_t(-1); m_iEyeRightleft = LocalFlexController_t(-1); - m_bSearchedForEyeFlexes = false; m_iMouthAttachment = 0; - delete[] m_flFlexDelayedWeight; - m_flFlexDelayedWeight = NULL; - m_cFlexDelayedWeight = 0; + if ( m_flFlexDelayedWeight ) + { + delete[] m_flFlexDelayedWeight; + m_flFlexDelayedWeight = NULL; + } if (hdr) { - if (hdr->numflexdesc()) + int nFlexDescCount = hdr->numflexdesc(); + m_CachedFlexWeights.SetCount( nFlexDescCount ); + m_CachedDelayedFlexWeights.SetCount( nFlexDescCount ); + if ( nFlexDescCount ) { - m_cFlexDelayedWeight = hdr->numflexdesc(); - m_flFlexDelayedWeight = new float[ m_cFlexDelayedWeight ]; - memset( m_flFlexDelayedWeight, 0, sizeof( float ) * m_cFlexDelayedWeight ); + m_flFlexDelayedWeight = new float[ nFlexDescCount ]; + memset( m_flFlexDelayedWeight, 0, nFlexDescCount * sizeof(float) ); + memset( m_CachedFlexWeights.Base(), 0, nFlexDescCount * sizeof(float) ); + memset( m_CachedDelayedFlexWeights.Base(), 0, nFlexDescCount * sizeof(float) ); } - m_iv_flexWeight.SetMaxCount( hdr->numflexcontrollers() ); - + m_iv_flexWeight.SetMaxCount( gpGlobals->curtime, hdr->numflexcontrollers() ); m_iMouthAttachment = LookupAttachment( "mouth" ); - LinkToGlobalFlexControllers( hdr ); + // NOTE: Eye updown/right left controllers are *local* + // blink is global + m_iEyeUpdown = FindFlexController( "eyes_updown" ); + m_iEyeRightleft = FindFlexController( "eyes_rightleft" ); + m_iBlink = AddGlobalFlexController( "blink" ); } return hdr; } -void C_BaseFlex::StandardBlendingRules( CStudioHdr *hdr, Vector pos[], Quaternion q[], float currentTime, int boneMask ) +void C_BaseFlex::StandardBlendingRules( CStudioHdr *hdr, Vector pos[], QuaternionAligned q[], float currentTime, int boneMask ) { BaseClass::StandardBlendingRules( hdr, pos, q, currentTime, boneMask ); @@ -284,7 +317,7 @@ bool C_BaseFlex::GetSoundSpatialization( SpatializationInfo_t& info ) // Default things it's audible, put it at a better spot? if ( bret ) { - if ((info.info.nChannel == CHAN_VOICE || info.info.nChannel == CHAN_VOICE2) && m_iMouthAttachment > 0) + if (info.info.nChannel == CHAN_VOICE && m_iMouthAttachment > 0) { Vector origin; QAngle angles; @@ -311,10 +344,10 @@ bool C_BaseFlex::GetSoundSpatialization( SpatializationInfo_t& info ) //----------------------------------------------------------------------------- -// Purpose: run the interpreted FAC's expressions, converting global flex_controller +// Purpose: run the interpreted FAC's expressions, converting flex_controller // values into FAC weights //----------------------------------------------------------------------------- -void C_BaseFlex::RunFlexRules( CStudioHdr *hdr, float *dest ) +void C_BaseFlex::RunFlexRules( CStudioHdr *hdr, const float *pGlobalFlexWeight, float *dest ) { if ( !g_CV_FlexRules.GetInt() ) return; @@ -333,205 +366,208 @@ void C_BaseFlex::RunFlexRules( CStudioHdr *hdr, float *dest ) } //*/ - hdr->RunFlexRules( g_flexweight, dest ); + hdr->RunFlexRules( pGlobalFlexWeight, dest ); } -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -bool CFlexSceneFileManager::Init() +class CFlexSceneFileManager : CAutoGameSystem { - // Trakcer 16692: Preload these at startup to avoid hitch first time we try to load them during actual gameplay - FindSceneFile( NULL, "phonemes", true ); - FindSceneFile( NULL, "phonemes_weak", true ); - FindSceneFile(NULL, "phonemes_strong", true ); +public: -#if defined( HL2_CLIENT_DLL ) - FindSceneFile( NULL, "random", true ); - FindSceneFile( NULL, "randomAlert", true ); -#endif + CFlexSceneFileManager() : CAutoGameSystem( "CFlexSceneFileManager" ) + { + } -#if defined( TF_CLIENT_DLL ) - // HACK TO ALL TF TO HAVE PER CLASS OVERRIDES - char const *pTFClasses[] = - { - "scout", - "sniper", - "soldier", - "demo", - "medic", - "heavy", - "pyro", - "spy", - "engineer", - }; - - char fn[ MAX_PATH ]; - for ( int i = 0; i < ARRAYSIZE( pTFClasses ); ++i ) - { - Q_snprintf( fn, sizeof( fn ), "player/%s/phonemes/phonemes", pTFClasses[i] ); - FindSceneFile( NULL, fn, true ); - Q_snprintf( fn, sizeof( fn ), "player/%s/phonemes/phonemes_weak", pTFClasses[i] ); - FindSceneFile( NULL, fn, true ); - Q_snprintf( fn, sizeof( fn ), "player/%s/phonemes/phonemes_strong", pTFClasses[i] ); - FindSceneFile( NULL, fn, true ); - - if ( !IsX360() ) + virtual bool InitRecursive( const char *pFolder ) + { + if ( pFolder == NULL ) { - Q_snprintf( fn, sizeof( fn ), "player/hwm/%s/phonemes/phonemes", pTFClasses[i] ); - FindSceneFile( NULL, fn, true ); - Q_snprintf( fn, sizeof( fn ), "player/hwm/%s/phonemes/phonemes_weak", pTFClasses[i] ); - FindSceneFile( NULL, fn, true ); - Q_snprintf( fn, sizeof( fn ), "player/hwm/%s/phonemes/phonemes_strong", pTFClasses[i] ); - FindSceneFile( NULL, fn, true ); + pFolder = "expressions"; } - Q_snprintf( fn, sizeof( fn ), "player/%s/emotion/emotion", pTFClasses[i] ); - FindSceneFile( NULL, fn, true ); - if ( !IsX360() ) + char directory[ MAX_PATH ]; + Q_snprintf( directory, sizeof( directory ), "%s/*.*", pFolder ); + + FileFindHandle_t fh; + const char *fn; + + for (fn = g_pFullFileSystem->FindFirst( directory, &fh ); fn; fn = g_pFullFileSystem->FindNext( fh ) ) { - Q_snprintf( fn, sizeof( fn ), "player/hwm/%s/emotion/emotion", pTFClasses[i] ); - FindSceneFile( NULL, fn, true ); + if ( !stricmp( fn, ".") || !stricmp( fn, "..") ) + { + continue; + } + + if ( g_pFullFileSystem->FindIsDirectory( fh ) ) + { + char folderpath[MAX_PATH]; + Q_snprintf( folderpath, sizeof( folderpath ), "%s/%s", pFolder, fn ); + + InitRecursive( folderpath ); + continue; + } + + const char *pExt = Q_GetFileExtension( fn ); + if ( pExt && Q_stricmp( pExt, "vfe" ) ) + { + continue; + } + + char fullFileName[MAX_PATH]; + Q_snprintf( fullFileName, sizeof(fullFileName), "%s/%s", pFolder, fn ); + + // strip default folder and extension + int index = V_strlen( "expressions/" ); + char vfeName[ MAX_PATH ]; + V_StripExtension( &fullFileName[index], vfeName, sizeof( vfeName ) ); + V_FixSlashes( vfeName ); + + FindSceneFile( NULL, vfeName, true ); } + return true; } + + virtual bool Init() + { + // Trakcer 16692: Preload these at startup to avoid hitch first time we try to load them during actual gameplay + FindSceneFile( NULL, "phonemes", true ); + FindSceneFile( NULL, "phonemes_weak", true ); + FindSceneFile(NULL, "phonemes_strong", true ); + +#if defined( HL2_CLIENT_DLL ) + FindSceneFile( NULL, "random", true ); + FindSceneFile( NULL, "randomAlert", true ); #endif - return true; -} -//----------------------------------------------------------------------------- -// Tracker 14992: We used to load 18K of .vfes for every C_BaseFlex who lipsynced, but now we only load those files once globally. -// Note, we could wipe these between levels, but they don't ever load more than the weak/normal/strong phoneme classes that I can tell -// so I'll just leave them loaded forever for now -//----------------------------------------------------------------------------- -void CFlexSceneFileManager::Shutdown() -{ - DeleteSceneFiles(); -} -//----------------------------------------------------------------------------- -// Purpose: Sets up translations -// Input : *instance - -// *pSettinghdr - -// Output : void -//----------------------------------------------------------------------------- -void CFlexSceneFileManager::EnsureTranslations( IHasLocalToGlobalFlexSettings *instance, const flexsettinghdr_t *pSettinghdr ) -{ - // The only time instance is NULL is in Init() above, where we're just loading the .vfe files off of the hard disk. - if ( instance ) - { - instance->EnsureTranslations( pSettinghdr ); + InitRecursive( NULL ); + return true; } -} -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void *CFlexSceneFileManager::FindSceneFile( IHasLocalToGlobalFlexSettings *instance, const char *filename, bool allowBlockingIO ) -{ - char szFilename[MAX_PATH]; - Assert( V_strlen( filename ) < MAX_PATH ); - V_strcpy( szFilename, filename ); - -#if defined( TF_CLIENT_DLL ) - char szHWMFilename[MAX_PATH]; - if ( GetHWMExpressionFileName( szFilename, szHWMFilename ) ) + // Tracker 14992: We used to load 18K of .vfes for every C_BaseFlex who lipsynced, but now we only load those files once globally. + // Note, we could wipe these between levels, but they don't ever load more than the weak/normal/strong phoneme classes that I can tell + // so I'll just leave them loaded forever for now + virtual void Shutdown() { - V_strcpy( szFilename, szHWMFilename ); + DeleteSceneFiles(); } -#endif - - Q_FixSlashes( szFilename ); - // See if it's already loaded - int i; - for ( i = 0; i < m_FileList.Count(); i++ ) + //----------------------------------------------------------------------------- + // Purpose: Sets up translations + // Input : *instance - + // *pSettinghdr - + // Output : void + //----------------------------------------------------------------------------- + void EnsureTranslations( C_BaseFlex *instance, const flexsettinghdr_t *pSettinghdr ) { - CFlexSceneFile *file = m_FileList[ i ]; - if ( file && !Q_stricmp( file->filename, szFilename ) ) + // The only time instance is NULL is in Init() above, where we're just loading the .vfe files off of the hard disk. + if ( instance ) { - // Make sure translations (local to global flex controller) are set up for this instance - EnsureTranslations( instance, ( const flexsettinghdr_t * )file->buffer ); - return file->buffer; + instance->EnsureTranslations( pSettinghdr ); } } - - if ( !allowBlockingIO ) + + const void *FindSceneFile( C_BaseFlex *instance, const char *filename, bool allowBlockingIO ) { - return NULL; - } + char szFilename[MAX_PATH]; + Assert( V_strlen( filename ) < MAX_PATH ); + V_strcpy( szFilename, filename ); + - // Load file into memory - void *buffer = NULL; - int len = filesystem->ReadFileEx( VarArgs( "expressions/%s.vfe", szFilename ), "GAME", &buffer ); - if ( !len ) - return NULL; + Q_FixSlashes( szFilename ); - // Create scene entry - CFlexSceneFile *pfile = new CFlexSceneFile; - // Remember filename - Q_strncpy( pfile->filename, szFilename, sizeof( pfile->filename ) ); - // Remember data pointer - pfile->buffer = buffer; - // Add to list - m_FileList.AddToTail( pfile ); - - // Swap the entire file - if ( IsX360() ) - { - CByteswap swap; - swap.ActivateByteSwapping( true ); - byte *pData = (byte*)buffer; - flexsettinghdr_t *pHdr = (flexsettinghdr_t*)pData; - swap.SwapFieldsToTargetEndian( pHdr ); - - // Flex Settings - flexsetting_t *pFlexSetting = (flexsetting_t*)((byte*)pHdr + pHdr->flexsettingindex); - for ( int i = 0; i < pHdr->numflexsettings; ++i, ++pFlexSetting ) + // See if it's already loaded + int i; + for ( i = 0; i < m_FileList.Count(); i++ ) { - swap.SwapFieldsToTargetEndian( pFlexSetting ); - - flexweight_t *pWeight = (flexweight_t*)(((byte*)pFlexSetting) + pFlexSetting->settingindex ); - for ( int j = 0; j < pFlexSetting->numsettings; ++j, ++pWeight ) + CFlexSceneFile *file = m_FileList[ i ]; + if ( file && !V_stricmp( file->filename, szFilename ) ) { - swap.SwapFieldsToTargetEndian( pWeight ); + // Make sure translations (local to global flex controller) are set up for this instance + EnsureTranslations( instance, ( const flexsettinghdr_t * )file->buffer ); + return file->buffer; } } + + if ( !allowBlockingIO ) + { + return NULL; + } - // indexes - pData = (byte*)pHdr + pHdr->indexindex; - swap.SwapBufferToTargetEndian( (int*)pData, (int*)pData, pHdr->numindexes ); + // Load file into memory + void *buffer = NULL; + int len = filesystem->ReadFileEx( VarArgs( "expressions/%s.vfe", szFilename ), "GAME", &buffer ); - // keymappings - pData = (byte*)pHdr + pHdr->keymappingindex; - swap.SwapBufferToTargetEndian( (int*)pData, (int*)pData, pHdr->numkeys ); + if ( !len ) + return NULL; - // keyname indices - pData = (byte*)pHdr + pHdr->keynameindex; - swap.SwapBufferToTargetEndian( (int*)pData, (int*)pData, pHdr->numkeys ); - } + // Create scene entry + CFlexSceneFile *pfile = new CFlexSceneFile; + // Remember filename + Q_strncpy( pfile->filename, szFilename, sizeof( pfile->filename ) ); + // Remember data pointer + pfile->buffer = buffer; + // Add to list + m_FileList.AddToTail( pfile ); - // Fill in translation table - EnsureTranslations( instance, ( const flexsettinghdr_t * )pfile->buffer ); + // Swap the entire file + if ( IsX360() ) + { + CByteswap swap; + swap.ActivateByteSwapping( true ); + byte *pData = (byte*)buffer; + flexsettinghdr_t *pHdr = (flexsettinghdr_t*)pData; + swap.SwapFieldsToTargetEndian( pHdr ); + + // Flex Settings + flexsetting_t *pFlexSetting = (flexsetting_t*)((byte*)pHdr + pHdr->flexsettingindex); + for ( int i = 0; i < pHdr->numflexsettings; ++i, ++pFlexSetting ) + { + swap.SwapFieldsToTargetEndian( pFlexSetting ); + + flexweight_t *pWeight = (flexweight_t*)(((byte*)pFlexSetting) + pFlexSetting->settingindex ); + for ( int j = 0; j < pFlexSetting->numsettings; ++j, ++pWeight ) + { + swap.SwapFieldsToTargetEndian( pWeight ); + } + } - // Return data - return pfile->buffer; -} + // indexes + pData = (byte*)pHdr + pHdr->indexindex; + swap.SwapBufferToTargetEndian( (int*)pData, (int*)pData, pHdr->numindexes ); -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CFlexSceneFileManager::DeleteSceneFiles() -{ - while ( m_FileList.Count() > 0 ) + // keymappings + pData = (byte*)pHdr + pHdr->keymappingindex; + swap.SwapBufferToTargetEndian( (int*)pData, (int*)pData, pHdr->numkeys ); + + // keyname indices + pData = (byte*)pHdr + pHdr->keynameindex; + swap.SwapBufferToTargetEndian( (int*)pData, (int*)pData, pHdr->numkeys ); + } + + // Fill in translation table + EnsureTranslations( instance, ( const flexsettinghdr_t * )pfile->buffer ); + + // Return data + return pfile->buffer; + } + +private: + + void DeleteSceneFiles() { - CFlexSceneFile *file = m_FileList[ 0 ]; - m_FileList.Remove( 0 ); - free( file->buffer ); - delete file; + while ( m_FileList.Count() > 0 ) + { + CFlexSceneFile *file = m_FileList[ 0 ]; + m_FileList.Remove( 0 ); + delete[] file->buffer; + delete file; + } } -} + + CUtlVector< CFlexSceneFile * > m_FileList; +}; CFlexSceneFileManager g_FlexSceneFileManager; @@ -539,15 +575,66 @@ CFlexSceneFileManager g_FlexSceneFileManager; // Purpose: // Input : *filename - //----------------------------------------------------------------------------- -void *C_BaseFlex::FindSceneFile( const char *filename ) +const void *C_BaseFlex::FindSceneFile( const char *filename ) { - return g_FlexSceneFileManager.FindSceneFile( this, filename, false ); + // Ask manager to get the globally cached scene instead. + + // hunt up the tree for the filename starting with our model name prepended as the path + static char szExtendedPath[MAX_PATH]; + + const char *pModelName = NULL; + CStudioHdr *pStudioHdr = GetModelPtr(); + if ( pStudioHdr ) + { + pModelName = pStudioHdr->pszName(); + } + if ( !pModelName ) + { + return g_FlexSceneFileManager.FindSceneFile( this, filename, false ); + } + + if ( StringHasPrefix( pModelName, "models" ) ) + { + strcpy( szExtendedPath, StringAfterPrefix( pModelName, "models" ) + 1 ); + } + else + { + strcpy( szExtendedPath, pModelName ); + } + V_StripExtension( szExtendedPath, szExtendedPath, sizeof( szExtendedPath ) ); + V_FixupPathName( szExtendedPath, sizeof( szExtendedPath ), szExtendedPath ); + + const void *pSceneFile = NULL; + // FIXME: V_StripLastDir returns "./" path when it strips out the last one. That don't resolve on FindSceneFile + while ( V_strlen( szExtendedPath ) > 2 ) + { + static char szExtendedName[MAX_PATH]; + + V_ComposeFileName( szExtendedPath, filename, szExtendedName, sizeof( szExtendedName ) ); + + pSceneFile = g_FlexSceneFileManager.FindSceneFile( this, szExtendedName, false ); + + if ( pSceneFile ) + break; + + if ( !V_StripLastDir( szExtendedPath, sizeof( szExtendedPath ) ) ) + break; + } + + if ( !pSceneFile ) + { + // just ask for it by name + pSceneFile = g_FlexSceneFileManager.FindSceneFile( this, filename, false ); + } + + return pSceneFile; } + //----------------------------------------------------------------------------- // Purpose: make sure the eyes are within 30 degrees of forward //----------------------------------------------------------------------------- -Vector C_BaseFlex::SetViewTarget( CStudioHdr *pStudioHdr ) +Vector C_BaseFlex::SetViewTarget( CStudioHdr *pStudioHdr, const float *pGlobalFlexWeight ) { if ( !pStudioHdr ) return Vector( 0, 0, 0); @@ -555,23 +642,6 @@ Vector C_BaseFlex::SetViewTarget( CStudioHdr *pStudioHdr ) // aim the eyes Vector tmp = m_viewtarget; - if ( !m_bSearchedForEyeFlexes ) - { - m_bSearchedForEyeFlexes = true; - - m_iEyeUpdown = FindFlexController( "eyes_updown" ); - m_iEyeRightleft = FindFlexController( "eyes_rightleft" ); - - if ( m_iEyeUpdown != -1 ) - { - pStudioHdr->pFlexcontroller( m_iEyeUpdown )->localToGlobal = AddGlobalFlexController( "eyes_updown" ); - } - if ( m_iEyeRightleft != -1 ) - { - pStudioHdr->pFlexcontroller( m_iEyeRightleft )->localToGlobal = AddGlobalFlexController( "eyes_rightleft" ); - } - } - if (m_iEyeAttachment > 0) { matrix3x4_t attToWorld; @@ -597,13 +667,13 @@ Vector C_BaseFlex::SetViewTarget( CStudioHdr *pStudioHdr ) if ( m_iEyeUpdown != -1 ) { mstudioflexcontroller_t *pflex = pStudioHdr->pFlexcontroller( m_iEyeUpdown ); - eyeAng.x = g_flexweight[ pflex->localToGlobal ]; + eyeAng.x = pGlobalFlexWeight[ pflex->localToGlobal ]; } if ( m_iEyeRightleft != -1 ) { mstudioflexcontroller_t *pflex = pStudioHdr->pFlexcontroller( m_iEyeRightleft ); - eyeAng.y = g_flexweight[ pflex->localToGlobal ]; + eyeAng.y = pGlobalFlexWeight[ pflex->localToGlobal ]; } // debugoverlay->AddTextOverlay( GetAbsOrigin() + Vector( 0, 0, 64 ), 0, 0, "%5.3f %5.3f", eyeAng.x, eyeAng.y ); @@ -722,7 +792,7 @@ void C_BaseFlex::ComputeBlendedSetting( Emphasized_Phoneme *classes, float empha // scale - // newexpression - //----------------------------------------------------------------------------- -void C_BaseFlex::AddViseme( Emphasized_Phoneme *classes, float emphasis_intensity, int phoneme, float scale, bool newexpression ) +void C_BaseFlex::AddViseme( float *pGlobalFlexWeight, Emphasized_Phoneme *classes, float emphasis_intensity, int phoneme, float scale, bool newexpression ) { int type; @@ -760,7 +830,7 @@ void C_BaseFlex::AddViseme( Emphasized_Phoneme *classes, float emphasis_intensit // Translate to global controller number int j = FlexControllerLocalToGlobal( actual_flexsetting_header, pWeights->key ); // Add scaled weighting in - g_flexweight[j] += info->amount * scale * pWeights->weight; + pGlobalFlexWeight[j] += info->amount * scale * pWeights->weight; // Go to next setting pWeights++; } @@ -826,7 +896,7 @@ bool C_BaseFlex::SetupEmphasisBlend( Emphasized_Phoneme *classes, int phoneme ) // juststarted - //----------------------------------------------------------------------------- ConVar g_CV_PhonemeSnap("phonemesnap", "2", 0, "Lod at level at which visemes stops always considering two phonemes, regardless of duration." ); -void C_BaseFlex::AddVisemesForSentence( Emphasized_Phoneme *classes, float emphasis_intensity, CSentence *sentence, float t, float dt, bool juststarted ) +void C_BaseFlex::AddVisemesForSentence( float *pGlobalFlexWeight, Emphasized_Phoneme *classes, float emphasis_intensity, CSentence *sentence, float t, float dt, bool juststarted ) { CStudioHdr *hdr = GetModelPtr(); if ( !hdr ) @@ -911,7 +981,7 @@ void C_BaseFlex::AddVisemesForSentence( Emphasized_Phoneme *classes, float empha // FIXME: simple box filter. Should use something fancier scale = (t2 - t1); - AddViseme( classes, emphasis_intensity, phoneme->GetPhonemeCode(), scale, juststarted ); + AddViseme( pGlobalFlexWeight, classes, emphasis_intensity, phoneme->GetPhonemeCode(), scale, juststarted ); } } } @@ -920,7 +990,7 @@ void C_BaseFlex::AddVisemesForSentence( Emphasized_Phoneme *classes, float empha // Purpose: // Input : *classes - //----------------------------------------------------------------------------- -void C_BaseFlex::ProcessVisemes( Emphasized_Phoneme *classes ) +void C_BaseFlex::ProcessVisemes( Emphasized_Phoneme *classes, float *pGlobalFlexWeight ) { // Any sounds being played? if ( !MouthInfo().IsActive() ) @@ -969,7 +1039,7 @@ void C_BaseFlex::ProcessVisemes( Emphasized_Phoneme *classes ) float emphasis_intensity = sentence->GetIntensity( t, sentence_length ); // Blend and add visemes together - AddVisemesForSentence( classes, emphasis_intensity, sentence, t, dt, juststarted ); + AddVisemesForSentence( pGlobalFlexWeight, classes, emphasis_intensity, sentence, t, dt, juststarted ); } } @@ -990,14 +1060,12 @@ void C_BaseFlex::GetToolRecordingState( KeyValues *msg ) if ( !hdr ) return; - memset( g_flexweight, 0, sizeof( g_flexweight ) ); - if ( hdr->numflexcontrollers() == 0 ) return; LocalFlexController_t i; - ProcessSceneEvents( true ); + ProcessSceneEvents( true, NULL ); // FIXME: shouldn't this happen at runtime? // initialize the models local to global flex controller mappings @@ -1010,17 +1078,18 @@ void C_BaseFlex::GetToolRecordingState( KeyValues *msg ) } } + memset( s_pGlobalFlexWeight, 0, g_numflexcontrollers * sizeof( float ) ); + // blend weights from server for (i = LocalFlexController_t(0); i < hdr->numflexcontrollers(); i++) { mstudioflexcontroller_t *pflex = hdr->pFlexcontroller( i ); - g_flexweight[pflex->localToGlobal] = m_flexWeight[i]; // rescale - g_flexweight[pflex->localToGlobal] = g_flexweight[pflex->localToGlobal] * (pflex->max - pflex->min) + pflex->min; + s_pGlobalFlexWeight[pflex->localToGlobal] = m_flexWeight[i] * (pflex->max - pflex->min) + pflex->min; } - ProcessSceneEvents( false ); + ProcessSceneEvents( false, s_pGlobalFlexWeight ); // check for blinking if (m_blinktoggle != m_prevblinktoggle) @@ -1030,8 +1099,10 @@ void C_BaseFlex::GetToolRecordingState( KeyValues *msg ) } if (m_iBlink == -1) + { m_iBlink = AddGlobalFlexController( "blink" ); - g_flexweight[m_iBlink] = 0; + } + s_pGlobalFlexWeight[m_iBlink] = 0; // FIXME: this needs a better algorithm // blink the eyes @@ -1042,17 +1113,19 @@ void C_BaseFlex::GetToolRecordingState( KeyValues *msg ) t = cos(t); if (t > 0) { - g_flexweight[m_iBlink] = sqrtf( t ) * 2; - if (g_flexweight[m_iBlink] > 1) - g_flexweight[m_iBlink] = 2.0 - g_flexweight[m_iBlink]; + s_pGlobalFlexWeight[m_iBlink] = sqrtf( t ) * 2; + if (s_pGlobalFlexWeight[m_iBlink] > 1) + { + s_pGlobalFlexWeight[m_iBlink] = 2.0 - s_pGlobalFlexWeight[m_iBlink]; + } } } // Drive the mouth from .wav file playback... - ProcessVisemes( m_PhonemeClasses ); + ProcessVisemes( m_PhonemeClasses, s_pGlobalFlexWeight ); // Necessary??? - SetViewTarget( hdr ); + SetViewTarget( hdr, s_pGlobalFlexWeight ); Vector viewtarget = m_viewtarget; // Use the unfiltered value @@ -1064,8 +1137,8 @@ void C_BaseFlex::GetToolRecordingState( KeyValues *msg ) if ( flexupdown->localToGlobal != -1 && flexrightleft->localToGlobal != -1 ) { - float updown = g_flexweight[ flexupdown->localToGlobal ]; - float rightleft = g_flexweight[ flexrightleft->localToGlobal ]; + float updown = s_pGlobalFlexWeight[ flexupdown->localToGlobal ]; + float rightleft = s_pGlobalFlexWeight[ flexrightleft->localToGlobal ]; if ( flexupdown->min != flexupdown->max ) { @@ -1076,8 +1149,8 @@ void C_BaseFlex::GetToolRecordingState( KeyValues *msg ) rightleft = RemapVal( rightleft, flexrightleft->min, flexrightleft->max, 0.0f, 1.0f ); } - g_flexweight[ flexupdown->localToGlobal ] = updown; - g_flexweight[ flexrightleft->localToGlobal ] = rightleft; + s_pGlobalFlexWeight[ flexupdown->localToGlobal ] = updown; + s_pGlobalFlexWeight[ flexrightleft->localToGlobal ] = rightleft; } } @@ -1089,13 +1162,13 @@ void C_BaseFlex::GetToolRecordingState( KeyValues *msg ) // rescale if ( pflex->max != pflex->min ) { - g_flexweight[pflex->localToGlobal] = ( g_flexweight[pflex->localToGlobal] - pflex->min ) / ( pflex->max - pflex->min ); + s_pGlobalFlexWeight[pflex->localToGlobal] = ( s_pGlobalFlexWeight[pflex->localToGlobal] - pflex->min ) / ( pflex->max - pflex->min ); } } static BaseFlexRecordingState_t state; - state.m_nFlexCount = MAXSTUDIOFLEXCTRL; - state.m_pDestWeight = g_flexweight; + state.m_nFlexCount = g_numflexcontrollers; + state.m_pDestWeight = s_pGlobalFlexWeight; state.m_vecViewTarget = viewtarget; msg->SetPtr( "baseflex", &state ); } @@ -1127,37 +1200,18 @@ bool C_BaseFlex::UsesFlexDelayedWeights() } -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void C_BaseFlex::LinkToGlobalFlexControllers( CStudioHdr *hdr ) +void C_BaseFlex::InvalidateFlexCaches() { - if ( hdr && hdr->pFlexcontroller( LocalFlexController_t(0) )->localToGlobal == -1 ) - { - for (LocalFlexController_t i = LocalFlexController_t(0); i < hdr->numflexcontrollers(); i++) - { - int j = AddGlobalFlexController( hdr->pFlexcontroller( i )->pszName() ); - hdr->pFlexcontroller( i )->localToGlobal = j; - } - } + g_iFlexCounter++; } -//----------------------------------------------------------------------------- -// Purpose: Rendering callback to allow the client to set up all the model specific flex weights -//----------------------------------------------------------------------------- -void C_BaseFlex::SetupWeights( const matrix3x4_t *pBoneToWorld, int nFlexWeightCount, float *pFlexWeights, float *pFlexDelayedWeights ) +bool C_BaseFlex::IsFlexCacheValid() const { - // hack in an initialization - LinkToGlobalFlexControllers( GetModelPtr() ); - m_iBlink = AddGlobalFlexController( "blink" ); - - if ( SetupGlobalWeights( pBoneToWorld, nFlexWeightCount, pFlexWeights, pFlexDelayedWeights ) ) - { - SetupLocalWeights( pBoneToWorld, nFlexWeightCount, pFlexWeights, pFlexDelayedWeights ); - } + return m_iMostRecentFlexCounter == g_iFlexCounter; } + //----------------------------------------------------------------------------- // Purpose: Use the local bone positions to set flex control weights // via boneflexdrivers specified in the model @@ -1186,15 +1240,13 @@ void C_BaseFlex::BuildTransformations( CStudioHdr *pStudioHdr, Vector *pos, Quat //----------------------------------------------------------------------------- -// Purpose: process the entities networked state, vcd playback, wav file visemes, and blinks into a global shared flex controller array +// Purpose: //----------------------------------------------------------------------------- -bool C_BaseFlex::SetupGlobalWeights( const matrix3x4_t *pBoneToWorld, int nFlexWeightCount, float *pFlexWeights, float *pFlexDelayedWeights ) +void C_BaseFlex::SetupWeights( const matrix3x4_t *pBoneToWorld, int nFlexWeightCount, float *pFlexWeights, float *pFlexDelayedWeights ) { CStudioHdr *hdr = GetModelPtr(); if ( !hdr ) - return false; - - memset( g_flexweight, 0, sizeof(g_flexweight) ); + return; // FIXME: this should assert then, it's too complex a class for the model if ( hdr->numflexcontrollers() == 0 ) @@ -1205,26 +1257,53 @@ bool C_BaseFlex::SetupGlobalWeights( const matrix3x4_t *pBoneToWorld, int nFlexW { memset( pFlexDelayedWeights, 0, nSizeInBytes ); } - return false; + return; } + int nFlexDescCount = hdr->numflexdesc(); + Assert( nFlexDescCount == m_CachedFlexWeights.Count() ); + if ( IsFlexCacheValid() ) + { + int nCount = MIN( nFlexWeightCount, nFlexDescCount ); + memcpy( pFlexWeights, m_CachedFlexWeights.Base(), nCount * sizeof(float) ); + if ( pFlexDelayedWeights ) + { + memcpy( pFlexDelayedWeights, m_CachedDelayedFlexWeights.Base(), nCount * sizeof(float) ); + } + + modelrender->SetViewTarget( GetModelPtr(), GetBody(), m_CachedViewTarget ); + return; + } + + Assert( nFlexWeightCount >= nFlexDescCount ); + LocalFlexController_t i; - ProcessSceneEvents( true ); + ProcessSceneEvents( true, NULL ); + + // FIXME: shouldn't this happen at runtime? + // initialize the models local to global flex controller mappings + if ( hdr->pFlexcontroller( LocalFlexController_t(0) )->localToGlobal == -1 ) + { + for (i = LocalFlexController_t(0); i < hdr->numflexcontrollers(); i++) + { + int j = AddGlobalFlexController( hdr->pFlexcontroller( i )->pszName() ); + hdr->pFlexcontroller( i )->localToGlobal = j; + } + } - Assert( hdr->pFlexcontroller( LocalFlexController_t(0) )->localToGlobal != -1 ); + memset( s_pGlobalFlexWeight, 0, g_numflexcontrollers * sizeof(float) ); // get the networked flexweights and convert them from 0..1 to real dynamic range for (i = LocalFlexController_t(0); i < hdr->numflexcontrollers(); i++) { mstudioflexcontroller_t *pflex = hdr->pFlexcontroller( i ); - g_flexweight[pflex->localToGlobal] = m_flexWeight[i]; // rescale - g_flexweight[pflex->localToGlobal] = g_flexweight[pflex->localToGlobal] * (pflex->max - pflex->min) + pflex->min; + s_pGlobalFlexWeight[pflex->localToGlobal] = m_flexWeight[i] * (pflex->max - pflex->min) + pflex->min; } - ProcessSceneEvents( false ); + ProcessSceneEvents( false, s_pGlobalFlexWeight ); // check for blinking if (m_blinktoggle != m_prevblinktoggle) @@ -1233,11 +1312,6 @@ bool C_BaseFlex::SetupGlobalWeights( const matrix3x4_t *pBoneToWorld, int nFlexW m_blinktime = gpGlobals->curtime + g_CV_BlinkDuration.GetFloat(); } - if (m_iBlink == -1) - { - m_iBlink = AddGlobalFlexController( "blink" ); - } - // FIXME: this needs a better algorithm // blink the eyes float flBlinkDuration = g_CV_BlinkDuration.GetFloat(); @@ -1254,68 +1328,42 @@ bool C_BaseFlex::SetupGlobalWeights( const matrix3x4_t *pBoneToWorld, int nFlexW t = 2.0f - t; t = clamp( t, 0.0f, 1.0f ); // add it to whatever the blink track is doing - g_flexweight[m_iBlink] = clamp( g_flexweight[m_iBlink] + t, 0.0f, 1.0f ); + s_pGlobalFlexWeight[m_iBlink] = clamp( s_pGlobalFlexWeight[m_iBlink] + t, 0.0, 1.0 ); } } // Drive the mouth from .wav file playback... - ProcessVisemes( m_PhonemeClasses ); + ProcessVisemes( m_PhonemeClasses, s_pGlobalFlexWeight ); - return true; -} + // convert the flex controllers into actual flex values + RunFlexRules( hdr, s_pGlobalFlexWeight, pFlexWeights ); + + // aim the eyes + m_CachedViewTarget = SetViewTarget( hdr, s_pGlobalFlexWeight ); -void C_BaseFlex::RunFlexDelay( int nFlexWeightCount, float *pFlexWeights, float *pFlexDelayedWeights, float &flFlexDelayTime ) -{ // process the delayed version of the flexweights - if ( flFlexDelayTime > 0.0f && flFlexDelayTime < gpGlobals->curtime ) + float d = 1.0f; + if ( gpGlobals->frametime != 0 ) { - float d = clamp( gpGlobals->curtime - flFlexDelayTime, 0.0, gpGlobals->frametime ); - d = ExponentialDecay( 0.8, 0.033, d ); - - for ( int i = 0; i < nFlexWeightCount; i++) - { - pFlexDelayedWeights[i] = pFlexDelayedWeights[i] * d + pFlexWeights[i] * (1.0f - d); - } + d = ExponentialDecay( 0.8f, 0.033f, gpGlobals->frametime ); } - flFlexDelayTime = gpGlobals->curtime; -} - -//----------------------------------------------------------------------------- -// Purpose: convert the global flex controllers into model specific flex weights -//----------------------------------------------------------------------------- -void C_BaseFlex::SetupLocalWeights( const matrix3x4_t *pBoneToWorld, int nFlexWeightCount, float *pFlexWeights, float *pFlexDelayedWeights ) -{ - CStudioHdr *hdr = GetModelPtr(); - if ( !hdr ) - return; - - // BUGBUG: We have a bug with SetCustomModel that causes a disagreement between the studio header here and the one used in l_studio.cpp CModelRender::DrawModelExecute - // So when we hit that case, let's not do any work because otherwise we'd crash since the array sizes (m_flFlexDelayedWeight vs pFlexWeights) don't match. - // Note that this check is duplicated in CEconEntity::SetupWeights. - AssertMsg( nFlexWeightCount == m_cFlexDelayedWeight, "Disagreement between the number of flex weights. Do the studio headers match?" ); - if ( nFlexWeightCount != m_cFlexDelayedWeight ) + for ( i = LocalFlexController_t(0); i < nFlexDescCount; i++ ) { - return; + m_flFlexDelayedWeight[i] = m_flFlexDelayedWeight[i] * d + pFlexWeights[i] * (1 - d); } - // convert the flex controllers into actual flex values - RunFlexRules( hdr, pFlexWeights ); - - // aim the eyes - SetViewTarget( hdr ); - - AssertOnce( hdr->pFlexcontroller( LocalFlexController_t(0) )->localToGlobal != -1 ); - if ( pFlexDelayedWeights ) { - RunFlexDelay( nFlexWeightCount, pFlexWeights, m_flFlexDelayedWeight, m_flFlexDelayTime ); - memcpy( pFlexDelayedWeights, m_flFlexDelayedWeight, sizeof( float ) * nFlexWeightCount ); + memcpy( pFlexDelayedWeights, m_flFlexDelayedWeight, nFlexDescCount * sizeof(float) ); } - /* - LocalFlexController_t i; + // Cache off results + m_iMostRecentFlexCounter = g_iFlexCounter; + memcpy( m_CachedFlexWeights.Base(), pFlexWeights, nFlexDescCount * sizeof(float) ); + memcpy( m_CachedDelayedFlexWeights.Base(), m_flFlexDelayedWeight, nFlexDescCount * sizeof(float) ); + /* for (i = 0; i < hdr->numflexdesc; i++) { debugoverlay->AddTextOverlay( GetAbsOrigin() + Vector( 0, 0, 64 ), i-hdr->numflexcontrollers, 0, "%2d:%s : %3.2f", i, hdr->pFlexdesc( i )->pszFACS(), pFlexWeights[i] ); @@ -1326,21 +1374,18 @@ void C_BaseFlex::SetupLocalWeights( const matrix3x4_t *pBoneToWorld, int nFlexWe for (i = 0; i < g_numflexcontrollers; i++) { int j = hdr->pFlexcontroller( i )->link; - debugoverlay->AddTextOverlay( GetAbsOrigin() + Vector( 0, 0, 64 ), -i, 0, "%s %3.2f", g_flexcontroller[i], g_flexweight[j] ); + debugoverlay->AddTextOverlay( GetAbsOrigin() + Vector( 0, 0, 64 ), -i, 0, "%s %3.2f", g_flexcontroller[i], s_pGlobalFlexWeight[j] ); } */ } -//----------------------------------------------------------------------------- -// Purpose: Unified set of flex controller entries that all systems can talk to -//----------------------------------------------------------------------------- int C_BaseFlex::g_numflexcontrollers; char * C_BaseFlex::g_flexcontroller[MAXSTUDIOFLEXCTRL*4]; -float C_BaseFlex::g_flexweight[MAXSTUDIOFLEXDESC]; +float C_BaseFlex::s_pGlobalFlexWeight[MAXSTUDIOFLEXCTRL*4]; -int C_BaseFlex::AddGlobalFlexController( const char *szName ) +int C_BaseFlex::AddGlobalFlexController( char *szName ) { int i; for (i = 0; i < g_numflexcontrollers; i++) @@ -1478,7 +1523,7 @@ bool C_BaseFlex::ClearSceneEvent( CSceneEventInfo *info, bool fastKill, bool can // expression - // duration - //----------------------------------------------------------------------------- -void C_BaseFlex::AddSceneEvent( CChoreoScene *scene, CChoreoEvent *event, CBaseEntity *pTarget, bool bClientSide ) +void C_BaseFlex::AddSceneEvent( CChoreoScene *scene, CChoreoEvent *event, CBaseEntity *pTarget, bool bClientSide, C_SceneEntity *pSceneEntity ) { if ( !scene || !event ) { @@ -1503,6 +1548,7 @@ void C_BaseFlex::AddSceneEvent( CChoreoScene *scene, CChoreoEvent *event, CBaseE info.m_hTarget = pTarget; info.m_bStarted = false; info.m_bClientSide = bClientSide; + info.m_hSceneEntity = pSceneEntity; if (StartSceneEvent( &info, scene, event, actor, pTarget )) { @@ -1645,9 +1691,10 @@ void C_BaseFlex::SetFlexWeight( LocalFlexController_t index, float value ) if (pflexcontroller->max != pflexcontroller->min) { value = (value - pflexcontroller->min) / (pflexcontroller->max - pflexcontroller->min); - value = clamp( value, 0.0f, 1.0f ); + value = clamp( value, 0.0, 1.0 ); } + Assert( IsFinite( value ) ); m_flexWeight[ index ] = value; } } @@ -1676,10 +1723,8 @@ LocalFlexController_t C_BaseFlex::FindFlexController( const char *szName ) { for (LocalFlexController_t i = LocalFlexController_t(0); i < GetNumFlexControllers(); i++) { - if (stricmp( GetFlexControllerName( i ), szName ) == 0) - { + if ( !Q_stricmp( GetFlexControllerName( i ), szName ) ) return i; - } } // AssertMsg( 0, UTIL_VarArgs( "flexcontroller %s couldn't be mapped!!!\n", szName ) ); @@ -1689,7 +1734,7 @@ LocalFlexController_t C_BaseFlex::FindFlexController( const char *szName ) //----------------------------------------------------------------------------- // Purpose: Default implementation //----------------------------------------------------------------------------- -void C_BaseFlex::ProcessSceneEvents( bool bFlexEvents ) +void C_BaseFlex::ProcessSceneEvents( bool bFlexEvents, float *pGlobalFlexWeight ) { CStudioHdr *hdr = GetModelPtr(); if ( !hdr ) @@ -1720,7 +1765,7 @@ void C_BaseFlex::ProcessSceneEvents( bool bFlexEvents ) CChoreoScene *scene = info->m_pScene; Assert( scene ); - if ( ProcessSceneEvent( bFlexEvents, info, scene, event ) ) + if ( ProcessSceneEvent( pGlobalFlexWeight, bFlexEvents, info, scene, event ) ) { info->m_bStarted = true; } @@ -1740,7 +1785,7 @@ bool C_BaseFlex::ProcessFlexAnimationSceneEvent( CSceneEventInfo *info, CChoreoS return true; } -bool C_BaseFlex::ProcessFlexSettingSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event ) +bool C_BaseFlex::ProcessFlexSettingSceneEvent( float *pGlobalFlexWeight, CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event ) { // Flexanimations have to have an end time!!! if ( !event->HasEndTime() ) @@ -1755,16 +1800,19 @@ bool C_BaseFlex::ProcessFlexSettingSceneEvent( CSceneEventInfo *info, CChoreoSce // Have to find both strings if ( scenefile && name ) { - // Find the scene file - const flexsettinghdr_t *pExpHdr = ( const flexsettinghdr_t * )g_FlexSceneFileManager.FindSceneFile( this, scenefile, true ); - if ( pExpHdr ) + if ( info->m_pExpHdr == NULL) + { + info->m_pExpHdr = ( const flexsettinghdr_t * )FindSceneFile( scenefile ); + } + + if ( info->m_pExpHdr ) { float scenetime = scene->GetTime(); float scale = event->GetIntensity( scenetime ); // Add the named expression - AddFlexSetting( name, scale, pExpHdr, !info->m_bStarted ); + AddFlexSetting( pGlobalFlexWeight, name, scale, info->m_pExpHdr, !info->m_bStarted ); } } @@ -1778,7 +1826,7 @@ bool C_BaseFlex::ProcessFlexSettingSceneEvent( CSceneEventInfo *info, CChoreoSce // rhs - // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- -bool FlexSettingLessFunc( const FS_LocalToGlobal_t& lhs, const FS_LocalToGlobal_t& rhs ) +bool C_BaseFlex::FlexSettingLessFunc( const FS_LocalToGlobal_t& lhs, const FS_LocalToGlobal_t& rhs ) { return lhs.m_Key < rhs.m_Key; } @@ -1846,7 +1894,7 @@ int C_BaseFlex::FlexControllerLocalToGlobal( const flexsettinghdr_t *pSettinghdr // *pSettinghdr - // newexpression - //----------------------------------------------------------------------------- -void C_BaseFlex::AddFlexSetting( const char *expr, float scale, +void C_BaseFlex::AddFlexSetting( float *pGlobalFlexWeight, const char *expr, float scale, const flexsettinghdr_t *pSettinghdr, bool newexpression ) { int i; @@ -1861,14 +1909,12 @@ void C_BaseFlex::AddFlexSetting( const char *expr, float scale, const char *name = pSetting->pszName(); - if ( !V_stricmp( name, expr ) ) + if ( !stricmp( name, expr ) ) break; } - if ( i>=pSettinghdr->numflexsettings ) - { + if ( i >= pSettinghdr->numflexsettings ) return; - } flexweight_t *pWeights = NULL; int truecount = pSetting->psetting( (byte *)pSettinghdr, 0, &pWeights ); @@ -1881,16 +1927,16 @@ void C_BaseFlex::AddFlexSetting( const char *expr, float scale, // this is translating from the settings's local index to the models local index int index = FlexControllerLocalToGlobal( pSettinghdr, pWeights->key ); - // blend scaled weighting in to total (post networking g_flexweight!!!!) + // blend scaled weighting in to total float s = clamp( scale * pWeights->influence, 0.0f, 1.0f ); - g_flexweight[index] = g_flexweight[index] * (1.0f - s) + pWeights->weight * s; + pGlobalFlexWeight[index] = pGlobalFlexWeight[index] * (1.0f - s) + pWeights->weight * s; } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- -bool C_BaseFlex::ProcessSceneEvent( bool bFlexEvents, CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event ) +bool C_BaseFlex::ProcessSceneEvent( float *pGlobalFlexWeight, bool bFlexEvents, CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event ) { switch ( event->GetType() ) { @@ -1906,7 +1952,7 @@ bool C_BaseFlex::ProcessSceneEvent( bool bFlexEvents, CSceneEventInfo *info, CCh case CChoreoEvent::EXPRESSION: if ( !bFlexEvents ) { - return ProcessFlexSettingSceneEvent( info, scene, event ); + return ProcessFlexSettingSceneEvent( pGlobalFlexWeight, info, scene, event ); } return true; diff --git a/game/client/c_baseflex.h b/game/client/c_baseflex.h index 56c86cb32..4fe3d7dcf 100644 --- a/game/client/c_baseflex.h +++ b/game/client/c_baseflex.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // @@ -16,7 +16,7 @@ #include "c_baseanimatingoverlay.h" #include "sceneentity_shared.h" -#include "utlvector.h" +#include "UtlVector.h" //----------------------------------------------------------------------------- // Purpose: Item in list of loaded scene files @@ -37,93 +37,10 @@ class CFlexSceneFile struct Emphasized_Phoneme; class CSentence; -enum -{ - PHONEME_CLASS_WEAK = 0, - PHONEME_CLASS_NORMAL, - PHONEME_CLASS_STRONG, - - NUM_PHONEME_CLASSES -}; - -// Mapping for each loaded scene file used by this actor -struct FS_LocalToGlobal_t -{ - explicit FS_LocalToGlobal_t() : - m_Key( 0 ), - m_nCount( 0 ), - m_Mapping( 0 ) - { - } - - explicit FS_LocalToGlobal_t( const flexsettinghdr_t *key ) : - m_Key( key ), - m_nCount( 0 ), - m_Mapping( 0 ) - { - } - - void SetCount( int count ) - { - Assert( !m_Mapping ); - Assert( count > 0 ); - m_nCount = count; - m_Mapping = new int[ m_nCount ]; - Q_memset( m_Mapping, 0, m_nCount * sizeof( int ) ); - } - - FS_LocalToGlobal_t( const FS_LocalToGlobal_t& src ) - { - m_Key = src.m_Key; - delete m_Mapping; - m_Mapping = new int[ src.m_nCount ]; - Q_memcpy( m_Mapping, src.m_Mapping, src.m_nCount * sizeof( int ) ); - - m_nCount = src.m_nCount; - } - - ~FS_LocalToGlobal_t() - { - delete m_Mapping; - m_nCount = 0; - m_Mapping = 0; - } - - const flexsettinghdr_t *m_Key; - int m_nCount; - int *m_Mapping = NULL; -}; - -bool FlexSettingLessFunc( const FS_LocalToGlobal_t& lhs, const FS_LocalToGlobal_t& rhs ); - -class IHasLocalToGlobalFlexSettings -{ -public: - virtual void EnsureTranslations( const flexsettinghdr_t *pSettinghdr ) = 0; -}; - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -struct Emphasized_Phoneme -{ - // Global fields, setup at start - char classname[ 64 ]; - bool required; - // Global fields setup first time tracks played - bool basechecked; - const flexsettinghdr_t *base; - const flexsetting_t *exp; - - // Local fields, processed for each sentence - bool valid; - float amount; -}; - //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- -class C_BaseFlex : public C_BaseAnimatingOverlay, public IHasLocalToGlobalFlexSettings +class C_BaseFlex : public C_BaseAnimatingOverlay { DECLARE_CLASS( C_BaseFlex, C_BaseAnimatingOverlay ); public: @@ -136,35 +53,29 @@ class C_BaseFlex : public C_BaseAnimatingOverlay, public IHasLocalToGlobalFlexSe virtual void Spawn(); + virtual IClientModelRenderable* GetClientModelRenderable(); + virtual void InitPhonemeMappings(); void SetupMappings( char const *pchFileRoot ); virtual CStudioHdr *OnNewModel( void ); - virtual void StandardBlendingRules( CStudioHdr *hdr, Vector pos[], Quaternion q[], float currentTime, int boneMask ); + virtual void StandardBlendingRules( CStudioHdr *hdr, Vector pos[], QuaternionAligned q[], float currentTime, int boneMask ); virtual void OnThreadedDrawSetup(); // model specific virtual void BuildTransformations( CStudioHdr *pStudioHdr, Vector *pos, Quaternion q[], const matrix3x4_t& cameraTransform, int boneMask, CBoneBitList &boneComputed ); - static void LinkToGlobalFlexControllers( CStudioHdr *hdr ); virtual void SetupWeights( const matrix3x4_t *pBoneToWorld, int nFlexWeightCount, float *pFlexWeights, float *pFlexDelayedWeights ); - virtual bool SetupGlobalWeights( const matrix3x4_t *pBoneToWorld, int nFlexWeightCount, float *pFlexWeights, float *pFlexDelayedWeights ); - static void RunFlexDelay( int nFlexWeightCount, float *pFlexWeights, float *pFlexDelayedWeights, float &flFlexDelayTime ); - virtual void SetupLocalWeights( const matrix3x4_t *pBoneToWorld, int nFlexWeightCount, float *pFlexWeights, float *pFlexDelayedWeights ); virtual bool UsesFlexDelayedWeights(); - static void RunFlexRules( CStudioHdr *pStudioHdr, float *dest ); - - virtual Vector SetViewTarget( CStudioHdr *pStudioHdr ); - virtual bool GetSoundSpatialization( SpatializationInfo_t& info ); virtual void GetToolRecordingState( KeyValues *msg ); // Called at the lowest level to actually apply a flex animation - void AddFlexAnimation( CSceneEventInfo *info ); + void AddFlexAnimation( CSceneEventInfo *info ); void SetFlexWeight( LocalFlexController_t index, float value ); float GetFlexWeight( LocalFlexController_t index ); @@ -181,7 +92,7 @@ class C_BaseFlex : public C_BaseAnimatingOverlay, public IHasLocalToGlobalFlexSe int m_blinktoggle; - static int AddGlobalFlexController( const char *szName ); + static int AddGlobalFlexController( char *szName ); static char const *GetGlobalFlexControllerName( int idx ); // bah, this should be unified with all prev/current stuff. @@ -195,16 +106,6 @@ class C_BaseFlex : public C_BaseAnimatingOverlay, public IHasLocalToGlobalFlexSe // Start the specifics of an scene event virtual bool StartSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event, CChoreoActor *actor, C_BaseEntity *pTarget ); - // Manipulation of events for the object - // Should be called by think function to process all scene events - // The default implementation resets m_flexWeight array and calls - // AddSceneEvents - virtual void ProcessSceneEvents( bool bFlexEvents ); - - // Assumes m_flexWeight array has been set up, this adds the actual currently playing - // expressions to the flex weights and adds other scene events as needed - virtual bool ProcessSceneEvent( bool bFlexEvents, CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event ); - virtual bool ProcessSequenceSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event ); // Remove all playing events @@ -214,7 +115,7 @@ class C_BaseFlex : public C_BaseAnimatingOverlay, public IHasLocalToGlobalFlexSe virtual bool ClearSceneEvent( CSceneEventInfo *info, bool fastKill, bool canceled ); // Add the event to the queue for this actor - void AddSceneEvent( CChoreoScene *scene, CChoreoEvent *event, C_BaseEntity *pTarget = NULL, bool bClientSide = false ); + void AddSceneEvent( CChoreoScene *scene, CChoreoEvent *event, C_BaseEntity *pTarget = NULL, bool bClientSide = false, C_SceneEntity *pSceneEntity = NULL ); // Remove the event from the queue for this actor void RemoveSceneEvent( CChoreoScene *scene, CChoreoEvent *event, bool fastKill ); @@ -226,20 +127,33 @@ class C_BaseFlex : public C_BaseAnimatingOverlay, public IHasLocalToGlobalFlexSe virtual bool CheckSceneEventCompletion( CSceneEventInfo *info, float currenttime, CChoreoScene *scene, CChoreoEvent *event ); int FlexControllerLocalToGlobal( const flexsettinghdr_t *pSettinghdr, int key ); - - // IHasLocalToGlobalFlexSettings - virtual void EnsureTranslations( const flexsettinghdr_t *pSettinghdr ); + void EnsureTranslations( const flexsettinghdr_t *pSettinghdr ); // For handling scene files - void *FindSceneFile( const char *filename ); + const void *FindSceneFile( const char *filename ); + + static void InvalidateFlexCaches(); + bool IsFlexCacheValid() const; private: + Vector SetViewTarget( CStudioHdr *pStudioHdr, const float *pGlobalFlexWeight ); + void RunFlexRules( CStudioHdr *pStudioHdr, const float *pGlobalFlexWeight, float *dest ); + + // Manipulation of events for the object + // Should be called by think function to process all scene events + // The default implementation resets m_flexWeight array and calls + // AddSceneEvents + void ProcessSceneEvents( bool bFlexEvents, float *pGlobalFlexWeight ); + + // Assumes m_flexWeight array has been set up, this adds the actual currently playing + // expressions to the flex weights and adds other scene events as needed + bool ProcessSceneEvent( float *pGlobalFlexWeight, bool bFlexEvents, CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event ); bool RequestStartSequenceSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event, CChoreoActor *actor, CBaseEntity *pTarget ); bool ProcessFlexAnimationSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event ); - bool ProcessFlexSettingSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event ); - void AddFlexSetting( const char *expr, float scale, + bool ProcessFlexSettingSceneEvent( float *pGlobalFlexWeight, CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event ); + void AddFlexSetting( float *pGlobalFlexWeight, const char *expr, float scale, const flexsettinghdr_t *pSettinghdr, bool newexpression ); // Array of active SceneEvents, in order oldest to newest @@ -249,28 +163,107 @@ class C_BaseFlex : public C_BaseAnimatingOverlay, public IHasLocalToGlobalFlexSe bool HasSceneEvents() const; private: +// Mapping for each loaded scene file used by this actor + struct FS_LocalToGlobal_t + { + explicit FS_LocalToGlobal_t() : + m_Key( 0 ), + m_nCount( 0 ), + m_Mapping( 0 ) + { + } + + explicit FS_LocalToGlobal_t( const flexsettinghdr_t *key ) : + m_Key( key ), + m_nCount( 0 ), + m_Mapping( 0 ) + { + } + + void SetCount( int count ) + { + Assert( !m_Mapping ); + Assert( count > 0 ); + m_nCount = count; + m_Mapping = new int[ m_nCount ]; + Q_memset( m_Mapping, 0, m_nCount * sizeof( int ) ); + } + + FS_LocalToGlobal_t( const FS_LocalToGlobal_t& src ) + { + m_Key = src.m_Key; + delete m_Mapping; + m_Mapping = new int[ src.m_nCount ]; + Q_memcpy( m_Mapping, src.m_Mapping, src.m_nCount * sizeof( int ) ); + + m_nCount = src.m_nCount; + } + + ~FS_LocalToGlobal_t() + { + delete m_Mapping; + m_nCount = 0; + m_Mapping = 0; + } + + const flexsettinghdr_t *m_Key; + int m_nCount; + int *m_Mapping; + }; + + static bool FlexSettingLessFunc( const FS_LocalToGlobal_t& lhs, const FS_LocalToGlobal_t& rhs ); + CUtlRBTree< FS_LocalToGlobal_t, unsigned short > m_LocalToGlobal; float m_blinktime; int m_prevblinktoggle; - int m_iBlink; - LocalFlexController_t m_iEyeUpdown; - LocalFlexController_t m_iEyeRightleft; - bool m_bSearchedForEyeFlexes; + int m_iBlink; + LocalFlexController_t m_iEyeUpdown; + LocalFlexController_t m_iEyeRightleft; int m_iMouthAttachment; - float m_flFlexDelayTime; float *m_flFlexDelayedWeight; - int m_cFlexDelayedWeight; + + int m_iMostRecentFlexCounter; + Vector m_CachedViewTarget; + CUtlVector< float > m_CachedFlexWeights; + CUtlVector< float > m_CachedDelayedFlexWeights; // shared flex controllers static int g_numflexcontrollers; static char *g_flexcontroller[MAXSTUDIOFLEXCTRL*4]; // room for global set of flexcontrollers - static float g_flexweight[MAXSTUDIOFLEXDESC]; + static float s_pGlobalFlexWeight[MAXSTUDIOFLEXCTRL*4]; protected: + enum + { + PHONEME_CLASS_WEAK = 0, + PHONEME_CLASS_NORMAL, + PHONEME_CLASS_STRONG, + + NUM_PHONEME_CLASSES + }; + + //----------------------------------------------------------------------------- + // Purpose: + //----------------------------------------------------------------------------- + struct Emphasized_Phoneme + { + // Global fields, setup at start + char classname[ 64 ]; + bool required; + // Global fields setup first time tracks played + bool basechecked; + const flexsettinghdr_t *base; + const flexsetting_t *exp; + + // Local fields, processed for each sentence + bool valid; + float amount; + }; + Emphasized_Phoneme m_PhonemeClasses[ NUM_PHONEME_CLASSES ]; private: @@ -279,9 +272,9 @@ class C_BaseFlex : public C_BaseAnimatingOverlay, public IHasLocalToGlobalFlexSe const flexsetting_t *FindNamedSetting( const flexsettinghdr_t *pSettinghdr, const char *expr ); - void ProcessVisemes( Emphasized_Phoneme *classes ); - void AddVisemesForSentence( Emphasized_Phoneme *classes, float emphasis_intensity, CSentence *sentence, float t, float dt, bool juststarted ); - void AddViseme( Emphasized_Phoneme *classes, float emphasis_intensity, int phoneme, float scale, bool newexpression ); + void ProcessVisemes( Emphasized_Phoneme *classes, float *pGlobalFlexWeight ); + void AddVisemesForSentence( float *pGlobalFlexWeight, Emphasized_Phoneme *classes, float emphasis_intensity, CSentence *sentence, float t, float dt, bool juststarted ); + void AddViseme( float *pGlobalFlexWeight, Emphasized_Phoneme *classes, float emphasis_intensity, int phoneme, float scale, bool newexpression ); bool SetupEmphasisBlend( Emphasized_Phoneme *classes, int phoneme ); void ComputeBlendedSetting( Emphasized_Phoneme *classes, float emphasis_intensity ); @@ -296,30 +289,6 @@ class C_BaseFlex : public C_BaseAnimatingOverlay, public IHasLocalToGlobalFlexSe }; -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -class CFlexSceneFileManager : CAutoGameSystem -{ -public: - - CFlexSceneFileManager() : CAutoGameSystem( "CFlexSceneFileManager" ) - { - } - - virtual bool Init(); - virtual void Shutdown(); - - void EnsureTranslations( IHasLocalToGlobalFlexSettings *instance, const flexsettinghdr_t *pSettinghdr ); - void *FindSceneFile( IHasLocalToGlobalFlexSettings *instance, const char *filename, bool allowBlockingIO ); - -private: - void DeleteSceneFiles(); - - CUtlVector< CFlexSceneFile * > m_FileList; -}; - - //----------------------------------------------------------------------------- // Do we have active expressions? //----------------------------------------------------------------------------- @@ -333,7 +302,6 @@ EXTERN_RECV_TABLE(DT_BaseFlex); float *GetVisemeWeights( int phoneme ); - #endif // C_STUDIOFLEX_H diff --git a/game/client/c_baselesson.cpp b/game/client/c_baselesson.cpp new file mode 100644 index 000000000..1ec2c1e65 --- /dev/null +++ b/game/client/c_baselesson.cpp @@ -0,0 +1,3820 @@ +//========= Copyright © 1996-2008, Valve Corporation, All rights reserved. ============// +// +// Purpose: Client handler implementations for instruction players how to play +// +//=============================================================================// + +#include "cbase.h" + +#include "c_baselesson.h" +#include "c_gameinstructor.h" + +#include "hud_locator_target.h" +#include "c_world.h" +#include "iinput.h" +#include "ammodef.h" +#include "vprof.h" +#include "view.h" +#include "vstdlib/ikeyvaluessystem.h" + +#ifdef INFESTED_DLL + #include "c_asw_marine.h" + #include "c_asw_marine_resource.h" +#endif + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + +#define LESSON_PRIORITY_MAX 1000 +#define LESSON_PRIORITY_NONE 0 +#define LESSON_MIN_TIME_ON_SCREEN_TO_MARK_DISPLAYED 1.5f +#define LESSON_MIN_TIME_BEFORE_LOCK_ALLOWED 0.1f +#define LESSON_DISTANCE_UPDATE_RATE 0.25f + +// See comments in UtlSymbol on why this is useful and how it works +IMPLEMENT_PRIVATE_SYMBOLTYPE( CGameInstructorSymbol ); + +extern ConVar gameinstructor_verbose; +extern ConVar gameinstructor_verbose_lesson; +extern ConVar gameinstructor_find_errors; + +// +// CGameInstructorLesson +// + +Color CBaseLesson::m_rgbaVerboseHeader = Color( 255, 128, 64, 255 ); +Color CBaseLesson::m_rgbaVerbosePlain = Color( 64, 128, 255, 255 ); +Color CBaseLesson::m_rgbaVerboseName = Color( 255, 255, 255, 255 ); +Color CBaseLesson::m_rgbaVerboseOpen = Color( 0, 255, 0, 255 ); +Color CBaseLesson::m_rgbaVerboseClose = Color( 255, 0, 0, 255 ); +Color CBaseLesson::m_rgbaVerboseSuccess = Color( 255, 255, 0, 255 ); +Color CBaseLesson::m_rgbaVerboseUpdate = Color( 255, 0, 255, 255 ); + + +CBaseLesson::CBaseLesson( const char *pchName, bool bIsDefaultHolder, bool bIsOpenOpportunity, int nSplitScreenSlot ) +{ + COMPILE_TIME_ASSERT( sizeof( CGameInstructorSymbol ) == sizeof( CUtlSymbol ) ); + + m_nSplitScreenSlot = nSplitScreenSlot; + m_stringName = pchName; + m_stringReplaceKey = ""; + m_bIsDefaultHolder = bIsDefaultHolder; + m_bIsOpenOpportunity = bIsOpenOpportunity; + + Init(); +} + +CBaseLesson::~CBaseLesson( void ) +{ + if ( m_pRoot ) + { + // Remove from root's children list + m_pRoot->m_OpenOpportunities.FindAndRemove( this ); + } + else + { + for ( int i = 0; i < m_OpenOpportunities.Count(); ++i ) + { + // Remove from children if they are still around + CBaseLesson *pLesson = m_OpenOpportunities[ i ]; + pLesson->m_pRoot = NULL; + } + } +} + +void CBaseLesson::AddPrerequisite( const char *pchLessonName ) +{ + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerboseHeader, "\t%s: ", GetName() ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "Adding prereq " ); + ConColorMsg( CBaseLesson::m_rgbaVerboseOpen, "\"%s\"", pchLessonName ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ".\n" ); + } + + const CBaseLesson *pPrerequisite = GetGameInstructor().GetLesson( pchLessonName ); + if ( !pPrerequisite ) + { + DevWarning( "Prerequisite %s added by lesson %s doesn't exist!\n", pchLessonName, GetName() ); + return; + } + + m_Prerequisites.AddToTail( pPrerequisite ); +} + +void CBaseLesson::SetRoot( CBaseLesson *pRoot ) +{ + m_pRoot = pRoot; + + if ( m_pRoot->m_OpenOpportunities.Find( this ) == -1 ) + { + m_pRoot->m_OpenOpportunities.AddToTail( this ); + } +} + +bool CBaseLesson::ShouldShowSpew( void ) +{ + if ( gameinstructor_verbose_lesson.GetString()[ 0 ] == '\0' ) + return false; + + return ( Q_stristr( GetName(), gameinstructor_verbose_lesson.GetString() ) != NULL ); +} + +bool CBaseLesson::NoPriority( void ) const +{ + return ( m_iPriority == LESSON_PRIORITY_NONE ); +} + +bool CBaseLesson::IsLocked( void ) const +{ + if ( m_fLockDuration == 0.0f ) + return false; + + if ( !IsInstructing() || !IsVisible() ) + return false; + + float fLockTime = m_fLockTime; + + if ( fLockTime == 0.0f ) + { + fLockTime = m_fStartTime; + } + + return ( gpGlobals->curtime > m_fStartTime + LESSON_MIN_TIME_BEFORE_LOCK_ALLOWED && gpGlobals->curtime < fLockTime + m_fLockDuration ); +} + +bool CBaseLesson::IsLearned( void ) const +{ + if ( m_iDisplayLimit > 0 && m_iDisplayCount >= m_iDisplayLimit ) + return true; + + if ( m_iSuccessLimit > 0 && m_iSuccessCount >= m_iSuccessLimit ) + return true; + + return false; +} + +bool CBaseLesson::PrerequisitesHaveBeenMet( void ) const +{ + for ( int i = 0; i < m_Prerequisites.Count(); ++i ) + { + if ( !m_Prerequisites[ i ]->IsLearned() ) + { + // Failed a prereq + return false; + } + } + + // All prereqs passed + return true; +} + +bool CBaseLesson::IsTimedOut( void ) +{ + VPROF_BUDGET( "CBaseLesson::IsTimedOut", "GameInstructor" ); + + // Check for no timeout + if ( m_fTimeout == 0.0f ) + return false; + + float fStartTime = m_fStartTime; + + if ( GetRoot()->IsLearned() ) + { + if ( !m_bBumpWithTimeoutWhenLearned ) + { + // Time out instantly if we've learned this and don't want to keep it open for priority bumping + return true; + } + else + { + // It'll never be active, so lets use timeout based on when it was initialized + fStartTime = m_fInitTime; + } + } + + if ( !fStartTime ) + { + if ( !m_bCanTimeoutWhileInactive ) + { + return false; + } + + // Not active, so lets use timeout based on when it was initialized + fStartTime = m_fInitTime; + } + + bool bTimedOut = ( fStartTime + m_fTimeout < gpGlobals->curtime ); + + if ( bTimedOut ) + { + SetCloseReason( "Timed out." ); + } + + return bTimedOut; +} + +void CBaseLesson::ResetDisplaysAndSuccesses( void ) +{ + m_iDisplayCount = 0; + + m_bSuccessCounted = false; + m_iSuccessCount = 0; +} + +bool CBaseLesson::IncDisplayCount( void ) +{ + if ( m_iDisplayCount < m_iDisplayLimit ) + { + m_iDisplayCount++; + return true; + } + + return false; +} + +bool CBaseLesson::IncSuccessCount( void ) +{ + if ( m_iSuccessCount < m_iSuccessLimit ) + { + m_iSuccessCount++; + return true; + } + + return false; +} + +void CBaseLesson::Init( void ) +{ + m_pRoot = NULL; + m_bSuccessCounted = false; + + SetCloseReason( "None given." ); + + m_iPriority = LESSON_PRIORITY_MAX; // Set to invalid value to ensure that it is actually set later on + m_iInstanceType = LESSON_INSTANCE_MULTIPLE; + m_iFixedInstancesMax = 1; + m_bReplaceOnlyWhenStopped = false; + m_iTeam = TEAM_ANY; + m_bOnlyKeyboard = false; + m_bOnlyGamepad = false; + + m_iDisplayLimit = 0; + m_iDisplayCount = 0; + m_bWasDisplayed = false; + + m_iSuccessLimit = 0; + m_iSuccessCount = 0; + + m_fLockDuration = 0.0f; + m_bCanOpenWhenDead = false; + m_bBumpWithTimeoutWhenLearned = false; + m_bCanTimeoutWhileInactive = false; + m_fTimeout = 0.0f; + + m_fInitTime = gpGlobals->curtime; + m_fStartTime = 0.0f; + m_fLockTime = 0.0f; + + m_fUpdateInterval = 0.5; + + m_bHasPlayedSound = false; + + m_szStartSound = "Instructor.LessonStart"; + m_szLessonGroup = ""; + + m_iNumDelayedPlayerSwaps = 0; +} + +void CBaseLesson::TakePlaceOf( CBaseLesson *pLesson ) +{ + // Transfer over marked as displayed so a replaced lesson won't count as an extra display + m_bWasDisplayed = pLesson->m_bWasDisplayed; + pLesson->m_bWasDisplayed = false; +} + +void CBaseLesson::MarkSucceeded( void ) +{ + if ( !m_bSuccessCounted ) + { + GetGameInstructor().MarkSucceeded( GetName() ); + m_bSuccessCounted = true; + } +} + +void CBaseLesson::CloseOpportunity( const char *pchReason ) +{ + SetCloseReason( pchReason ); + m_bIsOpenOpportunity = false; +} + +bool CBaseLesson::DoDelayedPlayerSwaps( void ) const +{ + // A bot has swapped places with a player or player with a bot... + // At the time of the actual swap there was no client representation for the new player... + // So that swap was queued up and now we're going to make things right! + while ( m_iNumDelayedPlayerSwaps ) + { + C_BasePlayer *pNewPlayer = UTIL_PlayerByUserId( m_pDelayedPlayerSwap[ m_iNumDelayedPlayerSwaps - 1 ].iNewUserID ); + + if ( !pNewPlayer ) + { + // There is still no client representation of the new player, we'll have to try again later + if ( gameinstructor_verbose.GetInt() > 1 ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\tFailed delayed player swap!" ); + } + return false; + } + + if ( gameinstructor_verbose.GetInt() > 1 ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\tSuccessful delayed player swap!" ); + } + + m_pDelayedPlayerSwap[ m_iNumDelayedPlayerSwaps - 1 ].phHandleToChange->Set( pNewPlayer ); + + m_iNumDelayedPlayerSwaps--; + } + + return true; +} + + +// +// CTextLesson +// + +void CTextLesson::Init( void ) +{ + m_szDisplayText = ""; + m_szDisplayParamText = ""; + m_szBinding = ""; + m_szGamepadBinding = ""; +} + +void CTextLesson::Start( void ) +{ + // TODO: Display some text + //m_szDisplayText +} + + +void CTextLesson::Stop( void ) +{ + // TODO: Clean up text +} + + +// +// CIconLesson +// + +void CIconLesson::Init( void ) +{ + m_hIconTarget = NULL; + m_szVguiTargetName = ""; + m_szVguiTargetLookup = ""; + m_nVguiTargetEdge = 0; + + m_hLocatorTarget = -1; + m_bFixedPosition = false; + m_bNoIconTarget = false; + m_bAllowNodrawTarget = false; + + m_bVisible = true; + m_bShowWhenOccluded = true; + m_bNoOffscreen = false; + m_bForceCaption = false; + + m_szOnscreenIcon = ""; + m_szOffscreenIcon = ""; + + m_flUpOffset = 0.0f; + m_flRelativeUpOffset = 0.0f; + m_fFixedPositionX = 0.0f; + m_fFixedPositionY = 0.0f; + + m_fRange = 0.0f; + m_fCurrentDistance = 0.0f; + + m_fOnScreenStartTime = 0.0f; + m_fUpdateDistanceTime = 0.0f; + + m_iFlags = LOCATOR_ICON_FX_NONE; + + m_szCaptionColor = "255,255,255";// Default to white +} + +void CIconLesson::Start( void ) +{ + if ( !DoDelayedPlayerSwaps() ) + { + return; + } + + // Display some text + C_BaseEntity *pIconTarget = m_hIconTarget.Get(); + + if ( !pIconTarget ) + { + if ( !m_bNoIconTarget ) + { + // Wanted one, but couldn't get it + CloseOpportunity( "Icon Target handle went invalid before the lesson started!" ); + } + + return; + } + else + { + if ( ( pIconTarget->IsEffectActive( EF_NODRAW ) || pIconTarget->IsDormant() ) && !m_bAllowNodrawTarget ) + { + // We don't allow no draw entities + CloseOpportunity( "Icon Target is using effect NODRAW and allow_nodraw_target is false!" ); + return; + } + } + + CLocatorTarget *pLocatorTarget = NULL; + + if( m_hLocatorTarget != -1 ) + { + // Lets try the handle that we've held on to + pLocatorTarget = Locator_GetTargetFromHandle( m_hLocatorTarget ); + + if ( !pLocatorTarget ) + { + // It's gone stale, get a new target + m_hLocatorTarget = Locator_AddTarget(); + pLocatorTarget = Locator_GetTargetFromHandle( m_hLocatorTarget ); + } + } + else + { + // Get a new target + m_hLocatorTarget = Locator_AddTarget(); + pLocatorTarget = Locator_GetTargetFromHandle( m_hLocatorTarget ); + } + + if( m_hLocatorTarget == -1 || !pLocatorTarget ) + { + CloseOpportunity( "Could not get a handle for new locator target. Too many targets in use!" ); + return; + } + + pLocatorTarget->AddIconEffects( m_iFlags ); + + pLocatorTarget->SetCaptionColor( GetCaptionColorString() ); + + UpdateLocatorTarget( pLocatorTarget, pIconTarget ); + + // Update occlusion data + Locator_ComputeTargetIconPositionFromHandle( m_hLocatorTarget ); +} + + +void CIconLesson::Stop( void ) +{ + if ( !DoDelayedPlayerSwaps() ) + { + return; + } + + if ( m_hLocatorTarget != -1 ) + { + Locator_RemoveTarget( m_hLocatorTarget ); + } + + m_fOnScreenStartTime = 0.0f; +} + +void CIconLesson::Update( void ) +{ + if ( !DoDelayedPlayerSwaps() ) + { + return; + } + + C_BaseEntity *pIconTarget = m_hIconTarget.Get(); + + if ( !pIconTarget ) + { + if ( !m_bNoIconTarget ) + { + CloseOpportunity( "Lost our icon target handle returned NULL." ); + } + + return; + } + else + { + if ( ( pIconTarget->IsEffectActive( EF_NODRAW ) || pIconTarget->IsDormant() ) && !m_bAllowNodrawTarget ) + { + // We don't allow no draw entities + CloseOpportunity( "Icon Target is using effect NODRAW and allow_nodraw_target is false!" ); + return; + } + } + + CLocatorTarget *pLocatorTarget = Locator_GetTargetFromHandle( m_hLocatorTarget ); + if ( !pLocatorTarget ) + { + // Temp instrumentation to catch a bug - possibly calling Update without having called Start? + Warning( "Problem in lesson %s: Locator_GetTargetFromHandle returned null for handle %d.\n IsInstanceActive: %s. IsInstructing: %s. IsLearned: %s\n", + GetName(), m_hLocatorTarget, + (IsInstanceActive() ? "yes" : "no"), + (IsInstructing() ? "yes" : "no"), + (IsLearned() ? "yes" : "no") ); + CloseOpportunity( "Lost locator target handle." ); + return; + } + + UpdateLocatorTarget( pLocatorTarget, pIconTarget ); + C_BasePlayer *pLocalPlayer = GetGameInstructor().GetLocalPlayer(); + + // Check if it has been onscreen long enough to count as being displayed + if ( m_fOnScreenStartTime == 0.0f ) + { + if ( pLocatorTarget->IsOnScreen() && ( IsPresentComplete() || ( pLocatorTarget->GetIconEffectsFlags() & LOCATOR_ICON_FX_STATIC ) ) ) + { + // Is either static or has finished presenting and is on screen + m_fOnScreenStartTime = gpGlobals->curtime; + } + } + else + { + if ( !pLocatorTarget->IsOnScreen() ) + { + // Was visible before, but it isn't now + m_fOnScreenStartTime = 0.0f; + } + else if ( gpGlobals->curtime - m_fOnScreenStartTime >= LESSON_MIN_TIME_ON_SCREEN_TO_MARK_DISPLAYED ) + { + // Lesson on screen long enough to be counted as displayed + m_bWasDisplayed = true; + } + } + + if ( m_fUpdateDistanceTime < gpGlobals->curtime ) + { + // Update it's distance from the local player + C_BaseEntity *pTarget = m_hIconTarget.Get(); + + if ( !pLocalPlayer || !pTarget || pLocalPlayer == pTarget ) + { + m_fCurrentDistance = 0.0f; + } + else + { + m_fCurrentDistance = pLocalPlayer->ActivePlayerCombatCharacter()->EyePosition().DistTo( pTarget->WorldSpaceCenter() ); + } + + m_fUpdateDistanceTime = gpGlobals->curtime + LESSON_DISTANCE_UPDATE_RATE; + } +} + +void CIconLesson::UpdateInactive( void ) +{ + if ( m_fUpdateDistanceTime < gpGlobals->curtime ) + { + if ( !DoDelayedPlayerSwaps() ) + { + return; + } + + C_BaseEntity *pIconTarget = m_hIconTarget.Get(); + + if ( !pIconTarget ) + { + if ( !m_bNoIconTarget ) + { + CloseOpportunity( "Lost our icon target handle returned NULL." ); + } + + m_fCurrentDistance = 0.0f; + return; + } + else + { + if ( ( pIconTarget->IsEffectActive( EF_NODRAW ) || pIconTarget->IsDormant() ) && !m_bAllowNodrawTarget ) + { + // We don't allow no draw entities + CloseOpportunity( "Icon Target is using effect NODRAW and allow_nodraw_target is false!" ); + return; + } + } + + // Update it's distance from the local player + C_BasePlayer *pLocalPlayer = GetGameInstructor().GetLocalPlayer(); + + if ( !pLocalPlayer || pLocalPlayer == pIconTarget ) + { + m_fCurrentDistance = 0.0f; + } + else + { + m_fCurrentDistance = pLocalPlayer->ActivePlayerCombatCharacter()->EyePosition().DistTo( pIconTarget->WorldSpaceCenter() ); + } + + m_fUpdateDistanceTime = gpGlobals->curtime + LESSON_DISTANCE_UPDATE_RATE; + } +} + +bool CIconLesson::ShouldDisplay( void ) const +{ + VPROF_BUDGET( "CIconLesson::ShouldDisplay", "GameInstructor" ); + + if ( !DoDelayedPlayerSwaps() ) + { + return false; + } + + if ( m_fRange > 0.0f && m_fCurrentDistance > m_fRange ) + { + // Distance to target is more than the max range + return false; + } + + if ( !m_bShowWhenOccluded && m_hLocatorTarget >= 0 ) + { + CLocatorTarget *pLocatorTarget = Locator_GetTargetFromHandle( m_hLocatorTarget ); + + if ( pLocatorTarget && pLocatorTarget->IsOccluded() ) + { + // Target is occluded and doesn't want to be shown when occluded + return false; + } + } + + // Ok to display + return true; +} + +bool CIconLesson::IsVisible( void ) const +{ + VPROF_BUDGET( "CIconLesson::IsVisible", "GameInstructor" ); + + if( m_hLocatorTarget == -1 ) + { + // If it doesn't want a target, it's "visible" otherwise we'll have to call it invisible + return m_bNoIconTarget; + } + + CLocatorTarget *pLocatorTarget = Locator_GetTargetFromHandle( m_hLocatorTarget ); + if ( !pLocatorTarget ) + { + return false; + } + + return pLocatorTarget->IsVisible(); +} + +void CIconLesson::SwapOutPlayers( int iOldUserID, int iNewUserID ) +{ + BaseClass::SwapOutPlayers( iOldUserID, iNewUserID ); + + if ( m_bNoIconTarget ) + return; + + // Get the player pointers from the user IDs + C_BasePlayer *pOldPlayer = UTIL_PlayerByUserId( iOldUserID ); + C_BasePlayer *pNewPlayer = UTIL_PlayerByUserId( iNewUserID ); + + if ( pOldPlayer == m_hIconTarget.Get() ) + { + if ( pNewPlayer ) + { + m_hIconTarget = pNewPlayer; + } + else + { + if ( m_iNumDelayedPlayerSwaps < MAX_DELAYED_PLAYER_SWAPS ) + { + m_pDelayedPlayerSwap[ m_iNumDelayedPlayerSwaps ].phHandleToChange = &m_hIconTarget; + m_pDelayedPlayerSwap[ m_iNumDelayedPlayerSwaps ].iNewUserID = iNewUserID; + ++m_iNumDelayedPlayerSwaps; + } + } + } +} + +void CIconLesson::TakePlaceOf( CBaseLesson *pLesson ) +{ + BaseClass::TakePlaceOf( pLesson ); + + const CIconLesson *pIconLesson = dynamic_cast( pLesson ); + + if ( pIconLesson ) + { + if ( pIconLesson->m_hLocatorTarget != -1 ) + { + CLocatorTarget *pLocatorTarget = Locator_GetTargetFromHandle( pIconLesson->m_hLocatorTarget ); + + if ( pLocatorTarget ) + { + // This one draw right to the hud... use it's icon target handle + m_hLocatorTarget = pIconLesson->m_hLocatorTarget; + } + } + + m_fOnScreenStartTime = pIconLesson->m_fOnScreenStartTime; + } +} + +void CIconLesson::SetLocatorBinding( CLocatorTarget * pLocatorTarget ) +{ + if ( IsX360() || input->ControllerModeActive() ) + { + // Try to use gamepad bindings first + if ( m_szGamepadBinding.String()[ 0 ] != '\0' ) + { + // Found gamepad binds! + pLocatorTarget->SetBinding( m_szGamepadBinding.String() ); + } + else + { + // No gamepad binding, so fallback to the regular binding + pLocatorTarget->SetBinding( m_szBinding.String() ); + } + } + else + { + // Always use the regular binding when the gamepad is disabled + pLocatorTarget->SetBinding( m_szBinding.String() ); + } +} + +bool CIconLesson::IsPresentComplete( void ) +{ + if ( m_hLocatorTarget == -1 ) + return false; + + CLocatorTarget *pLocatorTarget = Locator_GetTargetFromHandle( m_hLocatorTarget ); + + if ( !pLocatorTarget ) + return false; + + return !pLocatorTarget->IsPresenting(); +} + +void CIconLesson::PresentStart( void ) +{ + if ( m_hLocatorTarget == -1 ) + return; + + CLocatorTarget *pLocatorTarget = Locator_GetTargetFromHandle( m_hLocatorTarget ); + + if ( !pLocatorTarget ) + return; + + pLocatorTarget->StartPresent(); +} + +void CIconLesson::PresentEnd( void ) +{ + if ( m_hLocatorTarget == -1 ) + return; + + CLocatorTarget *pLocatorTarget = Locator_GetTargetFromHandle( m_hLocatorTarget ); + + if ( !pLocatorTarget ) + return; + + pLocatorTarget->EndPresent(); +} + +void CIconLesson::UpdateLocatorTarget( CLocatorTarget *pLocatorTarget, C_BaseEntity *pIconTarget ) +{ + if ( m_bFixedPosition ) + { + pLocatorTarget->m_bOriginInScreenspace = true; + pLocatorTarget->m_vecOrigin.x = m_fFixedPositionX; + pLocatorTarget->m_vecOrigin.y = m_fFixedPositionY; + pLocatorTarget->SetVguiTargetName( m_szVguiTargetName.String() ); + pLocatorTarget->SetVguiTargetLookup( m_szVguiTargetLookup.String() ); + pLocatorTarget->SetVguiTargetEdge( m_nVguiTargetEdge ); + } + else + { + pLocatorTarget->m_bOriginInScreenspace = false; + pLocatorTarget->m_vecOrigin = pIconTarget->EyePosition() + MainViewUp( 0 ) * m_flRelativeUpOffset + Vector( 0.0f, 0.0f, m_flUpOffset ); + pLocatorTarget->SetVguiTargetName( "" ); + } + + const char *pchDisplayParamText = m_szDisplayParamText.String(); +#ifdef INFESTED_DLL + char szCustomName[ 256 ]; +#endif + + // Check if the parameter is the be the player display name + if ( Q_stricmp( pchDisplayParamText, "use_name" ) == 0 ) + { + // Fix up the player display name + C_BasePlayer *pPlayer = ToBasePlayer( pIconTarget ); + if ( pPlayer ) + { + pchDisplayParamText = pPlayer->GetPlayerName(); + } + else + { + bool bNoName = true; + +#ifdef INFESTED_DLL + C_ASW_Marine *pMarine = dynamic_cast< C_ASW_Marine* >( pIconTarget ); + if ( pMarine ) + { + C_ASW_Marine_Resource *pMR = pMarine->GetMarineResource(); + if ( pMR ) + { + pMR->GetDisplayName( szCustomName, sizeof( szCustomName ) ); + pchDisplayParamText = szCustomName; + bNoName = false; + } + } +#endif + + if ( bNoName ) + { + // It's not a player! + pchDisplayParamText = ""; + } + } + } + + pLocatorTarget->SetCaptionText( m_szDisplayText.String(), pchDisplayParamText ); + SetLocatorBinding( pLocatorTarget ); + pLocatorTarget->SetOnscreenIconTextureName( m_szOnscreenIcon.String() ); + pLocatorTarget->SetOffscreenIconTextureName( m_szOffscreenIcon.String() ); + pLocatorTarget->SetVisible( m_bVisible ); + + C_BasePlayer *pLocalPlayer = GetGameInstructor().GetLocalPlayer(); + + if( !m_bFixedPosition && + ( ( pLocalPlayer != NULL && pLocalPlayer == m_hIconTarget ) || + GetClientWorldEntity() == m_hIconTarget ) ) + { + // Mark this icon as a static icon that draws in a fixed + // location on the hud rather than tracking an object + // in 3D space. + pLocatorTarget->AddIconEffects( LOCATOR_ICON_FX_STATIC ); + } + else + { + pLocatorTarget->AddIconEffects( LOCATOR_ICON_FX_NONE ); + } + + if ( m_bNoOffscreen ) + { + pLocatorTarget->AddIconEffects( LOCATOR_ICON_FX_NO_OFFSCREEN ); + } + else + { + pLocatorTarget->RemoveIconEffects( LOCATOR_ICON_FX_NO_OFFSCREEN ); + } + + if( m_bForceCaption || IsLocked() ) + { + pLocatorTarget->AddIconEffects( LOCATOR_ICON_FX_FORCE_CAPTION ); + } + else + { + pLocatorTarget->RemoveIconEffects( LOCATOR_ICON_FX_FORCE_CAPTION ); + } + + pLocatorTarget->Update(); + + if ( pLocatorTarget->m_bIsDrawing ) + { + if ( !m_bHasPlayedSound ) + { + GetGameInstructor().PlaySound( m_szStartSound.String() ); + m_bHasPlayedSound = true; + } + } +} + +// +// CScriptedIconLesson +// + +// Linking variables to scriptable entries is done here! +// The first parameter correlates to the case insensitive string name read from scripts. +// This macro generates code that passes this consistent variable data in to other macros +#define LESSON_VARIABLE_FACTORY \ + LESSON_VARIABLE_MACRO_EHANDLE( VOID, m_hLocalPlayer, EHANDLE ) \ + \ + LESSON_VARIABLE_MACRO_EHANDLE( LOCAL_PLAYER, m_hLocalPlayer, EHANDLE ) \ + LESSON_VARIABLE_MACRO( OUTPUT, m_fOutput, float ) \ + \ + LESSON_VARIABLE_MACRO_EHANDLE( ENTITY1, m_hEntity1, EHANDLE ) \ + LESSON_VARIABLE_MACRO_EHANDLE( ENTITY2, m_hEntity2, EHANDLE ) \ + LESSON_VARIABLE_MACRO_STRING( STRING1, m_szString1, CGameInstructorSymbol ) \ + LESSON_VARIABLE_MACRO_STRING( STRING2, m_szString2, CGameInstructorSymbol ) \ + LESSON_VARIABLE_MACRO( INTEGER1, m_iInteger1, int ) \ + LESSON_VARIABLE_MACRO( INTEGER2, m_iInteger2, int ) \ + LESSON_VARIABLE_MACRO( FLOAT1, m_fFloat1, float ) \ + LESSON_VARIABLE_MACRO( FLOAT2, m_fFloat2, float ) \ + \ + LESSON_VARIABLE_MACRO_EHANDLE( ICON_TARGET, m_hIconTarget, EHANDLE ) \ + LESSON_VARIABLE_MACRO_STRING( VGUI_TARGET_NAME, m_szVguiTargetName, CGameInstructorSymbol ) \ + LESSON_VARIABLE_MACRO_STRING( VGUI_TARGET_LOOKUP, m_szVguiTargetLookup, CGameInstructorSymbol ) \ + LESSON_VARIABLE_MACRO( VGUI_TARGET_EDGE, m_nVguiTargetEdge, int ) \ + LESSON_VARIABLE_MACRO( FIXED_POSITION_X, m_fFixedPositionX, float ) \ + LESSON_VARIABLE_MACRO( FIXED_POSITION_Y, m_fFixedPositionY, float ) \ + LESSON_VARIABLE_MACRO_BOOL( FIXED_POSITION, m_bFixedPosition, bool ) \ + LESSON_VARIABLE_MACRO_BOOL( NO_ICON_TARGET, m_bNoIconTarget, bool ) \ + LESSON_VARIABLE_MACRO_BOOL( ALLOW_NODRAW_TARGET, m_bAllowNodrawTarget, bool ) \ + LESSON_VARIABLE_MACRO_BOOL( VISIBLE, m_bVisible, bool ) \ + LESSON_VARIABLE_MACRO_BOOL( SHOW_WHEN_OCCLUDED, m_bShowWhenOccluded, bool ) \ + LESSON_VARIABLE_MACRO_BOOL( NO_OFFSCREEN, m_bNoOffscreen, bool ) \ + LESSON_VARIABLE_MACRO_BOOL( FORCE_CAPTION, m_bForceCaption, bool ) \ + LESSON_VARIABLE_MACRO_STRING( ONSCREEN_ICON, m_szOnscreenIcon, CGameInstructorSymbol ) \ + LESSON_VARIABLE_MACRO_STRING( OFFSCREEN_ICON, m_szOffscreenIcon, CGameInstructorSymbol ) \ + LESSON_VARIABLE_MACRO( ICON_OFFSET, m_flUpOffset, float ) \ + LESSON_VARIABLE_MACRO( ICON_RELATIVE_OFFSET, m_flRelativeUpOffset, float ) \ + LESSON_VARIABLE_MACRO( RANGE, m_fRange, float ) \ + \ + LESSON_VARIABLE_MACRO( FLAGS, m_iFlags, int ) \ + LESSON_VARIABLE_MACRO_STRING( CAPTION_COLOR, m_szCaptionColor, CGameInstructorSymbol ) \ + LESSON_VARIABLE_MACRO_STRING( GROUP, m_szLessonGroup, CGameInstructorSymbol ) \ + \ + LESSON_VARIABLE_MACRO_STRING( CAPTION, m_szDisplayText, CGameInstructorSymbol ) \ + LESSON_VARIABLE_MACRO_STRING( CAPTION_PARAM, m_szDisplayParamText, CGameInstructorSymbol ) \ + LESSON_VARIABLE_MACRO_STRING( BINDING, m_szBinding, CGameInstructorSymbol ) \ + LESSON_VARIABLE_MACRO_STRING( GAMEPAD_BINDING, m_szGamepadBinding, CGameInstructorSymbol ) \ + \ + LESSON_VARIABLE_MACRO( PRIORITY, m_iPriority, int ) \ + LESSON_VARIABLE_MACRO_STRING( REPLACE_KEY, m_stringReplaceKey, CGameInstructorSymbol ) \ + \ + LESSON_VARIABLE_MACRO( LOCK_DURATION, m_fLockDuration, float ) \ + LESSON_VARIABLE_MACRO_BOOL( CAN_OPEN_WHEN_DEAD, m_bCanOpenWhenDead, bool ) \ + LESSON_VARIABLE_MACRO_BOOL( BUMP_WITH_TIMEOUT_WHEN_LEARNED, m_bBumpWithTimeoutWhenLearned, bool ) \ + LESSON_VARIABLE_MACRO_BOOL( CAN_TIMEOUT_WHILE_INACTIVE, m_bCanTimeoutWhileInactive, bool ) \ + LESSON_VARIABLE_MACRO( TIMEOUT, m_fTimeout, float ) \ + LESSON_VARIABLE_MACRO( UPDATE_INTERVAL, m_fUpdateInterval, float ) \ + LESSON_VARIABLE_MACRO_STRING( START_SOUND, m_szStartSound, CGameInstructorSymbol ) \ + + +// Create keyvalues name symbol +#define LESSON_VARIABLE_SYMBOL( _varEnum, _varName, _varType ) static int g_n##_varEnum##Symbol; + +#define LESSON_VARIABLE_INIT_SYMBOL( _varEnum, _varName, _varType ) g_n##_varEnum##Symbol = KeyValuesSystem()->GetSymbolForString( #_varEnum ); + +#define LESSON_SCRIPT_STRING_ADD_TO_MAP( _varEnum, _varName, _varType ) g_NameToTypeMap.Insert( #_varEnum, LESSON_VARIABLE_##_varEnum## ); + +// Create enum value +#define LESSON_VARIABLE_ENUM( _varEnum, _varName, _varType ) LESSON_VARIABLE_##_varEnum##, + +// Init info call +#define LESSON_VARIABLE_INIT_INFO_CALL( _varEnum, _varName, _varType ) g_pLessonVariableInfo[ LESSON_VARIABLE_##_varEnum## ].Init_##_varEnum##(); + +// Init info +#define LESSON_VARIABLE_INIT_INFO( _varEnum, _varName, _varType ) \ + void Init_##_varEnum##( void ) \ + { \ + iOffset = offsetof( CScriptedIconLesson, CScriptedIconLesson::##_varName## ); \ + varType = LessonParamTypeFromString( #_varType ); \ + } + +#define LESSON_VARIABLE_INIT_INFO_BOOL( _varEnum, _varName, _varType ) \ + void Init_##_varEnum##( void ) \ + { \ + iOffset = offsetof( CScriptedIconLesson, CScriptedIconLesson::##_varName## ); \ + varType = FIELD_BOOLEAN; \ + } + +#define LESSON_VARIABLE_INIT_INFO_EHANDLE( _varEnum, _varName, _varType ) \ + void Init_##_varEnum##( void ) \ + { \ + iOffset = offsetof( CScriptedIconLesson, CScriptedIconLesson::##_varName## ); \ + varType = FIELD_EHANDLE; \ + } + +#define LESSON_VARIABLE_INIT_INFO_STRING( _varEnum, _varName, _varType ) \ + void Init_##_varEnum##( void ) \ + { \ + iOffset = offsetof( CScriptedIconLesson, CScriptedIconLesson::##_varName## ); \ + varType = FIELD_STRING; \ + } + +// Copy defaults into this scripted lesson into a new one +#define LESSON_VARIABLE_DEFAULT( _varEnum, _varName, _varType ) ( _varName = m_pDefaultHolder->_varName ); + +// Copy a variable from this scripted lesson into a new one +#define LESSON_VARIABLE_COPY( _varEnum, _varName, _varType ) ( pOpenLesson->_varName = _varName ); + +// Return the first param if pchName is the same as the second param +#define LESSON_SCRIPT_STRING( _type, _string ) \ + if ( Q_stricmp( pchName, _string ) == 0 )\ + {\ + return _type;\ + } + +// Wrapper for using this macro in the factory +#define LESSON_SCRIPT_STRING_GENERAL( _varEnum, _varName, _varType ) LESSON_SCRIPT_STRING( LESSON_VARIABLE_##_varEnum##, #_varEnum ) + +// Process the element action on this variable +#define PROCESS_LESSON_ACTION( _varEnum, _varName, _varType ) \ + case LESSON_VARIABLE_##_varEnum##:\ + return ProcessElementAction( pLessonElement->iAction, pLessonElement->bNot, #_varName, _varName, &pLessonElement->szParam, eventParam_float ); + +#define PROCESS_LESSON_ACTION_EHANDLE( _varEnum, _varName, _varType ) \ + case LESSON_VARIABLE_##_varEnum##:\ + return ProcessElementAction( pLessonElement->iAction, pLessonElement->bNot, #_varName, _varName, &pLessonElement->szParam, eventParam_float, eventParam_BaseEntity, eventParam_string ); + +#define PROCESS_LESSON_ACTION_STRING( _varEnum, _varName, _varType ) \ + case LESSON_VARIABLE_##_varEnum##:\ + return ProcessElementAction( pLessonElement->iAction, pLessonElement->bNot, #_varName, &_varName, &pLessonElement->szParam, eventParam_string ); + +// Init the variable from the script (or a convar) +#define LESSON_VARIABLE_INIT( _varEnum, _varName, _varType ) \ + else if ( g_n##_varEnum##Symbol == pSubKey->GetNameSymbol() ) \ + { \ + const char *pchParam = pSubKey->GetString(); \ + if ( pchParam && StringHasPrefix( pchParam, "convar " ) ) \ + { \ + ConVarRef tempCVar( pchParam + Q_strlen( "convar " ) ); \ + if ( tempCVar.IsValid() ) \ + { \ + _varName = static_cast<_varType>( tempCVar.GetFloat() ); \ + } \ + else \ + { \ + _varName = static_cast<_varType>( 0.0f ); \ + } \ + } \ + else \ + { \ + _varName = static_cast<_varType>( pSubKey->GetFloat() ); \ + } \ + } + +#define LESSON_VARIABLE_INIT_BOOL( _varEnum, _varName, _varType ) \ + else if ( Q_stricmp( #_varEnum, pSubKey->GetName() ) == 0 ) \ + { \ + _varName = pSubKey->GetBool(); \ + } + +#define LESSON_VARIABLE_INIT_EHANDLE( _varEnum, _varName, _varType ) \ + else if ( g_n##_varEnum##Symbol == pSubKey->GetNameSymbol() ) \ + { \ + DevWarning( "Can't initialize an EHANDLE from the instructor lesson script." ); \ + } + +#define LESSON_VARIABLE_INIT_STRING( _varEnum, _varName, _varType ) \ + else if ( g_n##_varEnum##Symbol == pSubKey->GetNameSymbol() ) \ + { \ + const char *pchParam = pSubKey->GetString(); \ + if ( pchParam && StringHasPrefix( pchParam, "convar " ) ) \ + { \ + ConVarRef tempCVar( pchParam + Q_strlen( "convar " ) ); \ + if ( tempCVar.IsValid() ) \ + { \ + _varName = tempCVar.GetString(); \ + } \ + else \ + { \ + _varName = ""; \ + } \ + } \ + else \ + { \ + _varName = pSubKey->GetString(); \ + } \ + } + +// Gets a scripted variable by offset and casts it to the proper type +#define LESSON_VARIABLE_GET_FROM_OFFSET( _type, _offset ) *static_cast<_type*>( static_cast( static_cast( static_cast( this ) ) + _offset ) ) + + +// Enum of scripted variables +enum LessonVariable +{ + // Run enum macros on all scriptable variables (see: LESSON_VARIABLE_FACTORY definition) +#define LESSON_VARIABLE_MACRO LESSON_VARIABLE_ENUM +#define LESSON_VARIABLE_MACRO_BOOL LESSON_VARIABLE_ENUM +#define LESSON_VARIABLE_MACRO_EHANDLE LESSON_VARIABLE_ENUM +#define LESSON_VARIABLE_MACRO_STRING LESSON_VARIABLE_ENUM + LESSON_VARIABLE_FACTORY +#undef LESSON_VARIABLE_MACRO +#undef LESSON_VARIABLE_MACRO_BOOL +#undef LESSON_VARIABLE_MACRO_EHANDLE +#undef LESSON_VARIABLE_MACRO_STRING + + LESSON_VARIABLE_TOTAL +}; + +// Declare the keyvalues symbols for the keynames +#define LESSON_VARIABLE_MACRO LESSON_VARIABLE_SYMBOL +#define LESSON_VARIABLE_MACRO_BOOL LESSON_VARIABLE_SYMBOL +#define LESSON_VARIABLE_MACRO_EHANDLE LESSON_VARIABLE_SYMBOL +#define LESSON_VARIABLE_MACRO_STRING LESSON_VARIABLE_SYMBOL + LESSON_VARIABLE_FACTORY +#undef LESSON_VARIABLE_MACRO +#undef LESSON_VARIABLE_MACRO_BOOL +#undef LESSON_VARIABLE_MACRO_EHANDLE +#undef LESSON_VARIABLE_MACRO_STRING + +// String lookup prototypes +LessonVariable LessonVariableFromString( const char *pchName, bool bWarnOnInvalidNames = true ); +_fieldtypes LessonParamTypeFromString( const char *pchName ); +int LessonActionFromString( const char *pchName ); + + +// This is used to get type info an variable offsets from the variable enumerated value +class LessonVariableInfo +{ +public: + + LessonVariableInfo( void ) + : iOffset( 0 ), varType( FIELD_VOID ) + { + } + + // Run init info macros on all scriptable variables (see: LESSON_VARIABLE_FACTORY definition) +#define LESSON_VARIABLE_MACRO LESSON_VARIABLE_INIT_INFO +#define LESSON_VARIABLE_MACRO_BOOL LESSON_VARIABLE_INIT_INFO_BOOL +#define LESSON_VARIABLE_MACRO_EHANDLE LESSON_VARIABLE_INIT_INFO_EHANDLE +#define LESSON_VARIABLE_MACRO_STRING LESSON_VARIABLE_INIT_INFO_STRING + LESSON_VARIABLE_FACTORY +#undef LESSON_VARIABLE_MACRO +#undef LESSON_VARIABLE_MACRO_BOOL +#undef LESSON_VARIABLE_MACRO_EHANDLE +#undef LESSON_VARIABLE_MACRO_STRING + +public: + + int iOffset; + _fieldtypes varType; +}; + +LessonVariableInfo g_pLessonVariableInfo[ LESSON_VARIABLE_TOTAL ]; + + +const LessonVariableInfo *GetLessonVariableInfo( int iLessonVariable ) +{ + Assert( iLessonVariable >= 0 && iLessonVariable < LESSON_VARIABLE_TOTAL ); + + if ( g_pLessonVariableInfo[ 0 ].varType == FIELD_VOID ) + { + // Run init info call macros on all scriptable variables (see: LESSON_VARIABLE_FACTORY definition) +#define LESSON_VARIABLE_MACRO LESSON_VARIABLE_INIT_INFO_CALL +#define LESSON_VARIABLE_MACRO_BOOL LESSON_VARIABLE_INIT_INFO_CALL +#define LESSON_VARIABLE_MACRO_EHANDLE LESSON_VARIABLE_INIT_INFO_CALL +#define LESSON_VARIABLE_MACRO_STRING LESSON_VARIABLE_INIT_INFO_CALL + LESSON_VARIABLE_FACTORY +#undef LESSON_VARIABLE_MACRO +#undef LESSON_VARIABLE_MACRO_BOOL +#undef LESSON_VARIABLE_MACRO_EHANDLE +#undef LESSON_VARIABLE_MACRO_STRING + } + + return &(g_pLessonVariableInfo[ iLessonVariable ]); +} + +static CUtlDict< LessonVariable, int > g_NameToTypeMap; +static CUtlDict< fieldtype_t, int > g_TypeToParamTypeMap; +CUtlDict< int, int > CScriptedIconLesson::LessonActionMap; + +CScriptedIconLesson::~CScriptedIconLesson( void ) +{ + if ( m_pDefaultHolder ) + { + delete m_pDefaultHolder; + m_pDefaultHolder = NULL; + } +} + + +void CScriptedIconLesson::Init( void ) +{ + m_hLocalPlayer.Set( NULL ); + m_fOutput = 0.0f; + m_hEntity1.Set( NULL ); + m_hEntity2.Set( NULL ); + m_szString1 = ""; + m_szString2 = ""; + m_iInteger1 = 0; + m_iInteger2 = 0; + m_fFloat1 = 0.0f; + m_fFloat2 = 0.0f; + + m_fUpdateEventTime = 0.0f; + m_pDefaultHolder = NULL; + + m_iScopeDepth = 0; + + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerboseHeader, "GAME INSTRUCTOR: " ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "Initializing scripted lesson " ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "\"%s\"", GetName() ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "...\n" ); + } + + if ( !IsDefaultHolder() ) + { + if ( !IsOpenOpportunity() ) + { + // Initialize from the key value file + InitFromKeys( GetGameInstructor().GetScriptKeys() ); + + if ( m_iPriority >= LESSON_PRIORITY_MAX ) + { + DevWarning( "Priority level not set for lesson: %s\n", GetName() ); + } + + // We use this to remember variable defaults to be reset before each open attempt + m_pDefaultHolder = new CScriptedIconLesson( GetName(), true, false, m_nSplitScreenSlot ); + CScriptedIconLesson *pOpenLesson = m_pDefaultHolder; + + // Run copy macros on all default scriptable variables (see: LESSON_VARIABLE_FACTORY definition) +#define LESSON_VARIABLE_MACRO LESSON_VARIABLE_COPY +#define LESSON_VARIABLE_MACRO_BOOL LESSON_VARIABLE_COPY +#define LESSON_VARIABLE_MACRO_EHANDLE LESSON_VARIABLE_COPY +#define LESSON_VARIABLE_MACRO_STRING LESSON_VARIABLE_COPY + LESSON_VARIABLE_FACTORY +#undef LESSON_VARIABLE_MACRO +#undef LESSON_VARIABLE_MACRO_BOOL +#undef LESSON_VARIABLE_MACRO_EHANDLE +#undef LESSON_VARIABLE_MACRO_STRING + + // Listen for open events + for ( int iLessonEvent = 0; iLessonEvent < m_OpenEvents.Count(); ++iLessonEvent ) + { + const LessonEvent_t *pLessonEvent = &(m_OpenEvents[ iLessonEvent ]); + ListenForGameEvent( pLessonEvent->szEventName.String() ); + + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\tListen for open event " ); + ConColorMsg( CBaseLesson::m_rgbaVerboseOpen, "\"%s\"", pLessonEvent->szEventName.String()); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ".\n" ); + } + } + + // Listen for close events + for ( int iLessonEvent = 0; iLessonEvent < m_CloseEvents.Count(); ++iLessonEvent ) + { + const LessonEvent_t *pLessonEvent = &(m_CloseEvents[ iLessonEvent ]); + ListenForGameEvent( pLessonEvent->szEventName.String() ); + + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\tListen for close event " ); + ConColorMsg( CBaseLesson::m_rgbaVerboseClose, "\"%s\"", pLessonEvent->szEventName.String()); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ".\n" ); + } + } + + // Listen for success events + for ( int iLessonEvent = 0; iLessonEvent < m_SuccessEvents.Count(); ++iLessonEvent ) + { + const LessonEvent_t *pLessonEvent = &(m_SuccessEvents[ iLessonEvent ]); + ListenForGameEvent( pLessonEvent->szEventName.String()); + + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\tListen for success event " ); + ConColorMsg( CBaseLesson::m_rgbaVerboseSuccess, "\"%s\"", pLessonEvent->szEventName.String()); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ".\n" ); + } + } + } + else + { + // This is an open lesson! Get the root for reference + const CScriptedIconLesson *pLesson = static_cast( GetGameInstructor().GetLesson( GetName() ) ); + SetRoot( const_cast( pLesson ) ); + } + } +} + +void CScriptedIconLesson::InitPrerequisites( void ) +{ + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerboseHeader, "GAME INSTRUCTOR: " ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "Initializing prereqs for scripted lesson " ); + ConColorMsg( CBaseLesson::m_rgbaVerboseOpen, "\"%s\"", GetName() ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "...\n" ); + } + + for ( int iPrerequisit = 0; iPrerequisit < m_PrerequisiteNames.Count(); ++iPrerequisit ) + { + const char *pPrerequisiteName = m_PrerequisiteNames[ iPrerequisit ].String(); + AddPrerequisite( pPrerequisiteName ); + } +} + +void CScriptedIconLesson::OnOpen( void ) +{ + VPROF_BUDGET( "CScriptedIconLesson::OnOpen", "GameInstructor" ); + + if ( !DoDelayedPlayerSwaps() ) + { + return; + } + + const CScriptedIconLesson *pLesson = static_cast( GetRoot() ); + + // Process all update events + for ( int iLessonEvent = 0; iLessonEvent < pLesson->m_OnOpenEvents.Count(); ++iLessonEvent ) + { + const LessonEvent_t *pLessonEvent = &(pLesson->m_OnOpenEvents[ iLessonEvent ]); + + if ( gameinstructor_verbose.GetInt() > 1 && ShouldShowSpew() ) + { + ConColorMsg( Color( 255, 128, 64, 255 ), "GAME INSTRUCTOR: " ); + ConColorMsg( Color( 64, 128, 255, 255 ), "OnOpen event " ); + ConColorMsg( Color( 0, 255, 0, 255 ), "\"%s\"", pLessonEvent->szEventName.String()); + ConColorMsg( Color( 64, 128, 255, 255 ), "received for lesson \"%s\"...\n", GetName() ); + } + + ProcessElements( NULL, &(pLessonEvent->elements) ); + } + + BaseClass::OnOpen(); +} + +void CScriptedIconLesson::Update( void ) +{ + VPROF_BUDGET( "CScriptedIconLesson::Update", "GameInstructor" ); + + if ( !DoDelayedPlayerSwaps() ) + { + return; + } + + const CScriptedIconLesson *pLesson = static_cast( GetRoot() ); + + if ( gpGlobals->curtime >= m_fUpdateEventTime ) + { + bool bShowSpew = ( gameinstructor_verbose.GetInt() > 1 && ShouldShowSpew() ); + + int iVerbose = gameinstructor_verbose.GetInt(); + if ( gameinstructor_verbose.GetInt() == 1 ) + { + // Force the verbose level from 1 to 0 for update events + gameinstructor_verbose.SetValue( 0 ); + } + + // Process all update events + for ( int iLessonEvent = 0; iLessonEvent < pLesson->m_UpdateEvents.Count(); ++iLessonEvent ) + { + const LessonEvent_t *pLessonEvent = &(pLesson->m_UpdateEvents[ iLessonEvent ]); + + if ( bShowSpew ) + { + ConColorMsg( CBaseLesson::m_rgbaVerboseHeader, "GAME INSTRUCTOR: " ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "Update event " ); + ConColorMsg( CBaseLesson::m_rgbaVerboseUpdate, "\"%s\"", pLessonEvent->szEventName.String()); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "received for lesson \"%s\"...\n", GetName() ); + } + + ProcessElements( NULL, &(pLessonEvent->elements) ); + } + + gameinstructor_verbose.SetValue( iVerbose ); + + // Wait before doing update events again + m_fUpdateEventTime = gpGlobals->curtime + m_fUpdateInterval; + } + + BaseClass::Update(); +} + +void CScriptedIconLesson::SwapOutPlayers( int iOldUserID, int iNewUserID ) +{ + BaseClass::SwapOutPlayers( iOldUserID, iNewUserID ); + + // Get the player pointers from the user IDs + C_BasePlayer *pOldPlayer = UTIL_PlayerByUserId( iOldUserID ); + C_BasePlayer *pNewPlayer = UTIL_PlayerByUserId( iNewUserID ); + + if ( pOldPlayer == m_hEntity1.Get() ) + { + if ( pNewPlayer ) + { + m_hEntity1 = pNewPlayer; + } + else + { + if ( m_iNumDelayedPlayerSwaps < MAX_DELAYED_PLAYER_SWAPS ) + { + m_pDelayedPlayerSwap[ m_iNumDelayedPlayerSwaps ].phHandleToChange = &m_hEntity1; + m_pDelayedPlayerSwap[ m_iNumDelayedPlayerSwaps ].iNewUserID = iNewUserID; + ++m_iNumDelayedPlayerSwaps; + } + } + } + + if ( pOldPlayer == m_hEntity2.Get() ) + { + if ( pNewPlayer ) + { + m_hEntity2 = pNewPlayer; + } + else + { + + if ( m_iNumDelayedPlayerSwaps < MAX_DELAYED_PLAYER_SWAPS ) + { + m_pDelayedPlayerSwap[ m_iNumDelayedPlayerSwaps ].phHandleToChange = &m_hEntity2; + m_pDelayedPlayerSwap[ m_iNumDelayedPlayerSwaps ].iNewUserID = iNewUserID; + ++m_iNumDelayedPlayerSwaps; + } + } + } +} + +void CScriptedIconLesson::FireGameEvent( IGameEvent *event ) +{ + VPROF_BUDGET( "CScriptedIconLesson::FireGameEvent", "GameInstructor" ); + + ACTIVE_SPLITSCREEN_PLAYER_GUARD( GetSplitScreenSlot() ); + + if ( m_bDisabled ) + return; + + if ( !DoDelayedPlayerSwaps() ) + { + return; + } + + if ( !C_BasePlayer::GetLocalPlayer() ) + return; + + // Check that this lesson is allowed for the current input device + if( m_bOnlyKeyboard && input->ControllerModeActive() ) + return; + + if( m_bOnlyGamepad && !input->ControllerModeActive() ) + return; + + // Check that this lesson is for the proper team + CBasePlayer *pLocalPlayer = GetGameInstructor().GetLocalPlayer(); + + if ( m_iTeam != TEAM_ANY && pLocalPlayer && pLocalPlayer->GetTeamNumber() != m_iTeam ) + { + // This lesson is intended for a different team + return; + } + + const char *name = event->GetName(); + + // Open events run on the root + ProcessOpenGameEvents( this, name, event ); + + // Close and success events run on the children + const CUtlVector < CBaseLesson * > *pChildren = GetChildren(); + for ( int iChild = 0; iChild < pChildren->Count(); ++iChild ) + { + CScriptedIconLesson *pScriptedChild = dynamic_cast( (*pChildren)[ iChild ] ); + + pScriptedChild->ProcessCloseGameEvents( this, name, event ); + pScriptedChild->ProcessSuccessGameEvents( this, name, event ); + } +} + +void CScriptedIconLesson::ProcessOpenGameEvents( const CScriptedIconLesson *pRootLesson, const char *name, IGameEvent *event ) +{ + if ( pRootLesson->InstanceType() == LESSON_INSTANCE_SINGLE_OPEN && GetGameInstructor().IsLessonOfSameTypeOpen( this ) ) + { + // We don't want more than one of this type, and there is already one open + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerboseHeader, "GAME INSTRUCTOR: " ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "Opportunity " ); + ConColorMsg( CBaseLesson::m_rgbaVerboseClose, "\"%s\" ", pRootLesson->GetName() ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "open events NOT processed (there is already an open lesson of this type).\n" ); + } + + return; + } + + for ( int iLessonEvent = 0; iLessonEvent < pRootLesson->m_OpenEvents.Count(); ++iLessonEvent ) + { + const LessonEvent_t *pLessonEvent = &(pRootLesson->m_OpenEvents[ iLessonEvent ]); + + if ( Q_strcmp( name, pLessonEvent->szEventName.String()) == 0 ) + { + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerboseHeader, "GAME INSTRUCTOR: " ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "Open event " ); + ConColorMsg( CBaseLesson::m_rgbaVerboseOpen, "\"%s\"", pLessonEvent->szEventName.String()); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "received for lesson \"%s\"...\n", GetName() ); + } + + if ( m_pDefaultHolder ) + { + // Run copy from default macros on all scriptable variables (see: LESSON_VARIABLE_FACTORY definition) +#define LESSON_VARIABLE_MACRO LESSON_VARIABLE_DEFAULT +#define LESSON_VARIABLE_MACRO_BOOL LESSON_VARIABLE_DEFAULT +#define LESSON_VARIABLE_MACRO_EHANDLE LESSON_VARIABLE_DEFAULT +#define LESSON_VARIABLE_MACRO_STRING LESSON_VARIABLE_DEFAULT + LESSON_VARIABLE_FACTORY +#undef LESSON_VARIABLE_MACRO +#undef LESSON_VARIABLE_MACRO_BOOL +#undef LESSON_VARIABLE_MACRO_EHANDLE +#undef LESSON_VARIABLE_MACRO_STRING + } + + if ( ProcessElements( event, &(pLessonEvent->elements) ) ) + { + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerboseOpen, "\tAll elements returned true. Opening!\n" ); + } + + MEM_ALLOC_CREDIT(); + CScriptedIconLesson *pOpenLesson = new CScriptedIconLesson( GetName(), false, true, GetSplitScreenSlot() ); + + // Run copy macros on all scriptable variables (see: LESSON_VARIABLE_FACTORY definition) +#define LESSON_VARIABLE_MACRO LESSON_VARIABLE_COPY +#define LESSON_VARIABLE_MACRO_BOOL LESSON_VARIABLE_COPY +#define LESSON_VARIABLE_MACRO_EHANDLE LESSON_VARIABLE_COPY +#define LESSON_VARIABLE_MACRO_STRING LESSON_VARIABLE_COPY + LESSON_VARIABLE_FACTORY +#undef LESSON_VARIABLE_MACRO +#undef LESSON_VARIABLE_MACRO_BOOL +#undef LESSON_VARIABLE_MACRO_EHANDLE +#undef LESSON_VARIABLE_MACRO_STRING + + if ( GetGameInstructor().OpenOpportunity( pOpenLesson ) ) + { + pOpenLesson->OnOpen(); + + if ( pRootLesson->InstanceType() == LESSON_INSTANCE_SINGLE_OPEN ) + { + // This one is open and we only want one! So, we're done. + // Other open events may be listening for the same events... skip them! + return; + } + } + } + } + } +} + +void CScriptedIconLesson::ProcessCloseGameEvents( const CScriptedIconLesson *pRootLesson, const char *name, IGameEvent *event ) +{ + for ( int iLessonEvent = 0; iLessonEvent < pRootLesson->m_CloseEvents.Count() && IsOpenOpportunity(); ++iLessonEvent ) + { + const LessonEvent_t *pLessonEvent = &(pRootLesson->m_CloseEvents[ iLessonEvent ]); + + if ( Q_strcmp( name, pLessonEvent->szEventName.String()) == 0 ) + { + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerboseHeader, "GAME INSTRUCTOR: " ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "Close event " ); + ConColorMsg( CBaseLesson::m_rgbaVerboseClose, "\"%s\"", pLessonEvent->szEventName.String()); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "received for lesson \"%s\"...\n", GetName() ); + } + + if ( ProcessElements( event, &(pLessonEvent->elements) ) ) + { + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerboseClose, "\tAll elements returned true. Closing!\n" ); + } + + CloseOpportunity( "Close event elements completed." ); + } + } + } +} + +void CScriptedIconLesson::ProcessSuccessGameEvents( const CScriptedIconLesson *pRootLesson, const char *name, IGameEvent *event ) +{ + for ( int iLessonEvent = 0; iLessonEvent < pRootLesson->m_SuccessEvents.Count(); ++iLessonEvent ) + { + const LessonEvent_t *pLessonEvent = &(pRootLesson->m_SuccessEvents[ iLessonEvent ]); + + if ( Q_strcmp( name, pLessonEvent->szEventName.String()) == 0 ) + { + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerboseHeader, "GAME INSTRUCTOR: " ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "Success event " ); + ConColorMsg( CBaseLesson::m_rgbaVerboseSuccess, "\"%s\"", pLessonEvent->szEventName.String()); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "received for lesson \"%s\"...\n", GetName() ); + } + + if ( ProcessElements( event, &(pLessonEvent->elements) ) ) + { + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerboseSuccess, "\tAll elements returned true. Succeeding!\n" ); + } + + MarkSucceeded(); + } + } + } +} + +LessonVariable LessonVariableFromString( const char *pchName, bool bWarnOnInvalidNames ) +{ + int slot = g_NameToTypeMap.Find( pchName ); + if ( slot != g_NameToTypeMap.InvalidIndex() ) + return g_NameToTypeMap[ slot ]; + + if ( bWarnOnInvalidNames ) + { + AssertMsg( 0, "Invalid scripted lesson variable!" ); + DevWarning( "Invalid scripted lesson variable: %s\n", pchName ); + } + + return LESSON_VARIABLE_TOTAL; +} + +_fieldtypes LessonParamTypeFromString( const char *pchName ) +{ + int slot = g_TypeToParamTypeMap.Find( pchName ); + if ( slot != g_TypeToParamTypeMap.InvalidIndex() ) + return g_TypeToParamTypeMap[ slot ]; + + DevWarning( "Invalid scripted lesson variable/param type: %s\n", pchName ); + return FIELD_VOID; +} + +int LessonActionFromString( const char *pchName ) +{ + int slot = CScriptedIconLesson::LessonActionMap.Find( pchName ); + if ( slot != CScriptedIconLesson::LessonActionMap.InvalidIndex() ) + return CScriptedIconLesson::LessonActionMap[ slot ]; + + DevWarning( "Invalid scripted lesson action: %s\n", pchName ); + return LESSON_ACTION_NONE; +} + +void CScriptedIconLesson::InitElementsFromKeys( CUtlVector< LessonElement_t > *pLessonElements, KeyValues *pKey ) +{ + KeyValues *pSubKey = NULL; + for ( pSubKey = pKey->GetFirstSubKey(); pSubKey; pSubKey = pSubKey->GetNextKey() ) + { + char szSubKeyName[ 256 ]; + Q_strcpy( szSubKeyName, pSubKey->GetName() ); + + char *pchToken = strtok( szSubKeyName, " " ); + LessonVariable iVariable = LessonVariableFromString( pchToken ); + + pchToken = strtok ( NULL, "" ); + int iAction = LESSON_ACTION_NONE; + bool bNot = false; + bool bOptionalParam = false; + + if ( !pchToken || pchToken[ 0 ] == '\0' ) + { + DevWarning( "No action specified for variable: \"%s\"\n", pSubKey->GetName() ); + } + else + { + if ( pchToken[ 0 ] == '?' ) + { + pchToken++; + bOptionalParam = true; + } + + if ( pchToken[ 0 ] == '!' ) + { + pchToken++; + bNot = true; + } + + iAction = LessonActionFromString( pchToken ); + } + + Q_strcpy( szSubKeyName, pSubKey->GetString() ); + + pchToken = strtok( szSubKeyName, " " ); + _fieldtypes paramType = LessonParamTypeFromString( pchToken ); + + char *pchParam = ""; + + if ( paramType != FIELD_VOID ) + { + pchToken = strtok ( NULL, "" ); + pchParam = pchToken; + } + + if ( !pchParam ) + { + DevWarning( "No parameter specified for action: \"%s\"\n", pSubKey->GetName() ); + } + else + { + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\t\tElement \"%s %s\" added.\n", pSubKey->GetName(), pSubKey->GetString() ); + } + + // See if our param is a scripted var + LessonVariable iParamVarIndex = LessonVariableFromString( pchParam, false ); + + pLessonElements->AddToTail( LessonElement_t( iVariable, iAction, bNot, bOptionalParam, pchParam, iParamVarIndex, paramType ) ); + } + } +} + +void CScriptedIconLesson::InitElementsFromElements( CUtlVector< LessonElement_t > *pLessonElements, const CUtlVector< LessonElement_t > *pLessonElements2 ) +{ + for ( int i = 0; i < pLessonElements2->Count(); ++i ) + { + pLessonElements->AddToTail( LessonElement_t( (*pLessonElements2)[ i ] ) ); + } +} + +void CScriptedIconLesson::InitFromKeys( KeyValues *pKey ) +{ + if ( !pKey ) + return; + + static int s_nInstanceTypeSymbol = KeyValuesSystem()->GetSymbolForString( "instance_type" ); + static int s_nReplaceKeySymbol = KeyValuesSystem()->GetSymbolForString( "replace_key" ); + static int s_nFixedInstancesMaxSymbol = KeyValuesSystem()->GetSymbolForString( "fixed_instances_max" ); + static int s_nReplaceOnlyWhenStopped = KeyValuesSystem()->GetSymbolForString( "replace_only_when_stopped" ); + static int s_nTeamSymbol = KeyValuesSystem()->GetSymbolForString( "team" ); + static int s_nOnlyKeyboardSymbol = KeyValuesSystem()->GetSymbolForString( "only_keyboard" ); + static int s_nOnlyGamepadSymbol = KeyValuesSystem()->GetSymbolForString( "only_gamepad" ); + static int s_nDisplayLimitSymbol = KeyValuesSystem()->GetSymbolForString( "display_limit" ); + static int s_nSuccessLimitSymbol = KeyValuesSystem()->GetSymbolForString( "success_limit" ); + static int s_nPreReqSymbol = KeyValuesSystem()->GetSymbolForString( "prereq" ); + static int s_nOpenSymbol = KeyValuesSystem()->GetSymbolForString( "open" ); + static int s_nCloseSymbol = KeyValuesSystem()->GetSymbolForString( "close" ); + static int s_nSuccessSymbol = KeyValuesSystem()->GetSymbolForString( "success" ); + static int s_nOnOpenSymbol = KeyValuesSystem()->GetSymbolForString( "onopen" ); + static int s_nUpdateSymbol = KeyValuesSystem()->GetSymbolForString( "update" ); + + KeyValues *pSubKey = NULL; + for ( pSubKey = pKey->GetFirstSubKey(); pSubKey; pSubKey = pSubKey->GetNextKey() ) + { + if ( pSubKey->GetNameSymbol() == s_nInstanceTypeSymbol ) + { + m_iInstanceType = LessonInstanceType( pSubKey->GetInt() ); + } + else if ( pSubKey->GetNameSymbol() == s_nReplaceKeySymbol ) + { + m_stringReplaceKey = pSubKey->GetString(); + } + else if ( pSubKey->GetNameSymbol() == s_nFixedInstancesMaxSymbol ) + { + m_iFixedInstancesMax = pSubKey->GetInt(); + } + else if ( pSubKey->GetNameSymbol() == s_nReplaceOnlyWhenStopped ) + { + m_bReplaceOnlyWhenStopped = pSubKey->GetBool(); + } + else if ( pSubKey->GetNameSymbol() == s_nTeamSymbol ) + { + m_iTeam = pSubKey->GetInt(); + } + else if ( pSubKey->GetNameSymbol() == s_nOnlyKeyboardSymbol ) + { + m_bOnlyKeyboard = pSubKey->GetBool(); + } + else if ( pSubKey->GetNameSymbol() == s_nOnlyGamepadSymbol ) + { + m_bOnlyGamepad = pSubKey->GetBool(); + } + else if ( pSubKey->GetNameSymbol() == s_nDisplayLimitSymbol ) + { + m_iDisplayLimit = pSubKey->GetInt(); + } + else if ( pSubKey->GetNameSymbol() == s_nSuccessLimitSymbol ) + { + m_iSuccessLimit = pSubKey->GetInt(); + } + else if ( pSubKey->GetNameSymbol() == s_nPreReqSymbol ) + { + CGameInstructorSymbol pName; + pName = pSubKey->GetString(); + m_PrerequisiteNames.AddToTail( pName ); + } + else if ( pSubKey->GetNameSymbol() == s_nOpenSymbol ) + { + KeyValues *pEventKey = NULL; + for ( pEventKey = pSubKey->GetFirstTrueSubKey(); pEventKey; pEventKey = pEventKey->GetNextTrueSubKey() ) + { + LessonEvent_t *pLessonEvent = AddOpenEvent(); + pLessonEvent->szEventName = pEventKey->GetName(); + + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\tAdding open event " ); + ConColorMsg( CBaseLesson::m_rgbaVerboseOpen, "\"%s\" ", pLessonEvent->szEventName.String()); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "...\n" ); + } + + InitElementsFromKeys( &(pLessonEvent->elements), pEventKey ); + } + } + else if ( pSubKey->GetNameSymbol() == s_nCloseSymbol ) + { + KeyValues *pEventKey = NULL; + for ( pEventKey = pSubKey->GetFirstTrueSubKey(); pEventKey; pEventKey = pEventKey->GetNextTrueSubKey() ) + { + LessonEvent_t *pLessonEvent = AddCloseEvent(); + pLessonEvent->szEventName = pEventKey->GetName(); + + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\tAdding close event " ); + ConColorMsg( CBaseLesson::m_rgbaVerboseClose, "\"%s\" ", pLessonEvent->szEventName.String()); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "...\n" ); + } + + InitElementsFromKeys( &(pLessonEvent->elements), pEventKey ); + } + } + else if ( pSubKey->GetNameSymbol() == s_nSuccessSymbol ) + { + KeyValues *pEventKey = NULL; + for ( pEventKey = pSubKey->GetFirstTrueSubKey(); pEventKey; pEventKey = pEventKey->GetNextTrueSubKey() ) + { + LessonEvent_t *pLessonEvent = AddSuccessEvent(); + pLessonEvent->szEventName = pEventKey->GetName(); + + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\tAdding success event " ); + ConColorMsg( CBaseLesson::m_rgbaVerboseSuccess, "\"%s\" ", pLessonEvent->szEventName.String()); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "...\n" ); + } + + InitElementsFromKeys( &(pLessonEvent->elements), pEventKey ); + } + } + else if ( pSubKey->GetNameSymbol() == s_nOnOpenSymbol ) + { + KeyValues *pEventKey = NULL; + for ( pEventKey = pSubKey->GetFirstTrueSubKey(); pEventKey; pEventKey = pEventKey->GetNextTrueSubKey() ) + { + LessonEvent_t *pLessonEvent = AddOnOpenEvent(); + pLessonEvent->szEventName = pEventKey->GetName(); + + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\tAdding onopen event " ); + ConColorMsg( CBaseLesson::m_rgbaVerboseOpen, "\"%s\" ", pLessonEvent->szEventName.String()); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "...\n" ); + } + + InitElementsFromKeys( &(pLessonEvent->elements), pEventKey ); + } + } + else if ( pSubKey->GetNameSymbol() == s_nUpdateSymbol ) + { + KeyValues *pEventKey = NULL; + for ( pEventKey = pSubKey->GetFirstTrueSubKey(); pEventKey; pEventKey = pEventKey->GetNextTrueSubKey() ) + { + LessonEvent_t *pLessonEvent = AddUpdateEvent(); + pLessonEvent->szEventName = pEventKey->GetName(); + + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\tAdding update event " ); + ConColorMsg( CBaseLesson::m_rgbaVerboseUpdate, "\"%s\" ", pLessonEvent->szEventName.String()); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "...\n" ); + } + + InitElementsFromKeys( &(pLessonEvent->elements), pEventKey ); + } + } + + // Run intialize from key macros on all scriptable variables (see: LESSON_VARIABLE_FACTORY definition) +#define LESSON_VARIABLE_MACRO LESSON_VARIABLE_INIT +#define LESSON_VARIABLE_MACRO_BOOL LESSON_VARIABLE_INIT_BOOL +#define LESSON_VARIABLE_MACRO_EHANDLE LESSON_VARIABLE_INIT_EHANDLE +#define LESSON_VARIABLE_MACRO_STRING LESSON_VARIABLE_INIT_STRING + LESSON_VARIABLE_FACTORY +#undef LESSON_VARIABLE_MACRO +#undef LESSON_VARIABLE_MACRO_BOOL +#undef LESSON_VARIABLE_MACRO_EHANDLE +#undef LESSON_VARIABLE_MACRO_STRING + } +} + +bool CScriptedIconLesson::ProcessElements( IGameEvent *event, const CUtlVector< LessonElement_t > *pElements ) +{ + VPROF_BUDGET( "CScriptedIconLesson::ProcessElements", "GameInstructor" ); + + m_hLocalPlayer = GetGameInstructor().GetLocalPlayer(); + + bool bSuccess = true; + int nContinueScope = -1; + m_iScopeDepth = 0; + + if ( gameinstructor_find_errors.GetBool() ) + { + // Just run them all to check for errors! + for ( int iElement = 0; iElement < pElements->Count(); ++iElement ) + { + ProcessElement( event, &((*pElements)[ iElement ] ), false ); + } + + return false; + } + + // Process each element until a step fails + for ( int iElement = 0; iElement < pElements->Count(); ++iElement ) + { + if ( nContinueScope == m_iScopeDepth ) + { + nContinueScope = -1; + } + + if ( !ProcessElement( event, &((*pElements)[ iElement ]), nContinueScope != -1 ) ) + { + // This element failed + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerboseClose, "\tPrevious element returned false.\n" ); + } + + nContinueScope = m_iScopeDepth - 1; + + if ( nContinueScope < 0 ) + { + // No outer scope to worry about, we're done + bSuccess = false; + break; + } + } + } + + return bSuccess; +} + +bool CScriptedIconLesson::ProcessElement( IGameEvent *event, const LessonElement_t *pLessonElement, bool bInFailedScope ) +{ + ACTIVE_SPLITSCREEN_PLAYER_GUARD( GetSplitScreenSlot() ); + + VPROF_BUDGET( "CScriptedIconLesson::ProcessElement", "GameInstructor" ); + + if ( pLessonElement->iAction == LESSON_ACTION_SCOPE_IN ) + { + // Special case for closing (we don't need variables for this) + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\tScopeIn()\n" ); + } + + m_iScopeDepth++; + return true; + } + else if ( pLessonElement->iAction == LESSON_ACTION_SCOPE_OUT ) + { + // Special case for closing (we don't need variables for this) + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\tScopeOut()\n" ); + } + + m_iScopeDepth--; + return true; + } + + if ( bInFailedScope ) + { + // Only scope upkeep is done when we're in a failing scope... bail! + return true; + } + + if ( pLessonElement->iAction == LESSON_ACTION_CLOSE ) + { + // Special case for closing (we don't need variables for this) + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\tCloseOpportunity()\n" ); + } + + CloseOpportunity( "Close action." ); + return true; + } + else if ( pLessonElement->iAction == LESSON_ACTION_SUCCESS ) + { + // Special case for succeeding (we don't need variables for this) + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\tMarkSucceeded()\n" ); + } + + MarkSucceeded(); + return true; + } + else if ( pLessonElement->iAction == LESSON_ACTION_LOCK ) + { + // Special case for setting the starting point for the lesson to stay locked from (we don't need variables for this) + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\tm_fLockTime = gpGlobals->curtime\n" ); + } + + m_fLockTime = gpGlobals->curtime; + return true; + } + else if ( pLessonElement->iAction == LESSON_ACTION_PRESENT_COMPLETE ) + { + // Special case for checking presentation status (we don't need variables for this) + bool bPresentComplete = IsPresentComplete(); + + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\tIsPresentComplete() " ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "%s ", ( bPresentComplete ) ? ( "true" ) : ( "false" ) ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ( pLessonElement->bNot ) ? ( "!= true\n" ) : ( "== true\n" ) ); + } + + return ( pLessonElement->bNot ) ? ( !bPresentComplete ) : ( bPresentComplete ); + } + else if ( pLessonElement->iAction == LESSON_ACTION_PRESENT_START ) + { + // Special case for setting presentation status (we don't need variables for this) + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\tPresentStart()\n" ); + } + + PresentStart(); + return true; + } + else if ( pLessonElement->iAction == LESSON_ACTION_PRESENT_END ) + { + // Special case for setting presentation status (we don't need variables for this) + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\tPresentEnd()\n" ); + } + + PresentEnd(); + return true; + } + + // These values temporarily hold the parameter's value + const char *pParamName = pLessonElement->szParam.String(); + float eventParam_float = 0.0f; + char eventParam_string[ 256 ]; + eventParam_string[ 0 ] = '\0'; + C_BaseEntity *eventParam_BaseEntity = NULL; + + // Get the value from the event parameter based on its type + switch ( pLessonElement->paramType ) + { + case FIELD_FLOAT: + if ( pLessonElement->iParamVarIndex < LESSON_VARIABLE_TOTAL ) + { + // The parameter is a scripted var + const LessonVariableInfo *pInfo = GetLessonVariableInfo( pLessonElement->iParamVarIndex ); + + switch ( pInfo->varType ) + { + case FIELD_FLOAT: + eventParam_float = LESSON_VARIABLE_GET_FROM_OFFSET( float, pInfo->iOffset ); + break; + case FIELD_INTEGER: + eventParam_float = static_cast( LESSON_VARIABLE_GET_FROM_OFFSET( int, pInfo->iOffset ) ); + break; + case FIELD_BOOLEAN: + eventParam_float = static_cast( LESSON_VARIABLE_GET_FROM_OFFSET( bool, pInfo->iOffset ) ); + break; + case FIELD_STRING: + eventParam_float = static_cast( atoi( &LESSON_VARIABLE_GET_FROM_OFFSET( CGameInstructorSymbol, pInfo->iOffset )->String() ) ); + break; + case FIELD_EHANDLE: + case FIELD_FUNCTION: + DevWarning( "Can't use this variable type with this parameter type in lesson script.\n" ); + break; + } + } + else if ( event && !(event->IsEmpty( pParamName )) ) + { + eventParam_float = event->GetFloat( pParamName ); + } + else if ( pLessonElement->bOptionalParam ) + { + // We don't want to interpret this and not finding the param is still ok + return true; + } + else if ( ( pParamName[ 0 ] >= '0' && pParamName[ 0 ] <= '9' ) || pParamName[ 0 ] == '-' || pParamName[ 0 ] == '.' ) + { + // This param doesn't exist, try parsing the string + eventParam_float = Q_atof( pParamName ); + } + else + { + DevWarning( "Invalid event field name and not a float \"%s\".\n", pParamName ); + return false; + } + break; + + case FIELD_INTEGER: + if ( pLessonElement->iParamVarIndex < LESSON_VARIABLE_TOTAL ) + { + // The parameter is a scripted var + const LessonVariableInfo *pInfo = GetLessonVariableInfo( pLessonElement->iParamVarIndex ); + + switch ( pInfo->varType ) + { + case FIELD_FLOAT: + eventParam_float = static_cast( LESSON_VARIABLE_GET_FROM_OFFSET( float, pInfo->iOffset ) ); + break; + case FIELD_INTEGER: + eventParam_float = LESSON_VARIABLE_GET_FROM_OFFSET( int, pInfo->iOffset ); + break; + case FIELD_BOOLEAN: + eventParam_float = static_cast( LESSON_VARIABLE_GET_FROM_OFFSET( bool, pInfo->iOffset ) ); + break; + case FIELD_STRING: + eventParam_float = atof( &LESSON_VARIABLE_GET_FROM_OFFSET( CGameInstructorSymbol, pInfo->iOffset )->String() ); + break; + case FIELD_EHANDLE: + case FIELD_FUNCTION: + DevWarning( "Can't use this variable type with this parameter type in lesson script.\n" ); + break; + } + } + else if ( event && !(event->IsEmpty( pParamName )) ) + { + eventParam_float = static_cast( event->GetInt( pParamName ) ); + } + else if ( pLessonElement->bOptionalParam ) + { + // We don't want to interpret this and not finding the param is still ok + return true; + } + else if ( ( pParamName[ 0 ] >= '0' && pParamName[ 0 ] <= '9' ) || pParamName[ 0 ] == '-' ) + { + // This param doesn't exist, try parsing the string + eventParam_float = static_cast( Q_atoi( pParamName ) ); + } + else + { + DevWarning( "Invalid event field name and not an integer \"%s\".\n", pParamName ); + return false; + } + break; + + case FIELD_STRING: + if ( pLessonElement->iParamVarIndex < LESSON_VARIABLE_TOTAL ) + { + // The parameter is a scripted var + const LessonVariableInfo *pInfo = GetLessonVariableInfo( pLessonElement->iParamVarIndex ); + + switch ( pInfo->varType ) + { + case FIELD_STRING: + Q_strncpy( eventParam_string, &LESSON_VARIABLE_GET_FROM_OFFSET( CGameInstructorSymbol, pInfo->iOffset )->String(), sizeof( eventParam_string ) ); + break; + case FIELD_FLOAT: + Q_snprintf( eventParam_string, sizeof( eventParam_string ), "%f", LESSON_VARIABLE_GET_FROM_OFFSET( float, pInfo->iOffset ) ); + break; + case FIELD_INTEGER: + Q_snprintf( eventParam_string, sizeof( eventParam_string ), "%i", LESSON_VARIABLE_GET_FROM_OFFSET( int, pInfo->iOffset ) ); + break; + case FIELD_BOOLEAN: + case FIELD_EHANDLE: + case FIELD_FUNCTION: + DevWarning( "Can't use this variable type with this parameter type in lesson script.\n" ); + break; + } + } + else + { + const char *pchEventString = NULL; + + if ( event && !(event->IsEmpty( pParamName )) ) + { + pchEventString = event->GetString( pParamName ); + } + + if ( pchEventString && pchEventString[0] ) + { + Q_strcpy( eventParam_string, pchEventString ); + } + else if ( pLessonElement->bOptionalParam ) + { + // We don't want to interpret this and not finding the param is still ok + return true; + } + else + { + // This param doesn't exist, try parsing the string + Q_strncpy( eventParam_string, pParamName, sizeof( eventParam_string ) ); + } + } + break; + + case FIELD_BOOLEAN: + if ( pLessonElement->iParamVarIndex < LESSON_VARIABLE_TOTAL ) + { + // The parameter is a scripted var + const LessonVariableInfo *pInfo = GetLessonVariableInfo( pLessonElement->iParamVarIndex ); + + switch ( pInfo->varType ) + { + case FIELD_FLOAT: + eventParam_float = ( ( LESSON_VARIABLE_GET_FROM_OFFSET( float, pInfo->iOffset ) ) ? ( 1.0f ) : ( 0.0f ) ); + break; + case FIELD_INTEGER: + eventParam_float = ( ( LESSON_VARIABLE_GET_FROM_OFFSET( int, pInfo->iOffset ) ) ? ( 1.0f ) : ( 0.0f ) ); + break; + case FIELD_BOOLEAN: + eventParam_float = ( ( LESSON_VARIABLE_GET_FROM_OFFSET( bool, pInfo->iOffset ) ) ? ( 1.0f ) : ( 0.0f ) ); + break; + case FIELD_EHANDLE: + case FIELD_STRING: + case FIELD_FUNCTION: + DevWarning( "Can't use this variable type with this parameter type in lesson script.\n" ); + break; + } + } + else if ( event && !(event->IsEmpty( pParamName )) ) + { + eventParam_float = ( event->GetBool( pParamName ) ) ? ( 1.0f ) : ( 0.0f ); + } + else if ( pLessonElement->bOptionalParam ) + { + // We don't want to interpret this and not finding the param is still ok + return true; + } + else if ( pParamName[ 0 ] == '0' || pParamName[ 0 ] == '1' ) + { + // This param doesn't exist, try parsing the string + eventParam_float = Q_atof( pParamName ) != 0.0f; + } + else + { + DevWarning( "Invalid event field name and not an boolean \"%s\".\n", pParamName ); + return false; + } + break; + + case FIELD_CUSTOM: + if ( pLessonElement->iParamVarIndex < LESSON_VARIABLE_TOTAL ) + { + // The parameter is a scripted var + const LessonVariableInfo *pInfo = GetLessonVariableInfo( pLessonElement->iParamVarIndex ); + + switch ( pInfo->varType ) + { + case FIELD_EHANDLE: + eventParam_BaseEntity = ( LESSON_VARIABLE_GET_FROM_OFFSET( EHANDLE, pInfo->iOffset ) ).Get(); + if ( !eventParam_BaseEntity ) + { + if ( pLessonElement->bOptionalParam ) + { + // Not having an entity is fine + return true; + } + + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\tPlayer param \"%s\" returned NULL.\n", pParamName ); + } + return false; + } + break; + case FIELD_FLOAT: + case FIELD_INTEGER: + case FIELD_BOOLEAN: + case FIELD_STRING: + case FIELD_FUNCTION: + DevWarning( "Can't use this variable type with this parameter type in lesson script.\n" ); + break; + } + } + else if ( event && !(event->IsEmpty( pParamName )) ) + { + eventParam_BaseEntity = UTIL_PlayerByUserId( event->GetInt( pParamName ) ); + if ( !eventParam_BaseEntity ) + { + if ( pLessonElement->bOptionalParam ) + { + // Not having an entity is fine + return true; + } + + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\tPlayer param \"%s\" returned NULL.\n", pParamName ); + } + return false; + } + } + else if ( pLessonElement->bOptionalParam ) + { + // We don't want to interpret this and not finding the param is still ok + return true; + } + else if ( Q_stricmp( pParamName, "null" ) == 0 ) + { + // They explicitly want a null pointer + eventParam_BaseEntity = NULL; + } + else + { + DevWarning( "Invalid event field name \"%s\".\n", pParamName ); + return false; + } + break; + + case FIELD_EHANDLE: + if ( pLessonElement->iParamVarIndex < LESSON_VARIABLE_TOTAL ) + { + // The parameter is a scripted var + const LessonVariableInfo *pInfo = GetLessonVariableInfo( pLessonElement->iParamVarIndex ); + + switch ( pInfo->varType ) + { + case FIELD_EHANDLE: + eventParam_BaseEntity = ( LESSON_VARIABLE_GET_FROM_OFFSET( EHANDLE, pInfo->iOffset ) ).Get(); + if ( !eventParam_BaseEntity ) + { + if ( pLessonElement->bOptionalParam ) + { + // Not having an entity is fine + return true; + } + + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\tEntity param \"%s\" returned NULL.\n", pParamName ); + } + return false; + } + break; + case FIELD_FLOAT: + case FIELD_INTEGER: + case FIELD_BOOLEAN: + case FIELD_STRING: + case FIELD_FUNCTION: + DevWarning( "Can't use this variable type with this parameter type in lesson script.\n" ); + break; + } + } + else if ( event && !(event->IsEmpty( pParamName )) ) + { + int iEntID = event->GetInt( pParamName ); + if ( iEntID >= NUM_ENT_ENTRIES ) + { + AssertMsg( 0, "Invalid entity ID used in game event field!" ); + DevWarning( "Invalid entity ID used in game event (%s) for param (%s).", event->GetName(), pParamName ); + return false; + } + + eventParam_BaseEntity = C_BaseEntity::Instance( iEntID ); + if ( !eventParam_BaseEntity ) + { + if ( pLessonElement->bOptionalParam ) + { + // Not having an entity is fine + return true; + } + + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\tEntity param \"%s\" returned NULL.\n", pParamName ); + } + return false; + } + } + else if ( pLessonElement->bOptionalParam ) + { + // We don't want to interpret this and not finding the param is still ok + return true; + } + else if ( Q_stricmp( pParamName, "null" ) == 0 ) + { + // They explicitly want a null pointer + eventParam_BaseEntity = NULL; + } + else if ( Q_stricmp( pParamName, "world" ) == 0 ) + { + // They explicitly want the world + eventParam_BaseEntity = GetClientWorldEntity(); + } + else + { + DevWarning( "Invalid event field name \"%s\".\n", pParamName ); + return false; + } + break; + + case FIELD_EMBEDDED: + { + // The parameter is a convar + ConVarRef tempCVar( pParamName ); + if ( tempCVar.IsValid() ) + { + eventParam_float = tempCVar.GetFloat(); + Q_strncpy( eventParam_string, tempCVar.GetString(), sizeof( eventParam_string ) ); + } + else + { + DevWarning( "Invalid convar name \"%s\".\n", pParamName ); + return false; + } + } + break; + } + + // Do the action to the specified variable + switch ( pLessonElement->iVariable ) + { + // Run process action macros on all scriptable variables (see: LESSON_VARIABLE_FACTORY definition) +#define LESSON_VARIABLE_MACRO PROCESS_LESSON_ACTION +#define LESSON_VARIABLE_MACRO_BOOL PROCESS_LESSON_ACTION +#define LESSON_VARIABLE_MACRO_EHANDLE PROCESS_LESSON_ACTION_EHANDLE +#define LESSON_VARIABLE_MACRO_STRING PROCESS_LESSON_ACTION_STRING + LESSON_VARIABLE_FACTORY; +#undef LESSON_VARIABLE_MACRO +#undef LESSON_VARIABLE_MACRO_BOOL +#undef LESSON_VARIABLE_MACRO_EHANDLE +#undef LESSON_VARIABLE_MACRO_STRING + } + + return true; +} + +bool CScriptedIconLesson::ProcessElementAction( int iAction, bool bNot, const char *pchVarName, float &fVar, const CGameInstructorSymbol *pchParamName, float fParam ) +{ + switch ( iAction ) + { + case LESSON_ACTION_SET: + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\t[%s] = [%s] ", pchVarName, pchParamName->String() ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "%f\n", fParam ); + } + + fVar = fParam; + return true; + + case LESSON_ACTION_ADD: + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\t[%s] += [%s] ", pchVarName, pchParamName->String() ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "%f\n", fParam ); + } + + fVar += fParam; + return true; + + case LESSON_ACTION_SUBTRACT: + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\t[%s] -= [%s] ", pchVarName, pchParamName->String() ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "%f\n", fParam ); + } + + fVar -= fParam; + return true; + + case LESSON_ACTION_MULTIPLY: + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\t[%s] *= [%s] ", pchVarName, pchParamName->String() ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "%f\n", fParam ); + } + + fVar *= fParam; + return true; + + case LESSON_ACTION_IS: + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\t[%s] ", pchVarName ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "%f ", fVar ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ( bNot ) ? ( "!= [%s] " ) : ( "== [%s] " ), pchParamName->String() ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "%f\n", fParam ); + } + + return ( bNot ) ? ( fVar != fParam ) : ( fVar == fParam ); + + case LESSON_ACTION_LESS_THAN: + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\t[%s] ", pchVarName ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "%f ", fVar ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ( bNot ) ? ( ">= [%s] " ) : ( "< [%s] " ), pchParamName->String() ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "%f\n", fParam ); + } + + return ( bNot ) ? ( fVar >= fParam ) : ( fVar < fParam ); + + case LESSON_ACTION_HAS_BIT: + { + int iTemp1 = static_cast( fVar ); + int iTemp2 = ( 1 << static_cast( fParam ) ); + + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\t([%s] ", pchVarName ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "0x%X ", iTemp1 ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "& [%s] ", pchParamName->String() ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "0x%X", iTemp2 ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ( bNot ) ? ( ") == 0\n" ) : ( ") != 0\n" ) ); + } + + return ( bNot ) ? ( ( iTemp1 & iTemp2 ) == 0 ) : ( ( iTemp1 & iTemp2 ) != 0 ); + } + + case LESSON_ACTION_BIT_COUNT_IS: + { + int iTemp1 = UTIL_CountNumBitsSet( static_cast( fVar ) ); + int iTemp2 = static_cast( fParam ); + + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\tUTIL_CountNumBitsSet([%s]) ", pchVarName ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "%i ", iTemp1 ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ( bNot ) ? ( " != [%s] " ) : ( " == [%s] " ), pchParamName->String() ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "%i\n", iTemp2 ); + } + + return ( bNot ) ? ( iTemp1 != iTemp2 ) : ( iTemp1 == iTemp2 ); + } + + case LESSON_ACTION_BIT_COUNT_LESS_THAN: + { + int iTemp1 = UTIL_CountNumBitsSet( static_cast( fVar ) ); + int iTemp2 = static_cast( fParam ); + + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\tUTIL_CountNumBitsSet([%s]) ", pchVarName ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "%i ", iTemp1 ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ( bNot ) ? ( " >= [%s] " ) : ( " < [%s] " ), pchParamName->String() ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "%i\n", iTemp2 ); + } + + return ( bNot ) ? ( iTemp1 >= iTemp2 ) : ( iTemp1 < iTemp2 ); + } + } + + DevWarning( "Invalid lesson action type used with \"%s\" variable type.\n", pchVarName ); + + return false; +} + +bool CScriptedIconLesson::ProcessElementAction( int iAction, bool bNot, const char *pchVarName, int &iVar, const CGameInstructorSymbol *pchParamName, float fParam ) +{ + float fTemp = static_cast( iVar ); + bool bRetVal = ProcessElementAction( iAction, bNot, pchVarName, fTemp, pchParamName, fParam ); + + iVar = static_cast( fTemp ); + return bRetVal; +} + +bool CScriptedIconLesson::ProcessElementAction( int iAction, bool bNot, const char *pchVarName, bool &bVar, const CGameInstructorSymbol *pchParamName, float fParam ) +{ + float fTemp = ( bVar ) ? ( 1.0f ) : ( 0.0f ); + bool bRetVal = ProcessElementAction( iAction, bNot, pchVarName, fTemp, pchParamName, fParam ); + + bVar = ( fTemp != 0.0f ); + return bRetVal; +} + +bool CScriptedIconLesson::ProcessElementAction( int iAction, bool bNot, const char *pchVarName, EHANDLE &hVar, const CGameInstructorSymbol *pchParamName, float fParam, C_BaseEntity *pParam, const char *pchParam ) +{ + // First try to let the mod act on the action + bool bModHandled = false; + bool bModReturn = Mod_ProcessElementAction( iAction, bNot, pchVarName, hVar, pchParamName, fParam, pParam, pchParam, bModHandled ); + + if ( bModHandled ) + { + return bModReturn; + } + + C_BaseEntity *pVar = hVar.Get(); + + switch ( iAction ) + { + case LESSON_ACTION_SET: + { + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\t[%s] = [%s]\n", pchVarName, pchParamName->String() ); + } + + hVar = pParam; + return true; + } + + case LESSON_ACTION_IS: + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ( bNot ) ? ( "\t[%s] != [%s]\n" ) : ( "\t[%s] == [%s]\n" ), pchVarName, pchParamName->String() ); + } + + return ( bNot ) ? ( pVar != pParam ) : ( pVar == pParam ); + + case LESSON_ACTION_GET_DISTANCE: + { + if ( !pVar || !pParam ) + { + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\t[output] = [%s]->DistTo( [%s] )", pchVarName, pchParamName->String() ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "...\n" ); + ConColorMsg( CBaseLesson::m_rgbaVerboseClose, "\tVar handle or Param handle returned NULL!\n" ); + } + + return false; + } + + C_BasePlayer *pVarPlayer = ( pVar->IsPlayer() ? static_cast< C_BasePlayer* >( pVar ) : NULL ); + C_BasePlayer *pParamPlayer = ( pParam->IsPlayer() ? static_cast< C_BasePlayer* >( pParam ) : NULL ); + + Vector vVarPos = ( pVarPlayer ? pVarPlayer->ActivePlayerCombatCharacter()->EyePosition() : pVar->WorldSpaceCenter() ); + Vector vParamPos = ( pParamPlayer ? pParamPlayer->ActivePlayerCombatCharacter()->EyePosition() : pParam->WorldSpaceCenter() ); + + m_fOutput = vVarPos.DistTo( vParamPos ); + + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\t[output] = [%s]->DistTo( [%s] ) ", pchVarName, pchParamName->String() ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "%f\n", m_fOutput ); + } + + return true; + } + + case LESSON_ACTION_GET_ANGULAR_DISTANCE: + { + if ( !pVar || !pParam ) + { + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\t[output] = [%s]->AngularDistTo( [%s] )", pchVarName, pchParamName->String() ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "...\n" ); + ConColorMsg( CBaseLesson::m_rgbaVerboseClose, "\tVar handle or Param handle returned NULL!\n" ); + } + + return false; + } + + C_BasePlayer *pVarPlayer = ( pVar->IsPlayer() ? static_cast< C_BasePlayer* >( pVar ) : NULL ); + C_BasePlayer *pParamPlayer = ( pParam->IsPlayer() ? static_cast< C_BasePlayer* >( pParam ) : NULL ); + + Vector vVarPos = ( pVarPlayer ? pVarPlayer->ActivePlayerCombatCharacter()->EyePosition() : pVar->WorldSpaceCenter() ); + Vector vParamPos = ( pParamPlayer ? pParamPlayer->ActivePlayerCombatCharacter()->EyePosition() : pParam->WorldSpaceCenter() ); + + Vector vVarToParam = vParamPos - vVarPos; + VectorNormalize( vVarToParam ); + + Vector vVarForward; + + if ( pVar->IsPlayer() ) + { + AngleVectors( static_cast< C_BasePlayer* >( pVar )->ActivePlayerCombatCharacter()->EyeAngles(), &vVarForward, NULL, NULL ); + } + else + { + pVar->GetVectors( &vVarForward, NULL, NULL ); + } + + // Set the distance in degrees + m_fOutput = ( vVarToParam.Dot( vVarForward ) - 1.0f ) * -90.0f; + + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\t[output] = [%s]->AngularDistTo( [%s] ) ", pchVarName, pchParamName->String() ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "%f\n", m_fOutput ); + } + + return true; + } + + case LESSON_ACTION_GET_PLAYER_DISPLAY_NAME: + { + int iTemp = static_cast( fParam ); + + if ( iTemp <= 0 || iTemp > 2 ) + { + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\tQ_strcpy( [stringINVALID], [%s]->GetPlayerName() ", pchVarName ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "... " ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ")\n" ); + ConColorMsg( CBaseLesson::m_rgbaVerboseClose, "\tParam selecting string is out of range!\n" ); + } + + return false; + } + + // Use string2 if it was specified, otherwise, use string1 + CGameInstructorSymbol *pString; + char const *pchParamNameTemp = NULL; + + if ( iTemp == 2 ) + { + pString = &m_szString2; + pchParamNameTemp = "string2"; + } + else + { + pString = &m_szString1; + pchParamNameTemp = "string1"; + } + + if ( !pVar ) + { + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\tQ_strcpy( [%s], [%s]->GetPlayerName() ", pchParamNameTemp, pchVarName ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "... " ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ")\n" ); + ConColorMsg( CBaseLesson::m_rgbaVerboseClose, "\tVar handle returned NULL!\n" ); + } + + return false; + } + + *pString = pVar->GetPlayerName(); + + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\tQ_strcpy( [%s], [%s]->GetPlayerName() ", pchParamNameTemp, pchVarName ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "\"%s\" ", pString->String() ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ")\n" ); + } + + return true; + } + + case LESSON_ACTION_CLASSNAME_IS: + { + if ( !pVar ) + { + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ( bNot ) ? ( "\t!FClassnameIs( [%s] " ) : ( "\tFClassnameIs( [%s] " ), pchVarName ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "..." ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ", [%s] ", pchParamName->String() ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "\"%s\" ", pchParam ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ")\n" ); + + ConColorMsg( CBaseLesson::m_rgbaVerboseClose, "\tVar handle returned NULL!\n" ); + } + + return false; + } + + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ( bNot ) ? ( "\t!FClassnameIs( [%s] " ) : ( "\tFClassnameIs( [%s] " ), pchVarName ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "%s", pVar->GetClassname() ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ", [%s] ", pchParamName->String() ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "\"%s\" ", pchParam ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ")\n" ); + } + + return ( bNot ) ? ( !FClassnameIs( pVar, pchParam ) ) : ( FClassnameIs( pVar, pchParam ) ); + } + + case LESSON_ACTION_TEAM_IS: + { + int iTemp = static_cast( fParam ); + + if ( !pVar ) + { + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\t[%s]->GetTeamNumber() ", pchVarName ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "... " ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ( bNot ) ? ( "!= [%s] " ) : ( "== [%s] " ), pchParamName->String() ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "%i\n", iTemp ); + ConColorMsg( CBaseLesson::m_rgbaVerboseClose, "\tVar handle returned NULL!\n" ); + } + + return false; + } + + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\t[%s]->GetTeamNumber() ", pchVarName ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "%i ", pVar->GetTeamNumber() ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ( bNot ) ? ( "!= [%s] " ) : ( "== [%s] " ), pchParamName->String() ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "%i\n", iTemp ); + } + + return ( bNot ) ? ( pVar->GetTeamNumber() != iTemp ) : ( pVar->GetTeamNumber() == iTemp ); + } + + case LESSON_ACTION_MODELNAME_IS: + { + C_BaseAnimating *pBaseAnimating = dynamic_cast( pVar ); + + if ( !pBaseAnimating ) + { + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\tQ_stricmp( [%s]->ModelName() ", pchVarName ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "..." ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ", [%s] ", pchParamName->String() ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "\"%s\" ", pchParam ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ( bNot ) ? ( ") != 0\n" ) : ( ") == 0\n" ) ); + ConColorMsg( CBaseLesson::m_rgbaVerboseClose, "\tVar handle as BaseAnimating returned NULL!\n" ); + } + + return false; + } + + const char *pchModelName = "-no model-"; + CStudioHdr *pModel = pBaseAnimating->GetModelPtr(); + if ( pModel ) + { + const studiohdr_t *pRenderHDR = pModel->GetRenderHdr(); + if ( pRenderHDR ) + { + pchModelName = pRenderHDR->name; + } + } + + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\tQ_stricmp( [%s]->ModelName() ", pchVarName ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "%s", pchModelName ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ", [%s] ", pchParamName->String() ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "\"%s\" ", pchParam ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ( bNot ) ? ( ") != 0\n" ) : ( ") == 0\n" ) ); + } + + return ( bNot ) ? ( Q_stricmp( pchModelName, pchParam ) != 0 ) : ( Q_stricmp( pchModelName, pchParam ) == 0 ); + } + + case LESSON_ACTION_HEALTH_LESS_THAN: + { + int iTemp = static_cast( fParam ); + + if ( !pVar ) + { + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\t[%s]->GetHealth() ", pchVarName ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "... " ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ( bNot ) ? ( ">= [%s] " ) : ( "< [%s] " ), pchParamName->String() ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "%i\n", iTemp ); + ConColorMsg( CBaseLesson::m_rgbaVerboseClose, "\tVar handle returned NULL!\n" ); + } + + return false; + } + + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\t[%s]->GetHealth() ", pchVarName ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "%i ", pVar->GetHealth() ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ( bNot ) ? ( ">= [%s] " ) : ( "< [%s] " ), pchParamName->String() ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "%i\n", iTemp ); + } + + return ( bNot ) ? ( pVar->GetHealth() >= iTemp ) : ( pVar->GetHealth() < iTemp ); + } + + case LESSON_ACTION_HEALTH_PERCENTAGE_LESS_THAN: + { + if ( !pVar ) + { + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\t[%s]->HealthFraction() ", pchVarName, pchVarName ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "... " ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ( bNot ) ? ( ">= [%s] " ) : ( "< [%s] " ), pchParamName->String() ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "%f\n", fParam ); + ConColorMsg( CBaseLesson::m_rgbaVerboseClose, "\tVar handle returned NULL!\n" ); + } + + return false; + } + + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\t[%s]->HealthFraction() ", pchVarName, pchVarName ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "%f ", pVar->HealthFraction() ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ( bNot ) ? ( ">= [%s] " ) : ( "< [%s] " ), pchParamName->String() ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "%f\n", fParam ); + } + + float fHealthPercentage = 1.0f; + + if ( pVar->GetMaxHealth() != 0.0f ) + { + fHealthPercentage = pVar->HealthFraction(); + } + + return ( bNot ) ? ( fHealthPercentage >= fParam ) : ( fHealthPercentage < fParam ); + } + + case LESSON_ACTION_GET_ACTIVE_WEAPON: + { + int iTemp = static_cast( fParam ); + + if ( iTemp <= 0 || iTemp > 2 ) + { + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\t[entityINVALID] = [%s]->GetActiveWeapon()\n", pchVarName ); + ConColorMsg( CBaseLesson::m_rgbaVerboseClose, "\tParam selecting string is out of range!\n" ); + } + + return false; + } + + // Use entity2 if it was specified, otherwise, use entity1 + CHandle *pHandle; + + char const *pchParamNameTemp = NULL; + + if ( iTemp == 2 ) + { + pHandle = &m_hEntity2; + pchParamNameTemp = "entity2"; + } + else + { + pHandle = &m_hEntity1; + pchParamNameTemp = "entity1"; + } + + C_BaseCombatCharacter *pBaseCombatCharacter = NULL; + + if ( pVar ) + { + pBaseCombatCharacter = pVar->MyCombatCharacterPointer(); + } + + if ( !pBaseCombatCharacter ) + { + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\t[%s] = [%s]->GetActiveWeapon()", pchParamNameTemp, pchVarName ); + ConColorMsg( CBaseLesson::m_rgbaVerboseClose, "\tVar handle as BaseCombatCharacter returned NULL!\n" ); + } + + return false; + } + + pHandle->Set( pBaseCombatCharacter->GetActiveWeapon() ); + + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\t[%s] = [%s]->GetActiveWeapon()", pchParamNameTemp, pchVarName ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "\"%s\"\n", pchParam ); + } + + return true; + } + + case LESSON_ACTION_WEAPON_IS: + { + C_BaseCombatCharacter *pBaseCombatCharacter = NULL; + + if ( pVar ) + { + pBaseCombatCharacter = pVar->MyCombatCharacterPointer(); + } + + if ( !pBaseCombatCharacter ) + { + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\t[%s]->GetActiveWeapon()->GetName() ", pchVarName ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "... " ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ( bNot ) ? ( "!= [%s] " ) : ( "== [%s] " ), pchParamName->String() ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "\"%s\"\n", pchParam ); + ConColorMsg( CBaseLesson::m_rgbaVerboseClose, "\tVar handle as BaseCombatCharacter returned NULL!\n" ); + } + + return false; + } + + CBaseCombatWeapon *pBaseCombatWeapon = pBaseCombatCharacter->GetActiveWeapon(); + + if ( !pBaseCombatWeapon ) + { + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\t[%s]->GetActiveWeapon()->GetName() ", pchVarName ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "... " ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ( bNot ) ? ( "!= [%s] " ) : ( "== [%s] " ), pchParamName->String() ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "\"%s\"\n", pchParam ); + ConColorMsg( CBaseLesson::m_rgbaVerboseClose, "\tVar GetActiveWeapon returned NULL!\n" ); + } + + return false; + } + + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\t[%s]->GetActiveWeapon()->GetName() ", pchVarName ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "\"%s\" ", pBaseCombatWeapon->GetName() ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ( bNot ) ? ( "!= [%s] " ) : ( "== [%s] " ), pchParamName->String() ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "\"%s\"\n", pchParam ); + } + + return ( bNot ) ? ( Q_stricmp( pBaseCombatWeapon->GetName(), pchParam ) != 0 ) : ( Q_stricmp( pBaseCombatWeapon->GetName(), pchParam ) == 0 ); + } + + case LESSON_ACTION_WEAPON_HAS: + { + C_BaseCombatCharacter *pBaseCombatCharacter = NULL; + + if ( pVar ) + { + pBaseCombatCharacter = pVar->MyCombatCharacterPointer(); + } + + if ( !pBaseCombatCharacter ) + { + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ( bNot ) ? ( "\t![%s]->Weapon_OwnsThisType([%s] " ) : ( "\t[%s]->Weapon_OwnsThisType([%s] " ), pchVarName, pchParamName->String() ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "\"%s\"", pchParam ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ")\n" ); + ConColorMsg( CBaseLesson::m_rgbaVerboseClose, "\tVar handle as BaseCombatCharacter returned NULL!\n" ); + } + + return false; + } + + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ( bNot ) ? ( "\t![%s]->Weapon_OwnsThisType([%s] " ) : ( "\t[%s]->Weapon_OwnsThisType([%s] " ), pchVarName, pchParamName->String() ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "\"%s\"", pchParam ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ")\n" ); + } + + return ( bNot ) ? ( pBaseCombatCharacter->Weapon_OwnsThisType( pchParam ) == NULL ) : ( pBaseCombatCharacter->Weapon_OwnsThisType( pchParam ) != NULL ); + } + + case LESSON_ACTION_GET_ACTIVE_WEAPON_SLOT: + { + C_BaseCombatCharacter *pBaseCombatCharacter = NULL; + + if ( pVar ) + { + pBaseCombatCharacter = pVar->MyCombatCharacterPointer(); + } + + if ( !pBaseCombatCharacter ) + { + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\t[output] = [%s]->Weapon_GetActiveSlot() ...\n", pchVarName ); + ConColorMsg( CBaseLesson::m_rgbaVerboseClose, "\tVar handle as BaseCombatCharacter returned NULL!\n" ); + } + + return false; + } + + C_BaseCombatWeapon *pWeapon = pBaseCombatCharacter->GetActiveWeapon(); + + if ( !pWeapon ) + { + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\t[output] = [%s]->Weapon_GetActiveSlot() ...\n", pchVarName ); + ConColorMsg( CBaseLesson::m_rgbaVerboseClose, "\tVar GetActiveWeapon returned NULL!\n" ); + } + + return false; + } + + m_fOutput = pBaseCombatCharacter->Weapon_GetSlot( pWeapon->GetWpnData().szClassName ); + + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\t[output] = [%s]->Weapon_GetSlot() ", pchVarName ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "%f\n", m_fOutput ); + } + + return true; + } + + case LESSON_ACTION_GET_WEAPON_SLOT: + { + C_BaseCombatCharacter *pBaseCombatCharacter = NULL; + + if ( pVar ) + { + pBaseCombatCharacter = pVar->MyCombatCharacterPointer(); + } + + if ( !pBaseCombatCharacter ) + { + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\t[output] = [%s]->Weapon_GetSlot([%s] ", pchVarName, pchParamName->String() ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "\"%s\"", pchParam ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ") ...\n" ); + ConColorMsg( CBaseLesson::m_rgbaVerboseClose, "\tVar handle as BaseCombatCharacter returned NULL!\n" ); + } + + return false; + } + + m_fOutput = pBaseCombatCharacter->Weapon_GetSlot( pchParam ); + + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\t[output] = [%s]->Weapon_GetSlot([%s] ", pchVarName, pchParamName->String() ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "\"%s\"", pchParam ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ") " ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "%f\n", m_fOutput ); + } + + return true; + } + + case LESSON_ACTION_GET_WEAPON_IN_SLOT: + { + int nTemp = static_cast( fParam ); + + C_BaseCombatCharacter *pBaseCombatCharacter = NULL; + + if ( pVar ) + { + pBaseCombatCharacter = pVar->MyCombatCharacterPointer(); + } + + if ( !pBaseCombatCharacter ) + { + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\t[entity1] = [%s]->GetWeapon([%s] ", pchVarName, pchParamName->String() ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "\"%i\"", nTemp ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ")\n" ); + ConColorMsg( CBaseLesson::m_rgbaVerboseClose, "\tVar handle as BaseCombatCharacter returned NULL!\n" ); + } + + return false; + } + + m_hEntity1 = pBaseCombatCharacter->GetWeapon( nTemp ); + + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\t[entity1] = [%s]->GetWeapon([%s] ", pchVarName, pchParamName->String() ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "\"%i\"", nTemp ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ")\n" ); + } + + return true; + } + + case LESSON_ACTION_CLIP_PERCENTAGE_LESS_THAN: + { + C_BaseCombatCharacter *pBaseCombatCharacter = NULL; + + if ( pVar ) + { + pBaseCombatCharacter = pVar->MyCombatCharacterPointer(); + } + + if ( !pBaseCombatCharacter ) + { + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\t[%s]->GetActiveWeapon()->Clip1Percentage() ", pchVarName ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "... " ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ( bNot ) ? ( ">= [%s] " ) : ( "< [%s] " ), pchParamName->String() ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "%.1f\n", fParam ); + ConColorMsg( CBaseLesson::m_rgbaVerboseClose, "\tVar handle as BaseCombatCharacter returned NULL!\n" ); + } + + return false; + } + + CBaseCombatWeapon *pBaseCombatWeapon = pBaseCombatCharacter->GetActiveWeapon(); + + if ( !pBaseCombatWeapon ) + { + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\t[%s]->GetActiveWeapon()->Clip1Percentage() ", pchVarName ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "... " ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ( bNot ) ? ( ">= [%s] " ) : ( "< [%s] " ), pchParamName->String() ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "%.1f\n", fParam ); + ConColorMsg( CBaseLesson::m_rgbaVerboseClose, "\tVar GetActiveWeapon returned NULL!\n" ); + } + + return false; + } + + float fClip1Percentage = 100.0f; + + if ( pBaseCombatWeapon->UsesClipsForAmmo1() ) + { + fClip1Percentage = 100.0f * ( static_cast( pBaseCombatWeapon->Clip1() ) / static_cast( pBaseCombatWeapon->GetMaxClip1() ) ); + } + + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\t[%s]->GetActiveWeapon()->Clip1Percentage() ", pchVarName ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "%.1f ", fClip1Percentage ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ( bNot ) ? ( ">= [%s] " ) : ( "< [%s] " ), pchParamName->String() ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "%.1f\n", fParam ); + } + + return ( bNot ) ? ( fClip1Percentage >= fParam ) : ( fClip1Percentage < fParam ); + } + + case LESSON_ACTION_WEAPON_AMMO_LOW: + { + int iTemp = static_cast( fParam ); + + C_BasePlayer *pBasePlayer = ToBasePlayer( pVar ); + + if ( !pBasePlayer ) + { + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\t[%s]->GetWeaponInSlot( ", pchVarName ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "%i ", iTemp ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ( bNot ) ? ( ")->AmmoPercentage() >= 30\n" ) : ( ")->AmmoPercentage() < 30\n" ) ); + ConColorMsg( CBaseLesson::m_rgbaVerboseClose, "\tVar handle as BasePlayer returned NULL!\n" ); + } + + return false; + } + + CBaseCombatWeapon *pBaseCombatWeapon = NULL; + + // Get the weapon in variable slot + for ( int iWeapon = 0; iWeapon < MAX_WEAPONS; iWeapon++ ) + { + CBaseCombatWeapon *pBaseCombatWeaponTemp = pBasePlayer->ActivePlayerCombatCharacter()->GetWeapon( iWeapon ); + if ( pBaseCombatWeaponTemp ) + { + if ( pBaseCombatWeaponTemp->GetSlot() == iTemp ) + { + pBaseCombatWeapon = pBaseCombatWeaponTemp; + break; + } + } + } + + if ( !pBaseCombatWeapon ) + { + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\t[%s]->GetWeaponInSlot( ", pchVarName ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "%i ", iTemp ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ( bNot ) ? ( ")->AmmoPercentage() >= 30\n" ) : ( ")->AmmoPercentage() < 30\n" ) ); + ConColorMsg( CBaseLesson::m_rgbaVerboseClose, "\tVar GetActiveWeapon returned NULL!\n" ); + } + + return false; + } + + // Check if the ammo is full + int iAmmoType = pBaseCombatWeapon->GetPrimaryAmmoType(); + int iMaxAmmo = GetAmmoDef()->MaxCarry( iAmmoType, pBasePlayer ); + int iPlayerAmmo = pBasePlayer->ActivePlayerCombatCharacter()->GetAmmoCount( iAmmoType ); + + bool bAmmoLow = ( iPlayerAmmo < ( iMaxAmmo / 3 ) ); + + if ( bNot ) + { + bAmmoLow = !bAmmoLow; + } + + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\t[%s]->GetWeaponInSlot( ", pchVarName ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "%i ", iTemp ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ( bNot ) ? ( ")->AmmoPercentage() >= 30 " ) : ( ")->AmmoPercentage() < 30 " ) ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ( bAmmoLow ) ? ( "true\n" ) : ( "false\n" ) ); + } + + return bAmmoLow; + } + + case LESSON_ACTION_WEAPON_AMMO_FULL: + { + int iTemp = static_cast( fParam ); + + C_BasePlayer *pBasePlayer = ToBasePlayer( pVar ); + + if ( !pBasePlayer ) + { + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ( bNot ) ? ( "\t![%s]->GetWeaponInSlot( " ) : ( "\t[%s]->GetWeaponInSlot( " ), pchVarName ); + ConColorMsg( CBaseLesson::m_rgbaVerboseSuccess, "%i ", iTemp ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ")->AmmoFull()\n" ); + ConColorMsg( CBaseLesson::m_rgbaVerboseClose, "\tVar handle as BasePlayer returned NULL!\n" ); + } + + return false; + } + + CBaseCombatWeapon *pBaseCombatWeapon = NULL; + + // Get the weapon in variable slot + for ( int iWeapon = 0; iWeapon < MAX_WEAPONS; iWeapon++ ) + { + CBaseCombatWeapon *pBaseCombatWeaponTemp = pBasePlayer->ActivePlayerCombatCharacter()->GetWeapon( iWeapon ); + if ( pBaseCombatWeaponTemp ) + { + if ( pBaseCombatWeaponTemp->GetSlot() == iTemp ) + { + pBaseCombatWeapon = pBaseCombatWeaponTemp; + break; + } + } + } + + if ( !pBaseCombatWeapon ) + { + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ( bNot ) ? ( "\t![%s]->GetWeaponInSlot( " ) : ( "\t[%s]->GetWeaponInSlot( " ), pchVarName ); + ConColorMsg( CBaseLesson::m_rgbaVerboseSuccess, "%i ", iTemp ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ")->AmmoFull()\n" ); + ConColorMsg( CBaseLesson::m_rgbaVerboseClose, "\tVar GetWeaponInSlot returned NULL!\n" ); + } + + return false; + } + + // Check if the ammo is full + int iAmmoType = pBaseCombatWeapon->GetPrimaryAmmoType(); + int iMaxAmmo = GetAmmoDef()->MaxCarry( iAmmoType, pBasePlayer ); + int iPlayerAmmo = pBasePlayer->ActivePlayerCombatCharacter()->GetAmmoCount( iAmmoType ); + + bool bAmmoFull = ( iPlayerAmmo >= iMaxAmmo ); + + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ( bNot ) ? ( "\t![%s]->GetWeaponInSlot( " ) : ( "\t[%s]->GetWeaponInSlot( " ), pchVarName ); + ConColorMsg( CBaseLesson::m_rgbaVerboseSuccess, "%i ", iTemp ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ")->AmmoFull() " ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, ( bAmmoFull ) ? ( "true\n" ) : ( "false\n" ) ); + } + + return ( bNot ) ? ( !bAmmoFull ) : ( bAmmoFull ); + } + + case LESSON_ACTION_WEAPON_AMMO_EMPTY: + { + int iTemp = static_cast( fParam ); + + C_BasePlayer *pBasePlayer = ToBasePlayer( pVar ); + + if ( !pBasePlayer ) + { + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ( bNot ) ? ( "\t![%s]->GetWeaponInSlot( " ) : ( "\t[%s]->GetWeaponInSlot( " ), pchVarName ); + ConColorMsg( CBaseLesson::m_rgbaVerboseSuccess, "%i ", iTemp ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ")->AmmoEmpty()\n" ); + ConColorMsg( CBaseLesson::m_rgbaVerboseClose, "\tVar handle as BasePlayer returned NULL!\n" ); + } + + return false; + } + + CBaseCombatWeapon *pBaseCombatWeapon = NULL; + + // Get the weapon in variable slot + for ( int iWeapon = 0; iWeapon < MAX_WEAPONS; iWeapon++ ) + { + CBaseCombatWeapon *pBaseCombatWeaponTemp = pBasePlayer->ActivePlayerCombatCharacter()->GetWeapon( iWeapon ); + if ( pBaseCombatWeaponTemp ) + { + if ( pBaseCombatWeaponTemp->GetSlot() == iTemp ) + { + pBaseCombatWeapon = pBaseCombatWeaponTemp; + break; + } + } + } + + if ( !pBaseCombatWeapon ) + { + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ( bNot ) ? ( "\t![%s]->GetWeaponInSlot( " ) : ( "\t[%s]->GetWeaponInSlot( " ), pchVarName ); + ConColorMsg( CBaseLesson::m_rgbaVerboseSuccess, "%i ", iTemp ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ")->AmmoEmpty()\n" ); + ConColorMsg( CBaseLesson::m_rgbaVerboseClose, "\tVar GetWeaponInSlot returned NULL!\n" ); + } + + return false; + } + + // Check if the ammo is empty + int iAmmoType = pBaseCombatWeapon->GetPrimaryAmmoType(); + int iPlayerAmmo = pBasePlayer->ActivePlayerCombatCharacter()->GetAmmoCount( iAmmoType ); + + bool bAmmoEmpty = ( iPlayerAmmo <= 0 ); + + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ( bNot ) ? ( "\t![%s]->GetWeaponInSlot( " ) : ( "\t[%s]->GetWeaponInSlot( " ), pchVarName ); + ConColorMsg( CBaseLesson::m_rgbaVerboseSuccess, "%i ", iTemp ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ")->AmmoEmpty() " ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, ( bAmmoEmpty ) ? ( "true" ) : ( "false" ) ); + ConColorMsg(CBaseLesson::m_rgbaVerbosePlain, " )\n" ); + } + + return ( bNot ) ? ( !bAmmoEmpty ) : ( bAmmoEmpty ); + } + + case LESSON_ACTION_WEAPON_CAN_USE: + { + C_BaseCombatWeapon *pBaseCombatWeapon = dynamic_cast( pParam ); + C_BasePlayer *pBasePlayer = ToBasePlayer( pVar ); + + if ( !pBasePlayer ) + { + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ( bNot ) ? ( "\t![%s]->Weapon_CanUse([%s])\n" ) : ( "\t[%s]->Weapon_CanUse([%s])\n" ), pchVarName, pchParamName->String() ); + ConColorMsg( CBaseLesson::m_rgbaVerboseClose, "\tVar handle as BasePlayer returned NULL!\n" ); + } + + return false; + } + + if ( !pBaseCombatWeapon ) + { + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ( bNot ) ? ( "\t![%s]->Weapon_CanUse([%s])\n" ) : ( "\t[%s]->Weapon_CanUse([%s])\n" ), pchVarName, pchParamName->String() ); + ConColorMsg( CBaseLesson::m_rgbaVerboseClose, "\tParam BaseCombatWeapon returned NULL!\n" ); + } + + return false; + } + + bool bCanEquip = pBasePlayer->Weapon_CanUse( pBaseCombatWeapon ); + + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ( bNot ) ? ( "\t![%s]->Weapon_CanUse([%s]) " ) : ( "\t[%s]->Weapon_CanUse([%s]) " ), pchVarName, pchParamName->String() ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, ( bCanEquip ) ? ( "true\n" ) : ( "false\n" ) ); + } + + return ( bNot ) ? ( !bCanEquip ) : ( bCanEquip ); + } + + case LESSON_ACTION_USE_TARGET_IS: + { + C_BasePlayer *pBasePlayer = ToBasePlayer( pVar ); + + if ( !pBasePlayer ) + { + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ( bNot ) ? ( "\tC_BaseEntity::Instance([%s]->GetUseEntity()) != [%s]\n" ) : ( "\tC_BaseEntity::Instance([%s]->GetUseEntity()) == [%s]\n" ), pchVarName, pchParamName->String() ); + ConColorMsg( CBaseLesson::m_rgbaVerboseClose, "\tVar handle as Player returned NULL!\n" ); + } + + return false; + } + + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ( bNot ) ? ( "\tC_BaseEntity::Instance([%s]->GetUseEntity()) != [%s]\n" ) : ( "\tC_BaseEntity::Instance([%s]->GetUseEntity()) == [%s]\n" ), pchVarName, pchParamName->String() ); + } + + return ( bNot ) ? ( C_BaseEntity::Instance( pBasePlayer->GetUseEntity() ) != pParam ) : ( C_BaseEntity::Instance( pBasePlayer->GetUseEntity() ) == pParam ); + } + + case LESSON_ACTION_GET_USE_TARGET: + { + int iTemp = static_cast( fParam ); + + if ( iTemp <= 0 || iTemp > 2 ) + { + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\t[entityINVALID] = C_BaseEntity::Instance([%s]->GetUseEntity())\n", pchVarName ); + ConColorMsg( CBaseLesson::m_rgbaVerboseClose, "\tParam selecting string is out of range!\n" ); + } + + return false; + } + + // Use entity2 if it was specified, otherwise, use entity1 + CHandle *pHandle; + char const *pchParamNameTemp = NULL; + + if ( iTemp == 2 ) + { + pHandle = &m_hEntity2; + pchParamNameTemp = "entity2"; + } + else + { + pHandle = &m_hEntity1; + pchParamNameTemp = "entity1"; + } + + C_BasePlayer *pBasePlayer = ToBasePlayer( pVar ); + + if ( !pBasePlayer ) + { + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\t[%s] = C_BaseEntity::Instance([%s]->GetUseEntity())\n", pchParamNameTemp, pchVarName ); + ConColorMsg( CBaseLesson::m_rgbaVerboseClose, "\tVar handle as Player returned NULL!\n" ); + } + + return false; + } + + pHandle->Set( C_BaseEntity::Instance( pBasePlayer->GetUseEntity() ) ); + + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\t[%s] = C_BaseEntity::Instance([%s]->GetUseEntity())\n", pchParamNameTemp, pchVarName ); + } + + return true; + } + + case LESSON_ACTION_GET_POTENTIAL_USE_TARGET: + { + int iTemp = static_cast( fParam ); + + if ( iTemp <= 0 || iTemp > 2 ) + { + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\t[entityINVALID] = C_BaseEntity::Instance([%s]->GetPotentialUseEntity())\n", pchVarName ); + ConColorMsg( CBaseLesson::m_rgbaVerboseClose, "\tParam selecting string is out of range!\n" ); + } + + return false; + } + + // Use entity2 if it was specified, otherwise, use entity1 + CHandle *pHandle; + char const *pchParamNameTemp = NULL; + + if ( iTemp == 2 ) + { + pHandle = &m_hEntity2; + pchParamNameTemp = "entity2"; + } + else + { + pHandle = &m_hEntity1; + pchParamNameTemp = "entity1"; + } + + C_BasePlayer *pBasePlayer = ToBasePlayer( pVar ); + + if ( !pBasePlayer ) + { + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\t[%s] = C_BaseEntity::Instance([%s]->GetPotentialUseEntity())\n", pchParamNameTemp, pchVarName ); + ConColorMsg( CBaseLesson::m_rgbaVerboseClose, "\tVar handle as Player returned NULL!\n" ); + } + + return false; + } + + pHandle->Set( C_BaseEntity::Instance( pBasePlayer->GetPotentialUseEntity() ) ); + + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\t[%s] = C_BaseEntity::Instance([%s]->GetPotentialUseEntity())\n", pchParamNameTemp, pchVarName ); + } + + return true; + } + } + + DevWarning( "Invalid lesson action type used with \"%s\" variable type.\n", pchVarName ); + + return false; +} + +bool CScriptedIconLesson::ProcessElementAction( int iAction, bool bNot, const char *pchVarName, CGameInstructorSymbol *pchVar, const CGameInstructorSymbol *pchParamName, const char *pchParam ) +{ + switch ( iAction ) + { + case LESSON_ACTION_REFERENCE_OPEN: + { + const CBaseLesson *pLesson = GetGameInstructor().GetLesson( pchParamName->String() ); + if ( !pLesson ) + { + DevWarning( "Invalid lesson specified: \"%s\".", pchParamName->String() ); + return false; + } + + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( Color( 64, 128, 255, 255 ), ( bNot ) ? ( "\t!( [\"%s\"]->IsInstanceActive() " ) : ( "\t( [\"%s\"]->IsInstanceActive() " ), pchParamName->String() ); + ConColorMsg( Color( 255, 255, 255, 255 ), "\"%s\"", (pLesson->IsInstanceActive() ? "true" : "false") ); + ConColorMsg( Color( 64, 128, 255, 255 ), " )\n" ); + } + + return ( bNot ) ? ( !pLesson->IsInstanceActive() ) : ( pLesson->IsInstanceActive() ); + } + + case LESSON_ACTION_SET: + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\tQ_strcpy([%s], [%s] ", pchVarName, pchParamName->String() ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "\"%s\"", pchParam ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ")\n" ); + } + + *pchVar = pchParam; + return true; + + case LESSON_ACTION_ADD: + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\tQ_strcat([%s], [%s] ", pchVarName, pchParamName->String() ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "\"%s\"", pchParam ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ")\n" ); + } + + char szTemp[ 256 ]; + Q_strncpy( szTemp, pchVar->String(), sizeof( szTemp ) ); + Q_strncat( szTemp, pchParam, sizeof( szTemp ) ); + + *pchVar = szTemp; + return true; + + case LESSON_ACTION_IS: + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\tQ_strcmp([%s] ", pchVarName ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "\"%s\"", pchVar->String() ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ", [%s] ", pchParamName->String() ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "\"%s\"", pchParam ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ( bNot ) ? ( ") != 0\n" ) : ( ") == 0\n" ) ); + } + + return ( bNot ) ? ( Q_strcmp( pchVar->String(), pchParam ) != 0 ) : ( Q_strcmp( pchVar->String(), pchParam ) == 0 ); + + case LESSON_ACTION_HAS_PREFIX: + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\tStringHasPrefix([%s] ", pchVarName ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "\"%s\"", pchVar->String() ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ", [%s] ", pchParamName->String() ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "\"%s\"", pchParam ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ( bNot ) ? ( ") == false\n" ) : ( ") == true\n" ) ); + } + + return ( bNot ) ? ( !StringHasPrefix( pchVar->String(), pchParam ) ) : ( StringHasPrefix( pchVar->String(), pchParam ) ); + + case LESSON_ACTION_LESS_THAN: + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\tQ_strcmp([%s] ", pchVarName ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\"%s\"", pchVar->String() ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ", [%s] ", pchParamName->String() ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\"%s\"", pchParam ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ( bNot ) ? ( ") >= 0\n" ) : ( ") < 0\n" ) ); + } + + return ( bNot ) ? ( Q_strcmp( pchVar->String(), pchParam ) >= 0 ) : ( Q_strcmp( pchVar->String(), pchParam ) < 0 ); + } + + DevWarning( "Invalid lesson action type used with \"%s\" variable type.\n", pchVarName ); + + return false; +} + +LessonEvent_t * CScriptedIconLesson::AddOpenEvent( void ) +{ + int iNewLessonEvent = m_OpenEvents.AddToTail(); + return &(m_OpenEvents[ iNewLessonEvent ]); +} + +LessonEvent_t * CScriptedIconLesson::AddCloseEvent( void ) +{ + int iNewLessonEvent = m_CloseEvents.AddToTail(); + return &(m_CloseEvents[ iNewLessonEvent ]); +} + +LessonEvent_t * CScriptedIconLesson::AddSuccessEvent( void ) +{ + int iNewLessonEvent = m_SuccessEvents.AddToTail(); + return &(m_SuccessEvents[ iNewLessonEvent ]); +} + +LessonEvent_t * CScriptedIconLesson::AddOnOpenEvent( void ) +{ + int iNewLessonEvent = m_OnOpenEvents.AddToTail(); + return &(m_OnOpenEvents[ iNewLessonEvent ]); +} + +LessonEvent_t * CScriptedIconLesson::AddUpdateEvent( void ) +{ + int iNewLessonEvent = m_UpdateEvents.AddToTail(); + return &(m_UpdateEvents[ iNewLessonEvent ]); +} + +// Static method to init the keyvalues symbols used for comparisons +void CScriptedIconLesson::PreReadLessonsFromFile() +{ + static bool bFirstTime = true; + if ( !bFirstTime ) + return; + bFirstTime = false; + + // Run init info call macros on all scriptable variables (see: LESSON_VARIABLE_FACTORY definition) +#define LESSON_VARIABLE_MACRO LESSON_VARIABLE_INIT_SYMBOL +#define LESSON_VARIABLE_MACRO_BOOL LESSON_VARIABLE_INIT_SYMBOL +#define LESSON_VARIABLE_MACRO_EHANDLE LESSON_VARIABLE_INIT_SYMBOL +#define LESSON_VARIABLE_MACRO_STRING LESSON_VARIABLE_INIT_SYMBOL + LESSON_VARIABLE_FACTORY +#undef LESSON_VARIABLE_MACRO +#undef LESSON_VARIABLE_MACRO_BOOL +#undef LESSON_VARIABLE_MACRO_EHANDLE +#undef LESSON_VARIABLE_MACRO_STRING + + // And build the map of variable name to enum + // Run string to int macros on all scriptable variables (see: LESSON_VARIABLE_FACTORY definition) +#define LESSON_VARIABLE_MACRO LESSON_SCRIPT_STRING_ADD_TO_MAP +#define LESSON_VARIABLE_MACRO_BOOL LESSON_SCRIPT_STRING_ADD_TO_MAP +#define LESSON_VARIABLE_MACRO_EHANDLE LESSON_SCRIPT_STRING_ADD_TO_MAP +#define LESSON_VARIABLE_MACRO_STRING LESSON_SCRIPT_STRING_ADD_TO_MAP + LESSON_VARIABLE_FACTORY +#undef LESSON_VARIABLE_MACRO +#undef LESSON_VARIABLE_MACRO_BOOL +#undef LESSON_VARIABLE_MACRO_EHANDLE +#undef LESSON_VARIABLE_MACRO_STRING + + // Set up mapping of field types + g_TypeToParamTypeMap.Insert( "float", FIELD_FLOAT ); + g_TypeToParamTypeMap.Insert( "string", FIELD_STRING ); + g_TypeToParamTypeMap.Insert( "int", FIELD_INTEGER ); + g_TypeToParamTypeMap.Insert( "integer", FIELD_INTEGER ); + g_TypeToParamTypeMap.Insert( "short", FIELD_INTEGER ); + g_TypeToParamTypeMap.Insert( "long", FIELD_INTEGER ); + g_TypeToParamTypeMap.Insert( "bool", FIELD_BOOLEAN ); + g_TypeToParamTypeMap.Insert( "player", FIELD_CUSTOM ); + g_TypeToParamTypeMap.Insert( "entity", FIELD_EHANDLE ); + g_TypeToParamTypeMap.Insert( "convar", FIELD_EMBEDDED ); + g_TypeToParamTypeMap.Insert( "void", FIELD_VOID ); + + // Set up the lesson action map + + CScriptedIconLesson::LessonActionMap.Insert( "scope in", LESSON_ACTION_SCOPE_IN ); + CScriptedIconLesson::LessonActionMap.Insert( "scope out", LESSON_ACTION_SCOPE_OUT ); + CScriptedIconLesson::LessonActionMap.Insert( "close", LESSON_ACTION_CLOSE ); + CScriptedIconLesson::LessonActionMap.Insert( "success", LESSON_ACTION_SUCCESS ); + CScriptedIconLesson::LessonActionMap.Insert( "lock", LESSON_ACTION_LOCK ); + CScriptedIconLesson::LessonActionMap.Insert( "present complete", LESSON_ACTION_PRESENT_COMPLETE ); + CScriptedIconLesson::LessonActionMap.Insert( "present start", LESSON_ACTION_PRESENT_START ); + CScriptedIconLesson::LessonActionMap.Insert( "present end", LESSON_ACTION_PRESENT_END ); + + CScriptedIconLesson::LessonActionMap.Insert( "reference open", LESSON_ACTION_REFERENCE_OPEN ); + + CScriptedIconLesson::LessonActionMap.Insert( "set", LESSON_ACTION_SET ); + CScriptedIconLesson::LessonActionMap.Insert( "add", LESSON_ACTION_ADD ); + CScriptedIconLesson::LessonActionMap.Insert( "subtract", LESSON_ACTION_SUBTRACT ); + CScriptedIconLesson::LessonActionMap.Insert( "multiply", LESSON_ACTION_MULTIPLY ); + CScriptedIconLesson::LessonActionMap.Insert( "is", LESSON_ACTION_IS ); + CScriptedIconLesson::LessonActionMap.Insert( "less than", LESSON_ACTION_LESS_THAN ); + CScriptedIconLesson::LessonActionMap.Insert( "has prefix", LESSON_ACTION_HAS_PREFIX ); + CScriptedIconLesson::LessonActionMap.Insert( "has bit", LESSON_ACTION_HAS_BIT ); + CScriptedIconLesson::LessonActionMap.Insert( "bit count is", LESSON_ACTION_BIT_COUNT_IS ); + CScriptedIconLesson::LessonActionMap.Insert( "bit count less than", LESSON_ACTION_BIT_COUNT_LESS_THAN ); + + CScriptedIconLesson::LessonActionMap.Insert( "get distance", LESSON_ACTION_GET_DISTANCE ); + CScriptedIconLesson::LessonActionMap.Insert( "get angular distance", LESSON_ACTION_GET_ANGULAR_DISTANCE ); + CScriptedIconLesson::LessonActionMap.Insert( "get player display name", LESSON_ACTION_GET_PLAYER_DISPLAY_NAME ); + CScriptedIconLesson::LessonActionMap.Insert( "classname is", LESSON_ACTION_CLASSNAME_IS ); + CScriptedIconLesson::LessonActionMap.Insert( "modelname is", LESSON_ACTION_MODELNAME_IS ); + CScriptedIconLesson::LessonActionMap.Insert( "team is", LESSON_ACTION_TEAM_IS ); + CScriptedIconLesson::LessonActionMap.Insert( "health less than", LESSON_ACTION_HEALTH_LESS_THAN ); + CScriptedIconLesson::LessonActionMap.Insert( "health percentage less than", LESSON_ACTION_HEALTH_PERCENTAGE_LESS_THAN ); + CScriptedIconLesson::LessonActionMap.Insert( "get active weapon", LESSON_ACTION_GET_ACTIVE_WEAPON ); + CScriptedIconLesson::LessonActionMap.Insert( "weapon is", LESSON_ACTION_WEAPON_IS ); + CScriptedIconLesson::LessonActionMap.Insert( "weapon has", LESSON_ACTION_WEAPON_HAS ); + CScriptedIconLesson::LessonActionMap.Insert( "get active weapon slot", LESSON_ACTION_GET_ACTIVE_WEAPON_SLOT ); + CScriptedIconLesson::LessonActionMap.Insert( "get weapon slot", LESSON_ACTION_GET_WEAPON_SLOT ); + CScriptedIconLesson::LessonActionMap.Insert( "get weapon in slot", LESSON_ACTION_GET_WEAPON_IN_SLOT ); + CScriptedIconLesson::LessonActionMap.Insert( "clip percentage less than", LESSON_ACTION_CLIP_PERCENTAGE_LESS_THAN); + CScriptedIconLesson::LessonActionMap.Insert( "weapon ammo low", LESSON_ACTION_WEAPON_AMMO_LOW ); + CScriptedIconLesson::LessonActionMap.Insert( "weapon ammo full", LESSON_ACTION_WEAPON_AMMO_FULL ); + CScriptedIconLesson::LessonActionMap.Insert( "weapon ammo empty", LESSON_ACTION_WEAPON_AMMO_EMPTY ); + CScriptedIconLesson::LessonActionMap.Insert( "weapon can use", LESSON_ACTION_WEAPON_CAN_USE ); + CScriptedIconLesson::LessonActionMap.Insert( "use target is", LESSON_ACTION_USE_TARGET_IS ); + CScriptedIconLesson::LessonActionMap.Insert( "get use target", LESSON_ACTION_GET_USE_TARGET ); + CScriptedIconLesson::LessonActionMap.Insert( "get potential use target", LESSON_ACTION_GET_POTENTIAL_USE_TARGET ); + + // Add mod actions to the map + Mod_PreReadLessonsFromFile(); +} diff --git a/game/client/c_baselesson.h b/game/client/c_baselesson.h new file mode 100644 index 000000000..beb0b8953 --- /dev/null +++ b/game/client/c_baselesson.h @@ -0,0 +1,446 @@ +//========= Copyright © 1996-2008, Valve Corporation, All rights reserved. ============// +// +// Purpose: Client handler for instruction players how to play +// +//=============================================================================// + +#ifndef _C_BASELESSON_H_ +#define _C_BASELESSON_H_ + + +#include "GameEventListener.h" +#include "hud_locator_target.h" + + +#define DECLARE_LESSON( _lessonClassName, _baseLessonClassName ) \ + typedef _baseLessonClassName BaseClass;\ + typedef _lessonClassName ThisClass;\ + _lessonClassName( const char *pchName, bool bIsDefaultHolder, bool bIsOpenOpportunity, int nSplitScreenSlot )\ + : _baseLessonClassName( pchName, bIsDefaultHolder, bIsOpenOpportunity, nSplitScreenSlot )\ + {\ + Init();\ + } + + +enum LessonInstanceType +{ + LESSON_INSTANCE_MULTIPLE, + LESSON_INSTANCE_SINGLE_OPEN, + LESSON_INSTANCE_FIXED_REPLACE, + LESSON_INSTANCE_SINGLE_ACTIVE, + + LESSON_INSTANCE_TYPE_TOTAL +}; + + +// This is used to solve a problem where bots can take the place of a player, where on or the other don't have valid entities on the client at the same time +#define MAX_DELAYED_PLAYER_SWAPS 8 + +struct delayed_player_swap_t +{ + CHandle *phHandleToChange; + int iNewUserID; + + delayed_player_swap_t( void ) + { + phHandleToChange = NULL; + iNewUserID = -1; + } +}; + + +abstract_class CBaseLesson : public CGameEventListener +{ +public: + CBaseLesson( const char *pchName, bool bIsDefaultHolder, bool bIsOpenOpportunity, int nSplitScreenSlot ); + virtual ~CBaseLesson( void ); + + void AddPrerequisite( const char *pchLessonName ); + + const CGameInstructorSymbol& GetNameSymbol( void ) const { return m_stringName; } + const char * GetName( void ) const { return m_stringName.String(); } + int GetPriority( void ) const { return m_iPriority; } + const char * GetCloseReason( void ) const { return m_stringCloseReason.String(); } + void SetCloseReason( const char *pchReason ) { m_stringCloseReason = pchReason; } + + CBaseLesson* GetRoot( void ) const { return m_pRoot; } + void SetRoot( CBaseLesson *pRoot ); + const CUtlVector < CBaseLesson * >* GetChildren( void ) const { return &m_OpenOpportunities; } + + float GetInitTime( void ) { return m_fInitTime; } + void SetStartTime( void ) { m_fStartTime = gpGlobals->curtime; } + void ResetStartTime( void ) { m_fStartTime = 0.0f; m_bHasPlayedSound = false; } + + bool ShouldShowSpew( void ); + bool NoPriority( void ) const; + bool IsDefaultHolder( void ) const { return m_bIsDefaultHolder; } + bool IsOpenOpportunity( void ) const { return m_bIsOpenOpportunity; } + bool IsLocked( void ) const; + bool CanOpenWhenDead( void ) const { return m_bCanOpenWhenDead; } + bool IsInstructing( void ) const { return ( m_fStartTime > 0.0f ); } + bool IsLearned( void ) const; + bool PrerequisitesHaveBeenMet( void ) const; + bool IsTimedOut( void ); + + int InstanceType( void ) const { return m_iInstanceType; } + const CGameInstructorSymbol& GetReplaceKeySymbol( void ) const { return m_stringReplaceKey; } + const char* GetReplaceKey( void ) const { return m_stringReplaceKey.String(); } + int GetFixedInstancesMax( void ) const { return m_iFixedInstancesMax; } + bool ShouldReplaceOnlyWhenStopped( void ) const { return m_bReplaceOnlyWhenStopped; } + void SetInstanceActive( bool bInstanceActive ) { m_bInstanceActive = bInstanceActive; } + bool IsInstanceActive( void ) const { return m_bInstanceActive; } + + void ResetDisplaysAndSuccesses( void ); + bool IncDisplayCount( void ); + bool IncSuccessCount( void ); + void SetDisplayCount( int iDisplayCount ) { m_iDisplayCount = iDisplayCount; } + void SetSuccessCount( int iSuccessCount ) { m_iSuccessCount = iSuccessCount; } + int GetDisplayCount( void ) const { return m_iDisplayCount; } + int GetSuccessCount( void ) const { return m_iSuccessCount; } + int GetDisplayLimit( void ) const { return m_iDisplayLimit; } + int GetSuccessLimit( void ) const { return m_iSuccessLimit; } + + void Init( void ); // NOT virtual, each constructor calls their own + virtual void InitPrerequisites( void ) {}; + virtual void Start( void ) = 0; + virtual void Stop( void ) = 0; + virtual void OnOpen( void ) {}; + virtual void Update( void ) {}; + virtual void UpdateInactive( void ) {}; + + virtual bool ShouldDisplay( void ) const { return true; } + virtual bool IsVisible( void ) const { return true; } + virtual bool WasDisplayed( void ) const { return m_bWasDisplayed ? true : false; } + virtual void SwapOutPlayers( int iOldUserID, int iNewUserID ) {} + virtual void TakePlaceOf( CBaseLesson *pLesson ); + + int GetSplitScreenSlot() const { return m_nSplitScreenSlot; } + + const char *GetGroup() { return m_szLessonGroup.String(); } + void SetEnabled( bool bEnabled ) { m_bDisabled = !bEnabled; } + +protected: + void MarkSucceeded( void ); + void CloseOpportunity( const char *pchReason ); + bool DoDelayedPlayerSwaps( void ) const; + +private: + + CBaseLesson *m_pRoot; + CUtlVector < CBaseLesson * > m_OpenOpportunities; + CUtlVector < const CBaseLesson * > m_Prerequisites; + + CGameInstructorSymbol m_stringCloseReason; + CGameInstructorSymbol m_stringName; + + bool m_bInstanceActive : 1; + bool m_bSuccessCounted : 1; + bool m_bIsDefaultHolder : 1; + bool m_bIsOpenOpportunity : 1; + +protected: + LessonInstanceType m_iInstanceType; + + int m_iPriority; + CGameInstructorSymbol m_stringReplaceKey; + int m_iFixedInstancesMax; + bool m_bReplaceOnlyWhenStopped; + int m_iTeam; + bool m_bOnlyKeyboard; + bool m_bOnlyGamepad; + + int m_iDisplayLimit; + int m_iDisplayCount; + bool m_bWasDisplayed; + int m_iSuccessLimit; + int m_iSuccessCount; + int m_nSplitScreenSlot; + + float m_fLockDuration; + float m_fTimeout; + float m_fInitTime; + float m_fStartTime; + float m_fLockTime; + float m_fUpdateInterval; + bool m_bHasPlayedSound; + + CGameInstructorSymbol m_szStartSound; + CGameInstructorSymbol m_szLessonGroup; + + bool m_bCanOpenWhenDead; + bool m_bBumpWithTimeoutWhenLearned; + bool m_bCanTimeoutWhileInactive; + bool m_bDisabled; + + // Right now we can only queue up 4 swaps... + // this number can be increased if more entity handle scripted variables are added + mutable delayed_player_swap_t m_pDelayedPlayerSwap[ MAX_DELAYED_PLAYER_SWAPS ]; + mutable int m_iNumDelayedPlayerSwaps; + +public: + + // Colors for console spew in verbose mode + static Color m_rgbaVerboseHeader; + static Color m_rgbaVerbosePlain; + static Color m_rgbaVerboseName; + static Color m_rgbaVerboseOpen; + static Color m_rgbaVerboseClose; + static Color m_rgbaVerboseSuccess; + static Color m_rgbaVerboseUpdate; +}; + + +class CTextLesson : public CBaseLesson +{ +public: + DECLARE_LESSON( CTextLesson, CBaseLesson ); + + void Init( void ); // NOT virtual, each constructor calls their own + virtual void Start( void ); + virtual void Stop( void ); + +protected: + + CGameInstructorSymbol m_szDisplayText; + CGameInstructorSymbol m_szDisplayParamText; + CGameInstructorSymbol m_szBinding; + CGameInstructorSymbol m_szGamepadBinding; +}; + + +class CIconLesson : public CTextLesson +{ +public: + DECLARE_LESSON( CIconLesson, CTextLesson ); + + void Init( void ); // NOT virtual, each constructor calls their own + virtual void Start( void ); + virtual void Stop( void ); + virtual void Update( void ); + virtual void UpdateInactive( void ); + + virtual bool ShouldDisplay( void ) const; + virtual bool IsVisible( void ) const; + virtual void SwapOutPlayers( int iOldUserID, int iNewUserID ); + virtual void TakePlaceOf( CBaseLesson *pLesson ); + + void SetLocatorBinding( CLocatorTarget * pLocatorTarget ); + + const char *GetCaptionColorString() { return m_szCaptionColor.String(); } + + bool IsPresentComplete( void ); + void PresentStart( void ); + void PresentEnd( void ); + +private: + virtual void UpdateLocatorTarget( CLocatorTarget *pLocatorTarget, C_BaseEntity *pIconTarget ); + +protected: + CHandle m_hIconTarget; + CGameInstructorSymbol m_szVguiTargetName; + CGameInstructorSymbol m_szVguiTargetLookup; + int m_nVguiTargetEdge; + float m_flUpOffset; + float m_flRelativeUpOffset; + float m_fFixedPositionX; + float m_fFixedPositionY; + + int m_hLocatorTarget; + int m_iFlags; + + float m_fRange; + float m_fCurrentDistance; + float m_fOnScreenStartTime; + float m_fUpdateDistanceTime; + + CGameInstructorSymbol m_szOnscreenIcon; + CGameInstructorSymbol m_szOffscreenIcon; + CGameInstructorSymbol m_szCaptionColor; + + bool m_bFixedPosition; + bool m_bNoIconTarget; + bool m_bAllowNodrawTarget; + bool m_bVisible; + bool m_bShowWhenOccluded; + bool m_bNoOffscreen; + bool m_bForceCaption; +}; + +enum LessonAction +{ + LESSON_ACTION_NONE, + + LESSON_ACTION_SCOPE_IN, + LESSON_ACTION_SCOPE_OUT, + LESSON_ACTION_CLOSE, + LESSON_ACTION_SUCCESS, + LESSON_ACTION_LOCK, + LESSON_ACTION_PRESENT_COMPLETE, + LESSON_ACTION_PRESENT_START, + LESSON_ACTION_PRESENT_END, + + LESSON_ACTION_REFERENCE_OPEN, + + LESSON_ACTION_SET, + LESSON_ACTION_ADD, + LESSON_ACTION_SUBTRACT, + LESSON_ACTION_MULTIPLY, + LESSON_ACTION_IS, + LESSON_ACTION_LESS_THAN, + LESSON_ACTION_HAS_PREFIX, + LESSON_ACTION_HAS_BIT, + LESSON_ACTION_BIT_COUNT_IS, + LESSON_ACTION_BIT_COUNT_LESS_THAN, + + LESSON_ACTION_GET_DISTANCE, + LESSON_ACTION_GET_ANGULAR_DISTANCE, + LESSON_ACTION_GET_PLAYER_DISPLAY_NAME, + LESSON_ACTION_CLASSNAME_IS, + LESSON_ACTION_MODELNAME_IS, + LESSON_ACTION_TEAM_IS, + LESSON_ACTION_HEALTH_LESS_THAN, + LESSON_ACTION_HEALTH_PERCENTAGE_LESS_THAN, + LESSON_ACTION_GET_ACTIVE_WEAPON, + LESSON_ACTION_WEAPON_IS, + LESSON_ACTION_WEAPON_HAS, + LESSON_ACTION_GET_ACTIVE_WEAPON_SLOT, + LESSON_ACTION_GET_WEAPON_SLOT, + LESSON_ACTION_GET_WEAPON_IN_SLOT, + LESSON_ACTION_CLIP_PERCENTAGE_LESS_THAN, + LESSON_ACTION_WEAPON_AMMO_LOW, + LESSON_ACTION_WEAPON_AMMO_FULL, + LESSON_ACTION_WEAPON_AMMO_EMPTY, + LESSON_ACTION_WEAPON_CAN_USE, + LESSON_ACTION_USE_TARGET_IS, + LESSON_ACTION_GET_USE_TARGET, + LESSON_ACTION_GET_POTENTIAL_USE_TARGET, + + // Enum continued in Mod_LessonAction + LESSON_ACTION_MOD_START, +}; + +struct LessonElement_t +{ + int iVariable; + int iParamVarIndex; + int iAction; + _fieldtypes paramType; + CGameInstructorSymbol szParam; + bool bNot : 1; + bool bOptionalParam : 1; + + LessonElement_t( int p_iVariable, int p_iAction, bool p_bNot, bool p_bOptionalParam, const char *pchParam, int p_iParamVarIndex, _fieldtypes p_paramType ) + { + iVariable = p_iVariable; + iAction = p_iAction; + bNot = p_bNot; + bOptionalParam = p_bOptionalParam; + szParam = pchParam; + iParamVarIndex = p_iParamVarIndex; + paramType = p_paramType; + } + + LessonElement_t( const LessonElement_t &p_LessonElement ) + { + iVariable = p_LessonElement.iVariable; + iAction = p_LessonElement.iAction; + bNot = p_LessonElement.bNot; + bOptionalParam = p_LessonElement.bOptionalParam; + szParam = p_LessonElement.szParam; + iParamVarIndex = p_LessonElement.iParamVarIndex; + paramType = p_LessonElement.paramType; + } +}; + +struct LessonEvent_t +{ + CUtlVector< LessonElement_t > elements; + CGameInstructorSymbol szEventName; +}; + +class CScriptedIconLesson : public CIconLesson +{ +public: + DECLARE_LESSON( CScriptedIconLesson, CIconLesson ) + + virtual ~CScriptedIconLesson( void ); + + static void PreReadLessonsFromFile( void ); + static void Mod_PreReadLessonsFromFile( void ); + + void Init( void ); // NOT virtual, each constructor calls their own + virtual void InitPrerequisites( void ); + virtual void OnOpen( void ); + virtual void Update( void ); + + virtual void SwapOutPlayers( int iOldUserID, int iNewUserID ); + + virtual void FireGameEvent( IGameEvent *event ); + virtual void ProcessOpenGameEvents( const CScriptedIconLesson *pRootLesson, const char *name, IGameEvent *event ); + virtual void ProcessCloseGameEvents( const CScriptedIconLesson *pRootLesson, const char *name, IGameEvent *event ); + virtual void ProcessSuccessGameEvents( const CScriptedIconLesson *pRootLesson, const char *name, IGameEvent *event ); + + CUtlVector< LessonEvent_t >& GetOpenEvents( void ) { return m_OpenEvents; } + CUtlVector< LessonEvent_t >& GetCloseEvents( void ) { return m_CloseEvents; } + CUtlVector< LessonEvent_t >& GetSuccessEvents( void ) { return m_SuccessEvents; } + CUtlVector< LessonEvent_t >& GetOnOpenEvents( void ) { return m_OnOpenEvents; } + CUtlVector< LessonEvent_t >& GetUpdateEvents( void ) { return m_UpdateEvents; } + + bool ProcessElements( IGameEvent *event, const CUtlVector< LessonElement_t > *pElements ); + +private: + void InitElementsFromKeys( CUtlVector< LessonElement_t > *pLessonElements, KeyValues *pKey ); + void InitElementsFromElements( CUtlVector< LessonElement_t > *pLessonElements, const CUtlVector< LessonElement_t > *pLessonElements2 ); + + void InitFromKeys( KeyValues *pKey ); + + bool ProcessElement( IGameEvent *event, const LessonElement_t *pLessonElement, bool bInFailedScope ); + + bool ProcessElementAction( int iAction, bool bNot, const char *pchVarName, float &bVar, const CGameInstructorSymbol *pchParamName, float fParam ); + bool ProcessElementAction( int iAction, bool bNot, const char *pchVarName, int &bVar, const CGameInstructorSymbol *pchParamName, float fParam ); + bool ProcessElementAction( int iAction, bool bNot, const char *pchVarName, bool &bVar, const CGameInstructorSymbol *pchParamName, float fParam ); + bool ProcessElementAction( int iAction, bool bNot, const char *pchVarName, EHANDLE &hVar, const CGameInstructorSymbol *pchParamName, float fParam, C_BaseEntity *pParam, const char *pchParam ); + bool ProcessElementAction( int iAction, bool bNot, const char *pchVarName, CGameInstructorSymbol *pchVar, const CGameInstructorSymbol *pchParamName, const char *pchParam ); + + // Implemented per mod so they can have custom actions + bool Mod_ProcessElementAction( int iAction, bool bNot, const char *pchVarName, EHANDLE &hVar, const CGameInstructorSymbol *pchParamName, float fParam, C_BaseEntity *pParam, const char *pchParam, bool &bModHandled ); + + LessonEvent_t * AddOpenEvent( void ); + LessonEvent_t * AddCloseEvent( void ); + LessonEvent_t * AddSuccessEvent( void ); + LessonEvent_t * AddOnOpenEvent( void ); + LessonEvent_t * AddUpdateEvent( void ); + +private: + static CUtlDict< int, int > CScriptedIconLesson::LessonActionMap; + + EHANDLE m_hLocalPlayer; + float m_fOutput; + CHandle m_hEntity1; + CHandle m_hEntity2; + CGameInstructorSymbol m_szString1; + CGameInstructorSymbol m_szString2; + int m_iInteger1; + int m_iInteger2; + float m_fFloat1; + float m_fFloat2; + + CUtlVector< CGameInstructorSymbol > m_PrerequisiteNames; + CUtlVector< LessonEvent_t > m_OpenEvents; + CUtlVector< LessonEvent_t > m_CloseEvents; + CUtlVector< LessonEvent_t > m_SuccessEvents; + CUtlVector< LessonEvent_t > m_OnOpenEvents; + CUtlVector< LessonEvent_t > m_UpdateEvents; + + float m_fUpdateEventTime; + CScriptedIconLesson *m_pDefaultHolder; + + int m_iScopeDepth; + + // Need this to get offsets to scripted variables + friend class LessonVariableInfo; + friend int LessonActionFromString( const char *pchName ); +}; + + +#endif // _C_BASELESSON_H_ diff --git a/game/client/c_baseplayer.cpp b/game/client/c_baseplayer.cpp index 9b3b8c8c0..4554d4b96 100644 --- a/game/client/c_baseplayer.cpp +++ b/game/client/c_baseplayer.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//====== Copyright � 1996-2005, Valve Corporation, All rights reserved. =====// // // Purpose: Client-side CBasePlayer. // @@ -12,6 +12,7 @@ #include "history_resource.h" #include "iinput.h" #include "input.h" +#include "ammodef.h" #include "view.h" #include "iviewrender.h" #include "iclientmode.h" @@ -31,31 +32,24 @@ #include "particles_simple.h" #include "fx_water.h" #include "hltvcamera.h" +#if defined( REPLAY_ENABLED ) +#include "replaycamera.h" +#endif #include "toolframework/itoolframework.h" #include "toolframework_client.h" #include "view_scene.h" #include "c_vguiscreen.h" #include "datacache/imdlcache.h" -#include "vgui/ISurface.h" +#include "vgui/isurface.h" #include "voice_status.h" #include "fx.h" -#include "dt_utlvector_recv.h" -#include "cam_thirdperson.h" -#if defined( REPLAY_ENABLED ) -#include "replay/replaycamera.h" -#include "replay/ireplaysystem.h" -#include "replay/ienginereplay.h" -#endif -#include "steam/steam_api.h" -#include "sourcevr/isourcevirtualreality.h" -#include "client_virtualreality.h" +#include "cellcoord.h" -#if defined USES_ECON_ITEMS -#include "econ_wearable.h" -#endif +#include "debugoverlay_shared.h" -// NVNT haptics system interface -#include "haptics/ihaptics.h" +#ifdef DEMOPOLISH_ENABLED +#include "demo_polish/demo_polish.h" +#endif // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -70,6 +64,7 @@ int g_nKillCamTarget1 = 0; int g_nKillCamTarget2 = 0; extern ConVar mp_forcecamera; // in gamevars_shared.h +extern ConVar r_mapextents; #define FLASHLIGHT_DISTANCE 1000 #define MAX_VGUI_INPUT_MODE_SPEED 30 @@ -81,13 +76,11 @@ static Vector WALL_MAX(WALL_OFFSET,WALL_OFFSET,WALL_OFFSET); bool CommentaryModeShouldSwallowInput( C_BasePlayer *pPlayer ); extern ConVar default_fov; -#ifndef _XBOX extern ConVar sensitivity; -#endif -static C_BasePlayer *s_pLocalPlayer = NULL; +static C_BasePlayer *s_pLocalPlayer[ MAX_SPLITSCREEN_PLAYERS ]; -static ConVar cl_customsounds ( "cl_customsounds", "1", 0, "Enable customized player sound playback" ); +static ConVar cl_customsounds ( "cl_customsounds", "0", 0, "Enable customized player sound playback" ); static ConVar spec_track ( "spec_track", "0", 0, "Tracks an entity in spec mode" ); static ConVar cl_smooth ( "cl_smooth", "1", 0, "Smooth view/eye origin after prediction errors" ); static ConVar cl_smoothtime ( @@ -99,35 +92,12 @@ static ConVar cl_smoothtime ( true, 2.0 ); -#ifdef CSTRIKE_DLL -ConVar spec_freeze_time( "spec_freeze_time", "5.0", FCVAR_CHEAT | FCVAR_REPLICATED, "Time spend frozen in observer freeze cam." ); -ConVar spec_freeze_traveltime( "spec_freeze_traveltime", "0.7", FCVAR_CHEAT | FCVAR_REPLICATED, "Time taken to zoom in to frame a target in observer freeze cam.", true, 0.01, false, 0 ); -ConVar spec_freeze_distance_min( "spec_freeze_distance_min", "80", FCVAR_CHEAT, "Minimum random distance from the target to stop when framing them in observer freeze cam." ); -ConVar spec_freeze_distance_max( "spec_freeze_distance_max", "90", FCVAR_CHEAT, "Maximum random distance from the target to stop when framing them in observer freeze cam." ); -#else ConVar spec_freeze_time( "spec_freeze_time", "4.0", FCVAR_CHEAT | FCVAR_REPLICATED, "Time spend frozen in observer freeze cam." ); ConVar spec_freeze_traveltime( "spec_freeze_traveltime", "0.4", FCVAR_CHEAT | FCVAR_REPLICATED, "Time taken to zoom in to frame a target in observer freeze cam.", true, 0.01, false, 0 ); ConVar spec_freeze_distance_min( "spec_freeze_distance_min", "96", FCVAR_CHEAT, "Minimum random distance from the target to stop when framing them in observer freeze cam." ); ConVar spec_freeze_distance_max( "spec_freeze_distance_max", "200", FCVAR_CHEAT, "Maximum random distance from the target to stop when framing them in observer freeze cam." ); -#endif - -static ConVar cl_first_person_uses_world_model ( "cl_first_person_uses_world_model", "0", FCVAR_ARCHIVE, "Causes the third person model to be drawn instead of the view model" ); - -ConVar demo_fov_override( "demo_fov_override", "0", FCVAR_CLIENTDLL | FCVAR_DONTRECORD, "If nonzero, this value will be used to override FOV during demo playback." ); - -// This only needs to be approximate - it just controls the distance to the pivot-point of the head ("the neck") of the in-game character, not the player's real-world neck length. -// Ideally we would find this vector by subtracting the neutral-pose difference between the head bone (the pivot point) and the "eyes" attachment point. -// However, some characters don't have this attachment point, and finding the neutral pose is a pain. -// This value is found by hand, and a good value depends more on the in-game models than on actual human shapes. -ConVar cl_meathook_neck_pivot_ingame_up( "cl_meathook_neck_pivot_ingame_up", "7.0" ); -ConVar cl_meathook_neck_pivot_ingame_fwd( "cl_meathook_neck_pivot_ingame_fwd", "3.0" ); -void RecvProxy_LocalVelocityX( const CRecvProxyData *pData, void *pStruct, void *pOut ); -void RecvProxy_LocalVelocityY( const CRecvProxyData *pData, void *pStruct, void *pOut ); -void RecvProxy_LocalVelocityZ( const CRecvProxyData *pData, void *pStruct, void *pOut ); - -void RecvProxy_ObserverTarget( const CRecvProxyData *pData, void *pStruct, void *pOut ); -void RecvProxy_ObserverMode ( const CRecvProxyData *pData, void *pStruct, void *pOut ); +bool IsDemoPolishRecording(); // -------------------------------------------------------------------------------- // // RecvTable for CPlayerState. @@ -150,9 +120,9 @@ BEGIN_RECV_TABLE_NOBASE( CPlayerLocalData, DT_Local ) RecvPropInt (RECVINFO(m_bDucked)), RecvPropInt (RECVINFO(m_bDucking)), RecvPropInt (RECVINFO(m_bInDuckJump)), - RecvPropFloat (RECVINFO(m_flDucktime)), - RecvPropFloat (RECVINFO(m_flDuckJumpTime)), - RecvPropFloat (RECVINFO(m_flJumpTime)), + RecvPropInt (RECVINFO(m_nDuckTimeMsecs)), + RecvPropInt (RECVINFO(m_nDuckJumpTimeMsecs)), + RecvPropInt (RECVINFO(m_nJumpTimeMsecs)), RecvPropFloat (RECVINFO(m_flFallVelocity)), #if PREDICTION_ERROR_CHECK_LEVEL > 1 @@ -182,14 +152,12 @@ BEGIN_RECV_TABLE_NOBASE( CPlayerLocalData, DT_Local ) RecvPropInt( RECVINFO( m_skybox3d.fog.enable ) ), RecvPropInt( RECVINFO( m_skybox3d.fog.blend ) ), RecvPropVector( RECVINFO( m_skybox3d.fog.dirPrimary ) ), - RecvPropInt( RECVINFO( m_skybox3d.fog.colorPrimary ) ), - RecvPropInt( RECVINFO( m_skybox3d.fog.colorSecondary ) ), + RecvPropInt( RECVINFO( m_skybox3d.fog.colorPrimary ), 0, RecvProxy_Int32ToColor32 ), + RecvPropInt( RECVINFO( m_skybox3d.fog.colorSecondary ), 0, RecvProxy_Int32ToColor32 ), RecvPropFloat( RECVINFO( m_skybox3d.fog.start ) ), RecvPropFloat( RECVINFO( m_skybox3d.fog.end ) ), RecvPropFloat( RECVINFO( m_skybox3d.fog.maxdensity ) ), - - // fog data - RecvPropEHandle( RECVINFO( m_PlayerFog.m_hCtrl ) ), + RecvPropFloat( RECVINFO( m_skybox3d.fog.HDRColorScale ) ), // audio data RecvPropVector( RECVINFO( m_audio.localSound[0] ) ), @@ -202,7 +170,8 @@ BEGIN_RECV_TABLE_NOBASE( CPlayerLocalData, DT_Local ) RecvPropVector( RECVINFO( m_audio.localSound[7] ) ), RecvPropInt( RECVINFO( m_audio.soundscapeIndex ) ), RecvPropInt( RECVINFO( m_audio.localBits ) ), - RecvPropEHandle( RECVINFO( m_audio.ent ) ), + RecvPropInt( RECVINFO( m_audio.entIndex ) ), + END_RECV_TABLE() // -------------------------------------------------------------------------------- // @@ -226,11 +195,10 @@ END_RECV_TABLE() RecvPropInt ( RECVINFO( m_nNextThinkTick ) ), RecvPropEHandle ( RECVINFO( m_hLastWeapon ) ), - RecvPropEHandle ( RECVINFO( m_hGroundEntity ) ), - RecvPropFloat ( RECVINFO(m_vecVelocity[0]), 0, RecvProxy_LocalVelocityX ), - RecvPropFloat ( RECVINFO(m_vecVelocity[1]), 0, RecvProxy_LocalVelocityY ), - RecvPropFloat ( RECVINFO(m_vecVelocity[2]), 0, RecvProxy_LocalVelocityZ ), + RecvPropFloat ( RECVINFO(m_vecVelocity[0]), 0, C_BasePlayer::RecvProxy_LocalVelocityX ), + RecvPropFloat ( RECVINFO(m_vecVelocity[1]), 0, C_BasePlayer::RecvProxy_LocalVelocityY ), + RecvPropFloat ( RECVINFO(m_vecVelocity[2]), 0, C_BasePlayer::RecvProxy_LocalVelocityZ ), RecvPropVector ( RECVINFO( m_vecBaseVelocity ) ), @@ -239,32 +207,26 @@ END_RECV_TABLE() RecvPropFloat ( RECVINFO( m_flConstraintRadius )), RecvPropFloat ( RECVINFO( m_flConstraintWidth )), RecvPropFloat ( RECVINFO( m_flConstraintSpeedFactor )), + RecvPropBool ( RECVINFO( m_bConstraintPastRadius )), RecvPropFloat ( RECVINFO( m_flDeathTime )), RecvPropInt ( RECVINFO( m_nWaterLevel ) ), RecvPropFloat ( RECVINFO( m_flLaggedMovementValue )), + RecvPropEHandle ( RECVINFO( m_hTonemapController ) ), + END_RECV_TABLE() // -------------------------------------------------------------------------------- // // DT_BasePlayer datatable. // -------------------------------------------------------------------------------- // - -#if defined USES_ECON_ITEMS - EXTERN_RECV_TABLE(DT_AttributeList); -#endif - IMPLEMENT_CLIENTCLASS_DT(C_BasePlayer, DT_BasePlayer, CBasePlayer) // We have both the local and nonlocal data in here, but the server proxies // only send one. RecvPropDataTable( "localdata", 0, 0, &REFERENCE_RECV_TABLE(DT_LocalPlayerExclusive) ), -#if defined USES_ECON_ITEMS - RecvPropDataTable(RECVINFO_DT(m_AttributeList),0, &REFERENCE_RECV_TABLE(DT_AttributeList) ), -#endif - RecvPropDataTable(RECVINFO_DT(pl), 0, &REFERENCE_RECV_TABLE(DT_PlayerState), DataTableRecvProxy_StaticDataTable), RecvPropInt (RECVINFO(m_iFOV)), @@ -276,6 +238,9 @@ END_RECV_TABLE() RecvPropEHandle( RECVINFO(m_hVehicle) ), RecvPropEHandle( RECVINFO(m_hUseEntity) ), + RecvPropEHandle ( RECVINFO( m_hViewEntity ) ), // L4D: send view entity to everyone for first-person spectating + RecvPropEHandle ( RECVINFO( m_hGroundEntity ) ), + RecvPropInt (RECVINFO(m_iHealth)), RecvPropInt (RECVINFO(m_lifeState)), @@ -286,16 +251,22 @@ END_RECV_TABLE() RecvPropInt (RECVINFO(m_fFlags)), - RecvPropInt (RECVINFO(m_iObserverMode), 0, RecvProxy_ObserverMode ), - RecvPropEHandle (RECVINFO(m_hObserverTarget), RecvProxy_ObserverTarget ), + RecvPropInt (RECVINFO(m_iObserverMode), 0, C_BasePlayer::RecvProxy_ObserverMode ), + RecvPropEHandle (RECVINFO(m_hObserverTarget), C_BasePlayer::RecvProxy_ObserverTarget ), RecvPropArray ( RecvPropEHandle( RECVINFO( m_hViewModel[0] ) ), m_hViewModel ), RecvPropString( RECVINFO(m_szLastPlaceName) ), + RecvPropVector( RECVINFO(m_vecLadderNormal) ), + RecvPropInt (RECVINFO(m_ladderSurfaceProps) ), -#if defined USES_ECON_ITEMS - RecvPropUtlVector( RECVINFO_UTLVECTOR( m_hMyWearables ), MAX_WEARABLES_SENT_FROM_SERVER, RecvPropEHandle(NULL, 0, 0) ), -#endif + RecvPropInt( RECVINFO( m_ubEFNoInterpParity ) ), + + RecvPropEHandle( RECVINFO( m_hPostProcessCtrl ) ), // Send to everybody - for spectating + RecvPropEHandle( RECVINFO( m_hColorCorrectionCtrl ) ), // Send to everybody - for spectating + + // fog data + RecvPropEHandle( RECVINFO( m_PlayerFog.m_hCtrl ) ), END_RECV_TABLE() @@ -332,9 +303,9 @@ BEGIN_PREDICTION_DATA_NO_BASE( CPlayerLocalData ) DEFINE_PRED_FIELD( m_bDucked, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ), DEFINE_PRED_FIELD( m_bDucking, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ), DEFINE_PRED_FIELD( m_bInDuckJump, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ), - DEFINE_PRED_FIELD( m_flDucktime, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ), - DEFINE_PRED_FIELD( m_flDuckJumpTime, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ), - DEFINE_PRED_FIELD( m_flJumpTime, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_nDuckTimeMsecs, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_nDuckJumpTimeMsecs, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_nJumpTimeMsecs, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ), DEFINE_PRED_FIELD_TOL( m_flFallVelocity, FIELD_FLOAT, FTYPEDESC_INSENDTABLE, 0.5f ), // DEFINE_PRED_FIELD( m_nOldButtons, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ), DEFINE_FIELD( m_nOldButtons, FIELD_INTEGER ), @@ -371,6 +342,7 @@ BEGIN_PREDICTION_DATA( C_BasePlayer ) DEFINE_FIELD( m_flStepSoundTime, FIELD_FLOAT ), DEFINE_FIELD( m_flSwimSoundTime, FIELD_FLOAT ), DEFINE_FIELD( m_vecLadderNormal, FIELD_VECTOR ), + DEFINE_FIELD( m_ladderSurfaceProps, FIELD_INTEGER ), DEFINE_FIELD( m_flPhysics, FIELD_INTEGER ), DEFINE_AUTO_ARRAY( m_szAnimExtension, FIELD_CHARACTER ), DEFINE_FIELD( m_afButtonLast, FIELD_INTEGER ), @@ -396,8 +368,10 @@ BEGIN_PREDICTION_DATA( C_BasePlayer ) END_PREDICTION_DATA() + LINK_ENTITY_TO_CLASS( player, C_BasePlayer ); + // -------------------------------------------------------------------------------- // // Functions. // -------------------------------------------------------------------------------- // @@ -407,10 +381,15 @@ C_BasePlayer::C_BasePlayer() : m_iv_vecViewOffset( "C_BasePlayer::m_iv_vecViewOf #ifdef _DEBUG m_vecLadderNormal.Init(); + m_ladderSurfaceProps = 0; m_vecOldViewAngles.Init(); #endif + m_hViewEntity = NULL; - m_pFlashlight = NULL; + for ( int i = 0; i < MAX_SPLITSCREEN_PLAYERS; i++ ) + { + m_bFlashlightEnabled[ i ] = false; + } m_pCurrentVguiScreen = NULL; m_pCurrentCommand = NULL; @@ -430,14 +409,10 @@ C_BasePlayer::C_BasePlayer() : m_iv_vecViewOffset( "C_BasePlayer::m_iv_vecViewOf m_pSurfaceData = NULL; m_surfaceFriction = 1.0f; m_chTextureType = 0; + m_nSplitScreenSlot = -1; + m_bIsLocalPlayer = false; + m_afButtonForced = 0; - m_flNextAchievementAnnounceTime = 0; - - m_bFiredWeapon = false; - - m_nForceVisionFilterFlags = 0; - - ListenForGameEvent( "base_player_teleported" ); } //----------------------------------------------------------------------------- @@ -446,15 +421,25 @@ C_BasePlayer::C_BasePlayer() : m_iv_vecViewOffset( "C_BasePlayer::m_iv_vecViewOf C_BasePlayer::~C_BasePlayer() { DeactivateVguiScreen( m_pCurrentVguiScreen.Get() ); - if ( this == s_pLocalPlayer ) + for ( int i = 0; i < MAX_SPLITSCREEN_PLAYERS; ++i ) { - s_pLocalPlayer = NULL; - } + if ( this == s_pLocalPlayer[ i ] ) + { + s_pLocalPlayer[ i ] = NULL; + } + else if ( s_pLocalPlayer[ i ] ) + { + s_pLocalPlayer[ i ]->RemoveSplitScreenPlayer( this ); + } - delete m_pFlashlight; + if ( m_bFlashlightEnabled[ i ] ) + { + FlashlightEffectManager( i ).TurnOffFlashlight( true ); + m_bFlashlightEnabled[ i ] = false; + } + } } - //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- @@ -478,8 +463,6 @@ void C_BasePlayer::Spawn( void ) SharedSpawn(); m_bWasFreezeFraming = false; - - m_bFiredWeapon = false; } //----------------------------------------------------------------------------- @@ -490,30 +473,22 @@ bool C_BasePlayer::AudioStateIsUnderwater( Vector vecMainViewOrigin ) if ( IsObserver() ) { // Just check the view position - int cont = enginetrace->GetPointContents ( vecMainViewOrigin ); - return (cont & MASK_WATER); + int cont = enginetrace->GetPointContents_WorldOnly( vecMainViewOrigin, MASK_WATER ); + return (cont & MASK_WATER) ? true : false; } return ( GetWaterLevel() >= WL_Eyes ); } -bool C_BasePlayer::IsHLTV() const -{ - return ( IsLocalPlayer() && engine->IsHLTV() ); -} - +#if defined( REPLAY_ENABLED ) bool C_BasePlayer::IsReplay() const { -#if defined( REPLAY_ENABLED ) - return ( IsLocalPlayer() && g_pEngineClientReplay->IsPlayingReplayDemo() ); -#else - return false; -#endif + return ( IsLocalPlayer( const_cast< C_BasePlayer * >( this ) ) && engine->IsReplay() ); } +#endif -CBaseEntity *C_BasePlayer::GetObserverTarget() const // returns players target or NULL +CBaseEntity *C_BasePlayer::GetObserverTarget() const // returns players targer or NULL { -#ifndef _XBOX if ( IsHLTV() ) { return HLTVCamera()->GetPrimaryTarget(); @@ -523,7 +498,6 @@ CBaseEntity *C_BasePlayer::GetObserverTarget() const // returns players target o { return ReplayCamera()->GetPrimaryTarget(); } -#endif #endif if ( GetObserverMode() == OBS_MODE_ROAMING ) @@ -532,33 +506,23 @@ CBaseEntity *C_BasePlayer::GetObserverTarget() const // returns players target o } else { - if ( IsLocalPlayer() && UseVR() ) - { - // In VR mode, certain views cause disorientation and nausea. So let's not. - switch ( m_iObserverMode ) - { - case OBS_MODE_NONE: // not in spectator mode - case OBS_MODE_FIXED: // view from a fixed camera position - case OBS_MODE_IN_EYE: // follow a player in first person view - case OBS_MODE_CHASE: // follow a player in third person view - case OBS_MODE_ROAMING: // free roaming - return m_hObserverTarget; - break; - case OBS_MODE_DEATHCAM: // special mode for death cam animation - case OBS_MODE_FREEZECAM: // zooms to a target, and freeze-frames on them - // These are both terrible - they get overriden to chase, but here we change it to "chase" your own body (which will be ragdolled). - return (const_cast(this))->GetBaseEntity(); - break; - default: - assert ( false ); - break; - } - } - return m_hObserverTarget; } } +// Helper method to fix up visiblity across split screen for view models when observer target or mode changes +static void UpdateViewmodelVisibility( C_BasePlayer *player ) +{ + // Update view model visibility + for ( int i = 0; i < MAX_VIEWMODELS; i++ ) + { + CBaseViewModel *vm = player->GetViewModel( i ); + if ( !vm ) + continue; + vm->UpdateVisibility(); + } +} + // Called from Recv Proxy, mainly to reset tone map scale void C_BasePlayer::SetObserverTarget( EHANDLE hObserverTarget ) { @@ -580,40 +544,17 @@ void C_BasePlayer::SetObserverTarget( EHANDLE hObserverTarget ) gameeventmanager->FireEventClientSide( event ); } - if ( IsLocalPlayer() ) - { - ResetToneMapping(1.0); - } - // NVNT notify haptics of changed player - if ( haptics ) - haptics->OnPlayerChanged(); - - if ( IsLocalPlayer() ) - { - // On a change of viewing mode or target, we may want to reset both head and torso to point at the new target. - g_ClientVirtualReality.AlignTorsoAndViewToWeapon(); - } - } -} - - -void C_BasePlayer::SetObserverMode ( int iNewMode ) -{ - if ( m_iObserverMode != iNewMode ) - { - m_iObserverMode = iNewMode; - if ( IsLocalPlayer() ) + if ( IsLocalPlayer( this ) ) { - // On a change of viewing mode or target, we may want to reset both head and torso to point at the new target. - g_ClientVirtualReality.AlignTorsoAndViewToWeapon(); + ACTIVE_SPLITSCREEN_PLAYER_GUARD_ENT( this ); + ResetToneMapping( -1.0f ); // This forces the tonemapping scalar to the average of min and max } + UpdateViewmodelVisibility( this ); } } - int C_BasePlayer::GetObserverMode() const { -#ifndef _XBOX if ( IsHLTV() ) { return HLTVCamera()->GetMode(); @@ -623,44 +564,11 @@ int C_BasePlayer::GetObserverMode() const { return ReplayCamera()->GetMode(); } -#endif #endif - if ( IsLocalPlayer() && UseVR() ) - { - // IN VR mode, certain views cause disorientation and nausea. So let's not. - switch ( m_iObserverMode ) - { - case OBS_MODE_NONE: // not in spectator mode - case OBS_MODE_FIXED: // view from a fixed camera position - case OBS_MODE_IN_EYE: // follow a player in first person view - case OBS_MODE_CHASE: // follow a player in third person view - case OBS_MODE_ROAMING: // free roaming - return m_iObserverMode; - break; - case OBS_MODE_DEATHCAM: // special mode for death cam animation - case OBS_MODE_FREEZECAM: // zooms to a target, and freeze-frames on them - // These are both terrible - just do chase of your ragdoll. - return OBS_MODE_CHASE; - break; - default: - assert ( false ); - break; - } - } - return m_iObserverMode; } -bool C_BasePlayer::ViewModel_IsTransparent( void ) -{ - return IsTransparent(); -} - -bool C_BasePlayer::ViewModel_IsUsingFBTexture( void ) -{ - return UsesPowerOfTwoFrameBufferTexture(); -} //----------------------------------------------------------------------------- // Used by prediction, sets the view angles for the player @@ -707,20 +615,6 @@ surfacedata_t* C_BasePlayer::GetGroundSurface() return physprops->GetSurfaceData( trace.surface.surfaceProps ); } -void C_BasePlayer::FireGameEvent( IGameEvent *event ) -{ - if ( FStrEq( event->GetName(), "base_player_teleported" ) ) - { - const int index = event->GetInt( "entindex" ); - if ( index == entindex() && IsLocalPlayer() ) - { - // In VR, we want to make sure our head and body - // are aligned after we teleport. - g_ClientVirtualReality.AlignTorsoAndViewToWeapon(); - } - } - -} //----------------------------------------------------------------------------- // returns the player name @@ -767,7 +661,7 @@ void C_BasePlayer::OnPreDataChanged( DataUpdateType_t updateType ) } m_bWasFreezeFraming = (GetObserverMode() == OBS_MODE_FREEZECAM); - m_hOldFogController = m_Local.m_PlayerFog.m_hCtrl; + m_hOldFogController = m_PlayerFog.m_hCtrl; BaseClass::OnPreDataChanged( updateType ); } @@ -775,6 +669,50 @@ void C_BasePlayer::OnPreDataChanged( DataUpdateType_t updateType ) void C_BasePlayer::PreDataUpdate( DataUpdateType_t updateType ) { BaseClass::PreDataUpdate( updateType ); + + m_ubOldEFNoInterpParity = m_ubEFNoInterpParity; +} + +void C_BasePlayer::CheckForLocalPlayer( int nSplitScreenSlot ) +{ + // Make sure s_pLocalPlayer is correct + int iLocalPlayerIndex = ( nSplitScreenSlot != -1 ) ? engine->GetLocalPlayer() : 0; + + if ( g_nKillCamMode ) + iLocalPlayerIndex = g_nKillCamTarget1; + + if ( iLocalPlayerIndex == index ) + { + Assert( s_pLocalPlayer[ nSplitScreenSlot ] == NULL ); + s_pLocalPlayer[ nSplitScreenSlot ] = this; + m_bIsLocalPlayer = true; + + // Tell host player about the parasitic splitscreen user + if ( nSplitScreenSlot != 0 ) + { + Assert( s_pLocalPlayer[ 0 ] ); + m_nSplitScreenSlot = nSplitScreenSlot; + m_hSplitOwner = s_pLocalPlayer[ 0 ]; + if ( s_pLocalPlayer[ 0 ] ) + { + s_pLocalPlayer[ 0 ]->AddSplitScreenPlayer( this ); + } + } + else + { + // We're the host, not the parasite... + m_nSplitScreenSlot = 0; + m_hSplitOwner = NULL; + } + + if ( nSplitScreenSlot == 0 ) + { + // Reset our sound mixed in case we were in a freeze cam when we + // changed level, which would cause the snd_soundmixer to be left modified. + ConVar *pVar = (ConVar *)cvar->FindVar( "snd_soundmixer" ); + pVar->Revert(); + } + } } //----------------------------------------------------------------------------- @@ -787,30 +725,32 @@ void C_BasePlayer::PostDataUpdate( DataUpdateType_t updateType ) // on this same frame are not stomped because prediction thinks there // isn't a local player yet!!! - if ( updateType == DATA_UPDATE_CREATED ) - { - // Make sure s_pLocalPlayer is correct - - int iLocalPlayerIndex = engine->GetLocalPlayer(); + int nSlot = -1; - if ( g_nKillCamMode ) - iLocalPlayerIndex = g_nKillCamTarget1; - - if ( iLocalPlayerIndex == index ) + FOR_EACH_VALID_SPLITSCREEN_PLAYER( i ) + { + int nIndex = engine->GetSplitScreenPlayer( i ); + if ( nIndex == index ) { - Assert( s_pLocalPlayer == NULL ); - s_pLocalPlayer = this; - - // Reset our sound mixed in case we were in a freeze cam when we - // changed level, which would cause the snd_soundmixer to be left modified. - ConVar *pVar = (ConVar *)cvar->FindVar( "snd_soundmixer" ); - pVar->Revert(); + nSlot = i; + break; } } + ACTIVE_SPLITSCREEN_PLAYER_GUARD( nSlot ); + + bool bRecheck = false; + if ( nSlot != -1 && !s_pLocalPlayer[ nSlot ] ) + { + bRecheck = true; + } + if ( updateType == DATA_UPDATE_CREATED || bRecheck ) + { + CheckForLocalPlayer( nSlot ); + } - bool bForceEFNoInterp = IsNoInterpolationFrame(); + bool bForceEFNoInterp = ( m_ubOldEFNoInterpParity != m_ubEFNoInterpParity ); - if ( IsLocalPlayer() ) + if ( IsLocalPlayer( this ) ) { SetSimulatedEveryTick( true ); } @@ -820,17 +760,27 @@ void C_BasePlayer::PostDataUpdate( DataUpdateType_t updateType ) // estimate velocity for non local players float flTimeDelta = m_flSimulationTime - m_flOldSimulationTime; - if ( flTimeDelta > 0 && !( IsNoInterpolationFrame() || bForceEFNoInterp ) ) + + if (IsParentChanging()) + { + bForceEFNoInterp = true; + } + + if ( flTimeDelta > 0 && !( IsEffectActive(EF_NOINTERP) || bForceEFNoInterp ) ) { Vector newVelo = (GetNetworkOrigin() - GetOldOrigin() ) / flTimeDelta; - SetAbsVelocity( newVelo); + // This code used to call SetAbsVelocity, which is a no-no since we are in networking and if + // in hieararchy, the parent velocity might not be set up yet. + // On top of that GetNetworkOrigin and GetOldOrigin are local coordinates + // So we'll just set the local vel and avoid an Assert here + SetLocalVelocity( newVelo ); } } BaseClass::PostDataUpdate( updateType ); // Only care about this for local player - if ( IsLocalPlayer() ) + if ( IsLocalPlayer( this ) ) { QAngle angles; engine->GetViewAngles( angles ); @@ -838,42 +788,21 @@ void C_BasePlayer::PostDataUpdate( DataUpdateType_t updateType ) { SetLocalViewAngles( angles ); m_flOldPlayerZ = GetLocalOrigin().z; - // NVNT the local player has just been created. - // set in the "on_foot" navigation. - if ( haptics ) - { - haptics->LocalPlayerReset(); - haptics->SetNavigationClass("on_foot"); - haptics->ProcessHapticEvent(2,"Movement","BasePlayer"); - } - } SetLocalAngles( angles ); if ( !m_bWasFreezeFraming && GetObserverMode() == OBS_MODE_FREEZECAM ) { - m_vecFreezeFrameStart = MainViewOrigin(); + m_vecFreezeFrameStart = MainViewOrigin( GetSplitScreenPlayerSlot() ); m_flFreezeFrameStartTime = gpGlobals->curtime; m_flFreezeFrameDistance = RandomFloat( spec_freeze_distance_min.GetFloat(), spec_freeze_distance_max.GetFloat() ); m_flFreezeZOffset = RandomFloat( -30, 20 ); m_bSentFreezeFrame = false; - m_nForceVisionFilterFlags = 0; - - C_BaseEntity *target = GetObserverTarget(); - if ( target && target->IsPlayer() ) - { - C_BasePlayer *player = ToBasePlayer( target ); - if ( player ) - { - m_nForceVisionFilterFlags = player->GetVisionFilterFlags(); - CalculateVisionUsingCurrentFlags(); - } - } IGameEvent *pEvent = gameeventmanager->CreateEvent( "show_freezepanel" ); if ( pEvent ) { - pEvent->SetInt( "killer", target ? target->entindex() : 0 ); + pEvent->SetInt( "killer", GetObserverTarget() ? GetObserverTarget()->entindex() : 0 ); gameeventmanager->FireEventClientSide( pEvent ); } @@ -893,9 +822,6 @@ void C_BasePlayer::PostDataUpdate( DataUpdateType_t updateType ) ConVar *pVar = (ConVar *)cvar->FindVar( "snd_soundmixer" ); pVar->Revert(); - - m_nForceVisionFilterFlags = 0; - CalculateVisionUsingCurrentFlags(); } } @@ -905,6 +831,18 @@ void C_BasePlayer::PostDataUpdate( DataUpdateType_t updateType ) { ResetLatched(); } +#ifdef DEMOPOLISH_ENABLED + if ( engine->IsRecordingDemo() && + IsDemoPolishRecording() ) + { + m_bBonePolishSetup = true; + matrix3x4a_t dummyBones[MAXSTUDIOBONES]; + C_BaseEntity::SetAbsQueriesValid( true ); + ForceSetupBonesAtTime( dummyBones, gpGlobals->curtime ); + C_BaseEntity::SetAbsQueriesValid( false ); + m_bBonePolishSetup = false; + } +#endif } //----------------------------------------------------------------------------- @@ -939,16 +877,20 @@ void C_BasePlayer::OnRestore() { BaseClass::OnRestore(); - if ( IsLocalPlayer() ) + if ( IsLocalPlayer( this ) ) { + ACTIVE_SPLITSCREEN_PLAYER_GUARD_ENT( this ); + // debounce the attack key, for if it was used for restore input->ClearInputButton( IN_ATTACK | IN_ATTACK2 ); // GetButtonBits() has to be called for the above to take effect - input->GetButtonBits( 0 ); + input->GetButtonBits( false ); } // For ammo history icons to current value so they don't flash on level transtions - for ( int i = 0; i < MAX_AMMO_TYPES; i++ ) + int ammoTypes = GetAmmoDef()->NumAmmoTypes(); + // ammodef is 1 based, use <= + for ( int i = 0; i <= ammoTypes; i++ ) { m_iOldAmmo[i] = GetAmmoCount(i); } @@ -960,7 +902,7 @@ void C_BasePlayer::OnRestore() void C_BasePlayer::OnDataChanged( DataUpdateType_t updateType ) { #if !defined( NO_ENTITY_PREDICTION ) - if ( IsLocalPlayer() ) + if ( IsLocalPlayer( this ) ) { SetPredictionEligible( true ); } @@ -969,16 +911,24 @@ void C_BasePlayer::OnDataChanged( DataUpdateType_t updateType ) BaseClass::OnDataChanged( updateType ); // Only care about this for local player - if ( IsLocalPlayer() ) + if ( IsLocalPlayer( this ) ) { - // Reset engine areabits pointer - render->SetAreaState( m_Local.m_chAreaBits, m_Local.m_chAreaPortalBits ); + int nSlot = GetSplitScreenPlayerSlot(); + // Reset engine areabits pointer, but only for main local player (not piggybacked split screen users) + if ( nSlot == 0 ) + { + render->SetAreaState( m_Local.m_chAreaBits, m_Local.m_chAreaPortalBits ); + } // Check for Ammo pickups. - for ( int i = 0; i < MAX_AMMO_TYPES; i++ ) + int ammoTypes = GetAmmoDef()->NumAmmoTypes(); + for ( int i = 0; i <= ammoTypes; i++ ) { if ( GetAmmoCount(i) > m_iOldAmmo[i] ) { + // Only add this to the correct Hud + ACTIVE_SPLITSCREEN_PLAYER_GUARD( nSlot ); + // Don't add to ammo pickup if the ammo doesn't do it const FileWeaponInfo_t *pWeaponData = gWR.GetWeaponFromAmmo(i); @@ -994,9 +944,13 @@ void C_BasePlayer::OnDataChanged( DataUpdateType_t updateType ) } } - Soundscape_Update( m_Local.m_audio ); + // Only add this to the correct Hud + { + ACTIVE_SPLITSCREEN_PLAYER_GUARD( nSlot ); + Soundscape_Update( m_Local.m_audio ); + } - if ( m_hOldFogController != m_Local.m_PlayerFog.m_hCtrl ) + if ( m_hOldFogController != m_PlayerFog.m_hCtrl ) { FogControllerChanged( updateType == DATA_UPDATE_CREATED ); } @@ -1203,84 +1157,102 @@ void C_BasePlayer::TeamChange( int iNewTeam ) //----------------------------------------------------------------------------- void C_BasePlayer::UpdateFlashlight() { - // The dim light is the flashlight. - if ( IsEffectActive( EF_DIMLIGHT ) ) + ASSERT_LOCAL_PLAYER_RESOLVABLE(); + int iSsPlayer = GET_ACTIVE_SPLITSCREEN_SLOT(); + + // TERROR: if we're in-eye spectating, use that player's flashlight + C_BasePlayer *pFlashlightPlayer = this; + if ( !IsAlive() ) { - if (!m_pFlashlight) + if ( GetObserverMode() == OBS_MODE_IN_EYE ) { - // Turned on the headlight; create it. - m_pFlashlight = new CFlashlightEffect(index); + pFlashlightPlayer = ToBasePlayer( GetObserverTarget() ); + } + } - if (!m_pFlashlight) - return; + if ( pFlashlightPlayer ) + { + FlashlightEffectManager().SetEntityIndex( pFlashlightPlayer->index ); + } - m_pFlashlight->TurnOn(); + // The dim light is the flashlight. + if ( pFlashlightPlayer && pFlashlightPlayer->IsAlive() && pFlashlightPlayer->IsEffectActive( EF_DIMLIGHT ) && !pFlashlightPlayer->GetViewEntity() ) + { + // Make sure we're using the proper flashlight texture + const char *pszTextureName = pFlashlightPlayer->GetFlashlightTextureName(); + if ( !m_bFlashlightEnabled[ iSsPlayer ] ) + { + // Turned on the headlight; create it. + if ( pszTextureName ) + { + FlashlightEffectManager().TurnOnFlashlight( pFlashlightPlayer->index, pszTextureName, pFlashlightPlayer->GetFlashlightFOV(), + pFlashlightPlayer->GetFlashlightFarZ(), pFlashlightPlayer->GetFlashlightLinearAtten() ); + } + else + { + FlashlightEffectManager().TurnOnFlashlight( pFlashlightPlayer->index ); + } + m_bFlashlightEnabled[ iSsPlayer ] = true; } + } + else if ( m_bFlashlightEnabled[ iSsPlayer ] ) + { + // Turned off the flashlight; delete it. + FlashlightEffectManager().TurnOffFlashlight(); + m_bFlashlightEnabled[ iSsPlayer ] = false; + } + if ( pFlashlightPlayer && m_bFlashlightEnabled[ iSsPlayer ] ) + { Vector vecForward, vecRight, vecUp; - EyeVectors( &vecForward, &vecRight, &vecUp ); + Vector vecPos; + //Check to see if we have an externally specified flashlight origin, if not, use eye vectors/render origin + if ( pFlashlightPlayer->m_vecFlashlightOrigin != vec3_origin && pFlashlightPlayer->m_vecFlashlightOrigin.IsValid() ) + { + vecPos = pFlashlightPlayer->m_vecFlashlightOrigin; + vecForward = pFlashlightPlayer->m_vecFlashlightForward; + vecRight = pFlashlightPlayer->m_vecFlashlightRight; + vecUp = pFlashlightPlayer->m_vecFlashlightUp; + } + else + { + EyeVectors( &vecForward, &vecRight, &vecUp ); + vecPos = GetRenderOrigin() + m_vecViewOffset; + } // Update the light with the new position and direction. - m_pFlashlight->UpdateLight( EyePosition(), vecForward, vecRight, vecUp, FLASHLIGHT_DISTANCE ); - } - else if (m_pFlashlight) - { - // Turned off the flashlight; delete it. - delete m_pFlashlight; - m_pFlashlight = NULL; + FlashlightEffectManager().UpdateFlashlight( vecPos, vecForward, vecRight, vecUp, pFlashlightPlayer->GetFlashlightFOV(), + pFlashlightPlayer->CastsFlashlightShadows(), pFlashlightPlayer->GetFlashlightFarZ(), pFlashlightPlayer->GetFlashlightLinearAtten(), + pFlashlightPlayer->GetFlashlightTextureName() ); } } //----------------------------------------------------------------------------- -// Purpose: Creates player flashlight if it's ative +// Purpose: Creates player flashlight if it's active //----------------------------------------------------------------------------- void C_BasePlayer::Flashlight( void ) { UpdateFlashlight(); - - // Check for muzzle flash and apply to view model - C_BaseAnimating *ve = this; - if ( GetObserverMode() == OBS_MODE_IN_EYE ) - { - ve = dynamic_cast< C_BaseAnimating* >( GetObserverTarget() ); - } } //----------------------------------------------------------------------------- -// Purpose: Engine is asking whether to add this player to the visible entities list +// Purpose: Turns off flashlight if it's active (TERROR) //----------------------------------------------------------------------------- -void C_BasePlayer::AddEntity( void ) +void C_BasePlayer::TurnOffFlashlight( void ) { - // FIXME/UNDONE: Should the local player say yes to adding itself now - // and then, when it ges time to render and it shouldn't still do the render with - // STUDIO_EVENTS set so that its attachment points will get updated even if not - // in third person? + ASSERT_LOCAL_PLAYER_RESOLVABLE(); + int nSlot = GET_ACTIVE_SPLITSCREEN_SLOT(); - // Add in water effects - if ( IsLocalPlayer() ) + if ( m_bFlashlightEnabled[ nSlot ] ) { - CreateWaterEffects(); + FlashlightEffectManager().TurnOffFlashlight(); + m_bFlashlightEnabled[ nSlot ] = false; } - - // If set to invisible, skip. Do this before resetting the entity pointer so it has - // valid data to decide whether it's visible. - if ( !IsVisible() || !g_pClientMode->ShouldDrawLocalPlayer( this ) ) - { - return; - } - - // Server says don't interpolate this frame, so set previous info to new info. - if ( IsNoInterpolationFrame() || Teleported() ) - { - ResetLatched(); - } - - // Add in lighting effects - CreateLightEffects(); } + extern float UTIL_WaterLevel( const Vector &position, float minz, float maxz ); //----------------------------------------------------------------------------- @@ -1372,35 +1344,78 @@ void C_BasePlayer::OverrideView( CViewSetup *pSetup ) bool C_BasePlayer::ShouldInterpolate() { // always interpolate myself - if ( IsLocalPlayer() ) + if ( IsLocalPlayer( this ) ) + return true; + + // always interpolate entity if followed by HLTV/Replay +#if defined( REPLAY_ENABLED ) + if ( HLTVCamera()->GetCameraMan() == this || + ReplayCamera()->GetCameraMan() == this ) return true; -#ifndef _XBOX - // always interpolate entity if followed by HLTV +#else if ( HLTVCamera()->GetCameraMan() == this ) return true; #endif + return BaseClass::ShouldInterpolate(); } bool C_BasePlayer::ShouldDraw() { - return ShouldDrawThisPlayer() && BaseClass::ShouldDraw(); + return ( this != GetSplitScreenViewPlayer() || C_BasePlayer::ShouldDrawLocalPlayer() || (GetObserverMode() == OBS_MODE_DEATHCAM ) ) && + BaseClass::ShouldDraw(); } -int C_BasePlayer::DrawModel( int flags ) +int C_BasePlayer::DrawModel( int flags, const RenderableInstance_t &instance ) { -#ifndef PORTAL - // In Portal this check is already performed as part of - // C_Portal_Player::DrawModel() - if ( !ShouldDrawThisPlayer() ) + // if local player is spectating this player in first person mode, don't draw it + C_BasePlayer * player = C_BasePlayer::GetLocalPlayer(); + + if ( player && player->IsObserver() ) { - return 0; + if ( player->GetObserverMode() == OBS_MODE_IN_EYE && + player->GetObserverTarget() == this && + !input->CAM_IsThirdPerson() ) + return 0; } -#endif - return BaseClass::DrawModel( flags ); + + return BaseClass::DrawModel( flags, instance ); } +//----------------------------------------------------------------------------- +// Computes the render mode for this player +//----------------------------------------------------------------------------- +PlayerRenderMode_t C_BasePlayer::GetPlayerRenderMode( int nSlot ) +{ + // check if local player chases owner of this weapon in first person + C_BasePlayer *pLocalPlayer = GetSplitScreenViewPlayer( nSlot ); + if ( !pLocalPlayer ) + return PLAYER_RENDER_THIRDPERSON; + + if ( pLocalPlayer->IsObserver() ) + { + if ( pLocalPlayer->GetObserverTarget() != this ) + return PLAYER_RENDER_THIRDPERSON; + if ( pLocalPlayer->GetObserverMode() != OBS_MODE_IN_EYE ) + return PLAYER_RENDER_THIRDPERSON; + } + else + { + if ( pLocalPlayer != this ) + return PLAYER_RENDER_THIRDPERSON; + } + + if ( input->CAM_IsThirdPerson( nSlot ) ) + return PLAYER_RENDER_THIRDPERSON; + +// if ( IsInThirdPersonView() ) +// return PLAYER_RENDER_THIRDPERSON; + + return PLAYER_RENDER_FIRSTPERSON; +} + + //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- @@ -1408,22 +1423,12 @@ Vector C_BasePlayer::GetChaseCamViewOffset( CBaseEntity *target ) { C_BasePlayer *player = ToBasePlayer( target ); - if ( player ) + if ( player && player->IsAlive() ) { - if ( player->IsAlive() ) - { - if ( player->GetFlags() & FL_DUCKING ) - { - return VEC_DUCK_VIEW_SCALED( player ); - } + if( player->GetFlags() & FL_DUCKING ) + return VEC_DUCK_VIEW; - return VEC_VIEW_SCALED( player ); - } - else - { - // assume it's the players ragdoll - return VEC_DEAD_VIEWHEIGHT_SCALED( player ); - } + return VEC_VIEW; } // assume it's the players ragdoll @@ -1466,70 +1471,24 @@ void C_BasePlayer::CalcChaseCamView(Vector& eyeOrigin, QAngle& eyeAngles, float& { viewangles = eyeAngles; } - else if ( IsLocalPlayer() ) + else if ( IsLocalPlayer( this ) ) { engine->GetViewAngles( viewangles ); - if ( UseVR() ) - { - // Don't let people play with the pitch - they drive it into the ground or into the air and - // it's distracting at best, nauseating at worst (e.g. when it clips through the ground plane). - viewangles[PITCH] = 20.0f; - } } else { viewangles = EyeAngles(); } - //============================================================================= - // HPE_BEGIN: - // [Forrest] Fix for (at least one potential case of) CSB-194. Spectating someone - // who is headshotted by a teammate and then switching to chase cam leaves - // you with a permanent roll to the camera that doesn't decay and is not reset - // even when switching to different players or at the start of the next round - // if you are still a spectator. (If you spawn as a player, the view is reset. - // if you switch spectator modes, the view is reset.) - //============================================================================= -#ifdef CSTRIKE_DLL - // The chase camera adopts the yaw and pitch of the previous camera, but the camera - // should not roll. - viewangles.z = 0; -#endif - //============================================================================= - // HPE_END - //============================================================================= - m_flObserverChaseDistance += gpGlobals->frametime*48.0f; - float flMinDistance = CHASE_CAM_DISTANCE_MIN; - float flMaxDistance = CHASE_CAM_DISTANCE_MAX; - + float flMaxDistance = CHASE_CAM_DISTANCE; if ( target && target->IsBaseTrain() ) { // if this is a train, we want to be back a little further so we can see more of it flMaxDistance *= 2.5f; } - - if ( target ) - { - C_BaseAnimating *pTargetAnimating = target->GetBaseAnimating(); - if ( pTargetAnimating ) - { - float flScaleSquared = pTargetAnimating->GetModelScale() * pTargetAnimating->GetModelScale(); - flMinDistance *= flScaleSquared; - flMaxDistance *= flScaleSquared; - m_flObserverChaseDistance = flMaxDistance; - } - } - - if ( target && !target->IsPlayer() && target->IsNextBot() ) - { - // if this is a boss, we want to be back a little further so we can see more of it - flMaxDistance *= 2.5f; - m_flObserverChaseDistance = flMaxDistance; - } - - m_flObserverChaseDistance = clamp( m_flObserverChaseDistance, flMinDistance, flMaxDistance ); + m_flObserverChaseDistance = clamp( m_flObserverChaseDistance, 16, flMaxDistance ); AngleVectors( viewangles, &forward ); @@ -1568,7 +1527,7 @@ void C_BasePlayer::CalcRoamingView(Vector& eyeOrigin, QAngle& eyeAngles, float& eyeOrigin = target->EyePosition(); eyeAngles = target->EyeAngles(); - + if ( spec_track.GetInt() > 0 ) { C_BaseEntity *target = ClientEntityList().GetBaseEntity( spec_track.GetInt() ); @@ -1606,7 +1565,7 @@ void C_BasePlayer::CalcFreezeCamView( Vector& eyeOrigin, QAngle& eyeAngles, floa // Zoom towards our target float flCurTime = (gpGlobals->curtime - m_flFreezeFrameStartTime); - float flBlendPerc = clamp( flCurTime / spec_freeze_traveltime.GetFloat(), 0.f, 1.f ); + float flBlendPerc = clamp( flCurTime / spec_freeze_traveltime.GetFloat(), 0, 1 ); flBlendPerc = SimpleSpline( flBlendPerc ); Vector vecCamDesired = pTarget->GetObserverCamOrigin(); // Returns ragdoll origin if they're ragdolled @@ -1615,12 +1574,12 @@ void C_BasePlayer::CalcFreezeCamView( Vector& eyeOrigin, QAngle& eyeAngles, floa if ( pTarget->IsAlive() ) { // Look at their chest, not their head - Vector maxs = pTarget->GetBaseAnimating() ? VEC_HULL_MAX_SCALED( pTarget->GetBaseAnimating() ) : VEC_HULL_MAX; + Vector maxs = GameRules()->GetViewVectors()->m_vHullMax; vecCamTarget.z -= (maxs.z * 0.5); } else { - vecCamTarget.z += pTarget->GetBaseAnimating() ? VEC_DEAD_VIEWHEIGHT_SCALED( pTarget->GetBaseAnimating() ).z : VEC_DEAD_VIEWHEIGHT.z; // look over ragdoll, not through + vecCamTarget.z += VEC_DEAD_VIEWHEIGHT.z; // look over ragdoll, not through } // Figure out a view position in front of the target @@ -1705,39 +1664,29 @@ void C_BasePlayer::CalcInEyeCamView(Vector& eyeOrigin, QAngle& eyeAngles, float& VectorAdd( eyeAngles, GetPunchAngle(), eyeAngles ); #if defined( REPLAY_ENABLED ) - if( engine->IsHLTV() || g_pEngineClientReplay->IsPlayingReplayDemo() ) + if( g_bEngineIsHLTV || engine->IsReplay() ) #else - if( engine->IsHLTV() ) + if( g_bEngineIsHLTV ) #endif { - C_BaseAnimating *pTargetAnimating = target->GetBaseAnimating(); if ( target->GetFlags() & FL_DUCKING ) { - eyeOrigin += pTargetAnimating ? VEC_DUCK_VIEW_SCALED( pTargetAnimating ) : VEC_DUCK_VIEW; + eyeOrigin += VEC_DUCK_VIEW; } else { - eyeOrigin += pTargetAnimating ? VEC_VIEW_SCALED( pTargetAnimating ) : VEC_VIEW; + eyeOrigin += VEC_VIEW; } } else { - Vector offset = GetViewOffset(); -#ifdef HL2MP - offset = target->GetViewOffset(); -#endif + Vector offset = m_vecViewOffset; eyeOrigin += offset; // hack hack } engine->SetViewAngles( eyeAngles ); } -float C_BasePlayer::GetDeathCamInterpolationTime() -{ - return DEATH_ANIMATION_TIME; -} - - void C_BasePlayer::CalcDeathCamView(Vector& eyeOrigin, QAngle& eyeAngles, float& fov) { CBaseEntity * pKiller = NULL; @@ -1749,25 +1698,24 @@ void C_BasePlayer::CalcDeathCamView(Vector& eyeOrigin, QAngle& eyeAngles, float& eyeAngles = EyeAngles(); } - float interpolation = ( gpGlobals->curtime - m_flDeathTime ) / GetDeathCamInterpolationTime(); + float interpolation = ( gpGlobals->curtime - m_flDeathTime ) / DEATH_ANIMATION_TIME; interpolation = clamp( interpolation, 0.0f, 1.0f ); m_flObserverChaseDistance += gpGlobals->frametime*48.0f; - m_flObserverChaseDistance = clamp( m_flObserverChaseDistance, ( CHASE_CAM_DISTANCE_MIN * 2 ), CHASE_CAM_DISTANCE_MAX ); + m_flObserverChaseDistance = clamp( m_flObserverChaseDistance, 16, CHASE_CAM_DISTANCE ); QAngle aForward = eyeAngles; Vector origin = EyePosition(); - // NOTE: This will create the ragdoll in CSS if m_hRagdoll is set, but m_pRagdoll is not yet presetn IRagdoll *pRagdoll = GetRepresentativeRagdoll(); if ( pRagdoll ) { origin = pRagdoll->GetRagdollOrigin(); - origin.z += VEC_DEAD_VIEWHEIGHT_SCALED( this ).z; + origin.z += VEC_DEAD_VIEWHEIGHT.z; // look over ragdoll, not through } if ( pKiller && pKiller->IsPlayer() && (pKiller != this) ) - { + { Vector vKiller = pKiller->EyePosition() - origin; QAngle aKiller; VectorAngles( vKiller, aKiller ); InterpolateAngles( aForward, aKiller, eyeAngles, interpolation ); @@ -1807,7 +1755,7 @@ C_BaseCombatWeapon *C_BasePlayer::GetActiveWeaponForSelection( void ) C_BaseAnimating* C_BasePlayer::GetRenderedWeaponModel() { // Attach to either their weapon model or their view model. - if ( ShouldDrawLocalPlayer() || !IsLocalPlayer() ) + if ( ShouldDrawLocalPlayer() || !IsLocalPlayer( this ) ) { return GetActiveWeapon(); } @@ -1819,142 +1767,127 @@ C_BaseAnimating* C_BasePlayer::GetRenderedWeaponModel() //----------------------------------------------------------------------------- // Purpose: Gets a pointer to the local player, if it exists yet. -// Output : C_BasePlayer +// static method //----------------------------------------------------------------------------- -C_BasePlayer *C_BasePlayer::GetLocalPlayer( void ) +C_BasePlayer *C_BasePlayer::GetLocalPlayer( int nSlot /*= -1*/ ) { - return s_pLocalPlayer; + if ( nSlot == -1 ) + { +// ASSERT_LOCAL_PLAYER_RESOLVABLE(); + return s_pLocalPlayer[ GET_ACTIVE_SPLITSCREEN_SLOT() ]; + } + return s_pLocalPlayer[ nSlot ]; } -//----------------------------------------------------------------------------- -// Purpose: -// Input : bThirdperson - -//----------------------------------------------------------------------------- -void C_BasePlayer::ThirdPersonSwitch( bool bThirdperson ) +void C_BasePlayer::SetRemoteSplitScreenPlayerViewsAreLocalPlayer( bool bSet ) { - // We've switch from first to third, or vice versa. - UpdateVisibility(); - - // Update the visibility of anything bone attached to us. - if ( IsLocalPlayer() ) + for( int i = 0; i != MAX_SPLITSCREEN_PLAYERS; ++i ) { - bool bShouldDrawLocalPlayer = ShouldDrawLocalPlayer(); - for ( int i=0; iRemoveEffects( EF_NODRAW ); - } - else - { - pBoneAttachment->AddEffects( EF_NODRAW ); - } - } + s_pLocalPlayer[i] = bSet ? GetSplitScreenViewPlayer( i ) : NULL; } } } - -//----------------------------------------------------------------------------- -// Purpose: single place to decide whether the camera is in the first-person position -// NOTE - ShouldDrawLocalPlayer() can be true even if the camera is in the first-person position, e.g. in VR. -//----------------------------------------------------------------------------- -/*static*/ bool C_BasePlayer::LocalPlayerInFirstPersonView() +bool C_BasePlayer::HasAnyLocalPlayer() { - C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer(); - if ( pLocalPlayer == NULL ) + FOR_EACH_VALID_SPLITSCREEN_PLAYER( i ) { - return false; - } - int ObserverMode = pLocalPlayer->GetObserverMode(); - if ( ( ObserverMode == OBS_MODE_NONE ) || ( ObserverMode == OBS_MODE_IN_EYE ) ) - { - return !input->CAM_IsThirdPerson() && ( !ToolsEnabled() || !ToolFramework_IsThirdPersonCamera() ); + if ( s_pLocalPlayer[ i ] ) + return true; } - - // Not looking at the local player, e.g. in a replay in third person mode or freelook. return false; } -//----------------------------------------------------------------------------- -// Purpose: single place to decide whether the local player should draw -//----------------------------------------------------------------------------- -/*static*/ bool C_BasePlayer::ShouldDrawLocalPlayer() +int C_BasePlayer::GetSplitScreenSlotForPlayer( C_BaseEntity *pl ) { - if ( !UseVR() ) + C_BasePlayer *pPlayer = ToBasePlayer( pl ); + + if ( !pPlayer ) { - return !LocalPlayerInFirstPersonView() || cl_first_person_uses_world_model.GetBool(); + Assert( 0 ); + return -1; } - - static ConVarRef vr_first_person_uses_world_model( "vr_first_person_uses_world_model" ); - return !LocalPlayerInFirstPersonView() || vr_first_person_uses_world_model.GetBool(); + return pPlayer->GetSplitScreenPlayerSlot(); } - //----------------------------------------------------------------------------- -// Purpose: single place to decide whether the camera is in the first-person position -// NOTE - ShouldDrawLocalPlayer() can be true even if the camera is in the first-person position, e.g. in VR. +// Purpose: +// Input : bThirdperson - //----------------------------------------------------------------------------- -bool C_BasePlayer::InFirstPersonView() +void C_BasePlayer::ThirdPersonSwitch( bool bThirdperson ) { - if ( IsLocalPlayer() ) - { - return LocalPlayerInFirstPersonView(); - } - C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer(); - if ( pLocalPlayer == NULL ) - { - return false; - } - // If this is who we're observing in first person, it's counted as the "local" player. - if ( pLocalPlayer->GetObserverMode() == OBS_MODE_IN_EYE && pLocalPlayer->GetObserverTarget() == ToBasePlayer(this) ) - { - return LocalPlayerInFirstPersonView(); - } - return false; + // We've switch from first to third, or vice versa. + UpdateVisibility(); } //----------------------------------------------------------------------------- -// Purpose: single place to decide whether the player is being drawn with the standard model (i.e. not the viewmodel) -// NOTE - ShouldDrawLocalPlayer() can be true even if the camera is in the first-person position, e.g. in VR. +// Purpose: single place to decide whether the local player should draw //----------------------------------------------------------------------------- -bool C_BasePlayer::ShouldDrawThisPlayer() +bool C_BasePlayer::ShouldDrawLocalPlayer() { - if ( !InFirstPersonView() ) + int nSlot = GetSplitScreenPlayerSlot(); + + + + ACTIVE_SPLITSCREEN_PLAYER_GUARD( nSlot ); + return input->CAM_IsThirdPerson() || ( ToolsEnabled() && ToolFramework_IsThirdPersonCamera() ); +} + +//---------------------------------------------------------------------------- +// Hooks into the fast path render system +//---------------------------------------------------------------------------- +IClientModelRenderable *C_BasePlayer::GetClientModelRenderable() +{ + // Honor base class eligibility + if ( !BaseClass::GetClientModelRenderable() ) + return NULL; + + // No fast path for firstperson local players + if ( IsLocalPlayer( this ) ) { - return true; + bool bThirdPerson = input->CAM_IsThirdPerson() || ( ToolsEnabled() && ToolFramework_IsThirdPersonCamera() ); + if ( !bThirdPerson ) + { + return NULL; + } } - if ( !UseVR() && cl_first_person_uses_world_model.GetBool() ) + + // if local player is spectating this player in first person mode, don't use fast path, so we can skip drawing it + C_BasePlayer *localPlayer = C_BasePlayer::GetLocalPlayer(); + if ( localPlayer && localPlayer->IsObserver() ) { - return true; + if ( localPlayer->GetObserverMode() == OBS_MODE_IN_EYE && + localPlayer->GetObserverTarget() == this && + !input->CAM_IsThirdPerson() ) + return NULL; } - if ( UseVR() ) + + // don't use fastpath for teammates (causes extra work for glows) + if ( localPlayer && localPlayer->GetTeamNumber() == GetTeamNumber() ) { - static ConVarRef vr_first_person_uses_world_model( "vr_first_person_uses_world_model" ); - if ( vr_first_person_uses_world_model.GetBool() ) - { - return true; - } + return NULL; } - return false; -} - + return this; +} //----------------------------------------------------------------------------- // Purpose: // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- -bool C_BasePlayer::IsLocalPlayer( void ) const +bool C_BasePlayer::IsLocalPlayer( const C_BaseEntity *pEntity ) { - return ( GetLocalPlayer() == this ); + if ( !pEntity || + !pEntity->IsPlayer() ) + return false; + + return static_cast< const C_BasePlayer * >( pEntity )->m_bIsLocalPlayer; } -int C_BasePlayer::GetUserID( void ) +int C_BasePlayer::GetUserID( void ) const { player_info_t pi; @@ -2014,16 +1947,8 @@ void C_BasePlayer::PostThink( void ) if ( IsAlive()) { - // Need to do this on the client to avoid prediction errors - if ( GetFlags() & FL_DUCKING ) - { - SetCollisionBounds( VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX ); - } - else - { - SetCollisionBounds( VEC_HULL_MIN, VEC_HULL_MAX ); - } - + UpdateCollisionBounds(); + if ( !CommentaryModeShouldSwallowInput( this ) ) { // do weapon stuff @@ -2061,8 +1986,8 @@ void C_BasePlayer::GetToolRecordingState( KeyValues *msg ) BaseClass::GetToolRecordingState( msg ); - msg->SetInt( "baseplayer", 1 ); - msg->SetInt( "localplayer", IsLocalPlayer() ? 1 : 0 ); + msg->SetBool( "baseplayer", true ); + msg->SetBool( "localplayer", IsLocalPlayer( this ) ); msg->SetString( "playername", GetPlayerName() ); static CameraRecordingState_t state; @@ -2078,8 +2003,9 @@ void C_BasePlayer::GetToolRecordingState( KeyValues *msg ) // then this code can (should!) be removed if ( state.m_bThirdPerson ) { - Vector cam_ofs = g_ThirdPersonManager.GetCameraOffsetAngles(); - + Vector cam_ofs; + ::input->CAM_GetCameraOffset( cam_ofs ); + QAngle camAngles; camAngles[ PITCH ] = cam_ofs[ PITCH ]; camAngles[ YAW ] = cam_ofs[ YAW ]; @@ -2101,11 +2027,13 @@ void C_BasePlayer::GetToolRecordingState( KeyValues *msg ) //----------------------------------------------------------------------------- // Purpose: Simulate the player for this frame //----------------------------------------------------------------------------- -void C_BasePlayer::Simulate() +bool C_BasePlayer::Simulate() { //Frame updates - if ( this == C_BasePlayer::GetLocalPlayer() ) + if ( C_BasePlayer::IsLocalPlayer( this ) ) { + ACTIVE_SPLITSCREEN_PLAYER_GUARD_ENT( this ); + //Update the flashlight Flashlight(); @@ -2121,25 +2049,26 @@ void C_BasePlayer::Simulate() } BaseClass::Simulate(); - if ( IsNoInterpolationFrame() || Teleported() ) + + // Server says don't interpolate this frame, so set previous info to new info. + if ( IsEffectActive( EF_NOINTERP ) || Teleported() ) { ResetLatched(); } + return true; } //----------------------------------------------------------------------------- // Purpose: // Output : CBaseViewModel -// Consider using GetRenderedWeaponModel() instead - it will get the -// viewmodel or the active weapon as appropriate. //----------------------------------------------------------------------------- -C_BaseViewModel *C_BasePlayer::GetViewModel( int index /*= 0*/, bool bObserverOK ) +C_BaseViewModel *C_BasePlayer::GetViewModel( int index /*= 0*/ ) { Assert( index >= 0 && index < MAX_VIEWMODELS ); C_BaseViewModel *vm = m_hViewModel[ index ]; - if ( bObserverOK && GetObserverMode() == OBS_MODE_IN_EYE ) + if ( GetObserverMode() == OBS_MODE_IN_EYE ) { C_BasePlayer *target = ToBasePlayer( GetObserverTarget() ); @@ -2158,7 +2087,7 @@ C_BaseCombatWeapon *C_BasePlayer::GetActiveWeapon( void ) const const C_BasePlayer *fromPlayer = this; // if localplayer is in InEye spectator mode, return weapon on chased player - if ( (fromPlayer == GetLocalPlayer()) && ( GetObserverMode() == OBS_MODE_IN_EYE) ) + if ( ( C_BasePlayer::IsLocalPlayer( const_cast< C_BasePlayer * >( fromPlayer) ) ) && ( GetObserverMode() == OBS_MODE_IN_EYE) ) { C_BaseEntity *target = GetObserverTarget(); @@ -2185,14 +2114,13 @@ Vector C_BasePlayer::GetAutoaimVector( float flScale ) void C_BasePlayer::PlayPlayerJingle() { -#ifndef _XBOX + if ( !cl_customsounds.GetBool() ) + return; + // Find player sound for shooter player_info_t info; engine->GetPlayerInfo( entindex(), &info ); - if ( !cl_customsounds.GetBool() ) - return; - // Doesn't have a jingle sound if ( !info.customFiles[1] ) return; @@ -2207,7 +2135,7 @@ void C_BasePlayer::PlayPlayerJingle() if ( !filesystem->FileExists( fullsoundname ) ) { char custname[ 512 ]; - Q_snprintf( custname, sizeof( custname ), "download/user_custom/%c%c/%s.dat", soundhex[0], soundhex[1], soundhex ); + Q_snprintf( custname, sizeof( custname ), "downloads/%s.dat", soundhex ); // it may have been downloaded but not copied under materials folder if ( !filesystem->FileExists( custname ) ) return; // not downloaded yet @@ -2215,7 +2143,7 @@ void C_BasePlayer::PlayPlayerJingle() // copy from download folder to materials/temp folder // this is done since material system can access only materials/*.vtf files - if ( !engine->CopyLocalFile( custname, fullsoundname) ) + if ( !engine->CopyFile( custname, fullsoundname) ) return; } @@ -2230,11 +2158,10 @@ void C_BasePlayer::PlayPlayerJingle() ep.m_SoundLevel = SNDLVL_NORM; C_BaseEntity::EmitSound( filter, GetSoundSourceIndex(), ep ); -#endif } // Stuff for prediction -void C_BasePlayer::SetSuitUpdate(const char *name, int fgroup, int iNoRepeat) +void C_BasePlayer::SetSuitUpdate(char *name, int fgroup, int iNoRepeat) { // FIXME: Do something here? } @@ -2258,7 +2185,7 @@ bool C_BasePlayer::ShouldPredict( void ) { #if !defined( NO_ENTITY_PREDICTION ) // Do this before calling into baseclass so prediction data block gets allocated - if ( IsLocalPlayer() ) + if ( IsLocalPlayer( this ) ) { return true; } @@ -2266,6 +2193,14 @@ bool C_BasePlayer::ShouldPredict( void ) return false; } +//----------------------------------------------------------------------------- +// Purpose: Return the player who will predict this entity +//----------------------------------------------------------------------------- +C_BasePlayer *C_BasePlayer::GetPredictionOwner( void ) +{ + return this; +} + //----------------------------------------------------------------------------- // Purpose: Special processing for player simulation // NOTE: Don't chain to BaseClass!!!! @@ -2287,7 +2222,7 @@ void C_BasePlayer::PhysicsSimulate( void ) m_nSimulationTick = gpGlobals->tickcount; - if ( !IsLocalPlayer() ) + if ( !IsLocalPlayer( this ) ) return; C_CommandContext *ctx = GetCommandContext(); @@ -2310,10 +2245,12 @@ void C_BasePlayer::PhysicsSimulate( void ) } // Run the next command + MoveHelper()->SetHost( this ); prediction->RunCommand( this, &ctx->cmd, MoveHelper() ); + MoveHelper()->SetHost( NULL ); #endif } @@ -2358,26 +2295,26 @@ bool C_BasePlayer::IsUseableEntity( CBaseEntity *pEntity, unsigned int requiredC return false; } +C_BaseEntity* C_BasePlayer::GetUseEntity( void ) const +{ + return m_hUseEntity; +} + +C_BaseEntity* C_BasePlayer::GetPotentialUseEntity( void ) const +{ + return GetUseEntity(); +} + //----------------------------------------------------------------------------- // Purpose: // Output : float //----------------------------------------------------------------------------- -float C_BasePlayer::GetFOV( void ) +float C_BasePlayer::GetFOV( void ) const { - // Allow users to override the FOV during demo playback - bool bUseDemoOverrideFov = engine->IsPlayingDemo() && demo_fov_override.GetFloat() > 0.0f; -#if defined( REPLAY_ENABLED ) - bUseDemoOverrideFov = bUseDemoOverrideFov && !g_pEngineClientReplay->IsPlayingReplayDemo(); -#endif - if ( bUseDemoOverrideFov ) - { - return clamp( demo_fov_override.GetFloat(), 10.0f, 90.0f ); - } - if ( GetObserverMode() == OBS_MODE_IN_EYE ) { - C_BasePlayer *pTargetPlayer = dynamic_cast( GetObserverTarget() ); + C_BasePlayer *pTargetPlayer = ToBasePlayer( GetObserverTarget() ); // get fov from observer target. Not if target is observer itself if ( pTargetPlayer && !pTargetPlayer->IsObserver() ) @@ -2388,10 +2325,10 @@ float C_BasePlayer::GetFOV( void ) // Allow our vehicle to override our FOV if it's currently at the default FOV. float flDefaultFOV; - IClientVehicle *pVehicle = GetVehicle(); + IClientVehicle *pVehicle = const_cast< C_BasePlayer * >(this)->GetVehicle(); if ( pVehicle ) { - CacheVehicleView(); + const_cast< C_BasePlayer * >(this)->CacheVehicleView(); flDefaultFOV = ( m_flVehicleViewFOV == 0 ) ? GetDefaultFOV() : m_flVehicleViewFOV; } else @@ -2406,7 +2343,7 @@ float C_BasePlayer::GetFOV( void ) if ( !prediction->InPrediction() ) { // See if we need to lerp the values for local player - if ( IsLocalPlayer() && ( fFOV != m_iFOVStart ) && (m_Local.m_flFOVRate > 0.0f ) ) + if ( IsLocalPlayer( this ) && ( fFOV != m_iFOVStart ) && (m_Local.m_flFOVRate > 0.0f ) ) { float deltaTime = (float)( gpGlobals->curtime - m_flFOVTime ) / m_Local.m_flFOVRate; @@ -2423,7 +2360,7 @@ float C_BasePlayer::GetFOV( void ) if ( deltaTime >= 1.0f ) { //If we're past the zoom time, just take the new value and stop lerping - m_iFOVStart = fFOV; + const_cast(this)->m_iFOVStart = fFOV; } else { @@ -2435,7 +2372,7 @@ float C_BasePlayer::GetFOV( void ) return fFOV; } -void RecvProxy_LocalVelocityX( const CRecvProxyData *pData, void *pStruct, void *pOut ) +void C_BasePlayer::RecvProxy_LocalVelocityX( const CRecvProxyData *pData, void *pStruct, void *pOut ) { C_BasePlayer *pPlayer = (C_BasePlayer *) pStruct; @@ -2452,7 +2389,7 @@ void RecvProxy_LocalVelocityX( const CRecvProxyData *pData, void *pStruct, void } } -void RecvProxy_LocalVelocityY( const CRecvProxyData *pData, void *pStruct, void *pOut ) +void C_BasePlayer::RecvProxy_LocalVelocityY( const CRecvProxyData *pData, void *pStruct, void *pOut ) { C_BasePlayer *pPlayer = (C_BasePlayer *) pStruct; @@ -2469,7 +2406,7 @@ void RecvProxy_LocalVelocityY( const CRecvProxyData *pData, void *pStruct, void } } -void RecvProxy_LocalVelocityZ( const CRecvProxyData *pData, void *pStruct, void *pOut ) +void C_BasePlayer::RecvProxy_LocalVelocityZ( const CRecvProxyData *pData, void *pStruct, void *pOut ) { C_BasePlayer *pPlayer = (C_BasePlayer *) pStruct; @@ -2486,7 +2423,20 @@ void RecvProxy_LocalVelocityZ( const CRecvProxyData *pData, void *pStruct, void } } -void RecvProxy_ObserverTarget( const CRecvProxyData *pData, void *pStruct, void *pOut ) +void C_BasePlayer::RecvProxy_ObserverMode( const CRecvProxyData *pData, void *pStruct, void *pOut ) +{ + RecvProxy_Int32ToInt32( pData, pStruct, pOut ); + + C_BasePlayer *pPlayer = (C_BasePlayer *) pStruct; + Assert( pPlayer ); + if ( C_BasePlayer::IsLocalPlayer( pPlayer ) ) + { + UpdateViewmodelVisibility( pPlayer ); + } + +} + +void C_BasePlayer::RecvProxy_ObserverTarget( const CRecvProxyData *pData, void *pStruct, void *pOut ) { C_BasePlayer *pPlayer = (C_BasePlayer *) pStruct; @@ -2499,13 +2449,48 @@ void RecvProxy_ObserverTarget( const CRecvProxyData *pData, void *pStruct, void pPlayer->SetObserverTarget( hTarget ); } -void RecvProxy_ObserverMode( const CRecvProxyData *pData, void *pStruct, void *pOut ) +void C_BasePlayer::RecvProxy_LocalOriginXY( const CRecvProxyData *pData, void *pStruct, void *pOut ) { - C_BasePlayer *pPlayer = (C_BasePlayer *) pStruct; + ((float*)pOut)[0] = pData->m_Value.m_Vector[0]; + ((float*)pOut)[1] = pData->m_Value.m_Vector[1]; +} - Assert( pPlayer ); +void C_BasePlayer::RecvProxy_LocalOriginZ( const CRecvProxyData *pData, void *pStruct, void *pOut ) +{ + *((float*)pOut) = pData->m_Value.m_Float; +} - pPlayer->SetObserverMode ( pData->m_Value.m_Int ); +void C_BasePlayer::RecvProxy_NonLocalOriginXY( const CRecvProxyData *pData, void *pStruct, void *pOut ) +{ + ((float*)pOut)[0] = pData->m_Value.m_Vector[0]; + ((float*)pOut)[1] = pData->m_Value.m_Vector[1]; +} + +void C_BasePlayer::RecvProxy_NonLocalOriginZ( const CRecvProxyData *pData, void *pStruct, void *pOut ) +{ + *((float*)pOut) = pData->m_Value.m_Float; +} + +void C_BasePlayer::RecvProxy_NonLocalCellOriginXY( const CRecvProxyData *pData, void *pStruct, void *pOut ) +{ + C_BasePlayer *player = (C_BasePlayer *) pStruct; + + player->m_vecCellOrigin.x = pData->m_Value.m_Vector[0]; + player->m_vecCellOrigin.y = pData->m_Value.m_Vector[1]; + + register int const cellwidth = player->m_cellwidth; // Load it into a register + ((float*)pOut)[0] = CoordFromCell( cellwidth, player->m_cellX, pData->m_Value.m_Vector[0] ); + ((float*)pOut)[1] = CoordFromCell( cellwidth, player->m_cellY, pData->m_Value.m_Vector[1] ); +} + +void C_BasePlayer::RecvProxy_NonLocalCellOriginZ( const CRecvProxyData *pData, void *pStruct, void *pOut ) +{ + C_BasePlayer *player = (C_BasePlayer *) pStruct; + + player->m_vecCellOrigin.z = pData->m_Value.m_Float; + + register int const cellwidth = player->m_cellwidth; // Load it into a register + *((float*)pOut) = CoordFromCell( cellwidth, player->m_cellZ, pData->m_Value.m_Float ); } //----------------------------------------------------------------------------- @@ -2594,7 +2579,7 @@ void C_BasePlayer::NotePredictionError( const Vector &vDelta ) // offset curtime and setup bones at that time using fake interpolation // fake interpolation means we don't have reliable interpolation history (the local player doesn't animate locally) // so we just modify cycle and origin directly and use that as a fake guess -void C_BasePlayer::ForceSetupBonesAtTimeFakeInterpolation( matrix3x4_t *pBonesOut, float curtimeOffset ) +void C_BasePlayer::ForceSetupBonesAtTimeFakeInterpolation( matrix3x4a_t *pBonesOut, float curtimeOffset ) { // we don't have any interpolation data, so fake it float cycle = m_flCycle; @@ -2606,7 +2591,7 @@ void C_BasePlayer::ForceSetupBonesAtTimeFakeInterpolation( matrix3x4_t *pBonesOu Interpolate( gpGlobals->curtime + curtimeOffset ); // force cycle back by boneDt - m_flCycle = fmod( 10 + cycle + m_flPlaybackRate * curtimeOffset, 1.0f ); + m_flCycle = fmod( 10 + cycle + GetPlaybackRate() * curtimeOffset, 1.0f ); SetLocalOrigin( origin + curtimeOffset * GetLocalVelocity() ); // Setup bone state to extrapolate physics velocity SetupBones( pBonesOut, MAXSTUDIOBONES, BONE_USED_BY_ANYTHING, gpGlobals->curtime + curtimeOffset ); @@ -2615,9 +2600,9 @@ void C_BasePlayer::ForceSetupBonesAtTimeFakeInterpolation( matrix3x4_t *pBonesOu SetLocalOrigin( origin ); } -void C_BasePlayer::GetRagdollInitBoneArrays( matrix3x4_t *pDeltaBones0, matrix3x4_t *pDeltaBones1, matrix3x4_t *pCurrentBones, float boneDt ) +void C_BasePlayer::GetRagdollInitBoneArrays( matrix3x4a_t *pDeltaBones0, matrix3x4a_t *pDeltaBones1, matrix3x4a_t *pCurrentBones, float boneDt ) { - if ( !IsLocalPlayer() ) + if ( !C_BasePlayer::IsLocalPlayer( this ) ) { BaseClass::GetRagdollInitBoneArrays(pDeltaBones0, pDeltaBones1, pCurrentBones, boneDt); return; @@ -2690,9 +2675,9 @@ bool IsInFreezeCam( void ) //----------------------------------------------------------------------------- void C_BasePlayer::FogControllerChanged( bool bSnap ) { - if ( m_Local.m_PlayerFog.m_hCtrl ) + if ( m_PlayerFog.m_hCtrl ) { - fogparams_t *pFogParams = &(m_Local.m_PlayerFog.m_hCtrl->m_fog); + fogparams_t *pFogParams = &(m_PlayerFog.m_hCtrl->m_fog); /* Msg("Updating Fog Target: (%d,%d,%d) %.0f,%.0f -> (%d,%d,%d) %.0f,%.0f (%.2f seconds)\n", @@ -2703,15 +2688,21 @@ void C_BasePlayer::FogControllerChanged( bool bSnap ) // Setup the fog color transition. - m_Local.m_PlayerFog.m_OldColor = m_CurrentFog.colorPrimary; - m_Local.m_PlayerFog.m_flOldStart = m_CurrentFog.start; - m_Local.m_PlayerFog.m_flOldEnd = m_CurrentFog.end; - - m_Local.m_PlayerFog.m_NewColor = pFogParams->colorPrimary; - m_Local.m_PlayerFog.m_flNewStart = pFogParams->start; - m_Local.m_PlayerFog.m_flNewEnd = pFogParams->end; - - m_Local.m_PlayerFog.m_flTransitionTime = bSnap ? -1 : gpGlobals->curtime; + m_PlayerFog.m_OldColor = m_CurrentFog.colorPrimary; + m_PlayerFog.m_flOldStart = m_CurrentFog.start; + m_PlayerFog.m_flOldEnd = m_CurrentFog.end; + m_PlayerFog.m_flOldMaxDensity = m_CurrentFog.maxdensity; + m_PlayerFog.m_flOldHDRColorScale = m_CurrentFog.HDRColorScale; + m_PlayerFog.m_flOldFarZ = m_CurrentFog.farz; + + m_PlayerFog.m_NewColor = pFogParams->colorPrimary; + m_PlayerFog.m_flNewStart = pFogParams->start; + m_PlayerFog.m_flNewEnd = pFogParams->end; + m_PlayerFog.m_flNewMaxDensity = pFogParams->maxdensity; + m_PlayerFog.m_flNewHDRColorScale = pFogParams->HDRColorScale; + m_PlayerFog.m_flNewFarZ = pFogParams->farz; + + m_PlayerFog.m_flTransitionTime = bSnap ? -1 : gpGlobals->curtime; m_CurrentFog = *pFogParams; @@ -2725,12 +2716,12 @@ void C_BasePlayer::FogControllerChanged( bool bSnap ) //----------------------------------------------------------------------------- void C_BasePlayer::UpdateFogController( void ) { - if ( m_Local.m_PlayerFog.m_hCtrl ) + if ( m_PlayerFog.m_hCtrl ) { // Don't bother copying while we're transitioning, since it'll be stomped in UpdateFogBlend(); - if ( m_Local.m_PlayerFog.m_flTransitionTime == -1 && (m_hOldFogController == m_Local.m_PlayerFog.m_hCtrl) ) + if ( m_PlayerFog.m_flTransitionTime == -1 && (m_hOldFogController == m_PlayerFog.m_hCtrl) ) { - fogparams_t *pFogParams = &(m_Local.m_PlayerFog.m_hCtrl->m_fog); + fogparams_t *pFogParams = &(m_PlayerFog.m_hCtrl->m_fog); if ( m_CurrentFog != *pFogParams ) { /* @@ -2765,27 +2756,43 @@ void C_BasePlayer::UpdateFogController( void ) void C_BasePlayer::UpdateFogBlend( void ) { // Transition. - if ( m_Local.m_PlayerFog.m_flTransitionTime != -1 ) + if ( m_PlayerFog.m_flTransitionTime != -1 ) { - float flTimeDelta = gpGlobals->curtime - m_Local.m_PlayerFog.m_flTransitionTime; + float flTimeDelta = gpGlobals->curtime - m_PlayerFog.m_flTransitionTime; if ( flTimeDelta < m_CurrentFog.duration ) { float flScale = flTimeDelta / m_CurrentFog.duration; - m_CurrentFog.colorPrimary.SetR( ( m_Local.m_PlayerFog.m_NewColor.r * flScale ) + ( m_Local.m_PlayerFog.m_OldColor.r * ( 1.0f - flScale ) ) ); - m_CurrentFog.colorPrimary.SetG( ( m_Local.m_PlayerFog.m_NewColor.g * flScale ) + ( m_Local.m_PlayerFog.m_OldColor.g * ( 1.0f - flScale ) ) ); - m_CurrentFog.colorPrimary.SetB( ( m_Local.m_PlayerFog.m_NewColor.b * flScale ) + ( m_Local.m_PlayerFog.m_OldColor.b * ( 1.0f - flScale ) ) ); - m_CurrentFog.start.Set( ( m_Local.m_PlayerFog.m_flNewStart * flScale ) + ( ( m_Local.m_PlayerFog.m_flOldStart * ( 1.0f - flScale ) ) ) ); - m_CurrentFog.end.Set( ( m_Local.m_PlayerFog.m_flNewEnd * flScale ) + ( ( m_Local.m_PlayerFog.m_flOldEnd * ( 1.0f - flScale ) ) ) ); + m_CurrentFog.colorPrimary.SetR( ( m_PlayerFog.m_NewColor.r * flScale ) + ( m_PlayerFog.m_OldColor.r * ( 1.0f - flScale ) ) ); + m_CurrentFog.colorPrimary.SetG( ( m_PlayerFog.m_NewColor.g * flScale ) + ( m_PlayerFog.m_OldColor.g * ( 1.0f - flScale ) ) ); + m_CurrentFog.colorPrimary.SetB( ( m_PlayerFog.m_NewColor.b * flScale ) + ( m_PlayerFog.m_OldColor.b * ( 1.0f - flScale ) ) ); + m_CurrentFog.start.Set( ( m_PlayerFog.m_flNewStart * flScale ) + ( ( m_PlayerFog.m_flOldStart * ( 1.0f - flScale ) ) ) ); + m_CurrentFog.end.Set( ( m_PlayerFog.m_flNewEnd * flScale ) + ( ( m_PlayerFog.m_flOldEnd * ( 1.0f - flScale ) ) ) ); + m_CurrentFog.maxdensity.Set( ( m_PlayerFog.m_flNewMaxDensity * flScale ) + ( ( m_PlayerFog.m_flOldMaxDensity * ( 1.0f - flScale ) ) ) ); + m_CurrentFog.HDRColorScale.Set( ( m_PlayerFog.m_flNewHDRColorScale * flScale ) + ( ( m_PlayerFog.m_flOldHDRColorScale * ( 1.0f - flScale ) ) ) ); + + // Lerp to a sane FarZ (default value comes from CViewRender::GetZFar()) + float newFarZ = m_PlayerFog.m_flNewFarZ; + if ( newFarZ <= 0 ) + newFarZ = r_mapextents.GetFloat() * 1.73205080757f; + + float oldFarZ = m_PlayerFog.m_flOldFarZ; + if ( oldFarZ <= 0 ) + oldFarZ = r_mapextents.GetFloat() * 1.73205080757f; + + m_CurrentFog.farz.Set( ( newFarZ * flScale ) + ( ( oldFarZ * ( 1.0f - flScale ) ) ) ); } else { // Slam the final fog values. - m_CurrentFog.colorPrimary.SetR( m_Local.m_PlayerFog.m_NewColor.r ); - m_CurrentFog.colorPrimary.SetG( m_Local.m_PlayerFog.m_NewColor.g ); - m_CurrentFog.colorPrimary.SetB( m_Local.m_PlayerFog.m_NewColor.b ); - m_CurrentFog.start.Set( m_Local.m_PlayerFog.m_flNewStart ); - m_CurrentFog.end.Set( m_Local.m_PlayerFog.m_flNewEnd ); - m_Local.m_PlayerFog.m_flTransitionTime = -1; + m_CurrentFog.colorPrimary.SetR( m_PlayerFog.m_NewColor.r ); + m_CurrentFog.colorPrimary.SetG( m_PlayerFog.m_NewColor.g ); + m_CurrentFog.colorPrimary.SetB( m_PlayerFog.m_NewColor.b ); + m_CurrentFog.start.Set( m_PlayerFog.m_flNewStart ); + m_CurrentFog.end.Set( m_PlayerFog.m_flNewEnd ); + m_CurrentFog.maxdensity.Set( m_PlayerFog.m_flNewMaxDensity ); + m_CurrentFog.HDRColorScale.Set( m_PlayerFog.m_flNewHDRColorScale ); + m_CurrentFog.farz.Set( m_PlayerFog.m_flNewFarZ ); + m_PlayerFog.m_flTransitionTime = -1; /* Msg("Finished transition to (%d,%d,%d) %.0f,%.0f\n", @@ -2797,172 +2804,70 @@ void C_BasePlayer::UpdateFogBlend( void ) } //----------------------------------------------------------------------------- -// Purpose: +// //----------------------------------------------------------------------------- -bool C_BasePlayer::GetSteamID( CSteamID *pID ) +C_PostProcessController* C_BasePlayer::GetActivePostProcessController() const { - // try to make this a little more efficient - - player_info_t pi; - if ( engine->GetPlayerInfo( entindex(), &pi ) ) - { - if ( pi.friendsID && steamapicontext && steamapicontext->SteamUtils() ) - { -#if 1 // new - static EUniverse universe = k_EUniverseInvalid; - - if ( universe == k_EUniverseInvalid ) - universe = steamapicontext->SteamUtils()->GetConnectedUniverse(); - - pID->InstancedSet( pi.friendsID, 1, universe, k_EAccountTypeIndividual ); -#else // old - pID->InstancedSet( pi.friendsID, 1, steamapicontext->SteamUtils()->GetConnectedUniverse(), k_EAccountTypeIndividual ); -#endif - - return true; - } - } - return false; + return m_hPostProcessCtrl.Get(); } -#if defined USES_ECON_ITEMS //----------------------------------------------------------------------------- -// Purpose: Update the visibility of our worn items. +// //----------------------------------------------------------------------------- -void C_BasePlayer::UpdateWearables( void ) +C_ColorCorrection* C_BasePlayer::GetActiveColorCorrection() const { - for ( int i=0; iValidateModelIndex(); - pItem->UpdateVisibility(); - } - } + return m_hColorCorrectionCtrl.Get(); } -#endif // USES_ECON_ITEMS - -//----------------------------------------------------------------------------- -// Purpose: In meathook mode, fix the bone transforms to hang the user's own -// avatar under the camera. -//----------------------------------------------------------------------------- -void C_BasePlayer::BuildFirstPersonMeathookTransformations( CStudioHdr *hdr, Vector *pos, Quaternion q[], const matrix3x4_t& cameraTransform, int boneMask, CBoneBitList &boneComputed, const char *pchHeadBoneName ) +bool C_BasePlayer::PreRender( int nSplitScreenPlayerSlot ) { - // Handle meathook mode. If we aren't rendering, just use last frame's transforms - if ( !InFirstPersonView() ) - return; - - // If we're in third-person view, don't do anything special. - // If we're in first-person view rendering the main view and using the viewmodel, we shouldn't have even got here! - // If we're in first-person view rendering the main view(s), meathook and headless. - // If we're in first-person view rendering shadowbuffers/reflections, don't do anything special either (we could do meathook but with a head?) - if ( IsAboutToRagdoll() ) - { - // We're re-animating specifically to set up the ragdoll. - // Meathook can push the player through the floor, which makes the ragdoll fall through the world, which is no good. - // So do nothing. - return; - } - - if ( !DrawingMainView() ) - { - return; - } - - // If we aren't drawing the player anyway, don't mess with the bones. This can happen in Portal. - if( !ShouldDrawThisPlayer() ) + if ( !IsVisible() || + !GetClientMode()->ShouldDrawLocalPlayer( this ) ) { - return; - } - - m_BoneAccessor.SetWritableBones( BONE_USED_BY_ANYTHING ); - - int iHead = LookupBone( pchHeadBoneName ); - if ( iHead == -1 ) - { - return; + return true; } - matrix3x4_t &mHeadTransform = GetBoneForWrite( iHead ); - - // "up" on the head bone is along the negative Y axis - not sure why. - //Vector vHeadTransformUp ( -mHeadTransform[0][1], -mHeadTransform[1][1], -mHeadTransform[2][1] ); - //Vector vHeadTransformFwd ( mHeadTransform[0][1], mHeadTransform[1][1], mHeadTransform[2][1] ); - Vector vHeadTransformTranslation ( mHeadTransform[0][3], mHeadTransform[1][3], mHeadTransform[2][3] ); - - - // Find out where the player's head (driven by the HMD) is in the world. - // We can't move this with animations or effects without causing nausea, so we need to move - // the whole body so that the animated head is in the right place to match the player-controlled head. - Vector vHeadUp; - Vector vRealPivotPoint; - if( UseVR() ) - { - VMatrix mWorldFromMideye = g_ClientVirtualReality.GetWorldFromMidEye(); + // Add in lighting effects + return CreateLightEffects(); +} - // What we do here is: - // * Take the required eye pos+orn - the actual pose the player is controlling with the HMD. - // * Go downwards in that space by cl_meathook_neck_pivot_ingame_* - this is now the neck-pivot in the game world of where the player is actually looking. - // * Now place the body of the animated character so that the head bone is at that position. - // The head bone is the neck pivot point of the in-game character. +bool C_BasePlayer::IsSplitScreenPartner( C_BasePlayer *pPlayer ) +{ + if ( !pPlayer || pPlayer == this ) + return false; - Vector vRealMidEyePos = mWorldFromMideye.GetTranslation(); - vRealPivotPoint = vRealMidEyePos - ( mWorldFromMideye.GetUp() * cl_meathook_neck_pivot_ingame_up.GetFloat() ) - ( mWorldFromMideye.GetForward() * cl_meathook_neck_pivot_ingame_fwd.GetFloat() ); - } - else + for ( int i = 0; i < MAX_SPLITSCREEN_PLAYERS; ++i ) { - // figure out where to put the body from the aim angles - Vector vForward, vRight, vUp; - AngleVectors( MainViewAngles(), &vForward, &vRight, &vUp ); - - vRealPivotPoint = MainViewOrigin() - ( vUp * cl_meathook_neck_pivot_ingame_up.GetFloat() ) - ( vForward * cl_meathook_neck_pivot_ingame_fwd.GetFloat() ); - } - - Vector vDeltaToAdd = vRealPivotPoint - vHeadTransformTranslation; + if ( s_pLocalPlayer[i] == pPlayer ) + return true; + } + return false; +} - // Now add this offset to the entire skeleton. - for (int i = 0; i < hdr->numbones(); i++) - { - // Only update bones reference by the bone mask. - if ( !( hdr->boneFlags( i ) & boneMask ) ) - { - continue; - } - matrix3x4_t& bone = GetBoneForWrite( i ); - Vector vBonePos; - MatrixGetTranslation ( bone, vBonePos ); - vBonePos += vDeltaToAdd; - MatrixSetTranslation ( vBonePos, bone ); - } +int C_BasePlayer::GetSplitScreenPlayerSlot() +{ + return m_nSplitScreenSlot; +} - // Then scale the head to zero, but leave its position - forms a "neck stub". - // This prevents us rendering junk all over the screen, e.g. inside of mouth, etc. - MatrixScaleByZero( mHeadTransform ); +bool C_BasePlayer::IsSplitScreenPlayer() const +{ + return m_nSplitScreenSlot >= 1; +} - // TODO: right now we nuke the hats by shrinking them to nothing, - // but it feels like we should do something more sensible. - // For example, for one sniper taunt he takes his hat off and waves it - would be nice to see it then. - int iHelm = LookupBone( "prp_helmet" ); - if ( iHelm != -1 ) - { - // Scale the helmet. - matrix3x4_t &transformhelmet = GetBoneForWrite( iHelm ); - MatrixScaleByZero( transformhelmet ); - } +bool C_BasePlayer::ShouldRegenerateOriginFromCellBits() const +{ + // Don't use cell bits for local players. + // Assumes full update for local players! + int nSlot = GET_ACTIVE_SPLITSCREEN_SLOT(); + int nIndex = engine->GetSplitScreenPlayer( nSlot ); + if ( nIndex == entindex() ) + return false; - iHelm = LookupBone( "prp_hat" ); - if ( iHelm != -1 ) - { - matrix3x4_t &transformhelmet = GetBoneForWrite( iHelm ); - MatrixScaleByZero( transformhelmet ); - } + return BaseClass::ShouldRegenerateOriginFromCellBits(); } - void CC_DumpClientSoundscapeData( const CCommand& args ) { C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); @@ -2971,16 +2876,8 @@ void CC_DumpClientSoundscapeData( const CCommand& args ) Msg("Client Soundscape data dump:\n"); Msg(" Position: %.2f %.2f %.2f\n", pPlayer->GetAbsOrigin().x, pPlayer->GetAbsOrigin().y, pPlayer->GetAbsOrigin().z ); - Msg(" soundscape index: %d\n", pPlayer->m_Local.m_audio.soundscapeIndex.Get() ); - Msg(" entity index: %d\n", pPlayer->m_Local.m_audio.ent.Get() ? pPlayer->m_Local.m_audio.ent->entindex() : -1 ); - if ( pPlayer->m_Local.m_audio.ent.Get() ) - { - Msg(" entity pos: %.2f %.2f %.2f\n", pPlayer->m_Local.m_audio.ent.Get()->GetAbsOrigin().x, pPlayer->m_Local.m_audio.ent.Get()->GetAbsOrigin().y, pPlayer->m_Local.m_audio.ent.Get()->GetAbsOrigin().z ); - if ( pPlayer->m_Local.m_audio.ent.Get()->IsDormant() ) - { - Msg(" ENTITY IS DORMANT\n"); - } - } + Msg(" soundscape index: %d\n", pPlayer->m_Local.m_audio.soundscapeIndex ); + Msg(" entity index: %d\n", pPlayer->m_Local.m_audio.entIndex ); bool bFoundOne = false; for ( int i = 0; i < NUM_AUDIO_LOCAL_SOUNDS; i++ ) { diff --git a/game/client/c_baseplayer.h b/game/client/c_baseplayer.h index 9d3657bf6..505380ff9 100644 --- a/game/client/c_baseplayer.h +++ b/game/client/c_baseplayer.h @@ -1,10 +1,10 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: Client-side CBasePlayer. // // - Manages the player's flashlight effect. // -//=============================================================================// +//===========================================================================// #ifndef C_BASEPLAYER_H #define C_BASEPLAYER_H @@ -14,29 +14,21 @@ #include "c_playerlocaldata.h" #include "c_basecombatcharacter.h" -#include "PlayerState.h" +#include "playerstate.h" #include "usercmd.h" #include "shareddefs.h" #include "timedevent.h" #include "smartptr.h" #include "fx_water.h" #include "hintsystem.h" -#include "SoundEmitterSystem/isoundemittersystembase.h" +#include "soundemittersystem/isoundemittersystembase.h" #include "c_env_fog_controller.h" -#include "igameevents.h" -#include "GameEventListener.h" - -#if defined USES_ECON_ITEMS -#include "econ_item.h" -#include "game_item_schema.h" -#include "econ_item_view.h" -#endif +#include "C_PostProcessController.h" +#include "C_ColorCorrection.h" class C_BaseCombatWeapon; class C_BaseViewModel; class C_FuncLadder; -class CFlashlightEffect; -class C_EconWearable; extern int g_nKillCamMode; extern int g_nKillCamTarget1; @@ -58,17 +50,24 @@ class C_PredictionError Vector error; }; -#define CHASE_CAM_DISTANCE_MIN 16.0f -#define CHASE_CAM_DISTANCE_MAX 96.0f +#define CHASE_CAM_DISTANCE 96.0f #define WALL_OFFSET 6.0f +enum PlayerRenderMode_t +{ + PLAYER_RENDER_NONE = 0, + PLAYER_RENDER_FIRSTPERSON, + PLAYER_RENDER_THIRDPERSON, +}; + + bool IsInFreezeCam( void ); //----------------------------------------------------------------------------- // Purpose: Base Player class //----------------------------------------------------------------------------- -class C_BasePlayer : public C_BaseCombatCharacter, public CGameEventListener +class C_BasePlayer : public C_BaseCombatCharacter { public: DECLARE_CLASS( C_BasePlayer, C_BaseCombatCharacter ); @@ -81,7 +80,7 @@ class C_BasePlayer : public C_BaseCombatCharacter, public CGameEventListener virtual void Spawn( void ); virtual void SharedSpawn(); // Shared between client and server. - virtual bool GetSteamID( CSteamID *pID ); + Class_T Classify( void ) { return CLASS_PLAYER; } // IClientEntity overrides. virtual void OnPreDataChanged( DataUpdateType_t updateType ); @@ -94,17 +93,13 @@ class C_BasePlayer : public C_BaseCombatCharacter, public CGameEventListener virtual void OnRestore(); - virtual void AddEntity( void ); - virtual void MakeTracer( const Vector &vecTracerSrc, const trace_t &tr, int iTracerType ); virtual void GetToolRecordingState( KeyValues *msg ); - virtual float GetPlayerMaxSpeed(); - void SetAnimationExtension( const char *pExtension ); - C_BaseViewModel *GetViewModel( int viewmodelindex = 0, bool bObserverOK=true ); + C_BaseViewModel *GetViewModel( int viewmodelindex = 0 ); C_BaseCombatWeapon *GetActiveWeapon( void ) const; const char *GetTracerType( void ); @@ -117,17 +112,21 @@ class C_BasePlayer : public C_BaseCombatCharacter, public CGameEventListener void SmoothViewOnStairs( Vector& eyeOrigin ); virtual float CalcRoll (const QAngle& angles, const Vector& velocity, float rollangle, float rollspeed); void CalcViewRoll( QAngle& eyeAngles ); + virtual void CalcViewBob( Vector& eyeOrigin ); void CreateWaterEffects( void ); virtual void SetPlayerUnderwater( bool state ); void UpdateUnderwaterState( void ); bool IsPlayerUnderwater( void ) { return m_bPlayerUnderwater; } + virtual C_BaseCombatCharacter *ActivePlayerCombatCharacter( void ) { return this; } + virtual Vector Weapon_ShootPosition(); + virtual bool Weapon_CanUse( C_BaseCombatWeapon *pWeapon ); virtual void Weapon_DropPrimary( void ) {} virtual Vector GetAutoaimVector( float flScale ); - void SetSuitUpdate(const char *name, int fgroup, int iNoRepeat); + void SetSuitUpdate(char *name, int fgroup, int iNoRepeat); // Input handling virtual bool CreateMove( float flInputSampleTime, CUserCmd *pCmd ); @@ -146,7 +145,6 @@ class C_BasePlayer : public C_BaseCombatCharacter, public CGameEventListener // observer mode virtual int GetObserverMode() const; - void SetObserverMode ( int iNewMode ); virtual CBaseEntity *GetObserverTarget() const; void SetObserverTarget( EHANDLE hObserverTarget ); @@ -169,7 +167,7 @@ class C_BasePlayer : public C_BaseCombatCharacter, public CGameEventListener virtual IRagdoll* GetRepresentativeRagdoll() const; // override the initial bone position for ragdolls - virtual void GetRagdollInitBoneArrays( matrix3x4_t *pDeltaBones0, matrix3x4_t *pDeltaBones1, matrix3x4_t *pCurrentBones, float boneDt ); + virtual void GetRagdollInitBoneArrays( matrix3x4a_t *pDeltaBones0, matrix3x4a_t *pDeltaBones1, matrix3x4a_t *pCurrentBones, float boneDt ); // Returns eye vectors void EyeVectors( Vector *pForward, Vector *pRight = NULL, Vector *pUp = NULL ); @@ -184,6 +182,17 @@ class C_BasePlayer : public C_BaseCombatCharacter, public CGameEventListener // Flashlight void Flashlight( void ); void UpdateFlashlight( void ); + void TurnOffFlashlight( void ); // TERROR + virtual const char *GetFlashlightTextureName( void ) const { return NULL; } // TERROR + virtual float GetFlashlightFOV( void ) const { return 0.0f; } // TERROR + virtual float GetFlashlightFarZ( void ) const { return 0.0f; } // TERROR + virtual float GetFlashlightLinearAtten( void ) const { return 0.0f; } // TERROR + virtual bool CastsFlashlightShadows( void ) const { return true; } // TERROR + virtual void GetFlashlightOffset( const Vector &vecForward, const Vector &vecRight, const Vector &vecUp, Vector *pVecOffset ) const; + Vector m_vecFlashlightOrigin; + Vector m_vecFlashlightForward; + Vector m_vecFlashlightUp; + Vector m_vecFlashlightRight; // Weapon selection code virtual bool IsAllowedToSwitchWeapons( void ) { return !IsObserver(); } @@ -195,7 +204,7 @@ class C_BasePlayer : public C_BaseCombatCharacter, public CGameEventListener virtual C_BaseAnimating* GetRenderedWeaponModel(); virtual bool IsOverridingViewmodel( void ) { return false; }; - virtual int DrawOverriddenViewmodel( C_BaseViewModel *pViewmodel, int flags ) { return 0; }; + virtual int DrawOverriddenViewmodel( C_BaseViewModel *pViewmodel, int flags, const RenderableInstance_t &instance ) { return 0; }; virtual float GetDefaultAnimSpeed( void ) { return 1.0; } @@ -211,27 +220,40 @@ class C_BasePlayer : public C_BaseCombatCharacter, public CGameEventListener } - bool IsLocalPlayer( void ) const; + // Makes sure s_pLocalPlayer is properly initialized + void CheckForLocalPlayer( int nSplitScreenSlot ); + + /// Is the passed in player one of the split screen users + static bool IsLocalPlayer( const C_BaseEntity *pl ); + /// is this player a local player ( call when you have already verified that your pointer really is a C_BasePlayer ) + inline bool IsLocalPlayer( void ) const; // Global/static methods virtual void ThirdPersonSwitch( bool bThirdperson ); - static bool LocalPlayerInFirstPersonView(); - static bool ShouldDrawLocalPlayer(); - static C_BasePlayer *GetLocalPlayer( void ); - int GetUserID( void ); + bool ShouldDrawLocalPlayer(); + static C_BasePlayer *GetLocalPlayer( int nSlot = -1 ); + static void SetRemoteSplitScreenPlayerViewsAreLocalPlayer( bool bSet ); //if true, calls to GetLocalPlayer() will return a remote splitscreen player when applicable. + static bool HasAnyLocalPlayer(); + static int GetSplitScreenSlotForPlayer( C_BaseEntity *pl ); + + void AddSplitScreenPlayer( C_BasePlayer *pOther ); + void RemoveSplitScreenPlayer( C_BasePlayer *pOther ); + CUtlVector< CHandle< C_BasePlayer > > &GetSplitScreenPlayers(); + + bool IsSplitScreenPartner( C_BasePlayer *pPlayer ); + + bool IsSplitScreenPlayer() const; + int GetSplitScreenPlayerSlot(); + + virtual IClientModelRenderable* GetClientModelRenderable(); + virtual bool PreRender( int nSplitScreenPlayerSlot ); + + int GetUserID( void ) const; virtual bool CanSetSoundMixer( void ); - virtual int GetVisionFilterFlags( bool bWeaponsCheck = false ) { return 0x00; } - bool HasVisionFilterFlags( int nFlags, bool bWeaponsCheck = false ) { return ( GetVisionFilterFlags( bWeaponsCheck ) & nFlags ) == nFlags; } - virtual void CalculateVisionUsingCurrentFlags( void ) {} - void BuildFirstPersonMeathookTransformations( CStudioHdr *hdr, Vector *pos, Quaternion q[], const matrix3x4_t& cameraTransform, int boneMask, CBoneBitList &boneComputed, const char *pchHeadBoneName ); - // Specific queries about this player. - bool InFirstPersonView(); - bool ShouldDrawThisPlayer(); + // return the entity used for soundscape radius checks + virtual C_BaseEntity *GetSoundscapeListener(); - // Called by the view model if its rendering is being overridden. - virtual bool ViewModel_IsTransparent( void ); - virtual bool ViewModel_IsUsingFBTexture( void ); #if !defined( NO_ENTITY_PREDICTION ) void AddToPlayerSimulationList( C_BaseEntity *other ); @@ -245,6 +267,7 @@ class C_BasePlayer : public C_BaseCombatCharacter, public CGameEventListener // Prediction stuff virtual bool ShouldPredict( void ); + virtual C_BasePlayer *GetPredictionOwner( void ); virtual void PreThink( void ); virtual void PostThink( void ); @@ -264,10 +287,10 @@ class C_BasePlayer : public C_BaseCombatCharacter, public CGameEventListener virtual void UpdateClientData( void ); - virtual float GetFOV( void ); - int GetDefaultFOV( void ) const; + virtual float GetFOV( void ) const; + virtual int GetDefaultFOV( void ) const; virtual bool IsZoomed( void ) { return false; } - bool SetFOV( CBaseEntity *pRequester, int FOV, float zoomRate = 0.0f, int iZoomStart = 0 ); + bool SetFOV( CBaseEntity *pRequester, int FOV, float zoomRate, int iZoomStart = 0 ); void ClearZoomOwner( void ); float GetFOVDistanceAdjustFactor(); @@ -278,29 +301,35 @@ class C_BasePlayer : public C_BaseCombatCharacter, public CGameEventListener void UpdateButtonState( int nUserCmdButtonMask ); int GetImpulse( void ) const; - virtual void Simulate(); + virtual bool Simulate(); virtual bool ShouldInterpolate(); virtual bool ShouldDraw(); - virtual int DrawModel( int flags ); + virtual int DrawModel( int flags, const RenderableInstance_t &instance ); // Called when not in tactical mode. Allows view to be overriden for things like driving a tank. virtual void OverrideView( CViewSetup *pSetup ); + C_BaseEntity *GetViewEntity( void ) const { return m_hViewEntity; } + // returns the player name const char * GetPlayerName(); virtual const Vector GetPlayerMins( void ) const; // uses local player virtual const Vector GetPlayerMaxs( void ) const; // uses local player + virtual void UpdateCollisionBounds( void ); + // Is the player dead? bool IsPlayerDead(); bool IsPoisoned( void ) { return m_Local.m_bPoisoned; } - C_BaseEntity *GetUseEntity(); + virtual C_BaseEntity* GetUseEntity( void ) const; + virtual C_BaseEntity* GetPotentialUseEntity( void ) const; // Vehicles... IClientVehicle *GetVehicle(); + const IClientVehicle *GetVehicle() const; bool IsInAVehicle() const { return ( NULL != m_hVehicle.Get() ) ? true : false; } virtual void SetVehicleRole( int nRole ); @@ -322,7 +351,7 @@ class C_BasePlayer : public C_BaseCombatCharacter, public CGameEventListener int CurrentCommandNumber() const; const CUserCmd *GetCurrentUserCommand() const; - const QAngle& GetPunchAngle(); + virtual const QAngle& GetPunchAngle(); void SetPunchAngle( const QAngle &angle ); float GetWaterJumpTime() const; @@ -346,9 +375,6 @@ class C_BasePlayer : public C_BaseCombatCharacter, public CGameEventListener virtual surfacedata_t * GetFootstepSurface( const Vector &origin, const char *surfaceName ); virtual void GetStepSoundVelocities( float *velwalk, float *velrun ); virtual void SetStepSoundTime( stepsoundtimes_t iStepSoundTime, bool bWalking ); - virtual const char *GetOverrideStepSound( const char *pszBaseStepSoundName ) { return pszBaseStepSoundName; } - - virtual void OnEmitFootstepSound( const CSoundParameters& params, const Vector& vecOrigin, float fVolume ) {} // Called by prediction when it detects a prediction correction. // vDelta is the line from where the client had predicted the player to at the usercmd in question, @@ -361,9 +387,13 @@ class C_BasePlayer : public C_BaseCombatCharacter, public CGameEventListener virtual void ExitLadder() {} surfacedata_t *GetLadderSurface( const Vector &origin ); - surfacedata_t *GetSurfaceData( void ) { return m_pSurfaceData; } + void ForceButtons( int nButtons ); + void UnforceButtons( int nButtons ); + void SetLadderNormal( Vector vecLadderNormal ) { m_vecLadderNormal = vecLadderNormal; } + const Vector &GetLadderNormal( void ) const { return m_vecLadderNormal; } + int GetLadderSurfaceProps( void ) const { return m_ladderSurfaceProps; } // Hints virtual CHintSystem *Hints( void ) { return NULL; } @@ -374,89 +404,142 @@ class C_BasePlayer : public C_BaseCombatCharacter, public CGameEventListener virtual IMaterial *GetHeadLabelMaterial( void ); // Fog - fogparams_t *GetFogParams( void ) { return &m_CurrentFog; } + virtual fogparams_t *GetFogParams( void ) { return &m_CurrentFog; } void FogControllerChanged( bool bSnap ); void UpdateFogController( void ); void UpdateFogBlend( void ); + C_PostProcessController* GetActivePostProcessController() const; + C_ColorCorrection* GetActiveColorCorrection() const; + + void IncrementEFNoInterpParity(); + int GetEFNoInterpParity() const; + float GetFOVTime( void ){ return m_flFOVTime; } - virtual void OnAchievementAchieved( int iAchievement ) {} - - bool ShouldAnnounceAchievement( void ){ return m_flNextAchievementAnnounceTime < gpGlobals->curtime; } - void SetNextAchievementAnnounceTime( float flTime ){ m_flNextAchievementAnnounceTime = flTime; } - -#if defined USES_ECON_ITEMS - // Wearables - void UpdateWearables(); - C_EconWearable *GetWearable( int i ) { return m_hMyWearables[i]; } - int GetNumWearables( void ) { return m_hMyWearables.Count(); } -#endif + PlayerRenderMode_t GetPlayerRenderMode( int nSlot ); - bool HasFiredWeapon( void ) { return m_bFiredWeapon; } - void SetFiredWeapon( bool bFlag ) { m_bFiredWeapon = bFlag; } + virtual void OnAchievementAchieved( int iAchievement ) {} - virtual bool CanUseFirstPersonCommand( void ){ return true; } - protected: fogparams_t m_CurrentFog; EHANDLE m_hOldFogController; +public: + // RecvProxies + static void RecvProxy_LocalVelocityX( const CRecvProxyData *pData, void *pStruct, void *pOut ); + static void RecvProxy_LocalVelocityY( const CRecvProxyData *pData, void *pStruct, void *pOut ); + static void RecvProxy_LocalVelocityZ( const CRecvProxyData *pData, void *pStruct, void *pOut ); + + static void RecvProxy_ObserverTarget( const CRecvProxyData *pData, void *pStruct, void *pOut ); + static void RecvProxy_ObserverMode( const CRecvProxyData *pData, void *pStruct, void *pOut ); + + static void RecvProxy_LocalOriginXY( const CRecvProxyData *pData, void *pStruct, void *pOut ); + static void RecvProxy_LocalOriginZ( const CRecvProxyData *pData, void *pStruct, void *pOut ); + static void RecvProxy_NonLocalOriginXY( const CRecvProxyData *pData, void *pStruct, void *pOut ); + static void RecvProxy_NonLocalOriginZ( const CRecvProxyData *pData, void *pStruct, void *pOut ); + static void RecvProxy_NonLocalCellOriginXY( const CRecvProxyData *pData, void *pStruct, void *pOut ); + static void RecvProxy_NonLocalCellOriginZ( const CRecvProxyData *pData, void *pStruct, void *pOut ); + + virtual bool ShouldRegenerateOriginFromCellBits() const; + public: int m_StuckLast; // Data for only the local player CNetworkVarEmbedded( CPlayerLocalData, m_Local ); -#if defined USES_ECON_ITEMS - CNetworkVarEmbedded( CAttributeList, m_AttributeList ); -#endif + EHANDLE m_hTonemapController; // Data common to all other players, too CPlayerState pl; +public: +// BEGIN PREDICTION DATA COMPACTION (these fields are together to allow for faster copying in prediction system) + +// FTYPEDESC_INSENDTABLE STUFF // Player FOV values int m_iFOV; // field of view int m_iFOVStart; // starting value of the FOV changing over time (client only) + int m_afButtonLast; + int m_afButtonPressed; + int m_afButtonReleased; + int m_nButtons; +protected: + int m_nImpulse; + CNetworkVar( int, m_ladderSurfaceProps ); + int m_flPhysics; +public: float m_flFOVTime; // starting time of the FOV zoom - int m_iDefaultFOV; // default FOV if no other zooms are occurring +private: + float m_flWaterJumpTime; // used to be called teleport_time + float m_flSwimSoundTime; +protected: + float m_flStepSoundTime; + float m_surfaceFriction; +private: + CNetworkVector( m_vecLadderNormal ); + +// FTYPEDESC_INSENDTABLE STUFF (end) +public: + char m_szAnimExtension[32]; +private: + int m_nOldTickBase; +private: + int m_iBonusProgress; + int m_iBonusChallenge; + +private: + float m_flMaxspeed; + + +public: EHANDLE m_hZoomOwner; // This is a pointer to the entity currently controlling the player's zoom - // Only this entity can change the zoom state once it has ownership +private: + EHANDLE m_hVehicle; + typedef CHandle CBaseCombatWeaponHandle; + CBaseCombatWeaponHandle m_hLastWeapon; + // players own view models, left & right hand + CHandle< C_BaseViewModel > m_hViewModel[ MAX_VIEWMODELS ]; +public: // For weapon prediction - bool m_fOnTarget; //Is the crosshair on a target? - - char m_szAnimExtension[32]; + bool m_fOnTarget; //Is the crosshair on a target? - int m_afButtonLast; - int m_afButtonPressed; - int m_afButtonReleased; - int m_nButtons; + +// END PREDICTION DATA COMPACTION +public: + + + int m_iDefaultFOV; // default FOV if no other zooms are occurring + // Only this entity can change the zoom state once it has ownership + int m_afButtonForced; // These are forced onto the player's inputs + CUserCmd *m_pCurrentCommand; + EHANDLE m_hViewEntity; + // Movement constraints EHANDLE m_hConstraintEntity; Vector m_vecConstraintCenter; float m_flConstraintRadius; float m_flConstraintWidth; float m_flConstraintSpeedFactor; + bool m_bConstraintPastRadius; protected: - void CalcPlayerView( Vector& eyeOrigin, QAngle& eyeAngles, float& fov ); + virtual void CalcPlayerView( Vector& eyeOrigin, QAngle& eyeAngles, float& fov ); void CalcVehicleView(IClientVehicle *pVehicle, Vector& eyeOrigin, QAngle& eyeAngles, float& zNear, float& zFar, float& fov ); virtual void CalcObserverView( Vector& eyeOrigin, QAngle& eyeAngles, float& fov ); virtual Vector GetChaseCamViewOffset( CBaseEntity *target ); void CalcChaseCamView( Vector& eyeOrigin, QAngle& eyeAngles, float& fov ); - virtual void CalcInEyeCamView( Vector& eyeOrigin, QAngle& eyeAngles, float& fov ); - - virtual float GetDeathCamInterpolationTime(); - + void CalcInEyeCamView( Vector& eyeOrigin, QAngle& eyeAngles, float& fov ); virtual void CalcDeathCamView( Vector& eyeOrigin, QAngle& eyeAngles, float& fov ); - void CalcRoamingView(Vector& eyeOrigin, QAngle& eyeAngles, float& fov); + virtual void CalcRoamingView(Vector& eyeOrigin, QAngle& eyeAngles, float& fov); virtual void CalcFreezeCamView( Vector& eyeOrigin, QAngle& eyeAngles, float& fov ); // Check to see if we're in vgui input mode... @@ -469,8 +552,6 @@ class C_BasePlayer : public C_BaseCombatCharacter, public CGameEventListener // used by client side player footsteps surfacedata_t* GetGroundSurface(); - virtual void FireGameEvent( IGameEvent *event ); - protected: // Did we just enter a vehicle this frame? bool JustEnteredVehicle(); @@ -485,8 +566,6 @@ class C_BasePlayer : public C_BaseCombatCharacter, public CGameEventListener bool m_bWasFreezeFraming; float m_flDeathTime; // last time player died - float m_flStepSoundTime; - bool m_IsFootprintOnLeft; private: // Make sure no one calls this... @@ -494,50 +573,33 @@ class C_BasePlayer : public C_BaseCombatCharacter, public CGameEventListener C_BasePlayer( const C_BasePlayer & ); // not defined, not accessible // Vehicle stuff. - EHANDLE m_hVehicle; EHANDLE m_hOldVehicle; EHANDLE m_hUseEntity; - float m_flMaxspeed; - - int m_iBonusProgress; - int m_iBonusChallenge; - CInterpolatedVar< Vector > m_iv_vecViewOffset; // Not replicated Vector m_vecWaterJumpVel; - float m_flWaterJumpTime; // used to be called teleport_time - int m_nImpulse; - float m_flSwimSoundTime; - Vector m_vecLadderNormal; - + +protected: QAngle m_vecOldViewAngles; +private: bool m_bWasFrozen; - int m_flPhysics; int m_nTickBase; int m_nFinalPredictedTick; EHANDLE m_pCurrentVguiScreen; - bool m_bFiredWeapon; - // Player flashlight dynamic light pointers - CFlashlightEffect *m_pFlashlight; - - typedef CHandle CBaseCombatWeaponHandle; - CNetworkVar( CBaseCombatWeaponHandle, m_hLastWeapon ); + bool m_bFlashlightEnabled[ MAX_SPLITSCREEN_PLAYERS ]; #if !defined( NO_ENTITY_PREDICTION ) CUtlVector< CHandle< C_BaseEntity > > m_SimulatedByThisPlayer; #endif - - // players own view models, left & right hand - CHandle< C_BaseViewModel > m_hViewModel[ MAX_VIEWMODELS ]; float m_flOldPlayerZ; float m_flOldPlayerViewOffsetZ; @@ -561,16 +623,17 @@ class C_BasePlayer : public C_BaseCombatCharacter, public CGameEventListener bool m_bPlayerUnderwater; friend class CPrediction; + friend class CASW_Prediction; // HACK FOR TF2 Prediction friend class CTFGameMovementRecon; friend class CGameMovement; friend class CTFGameMovement; - friend class CHL1GameMovement; friend class CCSGameMovement; friend class CHL2GameMovement; - friend class CDODGameMovement; friend class CPortalGameMovement; + friend class CASW_MarineGameMovement; + friend class CPaintGameMovement; // Accessors for gamemovement float GetStepSize( void ) const { return m_Local.m_flStepSize; } @@ -585,7 +648,7 @@ class C_BasePlayer : public C_BaseCombatCharacter, public CGameEventListener virtual bool IsDucked( void ) const { return m_Local.m_bDucked; } virtual bool IsDucking( void ) const { return m_Local.m_bDucking; } virtual float GetFallVelocity( void ) { return m_Local.m_flFallVelocity; } - void ForceSetupBonesAtTimeFakeInterpolation( matrix3x4_t *pBonesOut, float curtimeOffset ); + void ForceSetupBonesAtTimeFakeInterpolation( matrix3x4a_t *pBonesOut, float curtimeOffset ); float m_flLaggedMovementValue; @@ -602,20 +665,18 @@ class C_BasePlayer : public C_BaseCombatCharacter, public CGameEventListener // Texture names and surface data, used by CGameMovement int m_surfaceProps; surfacedata_t* m_pSurfaceData; - float m_surfaceFriction; char m_chTextureType; bool m_bSentFreezeFrame; float m_flFreezeZOffset; + byte m_ubEFNoInterpParity; + byte m_ubOldEFNoInterpParity; - float m_flNextAchievementAnnounceTime; - - int m_nForceVisionFilterFlags; // Force our vision filter to a specific setting - -#if defined USES_ECON_ITEMS - // Wearables - CUtlVector > m_hMyWearables; -#endif + // If we have any attached split users, this is the list of them + CUtlVector< CHandle< CBasePlayer > > m_hSplitScreenPlayers; + int m_nSplitScreenSlot; //-1 == not a split player + CHandle< CBasePlayer > m_hSplitOwner; + bool m_bIsLocalPlayer; private: @@ -636,6 +697,17 @@ class C_BasePlayer : public C_BaseCombatCharacter, public CGameEventListener bool ShouldGoSouth( Vector vNPCForward, Vector vNPCRight ); //Such a bad name. void SetOldPlayerZ( float flOld ) { m_flOldPlayerZ = flOld; } + + const fogplayerparams_t& GetPlayerFog() const { return m_PlayerFog; } + +private: + friend class CMoveHelperClient; + + CNetworkHandle( CPostProcessController, m_hPostProcessCtrl ); // active postprocessing controller + CNetworkHandle( CColorCorrection, m_hColorCorrectionCtrl ); // active FXVolume color correction + + // fog params + fogplayerparams_t m_PlayerFog; }; EXTERN_RECV_TABLE(DT_BasePlayer); @@ -655,12 +727,20 @@ inline C_BasePlayer *ToBasePlayer( C_BaseEntity *pEntity ) return static_cast( pEntity ); } -inline C_BaseEntity *C_BasePlayer::GetUseEntity() -{ - return m_hUseEntity; +inline const C_BasePlayer *ToBasePlayer( const C_BaseEntity *pEntity ) +{ + if ( !pEntity || !pEntity->IsPlayer() ) + return NULL; + +#if _DEBUG + Assert( dynamic_cast( pEntity ) != NULL ); +#endif + + return static_cast( pEntity ); } + inline IClientVehicle *C_BasePlayer::GetVehicle() { C_BaseEntity *pVehicleEnt = m_hVehicle.Get(); @@ -686,6 +766,8 @@ inline C_CommandContext* C_BasePlayer::GetCommandContext() inline int CBasePlayer::CurrentCommandNumber() const { Assert( m_pCurrentCommand ); + if ( !m_pCurrentCommand ) + return 0; return m_pCurrentCommand->command_number; } @@ -695,4 +777,17 @@ inline const CUserCmd *CBasePlayer::GetCurrentUserCommand() const return m_pCurrentCommand; } +extern bool g_bEngineIsHLTV; + +inline bool C_BasePlayer::IsHLTV() const +{ + return m_bIsLocalPlayer && g_bEngineIsHLTV; +} + +inline bool C_BasePlayer::IsLocalPlayer( void ) const +{ + return m_bIsLocalPlayer; +} + + #endif // C_BASEPLAYER_H diff --git a/game/client/c_basetempentity.cpp b/game/client/c_basetempentity.cpp index 91ebf0115..754f9cf3f 100644 --- a/game/client/c_basetempentity.cpp +++ b/game/client/c_basetempentity.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: Core Temp Entity client implementation. // diff --git a/game/client/c_basetempentity.h b/game/client/c_basetempentity.h index d462461c5..86217ed77 100644 --- a/game/client/c_basetempentity.h +++ b/game/client/c_basetempentity.h @@ -1,9 +1,9 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // // $NoKeywords: $ -//=============================================================================// +//===========================================================================// #ifndef C_BASETEMPENTITY_H #define C_BASETEMPENTITY_H @@ -46,7 +46,8 @@ class C_BaseTempEntity : public IClientUnknown, public IClientNetworkable virtual IClientEntity* GetIClientEntity() { return 0; } virtual C_BaseEntity* GetBaseEntity() { return 0; } virtual IClientThinkable* GetClientThinkable() { return 0; } - + virtual IClientModelRenderable* GetClientModelRenderable() { return 0; } + virtual IClientAlphaProperty* GetClientAlphaProperty() { return 0; } // IClientNetworkable overrides. public: diff --git a/game/client/c_basetoggle.cpp b/game/client/c_basetoggle.cpp new file mode 100644 index 000000000..01ba78758 --- /dev/null +++ b/game/client/c_basetoggle.cpp @@ -0,0 +1,33 @@ +//-------------------------------------------------------------------------------------------------------- +// Copyright (c) 2007 Turtle Rock Studios, Inc. + +#include "cbase.h" +#include "c_basetoggle.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +IMPLEMENT_CLIENTCLASS_DT( C_BaseToggle, DT_BaseToggle, CBaseToggle ) +END_RECV_TABLE() + + +//-------------------------------------------------------------------------------------------------------- +// Returns the velocity imparted to players standing on us. +void C_BaseToggle::GetGroundVelocityToApply( Vector &vecGroundVel ) +{ + vecGroundVel = GetLocalVelocity(); + vecGroundVel.z = 0.0f; // don't give upward velocity, or it could predict players into the air. +} + + +//-------------------------------------------------------------------------------------------------------- +IMPLEMENT_CLIENTCLASS_DT( C_BaseButton, DT_BaseButton, CBaseButton ) + RecvPropBool( RECVINFO( m_usable ) ), +END_RECV_TABLE() + + +//-------------------------------------------------------------------------------------------------------- +bool C_BaseButton::IsPotentiallyUsable( void ) +{ + return true; +} diff --git a/game/client/c_basetoggle.h b/game/client/c_basetoggle.h new file mode 100644 index 000000000..251728040 --- /dev/null +++ b/game/client/c_basetoggle.h @@ -0,0 +1,42 @@ +//-------------------------------------------------------------------------------------------------------- +// Copyright (c) 2007 Turtle Rock Studios, Inc. + +#if !defined( C_BASETOGGLE_H ) +#define C_BASETOGGLE_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "c_baseentity.h" + +//-------------------------------------------------------------------------------------------------------- +class C_BaseToggle: public C_BaseEntity +{ +public: + DECLARE_CLASS( C_BaseToggle, C_BaseEntity ); + DECLARE_CLIENTCLASS(); + + virtual void GetGroundVelocityToApply( Vector &vecGroundVel ); +}; + + +//-------------------------------------------------------------------------------------------------------- +class C_BaseButton: public C_BaseToggle +{ +public: + DECLARE_CLASS( C_BaseButton, C_BaseToggle ); + DECLARE_CLIENTCLASS(); + + C_BaseButton() + { + } + + virtual bool IsPotentiallyUsable( void ); + +private: + bool m_usable; +}; + + +#endif // C_BASETOGGLE_H \ No newline at end of file diff --git a/game/client/c_baseviewmodel.cpp b/game/client/c_baseviewmodel.cpp index 98132bc95..6e4c0786c 100644 --- a/game/client/c_baseviewmodel.cpp +++ b/game/client/c_baseviewmodel.cpp @@ -1,10 +1,10 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: Client side view model implementation. Responsible for drawing // the view model. // // $NoKeywords: $ -//=============================================================================// +//===========================================================================// #include "cbase.h" #include "c_baseviewmodel.h" #include "model_types.h" @@ -18,34 +18,43 @@ #include "tools/bonelist.h" #include #include "hltvcamera.h" - +#include "r_efx.h" +#include "dlight.h" +#include "clientalphaproperty.h" +#include "iinput.h" #if defined( REPLAY_ENABLED ) -#include "replay/replaycamera.h" -#include "replay/ireplaysystem.h" -#include "replay/ienginereplay.h" +#include "replaycamera.h" #endif -// NVNT haptics system interface -#include "haptics/ihaptics.h" - - // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" -#ifdef CSTRIKE_DLL - ConVar cl_righthand( "cl_righthand", "1", FCVAR_ARCHIVE, "Use right-handed view models." ); -#endif - -#ifdef TF_CLIENT_DLL - ConVar cl_flipviewmodels( "cl_flipviewmodels", "0", FCVAR_USERINFO | FCVAR_ARCHIVE | FCVAR_NOT_CONNECTED, "Flip view models." ); -#endif +ConVar vm_debug( "vm_debug", "0", FCVAR_CHEAT ); +ConVar vm_draw_always( "vm_draw_always", "0" ); void PostToolMessage( HTOOLHANDLE hEntity, KeyValues *msg ); +extern float g_flMuzzleFlashScale; -void FormatViewModelAttachment( Vector &vOrigin, bool bInverse ) +void FormatViewModelAttachment( C_BasePlayer *pPlayer, Vector &vOrigin, bool bInverse ) { + int nSlot = 0; + if ( pPlayer ) + { + int nPlayerSlot = C_BasePlayer::GetSplitScreenSlotForPlayer( pPlayer ); + if ( nPlayerSlot == -1 ) + { + nSlot = GET_ACTIVE_SPLITSCREEN_SLOT(); + } + else + { + nSlot = nPlayerSlot; + } + } + + Assert( nSlot != -1 ); + // Presumably, SetUpView has been called so we know our FOV and render origin. - const CViewSetup *pViewSetup = view->GetPlayerViewSetup(); + const CViewSetup *pViewSetup = view->GetPlayerViewSetup( nSlot ); float worldx = tan( pViewSetup->fov * M_PI/360.0 ); float viewx = tan( pViewSetup->fovViewmodel * M_PI/360.0 ); @@ -59,7 +68,7 @@ void FormatViewModelAttachment( Vector &vOrigin, bool bInverse ) // Get the coordinates in the viewer's space. Vector tmp = vOrigin - pViewSetup->origin; - Vector vTransformed( MainViewRight().Dot( tmp ), MainViewUp().Dot( tmp ), MainViewForward().Dot( tmp ) ); + Vector vTransformed( MainViewRight(nSlot).Dot( tmp ), MainViewUp(nSlot).Dot( tmp ), MainViewForward(nSlot).Dot( tmp ) ); // Now squash X and Y. if ( bInverse ) @@ -84,39 +93,35 @@ void FormatViewModelAttachment( Vector &vOrigin, bool bInverse ) // Transform back to world space. - Vector vOut = (MainViewRight() * vTransformed.x) + (MainViewUp() * vTransformed.y) + (MainViewForward() * vTransformed.z); + Vector vOut = (MainViewRight(nSlot) * vTransformed.x) + (MainViewUp(nSlot) * vTransformed.y) + (MainViewForward(nSlot) * vTransformed.z); vOrigin = pViewSetup->origin + vOut; } void C_BaseViewModel::FormatViewModelAttachment( int nAttachment, matrix3x4_t &attachmentToWorld ) { + C_BasePlayer *pPlayer = ToBasePlayer( GetOwner() ); Vector vecOrigin; MatrixPosition( attachmentToWorld, vecOrigin ); - ::FormatViewModelAttachment( vecOrigin, false ); + ::FormatViewModelAttachment( pPlayer, vecOrigin, false ); PositionMatrix( vecOrigin, attachmentToWorld ); } - -bool C_BaseViewModel::IsViewModel() const -{ - return true; -} - void C_BaseViewModel::UncorrectViewModelAttachment( Vector &vOrigin ) { + C_BasePlayer *pPlayer = ToBasePlayer( GetOwner() ); // Unformat the attachment. - ::FormatViewModelAttachment( vOrigin, true ); + ::FormatViewModelAttachment( pPlayer, vOrigin, true ); } //----------------------------------------------------------------------------- // Purpose //----------------------------------------------------------------------------- -void C_BaseViewModel::FireEvent( const Vector& origin, const QAngle& angles, int event, const char *options ) +void C_BaseViewModel::FireEvent( const Vector& origin, const QAngle& angles, int eventNum, const char *options ) { // We override sound requests so that we can play them locally on the owning player - if ( ( event == AE_CL_PLAYSOUND ) || ( event == CL_EVENT_SOUND ) ) + if ( ( eventNum == AE_CL_PLAYSOUND ) || ( eventNum == CL_EVENT_SOUND ) ) { // Only do this if we're owned by someone if ( GetOwner() != NULL ) @@ -127,18 +132,23 @@ void C_BaseViewModel::FireEvent( const Vector& origin, const QAngle& angles, int } } + C_BasePlayer *pOwner = ToBasePlayer( GetOwner() ); + if ( !pOwner ) + return; + + ACTIVE_SPLITSCREEN_PLAYER_GUARD_ENT( pOwner ); + // Otherwise pass the event to our associated weapon - C_BaseCombatWeapon *pWeapon = GetActiveWeapon(); + C_BaseCombatWeapon *pWeapon = pOwner->GetActiveWeapon(); if ( pWeapon ) { - // NVNT notify the haptics system of our viewmodel's event - if ( haptics ) - haptics->ProcessHapticEvent(4,"Weapons",pWeapon->GetName(),"AnimationEvents",VarArgs("%i",event)); - - bool bResult = pWeapon->OnFireEvent( this, origin, angles, event, options ); + bool bResult = pWeapon->OnFireEvent( this, origin, angles, eventNum, options ); if ( !bResult ) { - BaseClass::FireEvent( origin, angles, event, options ); + if ( eventNum == AE_CLIENT_EFFECT_ATTACH && ::input->CAM_IsThirdPerson() ) + return; + + BaseClass::FireEvent( origin, angles, eventNum, options ); } } } @@ -153,7 +163,7 @@ bool C_BaseViewModel::Interpolate( float currentTime ) // Hack to extrapolate cycle counter for view model float elapsed_time = currentTime - m_flAnimTime; - C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + C_BasePlayer *pPlayer = ToBasePlayer( GetOwner() ); // Predicted viewmodels have fixed up interval if ( GetPredictable() || IsClientCreated() ) @@ -162,10 +172,7 @@ bool C_BaseViewModel::Interpolate( float currentTime ) float curtime = pPlayer ? pPlayer->GetFinalPredictedTime() : gpGlobals->curtime; elapsed_time = curtime - m_flAnimTime; // Adjust for interpolated partial frame - if ( !engine->IsPaused() ) - { - elapsed_time += ( gpGlobals->interpolation_amount * TICK_INTERVAL ); - } + elapsed_time += ( gpGlobals->interpolation_amount * TICK_INTERVAL ); } // Prediction errors? @@ -174,7 +181,7 @@ bool C_BaseViewModel::Interpolate( float currentTime ) elapsed_time = 0; } - float dt = elapsed_time * GetSequenceCycleRate( pStudioHdr, GetSequence() ) * GetPlaybackRate(); + float dt = elapsed_time * GetSequenceCycleRate( pStudioHdr, GetSequence() ); if ( dt >= 1.0f ) { if ( !IsSequenceLooping( GetSequence() ) ) @@ -194,24 +201,6 @@ bool C_BaseViewModel::Interpolate( float currentTime ) inline bool C_BaseViewModel::ShouldFlipViewModel() { -#ifdef CSTRIKE_DLL - // If cl_righthand is set, then we want them all right-handed. - CBaseCombatWeapon *pWeapon = m_hWeapon.Get(); - if ( pWeapon ) - { - const FileWeaponInfo_t *pInfo = &pWeapon->GetWpnData(); - return pInfo->m_bAllowFlipping && pInfo->m_bBuiltRightHanded != cl_righthand.GetBool(); - } -#endif - -#ifdef TF_CLIENT_DLL - CBaseCombatWeapon *pWeapon = m_hWeapon.Get(); - if ( pWeapon ) - { - return pWeapon->m_bFlipViewModel != cl_flipviewmodels.GetBool(); - } -#endif - return false; } @@ -220,6 +209,8 @@ void C_BaseViewModel::ApplyBoneMatrixTransform( matrix3x4_t& transform ) { if ( ShouldFlipViewModel() ) { + ACTIVE_SPLITSCREEN_PLAYER_GUARD_ENT( GetOwner() ); + matrix3x4_t viewMatrix, viewMatrixInverse; // We could get MATERIAL_VIEW here, but this is called sometimes before the renderer @@ -256,13 +247,13 @@ void C_BaseViewModel::ApplyBoneMatrixTransform( matrix3x4_t& transform ) //----------------------------------------------------------------------------- bool C_BaseViewModel::ShouldDraw() { - if ( engine->IsHLTV() ) + if ( g_bEngineIsHLTV ) { return ( HLTVCamera()->GetMode() == OBS_MODE_IN_EYE && HLTVCamera()->GetPrimaryTarget() == GetOwner() ); } #if defined( REPLAY_ENABLED ) - else if ( g_pEngineClientReplay->IsPlayingReplayDemo() ) + else if ( engine->IsReplay() ) { return ( ReplayCamera()->GetMode() == OBS_MODE_IN_EYE && ReplayCamera()->GetPrimaryTarget() == GetOwner() ); @@ -270,6 +261,14 @@ bool C_BaseViewModel::ShouldDraw() #endif else { + Assert( !IsEffectActive( EF_NODRAW ) ); + Assert( GetRenderMode() != kRenderNone ); + + if ( vm_draw_always.GetBool() ) + return true; + if ( GetOwner() != C_BasePlayer::GetLocalPlayer() ) + return false; + return BaseClass::ShouldDraw(); } } @@ -278,7 +277,7 @@ bool C_BaseViewModel::ShouldDraw() // Purpose: Render the weapon. Draw the Viewmodel if the weapon's being carried // by this player, otherwise draw the worldmodel. //----------------------------------------------------------------------------- -int C_BaseViewModel::DrawModel( int flags ) +int C_BaseViewModel::DrawModel( int flags, const RenderableInstance_t &instance ) { if ( !m_bReadyToDraw ) return 0; @@ -286,7 +285,7 @@ int C_BaseViewModel::DrawModel( int flags ) if ( flags & STUDIO_RENDER ) { // Determine blending amount and tell engine - float blend = (float)( GetFxBlend() / 255.0f ); + float blend = (float)( instance.m_nAlpha / 255.0f ); // Totally gone if ( blend <= 0.0f ) @@ -299,24 +298,32 @@ int C_BaseViewModel::DrawModel( int flags ) GetColorModulation( color ); render->SetColorModulation( color ); } - + + CMatRenderContextPtr pRenderContext( materials ); + + if ( ShouldFlipViewModel() ) + pRenderContext->CullMode( MATERIAL_CULLMODE_CW ); + + int ret = 0; C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); C_BaseCombatWeapon *pWeapon = GetOwningWeapon(); - int ret; + // If the local player's overriding the viewmodel rendering, let him do it if ( pPlayer && pPlayer->IsOverridingViewmodel() ) { - ret = pPlayer->DrawOverriddenViewmodel( this, flags ); + ret = pPlayer->DrawOverriddenViewmodel( this, flags, instance ); } else if ( pWeapon && pWeapon->IsOverridingViewmodel() ) { - ret = pWeapon->DrawOverriddenViewmodel( this, flags ); + ret = pWeapon->DrawOverriddenViewmodel( this, flags, instance ); } else { - ret = BaseClass::DrawModel( flags ); + ret = BaseClass::DrawModel( flags, instance ); } + pRenderContext->CullMode( MATERIAL_CULLMODE_CCW ); + // Now that we've rendered, reset the animation restart flag if ( flags & STUDIO_RENDER ) { @@ -324,28 +331,58 @@ int C_BaseViewModel::DrawModel( int flags ) { m_nOldAnimationParity = m_nAnimationParity; } + // Tell the weapon itself that we've rendered, in case it wants to do something if ( pWeapon ) { pWeapon->ViewModelDrawn( this ); } - } - - return ret; -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -int C_BaseViewModel::InternalDrawModel( int flags ) -{ - CMatRenderContextPtr pRenderContext( materials ); - if ( ShouldFlipViewModel() ) - pRenderContext->CullMode( MATERIAL_CULLMODE_CW ); - int ret = BaseClass::InternalDrawModel( flags ); - - pRenderContext->CullMode( MATERIAL_CULLMODE_CCW ); + if ( vm_debug.GetBool() ) + { + MDLCACHE_CRITICAL_SECTION(); + + int line = 16; + CStudioHdr *hdr = GetModelPtr(); + engine->Con_NPrintf( line++, "%s: %s(%d), cycle: %.2f cyclerate: %.2f playbackrate: %.2f\n", + (hdr)?hdr->pszName():"(null)", + GetSequenceName( GetSequence() ), + GetSequence(), + GetCycle(), + GetSequenceCycleRate( hdr, GetSequence() ), + GetPlaybackRate() + ); + if ( hdr ) + { + for( int i=0; i < hdr->GetNumPoseParameters(); ++i ) + { + const mstudioposeparamdesc_t &Pose = hdr->pPoseParameter( i ); + engine->Con_NPrintf( line++, "pose_param %s: %f", + Pose.pszName(), GetPoseParameter( i ) ); + } + } + + // Determine blending amount and tell engine + float blend = (float)( instance.m_nAlpha / 255.0f ); + float color[3]; + GetColorModulation( color ); + engine->Con_NPrintf( line++, "blend=%f, color=%f,%f,%f", blend, color[0], color[1], color[2] ); + engine->Con_NPrintf( line++, "GetRenderMode()=%d", GetRenderMode() ); + engine->Con_NPrintf( line++, "m_nRenderFX=0x%8.8X", GetRenderFX() ); + + color24 c = GetRenderColor(); + unsigned char a = GetRenderAlpha(); + engine->Con_NPrintf( line++, "rendercolor=%d,%d,%d,%d", c.r, c.g, c.b, a ); + + engine->Con_NPrintf( line++, "origin=%f, %f, %f", GetRenderOrigin().x, GetRenderOrigin().y, GetRenderOrigin().z ); + engine->Con_NPrintf( line++, "angles=%f, %f, %f", GetRenderAngles()[0], GetRenderAngles()[1], GetRenderAngles()[2] ); + + if ( IsEffectActive( EF_NODRAW ) ) + { + engine->Con_NPrintf( line++, "EF_NODRAW" ); + } + } + } return ret; } @@ -353,82 +390,61 @@ int C_BaseViewModel::InternalDrawModel( int flags ) //----------------------------------------------------------------------------- // Purpose: Called by the player when the player's overriding the viewmodel drawing. Avoids infinite recursion. //----------------------------------------------------------------------------- -int C_BaseViewModel::DrawOverriddenViewmodel( int flags ) +int C_BaseViewModel::DrawOverriddenViewmodel( int flags, const RenderableInstance_t &instance ) { - return BaseClass::DrawModel( flags ); + return BaseClass::DrawModel( flags, instance ); } //----------------------------------------------------------------------------- // Purpose: // Output : int //----------------------------------------------------------------------------- -int C_BaseViewModel::GetFxBlend( void ) +uint8 C_BaseViewModel::OverrideAlphaModulation( uint8 nAlpha ) { + ACTIVE_SPLITSCREEN_PLAYER_GUARD_ENT( GetOwner() ); + // See if the local player wants to override the viewmodel's rendering C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); if ( pPlayer && pPlayer->IsOverridingViewmodel() ) - { - pPlayer->ComputeFxBlend(); - return pPlayer->GetFxBlend(); - } - + return pPlayer->AlphaProp()->ComputeRenderAlpha(); + C_BaseCombatWeapon *pWeapon = GetOwningWeapon(); if ( pWeapon && pWeapon->IsOverridingViewmodel() ) - { - pWeapon->ComputeFxBlend(); - return pWeapon->GetFxBlend(); - } + return pWeapon->AlphaProp()->ComputeRenderAlpha(); + + return nAlpha; - return BaseClass::GetFxBlend(); } + //----------------------------------------------------------------------------- // Purpose: // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- -bool C_BaseViewModel::IsTransparent( void ) +RenderableTranslucencyType_t C_BaseViewModel::ComputeTranslucencyType( void ) { - // See if the local player wants to override the viewmodel's rendering - C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); - if ( pPlayer && pPlayer->IsOverridingViewmodel() ) - { - return pPlayer->ViewModel_IsTransparent(); - } + ACTIVE_SPLITSCREEN_PLAYER_GUARD_ENT( GetOwner() ); - C_BaseCombatWeapon *pWeapon = GetOwningWeapon(); - if ( pWeapon && pWeapon->IsOverridingViewmodel() ) - return pWeapon->ViewModel_IsTransparent(); - - return BaseClass::IsTransparent(); -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -bool C_BaseViewModel::UsesPowerOfTwoFrameBufferTexture( void ) -{ // See if the local player wants to override the viewmodel's rendering C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); if ( pPlayer && pPlayer->IsOverridingViewmodel() ) - { - return pPlayer->ViewModel_IsUsingFBTexture(); - } + return pPlayer->ComputeTranslucencyType(); C_BaseCombatWeapon *pWeapon = GetOwningWeapon(); if ( pWeapon && pWeapon->IsOverridingViewmodel() ) - { - return pWeapon->ViewModel_IsUsingFBTexture(); - } + return pWeapon->ComputeTranslucencyType(); + + return BaseClass::ComputeTranslucencyType(); - return BaseClass::UsesPowerOfTwoFrameBufferTexture(); } + //----------------------------------------------------------------------------- // Purpose: If the animation parity of the weapon has changed, we reset cycle to avoid popping //----------------------------------------------------------------------------- void C_BaseViewModel::UpdateAnimationParity( void ) { - C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + C_BasePlayer *pPlayer = ToBasePlayer( GetOwner() ); // If we're predicting, then we don't use animation parity because we change the animations on the clientside // while predicting. When not predicting, only the server changes the animations, so a parity mismatch @@ -450,27 +466,26 @@ void C_BaseViewModel::UpdateAnimationParity( void ) //----------------------------------------------------------------------------- void C_BaseViewModel::OnDataChanged( DataUpdateType_t updateType ) { + if ( updateType == DATA_UPDATE_CREATED ) + { + AlphaProp()->EnableAlphaModulationOverride( true ); + } + SetPredictionEligible( true ); BaseClass::OnDataChanged(updateType); } - void C_BaseViewModel::PostDataUpdate( DataUpdateType_t updateType ) { BaseClass::PostDataUpdate(updateType); OnLatchInterpolatedVariables( LATCH_ANIMATION_VAR ); } - //----------------------------------------------------------------------------- -// Purpose: Add entity to visible view models list +// Purpose: Return the player who will predict this entity //----------------------------------------------------------------------------- -void C_BaseViewModel::AddEntity( void ) +CBasePlayer *C_BaseViewModel::GetPredictionOwner() { - // Server says don't interpolate this frame, so set previous info to new info. - if ( IsNoInterpolationFrame() ) - { - ResetLatched(); - } + return ToBasePlayer( GetOwner() ); } //----------------------------------------------------------------------------- @@ -481,18 +496,14 @@ void C_BaseViewModel::GetBoneControllers(float controllers[MAXSTUDIOBONECTRLS]) BaseClass::GetBoneControllers( controllers ); // Tell the weapon itself that we've rendered, in case it wants to do something - C_BaseCombatWeapon *pWeapon = GetActiveWeapon(); + C_BasePlayer *pPlayer = ToBasePlayer( GetOwner() ); + if ( !pPlayer ) + return; + + C_BaseCombatWeapon *pWeapon = pPlayer->GetActiveWeapon(); if ( pWeapon ) { pWeapon->GetViewmodelBoneControllers( this, controllers ); } } -//----------------------------------------------------------------------------- -// Purpose: -// Output : RenderGroup_t -//----------------------------------------------------------------------------- -RenderGroup_t C_BaseViewModel::GetRenderGroup() -{ - return RENDER_GROUP_VIEW_MODEL_OPAQUE; -} diff --git a/game/client/c_baseviewmodel.h b/game/client/c_baseviewmodel.h index fa59176da..c4cd21d50 100644 --- a/game/client/c_baseviewmodel.h +++ b/game/client/c_baseviewmodel.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: Client side view model implementation. Responsible for drawing // the view model. @@ -13,7 +13,8 @@ #endif #include "c_baseanimating.h" -#include "utlvector.h" +#include "UtlVector.h" #include "baseviewmodel_shared.h" + #endif // C_BASEVIEWMODEL_H diff --git a/game/client/c_beamspotlight.cpp b/game/client/c_beamspotlight.cpp new file mode 100644 index 000000000..ceeb7d70d --- /dev/null +++ b/game/client/c_beamspotlight.cpp @@ -0,0 +1,354 @@ +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// +// +// Purpose: +// +//===========================================================================// + +#include "cbase.h" +#include "dlight.h" +#include "iefx.h" + +#include "beam_shared.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CSpotlightTraceCacheEntry +{ +public: + CSpotlightTraceCacheEntry() + { + m_origin.Init(); + m_radius = -1.0f; + } + bool IsValidFor( const Vector &origin ) + { + if ( m_radius > 0 && m_origin.DistToSqr(origin) < 1.0f ) + return true; + return false; + } + void Cache( const Vector &origin, const trace_t &tr ) + { + m_radius = (tr.endpos - origin).Length(); + m_origin = origin; + } + + Vector m_origin; + float m_radius; +}; + +static const int NUM_CACHE_ENTRIES = 64; + +class C_BeamSpotLight : public C_BaseEntity +{ +public: + DECLARE_CLASS( C_BeamSpotLight, C_BaseEntity ); + DECLARE_CLIENTCLASS(); + + C_BeamSpotLight(); + ~C_BeamSpotLight(); + + bool ShouldDraw(); + void ClientThink( void ); + void OnDataChanged( DataUpdateType_t updateType ); + void Release( void ); + +private: + + Vector SpotlightCurrentPos(void); + void SpotlightCreate(void); + void SpotlightDestroy(void); + + // Computes render info for a spotlight + void ComputeRenderInfo(); + +private: + + int m_nHaloIndex; + int m_nRotationAxis; + float m_flRotationSpeed; + + + bool m_bSpotlightOn; + bool m_bHasDynamicLight; + + float m_flSpotlightMaxLength; + float m_flSpotlightGoalWidth; + float m_flHDRColorScale; + + Vector m_vSpotlightTargetPos; + Vector m_vSpotlightCurrentPos; + Vector m_vSpotlightDir; + + CHandle m_hSpotlight; + + float m_flSpotlightCurLength; + + float m_flLightScale; + + dlight_t* m_pDynamicLight; + + float m_lastTime; + CSpotlightTraceCacheEntry *m_pCache; +}; + +LINK_ENTITY_TO_CLASS( beam_spotlight, C_BeamSpotLight ); + +IMPLEMENT_CLIENTCLASS_DT( C_BeamSpotLight, DT_BeamSpotlight, CBeamSpotlight ) + RecvPropInt( RECVINFO(m_nHaloIndex) ), + RecvPropBool( RECVINFO(m_bSpotlightOn) ), + RecvPropBool( RECVINFO(m_bHasDynamicLight) ), + RecvPropFloat( RECVINFO(m_flSpotlightMaxLength) ), + RecvPropFloat( RECVINFO(m_flSpotlightGoalWidth) ), + RecvPropFloat( RECVINFO(m_flHDRColorScale) ), + RecvPropInt( RECVINFO(m_nRotationAxis) ), + RecvPropFloat( RECVINFO(m_flRotationSpeed) ), +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +C_BeamSpotLight::C_BeamSpotLight() +: m_vSpotlightTargetPos( vec3_origin ) +, m_vSpotlightCurrentPos( vec3_origin ) +, m_vSpotlightDir( vec3_origin ) +, m_flSpotlightCurLength( 0.0f ) +, m_flLightScale( 100.0f ) +, m_pDynamicLight( NULL ) +, m_lastTime( 0.0f ) +, m_pCache(NULL) +{ +} + +C_BeamSpotLight::~C_BeamSpotLight() +{ + delete[] m_pCache; +} + + +//----------------------------------------------------------------------------- +bool C_BeamSpotLight::ShouldDraw() +{ + return false; +} + +//----------------------------------------------------------------------------- +void C_BeamSpotLight::ClientThink( void ) +{ + float dt = gpGlobals->curtime - m_lastTime; + if ( !m_lastTime ) + { + dt = 0.0f; + } + m_lastTime = gpGlobals->curtime; + + // --------------------------------------------------- + // If I don't have a spotlight attempt to create one + // --------------------------------------------------- + if ( !m_hSpotlight ) + { + if ( m_bSpotlightOn ) + { + // Make the spotlight + SpotlightCreate(); + } + else + { + SetNextClientThink( CLIENT_THINK_NEVER ); + return; + } + } + else if ( !m_bSpotlightOn ) + { + SpotlightDestroy(); + SetNextClientThink( CLIENT_THINK_NEVER ); + return; + } + + // update rotation + if ( m_flRotationSpeed != 0.0f ) + { + QAngle angles = GetAbsAngles(); + angles[m_nRotationAxis] += m_flRotationSpeed * dt; + angles[m_nRotationAxis] = anglemod(angles[m_nRotationAxis]); + if ( !m_pCache ) + { + m_pCache = new CSpotlightTraceCacheEntry[NUM_CACHE_ENTRIES]; + } + + SetAbsAngles( angles ); + } + m_vSpotlightCurrentPos = SpotlightCurrentPos(); + + Assert( m_hSpotlight ); + + m_hSpotlight->SetStartPos( GetAbsOrigin() ); + m_hSpotlight->SetEndPos( m_vSpotlightCurrentPos ); + + // Avoid sudden change in where beam fades out when cross disconinuities + Vector dir = m_vSpotlightCurrentPos - GetAbsOrigin(); + float flBeamLength = VectorNormalize( dir ); + m_flSpotlightCurLength = (0.60*m_flSpotlightCurLength) + (0.4*flBeamLength); + + ComputeRenderInfo(); + + m_hSpotlight->RelinkBeam(); + + //NDebugOverlay::Cross3D(GetAbsOrigin(),Vector(-5,-5,-5),Vector(5,5,5),0,255,0,true,0.1); + //NDebugOverlay::Cross3D(m_vSpotlightCurrentPos,Vector(-5,-5,-5),Vector(5,5,5),0,255,0,true,0.1); + //NDebugOverlay::Cross3D(m_vSpotlightTargetPos,Vector(-5,-5,-5),Vector(5,5,5),255,0,0,true,0.1); + + // Do we need to keep updating? + if ( !GetMoveParent() && m_flRotationSpeed == 0 ) + { + // No reason to think again, we're not going to move unless there's a data change + SetNextClientThink( CLIENT_THINK_NEVER ); + } +} + +//----------------------------------------------------------------------------- +void C_BeamSpotLight::OnDataChanged( DataUpdateType_t updateType ) +{ + BaseClass::OnDataChanged( updateType ); + if ( updateType == DATA_UPDATE_CREATED ) + { + m_flSpotlightCurLength = m_flSpotlightMaxLength; + } + + // On a data change always think again + SetNextClientThink( CLIENT_THINK_ALWAYS ); +} + +//------------------------------------------------------------------------------ +void C_BeamSpotLight::Release() +{ + SpotlightDestroy(); + BaseClass::Release(); +} + +//------------------------------------------------------------------------------ +void C_BeamSpotLight::SpotlightCreate(void) +{ + m_vSpotlightTargetPos = SpotlightCurrentPos(); + + { + //C_Beam *beam = CBeam::BeamCreate( "sprites/spotlight.vmt", m_flSpotlightGoalWidth ); + C_Beam *beam = C_Beam::BeamCreate( "sprites/glow_test02.vmt", m_flSpotlightGoalWidth ); + // Beam only exists client side + ClientEntityList().AddNonNetworkableEntity( beam ); + m_hSpotlight = beam; + } + + // Set the temporary spawnflag on the beam so it doesn't save (we'll recreate it on restore) + m_hSpotlight->SetHDRColorScale( m_flHDRColorScale ); + const color24 c = GetRenderColor(); + m_hSpotlight->SetColor( c.r, c.g, c.b ); + m_hSpotlight->SetHaloTexture(m_nHaloIndex); + m_hSpotlight->SetHaloScale(60); + m_hSpotlight->SetEndWidth(m_flSpotlightGoalWidth); + m_hSpotlight->SetBeamFlags( (FBEAM_SHADEOUT|FBEAM_NOTILE) ); + m_hSpotlight->SetBrightness( 64 ); + m_hSpotlight->SetNoise( 0 ); + + m_hSpotlight->PointsInit( GetAbsOrigin(), m_vSpotlightTargetPos ); +} + +//------------------------------------------------------------------------------ +void C_BeamSpotLight::SpotlightDestroy(void) +{ + if ( m_hSpotlight ) + { + UTIL_Remove( m_hSpotlight ); + m_hSpotlight.Term(); + } +} + +//------------------------------------------------------------------------------ +Vector C_BeamSpotLight::SpotlightCurrentPos(void) +{ + QAngle angles = GetAbsAngles(); + GetVectors( &m_vSpotlightDir, NULL, NULL ); + Vector position = GetAbsOrigin(); + int cacheIndex = -1; + if ( m_pCache ) + { + cacheIndex = int( angles[m_nRotationAxis] * float(NUM_CACHE_ENTRIES) * (1.0f / 360.0f)) & (NUM_CACHE_ENTRIES - 1); + if ( m_pCache[cacheIndex].IsValidFor(GetAbsOrigin()) ) + { + return position + m_vSpotlightDir * m_pCache[cacheIndex].m_radius; + } + } + + + // Get beam end point. Only collide with solid objects, not npcs + trace_t tr; + UTIL_TraceLine( position, position + (m_vSpotlightDir * 2 * m_flSpotlightMaxLength), MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr ); + if ( cacheIndex >= 0 ) + { + m_pCache[cacheIndex].Cache(position, tr); + } + + return tr.endpos; +} + +//----------------------------------------------------------------------------- +// Computes render info for a spotlight +//----------------------------------------------------------------------------- +void C_BeamSpotLight::ComputeRenderInfo() +{ + // Fade out spotlight end if past max length. + if ( m_flSpotlightCurLength > 2*m_flSpotlightMaxLength ) + { + SetRenderAlpha( 0 ); + m_hSpotlight->SetFadeLength( m_flSpotlightMaxLength ); + } + else if ( m_flSpotlightCurLength > m_flSpotlightMaxLength ) + { + SetRenderAlpha( (1-((m_flSpotlightCurLength-m_flSpotlightMaxLength)/m_flSpotlightMaxLength)) ); + m_hSpotlight->SetFadeLength( m_flSpotlightMaxLength ); + } + else + { + SetRenderAlpha( 1.0 ); + m_hSpotlight->SetFadeLength( m_flSpotlightCurLength ); + } + + // Adjust end width to keep beam width constant + float flNewWidth = m_flSpotlightGoalWidth * (m_flSpotlightCurLength / m_flSpotlightMaxLength); + flNewWidth = clamp(flNewWidth, 0, MAX_BEAM_WIDTH ); + m_hSpotlight->SetEndWidth(flNewWidth); + + if ( m_bHasDynamicLight ) + { + // <> - magic number 1.8 depends on sprite size + m_flLightScale = 1.8*flNewWidth; + + if ( m_flLightScale > 0 ) + { + const color24 c = GetRenderColor(); + float a = GetRenderAlpha() / 255.0f; + ColorRGBExp32 color; + color.r = c.r * a; + color.g = c.g * a; + color.b = c.b * a; + color.exponent = 0; + if ( color.r == 0 && color.g == 0 && color.b == 0 ) + return; + + // Deal with the environment light + if ( !m_pDynamicLight || (m_pDynamicLight->key != index) ) + { + m_pDynamicLight = effects->CL_AllocDlight( index ); + assert (m_pDynamicLight); + } + + //m_pDynamicLight->flags = DLIGHT_NO_MODEL_ILLUMINATION; + m_pDynamicLight->radius = m_flLightScale*3.0f; + m_pDynamicLight->origin = GetAbsOrigin() + Vector(0,0,5); + m_pDynamicLight->die = gpGlobals->curtime + 0.05f; + m_pDynamicLight->color = color; + } + } +} + diff --git a/game/client/c_breakableprop.cpp b/game/client/c_breakableprop.cpp index 8271c3a19..debb485c5 100644 --- a/game/client/c_breakableprop.cpp +++ b/game/client/c_breakableprop.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // @@ -18,6 +18,7 @@ #include "tier0/memdbgon.h" IMPLEMENT_CLIENTCLASS_DT(C_BreakableProp, DT_BreakableProp, CBreakableProp) + RecvPropBool( RECVINFO( m_bClientPhysics ) ), END_RECV_TABLE() //----------------------------------------------------------------------------- @@ -28,19 +29,23 @@ C_BreakableProp::C_BreakableProp( void ) m_takedamage = DAMAGE_YES; } -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void C_BreakableProp::SetFadeMinMax( float fademin, float fademax ) -{ - m_fadeMinDist = fademin; - m_fadeMaxDist = fademax; -} //----------------------------------------------------------------------------- // Copy fade from another breakable prop //----------------------------------------------------------------------------- void C_BreakableProp::CopyFadeFrom( C_BreakableProp *pSource ) { - m_flFadeScale = pSource->m_flFadeScale; + SetGlobalFadeScale( pSource->GetGlobalFadeScale() ); + SetDistanceFade( pSource->GetMinFadeDist(), pSource->GetMaxFadeDist() ); } + +void C_BreakableProp::OnDataChanged( DataUpdateType_t type ) +{ + BaseClass::OnDataChanged( type ); + if ( m_bClientPhysics ) + { + bool bCreate = (type == DATA_UPDATE_CREATED) ? true : false; + VPhysicsShadowDataChanged(bCreate, this); + } +} + diff --git a/game/client/c_breakableprop.h b/game/client/c_breakableprop.h index 666d9a35e..e49101d17 100644 --- a/game/client/c_breakableprop.h +++ b/game/client/c_breakableprop.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // @@ -20,11 +20,18 @@ class C_BreakableProp : public C_BaseAnimating DECLARE_CLIENTCLASS(); C_BreakableProp(); - - virtual void SetFadeMinMax( float fademin, float fademax ); + + virtual bool IsProp( void ) const + { + return true; + }; // Copy fade from another breakable prop void CopyFadeFrom( C_BreakableProp *pSource ); + virtual void OnDataChanged( DataUpdateType_t type ); + +private: + bool m_bClientPhysics; }; #endif // C_BREAKABLEPROP_H diff --git a/game/client/c_colorcorrection.cpp b/game/client/c_colorcorrection.cpp index 6960031d5..d8b189804 100644 --- a/game/client/c_colorcorrection.cpp +++ b/game/client/c_colorcorrection.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: Color correction entity with simple radial falloff // @@ -6,10 +6,12 @@ //===========================================================================// #include "cbase.h" +#include "c_colorcorrection.h" #include "filesystem.h" #include "cdll_client_int.h" #include "colorcorrectionmgr.h" -#include "materialsystem/MaterialSystemUtil.h" +#include "materialsystem/materialsystemutil.h" +#include "iclientmode.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -17,46 +19,25 @@ static ConVar mat_colcorrection_disableentities( "mat_colcorrection_disableentities", "0", FCVAR_NONE, "Disable map color-correction entities" ); +static ConVar mat_colcorrection_forceentitiesclientside( "mat_colcorrection_forceentitiesclientside", "0", FCVAR_CHEAT, "Forces color correction entities to be updated on the client" ); -//------------------------------------------------------------------------------ -// Purpose : Color correction entity with radial falloff -//------------------------------------------------------------------------------ -class C_ColorCorrection : public C_BaseEntity -{ -public: - DECLARE_CLASS( C_ColorCorrection, C_BaseEntity ); - - DECLARE_CLIENTCLASS(); - - C_ColorCorrection(); - virtual ~C_ColorCorrection(); - - void OnDataChanged(DataUpdateType_t updateType); - bool ShouldDraw(); - - void ClientThink(); - -private: - Vector m_vecOrigin; - - float m_minFalloff; - float m_maxFalloff; - float m_flCurWeight; - char m_netLookupFilename[MAX_PATH]; - - bool m_bEnabled; - - ClientCCHandle_t m_CCHandle; -}; +#ifdef CColorCorrection +#undef CColorCorrection +#endif IMPLEMENT_CLIENTCLASS_DT(C_ColorCorrection, DT_ColorCorrection, CColorCorrection) RecvPropVector( RECVINFO(m_vecOrigin) ), RecvPropFloat( RECVINFO(m_minFalloff) ), RecvPropFloat( RECVINFO(m_maxFalloff) ), RecvPropFloat( RECVINFO(m_flCurWeight) ), + RecvPropFloat( RECVINFO(m_flMaxWeight) ), + RecvPropFloat( RECVINFO(m_flFadeInDuration) ), + RecvPropFloat( RECVINFO(m_flFadeOutDuration) ), RecvPropString( RECVINFO(m_netLookupFilename) ), RecvPropBool( RECVINFO(m_bEnabled) ), - + RecvPropBool( RECVINFO(m_bMaster) ), + RecvPropBool( RECVINFO(m_bClientSide) ), + RecvPropBool( RECVINFO(m_bExclusive) ) END_RECV_TABLE() @@ -65,14 +46,38 @@ END_RECV_TABLE() //------------------------------------------------------------------------------ C_ColorCorrection::C_ColorCorrection() { + m_minFalloff = -1.0f; + m_maxFalloff = -1.0f; + m_flFadeInDuration = 0.0f; + m_flFadeOutDuration = 0.0f; + m_flCurWeight = 0.0f; + m_flMaxWeight = 1.0f; + m_netLookupFilename[0] = '\0'; + m_bEnabled = false; + m_bMaster = false; + m_bExclusive = false; m_CCHandle = INVALID_CLIENT_CCHANDLE; + + for ( int i = 0; i < MAX_SPLITSCREEN_PLAYERS; i++ ) + { + m_bEnabledOnClient[i] = false; + m_flCurWeightOnClient[i] = 0.0f; + m_bFadingIn[i] = false; + m_flFadeStartWeight[i] = 0.0f; + m_flFadeStartTime[i] = 0.0f; + m_flFadeDuration[i] = 0.0f; + } } C_ColorCorrection::~C_ColorCorrection() { - g_pColorCorrectionMgr->RemoveColorCorrection( m_CCHandle ); + g_pColorCorrectionMgr->RemoveColorCorrectionEntity( this, m_CCHandle ); } +bool C_ColorCorrection::IsClientSide() const +{ + return m_bClientSide || mat_colcorrection_forceentitiesclientside.GetBool(); +} //------------------------------------------------------------------------------ // Purpose : @@ -87,11 +92,13 @@ void C_ColorCorrection::OnDataChanged(DataUpdateType_t updateType) { if ( m_CCHandle == INVALID_CLIENT_CCHANDLE ) { - char filename[MAX_PATH]; - Q_strncpy( filename, m_netLookupFilename, MAX_PATH ); + // forming a unique name without extension + char cleanName[MAX_PATH]; + V_StripExtension( m_netLookupFilename, cleanName, sizeof( cleanName ) ); + char name[MAX_PATH]; + Q_snprintf( name, MAX_PATH, "%s_%d", cleanName, entindex() ); - m_CCHandle = g_pColorCorrectionMgr->AddColorCorrection( filename ); - SetNextClientThink( ( m_CCHandle != INVALID_CLIENT_CCHANDLE ) ? CLIENT_THINK_ALWAYS : CLIENT_THINK_NEVER ); + m_CCHandle = g_pColorCorrectionMgr->AddColorCorrectionEntity( this, name, m_netLookupFilename ); } } } @@ -104,27 +111,33 @@ bool C_ColorCorrection::ShouldDraw() return false; } -void C_ColorCorrection::ClientThink() +void C_ColorCorrection::Update( C_BasePlayer *pPlayer, float ccScale ) { - if ( m_CCHandle == INVALID_CLIENT_CCHANDLE ) - return; + Assert( m_CCHandle != INVALID_CLIENT_CCHANDLE ); if ( mat_colcorrection_disableentities.GetInt() ) { // Allow the colorcorrectionui panel (or user) to turn off color-correction entities - g_pColorCorrectionMgr->SetColorCorrectionWeight( m_CCHandle, 0.0f ); + g_pColorCorrectionMgr->SetColorCorrectionWeight( m_CCHandle, 0.0f, m_bExclusive ); return; } - if( !m_bEnabled && m_flCurWeight == 0.0f ) + int nSlot = GET_ACTIVE_SPLITSCREEN_SLOT(); + bool bEnabled = IsClientSide() ? m_bEnabledOnClient[nSlot] : m_bEnabled; + + // fade weight on client + if ( IsClientSide() ) { - g_pColorCorrectionMgr->SetColorCorrectionWeight( m_CCHandle, 0.0f ); - return; + m_flCurWeightOnClient[nSlot] = Lerp( GetFadeRatio( nSlot ), m_flFadeStartWeight[nSlot], m_bFadingIn[nSlot] ? m_flMaxWeight : 0.0f ); } - C_BaseEntity *pPlayer = C_BasePlayer::GetLocalPlayer(); - if( !pPlayer ) + float flCurWeight = IsClientSide() ? m_flCurWeightOnClient[nSlot] : m_flCurWeight; + + if( !bEnabled && flCurWeight == 0.0f ) + { + g_pColorCorrectionMgr->SetColorCorrectionWeight( m_CCHandle, 0.0f, m_bExclusive ); return; + } Vector playerOrigin = pPlayer->GetAbsOrigin(); @@ -136,21 +149,99 @@ void C_ColorCorrection::ClientThink() if ( weight<0.0f ) weight = 0.0f; if ( weight>1.0f ) weight = 1.0f; } - - g_pColorCorrectionMgr->SetColorCorrectionWeight( m_CCHandle, m_flCurWeight * ( 1.0 - weight ) ); - BaseClass::ClientThink(); + g_pColorCorrectionMgr->SetColorCorrectionWeight( m_CCHandle, flCurWeight * ( 1.0 - weight ) * ccScale, m_bExclusive ); } +void C_ColorCorrection::EnableOnClient( bool bEnable, bool bSkipFade ) +{ + if ( !IsClientSide() ) + { + return; + } + + int nSlot = GET_ACTIVE_SPLITSCREEN_SLOT(); + + if( m_bEnabledOnClient[nSlot] == bEnable ) + { + return; + } + + m_bFadingIn[nSlot] = bEnable; + m_bEnabledOnClient[nSlot] = bEnable; + // initialize countdown timer + m_flFadeStartWeight[nSlot] = m_flCurWeightOnClient[nSlot]; + float flFadeTimeScale = 1.0f; + if ( m_flMaxWeight != 0.0f ) + { + flFadeTimeScale = m_flCurWeightOnClient[nSlot] / m_flMaxWeight; + } + if ( m_bFadingIn[nSlot] ) + { + flFadeTimeScale = 1.0f - flFadeTimeScale; + } + if ( bSkipFade ) + { + flFadeTimeScale = 0.0f; + } + StartFade( nSlot, flFadeTimeScale * ( m_bFadingIn[nSlot] ? m_flFadeInDuration : m_flFadeOutDuration ) ); + // update the clientside weight once here, in case the fade duration is 0 + m_flCurWeightOnClient[nSlot] = Lerp( GetFadeRatio( nSlot ), m_flFadeStartWeight[nSlot], m_bFadingIn[nSlot] ? m_flMaxWeight : 0.0f ); +} +Vector C_ColorCorrection::GetOrigin() +{ + return m_vecOrigin; +} +float C_ColorCorrection::GetMinFalloff() +{ + return m_minFalloff; +} +float C_ColorCorrection::GetMaxFalloff() +{ + return m_maxFalloff; +} +void C_ColorCorrection::SetWeight( float fWeight ) +{ + g_pColorCorrectionMgr->SetColorCorrectionWeight( m_CCHandle, fWeight, false ); +} +void C_ColorCorrection::StartFade( int nSplitScreenSlot, float flDuration ) +{ + m_flFadeStartTime[nSplitScreenSlot] = gpGlobals->curtime; + m_flFadeDuration[nSplitScreenSlot] = MAX( flDuration, 0.0f ); +} +float C_ColorCorrection::GetFadeRatio( int nSplitScreenSlot ) const +{ + float flRatio = 1.0f; + + if ( m_flFadeDuration[nSplitScreenSlot] != 0.0f ) + { + flRatio = ( gpGlobals->curtime - m_flFadeStartTime[nSplitScreenSlot] ) / m_flFadeDuration[nSplitScreenSlot]; + flRatio = clamp( flRatio, 0.0f, 1.0f ); + } + return flRatio; +} + +bool C_ColorCorrection::IsFadeTimeElapsed( int nSplitScreenSlot ) const +{ + return ( ( gpGlobals->curtime - m_flFadeStartTime[nSplitScreenSlot] ) > m_flFadeDuration[nSplitScreenSlot] ) || + ( ( gpGlobals->curtime - m_flFadeStartTime[nSplitScreenSlot] ) < 0.0f ); +} +void UpdateColorCorrectionEntities( C_BasePlayer *pPlayer, float ccScale, C_ColorCorrection **pList, int listCount ) +{ + for ( int i = 0; i < listCount; i++ ) + { + pList[i]->Update(pPlayer, ccScale); + } +} \ No newline at end of file diff --git a/game/client/c_colorcorrection.h b/game/client/c_colorcorrection.h new file mode 100644 index 000000000..b9891f12b --- /dev/null +++ b/game/client/c_colorcorrection.h @@ -0,0 +1,76 @@ +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// +// +// Purpose: Color correction entity with simple radial falloff +// +// $NoKeywords: $ +//===========================================================================// + +#ifndef C_COLORCORRECTION_H +#define C_COLORCORRECTION_H +#ifdef _WIN32 +#pragma once +#endif + +#include "colorcorrectionmgr.h" + +//------------------------------------------------------------------------------ +// Purpose : Color correction entity with radial falloff +//------------------------------------------------------------------------------ +class C_ColorCorrection : public C_BaseEntity +{ +public: + DECLARE_CLASS( C_ColorCorrection, C_BaseEntity ); + + DECLARE_CLIENTCLASS(); + + C_ColorCorrection(); + virtual ~C_ColorCorrection(); + + void OnDataChanged(DataUpdateType_t updateType); + bool ShouldDraw(); + + virtual void Update(C_BasePlayer *pPlayer, float ccScale); + + bool IsMaster() const { return m_bMaster; } + bool IsClientSide() const; + bool IsExclusive() const { return m_bExclusive; } + + void EnableOnClient( bool bEnable, bool bSkipFade = false ); + + Vector GetOrigin(); + float GetMinFalloff(); + float GetMaxFalloff(); + + void SetWeight( float fWeight ); + +protected: + void StartFade( int nSplitScreenSlot, float flDuration ); + float GetFadeRatio( int nSplitScreenSlot ) const; + bool IsFadeTimeElapsed( int nSplitScreenSlot ) const; + + Vector m_vecOrigin; + + float m_minFalloff; + float m_maxFalloff; + float m_flFadeInDuration; + float m_flFadeOutDuration; + float m_flMaxWeight; + float m_flCurWeight; // networked from server + char m_netLookupFilename[MAX_PATH]; + + bool m_bEnabled; // networked from server + bool m_bMaster; + bool m_bClientSide; + bool m_bExclusive; + + bool m_bEnabledOnClient[MAX_SPLITSCREEN_PLAYERS]; + float m_flCurWeightOnClient[MAX_SPLITSCREEN_PLAYERS]; + bool m_bFadingIn[MAX_SPLITSCREEN_PLAYERS]; + float m_flFadeStartWeight[MAX_SPLITSCREEN_PLAYERS]; + float m_flFadeStartTime[MAX_SPLITSCREEN_PLAYERS]; + float m_flFadeDuration[MAX_SPLITSCREEN_PLAYERS]; + + ClientCCHandle_t m_CCHandle; +}; + +#endif \ No newline at end of file diff --git a/game/client/c_colorcorrectionvolume.cpp b/game/client/c_colorcorrectionvolume.cpp index 4bbcea947..9afba35dd 100644 --- a/game/client/c_colorcorrectionvolume.cpp +++ b/game/client/c_colorcorrectionvolume.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: Color correction entity. // @@ -8,8 +8,11 @@ #include "filesystem.h" #include "cdll_client_int.h" -#include "materialsystem/MaterialSystemUtil.h" +#include "materialsystem/materialsystemutil.h" #include "colorcorrectionmgr.h" +#include "c_triggers.h" + + // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -22,11 +25,10 @@ //------------------------------------------------------------------------------ // Purpose : Shadow control entity //------------------------------------------------------------------------------ -class C_ColorCorrectionVolume : public C_BaseEntity +class C_ColorCorrectionVolume : public C_BaseTrigger { public: - DECLARE_CLASS( C_ColorCorrectionVolume, C_BaseEntity ); - + DECLARE_CLASS( C_ColorCorrectionVolume, C_BaseTrigger ); DECLARE_CLIENTCLASS(); DECLARE_PREDICTABLE(); @@ -36,9 +38,20 @@ class C_ColorCorrectionVolume : public C_BaseEntity void OnDataChanged(DataUpdateType_t updateType); bool ShouldDraw(); - void ClientThink(); + void Update( C_BasePlayer *pPlayer, float ccScale ); + + void StartTouch( C_BaseEntity *pOther ); + void EndTouch( C_BaseEntity *pOther ); private: + float m_LastEnterWeight; + float m_LastEnterTime; + + float m_LastExitWeight; + float m_LastExitTime; + bool m_bEnabled; + float m_MaxWeight; + float m_FadeDuration; float m_Weight; char m_lookupFilename[MAX_PATH]; @@ -46,6 +59,9 @@ class C_ColorCorrectionVolume : public C_BaseEntity }; IMPLEMENT_CLIENTCLASS_DT(C_ColorCorrectionVolume, DT_ColorCorrectionVolume, CColorCorrectionVolume) + RecvPropBool( RECVINFO(m_bEnabled) ), + RecvPropFloat( RECVINFO(m_MaxWeight) ), + RecvPropFloat( RECVINFO(m_FadeDuration) ), RecvPropFloat( RECVINFO(m_Weight) ), RecvPropString( RECVINFO(m_lookupFilename) ), END_RECV_TABLE() @@ -65,7 +81,7 @@ C_ColorCorrectionVolume::C_ColorCorrectionVolume() C_ColorCorrectionVolume::~C_ColorCorrectionVolume() { - g_pColorCorrectionMgr->RemoveColorCorrection( m_CCHandle ); + g_pColorCorrectionMgr->RemoveColorCorrectionVolume( this, m_CCHandle ); } @@ -82,11 +98,16 @@ void C_ColorCorrectionVolume::OnDataChanged(DataUpdateType_t updateType) { if ( m_CCHandle == INVALID_CLIENT_CCHANDLE ) { - char filename[MAX_PATH]; - Q_strncpy( filename, m_lookupFilename, MAX_PATH ); + // forming a unique name without extension + char cleanName[MAX_PATH]; + V_StripExtension( m_lookupFilename, cleanName, sizeof( cleanName ) ); + char name[MAX_PATH]; + Q_snprintf( name, MAX_PATH, "%s_%d", cleanName, entindex() ); - m_CCHandle = g_pColorCorrectionMgr->AddColorCorrection( filename ); - SetNextClientThink( ( m_CCHandle != INVALID_CLIENT_CCHANDLE ) ? CLIENT_THINK_ALWAYS : CLIENT_THINK_NEVER ); + m_CCHandle = g_pColorCorrectionMgr->AddColorCorrectionVolume( this, name, m_lookupFilename ); + + SetSolid( SOLID_BSP ); + SetSolidFlags( FSOLID_TRIGGER | FSOLID_NOT_SOLID ); } } } @@ -99,21 +120,85 @@ bool C_ColorCorrectionVolume::ShouldDraw() return false; } -void C_ColorCorrectionVolume::ClientThink() + +//-------------------------------------------------------------------------------------------------------- +void C_ColorCorrectionVolume::StartTouch( CBaseEntity *pEntity ) { - Vector entityPosition = GetAbsOrigin(); - g_pColorCorrectionMgr->SetColorCorrectionWeight( m_CCHandle, m_Weight ); + m_LastEnterTime = gpGlobals->curtime; + m_LastEnterWeight = m_Weight; } +//-------------------------------------------------------------------------------------------------------- +void C_ColorCorrectionVolume::EndTouch( CBaseEntity *pEntity ) +{ + m_LastExitTime = gpGlobals->curtime; + m_LastExitWeight = m_Weight; +} +void C_ColorCorrectionVolume::Update( C_BasePlayer *pPlayer, float ccScale ) +{ + if ( pPlayer ) + { + bool isTouching = CollisionProp()->IsPointInBounds( pPlayer->EyePosition() ); + bool wasTouching = m_LastEnterTime > m_LastExitTime; + if ( isTouching && !wasTouching ) + { + StartTouch( pPlayer ); + } + else if ( !isTouching && wasTouching ) + { + EndTouch( pPlayer ); + } + } + if( !m_bEnabled ) + { + m_Weight = 0.0f; + } + else + { + if( m_LastEnterTime > m_LastExitTime ) + { + // we most recently entered the volume + if( m_Weight < 1.0f ) + { + float dt = gpGlobals->curtime - m_LastEnterTime; + float weight = m_LastEnterWeight + dt / ((1.0f-m_LastEnterWeight)*m_FadeDuration); + if( weight>1.0f ) + weight = 1.0f; + m_Weight = weight; + } + } + else + { + // we most recently exitted the volume + if( m_Weight > 0.0f ) + { + float dt = gpGlobals->curtime - m_LastExitTime; + float weight = (1.0f-m_LastExitWeight) + dt / (m_LastExitWeight*m_FadeDuration); + if( weight>1.0f ) + weight = 1.0f; + m_Weight = 1.0f - weight; + } + } + } + // Vector entityPosition = GetAbsOrigin(); + g_pColorCorrectionMgr->SetColorCorrectionWeight( m_CCHandle, m_Weight * ccScale ); +} +void UpdateColorCorrectionVolumes( C_BasePlayer *pPlayer, float ccScale, C_ColorCorrectionVolume **pList, int listCount ) +{ + for ( int i = 0; i < listCount; i++ ) + { + pList[i]->Update(pPlayer, ccScale); + } +} diff --git a/game/client/c_dynamiclight.cpp b/game/client/c_dynamiclight.cpp index aaa461a07..323abe961 100644 --- a/game/client/c_dynamiclight.cpp +++ b/game/client/c_dynamiclight.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: Dynamic light // @@ -9,7 +9,7 @@ #include "cbase.h" #include "dlight.h" #include "iefx.h" -#include "iviewrender.h" +#include "IViewRender.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -152,9 +152,10 @@ void C_DynamicLight::ClientThink(void) m_pDynamicLight->flags = m_Flags; if ( m_OuterAngle > 0 ) m_pDynamicLight->flags |= DLIGHT_NO_WORLD_ILLUMINATION; - m_pDynamicLight->color.r = m_clrRender->r; - m_pDynamicLight->color.g = m_clrRender->g; - m_pDynamicLight->color.b = m_clrRender->b; + color24 c = GetRenderColor(); + m_pDynamicLight->color.r = c.r; + m_pDynamicLight->color.g = c.g; + m_pDynamicLight->color.b = c.b; m_pDynamicLight->color.exponent = m_Exponent; // this makes it match the world m_pDynamicLight->origin = GetAbsOrigin(); m_pDynamicLight->m_InnerAngle = m_InnerAngle; @@ -210,9 +211,10 @@ void C_DynamicLight::ClientThink(void) m_pSpotlightEnd->flags = DLIGHT_NO_MODEL_ILLUMINATION | (m_Flags & DLIGHT_DISPLACEMENT_MASK); m_pSpotlightEnd->radius = m_SpotRadius; // * falloff; m_pSpotlightEnd->die = gpGlobals->curtime + 1e6; - m_pSpotlightEnd->color.r = m_clrRender->r * falloff; - m_pSpotlightEnd->color.g = m_clrRender->g * falloff; - m_pSpotlightEnd->color.b = m_clrRender->b * falloff; + color24 c = GetRenderColor(); + m_pSpotlightEnd->color.r = c.r * falloff; + m_pSpotlightEnd->color.g = c.g * falloff; + m_pSpotlightEnd->color.b = c.b * falloff; m_pSpotlightEnd->color.exponent = m_Exponent; // For bumped lighting diff --git a/game/client/c_effects.cpp b/game/client/c_effects.cpp index 14a90a4cc..2a15486cd 100644 --- a/game/client/c_effects.cpp +++ b/game/client/c_effects.cpp @@ -1,14 +1,14 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // // $NoKeywords: $ // -//=============================================================================// +//===========================================================================// #include "cbase.h" +#include "c_effects.h" #include "c_tracer.h" #include "view.h" -#include "initializer.h" #include "particles_simple.h" #include "env_wind_shared.h" #include "engine/IEngineTrace.h" @@ -17,11 +17,17 @@ #include "fx_water.h" #include "c_world.h" #include "iviewrender.h" -#include "engine/ivdebugoverlay.h" -#include "clienteffectprecachesystem.h" +#include "engine/IVDebugOverlay.h" +#include "precache_register.h" #include "collisionutils.h" #include "tier0/vprof.h" #include "viewrender.h" +#include "raytrace.h" +#ifdef INFESTED_DLL +#include "c_asw_player.h" +#include "c_asw_marine.h" +#include "asw_input.h" +#endif // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -34,7 +40,8 @@ float g_flSplashScale = 0.15; float g_flSplashLifetime = 0.5f; float g_flSplashAlpha = 0.3f; ConVar r_RainSplashPercentage( "r_RainSplashPercentage", "20", FCVAR_CHEAT ); // N% chance of a rain particle making a splash. - +ConVar r_RainParticleDensity( "r_RainParticleDensity", "1", FCVAR_NONE, "Density of Particle Rain 0-1" ); +ConVar r_RainAllowInSplitScreen( "r_RainAllowInSplitScreen", "0", FCVAR_NONE, "Allows rain in splitscreen" ); float GUST_INTERVAL_MIN = 1; float GUST_INTERVAL_MAX = 2; @@ -49,162 +56,79 @@ ConVar r_RainHack( "r_RainHack", "0", FCVAR_CHEAT ); ConVar r_RainRadius( "r_RainRadius", "1500", FCVAR_CHEAT ); ConVar r_RainSideVel( "r_RainSideVel", "130", FCVAR_CHEAT, "How much sideways velocity rain gets." ); +// Performance optimization by Certain Affinity +// calling IsInAir() for 800 particles was taking 4 ms +ConVar r_RainCheck( "r_RainCheck", "0", FCVAR_CHEAT, "Enable/disable IsInAir() check for rain drops?" ); + ConVar r_RainSimulate( "r_RainSimulate", "1", FCVAR_CHEAT, "Enable/disable rain simulation." ); ConVar r_DrawRain( "r_DrawRain", "1", FCVAR_CHEAT, "Enable/disable rain rendering." ); ConVar r_RainProfile( "r_RainProfile", "0", FCVAR_CHEAT, "Enable/disable rain profiling." ); +ConVar r_RainDebugDuration( "r_RainDebugDuration", "0", FCVAR_CHEAT, "Shows rain tracelines for this many seconds (0 disables)" ); //Precahce the effects -CLIENTEFFECT_REGISTER_BEGIN( PrecachePrecipitation ) -CLIENTEFFECT_MATERIAL( "particle/rain" ) -CLIENTEFFECT_MATERIAL( "particle/snow" ) -CLIENTEFFECT_REGISTER_END() +PRECACHE_REGISTER_BEGIN( GLOBAL, PrecachePrecipitation ) + PRECACHE( MATERIAL, "particle/rain" ) + PRECACHE( MATERIAL, "particle/snow" ) + PRECACHE( PARTICLE_SYSTEM, "rain_storm" ) + PRECACHE( PARTICLE_SYSTEM, "rain_storm_screen" ) + PRECACHE( PARTICLE_SYSTEM, "rain_storm_outer" ) + PRECACHE( PARTICLE_SYSTEM, "rain" ) + PRECACHE( PARTICLE_SYSTEM, "rain_outer" ) + PRECACHE( PARTICLE_SYSTEM, "ash" ) + PRECACHE( PARTICLE_SYSTEM, "ash_outer" ) +#ifdef INFESTED_DLL + PRECACHE( PARTICLE_SYSTEM, "asw_snow" ) + PRECACHE( PARTICLE_SYSTEM, "asw_snow_outer" ) +#else + PRECACHE( PARTICLE_SYSTEM, "snow" ) + PRECACHE( PARTICLE_SYSTEM, "snow_outer" ) +#endif +PRECACHE_REGISTER_END() + +CUtlVector< RayTracingEnvironment* > g_RayTraceEnvironments; //----------------------------------------------------------------------------- -// Precipitation particle type +// Precipitation blocker entity //----------------------------------------------------------------------------- -class CPrecipitationParticle -{ -public: - Vector m_Pos; - Vector m_Velocity; - float m_SpawnTime; // Note: Tweak with this to change lifetime - float m_Mass; - float m_Ramp; - - float m_flCurLifetime; - float m_flMaxLifetime; -}; - +// Just receive the normal data table stuff +IMPLEMENT_CLIENTCLASS_DT(C_PrecipitationBlocker, DT_PrecipitationBlocker, CPrecipitationBlocker) +END_RECV_TABLE() -class CClient_Precipitation; -static CUtlVector g_Precipitations; -//=========== -// Snow fall -//=========== -class CSnowFallManager; -static CSnowFallManager *s_pSnowFallMgr = NULL; -bool SnowFallManagerCreate( CClient_Precipitation *pSnowEntity ); -void SnowFallManagerDestroy( void ); +static CUtlVector< C_PrecipitationBlocker * > g_PrecipitationBlockers; -class AshDebrisEffect : public CSimpleEmitter +C_PrecipitationBlocker::C_PrecipitationBlocker() { -public: - AshDebrisEffect( const char *pDebugName ) : CSimpleEmitter( pDebugName ) {} - - static AshDebrisEffect* Create( const char *pDebugName ); - - virtual float UpdateAlpha( const SimpleParticle *pParticle ); - virtual float UpdateRoll( SimpleParticle *pParticle, float timeDelta ); - -private: - AshDebrisEffect( const AshDebrisEffect & ); -}; - -//----------------------------------------------------------------------------- -// Precipitation base entity -//----------------------------------------------------------------------------- + g_PrecipitationBlockers.AddToTail( this ); +} -class CClient_Precipitation : public C_BaseEntity +C_PrecipitationBlocker::~C_PrecipitationBlocker() { -class CPrecipitationEffect; -friend class CClient_Precipitation::CPrecipitationEffect; - -public: - DECLARE_CLASS( CClient_Precipitation, C_BaseEntity ); - DECLARE_CLIENTCLASS(); - - CClient_Precipitation(); - virtual ~CClient_Precipitation(); - - // Inherited from C_BaseEntity - virtual void Precache( ); - - void Render(); - -private: - - // Creates a single particle - CPrecipitationParticle* CreateParticle(); - - virtual void OnDataChanged( DataUpdateType_t updateType ); - virtual void ClientThink(); - - void Simulate( float dt ); - - // Renders the particle - void RenderParticle( CPrecipitationParticle* pParticle, CMeshBuilder &mb ); - - void CreateWaterSplashes(); - - // Emits the actual particles - void EmitParticles( float fTimeDelta ); - - // Computes where we're gonna emit - bool ComputeEmissionArea( Vector& origin, Vector2D& size ); - - // Gets the tracer width and speed - float GetWidth() const; - float GetLength() const; - float GetSpeed() const; - - // Gets the remaining lifetime of the particle - float GetRemainingLifetime( CPrecipitationParticle* pParticle ) const; - - // Computes the wind vector - static void ComputeWindVector( ); - - // simulation methods - bool SimulateRain( CPrecipitationParticle* pParticle, float dt ); - bool SimulateSnow( CPrecipitationParticle* pParticle, float dt ); - - void CreateAshParticle( void ); - void CreateRainOrSnowParticle( Vector vSpawnPosition, Vector vVelocity ); - - // Information helpful in creating and rendering particles - IMaterial *m_MatHandle; // material used - - float m_Color[4]; // precip color - float m_Lifetime; // Precip lifetime - float m_InitialRamp; // Initial ramp value - float m_Speed; // Precip speed - float m_Width; // Tracer width - float m_Remainder; // particles we should render next time - PrecipitationType_t m_nPrecipType; // Precip type - float m_flHalfScreenWidth; // Precalculated each frame. - - float m_flDensity; - - // Some state used in rendering and simulation - // Used to modify the rain density and wind from the console - static ConVar s_raindensity; - static ConVar s_rainwidth; - static ConVar s_rainlength; - static ConVar s_rainspeed; - - static Vector s_WindVector; // Stores the wind speed vector - - CUtlLinkedList m_Particles; - CUtlVector m_Splashes; - - CSmartPtr m_pAshEmitter; - TimedEvent m_tAshParticleTimer; - TimedEvent m_tAshParticleTraceTimer; - bool m_bActiveAshEmitter; - Vector m_vAshSpawnOrigin; - - int m_iAshCount; + g_PrecipitationBlockers.FindAndRemove( this ); +} -private: - CClient_Precipitation( const CClient_Precipitation & ); // not defined, not accessible -}; +bool ParticleIsBlocked( const Vector &end, const Vector &start ) +{ + for ( int i=0; iCollisionProp()->IsPointInBounds( end ) ) + { + return true; + } + } + return false; +} // Just receive the normal data table stuff IMPLEMENT_CLIENTCLASS_DT(CClient_Precipitation, DT_Precipitation, CPrecipitation) - RecvPropInt( RECVINFO( m_nPrecipType ) ) + RecvPropInt( RECVINFO( m_nPrecipType ) ), +#ifdef INFESTED_DLL + RecvPropInt( RECVINFO( m_nSnowDustAmount ) ), +#endif END_RECV_TABLE() static ConVar r_SnowEnable( "r_SnowEnable", "1", FCVAR_CHEAT, "Snow Enable" ); @@ -275,7 +199,7 @@ void CClient_Precipitation::OnDataChanged( DataUpdateType_t updateType ) } } - m_flDensity = RemapVal( m_clrRender->a, 0, 255, 0, 0.001 ); + m_flDensity = RemapVal( GetRenderAlpha(), 0, 100, 0, 1 ); BaseClass::OnDataChanged( updateType ); } @@ -303,27 +227,32 @@ inline bool CClient_Precipitation::SimulateRain( CPrecipitationParticle* pPartic VectorMA( pParticle->m_Pos, dt, pParticle->m_Velocity, pParticle->m_Pos ); + if (cl_windspeed.GetFloat() > 0) // determines if s_WindVector is zeroes + { // wind blows rain around - for ( int i = 0 ; i < 2 ; i++ ) + float drift = 5 / pParticle->m_Mass; + for ( int i = 0 ; i < 2 ; i++ ) // X and Y components { - if ( pParticle->m_Velocity[i] < s_WindVector[i] ) + float vel = pParticle->m_Velocity[i]; + float wind = s_WindVector[i]; + if ( vel < wind ) { - pParticle->m_Velocity[i] += ( 5 / pParticle->m_Mass ); - - // clamp - if ( pParticle->m_Velocity[i] > s_WindVector[i] ) - pParticle->m_Velocity[i] = s_WindVector[i]; + vel = MIN( vel+drift, wind); } - else if (pParticle->m_Velocity[i] > s_WindVector[i] ) + else if ( vel > wind ) { - pParticle->m_Velocity[i] -= ( 5 / pParticle->m_Mass ); - - // clamp. - if ( pParticle->m_Velocity[i] < s_WindVector[i] ) - pParticle->m_Velocity[i] = s_WindVector[i]; + vel = MAX( vel-drift, wind); + } + pParticle->m_Velocity[i] = vel; } } + // Left4Dead does not use rain splashes on water surfaces + // This change could allow rain into some solids, but the code + // already performed a ray-test to calculate the particle lifetime, + // so it should still be blocked by normal bsp surfaces. + if (r_RainCheck.GetInt() != 0) + { // No longer in the air? punt. if ( !IsInAir( pParticle->m_Pos ) ) { @@ -344,6 +273,7 @@ inline bool CClient_Precipitation::SimulateRain( CPrecipitationParticle* pPartic // Tell the framework it's time to remove the particle from the list return false; } + } // We still want this particle return true; @@ -396,6 +326,13 @@ inline bool CClient_Precipitation::SimulateSnow( CPrecipitationParticle* pPartic void CClient_Precipitation::Simulate( float dt ) { + if ( m_nPrecipType == PRECIPITATION_TYPE_PARTICLERAIN || m_nPrecipType == PRECIPITATION_TYPE_PARTICLEASH + || m_nPrecipType == PRECIPITATION_TYPE_PARTICLERAINSTORM || PRECIPITATION_TYPE_PARTICLESNOW ) + { + CreateParticlePrecip(); + return; + } + // NOTE: When client-side prechaching works, we need to remove this Precache(); @@ -472,6 +409,10 @@ inline void CClient_Precipitation::RenderParticle( CPrecipitationParticle* pPart float scale; Vector start, delta; + if ( m_nPrecipType == PRECIPITATION_TYPE_PARTICLERAIN || m_nPrecipType == PRECIPITATION_TYPE_PARTICLEASH + || m_nPrecipType == PRECIPITATION_TYPE_PARTICLERAINSTORM || PRECIPITATION_TYPE_PARTICLESNOW ) + return; + if ( m_nPrecipType == PRECIPITATION_TYPE_ASH ) return; @@ -559,9 +500,15 @@ void CClient_Precipitation::CreateWaterSplashes() void CClient_Precipitation::Render() { + ASSERT_LOCAL_PLAYER_RESOLVABLE(); + int nSlot = GET_ACTIVE_SPLITSCREEN_SLOT(); if ( !r_DrawRain.GetInt() ) return; + if ( m_nPrecipType == PRECIPITATION_TYPE_PARTICLERAIN || m_nPrecipType == PRECIPITATION_TYPE_PARTICLEASH + || m_nPrecipType == PRECIPITATION_TYPE_PARTICLERAINSTORM || PRECIPITATION_TYPE_PARTICLESNOW ) + return; + // Don't render in monitors or in reflections or refractions. if ( CurrentViewID() == VIEW_MONITOR ) return; @@ -605,6 +552,8 @@ void CClient_Precipitation::Render() for ( int i=m_Particles.Head(); i != m_Particles.InvalidIndex(); i=m_Particles.Next( i ) ) { CPrecipitationParticle *p = &m_Particles[i]; + if ( p->m_nSplitScreenPlayerSlot != nSlot ) + continue; RenderParticle( p, mb ); } @@ -633,6 +582,14 @@ CClient_Precipitation::CClient_Precipitation() : m_Remainder(0.0f) m_MatHandle = INVALID_MATERIAL_HANDLE; m_flHalfScreenWidth = 1; + for ( int i = 0; i < MAX_SPLITSCREEN_PLAYERS; ++i ) + { + m_pParticlePrecipInnerNear[ i ] = NULL; + m_pParticlePrecipInnerFar[ i ] = NULL; + m_pParticlePrecipOuter[ i ] = NULL; + m_bActiveParticlePrecipEmitter[ i ] = false; + } + g_Precipitations.AddToTail( this ); } @@ -718,7 +675,7 @@ inline float CClient_Precipitation::GetSpeed() const inline float CClient_Precipitation::GetRemainingLifetime( CPrecipitationParticle* pParticle ) const { float timeSinceSpawn = gpGlobals->curtime - pParticle->m_SpawnTime; - return m_Lifetime - timeSinceSpawn; + return pParticle->m_flMaxLifetime - timeSinceSpawn; // TERROR: use per-particle lifetime not dependent on func_precipitation lower bound } //----------------------------------------------------------------------------- @@ -733,6 +690,9 @@ inline CPrecipitationParticle* CClient_Precipitation::CreateParticle() pParticle->m_SpawnTime = gpGlobals->curtime; pParticle->m_Ramp = m_InitialRamp; + ASSERT_LOCAL_PLAYER_RESOLVABLE(); + pParticle->m_nSplitScreenPlayerSlot = GET_ACTIVE_SPLITSCREEN_SLOT(); + return pParticle; } @@ -741,8 +701,14 @@ inline CPrecipitationParticle* CClient_Precipitation::CreateParticle() // Compute the emission area //----------------------------------------------------------------------------- -bool CClient_Precipitation::ComputeEmissionArea( Vector& origin, Vector2D& size ) +bool CClient_Precipitation::ComputeEmissionArea( Vector& origin, Vector2D& size, C_BaseCombatCharacter *pCharacter ) { + // calculate a volume around the player to snow in. Intersect this big magic + // box around the player with the volume of the current environmental ent. + + if ( !pCharacter ) + return false; + // FIXME: Compute the precipitation area based on computational power float emissionSize = r_RainRadius.GetFloat(); // size of box to emit particles in @@ -754,21 +720,15 @@ bool CClient_Precipitation::ComputeEmissionArea( Vector& origin, Vector2D& size vMaxs = GetClientWorldEntity()->m_WorldMaxs; } - // calculate a volume around the player to snow in. Intersect this big magic - // box around the player with the volume of the current environmental ent. - C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); - if ( !pPlayer ) - return false; - // Determine how much time it'll take a falling particle to hit the player - float emissionHeight = MIN( vMaxs[2], pPlayer->GetAbsOrigin()[2] + 512 ); - float distToFall = emissionHeight - pPlayer->GetAbsOrigin()[2]; + float emissionHeight = MIN( vMaxs[2], pCharacter->GetAbsOrigin()[2] + 512 ); + float distToFall = emissionHeight - pCharacter->GetAbsOrigin()[2]; float fallTime = distToFall / GetSpeed(); // Based on the windspeed, figure out the center point of the emission Vector2D center; - center[0] = pPlayer->GetAbsOrigin()[0] - fallTime * s_WindVector[0]; - center[1] = pPlayer->GetAbsOrigin()[1] - fallTime * s_WindVector[1]; + center[0] = pCharacter->GetAbsOrigin()[0] - fallTime * s_WindVector[0]; + center[1] = pCharacter->GetAbsOrigin()[1] - fallTime * s_WindVector[1]; Vector2D lobound, hibound; lobound[0] = center[0] - emissionSize * 0.5f; @@ -839,22 +799,25 @@ float AshDebrisEffect::UpdateRoll( SimpleParticle *pParticle, float timeDelta ) void CClient_Precipitation::CreateAshParticle( void ) { + FOR_EACH_VALID_SPLITSCREEN_PLAYER( hh ) + { + ACTIVE_SPLITSCREEN_PLAYER_GUARD( hh ); // Make sure the emitter is setup - if ( m_pAshEmitter == NULL ) + if ( m_Ash[ hh ].m_pAshEmitter == NULL ) { - if ( ( m_pAshEmitter = AshDebrisEffect::Create( "ashtray" ) ) == NULL ) - return; + if ( ( m_Ash[ hh ].m_pAshEmitter = AshDebrisEffect::Create( "ashtray" ) ) == NULL ) + continue; - m_tAshParticleTimer.Init( 192 ); - m_tAshParticleTraceTimer.Init( 15 ); - m_bActiveAshEmitter = false; - m_iAshCount = 0; + m_Ash[ hh ].m_tAshParticleTimer.Init( 192 ); + m_Ash[ hh ].m_tAshParticleTraceTimer.Init( 15 ); + m_Ash[ hh ].m_bActiveAshEmitter = false; + m_Ash[ hh ].m_iAshCount = 0; + m_Ash[ hh ].m_pAshEmitter->SetShouldDrawForSplitScreenUser( hh ); } C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); - if ( pPlayer == NULL ) - return; + continue; Vector vForward; pPlayer->GetVectors( &vForward, NULL, NULL ); @@ -868,7 +831,7 @@ void CClient_Precipitation::CreateAshParticle( void ) Vector absmaxs = WorldAlignMaxs(); //15 Traces a second. - while ( m_tAshParticleTraceTimer.NextEvent( curTime ) ) + while ( m_Ash[ hh ].m_tAshParticleTraceTimer.NextEvent( curTime ) ) { trace_t tr; @@ -876,7 +839,7 @@ void CClient_Precipitation::CreateAshParticle( void ) Vector vTraceEnd = pPlayer->EyePosition() + vForward * MAX_TRACE_LENGTH; UTIL_TraceLine( vTraceStart, vTraceEnd, MASK_SHOT_HULL & (~CONTENTS_GRATE), pPlayer, COLLISION_GROUP_NONE, &tr ); - + //UTIL_TraceModel( vTraceStart, vTraceEnd, Vector( -1, -1, -1 ), Vector( 1, 1, 1 ), this, COLLISION_GROUP_NONE, &tr ); //debugoverlay->AddLineOverlay( vTraceStart, tr.endpos, 255, 0, 0, 0, 0.2 ); if ( tr.fraction != 1.0f ) @@ -887,34 +850,34 @@ void CClient_Precipitation::CreateAshParticle( void ) if ( tr2.m_pEnt == this ) { - m_bActiveAshEmitter = true; + m_Ash[ hh ].m_bActiveAshEmitter = true; if ( tr2.startsolid == false ) { - m_vAshSpawnOrigin = tr2.endpos + vForward * 256; + m_Ash[ hh ].m_vAshSpawnOrigin = tr2.endpos + vForward * 256; } else { - m_vAshSpawnOrigin = vTraceStart; + m_Ash[ hh ].m_vAshSpawnOrigin = vTraceStart; } } else { - m_bActiveAshEmitter = false; + m_Ash[ hh ].m_bActiveAshEmitter = false; } } } - if ( m_bActiveAshEmitter == false ) - return; + if ( m_Ash[ hh ].m_bActiveAshEmitter == false ) + continue; Vector vecVelocity = pPlayer->GetAbsVelocity(); float flVelocity = VectorNormalize( vecVelocity ); - Vector offset = m_vAshSpawnOrigin; + Vector offset = m_Ash[ hh ].m_vAshSpawnOrigin; - m_pAshEmitter->SetSortOrigin( offset ); + m_Ash[ hh ].m_pAshEmitter->SetSortOrigin( offset ); PMaterialHandle hMaterial[4]; hMaterial[0] = ParticleMgr()->GetPMaterial( "effects/fleck_ash1" ); @@ -932,12 +895,12 @@ void CClient_Precipitation::CreateAshParticle( void ) } // Add as many particles as we need - while ( m_tAshParticleTimer.NextEvent( curTime ) ) + while ( m_Ash[ hh ].m_tAshParticleTimer.NextEvent( curTime ) ) { int iRandomAltitude = RandomInt( 0, 128 ); - offset = m_vAshSpawnOrigin + vSpawnOrigin + RandomVector( -256, 256 ); - offset.z = m_vAshSpawnOrigin.z + iRandomAltitude; + offset = m_Ash[ hh ].m_vAshSpawnOrigin + vSpawnOrigin + RandomVector( -256, 256 ); + offset.z = m_Ash[ hh ].m_vAshSpawnOrigin.z + iRandomAltitude; if ( offset[0] > absmaxs[0] || offset[1] > absmaxs[1] @@ -947,27 +910,27 @@ void CClient_Precipitation::CreateAshParticle( void ) || offset[2] < absmins[2] ) continue; - m_iAshCount++; + m_Ash[ hh ].m_iAshCount++; bool bEmberTime = false; - if ( m_iAshCount >= 250 ) + if ( m_Ash[ hh ].m_iAshCount >= 250 ) { bEmberTime = true; - m_iAshCount = 0; + m_Ash[ hh ].m_iAshCount = 0; } int iRandom = random->RandomInt(0,2); if ( bEmberTime == true ) { - offset = m_vAshSpawnOrigin + (vForward * 256) + RandomVector( -128, 128 ); + offset = m_Ash[ hh ].m_vAshSpawnOrigin + (vForward * 256) + RandomVector( -128, 128 ); offset.z = pPlayer->EyePosition().z + RandomFloat( -16, 64 ); iRandom = 3; } - pParticle = (SimpleParticle *) m_pAshEmitter->AddParticle( sizeof(SimpleParticle), hMaterial[iRandom], offset ); + pParticle = (SimpleParticle *)m_Ash[ hh ].m_pAshEmitter->AddParticle( sizeof(SimpleParticle), hMaterial[iRandom], offset ); if (pParticle == NULL) continue; @@ -995,7 +958,7 @@ void CClient_Precipitation::CreateAshParticle( void ) pParticle->m_uchColor[2] = color; pParticle->m_uchStartSize = 1; - pParticle->m_uchEndSize = 1; + pParticle->m_uchEndSize = 1.5; pParticle->m_uchStartAlpha = 255; @@ -1010,8 +973,381 @@ void CClient_Precipitation::CreateAshParticle( void ) } } } +} + + +void CClient_Precipitation::CreateParticlePrecip( void ) +{ + if ( !r_RainAllowInSplitScreen.GetBool() && engine->IsSplitScreenActive() ) + { + FOR_EACH_VALID_SPLITSCREEN_PLAYER( hh ) + { + if ( m_pParticlePrecipOuter[hh] != NULL ) + { + DestroyInnerParticlePrecip( hh ); + DestroyOuterParticlePrecip( hh ); + } + } + return; + } + + if ( !m_bParticlePrecipInitialized ) + { + InitializeParticlePrecip(); + } + + + FOR_EACH_VALID_SPLITSCREEN_PLAYER( hh ) + { + ACTIVE_SPLITSCREEN_PLAYER_GUARD( hh ); + + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + + if ( pPlayer == NULL ) + continue; + + // Make sure the emitter is setup + if ( !m_bActiveParticlePrecipEmitter[hh] ) + { + //Update 8 times per second. + m_tParticlePrecipTraceTimer[hh].Init( 8 ); + DestroyInnerParticlePrecip( hh ); + DestroyOuterParticlePrecip( hh ); + m_bActiveParticlePrecipEmitter[hh] = true; + } + + UpdateParticlePrecip( pPlayer, hh ); + } +} + +void CClient_Precipitation::UpdateParticlePrecip( C_BasePlayer *pPlayer, int nSlot ) +{ + if ( !pPlayer ) + return; + + Vector vForward; + Vector vRight; + +#ifdef INFESTED_DLL + vForward[PITCH] = 0; + vForward[YAW] = ASWInput()->ASW_GetCameraPitch(); + vForward[ROLL] = -ASWInput()->ASW_GetCameraYaw(); + vForward.NormalizeInPlace(); +#else + pPlayer->GetVectors( &vForward, &vRight, NULL ); + vForward.z = 0.0f; + vForward.NormalizeInPlace(); + Vector vForward45Right = vForward + vRight; + Vector vForward45Left = vForward - vRight; + vForward45Right.NormalizeInPlace(); + vForward45Left.NormalizeInPlace(); + fltx4 TMax = ReplicateX4( 320.0f ); + SubFloat( TMax, 3 ) = FLT_MAX; +#endif + float curTime = gpGlobals->frametime; + + while ( m_tParticlePrecipTraceTimer[nSlot].NextEvent( curTime ) ) + { +#ifdef INFESTED_DLL + Vector vPlayerPos = MainViewOrigin( nSlot ); + Vector vOffsetPos = vPlayerPos + Vector ( 0, 0, 4 ); + Vector vOffsetPosNear = vPlayerPos + Vector ( 0, 0, 4 ) + ( vForward * 32 ); + Vector vOffsetPosFar = vPlayerPos + Vector ( 0, 0, 4 ) + ( vForward * 100 ); + Vector vDensity = Vector( r_RainParticleDensity.GetFloat(), (float)m_nSnowDustAmount/100.0f, 0 ) * m_flDensity; + + RayTracingEnvironment *RtEnv = g_RayTraceEnvironments.Element( 0 ); + + bool bInside = !engine->CullBox( RtEnv->m_MinBound, RtEnv->m_MaxBound ); + bool bNearby = false; +#else + Vector vPlayerPos = pPlayer->EyePosition(); + Vector vOffsetPos = vPlayerPos + Vector ( 0, 0, 180 ); + Vector vOffsetPosNear = vPlayerPos + Vector ( 0, 0, 180 ) + ( vForward * 32 ); + Vector vOffsetPosFar = vPlayerPos + Vector ( 0, 0, 180 ) + ( vForward * 100 ); + + Vector vDensity = Vector( r_RainParticleDensity.GetFloat(), 0, 0 ) * m_flDensity; + + // Get the rain volume Ray Tracing Environment. Currently hard coded to 0, should have this lookup + RayTracingEnvironment *RtEnv = g_RayTraceEnvironments.Element( 0 ); + + // Our 4 Rays are forward, off to the left and right, and directly up. + // Use the first three to determine if there's generally visible rain where we're looking. + // The forth, straight up, tells us if we're standing inside a rain volume + // (based on the normal that we hit or if we miss entirely) + FourRays frRays; + FourVectors fvDirection; + fvDirection = FourVectors( vForward, vForward45Left, vForward45Right, Vector( 0, 0, 1 ) ); + frRays.direction = fvDirection; + frRays.origin.DuplicateVector( vPlayerPos ); + RayTracingResult Result; + + RtEnv->Trace4Rays( frRays, Four_Zeros, TMax, &Result ); + + i32x4 in4HitIds = LoadAlignedIntSIMD( Result.HitIds ); + fltx4 fl4HitIds = SignedIntConvertToFltSIMD ( in4HitIds ); + + fltx4 fl4Tolerance = ReplicateX4( 300.0f ); + // ignore upwards test for tolerance, as we may be below an area which is raining, but with it not visible in front of us + //SubFloat( fl4Tolerance, 3 ) = 0.0f; + + bool bInside = ( Result.HitIds[3] != -1 && Result.surface_normal.Vec( 3 ).z < 0.0f ); + bool bNearby = ( IsAnyNegative ( CmpGeSIMD ( fl4HitIds, Four_Zeros ) ) && IsAnyNegative( CmpGeSIMD( fl4Tolerance, Result.HitDistance ) ) ); +#endif + + if ( bInside || bNearby ) + { +#ifdef INFESTED_DLL + //debugoverlay->AddBoxOverlay(vPlayerPos, Vector( -12, -12, -12 ), Vector( 12, 12, 12 ), QAngle( 0, 0, 0 ), 255, 0, 0, 32, 0.2f ); + //debugoverlay->AddBoxOverlay(vOffsetPosNear, Vector( -10, -10, -10 ), Vector( 10, 10, 10 ), QAngle( 0, 0, 0 ), 0, 255, 0, 32, 0.2f ); + //debugoverlay->AddBoxOverlay(vOffsetPosFar, Vector( -5, -5, -5 ), Vector( 5, 5, 5 ), QAngle( 0, 0, 0 ), 0, 0, 255, 32, 0.2f ); + + // Update if we've already got systems, otherwise, create them. + if ( m_pParticlePrecipInnerNear[nSlot] != NULL && m_pParticlePrecipInnerFar[nSlot] != NULL && m_pParticlePrecipOuter[nSlot] != NULL ) + { + m_pParticlePrecipOuter[nSlot]->SetControlPoint( 1, vOffsetPos ); + m_pParticlePrecipInnerNear[nSlot]->SetControlPoint( 1, vOffsetPosNear ); + m_pParticlePrecipInnerFar[nSlot]->SetControlPoint( 1, vOffsetPosFar ); + m_pParticlePrecipInnerNear[nSlot]->SetControlPoint( 3, vDensity ); + m_pParticlePrecipInnerFar[nSlot]->SetControlPoint( 3, vDensity ); + m_pParticlePrecipOuter[nSlot]->SetControlPoint( 3, vDensity ); + } + else + { + DispatchInnerParticlePrecip( nSlot, pPlayer, vForward ); + } +#else + //We can see a rain volume, but it's farther than 180 units away, only use far effect. + if ( !bInside && SubFloat( FindLowestSIMD3( Result.HitDistance ), 0 ) >= m_flParticleInnerDist ) + { + // Kill the inner rain if it's previously been in use + if ( m_pParticlePrecipInnerNear[nSlot] != NULL ) + { + DestroyInnerParticlePrecip( nSlot ); + } + // Update if we've already got systems, otherwise, create them. + if ( m_pParticlePrecipOuter[nSlot] != NULL ) + { + m_pParticlePrecipOuter[nSlot]->SetControlPoint( 1, vOffsetPos ); + m_pParticlePrecipOuter[nSlot]->SetControlPoint( 3, vDensity ); + } + else + { + DispatchOuterParticlePrecip( nSlot, pPlayer, vForward ); + } + } + else //We're close enough to use the near effect. + { + // Update if we've already got systems, otherwise, create them. + if ( m_pParticlePrecipInnerNear[nSlot] != NULL && m_pParticlePrecipInnerFar[nSlot] != NULL && m_pParticlePrecipOuter[nSlot] != NULL ) + { + m_pParticlePrecipOuter[nSlot]->SetControlPoint( 1, vOffsetPos ); + m_pParticlePrecipInnerNear[nSlot]->SetControlPoint( 1, vOffsetPosNear ); + m_pParticlePrecipInnerFar[nSlot]->SetControlPoint( 1, vOffsetPosFar ); + m_pParticlePrecipInnerNear[nSlot]->SetControlPoint( 3, vDensity ); + m_pParticlePrecipInnerFar[nSlot]->SetControlPoint( 3, vDensity ); + m_pParticlePrecipOuter[nSlot]->SetControlPoint( 3, vDensity ); + } + else + { + DispatchInnerParticlePrecip( nSlot, pPlayer, vForward ); + } + } +#endif + } + else // No rain in the area, kill any leftover systems. + { + DestroyInnerParticlePrecip( nSlot ); + DestroyOuterParticlePrecip( nSlot ); + } + } +} + +void CClient_Precipitation::InitializeParticlePrecip( void ) +{ + //Set up which type of precipitation particle we'll use + if ( m_nPrecipType == PRECIPITATION_TYPE_PARTICLEASH ) + { + m_pParticleInnerNearDef = "ash"; + m_pParticleInnerFarDef = "ash"; + m_pParticleOuterDef = "ash_outer"; + m_flParticleInnerDist = 280.0; + } + else if ( m_nPrecipType == PRECIPITATION_TYPE_PARTICLESNOW ) + { +#ifdef INFESTED_DLL + m_pParticleInnerNearDef = "asw_snow"; + m_pParticleInnerFarDef = "asw_snow"; + m_pParticleOuterDef = "asw_snow_outer"; + m_flParticleInnerDist = 240.0; +#else + m_pParticleInnerNearDef = "snow"; + m_pParticleInnerFarDef = "snow"; + m_pParticleOuterDef = "snow_outer"; + m_flParticleInnerDist = 280.0; +#endif + } + else if ( m_nPrecipType == PRECIPITATION_TYPE_PARTICLERAINSTORM ) + { + m_pParticleInnerNearDef = "rain_storm"; + m_pParticleInnerFarDef = "rain_storm_screen"; + m_pParticleOuterDef = "rain_storm_outer"; + m_flParticleInnerDist = 0.0; + } + else //default to rain + { + m_pParticleInnerNearDef = "rain"; + m_pParticleInnerFarDef = "rain"; + m_pParticleOuterDef = "rain_outer"; + m_flParticleInnerDist = 180.0; + } + + Assert( m_pParticleInnerFarDef != NULL ); + + //We'll want to change this if/when we add more raytrace environments. + g_RayTraceEnvironments.PurgeAndDeleteElements(); + + // Sets up ray tracing environments for all func_precipitations and func_precipitation_blockers + RayTracingEnvironment *rtEnvRainEmission = new RayTracingEnvironment(); + g_RayTraceEnvironments.AddToTail( rtEnvRainEmission ); + RayTracingEnvironment *rtEnvRainBlocker = new RayTracingEnvironment(); + g_RayTraceEnvironments.AddToTail( rtEnvRainBlocker ); + + rtEnvRainEmission->Flags |= RTE_FLAGS_DONT_STORE_TRIANGLE_COLORS; // save some ram + rtEnvRainBlocker->Flags |= RTE_FLAGS_DONT_STORE_TRIANGLE_COLORS; // save some ram + + int nTriCount = 1; + for ( int i=0; iGetVCollide( volume->GetModelIndex() ); + + if ( !pCollide || pCollide->solidCount <= 0 ) + continue; + + Vector *outVerts; + int vertCount = g_pPhysicsCollision->CreateDebugMesh( pCollide->solids[0], &outVerts ); + + if ( vertCount ) + { + for ( int j = 0; j < vertCount; j += 3 ) + { + rtEnvRainEmission->AddTriangle( nTriCount++, outVerts[j], outVerts[j + 1], outVerts[j + 2], Vector( 1, 1, 1 ) ); + } + } + physcollision->DestroyDebugMesh( vertCount, outVerts ); + } + rtEnvRainEmission->SetupAccelerationStructure(); + + nTriCount = 1; + + for ( int i=0; iGetVCollide( blocker->GetModelIndex() ); + + if ( !pCollide || pCollide->solidCount <= 0 ) + continue; + + Vector *outVerts; + int vertCount = g_pPhysicsCollision->CreateDebugMesh( pCollide->solids[0], &outVerts ); + + if ( vertCount ) + { + for ( int j = 0; j < vertCount; j += 3 ) + { + rtEnvRainBlocker->AddTriangle( nTriCount++, outVerts[j], outVerts[j + 1], outVerts[j + 2], Vector( 1, 1, 1 ) ); + } + } + physcollision->DestroyDebugMesh( vertCount, outVerts ); + } + + rtEnvRainBlocker->SetupAccelerationStructure(); + + m_bParticlePrecipInitialized = true; +} + +void CClient_Precipitation::DestroyInnerParticlePrecip( int nSlot ) +{ + if ( m_pParticlePrecipInnerFar[nSlot] != NULL ) + { + m_pParticlePrecipInnerFar[nSlot]->StopEmission(); + m_pParticlePrecipInnerFar[nSlot] = NULL; + } + if ( m_pParticlePrecipInnerNear[nSlot] != NULL ) + { + m_pParticlePrecipInnerNear[nSlot]->StopEmission(); + m_pParticlePrecipInnerNear[nSlot] = NULL; + } +} + +void CClient_Precipitation::DestroyOuterParticlePrecip( int nSlot ) +{ + if ( m_pParticlePrecipOuter[nSlot] != NULL ) + { + m_pParticlePrecipOuter[nSlot]->StopEmission(); + m_pParticlePrecipOuter[nSlot] = NULL; + } +} + +void CClient_Precipitation::DispatchOuterParticlePrecip( int nSlot, C_BasePlayer *pPlayer, Vector vForward ) +{ + DestroyOuterParticlePrecip( nSlot ); + +#ifdef INFESTED_DLL + Vector vDensity = Vector( r_RainParticleDensity.GetFloat(), (float)m_nSnowDustAmount/100.0f, 0 ) * m_flDensity; + Vector vPlayerPos = MainViewOrigin( nSlot ); +#else + Vector vDensity = Vector( r_RainParticleDensity.GetFloat(), 0, 0 ) * m_flDensity; + Vector vPlayerPos = pPlayer->EyePosition(); +#endif -void CClient_Precipitation::CreateRainOrSnowParticle( Vector vSpawnPosition, Vector vVelocity ) + m_pParticlePrecipOuter[nSlot] = ParticleProp()->Create( m_pParticleOuterDef, PATTACH_ABSORIGIN_FOLLOW ); + m_pParticlePrecipOuter[nSlot]->SetControlPointEntity( 2, pPlayer ); + m_pParticlePrecipOuter[nSlot]->SetControlPoint( 1, vPlayerPos + Vector (0, 0, 180 ) ); + m_pParticlePrecipOuter[nSlot]->SetControlPoint( 3, vDensity ); + m_pParticlePrecipOuter[nSlot]->SetDrawOnlyForSplitScreenUser( nSlot ); +} + +void CClient_Precipitation::DispatchInnerParticlePrecip( int nSlot, C_BasePlayer *pPlayer, Vector vForward ) +{ + DestroyInnerParticlePrecip( nSlot ); + DestroyOuterParticlePrecip( nSlot ); +#ifdef INFESTED_DLL + Vector vPlayerPos = MainViewOrigin( nSlot ); + Vector vOffsetPos = vPlayerPos + Vector ( 0, 0, 64 ); + Vector vOffsetPosNear = vPlayerPos + Vector ( 0, 0, 64 ) + ( vForward * 32 ); + Vector vOffsetPosFar = vPlayerPos + Vector ( 0, 0, 64 ) + ( vForward * m_flParticleInnerDist ); + Vector vDensity = Vector( r_RainParticleDensity.GetFloat(), (float)m_nSnowDustAmount/100.0f, 0 ) * m_flDensity; +#else + Vector vPlayerPos = pPlayer->EyePosition(); + Vector vOffsetPos = vPlayerPos + Vector ( 0, 0, 180 ); + Vector vOffsetPosNear = vPlayerPos + Vector ( 0, 0, 180 ) + ( vForward * 32 ); + Vector vOffsetPosFar = vPlayerPos + Vector ( 0, 0, 180 ) + ( vForward * m_flParticleInnerDist ); // 100.0 + Vector vDensity = Vector( r_RainParticleDensity.GetFloat(), 0, 0 ) * m_flDensity; +#endif + + m_pParticlePrecipOuter[nSlot] = ParticleProp()->Create( m_pParticleOuterDef, PATTACH_ABSORIGIN_FOLLOW ); + m_pParticlePrecipInnerNear[nSlot] = ParticleProp()->Create( m_pParticleInnerNearDef, PATTACH_ABSORIGIN_FOLLOW ); + m_pParticlePrecipInnerFar[nSlot] = ParticleProp()->Create( m_pParticleInnerFarDef, PATTACH_ABSORIGIN_FOLLOW ); + m_pParticlePrecipOuter[nSlot]->SetControlPointEntity( 2, pPlayer ); + m_pParticlePrecipInnerNear[nSlot]->SetControlPointEntity( 2, pPlayer ); + m_pParticlePrecipInnerFar[nSlot]->SetControlPointEntity( 2, pPlayer ); + m_pParticlePrecipOuter[nSlot]->SetControlPoint( 1, vOffsetPos ); + m_pParticlePrecipInnerNear[nSlot]->SetControlPoint( 1, vOffsetPosNear ); + m_pParticlePrecipInnerFar[nSlot]->SetControlPoint( 1, vOffsetPosFar ); + m_pParticlePrecipInnerNear[nSlot]->SetControlPoint( 3, vDensity ); + m_pParticlePrecipInnerFar[nSlot]->SetControlPoint( 3, vDensity ); + m_pParticlePrecipOuter[nSlot]->SetControlPoint( 3, vDensity ); + m_pParticlePrecipOuter[nSlot]->SetDrawOnlyForSplitScreenUser( nSlot ); + m_pParticlePrecipInnerNear[nSlot]->SetDrawOnlyForSplitScreenUser( nSlot ); + m_pParticlePrecipInnerFar[nSlot]->SetDrawOnlyForSplitScreenUser( nSlot ); +} + + +// TERROR: adding end pos for lifetime calcs +void CClient_Precipitation::CreateRainOrSnowParticle( const Vector &vSpawnPosition, const Vector &vEndPosition, const Vector &vVelocity ) { // Create the particle CPrecipitationParticle* p = CreateParticle(); @@ -1021,10 +1357,14 @@ void CClient_Precipitation::CreateRainOrSnowParticle( Vector vSpawnPosition, Vec VectorCopy( vVelocity, p->m_Velocity ); p->m_Pos = vSpawnPosition; + /* TERROR: moving random velocity out so it can be included in endpos calcs p->m_Velocity[ 0 ] += random->RandomFloat(-r_RainSideVel.GetInt(), r_RainSideVel.GetInt()); p->m_Velocity[ 1 ] += random->RandomFloat(-r_RainSideVel.GetInt(), r_RainSideVel.GetInt()); + */ p->m_Mass = random->RandomFloat( 0.5, 1.5 ); + + p->m_flMaxLifetime = fabs((vSpawnPosition.z - vEndPosition.z) / vVelocity.z); } //----------------------------------------------------------------------------- @@ -1036,21 +1376,25 @@ void CClient_Precipitation::EmitParticles( float fTimeDelta ) Vector2D size; Vector vel, org; + FOR_EACH_VALID_SPLITSCREEN_PLAYER( hh ) + { + ACTIVE_SPLITSCREEN_PLAYER_GUARD( hh ); + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); if ( !pPlayer ) - return; + continue; Vector vPlayerCenter = pPlayer->WorldSpaceCenter(); // Compute where to emit - if (!ComputeEmissionArea( org, size )) - return; + if (!ComputeEmissionArea( org, size, pPlayer )) + continue; // clamp this to prevent creating a bunch of rain or snow at one time. if( fTimeDelta > 0.075f ) fTimeDelta = 0.075f; // FIXME: Compute the precipitation density based on computational power - float density = m_flDensity; + float density = m_flDensity * 0.001; if (density > 0.01f) density = 0.01f; @@ -1068,6 +1412,11 @@ void CClient_Precipitation::EmitParticles( float fTimeDelta ) // Emit all the particles for ( int i = 0 ; i < cParticles ; i++ ) { + // TERROR: moving random velocity out so it can be included in endpos calcs + Vector vParticleVel = vel; + vParticleVel[ 0 ] += random->RandomFloat(-r_RainSideVel.GetInt(), r_RainSideVel.GetInt()); + vParticleVel[ 1 ] += random->RandomFloat(-r_RainSideVel.GetInt(), r_RainSideVel.GetInt()); + Vector vParticlePos = org; vParticlePos[ 0 ] += size[ 0 ] * random->RandomFloat(0, 1); vParticlePos[ 1 ] += size[ 1 ] * random->RandomFloat(0, 1); @@ -1077,6 +1426,21 @@ void CClient_Precipitation::EmitParticles( float fTimeDelta ) Vector vPlayerHeight = vParticlePos; vPlayerHeight.z = vPlayerCenter.z; + if ( ParticleIsBlocked( vPlayerHeight, vParticlePos ) ) + { + if ( r_RainDebugDuration.GetBool() ) + { + debugoverlay->AddLineOverlay( vPlayerHeight, vParticlePos, 255, 0, 0, false, r_RainDebugDuration.GetFloat() ); + } + continue; + } + + Vector vUnitParticleVel = vParticleVel; + float fallHeight = vParticlePos.z - vPlayerHeight.z; + vUnitParticleVel /= fallHeight; + vPlayerHeight.x += vUnitParticleVel.x * fallHeight; + vPlayerHeight.y += vUnitParticleVel.y * fallHeight; + trace_t trace; UTIL_TraceLine( vPlayerHeight, vParticlePos, MASK_SOLID_BRUSHONLY, NULL, COLLISION_GROUP_NONE, &trace ); if ( trace.fraction < 1 ) @@ -1085,14 +1449,34 @@ void CClient_Precipitation::EmitParticles( float fTimeDelta ) if ( trace.surface.flags & SURF_SKY ) { vParticlePos = trace.endpos; + if ( r_RainDebugDuration.GetBool() ) + { + debugoverlay->AddLineOverlay( vPlayerHeight, trace.endpos, 0, 0, 255, false, r_RainDebugDuration.GetFloat() ); + } } else { + if ( r_RainDebugDuration.GetBool() ) + { + debugoverlay->AddLineOverlay( vPlayerHeight, trace.endpos, 255, 0, 0, false, r_RainDebugDuration.GetFloat() ); + } continue; } } - CreateRainOrSnowParticle( vParticlePos, vel ); + // TERROR: Find an endpos + Vector vParticleEndPos( vPlayerHeight ); + //vParticleEndPos.z -= 256.0f; + //UTIL_TraceLine( vPlayerHeight, vParticleEndPos, MASK_SOLID_BRUSHONLY, NULL, COLLISION_GROUP_NONE, &trace ); + //vParticleEndPos = trace.endpos; + + if ( r_RainDebugDuration.GetBool() ) + { + debugoverlay->AddLineOverlay( vParticlePos, vParticleEndPos, 0, 255, 0, true, r_RainDebugDuration.GetFloat() ); + } + + CreateRainOrSnowParticle( vParticlePos, vParticleEndPos, vParticleVel ); + } } } @@ -1114,7 +1498,6 @@ void CClient_Precipitation::ComputeWindVector( ) VectorScale( s_WindVector, windspeed, s_WindVector ); } - CHandle g_pPrecipHackEnt; class CPrecipHack : public CAutoGameSystemPerFrame @@ -1130,7 +1513,7 @@ class CPrecipHack : public CAutoGameSystemPerFrame if ( r_RainHack.GetInt() ) { CClient_Precipitation *pPrecipHackEnt = new CClient_Precipitation; - pPrecipHackEnt->InitializeAsClientEntity( NULL, RENDER_GROUP_TRANSLUCENT_ENTITY ); + pPrecipHackEnt->InitializeAsClientEntity( NULL, false ); g_pPrecipHackEnt = pPrecipHackEnt; } m_bLevelInitted = true; @@ -1140,7 +1523,7 @@ class CPrecipHack : public CAutoGameSystemPerFrame { if ( r_RainHack.GetInt() && g_pPrecipHackEnt ) { - g_pPrecipHackEnt->Release(); + UTIL_Remove( g_pPrecipHackEnt ); } m_bLevelInitted = false; } @@ -1326,7 +1709,7 @@ class C_Embers : public C_BaseEntity virtual void OnDataChanged( DataUpdateType_t updateType ); virtual bool ShouldDraw( void ); - virtual void AddEntity( void ); + virtual bool Simulate( void ); //Server-side int m_nDensity; @@ -1359,6 +1742,7 @@ END_RECV_TABLE() C_Embers::C_Embers() { m_pEmitter = CEmberEmitter::Create( "C_Embers" ); + AddToEntityList(ENTITY_LIST_SIMULATE); } C_Embers::~C_Embers() @@ -1375,6 +1759,10 @@ void C_Embers::OnDataChanged( DataUpdateType_t updateType ) Start(); } + if ( m_bEmit ) + { + AddToEntityList(ENTITY_LIST_SIMULATE); + } } //----------------------------------------------------------------------------- @@ -1400,10 +1788,10 @@ void C_Embers::Start( void ) //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- -void C_Embers::AddEntity( void ) +bool C_Embers::Simulate( void ) { if ( m_bEmit == false ) - return; + return false; float tempDelta = gpGlobals->frametime; @@ -1411,6 +1799,7 @@ void C_Embers::AddEntity( void ) { SpawnEmber(); } + return true; } //----------------------------------------------------------------------------- @@ -1439,9 +1828,9 @@ void C_Embers::SpawnEmber( void ) sParticle->m_flLifetime = 0.0f; sParticle->m_flDieTime = m_nLifetime; - sParticle->m_uchColor[0] = m_clrRender->r * cScale; - sParticle->m_uchColor[1] = m_clrRender->g * cScale; - sParticle->m_uchColor[2] = m_clrRender->b * cScale; + sParticle->m_uchColor[0] = GetRenderColorR() * cScale; + sParticle->m_uchColor[1] = GetRenderColorG() * cScale; + sParticle->m_uchColor[2] = GetRenderColorB() * cScale; sParticle->m_uchStartAlpha = 255; sParticle->m_uchEndAlpha = 0; sParticle->m_uchStartSize = 1; @@ -1476,7 +1865,7 @@ class C_QuadraticBeam : public C_BaseEntity //virtual void OnDataChanged( DataUpdateType_t updateType ); virtual bool ShouldDraw( void ) { return true; } - virtual int DrawModel( int ); + virtual int DrawModel( int, const RenderableInstance_t &instance ); virtual void GetRenderBounds( Vector& mins, Vector& maxs ) { @@ -1504,15 +1893,15 @@ IMPLEMENT_CLIENTCLASS_DT( C_QuadraticBeam, DT_QuadraticBeam, CEnvQuadraticBeam ) RecvPropFloat( RECVINFO(m_flWidth) ), END_RECV_TABLE() -Vector Color32ToVector( const color32 &color ) +Vector Color24ToVector( const color24 &color ) { return Vector( color.r * (1.0/255.0f), color.g * (1.0/255.0f), color.b * (1.0/255.0f) ); } -int C_QuadraticBeam::DrawModel( int ) +int C_QuadraticBeam::DrawModel( int, const RenderableInstance_t &instance ) { Draw_SetSpriteTexture( GetModel(), 0, GetRenderMode() ); - Vector color = Color32ToVector( GetRenderColor() ); + Vector color = Color24ToVector( GetRenderColor() ); DrawBeamQuadratic( GetRenderOrigin(), m_controlPosition, m_targetPosition, m_flWidth, color, gpGlobals->curtime*m_scrollRate ); return 1; } @@ -1583,10 +1972,9 @@ class SnowFallEffect : public CSimpleEmitter GetBinding().SetBBox( vecMin, vecMax, true ); } - bool IsTransparent( void ) { return false; } + RenderableTranslucencyType_t ComputeTranslucencyType( void ) { return RENDERABLE_IS_OPAQUE; } private: - SnowFallEffect( const SnowFallEffect & ); }; @@ -1614,18 +2002,18 @@ class CSnowFallManager : public C_BaseEntity SNOWFALL_IN_ENTITY, }; - bool IsTransparent( void ) { return false; } + RenderableTranslucencyType_t ComputeTranslucencyType( void ) { return RENDERABLE_IS_OPAQUE; } + void SetSplitScreenPlayerSlot( int nSlot ); private: - bool CreateSnowFallEmitter( void ); void CreateSnowFall( void ); - void CreateSnowFallParticles( float flCurrentTime, float flRadius, const Vector &vecEyePos, const Vector &vecForward, float flZoomScale ); - void CreateOutsideVolumeSnowParticles( float flCurrentTime, float flRadius, float flZoomScale ); - void CreateInsideVolumeSnowParticles( float flCurrentTime, float flRadius, const Vector &vecEyePos, const Vector &vecForward, float flZoomScale ); - void CreateSnowParticlesSphere( float flRadius ); - void CreateSnowParticlesRay( float flRadius, const Vector &vecEyePos, const Vector &vecForward ); - void CreateSnowFallParticle( const Vector &vecParticleSpawn, int iBBox ); + void CreateSnowFallParticles( float flCurrentTime, float flRadius, const Vector &vecEyePos, const Vector &vecForward, float flZoomScale, C_BasePlayer *pLocalPlayer ); + void CreateOutsideVolumeSnowParticles( float flCurrentTime, float flRadius, float flZoomScale, C_BasePlayer *pLocalPlayer ); + void CreateInsideVolumeSnowParticles( float flCurrentTime, float flRadius, const Vector &vecEyePos, const Vector &vecForward, float flZoomScale, C_BasePlayer *pLocalPlayer ); + void CreateSnowParticlesSphere( float flRadius, C_BasePlayer *pLocalPlayer ); + void CreateSnowParticlesRay( float flRadius, const Vector &vecEyePos, const Vector &vecForward, C_BasePlayer *pLocalPlayer ); + void CreateSnowFallParticle( const Vector &vecParticleSpawn, int iBBox, C_BasePlayer *pLocalPlayer ); int StandingInSnowVolume( Vector &vecPoint ); void FindSnowVolumes( Vector &vecCenter, float flRadius, Vector &vecEyePos, Vector &vecForward ); @@ -1653,7 +2041,7 @@ class CSnowFallManager : public C_BaseEntity bool m_bRayParticles; - struct SnowFall_t + typedef struct SnowFall_t { PMaterialHandle m_hMaterial; CClient_Precipitation *m_pEntity; @@ -1663,6 +2051,7 @@ class CSnowFallManager : public C_BaseEntity }; CUtlVector m_aSnow; + int m_nSplitScreenPlayerSlot; }; //----------------------------------------------------------------------------- @@ -1678,6 +2067,7 @@ CSnowFallManager::CSnowFallManager( void ) m_vecMax.Init( FLT_MIN, FLT_MIN, FLT_MIN ); m_nActiveSnowCount = 0; m_aSnow.Purge(); + m_nSplitScreenPlayerSlot = -1; } //----------------------------------------------------------------------------- @@ -1719,14 +2109,25 @@ bool CSnowFallManager::CreateSnowFallEmitter( void ) if ( ( m_pSnowFallEmitter = SnowFallEffect::Create( "snowfall" ) ) == NULL ) return false; + m_pSnowFallEmitter->SetShouldDrawForSplitScreenUser( m_nSplitScreenPlayerSlot ); return true; } +void CSnowFallManager::SetSplitScreenPlayerSlot( int nSlot ) +{ + m_nSplitScreenPlayerSlot = nSlot; +} + //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CSnowFallManager::ClientThink( void ) { + if ( !IsValidSplitScreenSlot( m_nSplitScreenPlayerSlot ) ) + return; + + ACTIVE_SPLITSCREEN_PLAYER_GUARD( m_nSplitScreenPlayerSlot ); + if ( !r_SnowEnable.GetBool() ) return; @@ -1894,6 +2295,7 @@ void CSnowFallManager::CreateSnowFall( void ) VPROF_BUDGET( "SnowFall", VPROF_BUDGETGROUP_PARTICLE_RENDERING ); #endif + ASSERT_LOCAL_PLAYER_RESOLVABLE(); // Check to see if we have a local player before starting the snow around a local player. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); if ( pPlayer == NULL ) @@ -1955,8 +2357,7 @@ void CSnowFallManager::CreateSnowFall( void ) } } - Vector vecEyePos = pPlayer->EyePosition(); - FindSnowVolumes( m_vecSnowFallEmitOrigin, flRadius, vecEyePos, vecForward ); + FindSnowVolumes( m_vecSnowFallEmitOrigin, flRadius, pPlayer->EyePosition(), vecForward ); if ( m_nActiveSnowCount != 0 && m_iSnowFallArea != SNOWFALL_AROUND_PLAYER ) { // We found an active snow emitter. @@ -1972,7 +2373,7 @@ void CSnowFallManager::CreateSnowFall( void ) m_pSnowFallEmitter->SetSortOrigin( m_vecSnowFallEmitOrigin ); // Create snow fall particles. - CreateSnowFallParticles( flCurrentTime, m_flSnowRadius, pPlayer->EyePosition(), vecForward, flZoomScale ); + CreateSnowFallParticles( flCurrentTime, m_flSnowRadius, pPlayer->EyePosition(), vecForward, flZoomScale, pPlayer ); } //----------------------------------------------------------------------------- @@ -1983,17 +2384,37 @@ void CSnowFallManager::CreateSnowFall( void ) // &vecForward - // flZoomScale - //----------------------------------------------------------------------------- -void CSnowFallManager::CreateSnowFallParticles( float flCurrentTime, float flRadius, const Vector &vecEyePos, const Vector &vecForward, float flZoomScale ) +void CSnowFallManager::CreateSnowFallParticles( float flCurrentTime, float flRadius, const Vector &vecEyePos, const Vector &vecForward, float flZoomScale, C_BasePlayer *pLocalPlayer ) +{ + const float SnowfallRate = 500.0f; + if ( m_nActiveSnowCount > 0 ) + { + C_BaseEntity *pEntity = m_aSnow[ m_aActiveSnow[0] ].m_pEntity; + int density = pEntity->GetRenderAlpha(); + density = clamp( density, 0, 100 ); + if ( pEntity && density > 0 ) + { + m_tSnowFallParticleTimer.ResetRate( SnowfallRate * density * 0.01f ); + } + else { + m_tSnowFallParticleTimer.ResetRate( SnowfallRate ); + } + } + else + { + m_tSnowFallParticleTimer.ResetRate( SnowfallRate ); + } + // Outside of a snow volume. if ( m_iSnowFallArea == SNOWFALL_IN_ENTITY ) { - CreateOutsideVolumeSnowParticles( flCurrentTime, flRadius, flZoomScale ); + CreateOutsideVolumeSnowParticles( flCurrentTime, flRadius, flZoomScale, pLocalPlayer ); } // Inside of a snow volume. else { - CreateInsideVolumeSnowParticles( flCurrentTime, flRadius, vecEyePos, vecForward, flZoomScale ); + CreateInsideVolumeSnowParticles( flCurrentTime, flRadius, vecEyePos, vecForward, flZoomScale, pLocalPlayer ); } } @@ -2003,7 +2424,7 @@ void CSnowFallManager::CreateSnowFallParticles( float flCurrentTime, float flRad // flRadius - // flZoomScale - //----------------------------------------------------------------------------- -void CSnowFallManager::CreateOutsideVolumeSnowParticles( float flCurrentTime, float flRadius, float flZoomScale ) +void CSnowFallManager::CreateOutsideVolumeSnowParticles( float flCurrentTime, float flRadius, float flZoomScale, C_BasePlayer *pLocalPlayer ) { Vector vecParticleSpawn; @@ -2026,7 +2447,7 @@ void CSnowFallManager::CreateOutsideVolumeSnowParticles( float flCurrentTime, fl float flDistance2 = ( m_vecSnowFallEmitOrigin - vecParticleSpawn ).LengthSqr(); if ( flDistance2 < flRadius2 ) { - CreateSnowFallParticle( vecParticleSpawn, m_aActiveSnow[iSnow] ); + CreateSnowFallParticle( vecParticleSpawn, m_aActiveSnow[iSnow], pLocalPlayer ); } iSnow = ( iSnow + 1 ) % m_nActiveSnowCount; @@ -2041,7 +2462,7 @@ void CSnowFallManager::CreateOutsideVolumeSnowParticles( float flCurrentTime, fl // &vecForward - // flZoomScale - //----------------------------------------------------------------------------- -void CSnowFallManager::CreateInsideVolumeSnowParticles( float flCurrentTime, float flRadius, const Vector &vecEyePos, const Vector &vecForward, float flZoomScale ) +void CSnowFallManager::CreateInsideVolumeSnowParticles( float flCurrentTime, float flRadius, const Vector &vecEyePos, const Vector &vecForward, float flZoomScale, C_BasePlayer *pLocalPlayer ) { Vector vecParticleSpawn; @@ -2067,13 +2488,13 @@ void CSnowFallManager::CreateInsideVolumeSnowParticles( float flCurrentTime, flo // Create particle inside of sphere. if ( iIndex > 0 ) { - CreateSnowParticlesSphere( flZoomRadius ); - CreateSnowParticlesRay( flZoomRadius, vecEyePos, vecForward ); + CreateSnowParticlesSphere( flZoomRadius, pLocalPlayer ); + CreateSnowParticlesRay( flZoomRadius, vecEyePos, vecForward, pLocalPlayer ); } else { - CreateSnowParticlesSphere( flRadius ); - CreateSnowParticlesRay( flRadius, vecEyePos, vecForward ); + CreateSnowParticlesSphere( flRadius, pLocalPlayer ); + CreateSnowParticlesRay( flRadius, vecEyePos, vecForward, pLocalPlayer ); } // Increment if zoomed. @@ -2088,7 +2509,7 @@ void CSnowFallManager::CreateInsideVolumeSnowParticles( float flCurrentTime, flo // Purpose: // Input : flRadius - //----------------------------------------------------------------------------- -void CSnowFallManager::CreateSnowParticlesSphere( float flRadius ) +void CSnowFallManager::CreateSnowParticlesSphere( float flRadius, C_BasePlayer *pLocalPlayer ) { Vector vecParticleSpawn; @@ -2112,7 +2533,7 @@ void CSnowFallManager::CreateSnowParticlesSphere( float flRadius ) if ( iSnow == m_nActiveSnowCount ) return; - CreateSnowFallParticle( vecParticleSpawn, m_aActiveSnow[iSnow] ); + CreateSnowFallParticle( vecParticleSpawn, m_aActiveSnow[iSnow], pLocalPlayer ); } //----------------------------------------------------------------------------- @@ -2120,7 +2541,7 @@ void CSnowFallManager::CreateSnowParticlesSphere( float flRadius ) // Input : &vecEyePos - // &vecForward - //----------------------------------------------------------------------------- -void CSnowFallManager::CreateSnowParticlesRay( float flRadius, const Vector &vecEyePos, const Vector &vecForward ) +void CSnowFallManager::CreateSnowParticlesRay( float flRadius, const Vector &vecEyePos, const Vector &vecForward, C_BasePlayer *pLocalPlayer ) { // Check to see if we should create particles along line-of-sight. if ( !m_bRayParticles && r_SnowRayEnable.GetBool() ) @@ -2156,10 +2577,10 @@ void CSnowFallManager::CreateSnowParticlesRay( float flRadius, const Vector &vec if ( iSnow == m_nActiveSnowCount ) return; - CreateSnowFallParticle( vecParticleSpawn, m_aActiveSnow[iSnow] ); + CreateSnowFallParticle( vecParticleSpawn, m_aActiveSnow[iSnow], pLocalPlayer ); } -void CSnowFallManager::CreateSnowFallParticle( const Vector &vecParticleSpawn, int iSnow ) +void CSnowFallManager::CreateSnowFallParticle( const Vector &vecParticleSpawn, int iSnow, C_BasePlayer *pLocalPlayer ) { SimpleParticle *pParticle = ( SimpleParticle* )m_pSnowFallEmitter->AddParticle( sizeof( SimpleParticle ), m_aSnow[iSnow].m_hMaterial, vecParticleSpawn ); if ( pParticle == NULL ) @@ -2195,17 +2616,29 @@ void CSnowFallManager::CreateSnowFallParticle( const Vector &vecParticleSpawn, i //----------------------------------------------------------------------------- bool SnowFallManagerCreate( CClient_Precipitation *pSnowEntity ) { - if ( !s_pSnowFallMgr ) + bool bret = true; + + for ( int i = 0; i < MAX_SPLITSCREEN_PLAYERS; ++i ) + { + if ( !s_pSnowFallMgr[ i ] ) { - s_pSnowFallMgr = new CSnowFallManager(); - s_pSnowFallMgr->CreateEmitter(); - s_pSnowFallMgr->InitializeAsClientEntity( NULL, RENDER_GROUP_OTHER ); - if ( !s_pSnowFallMgr ) - return false; + ACTIVE_SPLITSCREEN_PLAYER_GUARD( i ); + + s_pSnowFallMgr[ i ] = new CSnowFallManager(); + if ( !s_pSnowFallMgr[ i ] ) + { + bret = false; + break; + } + s_pSnowFallMgr[ i ]->SetSplitScreenPlayerSlot( i ); + s_pSnowFallMgr[ i ]->CreateEmitter(); + s_pSnowFallMgr[ i ]->InitializeAsClientEntity( NULL, false ); + g_pClientLeafSystem->EnableRendering( s_pSnowFallMgr[ i ]->RenderHandle(), false ); } - s_pSnowFallMgr->AddSnowFallEntity( pSnowEntity ); - return true; + s_pSnowFallMgr[ i ]->AddSnowFallEntity( pSnowEntity ); + } + return bret; } //----------------------------------------------------------------------------- @@ -2213,9 +2646,12 @@ bool SnowFallManagerCreate( CClient_Precipitation *pSnowEntity ) //----------------------------------------------------------------------------- void SnowFallManagerDestroy( void ) { - if ( s_pSnowFallMgr ) + for ( int i = 0; i < MAX_SPLITSCREEN_PLAYERS; ++i ) { - delete s_pSnowFallMgr; - s_pSnowFallMgr = NULL; + if ( s_pSnowFallMgr[ i ] ) + { + delete s_pSnowFallMgr[ i ]; + s_pSnowFallMgr[ i ] = NULL; + } } } diff --git a/game/client/c_effects.h b/game/client/c_effects.h index 27bb501e9..9c42d7023 100644 --- a/game/client/c_effects.h +++ b/game/client/c_effects.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // @@ -10,9 +10,201 @@ #pragma once #endif +#include "cbase.h" +#include "precipitation_shared.h" // Draw rain effects. void DrawPrecipitation(); +//----------------------------------------------------------------------------- +// Precipitation particle type +//----------------------------------------------------------------------------- + +class CPrecipitationParticle +{ +public: + Vector m_Pos; + Vector m_Velocity; + float m_SpawnTime; // Note: Tweak with this to change lifetime + float m_Mass; + float m_Ramp; + + float m_flMaxLifetime; + int m_nSplitScreenPlayerSlot; +}; + +class CClient_Precipitation; +static CUtlVector g_Precipitations; + +//=========== +// Snow fall +//=========== +class CSnowFallManager; +static CSnowFallManager *s_pSnowFallMgr[ MAX_SPLITSCREEN_PLAYERS ]; +bool SnowFallManagerCreate( CClient_Precipitation *pSnowEntity ); +void SnowFallManagerDestroy( void ); + +class AshDebrisEffect : public CSimpleEmitter +{ +public: + AshDebrisEffect( const char *pDebugName ) : CSimpleEmitter( pDebugName ) {} + + static AshDebrisEffect* Create( const char *pDebugName ); + + virtual float UpdateAlpha( const SimpleParticle *pParticle ); + virtual float UpdateRoll( SimpleParticle *pParticle, float timeDelta ); + +private: + AshDebrisEffect( const AshDebrisEffect & ); +}; + +//----------------------------------------------------------------------------- +// Precipitation blocker entity +//----------------------------------------------------------------------------- +class C_PrecipitationBlocker : public C_BaseEntity +{ +public: + DECLARE_CLASS( C_PrecipitationBlocker, C_BaseEntity ); + DECLARE_CLIENTCLASS(); + + C_PrecipitationBlocker(); + virtual ~C_PrecipitationBlocker(); +}; + +//----------------------------------------------------------------------------- +// Precipitation base entity +//----------------------------------------------------------------------------- +class CClient_Precipitation : public C_BaseEntity +{ + class CPrecipitationEffect; + friend class CClient_Precipitation::CPrecipitationEffect; + +public: + DECLARE_CLASS( CClient_Precipitation, C_BaseEntity ); + DECLARE_CLIENTCLASS(); + + CClient_Precipitation(); + virtual ~CClient_Precipitation(); + + // Inherited from C_BaseEntity + virtual void Precache( ); + virtual RenderableTranslucencyType_t ComputeTranslucencyType() { return RENDERABLE_IS_TRANSLUCENT; } + + void Render(); + + // Computes where we're gonna emit + bool ComputeEmissionArea( Vector& origin, Vector2D& size, C_BaseCombatCharacter *pCharacter ); + + +private: + + // Creates a single particle + CPrecipitationParticle* CreateParticle(); + + virtual void OnDataChanged( DataUpdateType_t updateType ); + virtual void ClientThink(); + + void Simulate( float dt ); + + // Renders the particle + void RenderParticle( CPrecipitationParticle* pParticle, CMeshBuilder &mb ); + + void CreateWaterSplashes(); + + // Emits the actual particles + void EmitParticles( float fTimeDelta ); + + // Gets the tracer width and speed + float GetWidth() const; + float GetLength() const; + float GetSpeed() const; + + // Gets the remaining lifetime of the particle + float GetRemainingLifetime( CPrecipitationParticle* pParticle ) const; + + // Computes the wind vector + static void ComputeWindVector( ); + + // simulation methods + bool SimulateRain( CPrecipitationParticle* pParticle, float dt ); + bool SimulateSnow( CPrecipitationParticle* pParticle, float dt ); + + void CreateParticlePrecip( void ); + void InitializeParticlePrecip( void ); + void DispatchOuterParticlePrecip( int nSlot, C_BasePlayer *pPlayer, Vector vForward ); + void DispatchInnerParticlePrecip( int nSlot, C_BasePlayer *pPlayer, Vector vForward ); + void DestroyOuterParticlePrecip( int nSlot ); + void DestroyInnerParticlePrecip( int nSlot ); + + void UpdateParticlePrecip( C_BasePlayer *pPlayer, int nSlot ); + float GetDensity() { return m_flDensity; } + +private: + void CreateAshParticle( void ); + void CreateRainOrSnowParticle( const Vector &vSpawnPosition, const Vector &vEndPosition, const Vector &vVelocity ); // TERROR: adding end pos for lifetime calcs + + // Information helpful in creating and rendering particles + IMaterial *m_MatHandle; // material used + + float m_Color[4]; // precip color + float m_Lifetime; // Precip lifetime + float m_InitialRamp; // Initial ramp value + float m_Speed; // Precip speed + float m_Width; // Tracer width + float m_Remainder; // particles we should render next time + PrecipitationType_t m_nPrecipType; // Precip type + float m_flHalfScreenWidth; // Precalculated each frame. + + float m_flDensity; + +#ifdef INFESTED_DLL + int m_nSnowDustAmount; +#endif + + // Some state used in rendering and simulation + // Used to modify the rain density and wind from the console + static ConVar s_raindensity; + static ConVar s_rainwidth; + static ConVar s_rainlength; + static ConVar s_rainspeed; + + static Vector s_WindVector; // Stores the wind speed vector + + CUtlLinkedList m_Particles; + CUtlVector m_Splashes; + + struct AshSplit_t + { + AshSplit_t() : m_bActiveAshEmitter( false ), m_vAshSpawnOrigin( 0, 0, 0 ), m_iAshCount( 0 ) + { + } + + CSmartPtr m_pAshEmitter; + TimedEvent m_tAshParticleTimer; + TimedEvent m_tAshParticleTraceTimer; + bool m_bActiveAshEmitter; + Vector m_vAshSpawnOrigin; + + int m_iAshCount; + }; + +protected: + AshSplit_t m_Ash[ MAX_SPLITSCREEN_PLAYERS ]; + + float m_flParticleInnerDist; //The distance at which to start drawing the inner system + char *m_pParticleInnerNearDef; //Name of the first inner system + char *m_pParticleInnerFarDef; //Name of the second inner system + char *m_pParticleOuterDef; //Name of the outer system + HPARTICLEFFECT m_pParticlePrecipInnerNear[ MAX_SPLITSCREEN_PLAYERS ]; + HPARTICLEFFECT m_pParticlePrecipInnerFar[ MAX_SPLITSCREEN_PLAYERS ]; + HPARTICLEFFECT m_pParticlePrecipOuter[ MAX_SPLITSCREEN_PLAYERS ]; + TimedEvent m_tParticlePrecipTraceTimer[ MAX_SPLITSCREEN_PLAYERS ]; + bool m_bActiveParticlePrecipEmitter[ MAX_SPLITSCREEN_PLAYERS ]; + bool m_bParticlePrecipInitialized; + +private: + CClient_Precipitation( const CClient_Precipitation & ); // not defined, not accessible +}; + #endif // C_EFFECTS_H diff --git a/game/client/c_entitydissolve.cpp b/game/client/c_entitydissolve.cpp index 0c8dadc21..bdbce0f36 100644 --- a/game/client/c_entitydissolve.cpp +++ b/game/client/c_entitydissolve.cpp @@ -1,13 +1,13 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // // $NoKeywords: $ -//=============================================================================// +//===========================================================================// #include "cbase.h" -#include "iviewrender.h" +#include "IViewRender.h" #include "view.h" #include "studio.h" #include "bone_setup.h" @@ -19,16 +19,16 @@ #include "IEffects.h" #include "c_entitydissolve.h" #include "movevars_shared.h" -#include "clienteffectprecachesystem.h" +#include "precache_register.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" -CLIENTEFFECT_REGISTER_BEGIN( PrecacheEffectBuild ) -CLIENTEFFECT_MATERIAL( "effects/tesla_glow_noz" ) -CLIENTEFFECT_MATERIAL( "effects/spark" ) -CLIENTEFFECT_MATERIAL( "effects/combinemuzzle2" ) -CLIENTEFFECT_REGISTER_END() +PRECACHE_REGISTER_BEGIN( GLOBAL, PrecacheEffectBuild ) +PRECACHE( MATERIAL,"effects/tesla_glow_noz" ) +PRECACHE( MATERIAL,"effects/spark" ) +PRECACHE( MATERIAL,"effects/combinemuzzle2" ) +PRECACHE_REGISTER_END() //----------------------------------------------------------------------------- // Networking @@ -55,9 +55,8 @@ PMaterialHandle g_Material_AR2Glow = NULL; C_EntityDissolve::C_EntityDissolve( void ) { m_bLinkedToServerEnt = true; - m_pController = NULL; + m_pController = false; m_bCoreExplode = false; - m_vEffectColor = Vector( 255, 255, 255 ); } //----------------------------------------------------------------------------- @@ -112,7 +111,7 @@ IMotionEvent::simresult_e C_EntityDissolve::Simulate( IPhysicsMotionController * angular.Init(); // Make it zero g - linear.z -= -1.02 * GetCurrentGravity(); + linear.z -= -1.02 * sv_gravity.GetFloat(); Vector vel; AngularImpulse angVel; @@ -226,10 +225,12 @@ void C_EntityDissolve::BuildTeslaEffect( mstudiobbox_t *pHitBox, const matrix3x4 { if ( !EffectOccluded( tr.endpos ) ) { + int nSlot = GET_ACTIVE_SPLITSCREEN_SLOT(); + // Move it towards the camera Vector vecFlash = tr.endpos; Vector vecForward; - AngleVectors( MainViewAngles(), &vecForward ); + AngleVectors( MainViewAngles(nSlot), &vecForward ); vecFlash -= (vecForward * 8); g_pEffects->EnergySplash( vecFlash, -vecForward, false ); @@ -503,26 +504,16 @@ float C_EntityDissolve::GetModelFadeOutPercentage( void ) //----------------------------------------------------------------------------- void C_EntityDissolve::ClientThink( void ) { - C_BaseEntity *pEnt = GetMoveParent(); - if ( !pEnt ) - return; - - bool bIsRagdoll; -#ifdef TF_CLIENT_DLL - bIsRagdoll = true; -#else C_BaseAnimating *pAnimating = GetMoveParent() ? GetMoveParent()->GetBaseAnimating() : NULL; if (!pAnimating) return; - bIsRagdoll = pAnimating->IsRagdoll(); -#endif // NOTE: IsRagdoll means *client-side* ragdoll. We shouldn't be trying to fight // the server ragdoll (or any server physics) on the client - if (( !m_pController ) && ( m_nDissolveType == ENTITY_DISSOLVE_NORMAL ) && bIsRagdoll ) + if (( !m_pController ) && ( m_nDissolveType == ENTITY_DISSOLVE_NORMAL ) && pAnimating->IsRagdoll()) { IPhysicsObject *ppList[VPHYSICS_MAX_OBJECT_LIST_COUNT]; - int nCount = pEnt->VPhysicsGetObjectList( ppList, ARRAYSIZE(ppList) ); + int nCount = pAnimating->VPhysicsGetObjectList( ppList, ARRAYSIZE(ppList) ); if ( nCount > 0 ) { m_pController = physenv->CreateMotionController( this ); @@ -535,14 +526,13 @@ void C_EntityDissolve::ClientThink( void ) color32 color; - color.r = ( 1.0f - GetFadeInPercentage() ) * m_vEffectColor.x; - color.g = ( 1.0f - GetFadeInPercentage() ) * m_vEffectColor.y; - color.b = ( 1.0f - GetFadeInPercentage() ) * m_vEffectColor.z; + color.r = color.g = color.b = ( 1.0f - GetFadeInPercentage() ) * 255.0f; color.a = GetModelFadeOutPercentage() * 255.0f; // Setup the entity fade - pEnt->SetRenderMode( kRenderTransColor ); - pEnt->SetRenderColor( color.r, color.g, color.b, color.a ); + pAnimating->SetRenderMode( kRenderTransColor ); + pAnimating->SetRenderColor( color.r, color.g, color.b ); + pAnimating->SetRenderAlpha( color.a ); if ( GetModelFadeOutPercentage() <= 0.2f ) { @@ -566,18 +556,12 @@ void C_EntityDissolve::ClientThink( void ) { Release(); - C_ClientRagdoll *pRagdoll = dynamic_cast ( pEnt ); + C_ClientRagdoll *pRagdoll = dynamic_cast ( pAnimating ); if ( pRagdoll ) { pRagdoll->ReleaseRagdoll(); } -#ifdef TF_CLIENT_DLL - else - { - pEnt->Release(); - } -#endif } } } @@ -587,7 +571,7 @@ void C_EntityDissolve::ClientThink( void ) // Input : flags - // Output : int //----------------------------------------------------------------------------- -int C_EntityDissolve::DrawModel( int flags ) +int C_EntityDissolve::DrawModel( int flags, const RenderableInstance_t &instance ) { // See if we should draw if ( gpGlobals->frametime == 0 || m_bReadyToDraw == false ) @@ -660,7 +644,7 @@ int C_EntityDissolve::DrawModel( int flags ) yDir = yvec; float yScale = VectorNormalize( yDir ) * 0.75f; - int numParticles = clamp( 3.0f * fadePerc, 0.f, 3.f ); + int numParticles = clamp( 3.0f * fadePerc, 0, 3 ); int iTempParts = 2; @@ -737,9 +721,9 @@ int C_EntityDissolve::DrawModel( int flags ) float alpha = 255; - sParticle->m_uchColor[0] = m_vEffectColor.x; - sParticle->m_uchColor[1] = m_vEffectColor.y; - sParticle->m_uchColor[2] = m_vEffectColor.z; + sParticle->m_uchColor[0] = alpha; + sParticle->m_uchColor[1] = alpha; + sParticle->m_uchColor[2] = alpha; sParticle->m_uchStartAlpha = alpha; sParticle->m_uchEndAlpha = 0; sParticle->m_uchEndSize = 0; @@ -765,9 +749,9 @@ int C_EntityDissolve::DrawModel( int flags ) float alpha = 255; - sParticle->m_uchColor[0] = m_vEffectColor.x; - sParticle->m_uchColor[1] = m_vEffectColor.y; - sParticle->m_uchColor[2] = m_vEffectColor.z; + sParticle->m_uchColor[0] = alpha; + sParticle->m_uchColor[1] = alpha; + sParticle->m_uchColor[2] = alpha; sParticle->m_uchStartAlpha = alpha; sParticle->m_uchEndAlpha = 0; sParticle->m_uchEndSize = 0; diff --git a/game/client/c_entitydissolve.h b/game/client/c_entitydissolve.h index d440e0b62..d4733c4cd 100644 --- a/game/client/c_entitydissolve.h +++ b/game/client/c_entitydissolve.h @@ -1,9 +1,9 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // // $NoKeywords: $ -//=============================================================================// +//===========================================================================// #ifndef C_ENTITY_DISSOLVE_H #define C_ENTITY_DISSOLVE_H @@ -23,14 +23,11 @@ class C_EntityDissolve : public C_BaseEntity, public IMotionEvent // Inherited from C_BaseEntity virtual void GetRenderBounds( Vector& theMins, Vector& theMaxs ); - virtual int DrawModel( int flags ); + virtual int DrawModel( int flags, const RenderableInstance_t &instance ); virtual bool ShouldDraw() { return true; } virtual void OnDataChanged( DataUpdateType_t updateType ); virtual void UpdateOnRemove( void ); - virtual Vector GetEffectColor( void ) { return m_vEffectColor; } - virtual void SetEffectColor( Vector v ) { m_vEffectColor = v; } - // Inherited from IMotionEvent virtual simresult_e Simulate( IPhysicsMotionController *pController, IPhysicsObject *pObject, float deltaTime, Vector &linear, AngularImpulse &angular ); @@ -50,8 +47,6 @@ class C_EntityDissolve : public C_BaseEntity, public IMotionEvent int m_nDissolveType; float m_flNextSparkTime; - Vector m_vEffectColor; - Vector m_vDissolverOrigin; int m_nMagnitude; diff --git a/game/client/c_entityflame.cpp b/game/client/c_entityflame.cpp new file mode 100644 index 000000000..19f389649 --- /dev/null +++ b/game/client/c_entityflame.cpp @@ -0,0 +1,156 @@ +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// + +#include "cbase.h" +#include "c_entityflame.h" +#include "particle_property.h" +#include "iefx.h" +#include "dlight.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + +//----------------------------------------------------------------------------- +// Datadesc +//----------------------------------------------------------------------------- +IMPLEMENT_CLIENTCLASS_DT( C_EntityFlame, DT_EntityFlame, CEntityFlame ) + RecvPropEHandle(RECVINFO(m_hEntAttached)), + RecvPropBool(RECVINFO(m_bCheapEffect)), +END_RECV_TABLE() + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_EntityFlame::C_EntityFlame( void ) : m_hEffect( NULL ) +{ + m_hOldAttached = NULL; + AddToEntityList( ENTITY_LIST_SIMULATE ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_EntityFlame::~C_EntityFlame( void ) +{ + StopEffect(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_EntityFlame::StopEffect( void ) +{ + if ( m_hEffect ) + { + ParticleProp()->StopEmission( m_hEffect, true ); + m_hEffect = NULL; + } + + if ( m_hEntAttached ) + { + m_hEntAttached->RemoveFlag( FL_ONFIRE ); + m_hEntAttached->SetEffectEntity( NULL ); + m_hEntAttached->StopSound( "General.BurningFlesh" ); + m_hEntAttached->StopSound( "General.BurningObject" ); + m_hEntAttached = NULL; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_EntityFlame::UpdateOnRemove( void ) +{ + StopEffect(); + BaseClass::UpdateOnRemove(); +} + +void C_EntityFlame::CreateEffect( void ) +{ + if ( m_hEffect ) + { + m_hOldAttached = m_hEntAttached; + ParticleProp()->StopEmission( m_hEffect, true ); + m_hEffect = NULL; + } + + C_BaseEntity *pEntity = m_hEntAttached; + if ( pEntity && !pEntity->IsAbleToHaveFireEffect() ) + return; + + m_hEffect = ParticleProp()->Create( m_bCheapEffect ? "burning_gib_01" : "burning_character", PATTACH_ABSORIGIN_FOLLOW ); + if ( m_hEffect ) + { + m_hOldAttached = m_hEntAttached; + + ParticleProp()->AddControlPoint( m_hEffect, 1, pEntity, PATTACH_ABSORIGIN_FOLLOW ); + m_hEffect->SetControlPoint( 0, GetAbsOrigin() ); + m_hEffect->SetControlPoint( 1, GetAbsOrigin() ); + m_hEffect->SetControlPointEntity( 0, pEntity ); + m_hEffect->SetControlPointEntity( 1, pEntity ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_EntityFlame::OnDataChanged( DataUpdateType_t updateType ) +{ + if ( updateType == DATA_UPDATE_CREATED ) + { + CreateEffect(); + } + + // FIXME: This is a bit of a shady path + if ( updateType == DATA_UPDATE_DATATABLE_CHANGED ) + { + // If our owner changed, then recreate the effect + if ( m_hEntAttached != m_hOldAttached ) + { + CreateEffect(); + } + } + + BaseClass::OnDataChanged( updateType ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool C_EntityFlame::Simulate( void ) +{ + if ( gpGlobals->frametime <= 0.0f ) + return true; + +#ifdef HL2_EPISODIC + if ( IsEffectActive(EF_BRIGHTLIGHT) || IsEffectActive(EF_DIMLIGHT) ) + { + dlight_t *dl = effects->CL_AllocDlight( index ); + dl->origin = GetAbsOrigin(); + dl->origin[2] += 16; + dl->color.r = 254; + dl->color.g = 174; + dl->color.b = 10; + dl->radius = random->RandomFloat(400,431); + dl->die = gpGlobals->curtime + 0.001; + } + +#endif // HL2_EPISODIC + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_EntityFlame::ClientThink( void ) +{ + StopEffect(); + Release(); +} diff --git a/game/client/c_entityflame.h b/game/client/c_entityflame.h new file mode 100644 index 000000000..820e177d6 --- /dev/null +++ b/game/client/c_entityflame.h @@ -0,0 +1,43 @@ +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// +// +// Purpose: +// +// $NoKeywords: $ +// +//===========================================================================// +#ifndef C_ENTITY_FLAME_H +#define C_ENTITY_FLAME_H + +#include "c_baseentity.h" + +// +// Entity flame, client-side implementation +// + +class C_EntityFlame : public C_BaseEntity +{ +public: + DECLARE_CLIENTCLASS(); + DECLARE_CLASS( C_EntityFlame, C_BaseEntity ); + + C_EntityFlame( void ); + virtual ~C_EntityFlame( void ); + + virtual bool Simulate( void ); + virtual void UpdateOnRemove( void ); + virtual void OnDataChanged( DataUpdateType_t updateType ); + virtual void ClientThink( void ); + + EHANDLE m_hEntAttached; // The entity that we are burning (attached to). + +private: + void CreateEffect( void ); + void StopEffect( void ); + + CUtlReference m_hEffect; + EHANDLE m_hOldAttached; + bool m_bCheapEffect; +}; + + +#endif // C_ENTITY_FLAME_H \ No newline at end of file diff --git a/game/client/c_entityfreezing.cpp b/game/client/c_entityfreezing.cpp new file mode 100644 index 000000000..23e213239 --- /dev/null +++ b/game/client/c_entityfreezing.cpp @@ -0,0 +1,116 @@ +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// + +#include "cbase.h" + +#include "c_entityfreezing.h" +#include "studio.h" +#include "bone_setup.h" +#include "c_surfacerender.h" +#include "engine/ivdebugoverlay.h" +#include "dt_utlvector_recv.h" +#include "debugoverlay_shared.h" +#include "animation.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + +ConVar cl_blobulator_freezing_max_metaball_radius( "cl_blobulator_freezing_max_metaball_radius", + #ifdef INFESTED_DLL + "25.0", // Don't need as much precision in Alien swarm because everything is zoomed out + #else + "12.0", + #endif + FCVAR_NONE, "Setting this can create more complex surfaces on large hitboxes at the cost of performance.", true, 12.0f, true, 100.0f ); + + +//PRECACHE_REGISTER_BEGIN( GLOBAL, PrecacheEffectFreezing ) +// PRECACHE( MATERIAL,"effects/tesla_glow_noz" ) +// PRECACHE( MATERIAL,"effects/spark" ) +// PRECACHE( MATERIAL,"effects/combinemuzzle2" ) +//PRECACHE_REGISTER_END() + +//----------------------------------------------------------------------------- +// Networking +//----------------------------------------------------------------------------- +IMPLEMENT_CLIENTCLASS_DT( C_EntityFreezing, DT_EntityFreezing, CEntityFreezing ) + RecvPropVector( RECVINFO(m_vFreezingOrigin) ), + RecvPropArray3( RECVINFO_ARRAY(m_flFrozenPerHitbox), RecvPropFloat( RECVINFO( m_flFrozenPerHitbox[0] ) ) ), + RecvPropFloat( RECVINFO(m_flFrozen) ), + RecvPropBool( RECVINFO(m_bFinishFreezing) ), +END_RECV_TABLE() + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_EntityFreezing::GetRenderBounds( Vector& theMins, Vector& theMaxs ) +{ + if ( GetMoveParent() ) + { + GetMoveParent()->GetRenderBounds( theMins, theMaxs ); + } + else + { + theMins = GetAbsOrigin(); + theMaxs = theMaxs; + } +} + + +//----------------------------------------------------------------------------- +// Yes we bloody are +//----------------------------------------------------------------------------- +RenderableTranslucencyType_t C_EntityFreezing::ComputeTranslucencyType( ) +{ + return RENDERABLE_IS_TRANSLUCENT; +} + + +//----------------------------------------------------------------------------- +// On data changed +//----------------------------------------------------------------------------- +void C_EntityFreezing::OnDataChanged( DataUpdateType_t updateType ) +{ + BaseClass::OnDataChanged( updateType ); + if ( updateType == DATA_UPDATE_CREATED ) + { + SetNextClientThink( CLIENT_THINK_ALWAYS ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_EntityFreezing::ClientThink( void ) +{ + __asm nop; + //C_BaseAnimating *pAnimating = GetMoveParent() ? GetMoveParent()->GetBaseAnimating() : NULL; + //if (!pAnimating) + // return; + + //color32 color = pAnimating->GetRenderColor(); + + //color.r = color.g = ( 1.0f - m_flFrozen ) * 255.0f; + + //// Setup the entity fade + //pAnimating->SetRenderMode( kRenderTransColor ); + //pAnimating->SetRenderColor( color.r, color.g, color.b, color.a ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : flags - +// Output : int +//----------------------------------------------------------------------------- +int C_EntityFreezing::DrawModel( int flags, const RenderableInstance_t &instance ) +{ + + + return 1; +} diff --git a/game/client/c_entityfreezing.h b/game/client/c_entityfreezing.h new file mode 100644 index 000000000..594084d28 --- /dev/null +++ b/game/client/c_entityfreezing.h @@ -0,0 +1,47 @@ +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_ENTITY_FREEZING_H +#define C_ENTITY_FREEZING_H + +#include "cbase.h" + + +struct EntityFreezingHitboxBlobData_t +{ + CUtlVector m_vPoints; +}; + + +//----------------------------------------------------------------------------- +// Entity Dissolve, client-side implementation +//----------------------------------------------------------------------------- +class C_EntityFreezing : public C_BaseEntity +{ +public: + DECLARE_CLIENTCLASS(); + DECLARE_CLASS( C_EntityFreezing, C_BaseEntity ); + + virtual void GetRenderBounds( Vector& theMins, Vector& theMaxs ); + virtual RenderableTranslucencyType_t ComputeTranslucencyType( ); + virtual int DrawModel( int flags, const RenderableInstance_t &instance ); + virtual bool ShouldDraw() { return true; } + virtual void OnDataChanged( DataUpdateType_t updateType ); + + void ClientThink( void ); + +private: + Vector m_vFreezingOrigin; + float m_flFrozenPerHitbox[ 50 ]; + float m_flFrozen; + bool m_bFinishFreezing; + + CUtlVector m_HitboxBlobData; +}; + +#endif // C_ENTITY_FREEZING_H + diff --git a/game/client/c_entityparticletrail.cpp b/game/client/c_entityparticletrail.cpp index efc4987bc..307660e92 100644 --- a/game/client/c_entityparticletrail.cpp +++ b/game/client/c_entityparticletrail.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // diff --git a/game/client/c_env_ambient_light.cpp b/game/client/c_env_ambient_light.cpp new file mode 100644 index 000000000..80099a49d --- /dev/null +++ b/game/client/c_env_ambient_light.cpp @@ -0,0 +1,95 @@ +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// +// +// Purpose: Ambient light controller entity with simple radial falloff +// +// $NoKeywords: $ +//===========================================================================// +#include "cbase.h" + +#include "c_spatialentity.h" +#include "spatialentitymgr.h" +#include "c_env_ambient_light.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + +static ConVar cl_ambient_light_disableentities( "cl_ambient_light_disableentities", "0", FCVAR_NONE, "Disable map ambient light entities." ); + + +static CSpatialEntityMgr s_EnvAmbientLightMgr; + + +IMPLEMENT_CLIENTCLASS_DT( C_EnvAmbientLight, DT_EnvAmbientLight, CEnvAmbientLight ) + RecvPropVector( RECVINFO_NAME( m_Value, m_vecColor ) ), +END_RECV_TABLE() + + +void C_EnvAmbientLight::ApplyAccumulation( void ) +{ + Vector rgbVal = BlendedValue(); + + static ConVarRef mat_ambient_light_r( "mat_ambient_light_r" ); + static ConVarRef mat_ambient_light_g( "mat_ambient_light_g" ); + static ConVarRef mat_ambient_light_b( "mat_ambient_light_b" ); + + if ( mat_ambient_light_r.IsValid() ) + { + mat_ambient_light_r.SetValue( rgbVal.x ); + } + + if ( mat_ambient_light_g.IsValid() ) + { + mat_ambient_light_g.SetValue( rgbVal.y ); + } + + if ( mat_ambient_light_b.IsValid() ) + { + mat_ambient_light_b.SetValue( rgbVal.z ); + } +} + + +void C_EnvAmbientLight::AddToPersonalSpatialEntityMgr( void ) +{ + s_EnvAmbientLightMgr.AddSpatialEntity( this ); +} + +void C_EnvAmbientLight::RemoveFromPersonalSpatialEntityMgr( void ) +{ + s_EnvAmbientLightMgr.RemoveSpatialEntity( this ); +} + + + +void C_EnvAmbientLight::SetColor( const Vector &vecColor, float flLerpTime ) +{ + if ( flLerpTime <= 0 ) + { + m_Value = vecColor / 255.0f; + m_colorTimer.Invalidate(); + return; + } + + m_vecStartColor = m_Value; + m_vecTargetColor = vecColor / 255.0f; + m_colorTimer.Start( flLerpTime ); +} + +void C_EnvAmbientLight::ClientThink( void ) +{ + BaseClass::ClientThink(); + + if ( m_colorTimer.HasStarted() ) + { + if ( m_colorTimer.IsElapsed() ) + { + m_Value = m_vecTargetColor; + m_colorTimer.Invalidate(); + } + else + { + m_Value = m_vecTargetColor - ( m_vecTargetColor - m_vecStartColor ) * m_colorTimer.GetRemainingRatio(); + } + } +} \ No newline at end of file diff --git a/game/client/c_env_ambient_light.h b/game/client/c_env_ambient_light.h new file mode 100644 index 000000000..9f23f2521 --- /dev/null +++ b/game/client/c_env_ambient_light.h @@ -0,0 +1,30 @@ +#ifndef _INCLUDED_C_ENV_AMBIENT_LIGHT_H +#define _INCLUDED_C_ENV_AMBIENT_LIGHT_H + +#include "c_spatialentity.h" + +//------------------------------------------------------------------------------ +// Purpose : Ambient light controller entity with radial falloff +//------------------------------------------------------------------------------ +class C_EnvAmbientLight : public C_SpatialEntityTemplate +{ +public: + DECLARE_CLASS( C_EnvAmbientLight, C_SpatialEntityTemplate ); + DECLARE_CLIENTCLASS(); + + virtual void ApplyAccumulation( void ); + virtual void ClientThink( void ); + + void SetColor( const Vector &vecColor, float flLerpTime = 0 ); + Vector GetTargetColor() { return m_vecTargetColor * 255.0f; } + +protected: + virtual void AddToPersonalSpatialEntityMgr( void ); + virtual void RemoveFromPersonalSpatialEntityMgr( void ); + + Vector m_vecStartColor; + Vector m_vecTargetColor; + CountdownTimer m_colorTimer; +}; + +#endif // _INCLUDED_C_ENV_AMBIENT_LIGHT_H \ No newline at end of file diff --git a/game/client/c_env_dof_controller.cpp b/game/client/c_env_dof_controller.cpp new file mode 100644 index 000000000..67d0a5ffc --- /dev/null +++ b/game/client/c_env_dof_controller.cpp @@ -0,0 +1,100 @@ +//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======= +// +// Purpose: +// +//============================================================================= + +#include "cbase.h" + +// NOTE: This has to be the last file included! +#include "tier0/memdbgon.h" + + +extern bool g_bDOFEnabled; +extern float g_flDOFNearBlurDepth; +extern float g_flDOFNearFocusDepth; +extern float g_flDOFFarFocusDepth; +extern float g_flDOFFarBlurDepth; +extern float g_flDOFNearBlurRadius; +extern float g_flDOFFarBlurRadius; + +EHANDLE g_hDOFControllerInUse = NULL; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_EnvDOFController : public C_BaseEntity +{ + DECLARE_CLASS( C_EnvDOFController, C_BaseEntity ); +public: + DECLARE_CLIENTCLASS(); + + C_EnvDOFController(); + ~C_EnvDOFController(); + virtual void OnDataChanged( DataUpdateType_t updateType ); + +private: + bool m_bDOFEnabled; + float m_flNearBlurDepth; + float m_flNearFocusDepth; + float m_flFarFocusDepth; + float m_flFarBlurDepth; + float m_flNearBlurRadius; + float m_flFarBlurRadius; + +private: + C_EnvDOFController( const C_EnvDOFController & ); +}; + +IMPLEMENT_CLIENTCLASS_DT( C_EnvDOFController, DT_EnvDOFController, CEnvDOFController ) + RecvPropInt( RECVINFO(m_bDOFEnabled) ), + RecvPropFloat( RECVINFO(m_flNearBlurDepth) ), + RecvPropFloat( RECVINFO(m_flNearFocusDepth) ), + RecvPropFloat( RECVINFO(m_flFarFocusDepth) ), + RecvPropFloat( RECVINFO(m_flFarBlurDepth) ), + RecvPropFloat( RECVINFO(m_flNearBlurRadius) ), + RecvPropFloat( RECVINFO(m_flFarBlurRadius) ) +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_EnvDOFController::C_EnvDOFController( void ) +: m_bDOFEnabled( true ), + m_flNearBlurDepth( 50.0f ), + m_flNearFocusDepth( 100.0f ), + m_flFarFocusDepth( 250.0f ), + m_flFarBlurDepth( 1000.0f ), + m_flNearBlurRadius( 0.0f ), // no near blur by default + m_flFarBlurRadius( 5.0f ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_EnvDOFController::~C_EnvDOFController( void ) +{ + if ( g_hDOFControllerInUse == this ) + { + g_bDOFEnabled = false; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_EnvDOFController::OnDataChanged( DataUpdateType_t updateType ) +{ + BaseClass::OnDataChanged( updateType ); + + g_bDOFEnabled = m_bDOFEnabled && ( ( m_flNearBlurRadius > 0.0f ) || ( m_flFarBlurRadius > 0.0f ) ); + g_flDOFNearBlurDepth = m_flNearBlurDepth; + g_flDOFNearFocusDepth = m_flNearFocusDepth; + g_flDOFFarFocusDepth = m_flFarFocusDepth; + g_flDOFFarBlurDepth = m_flFarBlurDepth; + g_flDOFNearBlurRadius = m_flNearBlurRadius; + g_flDOFFarBlurRadius = m_flFarBlurRadius; + + g_hDOFControllerInUse = this; +} diff --git a/game/client/c_env_fog_controller.cpp b/game/client/c_env_fog_controller.cpp index f890fb122..233ce0082 100644 --- a/game/client/c_env_fog_controller.cpp +++ b/game/client/c_env_fog_controller.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2007, Valve Corporation, All rights reserved. ==== // // An entity that allows level designer control over the fog parameters. // @@ -20,19 +20,21 @@ BEGIN_NETWORK_TABLE_NOBASE( CFogController, DT_FogController ) RecvPropInt( RECVINFO( m_fog.enable ) ), RecvPropInt( RECVINFO( m_fog.blend ) ), RecvPropVector( RECVINFO( m_fog.dirPrimary ) ), - RecvPropInt( RECVINFO( m_fog.colorPrimary ) ), - RecvPropInt( RECVINFO( m_fog.colorSecondary ) ), + RecvPropInt( RECVINFO( m_fog.colorPrimary ), 0, RecvProxy_Int32ToColor32 ), + RecvPropInt( RECVINFO( m_fog.colorSecondary ), 0, RecvProxy_Int32ToColor32 ), RecvPropFloat( RECVINFO( m_fog.start ) ), RecvPropFloat( RECVINFO( m_fog.end ) ), RecvPropFloat( RECVINFO( m_fog.farz ) ), RecvPropFloat( RECVINFO( m_fog.maxdensity ) ), - RecvPropInt( RECVINFO( m_fog.colorPrimaryLerpTo ) ), - RecvPropInt( RECVINFO( m_fog.colorSecondaryLerpTo ) ), + RecvPropInt( RECVINFO( m_fog.colorPrimaryLerpTo ), 0, RecvProxy_Int32ToColor32 ), + RecvPropInt( RECVINFO( m_fog.colorSecondaryLerpTo ), 0, RecvProxy_Int32ToColor32 ), RecvPropFloat( RECVINFO( m_fog.startLerpTo ) ), RecvPropFloat( RECVINFO( m_fog.endLerpTo ) ), + RecvPropFloat( RECVINFO( m_fog.maxdensityLerpTo ) ), RecvPropFloat( RECVINFO( m_fog.lerptime ) ), RecvPropFloat( RECVINFO( m_fog.duration ) ), + RecvPropFloat( RECVINFO( m_fog.HDRColorScale ) ), END_NETWORK_TABLE() //----------------------------------------------------------------------------- @@ -43,4 +45,5 @@ C_FogController::C_FogController() // Make sure that old maps without fog fields don't get wacked out fog values. m_fog.enable = false; m_fog.maxdensity = 1.0f; + m_fog.HDRColorScale = 1.0f; } diff --git a/game/client/c_env_fog_controller.h b/game/client/c_env_fog_controller.h index d91c97d01..6fc7331e9 100644 --- a/game/client/c_env_fog_controller.h +++ b/game/client/c_env_fog_controller.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // diff --git a/game/client/c_env_global_light.cpp b/game/client/c_env_global_light.cpp new file mode 100644 index 000000000..0df836487 --- /dev/null +++ b/game/client/c_env_global_light.cpp @@ -0,0 +1,248 @@ +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: Sunlight shadow control entity. +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" + +#include "c_baseplayer.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + +extern ConVar cl_sunlight_ortho_size; +extern ConVar cl_sunlight_depthbias; + +ConVar cl_globallight_freeze( "cl_globallight_freeze", "0" ); +ConVar cl_globallight_xoffset( "cl_globallight_xoffset", "-800" ); +ConVar cl_globallight_yoffset( "cl_globallight_yoffset", "1600" ); + +//------------------------------------------------------------------------------ +// Purpose : Sunlights shadow control entity +//------------------------------------------------------------------------------ +class C_GlobalLight : public C_BaseEntity +{ +public: + DECLARE_CLASS( C_GlobalLight, C_BaseEntity ); + + DECLARE_CLIENTCLASS(); + + virtual ~C_GlobalLight(); + + void OnDataChanged( DataUpdateType_t updateType ); + void Spawn(); + bool ShouldDraw(); + + void ClientThink(); + +private: + Vector m_shadowDirection; + bool m_bEnabled; + char m_TextureName[ MAX_PATH ]; + CTextureReference m_SpotlightTexture; + color32 m_LightColor; + Vector m_CurrentLinearFloatLightColor; + float m_flCurrentLinearFloatLightAlpha; + float m_flColorTransitionTime; + float m_flSunDistance; + float m_flFOV; + float m_flNearZ; + float m_flNorthOffset; + bool m_bEnableShadows; + bool m_bOldEnableShadows; + + static ClientShadowHandle_t m_LocalFlashlightHandle; +}; + + +ClientShadowHandle_t C_GlobalLight::m_LocalFlashlightHandle = CLIENTSHADOW_INVALID_HANDLE; + + +IMPLEMENT_CLIENTCLASS_DT(C_GlobalLight, DT_GlobalLight, CGlobalLight) + RecvPropVector(RECVINFO(m_shadowDirection)), + RecvPropBool(RECVINFO(m_bEnabled)), + RecvPropString(RECVINFO(m_TextureName)), + RecvPropInt(RECVINFO(m_LightColor), 0, RecvProxy_Int32ToColor32), + RecvPropFloat(RECVINFO(m_flColorTransitionTime)), + RecvPropFloat(RECVINFO(m_flSunDistance)), + RecvPropFloat(RECVINFO(m_flFOV)), + RecvPropFloat(RECVINFO(m_flNearZ)), + RecvPropFloat(RECVINFO(m_flNorthOffset)), + RecvPropBool(RECVINFO(m_bEnableShadows)), +END_RECV_TABLE() + + +C_GlobalLight::~C_GlobalLight() +{ + if ( m_LocalFlashlightHandle != CLIENTSHADOW_INVALID_HANDLE ) + { + g_pClientShadowMgr->DestroyFlashlight( m_LocalFlashlightHandle ); + m_LocalFlashlightHandle = CLIENTSHADOW_INVALID_HANDLE; + } +} + +void C_GlobalLight::OnDataChanged( DataUpdateType_t updateType ) +{ + if ( updateType == DATA_UPDATE_CREATED ) + { + m_SpotlightTexture.Init( m_TextureName, TEXTURE_GROUP_OTHER, true ); + } + + BaseClass::OnDataChanged( updateType ); +} + +void C_GlobalLight::Spawn() +{ + BaseClass::Spawn(); + + m_bOldEnableShadows = m_bEnableShadows; + + SetNextClientThink( CLIENT_THINK_ALWAYS ); +} + +//------------------------------------------------------------------------------ +// We don't draw... +//------------------------------------------------------------------------------ +bool C_GlobalLight::ShouldDraw() +{ + return false; +} + +void C_GlobalLight::ClientThink() +{ + VPROF("C_GlobalLight::ClientThink"); + + bool bSupressWorldLights = false; + + if ( cl_globallight_freeze.GetBool() == true ) + { + return; + } + + if ( m_bEnabled ) + { + Vector vLinearFloatLightColor( m_LightColor.r, m_LightColor.g, m_LightColor.b ); + float flLinearFloatLightAlpha = m_LightColor.a; + + if ( m_CurrentLinearFloatLightColor != vLinearFloatLightColor || m_flCurrentLinearFloatLightAlpha != flLinearFloatLightAlpha ) + { + float flColorTransitionSpeed = gpGlobals->frametime * m_flColorTransitionTime * 255.0f; + + m_CurrentLinearFloatLightColor.x = Approach( vLinearFloatLightColor.x, m_CurrentLinearFloatLightColor.x, flColorTransitionSpeed ); + m_CurrentLinearFloatLightColor.y = Approach( vLinearFloatLightColor.y, m_CurrentLinearFloatLightColor.y, flColorTransitionSpeed ); + m_CurrentLinearFloatLightColor.z = Approach( vLinearFloatLightColor.z, m_CurrentLinearFloatLightColor.z, flColorTransitionSpeed ); + m_flCurrentLinearFloatLightAlpha = Approach( flLinearFloatLightAlpha, m_flCurrentLinearFloatLightAlpha, flColorTransitionSpeed ); + } + + FlashlightState_t state; + + Vector vDirection = m_shadowDirection; + VectorNormalize( vDirection ); + + //Vector vViewUp = Vector( 0.0f, 1.0f, 0.0f ); + Vector vSunDirection2D = vDirection; + vSunDirection2D.z = 0.0f; + + HACK_GETLOCALPLAYER_GUARD( "C_GlobalLight::ClientThink" ); + + if ( !C_BasePlayer::GetLocalPlayer() ) + return; + + Vector vPos; + QAngle EyeAngles; + float flZNear, flZFar, flFov; + + C_BasePlayer::GetLocalPlayer()->CalcView( vPos, EyeAngles, flZNear, flZFar, flFov ); +// Vector vPos = C_BasePlayer::GetLocalPlayer()->GetAbsOrigin(); + +// vPos = Vector( 0.0f, 0.0f, 500.0f ); + vPos = ( vPos + vSunDirection2D * m_flNorthOffset ) - vDirection * m_flSunDistance; + vPos += Vector( cl_globallight_xoffset.GetFloat(), cl_globallight_yoffset.GetFloat(), 0.0f ); + + QAngle angAngles; + VectorAngles( vDirection, angAngles ); + + Vector vForward, vRight, vUp; + AngleVectors( angAngles, &vForward, &vRight, &vUp ); + + state.m_fHorizontalFOVDegrees = m_flFOV; + state.m_fVerticalFOVDegrees = m_flFOV; + + state.m_vecLightOrigin = vPos; + BasisToQuaternion( vForward, vRight, vUp, state.m_quatOrientation ); + + state.m_fQuadraticAtten = 0.0f; + state.m_fLinearAtten = m_flSunDistance * 2.0f; + state.m_fConstantAtten = 0.0f; + state.m_FarZAtten = m_flSunDistance * 2.0f; + state.m_Color[0] = m_CurrentLinearFloatLightColor.x * ( 1.0f / 255.0f ) * m_flCurrentLinearFloatLightAlpha; + state.m_Color[1] = m_CurrentLinearFloatLightColor.y * ( 1.0f / 255.0f ) * m_flCurrentLinearFloatLightAlpha; + state.m_Color[2] = m_CurrentLinearFloatLightColor.z * ( 1.0f / 255.0f ) * m_flCurrentLinearFloatLightAlpha; + state.m_Color[3] = 0.0f; // fixme: need to make ambient work m_flAmbient; + state.m_NearZ = 4.0f; + state.m_FarZ = m_flSunDistance * 2.0f; + state.m_fBrightnessScale = 2.0f; + state.m_bGlobalLight = true; + + float flOrthoSize = 1000.0f; + + if ( flOrthoSize > 0 ) + { + state.m_bOrtho = true; + state.m_fOrthoLeft = -flOrthoSize; + state.m_fOrthoTop = -flOrthoSize; + state.m_fOrthoRight = flOrthoSize; + state.m_fOrthoBottom = flOrthoSize; + } + else + { + state.m_bOrtho = false; + } + + state.m_bDrawShadowFrustum = true; + state.m_flShadowSlopeScaleDepthBias = g_pMaterialSystemHardwareConfig->GetShadowSlopeScaleDepthBias();; + state.m_flShadowDepthBias = g_pMaterialSystemHardwareConfig->GetShadowDepthBias(); + state.m_bEnableShadows = m_bEnableShadows; + state.m_pSpotlightTexture = m_SpotlightTexture; + state.m_pProjectedMaterial = NULL; // don't complain cause we aren't using simple projection in this class + state.m_nSpotlightTextureFrame = 0; + + state.m_nShadowQuality = 1; // Allow entity to affect shadow quality +// state.m_bShadowHighRes = true; + + if ( m_bOldEnableShadows != m_bEnableShadows ) + { + // If they change the shadow enable/disable, we need to make a new handle + if ( m_LocalFlashlightHandle != CLIENTSHADOW_INVALID_HANDLE ) + { + g_pClientShadowMgr->DestroyFlashlight( m_LocalFlashlightHandle ); + m_LocalFlashlightHandle = CLIENTSHADOW_INVALID_HANDLE; + } + + m_bOldEnableShadows = m_bEnableShadows; + } + + if( m_LocalFlashlightHandle == CLIENTSHADOW_INVALID_HANDLE ) + { + m_LocalFlashlightHandle = g_pClientShadowMgr->CreateFlashlight( state ); + } + else + { + g_pClientShadowMgr->UpdateFlashlightState( m_LocalFlashlightHandle, state ); + g_pClientShadowMgr->UpdateProjectedTexture( m_LocalFlashlightHandle, true ); + } + + bSupressWorldLights = m_bEnableShadows; + } + else if ( m_LocalFlashlightHandle != CLIENTSHADOW_INVALID_HANDLE ) + { + g_pClientShadowMgr->DestroyFlashlight( m_LocalFlashlightHandle ); + m_LocalFlashlightHandle = CLIENTSHADOW_INVALID_HANDLE; + } + + g_pClientShadowMgr->SetShadowFromWorldLightsEnabled( !bSupressWorldLights ); + + BaseClass::ClientThink(); +} diff --git a/game/client/c_env_particlescript.cpp b/game/client/c_env_particlescript.cpp index daf6d9e68..ed39fb080 100644 --- a/game/client/c_env_particlescript.cpp +++ b/game/client/c_env_particlescript.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // @@ -41,8 +41,7 @@ class C_EnvParticleScript : public C_BaseAnimating, public IParticleEffect // NOTE: Ths enclosed particle effect binding will do all the drawing // But we have to return true, unlike other particle systems, for the animation events to work virtual bool ShouldDraw() { return true; } - virtual int DrawModel( int flags ) { return 0; } - virtual int GetFxBlend( void ) { return 0; } + virtual int DrawModel( int flags, const RenderableInstance_t &instance ) { return 0; } virtual void FireEvent( const Vector& origin, const QAngle& angles, int event, const char *options ); virtual void OnPreDataChanged( DataUpdateType_t updateType ); @@ -107,9 +106,10 @@ void C_EnvParticleScript::OnDataChanged( DataUpdateType_t updateType ) { BaseClass::OnDataChanged( updateType ); - if(updateType == DATA_UPDATE_CREATED) + if( updateType == DATA_UPDATE_CREATED ) { ParticleMgr()->AddEffect( &m_ParticleEffect, this ); + g_pClientLeafSystem->EnableRendering( RenderHandle(), false ); } if ( m_nOldSequence != GetSequence() ) diff --git a/game/client/c_env_projectedtexture.cpp b/game/client/c_env_projectedtexture.cpp index 310c3a279..e0d98977c 100644 --- a/game/client/c_env_projectedtexture.cpp +++ b/game/client/c_env_projectedtexture.cpp @@ -1,10 +1,12 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//====== Copyright © 1996-2003, Valve Corporation, All rights reserved. ======= // // Purpose: // //============================================================================= #include "cbase.h" + +#include "c_env_projectedtexture.h" #include "shareddefs.h" #include "materialsystem/imesh.h" #include "materialsystem/imaterial.h" @@ -14,72 +16,70 @@ #include "texture_group_names.h" #include "tier0/icommandline.h" + // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" -static ConVar mat_slopescaledepthbias_shadowmap( "mat_slopescaledepthbias_shadowmap", "16", FCVAR_CHEAT ); -static ConVar mat_depthbias_shadowmap( "mat_depthbias_shadowmap", "0.0005", FCVAR_CHEAT ); - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -class C_EnvProjectedTexture : public C_BaseEntity -{ - DECLARE_CLASS( C_EnvProjectedTexture, C_BaseEntity ); -public: - DECLARE_CLIENTCLASS(); - - virtual void OnDataChanged( DataUpdateType_t updateType ); - void ShutDownLightHandle( void ); - - virtual void Simulate(); - - void UpdateLight( bool bForceUpdate ); - - C_EnvProjectedTexture(); - ~C_EnvProjectedTexture(); - -private: - - ClientShadowHandle_t m_LightHandle; - - EHANDLE m_hTargetEntity; +float C_EnvProjectedTexture::m_flVisibleBBoxMinHeight = -FLT_MAX; - bool m_bState; - float m_flLightFOV; - bool m_bEnableShadows; - bool m_bLightOnlyTarget; - bool m_bLightWorld; - bool m_bCameraSpace; - Vector m_LinearFloatLightColor; - float m_flAmbient; - float m_flNearZ; - float m_flFarZ; - char m_SpotlightTextureName[ MAX_PATH ]; - int m_nSpotlightTextureFrame; - int m_nShadowQuality; -}; IMPLEMENT_CLIENTCLASS_DT( C_EnvProjectedTexture, DT_EnvProjectedTexture, CEnvProjectedTexture ) RecvPropEHandle( RECVINFO( m_hTargetEntity ) ), RecvPropBool( RECVINFO( m_bState ) ), + RecvPropBool( RECVINFO( m_bAlwaysUpdate ) ), RecvPropFloat( RECVINFO( m_flLightFOV ) ), RecvPropBool( RECVINFO( m_bEnableShadows ) ), + RecvPropBool( RECVINFO( m_bSimpleProjection ) ), RecvPropBool( RECVINFO( m_bLightOnlyTarget ) ), RecvPropBool( RECVINFO( m_bLightWorld ) ), RecvPropBool( RECVINFO( m_bCameraSpace ) ), - RecvPropVector( RECVINFO( m_LinearFloatLightColor ) ), + RecvPropFloat( RECVINFO( m_flBrightnessScale ) ), + RecvPropInt( RECVINFO( m_LightColor ), 0, RecvProxy_Int32ToColor32 ), + RecvPropFloat( RECVINFO( m_flColorTransitionTime ) ), RecvPropFloat( RECVINFO( m_flAmbient ) ), RecvPropString( RECVINFO( m_SpotlightTextureName ) ), RecvPropInt( RECVINFO( m_nSpotlightTextureFrame ) ), RecvPropFloat( RECVINFO( m_flNearZ ) ), RecvPropFloat( RECVINFO( m_flFarZ ) ), RecvPropInt( RECVINFO( m_nShadowQuality ) ), + RecvPropFloat( RECVINFO( m_flProjectionSize ) ), + RecvPropFloat( RECVINFO( m_flRotation ) ), END_RECV_TABLE() +C_EnvProjectedTexture *C_EnvProjectedTexture::Create( ) +{ + C_EnvProjectedTexture *pEnt = new C_EnvProjectedTexture(); + + pEnt->m_flNearZ = 4.0f; + pEnt->m_flFarZ = 2000.0f; +// strcpy( pEnt->m_SpotlightTextureName, "particle/rj" ); + pEnt->m_bLightWorld = true; + pEnt->m_bLightOnlyTarget = false; + pEnt->m_bSimpleProjection = false; + pEnt->m_nShadowQuality = 1; + pEnt->m_flLightFOV = 10.0f; + pEnt->m_LightColor.r = 255; + pEnt->m_LightColor.g = 255; + pEnt->m_LightColor.b = 255; + pEnt->m_LightColor.a = 255; + pEnt->m_bEnableShadows = false; + pEnt->m_flColorTransitionTime = 1.0f; + pEnt->m_bCameraSpace = false; + pEnt->SetAbsAngles( QAngle( 90, 0, 0 ) ); + pEnt->m_bAlwaysUpdate = true; + pEnt->m_bState = true; + pEnt->m_flProjectionSize = 500.0f; + pEnt->m_flRotation = 0.0f; + + return pEnt; +} + C_EnvProjectedTexture::C_EnvProjectedTexture( void ) { m_LightHandle = CLIENTSHADOW_INVALID_HANDLE; + m_bForceUpdate = true; + m_pMaterial = NULL; + AddToEntityList( ENTITY_LIST_SIMULATE ); } C_EnvProjectedTexture::~C_EnvProjectedTexture( void ) @@ -92,122 +92,317 @@ void C_EnvProjectedTexture::ShutDownLightHandle( void ) // Clear out the light if( m_LightHandle != CLIENTSHADOW_INVALID_HANDLE ) { - g_pClientShadowMgr->DestroyFlashlight( m_LightHandle ); + if ( m_bSimpleProjection == true ) + { + g_pClientShadowMgr->DestroyProjection( m_LightHandle ); + } + else + { + g_pClientShadowMgr->DestroyFlashlight( m_LightHandle ); + } m_LightHandle = CLIENTSHADOW_INVALID_HANDLE; } } + +void C_EnvProjectedTexture::SetMaterial( IMaterial *pMaterial ) +{ + m_pMaterial = pMaterial; +} + + +void C_EnvProjectedTexture::SetLightColor( byte r, byte g, byte b, byte a ) +{ + m_LightColor.r = r; + m_LightColor.g = g; + m_LightColor.b = b; + m_LightColor.a = a; +} + + +void C_EnvProjectedTexture::SetSize( float flSize ) +{ + m_flProjectionSize = flSize; +} + +// add to rotation +void C_EnvProjectedTexture::SetRotation( float flRotation ) +{ + if ( m_flRotation != flRotation ) + { + m_flRotation = flRotation; +// m_bForceUpdate = true; + } +} + //----------------------------------------------------------------------------- // Purpose: // Input : updateType - //----------------------------------------------------------------------------- void C_EnvProjectedTexture::OnDataChanged( DataUpdateType_t updateType ) { - UpdateLight( true ); + if ( updateType == DATA_UPDATE_CREATED ) + { + m_SpotlightTexture.Init( m_SpotlightTextureName, TEXTURE_GROUP_OTHER, true ); + } + + m_bForceUpdate = true; + UpdateLight(); BaseClass::OnDataChanged( updateType ); } -void C_EnvProjectedTexture::UpdateLight( bool bForceUpdate ) +static ConVar asw_perf_wtf("asw_perf_wtf", "0", FCVAR_DEVELOPMENTONLY, "Disable updating of projected shadow textures from UpdateLight" ); +void C_EnvProjectedTexture::UpdateLight( void ) { - if ( m_bState == false ) + VPROF("C_EnvProjectedTexture::UpdateLight"); + bool bVisible = true; + + Vector vLinearFloatLightColor( m_LightColor.r, m_LightColor.g, m_LightColor.b ); + float flLinearFloatLightAlpha = m_LightColor.a; + + if ( m_bAlwaysUpdate ) { - if ( m_LightHandle != CLIENTSHADOW_INVALID_HANDLE ) - { - ShutDownLightHandle(); - } + m_bForceUpdate = true; + } - return; + if ( m_CurrentLinearFloatLightColor != vLinearFloatLightColor || m_flCurrentLinearFloatLightAlpha != flLinearFloatLightAlpha ) + { + float flColorTransitionSpeed = gpGlobals->frametime * m_flColorTransitionTime * 255.0f; + + m_CurrentLinearFloatLightColor.x = Approach( vLinearFloatLightColor.x, m_CurrentLinearFloatLightColor.x, flColorTransitionSpeed ); + m_CurrentLinearFloatLightColor.y = Approach( vLinearFloatLightColor.y, m_CurrentLinearFloatLightColor.y, flColorTransitionSpeed ); + m_CurrentLinearFloatLightColor.z = Approach( vLinearFloatLightColor.z, m_CurrentLinearFloatLightColor.z, flColorTransitionSpeed ); + m_flCurrentLinearFloatLightAlpha = Approach( flLinearFloatLightAlpha, m_flCurrentLinearFloatLightAlpha, flColorTransitionSpeed ); + + m_bForceUpdate = true; + } + + if ( !m_bForceUpdate ) + { + bVisible = IsBBoxVisible(); } - Vector vForward, vRight, vUp, vPos = GetAbsOrigin(); - FlashlightState_t state; + if ( m_bState == false || !bVisible ) + { + // Spotlight's extents aren't in view + ShutDownLightHandle(); + + return; + } - if ( m_hTargetEntity != NULL ) + if ( m_LightHandle == CLIENTSHADOW_INVALID_HANDLE || m_hTargetEntity != NULL || m_bForceUpdate ) { - if ( m_bCameraSpace ) - { - const QAngle &angles = GetLocalAngles(); + Vector vForward, vRight, vUp, vPos = GetAbsOrigin(); + FlashlightState_t state; - C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); - if( pPlayer ) + if ( m_hTargetEntity != NULL ) + { + if ( m_bCameraSpace ) { - const QAngle playerAngles = pPlayer->GetAbsAngles(); - - Vector vPlayerForward, vPlayerRight, vPlayerUp; - AngleVectors( playerAngles, &vPlayerForward, &vPlayerRight, &vPlayerUp ); + const QAngle &angles = GetLocalAngles(); + + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + if( pPlayer ) + { + const QAngle playerAngles = pPlayer->GetAbsAngles(); - matrix3x4_t mRotMatrix; - AngleMatrix( angles, mRotMatrix ); + Vector vPlayerForward, vPlayerRight, vPlayerUp; + AngleVectors( playerAngles, &vPlayerForward, &vPlayerRight, &vPlayerUp ); - VectorITransform( vPlayerForward, mRotMatrix, vForward ); - VectorITransform( vPlayerRight, mRotMatrix, vRight ); - VectorITransform( vPlayerUp, mRotMatrix, vUp ); + matrix3x4_t mRotMatrix; + AngleMatrix( angles, mRotMatrix ); - float dist = (m_hTargetEntity->GetAbsOrigin() - GetAbsOrigin()).Length(); - vPos = m_hTargetEntity->GetAbsOrigin() - vForward*dist; + VectorITransform( vPlayerForward, mRotMatrix, vForward ); + VectorITransform( vPlayerRight, mRotMatrix, vRight ); + VectorITransform( vPlayerUp, mRotMatrix, vUp ); + float dist = (m_hTargetEntity->GetAbsOrigin() - GetAbsOrigin()).Length(); + vPos = m_hTargetEntity->GetAbsOrigin() - vForward*dist; + + VectorNormalize( vForward ); + VectorNormalize( vRight ); + VectorNormalize( vUp ); + } + } + else + { + vForward = m_hTargetEntity->GetAbsOrigin() - GetAbsOrigin(); VectorNormalize( vForward ); - VectorNormalize( vRight ); - VectorNormalize( vUp ); + + // JasonM - unimplemented + Assert (0); + + //Quaternion q = DirectionToOrientation( dir ); + + + // + // JasonM - set up vRight, vUp + // + + // VectorNormalize( vRight ); + // VectorNormalize( vUp ); } } else { - vForward = m_hTargetEntity->GetAbsOrigin() - GetAbsOrigin(); - VectorNormalize( vForward ); + AngleVectors( GetAbsAngles(), &vForward, &vRight, &vUp ); + } + + state.m_fHorizontalFOVDegrees = m_flLightFOV; + state.m_fVerticalFOVDegrees = m_flLightFOV; - // JasonM - unimplemented - Assert (0); + state.m_vecLightOrigin = vPos; + BasisToQuaternion( vForward, vRight, vUp, state.m_quatOrientation ); + state.m_NearZ = m_flNearZ; + state.m_FarZ = m_flFarZ; - //Quaternion q = DirectionToOrientation( dir ); + // quickly check the proposed light's bbox against the view frustum to determine whether we + // should bother to create it, if it doesn't exist, or cull it, if it does. + if ( m_bSimpleProjection == false ) + { +#pragma message("OPTIMIZATION: this should be made SIMD") + // get the half-widths of the near and far planes, + // based on the FOV which is in degrees. Remember that + // on planet Valve, x is forward, y left, and z up. + const float tanHalfAngle = tan( m_flLightFOV * ( M_PI/180.0f ) * 0.5f ); + const float halfWidthNear = tanHalfAngle * m_flNearZ; + const float halfWidthFar = tanHalfAngle * m_flFarZ; + // now we can build coordinates in local space: the near rectangle is eg + // (0, -halfWidthNear, -halfWidthNear), (0, halfWidthNear, -halfWidthNear), + // (0, halfWidthNear, halfWidthNear), (0, -halfWidthNear, halfWidthNear) + + VectorAligned vNearRect[4] = { + VectorAligned( m_flNearZ, -halfWidthNear, -halfWidthNear), VectorAligned( m_flNearZ, halfWidthNear, -halfWidthNear), + VectorAligned( m_flNearZ, halfWidthNear, halfWidthNear), VectorAligned( m_flNearZ, -halfWidthNear, halfWidthNear) + }; + + VectorAligned vFarRect[4] = { + VectorAligned( m_flFarZ, -halfWidthFar, -halfWidthFar), VectorAligned( m_flFarZ, halfWidthFar, -halfWidthFar), + VectorAligned( m_flFarZ, halfWidthFar, halfWidthFar), VectorAligned( m_flFarZ, -halfWidthFar, halfWidthFar) + }; + + matrix3x4_t matOrientation( vForward, -vRight, vUp, vPos ); + + enum + { + kNEAR = 0, + kFAR = 1, + }; + VectorAligned vOutRects[2][4]; + + for ( int i = 0 ; i < 4 ; ++i ) + { + VectorTransform( vNearRect[i].Base(), matOrientation, vOutRects[0][i].Base() ); + } + for ( int i = 0 ; i < 4 ; ++i ) + { + VectorTransform( vFarRect[i].Base(), matOrientation, vOutRects[1][i].Base() ); + } + // now take the min and max extents for the bbox, and see if it is visible. + Vector mins = **vOutRects; + Vector maxs = **vOutRects; + for ( int i = 1; i < 8 ; ++i ) + { + VectorMin( mins, *(*vOutRects+i), mins ); + VectorMax( maxs, *(*vOutRects+i), maxs ); + } - // - // JasonM - set up vRight, vUp - // +#if 0 //for debugging the visibility frustum we just calculated + NDebugOverlay::Triangle( vOutRects[0][0], vOutRects[0][1], vOutRects[0][2], 255, 0, 0, 100, true, 0.0f ); //first tri + NDebugOverlay::Triangle( vOutRects[0][2], vOutRects[0][1], vOutRects[0][0], 255, 0, 0, 100, true, 0.0f ); //make it double sided + NDebugOverlay::Triangle( vOutRects[0][2], vOutRects[0][3], vOutRects[0][0], 255, 0, 0, 100, true, 0.0f ); //second tri + NDebugOverlay::Triangle( vOutRects[0][0], vOutRects[0][3], vOutRects[0][2], 255, 0, 0, 100, true, 0.0f ); //make it double sided + + NDebugOverlay::Triangle( vOutRects[1][0], vOutRects[1][1], vOutRects[1][2], 0, 0, 255, 100, true, 0.0f ); //first tri + NDebugOverlay::Triangle( vOutRects[1][2], vOutRects[1][1], vOutRects[1][0], 0, 0, 255, 100, true, 0.0f ); //make it double sided + NDebugOverlay::Triangle( vOutRects[1][2], vOutRects[1][3], vOutRects[1][0], 0, 0, 255, 100, true, 0.0f ); //second tri + NDebugOverlay::Triangle( vOutRects[1][0], vOutRects[1][3], vOutRects[1][2], 0, 0, 255, 100, true, 0.0f ); //make it double sided + + NDebugOverlay::Box( vec3_origin, mins, maxs, 0, 255, 0, 100, 0.0f ); +#endif + + bool bVisible = IsBBoxVisible( mins, maxs ); + if (!bVisible) + { + // Spotlight's extents aren't in view + if ( m_LightHandle != CLIENTSHADOW_INVALID_HANDLE ) + { + ShutDownLightHandle(); + } -// VectorNormalize( vRight ); -// VectorNormalize( vUp ); + return; + } } - } - else - { - AngleVectors( GetAbsAngles(), &vForward, &vRight, &vUp ); - } - state.m_fHorizontalFOVDegrees = m_flLightFOV; - state.m_fVerticalFOVDegrees = m_flLightFOV; - - state.m_vecLightOrigin = vPos; - BasisToQuaternion( vForward, vRight, vUp, state.m_quatOrientation ); - - state.m_fQuadraticAtten = 0.0; - state.m_fLinearAtten = 100; - state.m_fConstantAtten = 0.0f; - state.m_Color[0] = m_LinearFloatLightColor.x; - state.m_Color[1] = m_LinearFloatLightColor.y; - state.m_Color[2] = m_LinearFloatLightColor.z; - state.m_Color[3] = 0.0f; // fixme: need to make ambient work m_flAmbient; - state.m_NearZ = m_flNearZ; - state.m_FarZ = m_flFarZ; - state.m_flShadowSlopeScaleDepthBias = mat_slopescaledepthbias_shadowmap.GetFloat(); - state.m_flShadowDepthBias = mat_depthbias_shadowmap.GetFloat(); - state.m_bEnableShadows = m_bEnableShadows; - state.m_pSpotlightTexture = materials->FindTexture( m_SpotlightTextureName, TEXTURE_GROUP_OTHER, false ); - state.m_nSpotlightTextureFrame = m_nSpotlightTextureFrame; - - state.m_nShadowQuality = m_nShadowQuality; // Allow entity to affect shadow quality - - if( m_LightHandle == CLIENTSHADOW_INVALID_HANDLE ) - { - m_LightHandle = g_pClientShadowMgr->CreateFlashlight( state ); - } - else - { - if ( m_hTargetEntity != NULL || bForceUpdate == true ) + float flAlpha = m_flCurrentLinearFloatLightAlpha * ( 1.0f / 255.0f ); + + state.m_fQuadraticAtten = 0.0; + state.m_fLinearAtten = 100; + state.m_fConstantAtten = 0.0f; + state.m_FarZAtten = m_flFarZ; + state.m_fBrightnessScale = m_flBrightnessScale; + state.m_Color[0] = m_CurrentLinearFloatLightColor.x * ( 1.0f / 255.0f ) * flAlpha; + state.m_Color[1] = m_CurrentLinearFloatLightColor.y * ( 1.0f / 255.0f ) * flAlpha; + state.m_Color[2] = m_CurrentLinearFloatLightColor.z * ( 1.0f / 255.0f ) * flAlpha; + state.m_Color[3] = 0.0f; // fixme: need to make ambient work m_flAmbient; + state.m_flShadowSlopeScaleDepthBias = g_pMaterialSystemHardwareConfig->GetShadowSlopeScaleDepthBias(); + state.m_flShadowDepthBias = g_pMaterialSystemHardwareConfig->GetShadowDepthBias(); + state.m_bEnableShadows = m_bEnableShadows; + state.m_pSpotlightTexture = m_SpotlightTexture; + state.m_pProjectedMaterial = NULL; // only complain if we're using material projection + state.m_nSpotlightTextureFrame = m_nSpotlightTextureFrame; + state.m_flProjectionSize = m_flProjectionSize; + state.m_flProjectionRotation = m_flRotation; + + state.m_nShadowQuality = m_nShadowQuality; // Allow entity to affect shadow quality + + if ( m_bSimpleProjection == true ) + { + state.m_bSimpleProjection = true; + state.m_bOrtho = true; + state.m_fOrthoLeft = -m_flProjectionSize; + state.m_fOrthoTop = -m_flProjectionSize; + state.m_fOrthoRight = m_flProjectionSize; + state.m_fOrthoBottom = m_flProjectionSize; + } + + if( m_LightHandle == CLIENTSHADOW_INVALID_HANDLE ) + { + // Hack: env projected textures don't work like normal flashlights; they're not assigned to a given splitscreen slot, + // but the flashlight code requires this + HACK_GETLOCALPLAYER_GUARD( "Env projected texture" ); + if ( m_bSimpleProjection == true ) + { + m_LightHandle = g_pClientShadowMgr->CreateProjection( state ); + } + else + { + m_LightHandle = g_pClientShadowMgr->CreateFlashlight( state ); + } + + if ( m_LightHandle != CLIENTSHADOW_INVALID_HANDLE ) + { + m_bForceUpdate = false; + } + } + else { - g_pClientShadowMgr->UpdateFlashlightState( m_LightHandle, state ); + if ( m_bSimpleProjection == true ) + { + g_pClientShadowMgr->UpdateProjectionState( m_LightHandle, state ); + } + else + { + g_pClientShadowMgr->UpdateFlashlightState( m_LightHandle, state ); + } + m_bForceUpdate = false; } + + g_pClientShadowMgr->GetFrustumExtents( m_LightHandle, m_vecExtentsMin, m_vecExtentsMax ); + + m_vecExtentsMin = m_vecExtentsMin - GetAbsOrigin(); + m_vecExtentsMax = m_vecExtentsMax - GetAbsOrigin(); } if( m_bLightOnlyTarget ) @@ -221,16 +416,27 @@ void C_EnvProjectedTexture::UpdateLight( bool bForceUpdate ) g_pClientShadowMgr->SetFlashlightLightWorld( m_LightHandle, m_bLightWorld ); - if ( bForceUpdate == false ) + if ( !asw_perf_wtf.GetBool() && !m_bForceUpdate ) { g_pClientShadowMgr->UpdateProjectedTexture( m_LightHandle, true ); } } -void C_EnvProjectedTexture::Simulate( void ) +bool C_EnvProjectedTexture::Simulate( void ) { - UpdateLight( false ); + UpdateLight(); BaseClass::Simulate(); + return true; +} + +bool C_EnvProjectedTexture::IsBBoxVisible( Vector vecExtentsMin, Vector vecExtentsMax ) +{ + // Z position clamped to the min height (but must be less than the max) + float flVisibleBBoxMinHeight = MIN( vecExtentsMax.z - 1.0f, m_flVisibleBBoxMinHeight ); + vecExtentsMin.z = MAX( vecExtentsMin.z, flVisibleBBoxMinHeight ); + + // Check if the bbox is in the view + return !engine->CullBox( vecExtentsMin, vecExtentsMax ); } diff --git a/game/client/c_env_projectedtexture.h b/game/client/c_env_projectedtexture.h new file mode 100644 index 000000000..9f778bf9a --- /dev/null +++ b/game/client/c_env_projectedtexture.h @@ -0,0 +1,96 @@ +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_ENVPROJECTED_TEXTURE_H +#define C_ENVPROJECTED_TEXTURE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "c_baseentity.h" +#include "basetypes.h" + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_EnvProjectedTexture : public C_BaseEntity +{ + DECLARE_CLASS( C_EnvProjectedTexture, C_BaseEntity ); +public: + DECLARE_CLIENTCLASS(); + + void SetMaterial( IMaterial *pMaterial ); + void SetLightColor( byte r, byte g, byte b, byte a ); + void SetSize( float flSize ); + void SetRotation( float flRotation ); + + virtual void OnDataChanged( DataUpdateType_t updateType ); + void ShutDownLightHandle( void ); + + virtual bool Simulate(); + + void UpdateLight( void ); + + C_EnvProjectedTexture(); + ~C_EnvProjectedTexture(); + + static void SetVisibleBBoxMinHeight( float flVisibleBBoxMinHeight ) { m_flVisibleBBoxMinHeight = flVisibleBBoxMinHeight; } + static float GetVisibleBBoxMinHeight( void ) { return m_flVisibleBBoxMinHeight; } + static C_EnvProjectedTexture *Create( ); + +private: + + inline bool IsBBoxVisible( void ); + bool IsBBoxVisible( Vector vecExtentsMin, + Vector vecExtentsMax ); + + ClientShadowHandle_t m_LightHandle; + bool m_bForceUpdate; + + EHANDLE m_hTargetEntity; + + bool m_bState; + bool m_bAlwaysUpdate; + float m_flLightFOV; + bool m_bEnableShadows; + bool m_bSimpleProjection; + bool m_bLightOnlyTarget; + bool m_bLightWorld; + bool m_bCameraSpace; + float m_flBrightnessScale; + color32 m_LightColor; + Vector m_CurrentLinearFloatLightColor; + float m_flCurrentLinearFloatLightAlpha; + float m_flColorTransitionTime; + float m_flAmbient; + float m_flNearZ; + float m_flFarZ; + char m_SpotlightTextureName[ MAX_PATH ]; + CTextureReference m_SpotlightTexture; + int m_nSpotlightTextureFrame; + int m_nShadowQuality; + + // simple projection + IMaterial *m_pMaterial; + float m_flProjectionSize; + float m_flRotation; + + Vector m_vecExtentsMin; + Vector m_vecExtentsMax; + + static float m_flVisibleBBoxMinHeight; +}; + + + +bool C_EnvProjectedTexture::IsBBoxVisible( void ) +{ + return IsBBoxVisible( GetAbsOrigin() + m_vecExtentsMin, GetAbsOrigin() + m_vecExtentsMax ); +} + +#endif // C_ENV_PROJECTED_TEXTURE_H diff --git a/game/client/c_env_screenoverlay.cpp b/game/client/c_env_screenoverlay.cpp index 5496d4530..f70015831 100644 --- a/game/client/c_env_screenoverlay.cpp +++ b/game/client/c_env_screenoverlay.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // @@ -13,7 +13,7 @@ #include "view_shared.h" #include "texture_group_names.h" #include "tier0/icommandline.h" -#include "KeyValues.h" +#include "keyvalues.h" #include "ScreenSpaceEffects.h" #include "materialsystem/imaterialsystemhardwareconfig.h" @@ -243,11 +243,6 @@ void C_EnvScreenEffect::ReceiveMessage( int classID, bf_read &msg ) if ( m_nType == SCREENEFFECT_EP1_INTRO ) { - if( g_pMaterialSystemHardwareConfig->GetDXSupportLevel() < 80 ) - { - return; - } - // Set our keys pKeys->SetFloat( "duration", m_flDuration ); pKeys->SetInt( "fadeout", 0 ); @@ -265,9 +260,6 @@ void C_EnvScreenEffect::ReceiveMessage( int classID, bf_read &msg ) } else if ( m_nType == SCREENEFFECT_EP2_GROGGY ) { - if( g_pMaterialSystemHardwareConfig->GetDXSupportLevel() < 80 ) - return; - // Set our keys pKeys->SetFloat( "duration", m_flDuration ); pKeys->SetInt( "fadeout", 0 ); @@ -285,10 +277,6 @@ void C_EnvScreenEffect::ReceiveMessage( int classID, bf_read &msg ) if ( m_nType == SCREENEFFECT_EP1_INTRO ) { - if( g_pMaterialSystemHardwareConfig->GetDXSupportLevel() < 80 ) - { - return; - } // Create a keyvalue block to set these params KeyValues *pKeys = new KeyValues( "keys" ); if ( pKeys == NULL ) @@ -306,10 +294,6 @@ void C_EnvScreenEffect::ReceiveMessage( int classID, bf_read &msg ) } else if ( m_nType == SCREENEFFECT_EP2_GROGGY ) { - if( g_pMaterialSystemHardwareConfig->GetDXSupportLevel() < 80 ) - { - return; - } // Create a keyvalue block to set these params KeyValues *pKeys = new KeyValues( "keys" ); if ( pKeys == NULL ) diff --git a/game/client/c_env_tonemap_controller.cpp b/game/client/c_env_tonemap_controller.cpp index 9151d5888..5ae40cbdf 100644 --- a/game/client/c_env_tonemap_controller.cpp +++ b/game/client/c_env_tonemap_controller.cpp @@ -1,10 +1,15 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======= // // Purpose: // //============================================================================= + #include "cbase.h" +// NOTE: This has to be the last file included! +#include "tier0/memdbgon.h" + + extern bool g_bUseCustomAutoExposureMin; extern bool g_bUseCustomAutoExposureMax; extern bool g_bUseCustomBloomScale; @@ -25,8 +30,6 @@ class C_EnvTonemapController : public C_BaseEntity DECLARE_CLIENTCLASS(); C_EnvTonemapController(); - ~C_EnvTonemapController(); - virtual void OnDataChanged( DataUpdateType_t updateType ); private: bool m_bUseCustomAutoExposureMin; @@ -36,8 +39,12 @@ class C_EnvTonemapController : public C_BaseEntity float m_flCustomAutoExposureMax; float m_flCustomBloomScale; float m_flCustomBloomScaleMinimum; + float m_flBloomExponent; + float m_flBloomSaturation; private: C_EnvTonemapController( const C_EnvTonemapController & ); + + friend void GetTonemapSettingsFromEnvTonemapController( void ); }; IMPLEMENT_CLIENTCLASS_DT( C_EnvTonemapController, DT_EnvTonemapController, CEnvTonemapController ) @@ -48,6 +55,8 @@ IMPLEMENT_CLIENTCLASS_DT( C_EnvTonemapController, DT_EnvTonemapController, CEnvT RecvPropFloat( RECVINFO(m_flCustomAutoExposureMax) ), RecvPropFloat( RECVINFO(m_flCustomBloomScale) ), RecvPropFloat( RECVINFO(m_flCustomBloomScaleMinimum) ), + RecvPropFloat( RECVINFO(m_flBloomExponent) ), + RecvPropFloat( RECVINFO(m_flBloomSaturation) ), END_RECV_TABLE() //----------------------------------------------------------------------------- @@ -62,36 +71,31 @@ C_EnvTonemapController::C_EnvTonemapController( void ) m_flCustomAutoExposureMax = 0; m_flCustomBloomScale = 0.0f; m_flCustomBloomScaleMinimum = 0.0f; + m_flBloomExponent = 2.5f; + m_flBloomSaturation = 1.0f; } -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -C_EnvTonemapController::~C_EnvTonemapController( void ) + + +void GetTonemapSettingsFromEnvTonemapController( void ) { - if ( g_hTonemapControllerInUse == this ) + C_BasePlayer *localPlayer = C_BasePlayer::GetLocalPlayer(); + if ( localPlayer ) { - g_bUseCustomAutoExposureMin = false; - g_bUseCustomAutoExposureMax = false; - g_bUseCustomBloomScale = false; + C_EnvTonemapController *tonemapController = dynamic_cast< C_EnvTonemapController * >(localPlayer->m_hTonemapController.Get()); + if ( tonemapController != NULL ) + { + g_bUseCustomAutoExposureMin = tonemapController->m_bUseCustomAutoExposureMin; + g_bUseCustomAutoExposureMax = tonemapController->m_bUseCustomAutoExposureMax; + g_bUseCustomBloomScale = tonemapController->m_bUseCustomBloomScale; + g_flCustomAutoExposureMin = tonemapController->m_flCustomAutoExposureMin; + g_flCustomAutoExposureMax = tonemapController->m_flCustomAutoExposureMax; + g_flCustomBloomScale = tonemapController->m_flCustomBloomScale; + g_flCustomBloomScaleMinimum = tonemapController->m_flCustomBloomScaleMinimum; + return; + } } -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void C_EnvTonemapController::OnDataChanged( DataUpdateType_t updateType ) -{ - BaseClass::OnDataChanged(updateType); - g_bUseCustomAutoExposureMin = m_bUseCustomAutoExposureMin; - g_bUseCustomAutoExposureMax = m_bUseCustomAutoExposureMax; - g_bUseCustomBloomScale = m_bUseCustomBloomScale; - g_flCustomAutoExposureMin = m_flCustomAutoExposureMin; - g_flCustomAutoExposureMax = m_flCustomAutoExposureMax; - g_flCustomBloomScale = m_flCustomBloomScale; - g_flCustomBloomScaleMinimum = m_flCustomBloomScaleMinimum; - - g_hTonemapControllerInUse = this; + g_bUseCustomAutoExposureMax = false; + g_bUseCustomBloomScale = false; } - diff --git a/game/client/c_fire_smoke.cpp b/game/client/c_fire_smoke.cpp index 42e6f3edc..164cb4290 100644 --- a/game/client/c_fire_smoke.cpp +++ b/game/client/c_fire_smoke.cpp @@ -1,12 +1,12 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // // $NoKeywords: $ -//=============================================================================// +//===========================================================================// #include "cbase.h" -#include "iviewrender.h" -#include "clienteffectprecachesystem.h" +#include "IViewRender.h" +#include "precache_register.h" #include "studio.h" #include "bone_setup.h" #include "engine/ivmodelinfo.h" @@ -14,15 +14,15 @@ #include "engine/IEngineSound.h" #include "iefx.h" #include "dlight.h" -#include "tier0/icommandline.h" +#include "tier0/ICommandLine.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" -CLIENTEFFECT_REGISTER_BEGIN( SmokeStackMaterials ) - CLIENTEFFECT_MATERIAL( "particle/SmokeStack" ) -CLIENTEFFECT_REGISTER_END() +PRECACHE_REGISTER_BEGIN( GLOBAL, SmokeStackMaterials ) + PRECACHE( MATERIAL, "particle/SmokeStack" ) +PRECACHE_REGISTER_END() //----------------------------------------------------------------------------- @@ -109,12 +109,6 @@ C_FireSmoke::~C_FireSmoke() } -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void C_FireSmoke::Simulate( void ) -{ -} #define FLAME_ALPHA_START 0.9f #define FLAME_ALPHA_END 1.0f @@ -265,145 +259,3 @@ void C_FireSmoke::FindClipPlane( void ) void C_FireSmoke::SpawnSmoke( void ) { } - - -IMPLEMENT_CLIENTCLASS_DT( C_EntityFlame, DT_EntityFlame, CEntityFlame ) - RecvPropEHandle(RECVINFO(m_hEntAttached)), -END_RECV_TABLE() - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -C_EntityFlame::C_EntityFlame( void ) : -m_hEffect( NULL ) -{ - m_hOldAttached = NULL; -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -C_EntityFlame::~C_EntityFlame( void ) -{ - StopEffect(); -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void C_EntityFlame::StopEffect( void ) -{ - if ( m_hEffect ) - { - ParticleProp()->StopEmission( m_hEffect, true ); - m_hEffect->SetControlPointEntity( 0, NULL ); - m_hEffect->SetControlPointEntity( 1, NULL ); - m_hEffect = NULL; - } - - if ( m_hEntAttached ) - { - m_hEntAttached->RemoveFlag( FL_ONFIRE ); - m_hEntAttached->SetEffectEntity( NULL ); - m_hEntAttached->StopSound( "General.BurningFlesh" ); - m_hEntAttached->StopSound( "General.BurningObject" ); - - - m_hEntAttached = NULL; - } -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void C_EntityFlame::UpdateOnRemove( void ) -{ - StopEffect(); - BaseClass::UpdateOnRemove(); -} - -void C_EntityFlame::CreateEffect( void ) -{ - if ( m_hEffect ) - { - ParticleProp()->StopEmission( m_hEffect, true ); - m_hEffect->SetControlPointEntity( 0, NULL ); - m_hEffect->SetControlPointEntity( 1, NULL ); - m_hEffect = NULL; - } - -#ifdef TF_CLIENT_DLL - m_hEffect = ParticleProp()->Create( "burningplayer_red", PATTACH_ABSORIGIN_FOLLOW ); -#else - m_hEffect = ParticleProp()->Create( "burning_character", PATTACH_ABSORIGIN_FOLLOW ); -#endif - - if ( m_hEffect ) - { - C_BaseEntity *pEntity = m_hEntAttached; - m_hOldAttached = m_hEntAttached; - - ParticleProp()->AddControlPoint( m_hEffect, 1, pEntity, PATTACH_ABSORIGIN_FOLLOW ); - m_hEffect->SetControlPoint( 0, GetAbsOrigin() ); - m_hEffect->SetControlPoint( 1, GetAbsOrigin() ); - m_hEffect->SetControlPointEntity( 0, pEntity ); - m_hEffect->SetControlPointEntity( 1, pEntity ); - } -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void C_EntityFlame::OnDataChanged( DataUpdateType_t updateType ) -{ - if ( updateType == DATA_UPDATE_CREATED ) - { - CreateEffect(); - } - - // FIXME: This is a bit of a shady path - if ( updateType == DATA_UPDATE_DATATABLE_CHANGED ) - { - // If our owner changed, then recreate the effect - if ( m_hEntAttached != m_hOldAttached ) - { - CreateEffect(); - } - } - - BaseClass::OnDataChanged( updateType ); -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void C_EntityFlame::Simulate( void ) -{ - if ( gpGlobals->frametime <= 0.0f ) - return; - -#ifdef HL2_EPISODIC - - if ( IsEffectActive(EF_BRIGHTLIGHT) || IsEffectActive(EF_DIMLIGHT) ) - { - dlight_t *dl = effects->CL_AllocDlight ( index ); - dl->origin = GetAbsOrigin(); - dl->origin[2] += 16; - dl->color.r = 254; - dl->color.g = 174; - dl->color.b = 10; - dl->radius = random->RandomFloat(400,431); - dl->die = gpGlobals->curtime + 0.001; - } - -#endif // HL2_EPISODIC -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void C_EntityFlame::ClientThink( void ) -{ - StopEffect(); - Release(); -} diff --git a/game/client/c_fire_smoke.h b/game/client/c_fire_smoke.h index 9f7a94e11..beecfda54 100644 --- a/game/client/c_fire_smoke.h +++ b/game/client/c_fire_smoke.h @@ -1,10 +1,10 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // // $NoKeywords: $ // -//=============================================================================// +//===========================================================================// #ifndef C_FIRE_SMOKE_H #define C_FIRE_SMOKE_H @@ -13,6 +13,8 @@ #include "glow_overlay.h" #include "view.h" #include "particle_litsmokeemitter.h" +#include "tier1/utlobjectreference.h" + class CFireOverlay; @@ -21,7 +23,7 @@ class C_FireSprite : public C_Sprite DECLARE_CLASS( C_FireSprite, C_Sprite ); private: - virtual int DrawModel( int flags ) + virtual int DrawModel( int flags, const RenderableInstance_t &instance ) { if ( m_bFadeFromAbove ) { @@ -45,7 +47,7 @@ class C_FireSprite : public C_Sprite SetColor( iAlpha, iAlpha, iAlpha ); } - return BaseClass::DrawModel( flags ); + return BaseClass::DrawModel( flags, instance ); } public: @@ -57,7 +59,7 @@ class C_FireFromAboveSprite : public C_Sprite { DECLARE_CLASS( C_FireFromAboveSprite, C_Sprite ); - virtual int DrawModel( int flags ) + virtual int DrawModel( int flags, const RenderableInstance_t &instance ) { // The sprites become more visible the more you look down or up at them Vector vToPos = GetLocalOrigin() - CurrentViewOrigin(); @@ -78,7 +80,7 @@ class C_FireFromAboveSprite : public C_Sprite SetColor( iAlpha, iAlpha, iAlpha ); - return BaseClass::DrawModel( flags ); + return BaseClass::DrawModel( flags, instance ); } }; @@ -122,7 +124,6 @@ class C_FireSmoke : public C_BaseEntity ~C_FireSmoke(); void Start( void ); - void Simulate( void ); void StartClientOnly( void ); void RemoveClientOnly( void ); @@ -184,7 +185,7 @@ class C_FireSmoke : public C_BaseEntity CFireOverlay *m_pFireOverlay; // New Particle Fire Effect - CNewParticleEffect *m_hEffect; + CUtlReference m_hEffect; private: C_FireSmoke( const C_FireSmoke & ); }; @@ -269,34 +270,4 @@ class CFireOverlay : public CGlowOverlay int m_nGUID; }; -// -// Entity flame, client-side implementation -// - -#define NUM_FLAMELETS 5 - -class C_EntityFlame : public C_BaseEntity -{ -public: - DECLARE_CLIENTCLASS(); - DECLARE_CLASS( C_EntityFlame, C_BaseEntity ); - - C_EntityFlame( void ); - ~C_EntityFlame( void ); - - virtual void Simulate( void ); - virtual void UpdateOnRemove( void ); - virtual void OnDataChanged( DataUpdateType_t updateType ); - virtual void ClientThink( void ); - - CNewParticleEffect *m_hEffect; - EHANDLE m_hEntAttached; // The entity that we are burning (attached to). - EHANDLE m_hOldAttached; - -protected: - - void CreateEffect( void ); - void StopEffect( void ); -}; - -#endif //C_FIRE_SMOKE_H \ No newline at end of file +#endif // C_FIRE_SMOKE_H diff --git a/game/client/c_fish.cpp b/game/client/c_fish.cpp index 903080cc7..960f54140 100644 --- a/game/client/c_fish.cpp +++ b/game/client/c_fish.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // @@ -11,7 +11,7 @@ #include "cbase.h" #include -#include "engine/ivdebugoverlay.h" +#include "engine/IVDebugOverlay.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" diff --git a/game/client/c_forcefeedback.cpp b/game/client/c_forcefeedback.cpp index 8c0c0f7cc..86ba8bf36 100644 --- a/game/client/c_forcefeedback.cpp +++ b/game/client/c_forcefeedback.cpp @@ -1,9 +1,12 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// #include "cbase.h" #include "forcefeedback.h" #include "hud_macros.h" #include "input.h" +// NOTE: This has to be the last file included! +#include "tier0/memdbgon.h" + + #define FF_CLIENT_FLAG 0x8000 class FFParams diff --git a/game/client/c_func_areaportalwindow.cpp b/game/client/c_func_areaportalwindow.cpp index b910e7a82..3345cd6d2 100644 --- a/game/client/c_func_areaportalwindow.cpp +++ b/game/client/c_func_areaportalwindow.cpp @@ -1,14 +1,14 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // // $NoKeywords: $ // -//=============================================================================// +//===========================================================================// #include "cbase.h" #include "view.h" #include "model_types.h" -#include "ivrenderview.h" +#include "IVRenderView.h" #include "engine/ivmodelinfo.h" // memdbgon must be the last include file in a .cpp file!!! @@ -25,18 +25,14 @@ class C_FuncAreaPortalWindow : public C_BaseEntity // Overrides. public: - - virtual void ComputeFxBlend(); - virtual bool IsTransparent(); - virtual int DrawModel( int flags ); + RenderableTranslucencyType_t ComputeTranslucencyType( void ); + virtual int DrawModel( int flags, const RenderableInstance_t &instance ); virtual bool ShouldReceiveProjectedTextures( int flags ); private: float GetDistanceBlend(); - - public: float m_flFadeStartDist; // Distance at which it starts fading (when <= this, alpha=m_flTranslucencyLimit). float m_flFadeDist; // Distance at which it becomes solid. @@ -57,26 +53,12 @@ IMPLEMENT_CLIENTCLASS_DT( C_FuncAreaPortalWindow, DT_FuncAreaPortalWindow, CFunc END_RECV_TABLE() - -void C_FuncAreaPortalWindow::ComputeFxBlend() -{ - // We reset our blend down below so pass anything except 0 to the renderer. - m_nRenderFXBlend = 255; - -#ifdef _DEBUG - m_nFXComputeFrame = gpGlobals->framecount; -#endif - -} - - -bool C_FuncAreaPortalWindow::IsTransparent() +RenderableTranslucencyType_t C_FuncAreaPortalWindow::ComputeTranslucencyType( void ) { - return true; + return RENDERABLE_IS_TRANSLUCENT; } - -int C_FuncAreaPortalWindow::DrawModel( int flags ) +int C_FuncAreaPortalWindow::DrawModel( int flags, const RenderableInstance_t &instance ) { if ( !m_bReadyToDraw ) return 0; @@ -90,20 +72,17 @@ int C_FuncAreaPortalWindow::DrawModel( int flags ) return 0; // Draw the fading version. - render->SetBlend( GetDistanceBlend() ); - - DrawBrushModelMode_t mode = DBM_DRAW_ALL; - if ( flags & STUDIO_TWOPASS ) - { - mode = ( flags & STUDIO_TRANSPARENCY ) ? DBM_DRAW_TRANSLUCENT_ONLY : DBM_DRAW_OPAQUE_ONLY; - } + float flBlendAlpha = GetDistanceBlend(); + if ( flBlendAlpha == 0.0f ) + return 0; - render->DrawBrushModelEx( + render->SetBlend( flBlendAlpha ); + render->DrawBrushModel( this, (model_t *)GetModel(), GetAbsOrigin(), GetAbsAngles(), - mode ); + !!(flags & STUDIO_TRANSPARENCY) ); // Draw the optional foreground model next. // Only use the alpha in the texture from the thing in the front. @@ -113,19 +92,18 @@ int C_FuncAreaPortalWindow::DrawModel( int flags ) model_t *pBackground = ( model_t * )modelinfo->GetModel( m_iBackgroundModelIndex ); if( pBackground && modelinfo->GetModelType( pBackground ) == mod_brush ) { - render->DrawBrushModelEx( + render->DrawBrushModel( this, pBackground, GetAbsOrigin(), GetAbsAngles(), - mode ); + !!(flags & STUDIO_TRANSPARENCY) ); } } return 1; } - float C_FuncAreaPortalWindow::GetDistanceBlend() { // Get the viewer's distance to us. diff --git a/game/client/c_func_breakablesurf.cpp b/game/client/c_func_breakablesurf.cpp index 3118cd5e2..1be9dc1ae 100644 --- a/game/client/c_func_breakablesurf.cpp +++ b/game/client/c_func_breakablesurf.cpp @@ -1,19 +1,20 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ // -//=============================================================================// +//===========================================================================// #include "cbase.h" #include "particles_simple.h" -#include "iviewrender.h" -#include "proxyentity.h" -#include "materialsystem/imaterialvar.h" +#include "IViewRender.h" +#include "ProxyEntity.h" +#include "materialsystem/IMaterialVar.h" #include "model_types.h" #include "engine/ivmodelinfo.h" -#include "clienteffectprecachesystem.h" +#include "c_physbox.h" +#include "imaterialproxydict.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -73,7 +74,6 @@ struct EdgeTexture_t #define BITS_PANEL_IS_SOLID (1<<0) #define BITS_PANEL_IS_STALE (1<<1) - class C_BreakableSurface : public C_BaseEntity, public IBrushRenderer { public: @@ -106,10 +106,10 @@ class C_BreakableSurface : public C_BaseEntity, public IBrushRenderer virtual void OnDataChanged( DataUpdateType_t updateType ); virtual void OnPreDataChanged( DataUpdateType_t updateType ); - bool IsTransparent( void ); + RenderableTranslucencyType_t ComputeTranslucencyType( void ); bool HavePanel(int nWidth, int nHeight); bool RenderBrushModelSurface( IClientEntity* pBaseEntity, IBrushSurface* pBrushSurface ); - int DrawModel( int flags ); + int DrawModel( int flags, const RenderableInstance_t &instance ); void DrawSolidBlocks( IBrushSurface* pBrushSurface ); virtual void OnRestore(); @@ -154,7 +154,7 @@ class C_BreakableSurface : public C_BaseEntity, public IBrushRenderer Assert( type < NUM_EDGE_STYLES ); Assert( type >= 0 ); // Clear old value - m_nPanelBits[ w ][ h ] &= 0xF0; // ( ~0x03 << 2 ); Left shifting a negative value has undefined behavior. Use the constant 0xF0 instead. + m_nPanelBits[ w ][ h ] &= ( ~0x03 << 2 ); // Insert new value m_nPanelBits[ w ][ h ] |= ( type << 2 ); } @@ -285,7 +285,7 @@ END_RECV_TABLE() //----------------------------------------------------------------------------- void C_BreakableSurface::FindCrackedMaterial() { - m_pCrackedMaterial = 0; + m_pCrackedMaterial.Init( NULL ); // First time we've seen it, get the material on the brush model int materialCount = modelinfo->GetModelMaterialCount( const_cast(GetModel()) ); @@ -391,6 +391,9 @@ void C_BreakableSurface::OnDataChanged( DataUpdateType_t updateType ) { C_BaseEntity::OnDataChanged( updateType ); + // FIXME: Slightly bogus, recomputation only necessary when m_bBroken changed + OnTranslucencyTypeChanged(); + if ( updateType == DATA_UPDATE_CREATED ) { // Get at the cracked material @@ -494,22 +497,22 @@ void C_BreakableSurface::OnDataChanged( DataUpdateType_t updateType ) Q_memcpy( m_PrevRawPanelBitVec, m_RawPanelBitVec.Base(), sizeof( m_PrevRawPanelBitVec ) ); } -bool C_BreakableSurface::IsTransparent( void ) +RenderableTranslucencyType_t C_BreakableSurface::ComputeTranslucencyType( void ) { // Not an identity brush if it's broken - if (m_bIsBroken) - return true; + if ( m_bIsBroken ) + return RENDERABLE_IS_TRANSLUCENT; - return C_BaseEntity::IsTransparent(); + return BaseClass::ComputeTranslucencyType(); } - + //------------------------------------------------------------------------------ // Purpose : // Input : // Output : //------------------------------------------------------------------------------ -int C_BreakableSurface::DrawModel( int flags ) +int C_BreakableSurface::DrawModel( int flags, const RenderableInstance_t &instance ) { if ( !m_bReadyToDraw ) return 0; @@ -519,7 +522,7 @@ int C_BreakableSurface::DrawModel( int flags ) render->InstallBrushSurfaceRenderer( this ); // If it's broken, always draw it translucent - BaseClass::DrawModel( m_bIsBroken ? flags | STUDIO_TRANSPARENCY : flags ); + BaseClass::DrawModel( m_bIsBroken ? flags | STUDIO_TRANSPARENCY : flags, instance ); // Remove our nonstandard brush surface renderer... render->InstallBrushSurfaceRenderer( 0 ); @@ -1333,4 +1336,4 @@ IMaterial *CBreakableSurfaceProxy::GetMaterial() return m_BaseTextureVar->GetOwningMaterial(); } -EXPOSE_INTERFACE( CBreakableSurfaceProxy, IMaterialProxy, "BreakableSurface" IMATERIAL_PROXY_INTERFACE_VERSION ); +EXPOSE_MATERIAL_PROXY( CBreakableSurfaceProxy, BreakableSurface ); diff --git a/game/client/c_func_brush.cpp b/game/client/c_func_brush.cpp new file mode 100644 index 000000000..f0e4dc2b8 --- /dev/null +++ b/game/client/c_func_brush.cpp @@ -0,0 +1,19 @@ +#include "cbase.h" +#include "c_func_brush.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +IMPLEMENT_CLIENTCLASS_DT( C_FuncBrush, DT_FuncBrush, CFuncBrush ) +END_RECV_TABLE() + + +void C_FuncBrush::OnDataChanged( DataUpdateType_t type ) +{ + BaseClass::OnDataChanged( type ); + + bool bCreate = (type == DATA_UPDATE_CREATED) ? true : false; + VPhysicsShadowDataChanged(bCreate, this); +} + + diff --git a/game/client/c_func_brush.h b/game/client/c_func_brush.h new file mode 100644 index 000000000..51e440799 --- /dev/null +++ b/game/client/c_func_brush.h @@ -0,0 +1,24 @@ +//========= Copyright © 1996-2008, Valve Corporation, All rights reserved. ============// +// +// Purpose: +//=============================================================================// + +#ifndef C_FUNC_BRUSH_H +#define C_FUNC_BRUSH_H +#ifdef _WIN32 +#pragma once +#endif + +class C_FuncBrush : public C_BaseEntity +{ +public: + DECLARE_CLASS( C_FuncBrush, C_BaseEntity ); + DECLARE_CLIENTCLASS(); + + void OnDataChanged( DataUpdateType_t type ); + +private: +}; + +#endif // C_FUNC_BRUSH_H + diff --git a/game/client/c_func_conveyor.cpp b/game/client/c_func_conveyor.cpp index 58d21bf99..00b872941 100644 --- a/game/client/c_func_conveyor.cpp +++ b/game/client/c_func_conveyor.cpp @@ -1,24 +1,21 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // //===========================================================================// #include "cbase.h" -#include "materialsystem/imaterialproxy.h" -#include "materialsystem/imaterial.h" -#include "materialsystem/imaterialvar.h" -#include "functionproxy.h" +#include "materialsystem/IMaterialProxy.h" +#include "materialsystem/IMaterial.h" +#include "materialsystem/IMaterialVar.h" +#include "FunctionProxy.h" #include -#include "mathlib/vmatrix.h" -#include "toolframework_client.h" +#include "mathlib/VMatrix.h" +#include "imaterialproxydict.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" -// forward declarations -void ToolFramework_RecordMaterialParams( IMaterial *pMaterial ); - class C_FuncConveyor : public C_BaseEntity { public: @@ -143,11 +140,6 @@ void CConveyorMaterialProxy::OnBind( void *pC_BaseEntity ) { m_pTextureScrollVar->SetVecValue( sOffset, tOffset, 0.0f ); } - - if ( ToolsEnabled() ) - { - ToolFramework_RecordMaterialParams( GetMaterial() ); - } } IMaterial *CConveyorMaterialProxy::GetMaterial() @@ -155,4 +147,4 @@ IMaterial *CConveyorMaterialProxy::GetMaterial() return m_pTextureScrollVar ? m_pTextureScrollVar->GetOwningMaterial() : NULL; } -EXPOSE_INTERFACE( CConveyorMaterialProxy, IMaterialProxy, "ConveyorScroll" IMATERIAL_PROXY_INTERFACE_VERSION ); +EXPOSE_MATERIAL_PROXY( CConveyorMaterialProxy, ConveyorScroll ); diff --git a/game/client/c_func_dust.cpp b/game/client/c_func_dust.cpp index 94f114e4a..d22ae4e8e 100644 --- a/game/client/c_func_dust.cpp +++ b/game/client/c_func_dust.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // @@ -12,14 +12,13 @@ #include "env_wind_shared.h" #include "engine/IEngineTrace.h" #include "tier0/vprof.h" -#include "clienteffectprecachesystem.h" #include "particles_ez.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" IMPLEMENT_CLIENTCLASS_DT_NOBASE( C_Func_Dust, DT_Func_Dust, CFunc_Dust ) - RecvPropInt( RECVINFO(m_Color) ), + RecvPropInt( RECVINFO(m_Color), 0, RecvProxy_Int32ToColor32 ), RecvPropInt( RECVINFO(m_SpawnRate) ), RecvPropFloat( RECVINFO(m_flSizeMin) ), RecvPropFloat( RECVINFO(m_flSizeMax) ), @@ -228,12 +227,12 @@ void C_Func_Dust::AttemptSpawnNewParticle() pParticle->m_vVelocity.z -= m_FallSpeed; pParticle->m_flLifetime = 0; - pParticle->m_flDieTime = RemapVal( rand(), 0, VALVE_RAND_MAX, m_LifetimeMin, m_LifetimeMax ); + pParticle->m_flDieTime = RemapVal( rand(), 0, RAND_MAX, m_LifetimeMin, m_LifetimeMax ); if( m_DustFlags & DUSTFLAGS_SCALEMOTES ) - pParticle->m_flSize = RemapVal( rand(), 0, VALVE_RAND_MAX, m_flSizeMin/10000.0f, m_flSizeMax/10000.0f ); + pParticle->m_flSize = RemapVal( rand(), 0, RAND_MAX, m_flSizeMin/10000.0f, m_flSizeMax/10000.0f ); else - pParticle->m_flSize = RemapVal( rand(), 0, VALVE_RAND_MAX, m_flSizeMin, m_flSizeMax ); + pParticle->m_flSize = RemapVal( rand(), 0, RAND_MAX, m_flSizeMin, m_flSizeMax ); pParticle->m_Color = m_Color; } diff --git a/game/client/c_func_dust.h b/game/client/c_func_dust.h index 31ff0611f..66d3f7114 100644 --- a/game/client/c_func_dust.h +++ b/game/client/c_func_dust.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // diff --git a/game/client/c_func_lod.cpp b/game/client/c_func_lod.cpp index 766cced3d..cb2d8ea1a 100644 --- a/game/client/c_func_lod.cpp +++ b/game/client/c_func_lod.cpp @@ -1,13 +1,14 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // // $NoKeywords: $ // -//=============================================================================// +//===========================================================================// #include "cbase.h" #include "view.h" #include "iviewrender.h" +#include "clientalphaproperty.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -23,26 +24,25 @@ class C_Func_LOD : public C_BaseEntity // C_BaseEntity overrides. public: - unsigned char GetClientSideFade(); + virtual void OnDataChanged( DataUpdateType_t type ); public: // Replicated vars from the server. // These are documented in the server-side entity. public: - float m_fDisappearDist; + int m_nDisappearMinDist; + int m_nDisappearMaxDist; }; -ConVar lod_TransitionDist("lod_TransitionDist", "800"); - - // ------------------------------------------------------------------------- // // Tables. // ------------------------------------------------------------------------- // // Datatable.. IMPLEMENT_CLIENTCLASS_DT(C_Func_LOD, DT_Func_LOD, CFunc_LOD) - RecvPropFloat(RECVINFO(m_fDisappearDist)), + RecvPropInt(RECVINFO(m_nDisappearMinDist)), + RecvPropInt(RECVINFO(m_nDisappearMaxDist)), END_RECV_TABLE() @@ -53,15 +53,18 @@ END_RECV_TABLE() C_Func_LOD::C_Func_LOD() { - m_fDisappearDist = 5000.0f; + m_nDisappearMinDist = 5000; + m_nDisappearMaxDist = 5800; } -//----------------------------------------------------------------------------- -// Purpose: Calculate a fade. -//----------------------------------------------------------------------------- -unsigned char C_Func_LOD::GetClientSideFade() + +void C_Func_LOD::OnDataChanged( DataUpdateType_t type ) { - return UTIL_ComputeEntityFade( this, m_fDisappearDist, m_fDisappearDist + lod_TransitionDist.GetFloat(), 1.0f ); -} + BaseClass::OnDataChanged( type ); + bool bCreate = (type == DATA_UPDATE_CREATED) ? true : false; + VPhysicsShadowDataChanged(bCreate, this); + // Copy in fade parameters + AlphaProp()->SetFade( 1.0f, m_nDisappearMinDist, m_nDisappearMaxDist ); +} diff --git a/game/client/c_func_movelinear.cpp b/game/client/c_func_movelinear.cpp new file mode 100644 index 000000000..bd8124113 --- /dev/null +++ b/game/client/c_func_movelinear.cpp @@ -0,0 +1,47 @@ +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "c_basedoor.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +// ------------------------------------------------------------------------ +class C_FuncMoveLinear: public C_BaseToggle +{ +public: + DECLARE_CLASS( C_FuncMoveLinear, C_BaseToggle ); + DECLARE_CLIENTCLASS(); + + IMPLEMENT_NETWORK_VAR_FOR_DERIVED( m_vecVelocity ); + IMPLEMENT_NETWORK_VAR_FOR_DERIVED( m_fFlags ); + + C_FuncMoveLinear(); + virtual void OnDataChanged( DataUpdateType_t type ); +}; + + +IMPLEMENT_CLIENTCLASS_DT( C_FuncMoveLinear, DT_FuncMoveLinear, CFuncMoveLinear ) + RecvPropVector( RECVINFO(m_vecVelocity), 0, RecvProxy_LocalVelocity ), + RecvPropInt( RECVINFO( m_fFlags ) ), +END_RECV_TABLE() + + +C_FuncMoveLinear::C_FuncMoveLinear() +{ +} + +void C_FuncMoveLinear::OnDataChanged( DataUpdateType_t type ) +{ + BaseClass::OnDataChanged( type ); + + if ( type == DATA_UPDATE_CREATED ) + { + SetSolid(SOLID_VPHYSICS); + VPhysicsInitShadow( false, false ); + } +} diff --git a/game/client/c_func_occluder.cpp b/game/client/c_func_occluder.cpp index 32d016872..739f3e6fd 100644 --- a/game/client/c_func_occluder.cpp +++ b/game/client/c_func_occluder.cpp @@ -1,10 +1,10 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // // $NoKeywords: $ // -//=============================================================================// +//===========================================================================// #include "cbase.h" // memdbgon must be the last include file in a .cpp file!!! @@ -19,12 +19,12 @@ class C_FuncOccluder : public C_BaseEntity // Overrides. public: virtual bool ShouldDraw(); - virtual int DrawModel( int flags ); + virtual int DrawModel( int flags, const RenderableInstance_t &instance ); virtual void OnDataChanged( DataUpdateType_t updateType ); private: int m_nOccluderIndex; - bool m_bActive = false; + bool m_bActive; }; IMPLEMENT_CLIENTCLASS_DT( C_FuncOccluder, DT_FuncOccluder, CFuncOccluder ) @@ -44,7 +44,7 @@ bool C_FuncOccluder::ShouldDraw() return false; } -int C_FuncOccluder::DrawModel( int flags ) +int C_FuncOccluder::DrawModel( int flags, const RenderableInstance_t &instance ) { Assert(0); return 0; diff --git a/game/client/c_func_reflective_glass.cpp b/game/client/c_func_reflective_glass.cpp index 994d62ba2..7d48d0647 100644 --- a/game/client/c_func_reflective_glass.cpp +++ b/game/client/c_func_reflective_glass.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // @@ -6,14 +6,15 @@ //===========================================================================// #include "cbase.h" #include "view_shared.h" +#include "c_func_brush.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" -class C_FuncReflectiveGlass : public C_BaseEntity +class C_FuncReflectiveGlass : public C_FuncBrush { public: - DECLARE_CLASS( C_FuncReflectiveGlass, C_BaseEntity ); + DECLARE_CLASS( C_FuncReflectiveGlass, C_FuncBrush ); DECLARE_CLIENTCLASS(); // C_BaseEntity. @@ -86,7 +87,7 @@ bool IsReflectiveGlassInView( const CViewSetup& view, cplane_t &plane ) Vector vecMins, vecMaxs; pReflectiveGlass->GetRenderBoundsWorldspace( vecMins, vecMaxs ); - if ( R_CullBox( vecMins, vecMaxs, frustum ) ) + if ( frustum.CullBox( vecMins, vecMaxs ) ) continue; const model_t *pModel = pReflectiveGlass->GetModel(); diff --git a/game/client/c_func_reflective_glass.h b/game/client/c_func_reflective_glass.h index 48e1491ee..69c8ad80e 100644 --- a/game/client/c_func_reflective_glass.h +++ b/game/client/c_func_reflective_glass.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // diff --git a/game/client/c_func_rotating.cpp b/game/client/c_func_rotating.cpp index 9d28bc268..ad834dda2 100644 --- a/game/client/c_func_rotating.cpp +++ b/game/client/c_func_rotating.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // diff --git a/game/client/c_func_smokevolume.cpp b/game/client/c_func_smokevolume.cpp index d976c57be..de15f1a51 100644 --- a/game/client/c_func_smokevolume.cpp +++ b/game/client/c_func_smokevolume.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // @@ -8,6 +8,7 @@ #include "c_smoke_trail.h" #include "smoke_fog_overlay.h" #include "engine/IEngineTrace.h" +#include "view.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -139,6 +140,7 @@ class C_FuncSmokeVolume : public C_BaseParticleEntity, public IPrototypeAppEffec float m_RotationSpeed; float m_MovementSpeed; float m_Density; + float m_maxDrawDistance; int m_spawnflags; private: @@ -163,8 +165,8 @@ class C_FuncSmokeVolume : public C_BaseParticleEntity, public IPrototypeAppEffec }; IMPLEMENT_CLIENTCLASS_DT( C_FuncSmokeVolume, DT_FuncSmokeVolume, CFuncSmokeVolume ) - RecvPropInt( RECVINFO( m_Color1 ), 0, RecvProxy_IntToColor32 ), - RecvPropInt( RECVINFO( m_Color2 ), 0, RecvProxy_IntToColor32 ), + RecvPropInt( RECVINFO( m_Color1 ), 0, RecvProxy_Int32ToColor32 ), + RecvPropInt( RECVINFO( m_Color2 ), 0, RecvProxy_Int32ToColor32 ), RecvPropString( RECVINFO( m_MaterialName ) ), RecvPropFloat( RECVINFO( m_ParticleDrawWidth ) ), RecvPropFloat( RECVINFO( m_ParticleSpacingDistance ) ), @@ -172,6 +174,7 @@ IMPLEMENT_CLIENTCLASS_DT( C_FuncSmokeVolume, DT_FuncSmokeVolume, CFuncSmokeVolum RecvPropFloat( RECVINFO( m_RotationSpeed ) ), RecvPropFloat( RECVINFO( m_MovementSpeed ) ), RecvPropFloat( RECVINFO( m_Density ) ), + RecvPropFloat( RECVINFO( m_maxDrawDistance ) ), RecvPropInt( RECVINFO( m_spawnflags ) ), RecvPropDataTable( RECVINFO_DT( m_Collision ), 0, &REFERENCE_RECV_TABLE(DT_CollisionProperty) ), END_RECV_TABLE() @@ -220,8 +223,8 @@ static inline Vector& EngineGetVecRenderOrigin() static Vector dummy(0,0,0); return dummy; #else - extern Vector g_vecRenderOrigin; - return g_vecRenderOrigin; + extern Vector g_vecRenderOrigin[ MAX_SPLITSCREEN_PLAYERS ]; + return g_vecRenderOrigin[ GET_ACTIVE_SPLITSCREEN_SLOT() ]; #endif } @@ -254,7 +257,7 @@ C_FuncSmokeVolume::C_FuncSmokeVolume() m_vLastAngles.Init(); m_pSmokeParticleInfos = NULL; - m_SpacingRadius = 0.0f; + m_SpacingRadius = 0.0f;; m_ParticleRadius = 0.0f; m_MinColor.Init( 1.0, 1.0, 1.0 ); m_MaxColor.Init( 1.0, 1.0, 1.0 ); @@ -265,8 +268,6 @@ C_FuncSmokeVolume::~C_FuncSmokeVolume() delete [] m_pSmokeParticleInfos; } -static ConVar mat_reduceparticles( "mat_reduceparticles", "0" ); - void C_FuncSmokeVolume::OnDataChanged( DataUpdateType_t updateType ) { m_MinColor[0] = ( 1.0f / 255.0f ) * m_Color1.r; @@ -277,12 +278,6 @@ void C_FuncSmokeVolume::OnDataChanged( DataUpdateType_t updateType ) m_MaxColor[1] = ( 1.0f / 255.0f ) * m_Color2.g; m_MaxColor[2] = ( 1.0f / 255.0f ) * m_Color2.b; - if ( mat_reduceparticles.GetBool() ) - { - m_Density *= 0.5f; - m_ParticleSpacingDistance *= 1.5f; - } - m_ParticleRadius = m_ParticleDrawWidth * 0.5f; m_SpacingRadius = m_ParticleSpacingDistance * 0.5f; @@ -291,7 +286,7 @@ void C_FuncSmokeVolume::OnDataChanged( DataUpdateType_t updateType ) // Warning( "m_Density: %f\n", m_Density ); // Warning( "m_MovementSpeed: %f\n", m_MovementSpeed ); - if( updateType == DATA_UPDATE_CREATED ) + if(updateType == DATA_UPDATE_CREATED) { Vector size = WorldAlignMaxs() - WorldAlignMins(); m_xCount = 0.5f + ( size.x / ( m_SpacingRadius * 2.0f ) ); @@ -343,21 +338,36 @@ void C_FuncSmokeVolume::Update( float fTimeDelta ) m_ParticleEffect.SetBBox( vWorldMins, vWorldMaxs ); } + float minViewOrigingDistance = FLT_MAX; + FOR_EACH_VALID_SPLITSCREEN_PLAYER( hh ) + { + float d = CollisionProp()->CalcDistanceFromPoint( MainViewOrigin(hh) ); + if ( d < minViewOrigingDistance ) + minViewOrigingDistance = d; + } + + + float targetDensity = m_Density; + if ( m_maxDrawDistance > 0 && minViewOrigingDistance > m_maxDrawDistance ) + { + targetDensity = 0.0f; + } + // lerp m_CurrentDensity towards m_Density at a rate of m_DensityRampSpeed - if( m_CurrentDensity < m_Density ) + if( m_CurrentDensity < targetDensity ) { m_CurrentDensity += m_DensityRampSpeed * fTimeDelta; - if( m_CurrentDensity > m_Density ) + if( m_CurrentDensity > targetDensity ) { - m_CurrentDensity = m_Density; + m_CurrentDensity = targetDensity; } } - else if( m_CurrentDensity > m_Density ) + else if( m_CurrentDensity > targetDensity ) { m_CurrentDensity -= m_DensityRampSpeed * fTimeDelta; - if( m_CurrentDensity < m_Density ) + if( m_CurrentDensity < targetDensity ) { - m_CurrentDensity = m_Density; + m_CurrentDensity = targetDensity; } } @@ -525,18 +535,14 @@ void C_FuncSmokeVolume::RenderParticles( CParticleRenderIterator *pIterator ) TransformParticle( ParticleMgr()->GetModelView(), renderPos, tRenderPos ); float sortKey = 1;//tRenderPos.z; - // If we're reducing particle cost, only render sufficiently opaque particles - if ( ( alpha > 0.05f ) || !mat_reduceparticles.GetBool() ) - { - RenderParticle_ColorSizeAngle( - pIterator->GetParticleDraw(), - tRenderPos, - color, - alpha * GetAlphaDistanceFade(tRenderPos, 10, 30), // Alpha - m_ParticleRadius, - pParticle->m_CurRotation - ); - } + RenderParticle_ColorSizeAngle( + pIterator->GetParticleDraw(), + tRenderPos, + color, + alpha * GetAlphaDistanceFade(tRenderPos, 10, 30), // Alpha + m_ParticleRadius, + pParticle->m_CurRotation + ); pParticle = (const SmokeGrenadeParticle*)pIterator->GetNext( sortKey ); } @@ -588,7 +594,7 @@ void C_FuncSmokeVolume::FillVolume() if(pParticle) { pParticle->m_Pos = vPos; - pParticle->m_ColorInterp = (unsigned char)((rand() * 255) / VALVE_RAND_MAX); + pParticle->m_ColorInterp = (unsigned char)((rand() * 255) / RAND_MAX); pParticle->m_RotationFactor = FRand( -1.0f, 1.0f ); // Rotation factor. pParticle->m_CurRotation = FRand( -m_RotationSpeed, m_RotationSpeed ); } diff --git a/game/client/c_func_tracktrain.cpp b/game/client/c_func_tracktrain.cpp index c25c7448b..a55b6eb5d 100644 --- a/game/client/c_func_tracktrain.cpp +++ b/game/client/c_func_tracktrain.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // diff --git a/game/client/c_gameinstructor.cpp b/game/client/c_gameinstructor.cpp new file mode 100644 index 000000000..b65f63752 --- /dev/null +++ b/game/client/c_gameinstructor.cpp @@ -0,0 +1,1342 @@ +//========= Copyright © 1996-2008, Valve Corporation, All rights reserved. ============// +// +// Purpose: Client handler implementations for instruction players how to play +// +//=============================================================================// + +#include "cbase.h" + +#include "c_gameinstructor.h" +#include "c_baselesson.h" +#include "filesystem.h" +#include "vprof.h" +#include "ixboxsystem.h" +#include "tier0/icommandline.h" +#include "iclientmode.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + +PRECACHE_REGISTER_BEGIN( GLOBAL, GameinstructorIcons ) + PRECACHE( KV_DEP_FILE, "scripts/instructor_texturemanifest.txt" ) +PRECACHE_REGISTER_END() + + +#define MOD_DIR "MOD" + +#define GAMEINSTRUCTOR_SCRIPT_FILE "scripts/instructor_lessons.txt" +#define GAMEINSTRUCTOR_MOD_SCRIPT_FILE "scripts/mod_lessons.txt" + + +// Game instructor auto game system instantiation +C_GameInstructor g_GameInstructor[ MAX_SPLITSCREEN_PLAYERS ]; +C_GameInstructor &GetGameInstructor() +{ + ASSERT_LOCAL_PLAYER_RESOLVABLE(); + return g_GameInstructor[ GET_ACTIVE_SPLITSCREEN_SLOT() ]; +} + +ConVar gameinstructor_verbose( "gameinstructor_verbose", "0", FCVAR_CHEAT, "Set to 1 for standard debugging or 2 (in combo with gameinstructor_verbose_lesson) to show update actions." ); +ConVar gameinstructor_verbose_lesson( "gameinstructor_verbose_lesson", "", FCVAR_CHEAT, "Display more verbose information for lessons have this name." ); +ConVar gameinstructor_find_errors( "gameinstructor_find_errors", "0", FCVAR_CHEAT, "Set to 1 and the game instructor will run EVERY scripted command to uncover errors." ); + +void GameInstructorEnable_ChangeCallback( IConVar *var, const char *pOldValue, float flOldValue ); +ConVar gameinstructor_enable( "gameinstructor_enable", "1", FCVAR_CLIENTDLL | FCVAR_ARCHIVE, "Display in game lessons that teach new players.", GameInstructorEnable_ChangeCallback ); +extern ConVar sv_gameinstructor_disable; + + +ConVar gameinstructor_start_sound_cooldown( "gameinstructor_start_sound_cooldown", "4.0", FCVAR_NONE, "Number of seconds forced between similar lesson start sounds." ); + +// Enable or Disable the game instructor based on the client setting +void EnableDisableInstructor( void ) +{ + bool bEnabled = (!sv_gameinstructor_disable.GetBool() && gameinstructor_enable.GetBool()); + + if ( bEnabled ) + { + // Game instructor has been enabled, so init it! + GetGameInstructor().Init(); + } + else + { + // Game instructor has been disabled, so shut it down! + GetGameInstructor().Shutdown(); + } +} + +void GameInstructorEnable_ChangeCallback( IConVar *var, const char *pOldValue, float flOldValue ) +{ + for ( int i = 0 ; i < MAX_SPLITSCREEN_PLAYERS; ++i ) + { + ACTIVE_SPLITSCREEN_PLAYER_GUARD( i ); + if ( ( flOldValue != 0.0f ) != gameinstructor_enable.GetBool() ) + { + EnableDisableInstructor(); + } + } +} + +void SVGameInstructorDisable_ChangeCallback( IConVar *var, const char *pOldValue, float flOldValue ); +ConVar sv_gameinstructor_disable( "sv_gameinstructor_disable", "0", FCVAR_REPLICATED, "Force all clients to disable their game instructors.", SVGameInstructorDisable_ChangeCallback ); +void SVGameInstructorDisable_ChangeCallback( IConVar *var, const char *pOldValue, float flOldValue ) +{ + if ( !engine ) + return; + + for ( int i = 0 ; i < MAX_SPLITSCREEN_PLAYERS; ++i ) + { + ACTIVE_SPLITSCREEN_PLAYER_GUARD( i ); + EnableDisableInstructor(); + } +} + + + + + +// +// C_GameInstructor +// + +bool C_GameInstructor::Init( void ) +{ + // Make sure split slot is up to date + for ( int i = 0 ; i < MAX_SPLITSCREEN_PLAYERS; ++i ) + { + ACTIVE_SPLITSCREEN_PLAYER_GUARD( i ); + if ( &GetGameInstructor() == this ) + { + SetSlot( i ); + break; + } + } + + ACTIVE_SPLITSCREEN_PLAYER_GUARD( m_nSplitScreenSlot ); + + if ( !gameinstructor_enable.GetBool() || sv_gameinstructor_disable.GetBool() ) + { + // Don't init if it's disabled + return true; + } + + if ( gameinstructor_verbose.GetInt() > 0 ) + { + ConColorMsg( CBaseLesson::m_rgbaVerboseHeader, "GAME INSTRUCTOR: " ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "Initializing...\n" ); + } + + m_bNoDraw = false; + m_bHiddenDueToOtherElements = false; + + m_iCurrentPriority = 0; + m_hLastSpectatedPlayer = NULL; + m_bSpectatedPlayerChanged = false; + + m_szPreviousStartSound[ 0 ] = '\0'; + m_fNextStartSoundTime = 0; + + ReadLessonsFromFile( GAMEINSTRUCTOR_MOD_SCRIPT_FILE ); + ReadLessonsFromFile( GAMEINSTRUCTOR_SCRIPT_FILE ); + + InitLessonPrerequisites(); + + ReadSaveData(); + + ListenForGameEvent( "gameinstructor_draw" ); + ListenForGameEvent( "gameinstructor_nodraw" ); + + ListenForGameEvent( "round_end" ); + ListenForGameEvent( "round_start" ); + ListenForGameEvent( "player_death" ); + ListenForGameEvent( "player_team" ); + ListenForGameEvent( "player_disconnect" ); + ListenForGameEvent( "map_transition" ); + ListenForGameEvent( "game_newmap" ); + + + + ListenForGameEvent( "set_instructor_group_enabled" ); + + EvaluateLessonsForGameRules(); + + return true; +} + +void C_GameInstructor::Shutdown( void ) +{ + ACTIVE_SPLITSCREEN_PLAYER_GUARD( m_nSplitScreenSlot ); + + if ( gameinstructor_verbose.GetInt() > 0 ) + { + ConColorMsg( CBaseLesson::m_rgbaVerboseHeader, "GAME INSTRUCTOR: " ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "Shutting down...\n" ); + } + + CloseAllOpenOpportunities(); + + WriteSaveData(); + + // Clear out all the lessons + for ( int i = 0; i < m_Lessons.Count(); ++i ) + { + if ( m_Lessons[ i ] ) + { + m_Lessons[ i ]->StopListeningForAllEvents(); + delete m_Lessons[ i ]; + m_Lessons[ i ] = NULL; + } + } + m_Lessons.RemoveAll(); + + m_LessonGroupConVarToggles.RemoveAll(); + + // Stop listening for events + StopListeningForAllEvents(); +} + +void C_GameInstructor::UpdateHiddenByOtherElements( void ) +{ + bool bHidden = Mod_HiddenByOtherElements(); + + if ( bHidden && !m_bHiddenDueToOtherElements ) + { + StopAllLessons(); + } + + m_bHiddenDueToOtherElements = bHidden; +} + +void C_GameInstructor::Update( float frametime ) +{ + ACTIVE_SPLITSCREEN_PLAYER_GUARD( m_nSplitScreenSlot ); + + VPROF_BUDGET( "C_GameInstructor::Update", "GameInstructor" ); + + UpdateHiddenByOtherElements(); + + if ( !gameinstructor_enable.GetBool() || m_bNoDraw || m_bHiddenDueToOtherElements ) + { + // Don't update if disabled or hidden + return; + } + + if ( gameinstructor_find_errors.GetBool() ) + { + FindErrors(); + + gameinstructor_find_errors.SetValue( 0 ); + } + + if ( IsConsole() ) + { + // On X360 we want to save when they're not connected + if ( !engine->IsInGame() ) + { + // They aren't in game + WriteSaveData(); + } + else + { + const char *levelName = engine->GetLevelName(); + if ( levelName && levelName[0] && engine->IsLevelMainMenuBackground() ) + { + // The are in game, but it's a background map + WriteSaveData(); + } + } + } + + if ( m_bSpectatedPlayerChanged ) + { + // Safe spot to clean out stale lessons if spectator changed + if ( gameinstructor_verbose.GetInt() > 0 ) + { + ConColorMsg( CBaseLesson::m_rgbaVerboseHeader, "GAME INSTRUCTOR: " ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "Spectated player changed...\n" ); + } + + CloseAllOpenOpportunities(); + + m_bSpectatedPlayerChanged = false; + } + + // Loop through all the lesson roots and reset their active status + for ( int i = m_OpenOpportunities.Count() - 1; i >= 0; --i ) + { + CBaseLesson *pLesson = m_OpenOpportunities[ i ]; + CBaseLesson *pRootLesson = pLesson->GetRoot(); + + if ( pRootLesson->InstanceType() == LESSON_INSTANCE_SINGLE_ACTIVE ) + { + pRootLesson->SetInstanceActive( false ); + } + } + + int iCurrentPriority = 0; + + // Loop through all the open lessons + for ( int i = m_OpenOpportunities.Count() - 1; i >= 0; --i ) + { + CBaseLesson *pLesson = m_OpenOpportunities[ i ]; + + if ( !pLesson->IsOpenOpportunity() || pLesson->IsTimedOut() ) + { + // This opportunity has closed + CloseOpportunity( pLesson ); + continue; + } + + // Lesson should be displayed, so it can affect priority + CBaseLesson *pRootLesson = pLesson->GetRoot(); + + bool bShouldDisplay = pLesson->ShouldDisplay(); + bool bIsLocked = pLesson->IsLocked(); + + if ( ( bShouldDisplay || bIsLocked ) && + ( pLesson->GetPriority() >= m_iCurrentPriority || pLesson->NoPriority() || bIsLocked ) && + ( pRootLesson && ( pRootLesson->InstanceType() != LESSON_INSTANCE_SINGLE_ACTIVE || !pRootLesson->IsInstanceActive() ) ) ) + { + // Lesson is at the highest priority level, isn't violating instance rules, and has met all the prerequisites + if ( UpdateActiveLesson( pLesson, pRootLesson ) || pRootLesson->IsLearned() ) + { + // Lesson is active + if ( pLesson->IsVisible() || pRootLesson->IsLearned() ) + { + pRootLesson->SetInstanceActive( true ); + + if ( iCurrentPriority < pLesson->GetPriority() && !pLesson->NoPriority() ) + { + // This active or learned lesson has the highest priority so far + iCurrentPriority = pLesson->GetPriority(); + } + } + } + else + { + // On second thought, this shouldn't have been displayed + bShouldDisplay = false; + } + } + else + { + // Lesson shouldn't be displayed right now + UpdateInactiveLesson( pLesson ); + } + } + + // Set the priority for next frame + if ( gameinstructor_verbose.GetInt() > 1 && m_iCurrentPriority != iCurrentPriority ) + { + ConColorMsg( CBaseLesson::m_rgbaVerboseHeader, "GAME INSTRUCTOR: " ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "Priority changed from " ); + ConColorMsg( CBaseLesson::m_rgbaVerboseClose, "%i ", m_iCurrentPriority ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "to " ); + ConColorMsg( CBaseLesson::m_rgbaVerboseOpen, "%i", iCurrentPriority ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ".\n" ); + } + + m_iCurrentPriority = iCurrentPriority; +} + +void C_GameInstructor::FireGameEvent( IGameEvent *event ) +{ + ACTIVE_SPLITSCREEN_PLAYER_GUARD( m_nSplitScreenSlot ); + + VPROF_BUDGET( "C_GameInstructor::FireGameEvent", "GameInstructor" ); + + const char *name = event->GetName(); + + if ( Q_strcmp( name, "gameinstructor_draw" ) == 0 ) + { + if ( m_bNoDraw ) + { + if ( gameinstructor_verbose.GetInt() > 0 ) + { + ConColorMsg( CBaseLesson::m_rgbaVerboseHeader, "GAME INSTRUCTOR: " ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "Set to draw...\n" ); + } + + m_bNoDraw = false; + } + } + else if ( Q_strcmp( name, "gameinstructor_nodraw" ) == 0 ) + { + if ( !m_bNoDraw ) + { + if ( gameinstructor_verbose.GetInt() > 0 ) + { + ConColorMsg( CBaseLesson::m_rgbaVerboseHeader, "GAME INSTRUCTOR: " ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "Set to not draw...\n" ); + } + + m_bNoDraw = true; + StopAllLessons(); + } + } + else if ( Q_strcmp( name, "round_end" ) == 0 ) + { + if ( gameinstructor_verbose.GetInt() > 0 ) + { + ConColorMsg( CBaseLesson::m_rgbaVerboseHeader, "GAME INSTRUCTOR: " ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "Round ended...\n" ); + } + + CloseAllOpenOpportunities(); + + if ( IsPC() ) + { + // Good place to backup our counts + WriteSaveData(); + } + } + else if ( Q_strcmp( name, "round_start" ) == 0 ) + { + if ( gameinstructor_verbose.GetInt() > 0 ) + { + ConColorMsg( CBaseLesson::m_rgbaVerboseHeader, "GAME INSTRUCTOR: " ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "Round started...\n" ); + } + + CloseAllOpenOpportunities(); + + EvaluateLessonsForGameRules(); + } + else if ( Q_strcmp( name, "player_death" ) == 0 ) + { +#if !defined(NO_STEAM) && defined(USE_CEG) + Steamworks_TestSecret(); + Steamworks_SelfCheck(); +#endif + C_BasePlayer *pLocalPlayer = GetLocalPlayer(); + if ( pLocalPlayer && pLocalPlayer == UTIL_PlayerByUserId( event->GetInt( "userid" ) ) ) + { + if ( gameinstructor_verbose.GetInt() > 0 ) + { + ConColorMsg( CBaseLesson::m_rgbaVerboseHeader, "GAME INSTRUCTOR: " ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "Local player died...\n" ); + } + + for ( int i = m_OpenOpportunities.Count() - 1; i >= 0; --i ) + { + CBaseLesson *pLesson = m_OpenOpportunities[ i ]; + CBaseLesson *pRootLesson = pLesson->GetRoot(); + if ( !pRootLesson->CanOpenWhenDead() ) + { + CloseOpportunity( pLesson ); + } + } + } + } + else if ( Q_strcmp( name, "player_team" ) == 0 ) + { + C_BasePlayer *pLocalPlayer = GetLocalPlayer(); + if ( pLocalPlayer && pLocalPlayer == UTIL_PlayerByUserId( event->GetInt( "userid" ) ) && + ( event->GetInt( "team" ) != event->GetInt( "oldteam" ) || event->GetBool( "disconnect" ) ) ) + { + if ( gameinstructor_verbose.GetInt() > 0 ) + { + ConColorMsg( CBaseLesson::m_rgbaVerboseHeader, "GAME INSTRUCTOR: " ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "Local player changed team (or disconnected)...\n" ); + } + + CloseAllOpenOpportunities(); + } + + EvaluateLessonsForGameRules(); + } + else if ( Q_strcmp( name, "player_disconnect" ) == 0 ) + { + C_BasePlayer *pLocalPlayer = GetLocalPlayer(); + if ( pLocalPlayer && pLocalPlayer == UTIL_PlayerByUserId( event->GetInt( "userid" ) ) ) + { + if ( gameinstructor_verbose.GetInt() > 0 ) + { + ConColorMsg( CBaseLesson::m_rgbaVerboseHeader, "GAME INSTRUCTOR: " ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "Local player disconnected...\n" ); + } + + CloseAllOpenOpportunities(); + } + } + else if ( Q_strcmp( name, "map_transition" ) == 0 ) + { + if ( gameinstructor_verbose.GetInt() > 0 ) + { + ConColorMsg( CBaseLesson::m_rgbaVerboseHeader, "GAME INSTRUCTOR: " ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "Map transition...\n" ); + } + + CloseAllOpenOpportunities(); + + if ( m_bNoDraw ) + { + if ( gameinstructor_verbose.GetInt() > 0 ) + { + ConColorMsg( Color( 255, 128, 64, 255 ), "GAME INSTRUCTOR: " ); + ConColorMsg( Color( 64, 128, 255, 255 ), "Set to draw...\n" ); + } + + m_bNoDraw = false; + } + + if ( IsPC() ) + { + // Good place to backup our counts + WriteSaveData(); + } + } + else if ( Q_strcmp( name, "game_newmap" ) == 0 ) + { + if ( gameinstructor_verbose.GetInt() > 0 ) + { + ConColorMsg( CBaseLesson::m_rgbaVerboseHeader, "GAME INSTRUCTOR: " ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "New map...\n" ); + } + + CloseAllOpenOpportunities(); + + if ( m_bNoDraw ) + { + if ( gameinstructor_verbose.GetInt() > 0 ) + { + ConColorMsg( Color( 255, 128, 64, 255 ), "GAME INSTRUCTOR: " ); + ConColorMsg( Color( 64, 128, 255, 255 ), "Set to draw...\n" ); + } + + m_bNoDraw = false; + } + + if ( IsPC() ) + { + // Good place to backup our counts + WriteSaveData(); + } + } + + else if ( Q_strcmp( name, "set_instructor_group_enabled" ) == 0 ) + { + const char *pszGroup = event->GetString( "group" ); + bool bEnabled = event->GetInt( "enabled" ) != 0; + + if ( pszGroup && pszGroup[0] ) + { + SetLessonGroupEnabled( pszGroup, bEnabled ); + } + } +} + +void C_GameInstructor::DefineLesson( CBaseLesson *pLesson ) +{ + ACTIVE_SPLITSCREEN_PLAYER_GUARD( m_nSplitScreenSlot ); + + if ( gameinstructor_verbose.GetInt() > 0 ) + { + ConColorMsg( CBaseLesson::m_rgbaVerboseHeader, "GAME INSTRUCTOR: " ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "Lesson " ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "\"%s\" ", pLesson->GetName() ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "defined.\n" ); + } + + m_Lessons.AddToTail( pLesson ); +} + +const CBaseLesson * C_GameInstructor::GetLesson( const char *pchLessonName ) +{ + ACTIVE_SPLITSCREEN_PLAYER_GUARD( m_nSplitScreenSlot ); + return GetLesson_Internal( pchLessonName ); +} + +bool C_GameInstructor::IsLessonOfSameTypeOpen( const CBaseLesson *pLesson ) const +{ + for ( int i = 0; i < m_OpenOpportunities.Count(); ++i ) + { + CBaseLesson *pOpenOpportunity = m_OpenOpportunities[ i ]; + + if ( pOpenOpportunity->GetNameSymbol() == pLesson->GetNameSymbol() ) + { + return true; + } + } + + return false; +} + +bool C_GameInstructor::ReadSaveData( void ) +{ + // for external playtests, don't ever read in persisted instructor state, always start fresh + if( CommandLine()->FindParm( "-playtest" ) ) + return true; + + if ( m_bHasLoadedSaveData ) + return true; + + // Always reset state first in case storage device + // was declined or ends up in faulty state + ResetDisplaysAndSuccesses(); + + m_bHasLoadedSaveData = true; + +#ifdef _X360 + DevMsg( "Read Game Instructor for splitscreen slot %d\n", m_nSplitScreenSlot ); + + if ( m_nSplitScreenSlot < 0 ) + return false; + + if ( m_nSplitScreenSlot >= (int) XBX_GetNumGameUsers() ) + return false; + + int iController = XBX_GetUserId( m_nSplitScreenSlot ); + + if ( iController < 0 || XBX_GetUserIsGuest( iController ) ) + { + // Can't read data for guests + return false; + } + + DWORD nStorageDevice = XBX_GetStorageDeviceId( iController ); + if ( !XBX_DescribeStorageDevice( nStorageDevice ) ) + return false; +#endif + + char szFilename[_MAX_PATH]; + +#ifdef _X360 + if ( IsX360() ) + { + XBX_MakeStorageContainerRoot( iController, XBX_USER_SETTINGS_CONTAINER_DRIVE, szFilename, sizeof( szFilename ) ); + int nLen = strlen( szFilename ); + Q_snprintf( szFilename + nLen, sizeof( szFilename ) - nLen, ":\\game_instructor_counts.txt" ); + } + else +#endif + { + Q_snprintf( szFilename, sizeof( szFilename ), "save/game_instructor_counts.txt" ); + } + + KeyValues *data = new KeyValues( "Game Instructor Counts" ); + KeyValues::AutoDelete autoDelete(data); + + if ( data->LoadFromFile( g_pFullFileSystem, szFilename, NULL ) ) + { + int nVersion = 0; + + for ( KeyValues *pKey = data->GetFirstSubKey(); pKey; pKey = pKey->GetNextTrueSubKey() ) + { + CBaseLesson *pLesson = GetLesson_Internal( pKey->GetName() ); + + if ( pLesson ) + { + pLesson->SetDisplayCount( pKey->GetInt( "display", 0 ) ); + pLesson->SetSuccessCount( pKey->GetInt( "success", 0 ) ); + + if ( Q_strcmp( pKey->GetName(), "version number" ) == 0 ) + { + nVersion = pLesson->GetSuccessCount(); + } + } + } + + CBaseLesson *pLessonVersionNumber = GetLesson_Internal( "version number" ); + if ( pLessonVersionNumber && !pLessonVersionNumber->IsLearned() ) + { + ResetDisplaysAndSuccesses(); + pLessonVersionNumber->SetSuccessCount( pLessonVersionNumber->GetSuccessLimit() ); + m_bDirtySaveData = true; + } + + + return true; + } + + // Couldn't read from the file + return false; +} + +bool C_GameInstructor::WriteSaveData( void ) +{ + if ( engine->IsPlayingDemo() ) + return false; + + if ( !m_bDirtySaveData ) + return true; + +#ifdef _X360 + float flPlatTime = Plat_FloatTime(); + + static ConVarRef host_write_last_time( "host_write_last_time" ); + if ( host_write_last_time.IsValid() ) + { + float flTimeSinceLastWrite = flPlatTime - host_write_last_time.GetFloat(); + if ( flTimeSinceLastWrite < 3.5f ) + { + // Prevent writing to the same storage device twice in less than 3 second succession for TCR success! + // This happens after leaving a game in splitscreen. + //DevMsg( "Waiting to write Game Instructor for splitscreen slot %d... (%.1f seconds remain)\n", m_nSplitScreenSlot, 3.5f - flTimeSinceLastWrite ); + return false; + } + } +#endif + + // Always mark as clean state to avoid re-entry on + // subsequent frames when storage device might be + // in a yet-unmounted state. + m_bDirtySaveData = false; + +#ifdef _X360 + DevMsg( "Write Game Instructor for splitscreen slot %d at time: %.1f\n", m_nSplitScreenSlot, flPlatTime ); + + if ( m_nSplitScreenSlot < 0 ) + return false; + + if ( m_nSplitScreenSlot >= (int) XBX_GetNumGameUsers() ) + return false; + + int iController = XBX_GetUserId( m_nSplitScreenSlot ); + + if ( iController < 0 || XBX_GetUserIsGuest( iController ) ) + { + // Can't save data for guests + return false; + } + + DWORD nStorageDevice = XBX_GetStorageDeviceId( iController ); + if ( !XBX_DescribeStorageDevice( nStorageDevice ) ) + return false; +#endif + + // Build key value data to save + KeyValues *data = new KeyValues( "Game Instructor Counts" ); + KeyValues::AutoDelete autoDelete(data); + + for ( int i = 0; i < m_Lessons.Count();++i ) + { + CBaseLesson *pLesson = m_Lessons[ i ]; + + int iDisplayCount = pLesson->GetDisplayCount(); + int iSuccessCount = pLesson->GetSuccessCount(); + + if ( iDisplayCount || iSuccessCount ) + { + // We've got some data worth saving + KeyValues *pKVData = new KeyValues( pLesson->GetName() ); + + if ( iDisplayCount ) + { + pKVData->SetInt( "display", iDisplayCount ); + } + + if ( iSuccessCount ) + { + pKVData->SetInt( "success", iSuccessCount ); + } + + data->AddSubKey( pKVData ); + } + } + + // Save it! + CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER ); + + data->RecursiveSaveToFile( buf, 0 ); + + char szFilename[_MAX_PATH]; + +#ifdef _X360 + if ( IsX360() ) + { + XBX_MakeStorageContainerRoot( iController, XBX_USER_SETTINGS_CONTAINER_DRIVE, szFilename, sizeof( szFilename ) ); + int nLen = strlen( szFilename ); + Q_snprintf( szFilename + nLen, sizeof( szFilename ) - nLen, ":\\game_instructor_counts.txt" ); + } + else +#endif + { + Q_snprintf( szFilename, sizeof( szFilename ), "save/game_instructor_counts.txt" ); + filesystem->CreateDirHierarchy( "save", "MOD" ); + } + + bool bWriteSuccess = filesystem->WriteFile( szFilename, MOD_DIR, buf ); + +#ifdef _X360 + if ( xboxsystem ) + { + xboxsystem->FinishContainerWrites( iController ); + } +#endif + + return bWriteSuccess; +} + +void C_GameInstructor::RefreshDisplaysAndSuccesses( void ) +{ + m_bHasLoadedSaveData = false; + ReadSaveData(); +} + +void C_GameInstructor::ResetDisplaysAndSuccesses( void ) +{ + ACTIVE_SPLITSCREEN_PLAYER_GUARD( m_nSplitScreenSlot ); + if ( gameinstructor_verbose.GetInt() > 0 ) + { + ConColorMsg( CBaseLesson::m_rgbaVerboseHeader, "GAME INSTRUCTOR: " ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "Reset all lesson display and success counts.\n" ); + } + + for ( int i = 0; i < m_Lessons.Count(); ++i ) + { + m_Lessons[ i ]->ResetDisplaysAndSuccesses(); + } + + m_bDirtySaveData = false; +} + +void C_GameInstructor::MarkDisplayed( const char *pchLessonName ) +{ + ACTIVE_SPLITSCREEN_PLAYER_GUARD( m_nSplitScreenSlot ); + CBaseLesson *pLesson = GetLesson_Internal( pchLessonName ); + if ( !pLesson ) + return; + + if ( gameinstructor_verbose.GetInt() > 0 ) + { + ConColorMsg( CBaseLesson::m_rgbaVerboseHeader, "GAME INSTRUCTOR: " ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "Lesson " ); + ConColorMsg( CBaseLesson::m_rgbaVerboseOpen, "\"%s\" ", pLesson->GetName() ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "marked as displayed.\n" ); + } + + if ( pLesson->IncDisplayCount() ) + { + m_bDirtySaveData = true; + } +} + +void C_GameInstructor::MarkSucceeded( const char *pchLessonName ) +{ + ACTIVE_SPLITSCREEN_PLAYER_GUARD( m_nSplitScreenSlot ); + CBaseLesson *pLesson = GetLesson_Internal( pchLessonName ); + if ( !pLesson ) + return; + + if ( gameinstructor_verbose.GetInt() > 0 ) + { + ConColorMsg( CBaseLesson::m_rgbaVerboseHeader, "GAME INSTRUCTOR: " ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "Lesson " ); + ConColorMsg( CBaseLesson::m_rgbaVerboseSuccess, "\"%s\" ", pLesson->GetName() ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "marked as succeeded.\n" ); + } + + if ( pLesson->IncSuccessCount() ) + { + m_bDirtySaveData = true; + } +} + +void C_GameInstructor::PlaySound( const char *pchSoundName ) +{ + // emit alert sound + C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer(); + if ( pLocalPlayer ) + { + // Local player exists + if ( pchSoundName[ 0 ] != '\0' && Q_strcmp( m_szPreviousStartSound, pchSoundName ) != 0 ) + { + Q_strcpy( m_szPreviousStartSound, pchSoundName ); + m_fNextStartSoundTime = 0.0f; + } + + if ( gpGlobals->curtime >= m_fNextStartSoundTime && pchSoundName[ 0 ] != '\0' ) + { + // A sound was specified, so play it! + pLocalPlayer->EmitSound( pchSoundName ); + m_fNextStartSoundTime = gpGlobals->curtime + gameinstructor_start_sound_cooldown.GetFloat(); + } + } +} + +bool C_GameInstructor::OpenOpportunity( CBaseLesson *pLesson ) +{ + ACTIVE_SPLITSCREEN_PLAYER_GUARD( m_nSplitScreenSlot ); + // Get the root lesson + CBaseLesson *pRootLesson = pLesson->GetRoot(); + if ( !pRootLesson ) + { + if ( gameinstructor_verbose.GetInt() > 0 ) + { + ConColorMsg( CBaseLesson::m_rgbaVerboseHeader, "GAME INSTRUCTOR: " ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "Opportunity " ); + ConColorMsg( CBaseLesson::m_rgbaVerboseClose, "\"%s\" ", pLesson->GetName() ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "NOT opened (because root lesson could not be found).\n" ); + } + + delete pLesson; + return false; + } + + C_BasePlayer *pLocalPlayer = GetLocalPlayer(); + if ( !pRootLesson->CanOpenWhenDead() && ( !pLocalPlayer || !pLocalPlayer->IsAlive() ) ) + { + // If the player is dead don't allow lessons that can't be opened when dead + if ( gameinstructor_verbose.GetInt() > 0 ) + { + ConColorMsg( CBaseLesson::m_rgbaVerboseHeader, "GAME INSTRUCTOR: " ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "Opportunity " ); + ConColorMsg( CBaseLesson::m_rgbaVerboseClose, "\"%s\" ", pLesson->GetName() ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "NOT opened (because player is dead and can_open_when_dead not set).\n" ); + } + + delete pLesson; + return false; + } + + if ( !pRootLesson->PrerequisitesHaveBeenMet() ) + { + // If the prereqs haven't been met, don't open it + if ( gameinstructor_verbose.GetInt() > 0 ) + { + ConColorMsg( CBaseLesson::m_rgbaVerboseHeader, "GAME INSTRUCTOR: " ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "Opportunity " ); + ConColorMsg( CBaseLesson::m_rgbaVerboseClose, "\"%s\" ", pLesson->GetName() ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "NOT opened (because prereqs haven't been met).\n" ); + } + + delete pLesson; + return false; + } + + if ( pRootLesson->InstanceType() == LESSON_INSTANCE_FIXED_REPLACE ) + { + CBaseLesson *pLessonToReplace = NULL; + CBaseLesson *pLastReplacableLesson = NULL; + + int iInstanceCount = 0; + + // Check how many are already open + for ( int i = m_OpenOpportunities.Count() - 1; i >= 0; --i ) + { + CBaseLesson *pOpenOpportunity = m_OpenOpportunities[ i ]; + + if ( pOpenOpportunity->GetNameSymbol() == pLesson->GetNameSymbol() && + pOpenOpportunity->GetReplaceKeySymbol() == pLesson->GetReplaceKeySymbol() ) + { + iInstanceCount++; + + if ( pRootLesson->ShouldReplaceOnlyWhenStopped() ) + { + if ( !pOpenOpportunity->IsInstructing() ) + { + pLastReplacableLesson = pOpenOpportunity; + } + } + else + { + pLastReplacableLesson = pOpenOpportunity; + } + + if ( iInstanceCount >= pRootLesson->GetFixedInstancesMax() ) + { + pLessonToReplace = pLastReplacableLesson; + break; + } + } + } + + if ( pLessonToReplace ) + { + // Take the place of the previous instance + if ( gameinstructor_verbose.GetInt() > 0 ) + { + ConColorMsg( CBaseLesson::m_rgbaVerboseHeader, "GAME INSTRUCTOR: " ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "Opportunity " ); + ConColorMsg( CBaseLesson::m_rgbaVerboseOpen, "\"%s\" ", pLesson->GetName() ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "replacing open lesson of same type.\n" ); + } + + pLesson->TakePlaceOf( pLessonToReplace ); + CloseOpportunity( pLessonToReplace ); + } + else if ( iInstanceCount >= pRootLesson->GetFixedInstancesMax() ) + { + // Don't add another lesson of this type + if ( gameinstructor_verbose.GetInt() > 0 ) + { + ConColorMsg( CBaseLesson::m_rgbaVerboseHeader, "GAME INSTRUCTOR: " ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "Opportunity " ); + ConColorMsg( CBaseLesson::m_rgbaVerboseClose, "\"%s\" ", pLesson->GetName() ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "NOT opened (there is too many started lessons of this type).\n" ); + } + + delete pLesson; + return false; + } + } + + if ( gameinstructor_verbose.GetInt() > 0 ) + { + ConColorMsg( CBaseLesson::m_rgbaVerboseHeader, "GAME INSTRUCTOR: " ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "Opportunity " ); + ConColorMsg( CBaseLesson::m_rgbaVerboseOpen, "\"%s\" ", pLesson->GetName() ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "opened.\n" ); + } + + m_OpenOpportunities.AddToTail( pLesson ); + + return true; +} + +void C_GameInstructor::DumpOpenOpportunities( void ) +{ + ConColorMsg( CBaseLesson::m_rgbaVerboseHeader, "GAME INSTRUCTOR: " ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "Open lessons...\n" ); + + for ( int i = m_OpenOpportunities.Count() - 1; i >= 0; --i ) + { + CBaseLesson *pLesson = m_OpenOpportunities[ i ]; + CBaseLesson *pRootLesson = pLesson->GetRoot(); + + Color color; + + if ( pLesson->IsInstructing() ) + { + // Green + color = CBaseLesson::m_rgbaVerboseOpen; + } + else if ( pRootLesson->IsLearned() && pLesson->GetPriority() >= m_iCurrentPriority ) + { + // Yellow + color = CBaseLesson::m_rgbaVerboseSuccess; + } + else + { + // Red + color = CBaseLesson::m_rgbaVerboseClose; + } + + ConColorMsg( color, "\t%s\n", pLesson->GetName() ); + } +} + +KeyValues * C_GameInstructor::GetScriptKeys( void ) +{ + return m_pScriptKeys; +} + +C_BasePlayer * C_GameInstructor::GetLocalPlayer( void ) +{ + C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer(); + + // If we're not a developer, don't do the special spectator hook ups + if ( !developer.GetBool() ) + return pLocalPlayer; + + // If there is no local player and we're not spectating, just return that + if ( !pLocalPlayer || pLocalPlayer->GetTeamNumber() != TEAM_SPECTATOR ) + return pLocalPlayer; + + // We're purely a spectator let's get lessons of the person we're spectating + C_BasePlayer *pSpectatedPlayer = NULL; + + if ( pLocalPlayer->GetObserverMode() == OBS_MODE_IN_EYE || pLocalPlayer->GetObserverMode() == OBS_MODE_CHASE ) + { + pSpectatedPlayer = ToBasePlayer( pLocalPlayer->GetObserverTarget() ); + } + + if ( m_hLastSpectatedPlayer != pSpectatedPlayer ) + { + // We're spectating someone new! Close all the stale lessons! + m_bSpectatedPlayerChanged = true; + m_hLastSpectatedPlayer = pSpectatedPlayer; + } + + return pSpectatedPlayer; +} + +void C_GameInstructor::EvaluateLessonsForGameRules( void ) +{ + // Enable everything by default + for ( int i = 0; i < m_Lessons.Count(); ++i ) + { + m_Lessons[ i ]->SetEnabled( true ); + } + + // Then see if we should disable anything + for ( int nConVar = 0; nConVar < m_LessonGroupConVarToggles.Count(); ++nConVar ) + { + LessonGroupConVarToggle_t *pLessonGroupConVarToggle = &(m_LessonGroupConVarToggles[ nConVar ]); + if ( pLessonGroupConVarToggle->var.IsValid() ) + { + if ( pLessonGroupConVarToggle->var.GetBool() ) + { + SetLessonGroupEnabled( pLessonGroupConVarToggle->szLessonGroupName, false ); + } + } + } +} + +void C_GameInstructor::SetLessonGroupEnabled( const char *pszGroup, bool bEnabled ) +{ + for ( int i = 0; i < m_Lessons.Count(); ++i ) + { + if ( !Q_stricmp(pszGroup, m_Lessons[i]->GetGroup()) ) + { + m_Lessons[ i ]->SetEnabled( bEnabled ); + } + } +} + +void C_GameInstructor::FindErrors( void ) +{ + // Loop through all the lesson and run all their scripted actions + for ( int i = 0; i < m_Lessons.Count(); ++i ) + { + CScriptedIconLesson *pLesson = dynamic_cast( m_Lessons[ i ] ); + if ( pLesson ) + { + // Process all open events + for ( int iLessonEvent = 0; iLessonEvent < pLesson->GetOpenEvents().Count(); ++iLessonEvent ) + { + const LessonEvent_t *pLessonEvent = &(pLesson->GetOpenEvents()[ iLessonEvent ]); + pLesson->ProcessElements( NULL, &(pLessonEvent->elements) ); + } + + // Process all close events + for ( int iLessonEvent = 0; iLessonEvent < pLesson->GetCloseEvents().Count(); ++iLessonEvent ) + { + const LessonEvent_t *pLessonEvent = &(pLesson->GetCloseEvents()[ iLessonEvent ]); + pLesson->ProcessElements( NULL, &(pLessonEvent->elements) ); + } + + // Process all success events + for ( int iLessonEvent = 0; iLessonEvent < pLesson->GetSuccessEvents().Count(); ++iLessonEvent ) + { + const LessonEvent_t *pLessonEvent = &(pLesson->GetSuccessEvents()[ iLessonEvent ]); + pLesson->ProcessElements( NULL, &(pLessonEvent->elements) ); + } + + // Process all on open events + for ( int iLessonEvent = 0; iLessonEvent < pLesson->GetOnOpenEvents().Count(); ++iLessonEvent ) + { + const LessonEvent_t *pLessonEvent = &(pLesson->GetOnOpenEvents()[ iLessonEvent ]); + pLesson->ProcessElements( NULL, &(pLessonEvent->elements) ); + } + + // Process all update events + for ( int iLessonEvent = 0; iLessonEvent < pLesson->GetUpdateEvents().Count(); ++iLessonEvent ) + { + const LessonEvent_t *pLessonEvent = &(pLesson->GetUpdateEvents()[ iLessonEvent ]); + pLesson->ProcessElements( NULL, &(pLessonEvent->elements) ); + } + } + } +} + +bool C_GameInstructor::UpdateActiveLesson( CBaseLesson *pLesson, const CBaseLesson *pRootLesson ) +{ + ACTIVE_SPLITSCREEN_PLAYER_GUARD( m_nSplitScreenSlot ); + + VPROF_BUDGET( "C_GameInstructor::UpdateActiveLesson", "GameInstructor" ); + + bool bIsOpen = pLesson->IsInstructing(); + + if ( !bIsOpen && !pRootLesson->IsLearned() ) + { + pLesson->SetStartTime(); + pLesson->Start(); + + // Check to see if it successfully started + bIsOpen = ( pLesson->IsOpenOpportunity() && pLesson->ShouldDisplay() ); + + if ( bIsOpen ) + { + // Lesson hasn't been started and hasn't been learned + if ( gameinstructor_verbose.GetInt() > 0 ) + { + ConColorMsg( CBaseLesson::m_rgbaVerboseHeader, "GAME INSTRUCTOR: " ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "Started lesson " ); + ConColorMsg( CBaseLesson::m_rgbaVerboseOpen, "\"%s\"", pLesson->GetName() ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ".\n" ); + } + } + else + { + pLesson->Stop(); + pLesson->ResetStartTime(); + } + } + + if ( bIsOpen ) + { + // Update the running lesson + pLesson->Update(); + return true; + } + else + { + pLesson->UpdateInactive(); + return false; + } +} + +void C_GameInstructor::UpdateInactiveLesson( CBaseLesson *pLesson ) +{ + ACTIVE_SPLITSCREEN_PLAYER_GUARD( m_nSplitScreenSlot ); + + VPROF_BUDGET( "C_GameInstructor::UpdateInactiveLesson", "GameInstructor" ); + + if ( pLesson->IsInstructing() ) + { + // Lesson hasn't been stopped + if ( gameinstructor_verbose.GetInt() > 0 ) + { + ConColorMsg( CBaseLesson::m_rgbaVerboseHeader, "GAME INSTRUCTOR: " ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "Stopped lesson " ); + ConColorMsg( CBaseLesson::m_rgbaVerboseClose, "\"%s\"", pLesson->GetName() ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ".\n" ); + } + + pLesson->Stop(); + pLesson->ResetStartTime(); + } + + pLesson->UpdateInactive(); +} + +CBaseLesson * C_GameInstructor::GetLesson_Internal( const char *pchLessonName ) +{ + for ( int i = 0; i < m_Lessons.Count(); ++i ) + { + CBaseLesson *pLesson = m_Lessons[ i ]; + + if ( Q_strcmp( pLesson->GetName(), pchLessonName ) == 0 ) + { + return pLesson; + } + } + + return NULL; +} + +void C_GameInstructor::StopAllLessons( void ) +{ + ACTIVE_SPLITSCREEN_PLAYER_GUARD( m_nSplitScreenSlot ); + // Stop all the current lessons + for ( int i = m_OpenOpportunities.Count() - 1; i >= 0; --i ) + { + CBaseLesson *pLesson = m_OpenOpportunities[ i ]; + UpdateInactiveLesson( pLesson ); + } +} + +void C_GameInstructor::CloseAllOpenOpportunities( void ) +{ + ACTIVE_SPLITSCREEN_PLAYER_GUARD( m_nSplitScreenSlot ); + // Clear out all the open opportunities + for ( int i = m_OpenOpportunities.Count() - 1; i >= 0; --i ) + { + CBaseLesson *pLesson = m_OpenOpportunities[ i ]; + CloseOpportunity( pLesson ); + } + + Assert( m_OpenOpportunities.Count() == 0 ); +} + +void C_GameInstructor::CloseOpportunity( CBaseLesson *pLesson ) +{ + ACTIVE_SPLITSCREEN_PLAYER_GUARD( m_nSplitScreenSlot ); + UpdateInactiveLesson( pLesson ); + + if ( pLesson->WasDisplayed() ) + { + MarkDisplayed( pLesson->GetName() ); + } + + if ( gameinstructor_verbose.GetInt() > 0 ) + { + ConColorMsg( CBaseLesson::m_rgbaVerboseHeader, "GAME INSTRUCTOR: " ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "Opportunity " ); + ConColorMsg( CBaseLesson::m_rgbaVerboseClose, "\"%s\" ", pLesson->GetName() ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "closed for reason: " ); + ConColorMsg( CBaseLesson::m_rgbaVerboseClose, "%s\n", pLesson->GetCloseReason() ); + } + + pLesson->StopListeningForAllEvents(); + + m_OpenOpportunities.FindAndRemove( pLesson ); + delete pLesson; +} + +void C_GameInstructor::ReadLessonsFromFile( const char *pchFileName ) +{ + // Static init function + CScriptedIconLesson::PreReadLessonsFromFile(); + + MEM_ALLOC_CREDIT(); + + ACTIVE_SPLITSCREEN_PLAYER_GUARD( m_nSplitScreenSlot ); + KeyValues *pLessonKeys = new KeyValues( "instructor_lessons" ); + KeyValues::AutoDelete autoDelete(pLessonKeys); + pLessonKeys->LoadFromFile( g_pFullFileSystem, pchFileName, NULL ); + + for ( m_pScriptKeys = pLessonKeys->GetFirstTrueSubKey(); m_pScriptKeys; m_pScriptKeys = m_pScriptKeys->GetNextTrueSubKey() ) + { + if ( Q_stricmp( m_pScriptKeys->GetName(), "GroupConVarToggle" ) == 0 ) + { + // Add convar group toggler to the list + int nLessonGroupConVarToggle = m_LessonGroupConVarToggles.AddToTail( LessonGroupConVarToggle_t( m_pScriptKeys->GetString( "convar" ) ) ); + LessonGroupConVarToggle_t *pLessonGroupConVarToggle = &(m_LessonGroupConVarToggles[ nLessonGroupConVarToggle ]); + Q_strcpy( pLessonGroupConVarToggle->szLessonGroupName, m_pScriptKeys->GetString( "group" ) ); + + continue; + } + + // Ensure that lessons aren't added twice + if ( GetLesson_Internal( m_pScriptKeys->GetName() ) ) + { + DevWarning( "Lesson \"%s\" defined twice!\n", m_pScriptKeys->GetName() ); + continue; + } + + CScriptedIconLesson *pNewLesson = new CScriptedIconLesson( m_pScriptKeys->GetName(), false, false, m_nSplitScreenSlot ); + GetGameInstructor().DefineLesson( pNewLesson ); + } + + m_pScriptKeys = NULL; +} + +void C_GameInstructor::InitLessonPrerequisites( void ) +{ + for ( int i = 0; i < m_Lessons.Count(); ++i ) + { + m_Lessons[ i ]->InitPrerequisites(); + } +} + + +CON_COMMAND_F( gameinstructor_reload_lessons, "Shuts down all open lessons and reloads them from the script file.", FCVAR_CHEAT ) +{ + for ( int i = 0 ; i < MAX_SPLITSCREEN_PLAYERS; ++i ) + { + ACTIVE_SPLITSCREEN_PLAYER_GUARD( i ); + GetGameInstructor().Shutdown(); + GetGameInstructor().Init(); + } +} + +CON_COMMAND_F( gameinstructor_reset_counts, "Resets all display and success counts to zero.", FCVAR_NONE ) +{ + for ( int i = 0 ; i < MAX_SPLITSCREEN_PLAYERS; ++i ) + { + ACTIVE_SPLITSCREEN_PLAYER_GUARD( i ); + GetGameInstructor().ResetDisplaysAndSuccesses(); + } +} + +CON_COMMAND_F( gameinstructor_dump_open_lessons, "Gives a list of all currently open lessons.", FCVAR_CHEAT ) +{ + for ( int i = 0 ; i < MAX_SPLITSCREEN_PLAYERS; ++i ) + { + ACTIVE_SPLITSCREEN_PLAYER_GUARD( i ); + GetGameInstructor().DumpOpenOpportunities(); + } +} diff --git a/game/client/c_gameinstructor.h b/game/client/c_gameinstructor.h new file mode 100644 index 000000000..69b847299 --- /dev/null +++ b/game/client/c_gameinstructor.h @@ -0,0 +1,121 @@ +//========= Copyright © 1996-2008, Valve Corporation, All rights reserved. ============// +// +// Purpose: Client handler for instruction players how to play +// +//=============================================================================// + +#ifndef _C_GAMEINSTRUCTOR_H_ +#define _C_GAMEINSTRUCTOR_H_ + + +#include "GameEventListener.h" +#include "vgui_controls/phandle.h" + +class CBaseLesson; + + +struct LessonGroupConVarToggle_t +{ + ConVarRef var; + char szLessonGroupName[ 64 ]; + + LessonGroupConVarToggle_t( const char *pchConVarName ) : + var( pchConVarName ) + { + } +}; + + +class C_GameInstructor : public CAutoGameSystemPerFrame, public CGameEventListener +{ +public: + C_GameInstructor() : CAutoGameSystemPerFrame( "C_GameInstructor" ) + { + m_nSplitScreenSlot = -1; + + m_bHasLoadedSaveData = false; + m_bDirtySaveData = false; + } + + void SetSlot( int nSlot ) { m_nSplitScreenSlot = nSlot; } + + // Methods of IGameSystem + virtual bool Init( void ); + virtual void Shutdown( void ); + virtual void Update( float frametime ); + + void UpdateHiddenByOtherElements( void ); + bool Mod_HiddenByOtherElements( void ); + + virtual void FireGameEvent( IGameEvent *event ); + + void DefineLesson( CBaseLesson *pLesson ); + + const CBaseLesson * GetLesson( const char *pchLessonName ); + bool IsLessonOfSameTypeOpen( const CBaseLesson *pLesson ) const; + + bool ReadSaveData( void ); + bool WriteSaveData( void ); + void RefreshDisplaysAndSuccesses( void ); + void ResetDisplaysAndSuccesses( void ); + void MarkDisplayed( const char *pchLessonName ); + void MarkSucceeded( const char *pchLessonName ); + + void PlaySound( const char *pchSoundName ); + + bool OpenOpportunity( CBaseLesson *pLesson ); + + void DumpOpenOpportunities( void ); + + KeyValues * GetScriptKeys( void ); + C_BasePlayer * GetLocalPlayer( void ); + + void EvaluateLessonsForGameRules( void ); + void SetLessonGroupEnabled( const char *pszGroup, bool bEnabled ); + +private: + void FindErrors( void ); + + bool UpdateActiveLesson( CBaseLesson *pLesson, const CBaseLesson *pRootLesson ); + void UpdateInactiveLesson( CBaseLesson *pLesson ); + + CBaseLesson * GetLesson_Internal( const char *pchLessonName ); + + void StopAllLessons( void ); + + void CloseAllOpenOpportunities( void ); + void CloseOpportunity( CBaseLesson *pLesson ); + + void ReadLessonsFromFile( const char *pchFileName ); + void InitLessonPrerequisites( void ); + +private: + CUtlVector < CBaseLesson* > m_Lessons; + CUtlVector < CBaseLesson* > m_OpenOpportunities; + + CUtlVector < LessonGroupConVarToggle_t > m_LessonGroupConVarToggles; + + KeyValues *m_pScriptKeys; + + bool m_bNoDraw; + bool m_bHiddenDueToOtherElements; + + int m_iCurrentPriority; + EHANDLE m_hLastSpectatedPlayer; + bool m_bSpectatedPlayerChanged; + + char m_szPreviousStartSound[ 128 ]; + float m_fNextStartSoundTime; + int m_nSplitScreenSlot; + + bool m_bHasLoadedSaveData; + bool m_bDirtySaveData; +}; + +C_GameInstructor &GetGameInstructor(); + +void GameInstructor_Init(); +void GameInstructor_Shutdown(); + + +#endif // _C_GAMEINSTRUCTOR_H_ diff --git a/game/client/c_gib.cpp b/game/client/c_gib.cpp index e4941cf23..a8bc134b6 100644 --- a/game/client/c_gib.cpp +++ b/game/client/c_gib.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // @@ -53,7 +53,7 @@ C_Gib *C_Gib::CreateClientsideGib( const char *pszModelName, Vector vecOrigin, V //----------------------------------------------------------------------------- bool C_Gib::InitializeGib( const char *pszModelName, Vector vecOrigin, Vector vecForceDir, AngularImpulse vecAngularImp, float flLifetime ) { - if ( InitializeAsClientEntity( pszModelName, RENDER_GROUP_OPAQUE_ENTITY ) == false ) + if ( InitializeAsClientEntity( pszModelName, false ) == false ) { Release(); return false; @@ -93,9 +93,9 @@ bool C_Gib::InitializeGib( const char *pszModelName, Vector vecOrigin, Vector ve void C_Gib::ClientThink( void ) { SetRenderMode( kRenderTransAlpha ); - m_nRenderFX = kRenderFxFadeFast; + SetRenderFX( kRenderFxFadeFast ); - if ( m_clrRender->a == 0 ) + if ( GetRenderAlpha() == 0 ) { #ifdef HL2_CLIENT_DLL s_AntlionGibManager.RemoveGib( this ); diff --git a/game/client/c_gib.h b/game/client/c_gib.h index 16d53e4e6..29e573032 100644 --- a/game/client/c_gib.h +++ b/game/client/c_gib.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // diff --git a/game/client/c_hairball.cpp b/game/client/c_hairball.cpp index a6e4a427b..a7c75af5a 100644 --- a/game/client/c_hairball.cpp +++ b/game/client/c_hairball.cpp @@ -1,9 +1,9 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // // $NoKeywords: $ -//=============================================================================// +//===========================================================================// #include "cbase.h" #include "simple_physics.h" #include "mathlib/vmatrix.h" @@ -43,8 +43,8 @@ class C_Hairball : public C_BaseEntity // IClientRenderable. public: - virtual int DrawModel( int flags ); - + virtual int DrawModel( int flags, const RenderableInstance_t &instance ); + virtual RenderableTranslucencyType_t ComputeTranslucencyType(); public: @@ -166,7 +166,7 @@ void C_Hairball::Init() ClientEntityList().AddNonNetworkableEntity( this ); ClientThinkList()->SetNextClientThink( GetClientHandle(), CLIENT_THINK_ALWAYS ); - AddToLeafSystem( RENDER_GROUP_OPAQUE_ENTITY ); + AddToLeafSystem( false ); m_pMaterial = materials->FindMaterial( "cable/cable", TEXTURE_GROUP_OTHER ); m_flSitStillTime = 5; @@ -294,7 +294,12 @@ void C_Hairball::ClientThink() } -int C_Hairball::DrawModel( int flags ) +RenderableTranslucencyType_t C_Hairball::ComputeTranslucencyType() +{ + return ( m_pMaterial && m_pMaterial->IsTranslucent() ) ? RENDERABLE_IS_TRANSLUCENT : RENDERABLE_IS_OPAQUE; +} + +int C_Hairball::DrawModel( int flags, const RenderableInstance_t &instance ) { if ( !m_pMaterial ) return 0; @@ -311,11 +316,10 @@ int C_Hairball::DrawModel( int flags ) { BeamSeg_t seg; seg.m_vPos = pBase[i].m_vPredicted; - seg.m_vColor.Init( 0, 0, 0 ); + seg.m_color.r = seg.m_color.g = seg.m_color.b = seg.m_color.a = 0; seg.m_flTexCoord = 0; static float flHairWidth = 1; seg.m_flWidth = flHairWidth; - seg.m_flAlpha = 0; beamDraw.NextSeg( &seg ); } @@ -346,5 +350,5 @@ void CreateHairballCallback() } } -ConCommand cc_CreateHairball( "CreateHairball", CreateHairballCallback, 0, FCVAR_CHEAT ); +ConCommand cc_CreateHairball( "CreateHairball", CreateHairballCallback, 0, FCVAR_DEVELOPMENTONLY | FCVAR_CHEAT ); diff --git a/game/client/c_impact_effects.cpp b/game/client/c_impact_effects.cpp index 5b350c184..919982c3d 100644 --- a/game/client/c_impact_effects.cpp +++ b/game/client/c_impact_effects.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // @@ -7,8 +7,8 @@ #include "cbase.h" #include "fx.h" #include "fx_sparks.h" -#include "clienteffectprecachesystem.h" -#include "particle_simple3d.h" +#include "precache_register.h" +#include "particle_simple3D.h" #include "decals.h" #include "engine/IEngineSound.h" #include "c_te_particlesystem.h" @@ -23,18 +23,18 @@ #include "tier0/memdbgon.h" //Precahce the effects -CLIENTEFFECT_REGISTER_BEGIN( PrecacheEffectImpacts ) -CLIENTEFFECT_MATERIAL( "effects/fleck_cement1" ) -CLIENTEFFECT_MATERIAL( "effects/fleck_cement2" ) -CLIENTEFFECT_MATERIAL( "effects/fleck_antlion1" ) -CLIENTEFFECT_MATERIAL( "effects/fleck_antlion2" ) -CLIENTEFFECT_MATERIAL( "effects/fleck_wood1" ) -CLIENTEFFECT_MATERIAL( "effects/fleck_wood2" ) -CLIENTEFFECT_MATERIAL( "effects/blood" ) -CLIENTEFFECT_MATERIAL( "effects/blood2" ) -CLIENTEFFECT_MATERIAL( "sprites/bloodspray" ) -CLIENTEFFECT_MATERIAL( "particle/particle_noisesphere" ) -CLIENTEFFECT_REGISTER_END() +PRECACHE_REGISTER_BEGIN( GLOBAL, PrecacheEffectImpacts ) +PRECACHE( MATERIAL, "effects/fleck_cement1" ) +PRECACHE( MATERIAL, "effects/fleck_cement2" ) +PRECACHE( MATERIAL, "effects/fleck_antlion1" ) +PRECACHE( MATERIAL, "effects/fleck_antlion2" ) +PRECACHE( MATERIAL, "effects/fleck_wood1" ) +PRECACHE( MATERIAL, "effects/fleck_wood2" ) +PRECACHE( MATERIAL, "effects/blood" ) +PRECACHE( MATERIAL, "effects/blood2" ) +PRECACHE( MATERIAL, "sprites/bloodspray" ) +PRECACHE( MATERIAL, "particle/particle_noisesphere" ) +PRECACHE_REGISTER_END() // Cached handles to commonly used materials PMaterialHandle g_Mat_Fleck_Wood[2] = { NULL, NULL }; @@ -50,41 +50,39 @@ PMaterialHandle g_Mat_Combine_Muzzleflash[3] = { NULL, NULL, NULL }; static ConVar fx_drawimpactdebris( "fx_drawimpactdebris", "1", FCVAR_DEVELOPMENTONLY, "Draw impact debris effects." ); static ConVar fx_drawimpactdust( "fx_drawimpactdust", "1", FCVAR_DEVELOPMENTONLY, "Draw impact dust effects." ); -void FX_CacheMaterialHandles( void ) -{ - g_Mat_Fleck_Wood[0] = ParticleMgr()->GetPMaterial( "effects/fleck_wood1" ); - g_Mat_Fleck_Wood[1] = ParticleMgr()->GetPMaterial( "effects/fleck_wood2" ); +PRECACHE_REGISTER_BEGIN( GLOBAL, FX_CacheMaterialHandles ) - g_Mat_Fleck_Cement[0] = ParticleMgr()->GetPMaterial( "effects/fleck_cement1"); - g_Mat_Fleck_Cement[1] = ParticleMgr()->GetPMaterial( "effects/fleck_cement2" ); + PRECACHE_INDEX( PARTICLE_MATERIAL, "effects/fleck_wood1", g_Mat_Fleck_Wood[0] ) + PRECACHE_INDEX( PARTICLE_MATERIAL, "effects/fleck_wood2", g_Mat_Fleck_Wood[1] ) - g_Mat_Fleck_Antlion[0] = ParticleMgr()->GetPMaterial( "effects/fleck_antlion1" ); - g_Mat_Fleck_Antlion[1] = ParticleMgr()->GetPMaterial( "effects/fleck_antlion2" ); + PRECACHE_INDEX( PARTICLE_MATERIAL, "effects/fleck_cement1", g_Mat_Fleck_Cement[0]) + PRECACHE_INDEX( PARTICLE_MATERIAL, "effects/fleck_cement2", g_Mat_Fleck_Cement[1] ) - g_Mat_Fleck_Glass[0] = ParticleMgr()->GetPMaterial( "effects/fleck_glass1" ); - g_Mat_Fleck_Glass[1] = ParticleMgr()->GetPMaterial( "effects/fleck_glass2" ); + PRECACHE_INDEX( PARTICLE_MATERIAL, "effects/fleck_antlion1", g_Mat_Fleck_Antlion[0] ) + PRECACHE_INDEX( PARTICLE_MATERIAL, "effects/fleck_antlion2", g_Mat_Fleck_Antlion[1] ) - g_Mat_Fleck_Tile[0] = ParticleMgr()->GetPMaterial( "effects/fleck_tile1" ); - g_Mat_Fleck_Tile[1] = ParticleMgr()->GetPMaterial( "effects/fleck_tile2" ); + PRECACHE_INDEX( PARTICLE_MATERIAL, "effects/fleck_glass1", g_Mat_Fleck_Glass[0] ) + PRECACHE_INDEX( PARTICLE_MATERIAL, "effects/fleck_glass2", g_Mat_Fleck_Glass[1] ) - g_Mat_DustPuff[0] = ParticleMgr()->GetPMaterial( "particle/particle_smokegrenade" ); - g_Mat_DustPuff[1] = ParticleMgr()->GetPMaterial( "particle/particle_noisesphere" ); + PRECACHE_INDEX( PARTICLE_MATERIAL, "effects/fleck_tile1", g_Mat_Fleck_Tile[0] ) + PRECACHE_INDEX( PARTICLE_MATERIAL, "effects/fleck_tile2", g_Mat_Fleck_Tile[1] ) - g_Mat_BloodPuff[0] = ParticleMgr()->GetPMaterial( "effects/blood" ); - g_Mat_BloodPuff[1] = ParticleMgr()->GetPMaterial( "effects/blood2" ); - -#ifndef TF_CLIENT_DLL - g_Mat_SMG_Muzzleflash[0] = ParticleMgr()->GetPMaterial( "effects/muzzleflash1" ); - g_Mat_SMG_Muzzleflash[1] = ParticleMgr()->GetPMaterial( "effects/muzzleflash2" ); - g_Mat_SMG_Muzzleflash[2] = ParticleMgr()->GetPMaterial( "effects/muzzleflash3" ); - g_Mat_SMG_Muzzleflash[3] = ParticleMgr()->GetPMaterial( "effects/muzzleflash4" ); -#ifndef CSTRIKE_DLL - g_Mat_Combine_Muzzleflash[0] = ParticleMgr()->GetPMaterial( "effects/combinemuzzle1" ); - g_Mat_Combine_Muzzleflash[1] = ParticleMgr()->GetPMaterial( "effects/combinemuzzle2" ); - g_Mat_Combine_Muzzleflash[2] = ParticleMgr()->GetPMaterial( "effects/strider_muzzle" ); -#endif -#endif -} + PRECACHE_INDEX( PARTICLE_MATERIAL, "particle/particle_smokegrenade", g_Mat_DustPuff[0] ) + PRECACHE_INDEX( PARTICLE_MATERIAL, "particle/particle_noisesphere", g_Mat_DustPuff[1] ) + + PRECACHE_INDEX( PARTICLE_MATERIAL, "effects/blood", g_Mat_BloodPuff[0] ) + PRECACHE_INDEX( PARTICLE_MATERIAL, "effects/blood2", g_Mat_BloodPuff[1] ) + + PRECACHE_INDEX( PARTICLE_MATERIAL, "effects/muzzleflash1", g_Mat_SMG_Muzzleflash[0] ) + PRECACHE_INDEX( PARTICLE_MATERIAL, "effects/muzzleflash2", g_Mat_SMG_Muzzleflash[1] ) + PRECACHE_INDEX( PARTICLE_MATERIAL, "effects/muzzleflash3", g_Mat_SMG_Muzzleflash[2] ) + PRECACHE_INDEX( PARTICLE_MATERIAL, "effects/muzzleflash4", g_Mat_SMG_Muzzleflash[3] ) + + PRECACHE_INDEX( PARTICLE_MATERIAL, "effects/combinemuzzle1", g_Mat_Combine_Muzzleflash[0] ) + PRECACHE_INDEX( PARTICLE_MATERIAL, "effects/combinemuzzle2", g_Mat_Combine_Muzzleflash[1] ) + PRECACHE_INDEX( PARTICLE_MATERIAL, "effects/strider_muzzle", g_Mat_Combine_Muzzleflash[2] ) + +PRECACHE_REGISTER_END() extern PMaterialHandle g_Material_Spark; @@ -188,8 +186,7 @@ static void CreateFleckParticles( const Vector& origin, const Vector &color, tra float colorRamp; - float fScale = g_pParticleSystemMgr->ParticleThrottleScaling() * (float)iScale; - int numFlecks = (int)( 0.5f + fScale * (float)( random->RandomInt( 4, 16 ) ) ); + int numFlecks = random->RandomInt( 4, 16 ) * iScale; FleckParticle *pFleckParticle; @@ -476,9 +473,13 @@ void FX_DebrisFlecks( const Vector& origin, trace_t *tr, char materialType, int //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- -void FX_GlassImpact( const Vector &pos, const Vector &normal ) +void GlassImpactCallback( const CEffectData &data ) { - VPROF_BUDGET( "FX_GlassImpact", VPROF_BUDGETGROUP_PARTICLE_RENDERING ); + VPROF_BUDGET( "GlassImpactCallback", VPROF_BUDGETGROUP_PARTICLE_RENDERING ); + + Vector pos = data.m_vOrigin; + Vector normal = data.m_vNormal; + CSmartPtr pGlassEmitter = CSimple3DEmitter::Create( "FX_GlassImpact" ); pGlassEmitter->SetSortOrigin( pos ); @@ -501,7 +502,7 @@ void FX_GlassImpact( const Vector &pos, const Vector &normal ) for ( int i = 0; i < numShards; i++ ) { Particle3D *pParticle; - + pParticle = (Particle3D *) pGlassEmitter->AddParticle( sizeof(Particle3D), g_Mat_Fleck_Glass[random->RandomInt(0,1)], pos ); if ( pParticle ) @@ -547,7 +548,7 @@ void FX_GlassImpact( const Vector &pos, const Vector &normal ) newParticle.m_flLifetime= 0.0f; newParticle.m_flDieTime = random->RandomFloat( 0.1f, 0.25f ); - + dir[0] = normal[0] + random->RandomFloat( -0.8f, 0.8f ); dir[1] = normal[1] + random->RandomFloat( -0.8f, 0.8f ); dir[2] = normal[2] + random->RandomFloat( -0.8f, 0.8f ); @@ -560,7 +561,7 @@ void FX_GlassImpact( const Vector &pos, const Vector &normal ) newParticle.m_uchStartAlpha = random->RandomInt( 128, 255 ); newParticle.m_uchEndAlpha = 0; - + newParticle.m_flRoll = random->RandomFloat( 0, 360 ); newParticle.m_flRollDelta = random->RandomFloat( -1, 1 ); @@ -593,7 +594,7 @@ void FX_GlassImpact( const Vector &pos, const Vector &normal ) newParticle.m_uchStartAlpha = random->RandomInt( 32, 64 ); newParticle.m_uchEndAlpha = 0; - + newParticle.m_flRoll = random->RandomFloat( 0, 360 ); newParticle.m_flRollDelta = random->RandomFloat( -2, 2 ); @@ -606,12 +607,8 @@ void FX_GlassImpact( const Vector &pos, const Vector &normal ) AddSimpleParticle( &newParticle, g_Mat_DustPuff[0] ); } -void GlassImpactCallback( const CEffectData &data ) -{ - FX_GlassImpact( data.m_vOrigin, data.m_vNormal ); -} +DECLARE_CLIENT_EFFECT( GlassImpact, GlassImpactCallback ) -DECLARE_CLIENT_EFFECT( "GlassImpact", GlassImpactCallback ); //----------------------------------------------------------------------------- // Purpose: @@ -1085,12 +1082,6 @@ void FX_DustImpact( const Vector &origin, trace_t *tr, float flScale ) CSmartPtr pSimple = CDustParticle::Create( "dust" ); pSimple->SetSortOrigin( origin ); - // Three types of particle, ideally we want 4 of each. - float fNumParticles = 4.0f * g_pParticleSystemMgr->ParticleThrottleScaling(); - int nParticles1 = (int)( 0.50f + fNumParticles ); - int nParticles2 = (int)( 0.83f + fNumParticles ); // <-- most visible particle type. - int nParticles3 = (int)( 0.17f + fNumParticles ); - SimpleParticle *pParticle; Vector color; @@ -1098,14 +1089,9 @@ void FX_DustImpact( const Vector &origin, trace_t *tr, float flScale ) GetColorForSurface( tr, &color ); - // To get a decent spread even when scaling down the number of particles... - const static int nParticleIdArray[4] = {3,1,2,0}; - int i; - for ( i = 0; i < nParticles1; i++ ) + for ( i = 0; i < 4; i++ ) { - int nId = nParticleIdArray[i]; - pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_DustPuff[0], origin ); if ( pParticle != NULL ) @@ -1118,7 +1104,7 @@ void FX_DustImpact( const Vector &origin, trace_t *tr, float flScale ) VectorNormalize( pParticle->m_vecVelocity ); - float fForce = random->RandomFloat( 250, 500 ) * nId; + float fForce = random->RandomFloat( 250, 500 ) * i; // scaled pParticle->m_vecVelocity *= fForce * flScale; @@ -1130,7 +1116,7 @@ void FX_DustImpact( const Vector &origin, trace_t *tr, float flScale ) pParticle->m_uchColor[2] = MIN( 1.0f, color[2] * colorRamp ) * 255.0f; // scaled - pParticle->m_uchStartSize = ( unsigned char )( flScale * random->RandomInt( 3, 4 ) * (nId+1) ); + pParticle->m_uchStartSize = ( unsigned char )( flScale * random->RandomInt( 3, 4 ) * (i+1) ); // scaled pParticle->m_uchEndSize = ( unsigned char )( flScale * pParticle->m_uchStartSize * 4 ); @@ -1144,10 +1130,8 @@ void FX_DustImpact( const Vector &origin, trace_t *tr, float flScale ) } //Dust specs - for ( i = 0; i < nParticles2; i++ ) + for ( i = 0; i < 4; i++ ) { - int nId = nParticleIdArray[i]; - pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_BloodPuff[0], origin ); if ( pParticle != NULL ) @@ -1160,7 +1144,7 @@ void FX_DustImpact( const Vector &origin, trace_t *tr, float flScale ) VectorNormalize( pParticle->m_vecVelocity ); - float fForce = random->RandomFloat( 250, 500 ) * nId; + float fForce = random->RandomFloat( 250, 500 ) * i; pParticle->m_vecVelocity *= fForce; @@ -1170,7 +1154,7 @@ void FX_DustImpact( const Vector &origin, trace_t *tr, float flScale ) pParticle->m_uchColor[1] = MIN( 1.0f, color[1] * colorRamp ) * 255.0f; pParticle->m_uchColor[2] = MIN( 1.0f, color[2] * colorRamp ) * 255.0f; - pParticle->m_uchStartSize = random->RandomInt( 2, 4 ) * (nId+1); + pParticle->m_uchStartSize = random->RandomInt( 2, 4 ) * (i+1); pParticle->m_uchEndSize = pParticle->m_uchStartSize * 2; pParticle->m_uchStartAlpha = 255; @@ -1182,10 +1166,8 @@ void FX_DustImpact( const Vector &origin, trace_t *tr, float flScale ) } //Impact hit - for ( i = 0; i < nParticles3; i++ ) + for ( i = 0; i < 4; i++ ) { - //int nId = nParticleIdArray[i]; - pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_DustPuff[0], origin ); if ( pParticle != NULL ) diff --git a/game/client/c_impact_effects.h b/game/client/c_impact_effects.h index aaeddbe98..10d907801 100644 --- a/game/client/c_impact_effects.h +++ b/game/client/c_impact_effects.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // diff --git a/game/client/c_info_overlay_accessor.cpp b/game/client/c_info_overlay_accessor.cpp index ca755411f..f6ecd4d3a 100644 --- a/game/client/c_info_overlay_accessor.cpp +++ b/game/client/c_info_overlay_accessor.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // @@ -6,7 +6,7 @@ //=============================================================================// #include "cbase.h" -#include "materialsystem/imesh.h" +#include "materialsystem/IMesh.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" diff --git a/game/client/c_lightglow.cpp b/game/client/c_lightglow.cpp index 06f20a6cf..b2a290ec5 100644 --- a/game/client/c_lightglow.cpp +++ b/game/client/c_lightglow.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // @@ -88,7 +88,7 @@ class C_LightGlow : public C_BaseEntity public: virtual void OnDataChanged( DataUpdateType_t updateType ); - virtual void Simulate( void ); + virtual bool Simulate( void ); virtual void ClientThink( void ); public: @@ -112,7 +112,7 @@ static void RecvProxy_HDRColorScale( const CRecvProxyData *pData, void *pStruct, } IMPLEMENT_CLIENTCLASS_DT_NOBASE( C_LightGlow, DT_LightGlow, CLightGlow ) - RecvPropInt( RECVINFO(m_clrRender), 0, RecvProxy_IntToColor32 ), + RecvPropInt( RECVINFO(m_clrRender), 0, RecvProxy_Int32ToColor32 ), RecvPropInt( RECVINFO( m_nHorizontalSize ) ), RecvPropInt( RECVINFO( m_nVerticalSize ) ), RecvPropInt( RECVINFO( m_nMinDist ) ), @@ -134,13 +134,15 @@ m_nHorizontalSize( 0 ), m_nVerticalSize( 0 ), m_nMinDist( 0 ), m_nMaxDist( 0 ) { m_Glow.m_bDirectional = false; m_Glow.m_bInSky = false; + AddToEntityList(ENTITY_LIST_SIMULATE); } -void C_LightGlow::Simulate( void ) +bool C_LightGlow::Simulate( void ) { BaseClass::Simulate(); m_Glow.m_vPos = GetAbsOrigin(); + return true; } //----------------------------------------------------------------------------- @@ -156,13 +158,10 @@ void C_LightGlow::OnDataChanged( DataUpdateType_t updateType ) if ( updateType == DATA_UPDATE_CREATED ) { // Setup our flare. - Vector vColor( - m_clrRender->r / 255.0f, - m_clrRender->g / 255.0f, - m_clrRender->b / 255.0f ); + color24 c = GetRenderColor(); + Vector vColor( c.r / 255.0f, c.g / 255.0f, c.b / 255.0f ); m_Glow.m_nSprites = 1; - m_Glow.m_Sprites[0].m_flVertSize = (float) m_nVerticalSize; m_Glow.m_Sprites[0].m_flHorzSize = (float) m_nHorizontalSize; m_Glow.m_Sprites[0].m_vColor = vColor; @@ -181,11 +180,8 @@ void C_LightGlow::OnDataChanged( DataUpdateType_t updateType ) else if ( updateType == DATA_UPDATE_DATATABLE_CHANGED ) //Right now only color should change. { // Setup our flare. - Vector vColor( - m_clrRender->r / 255.0f, - m_clrRender->g / 255.0f, - m_clrRender->b / 255.0f ); - + color24 c = GetRenderColor(); + Vector vColor( c.r / 255.0f, c.g / 255.0f, c.b / 255.0f ); m_Glow.m_Sprites[0].m_vColor = vColor; } diff --git a/game/client/c_memorylog.cpp b/game/client/c_memorylog.cpp new file mode 100644 index 000000000..9e4d7ea03 --- /dev/null +++ b/game/client/c_memorylog.cpp @@ -0,0 +1,125 @@ +//========= Copyright © 1996-2008, Valve Corporation, All rights reserved. ============// +// +// Purpose: See c_memorylog.h +// +//=============================================================================// + +#include "cbase.h" +#include "inetchannelinfo.h" +#include "clientterrorplayer.h" +#include "c_memorylog.h" +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + +#if ( defined( _X360 ) && !defined( _CERT ) ) + +ConVar memorylog_tick( "memorylog_tick", "20", FCVAR_CHEAT, "Set to N to spew free memory to the console every N seconds to be captured by logging (0 disables)." ); +ConVar memorylog_mem_dump( "memorylog_mem_dump", "0", FCVAR_CHEAT ); + +// Memory log auto game system instantiation +C_MemoryLog g_MemoryLog; + + +bool C_MemoryLog::Init( void ) +{ + // Spew on the first frame after init + m_fLastSpewTime = -memorylog_tick.GetFloat(); + // Set up a string we can search for in full heap crashdumps: + memset( m_nRecentFreeMem, 0, sizeof( m_nRecentFreeMem ) ); + memcpy( m_nRecentFreeMem, "maryhadatinylamb", 16 ); + return true; +} + +void C_MemoryLog::Spew( void ) +{ + // Spew "date+time | free mem | listen/not | map | bots | players", so we can + // use console logs to correlate memory leaks with playtest patterns. + + if ( memorylog_tick.GetFloat() <= 0 ) + return; // Disabled + + int time = (int)( Plat_FloatTime() + 0.5f ); + + MEMORYSTATUS memStats; + GlobalMemoryStatus( &memStats ); + int freeMem = memStats.dwAvailPhys; + + // Determine if this machine is the server + INetChannelInfo *pNetInfo = engine->GetNetChannelInfo(); + bool listen = ( pNetInfo && ( pNetInfo->IsLoopback() || V_strstr( pNetInfo->GetAddress(), "127.0.0.1" ) ) ); + + char mapName[32] = ""; + if ( engine->GetLevelNameShort() ) + V_strncpy( mapName, engine->GetLevelNameShort(), sizeof( mapName ) ); + if ( !mapName[ 0 ] ) + V_strncpy( mapName, "none", sizeof( mapName ) ); + + char playerNames[ 512 ] = ""; + int numBots = 0; + int numPlayers = 0; + for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + { + player_info_s playerInfo; + C_TerrorPlayer *player = static_cast( UTIL_PlayerByIndex( i ) ); + if ( player && player->IsPlayer() && engine->GetPlayerInfo( i, &playerInfo ) ) + { + if ( playerInfo.fakeplayer ) + { + // Ignore zombie bots + if ( player->GetCharacter() < NUM_SURVIVOR_CHARACTERS ) + numBots++; + } + else + { + char playerName[64]; + V_snprintf( playerName, sizeof( playerName ), ", %s%s%s", + playerInfo.name, + player->IsObserver() ? "|SPEC" : "", + C_BasePlayer::IsLocalPlayer( player ) ? "|LOCAL" : "" ); + V_strcat( playerNames, playerName, sizeof( playerNames ) ); + numPlayers++; + } + } + } + + ConMsg( "[MEMORYLOG] Time:%6d | Free: %6.2f | %s | Map: %-32s | Bots: %2d | Players: %2d%s\n", + time, + freeMem / ( 1024.0f*1024.0f ), + listen ? "Server" : "Client", + mapName, + numBots, numPlayers, playerNames ); + + // Keep the last N free memory values in an array, for inspection in full heap crashdumps + for ( int i = 255; i > 4; i-- ) m_nRecentFreeMem[ i ] = m_nRecentFreeMem[ i - 1 ]; + m_nRecentFreeMem[ 4 ] = freeMem; + + if ( memorylog_mem_dump.GetBool() ) + { + g_pMemAlloc->DumpStats(); + } +} + +void C_MemoryLog::Update( float frametime ) +{ + float curTime = Plat_FloatTime(); + if ( ( curTime - m_fLastSpewTime ) >= memorylog_tick.GetFloat() ) + { + m_fLastSpewTime = curTime; + Spew(); + } +} + +void C_MemoryLog::LevelInitPostEntity( void ) +{ + // Spew on the first frame after map load + m_fLastSpewTime = -memorylog_tick.GetFloat(); +} + +void C_MemoryLog::LevelShutdownPreEntity( void ) +{ + // Spew in case we don't make it to the next map + Spew(); +} + +#endif // ( defined( _X360 ) && !defined( _CERT ) ) diff --git a/game/client/c_memorylog.h b/game/client/c_memorylog.h new file mode 100644 index 000000000..0093d63e3 --- /dev/null +++ b/game/client/c_memorylog.h @@ -0,0 +1,32 @@ +//========= Copyright © 1996-2008, Valve Corporation, All rights reserved. ============// +// +// Purpose: Spew free memory at a fixed rate, for logging +// +//=============================================================================// + +#ifndef C_MEMORYLOG_H +#define C_MEMORYLOG_H + +#if ( defined( _X360 ) && !defined( _CERT ) ) + +#include "igamesystem.h" + +class C_MemoryLog : public CAutoGameSystemPerFrame +{ +public: + // Methods of IGameSystem + virtual bool Init( void ); + virtual void Update( float frametime ); + virtual void LevelInitPostEntity(); + virtual void LevelShutdownPreEntity(); + +private: + void Spew( void ); + + float m_fLastSpewTime; + int m_nRecentFreeMem[ 256 ]; // For inspection in full heap crashdumps +}; + +#endif // ( defined( _X360 ) && !defined( _CERT ) ) + +#endif // C_MEMORYLOG_H diff --git a/game/client/c_mod_lesson_stubs.cpp b/game/client/c_mod_lesson_stubs.cpp new file mode 100644 index 000000000..0e8c1e7a7 --- /dev/null +++ b/game/client/c_mod_lesson_stubs.cpp @@ -0,0 +1,75 @@ +//========= Copyright © 1996-2008, Valve Corporation, All rights reserved. ============// +// +// Purpose: Stub for custom mod lesson actions. +// This is so that mods can do actions +// Remove this file from the mod's vpc and include your own. +// +//=============================================================================// + +#include "cbase.h" + +#include "c_gameinstructor.h" +#include "c_baselesson.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + +extern ConVar gameinstructor_verbose; + + +enum Mod_LessonAction +{ + // Enum starts from end of LessonAction + LESSON_ACTION_MOD_CUSTOM_ACTION_STUB = LESSON_ACTION_MOD_START, + + LESSON_ACTION_TOTAL +}; + + +void CScriptedIconLesson::Mod_PreReadLessonsFromFile( void ) +{ + // Add custom actions to the map + CScriptedIconLesson::LessonActionMap.Insert( "custom action stub", LESSON_ACTION_MOD_CUSTOM_ACTION_STUB ); +} + + +bool CScriptedIconLesson::Mod_ProcessElementAction( int iAction, bool bNot, const char *pchVarName, EHANDLE &hVar, const CGameInstructorSymbol *pchParamName, float fParam, C_BaseEntity *pParam, const char *pchParam, bool &bModHandled ) +{ + // Assume we're going to handle the action + bModHandled = true; + + C_BaseEntity *pVar; + pVar = hVar.Get(); + + switch ( iAction ) + { + case LESSON_ACTION_MOD_CUSTOM_ACTION_STUB: + { + float flStub = 0.0f; //pVar->GetStubValue(); + + if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) + { + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\t[%s]->GetStubValue() ", pchVarName ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "%.1f ", flStub ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ( bNot ) ? ( ">= [%s] " ) : ( "< [%s] " ), pchParamName->String() ); + ConColorMsg( CBaseLesson::m_rgbaVerboseName, "%.1f\n", fParam ); + } + + return ( flStub ) ? ( flStub >= fParam ) : ( flStub < fParam ); + } + + default: + // Didn't handle this action + bModHandled = false; + break; + } + + return false; +} + + +bool C_GameInstructor::Mod_HiddenByOtherElements( void ) +{ + return false; +} diff --git a/game/client/c_movie_display.cpp b/game/client/c_movie_display.cpp new file mode 100644 index 000000000..2285b97ed --- /dev/null +++ b/game/client/c_movie_display.cpp @@ -0,0 +1,26 @@ +//========= Copyright © 1996-2009, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// +//=====================================================================================// +#include "cbase.h" +#include "c_movie_display.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +IMPLEMENT_CLIENTCLASS_DT( C_MovieDisplay, DT_MovieDisplay, CMovieDisplay ) + RecvPropBool( RECVINFO( m_bEnabled ) ), + RecvPropBool( RECVINFO( m_bLooping ) ), + RecvPropString( RECVINFO( m_szMovieFilename ) ), + RecvPropString( RECVINFO( m_szGroupName ) ), +END_RECV_TABLE() + +C_MovieDisplay::C_MovieDisplay() +{ +} + +C_MovieDisplay::~C_MovieDisplay() +{ +} diff --git a/game/client/c_movie_display.h b/game/client/c_movie_display.h new file mode 100644 index 000000000..d133e82e4 --- /dev/null +++ b/game/client/c_movie_display.h @@ -0,0 +1,34 @@ +//========= Copyright © 1996-2009, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=====================================================================================// + +#ifndef C_MOVIE_DISPLAY_H +#define C_MOVIE_DISPLAY_H + +#include "cbase.h" + +class C_MovieDisplay : public C_BaseEntity +{ +public: + DECLARE_CLASS( C_MovieDisplay, C_BaseEntity ); + DECLARE_CLIENTCLASS(); + + C_MovieDisplay(); + ~C_MovieDisplay(); + + bool IsEnabled( void ) const { return m_bEnabled; } + bool IsLooping( void ) const { return m_bLooping; } + + const char *GetMovieFilename( void ) const { return m_szMovieFilename; } + const char *GetGroupName( void ) const { return m_szGroupName; } + +private: + bool m_bEnabled; + bool m_bLooping; + char m_szMovieFilename[128]; + char m_szGroupName[128]; +}; + +#endif //C_MOVIE_DISPLAY_H \ No newline at end of file diff --git a/game/client/c_movie_explosion.cpp b/game/client/c_movie_explosion.cpp index b548839b8..ec941faa6 100644 --- a/game/client/c_movie_explosion.cpp +++ b/game/client/c_movie_explosion.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // diff --git a/game/client/c_particle_fire.cpp b/game/client/c_particle_fire.cpp index 5dd5a9b7a..1d39f7581 100644 --- a/game/client/c_particle_fire.cpp +++ b/game/client/c_particle_fire.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // diff --git a/game/client/c_particle_smokegrenade.cpp b/game/client/c_particle_smokegrenade.cpp index da44878a3..7aa9f2b92 100644 --- a/game/client/c_particle_smokegrenade.cpp +++ b/game/client/c_particle_smokegrenade.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // @@ -12,13 +12,8 @@ #include "view.h" #include "dlight.h" #include "iefx.h" -#include "tier1/KeyValues.h" +#include "tier1/keyvalues.h" #include "toolframework_client.h" -#include "engine/ivdebugoverlay.h" - -#if CSTRIKE_DLL -#include "c_cs_player.h" -#endif // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -379,30 +374,23 @@ void C_ParticleSmokeGrenade::Start(CParticleMgr *pParticleMgr, IPrototypeArgAcce m_bStarted = true; SetNextClientThink( CLIENT_THINK_ALWAYS ); - -#if CSTRIKE_DLL - C_CSPlayer *pPlayer = C_CSPlayer::GetLocalCSPlayer(); - - if ( pPlayer ) - { - pPlayer->m_SmokeGrenades.AddToTail( this ); - } -#endif } + void C_ParticleSmokeGrenade::ClientThink() { if ( m_CurrentStage == 1 ) { // Add our influence to the global smoke fog alpha. - - float testDist = (MainViewOrigin() - m_SmokeBasePos ).Length(); + ASSERT_LOCAL_PLAYER_RESOLVABLE(); + int nSlot = GET_ACTIVE_SPLITSCREEN_SLOT(); + float testDist = (MainViewOrigin(nSlot) - m_SmokeBasePos).Length(); float fadeEnd = m_ExpandRadius; // The center of the smoke cloud that always gives full fog overlay - float flCoreDistance = fadeEnd * 0.3; + float flCoreDistance = fadeEnd * 0.15; if(testDist < fadeEnd) { @@ -572,9 +560,8 @@ void C_ParticleSmokeGrenade::Update(float fTimeDelta) // Update our bbox. - - Vector vMins = m_SmokeBasePos - Vector( m_SpacingRadius + SMOKEGRENADE_PARTICLERADIUS, m_SpacingRadius + SMOKEGRENADE_PARTICLERADIUS, m_SpacingRadius + SMOKEGRENADE_PARTICLERADIUS ); - Vector vMaxs = m_SmokeBasePos + Vector( m_SpacingRadius + SMOKEGRENADE_PARTICLERADIUS, m_SpacingRadius + SMOKEGRENADE_PARTICLERADIUS, m_SpacingRadius + SMOKEGRENADE_PARTICLERADIUS ); + Vector vMins = m_SmokeBasePos - Vector( m_SpacingRadius, m_SpacingRadius, m_SpacingRadius ); + Vector vMaxs = m_SmokeBasePos + Vector( m_SpacingRadius, m_SpacingRadius, m_SpacingRadius ); m_ParticleEffect.SetBBox( vMins, vMaxs ); @@ -590,10 +577,7 @@ void C_ParticleSmokeGrenade::Update(float fTimeDelta) m_ExpandTimeCounter = SMOKESPHERE_EXPAND_TIME; m_ExpandRadius = (m_SpacingRadius*2) * (float)sin(m_ExpandTimeCounter * M_PI * 0.5 / SMOKESPHERE_EXPAND_TIME); - -// debugoverlay->AddBoxOverlay( GetPos(), Vector( -m_ExpandRadius, -m_ExpandRadius, -m_ExpandRadius), Vector( m_ExpandRadius, m_ExpandRadius, m_ExpandRadius), vec3_angle, 0, 255, 0, 1, 1.0f ); - - + // Update all the moving traders and establish new ones. int nTotal = m_xCount * m_yCount * m_zCount; for(int i=0; i < nTotal; i++) @@ -710,7 +694,7 @@ void C_ParticleSmokeGrenade::RenderParticles( CParticleRenderIterator *pIterator float alpha = 1 - len / m_ExpandRadius; // This changes the ramp to be very solid in the core, then taper off. - static float testCutoff=0.3; + static float testCutoff=0.7; if(alpha > testCutoff) { alpha = 1; @@ -735,20 +719,16 @@ void C_ParticleSmokeGrenade::RenderParticles( CParticleRenderIterator *pIterator // Lighting. ApplyDynamicLight( renderPos, color ); - - color = (color + Vector( 0.5, 0.5, 0.5 )) / 2; //Desaturate Vector tRenderPos; TransformParticle(ParticleMgr()->GetModelView(), renderPos, tRenderPos); sortKey = tRenderPos.z; - //debugoverlay->AddBoxOverlay( renderPos, Vector( -2, -2, -2), Vector( 2, 2, 2), vec3_angle, 255, 255, 255, 255, 1.0f ); - RenderParticle_ColorSizeAngle( pIterator->GetParticleDraw(), tRenderPos, color, - alpha * GetAlphaDistanceFade(tRenderPos, 0, 10), // Alpha + alpha * GetAlphaDistanceFade(tRenderPos, 100, 200), // Alpha SMOKEPARTICLE_SIZE, pParticle->m_CurRotation ); @@ -774,15 +754,6 @@ void C_ParticleSmokeGrenade::NotifyRemove() { m_xCount = m_yCount = m_zCount = 0; -#if CSTRIKE_DLL - C_CSPlayer *pPlayer = C_CSPlayer::GetLocalCSPlayer(); - - if ( pPlayer ) - { - pPlayer->m_SmokeGrenades.FindAndRemove( this ); - } -#endif - } @@ -838,13 +809,12 @@ void C_ParticleSmokeGrenade::FillVolume() vPos.z = m_SmokeBasePos.z + ((float)z * invNumPerDimZ) * m_SpacingRadius * 2 - m_SpacingRadius; // Don't spawn and simulate particles that are inside a wall -// int contents = enginetrace->GetPointContents( vPos ); + int contents = enginetrace->GetPointContents( vPos ); - // Culling out particles in solid makes smoke not fill up small passageways. - //if( contents & CONTENTS_SOLID ) - //{ - // continue; - //} + if( contents & CONTENTS_SOLID ) + { + continue; + } if(SmokeParticleInfo *pInfo = GetSmokeParticleInfo(x,y,z)) { @@ -864,15 +834,11 @@ void C_ParticleSmokeGrenade::FillVolume() if(pParticle) { pParticle->m_Pos = vPos - m_SmokeBasePos; // store its position in local space - pParticle->m_ColorInterp = (unsigned char)((rand() * 255) / VALVE_RAND_MAX); + pParticle->m_ColorInterp = (unsigned char)((rand() * 255) / RAND_MAX); pParticle->m_RotationSpeed = FRand(-ROTATION_SPEED, ROTATION_SPEED); // Rotation speed. pParticle->m_CurRotation = FRand(-6, 6); - - //debugoverlay->AddBoxOverlay( vPos, Vector( -2, -2, -2), Vector( 2, 2, 2), vec3_angle, 255, 0, 0, 255, 5.0f ); } - - #ifdef _DEBUG int testX, testY, testZ; int index = GetSmokeParticleIndex(x,y,z); @@ -968,7 +934,7 @@ void C_ParticleSmokeGrenade::CleanupToolRecordingState( KeyValues *msg ) pLifetime->SetFloat( "maxLifetime", m_FadeEndTime ); KeyValues *pVelocity = pInitializers->FindKey( "DmeAttachmentVelocityInitializer", true ); - pVelocity->SetPtr( "entindex", (void*)(intp)entindex() ); + pVelocity->SetPtr( "entindex", (void*)entindex() ); pVelocity->SetFloat( "minRandomSpeed", 10 ); pVelocity->SetFloat( "maxRandomSpeed", 20 ); @@ -982,13 +948,13 @@ void C_ParticleSmokeGrenade::CleanupToolRecordingState( KeyValues *msg ) KeyValues *pColor = pInitializers->FindKey( "DmeRandomInterpolatedColorInitializer", true ); Color c1( - FastFToC( clamp( m_MinColor.x, 0.f, 1.f ) ), - FastFToC( clamp( m_MinColor.y, 0.f, 1.f ) ), - FastFToC( clamp( m_MinColor.z, 0.f, 1.f ) ), 255 ); + clamp( m_MinColor.x * 255.0f, 0, 255 ), + clamp( m_MinColor.y * 255.0f, 0, 255 ), + clamp( m_MinColor.z * 255.0f, 0, 255 ), 255 ); Color c2( - FastFToC( clamp( m_MaxColor.x, 0.f, 1.f ) ), - FastFToC( clamp( m_MaxColor.y, 0.f, 1.f ) ), - FastFToC( clamp( m_MaxColor.z, 0.f, 1.f ) ), 255 ); + clamp( m_MaxColor.x * 255.0f, 0, 255 ), + clamp( m_MaxColor.y * 255.0f, 0, 255 ), + clamp( m_MaxColor.z * 255.0f, 0, 255 ), 255 ); pColor->SetColor( "color1", c1 ); pColor->SetColor( "color2", c2 ); diff --git a/game/client/c_particle_system.cpp b/game/client/c_particle_system.cpp index 57f3c3750..17875744a 100644 --- a/game/client/c_particle_system.cpp +++ b/game/client/c_particle_system.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======= // // Purpose: // @@ -10,6 +10,7 @@ #include "particles_new.h" #include "networkstringtable_clientdll.h" #include "tier0/vprof.h" +#include "tier1/fmtstr.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -23,26 +24,43 @@ class C_ParticleSystem : public C_BaseEntity public: DECLARE_CLIENTCLASS(); - C_ParticleSystem(); + C_ParticleSystem( void ); - void PreDataUpdate( DataUpdateType_t updateType ); - void PostDataUpdate( DataUpdateType_t updateType ); - void ClientThink( void ); + virtual void PreDataUpdate( DataUpdateType_t updateType ); + virtual void PostDataUpdate( DataUpdateType_t updateType ); + virtual void ClientThink( void ); protected: + C_ParticleSystem::~C_ParticleSystem( void ); + int m_iEffectIndex; + int m_nStopType; bool m_bActive; bool m_bOldActive; float m_flStartTime; // Time at which the effect started + char m_szSnapshotFileName[ MAX_PATH ]; + + //server controlled control points (variables in particle effects instead of literal follow points) + Vector m_vServerControlPoints[4]; + uint8 m_iServerControlPointAssignments[4]; + + CUtlReference< CNewParticleEffect > m_pEffect; + CParticleSnapshot *m_pSnapshot; enum { kMAXCONTROLPOINTS = 63 }; ///< actually one less than the total number of cpoints since 0 is assumed to be me + // stop types + enum + { + STOP_NORMAL = 0, + STOP_DESTROY_IMMEDIATELY, + STOP_PLAY_ENDCAP, + NUM_STOP_TYPES + }; EHANDLE m_hControlPointEnts[kMAXCONTROLPOINTS]; // SendPropArray3( SENDINFO_ARRAY3(m_iControlPointParents), SendPropInt( SENDINFO_ARRAY(m_iControlPointParents), 3, SPROP_UNSIGNED ) ), unsigned char m_iControlPointParents[kMAXCONTROLPOINTS]; - - bool m_bWeatherEffect; }; IMPLEMENT_CLIENTCLASS(C_ParticleSystem, DT_ParticleSystem, CParticleSystem); @@ -56,19 +74,35 @@ BEGIN_RECV_TABLE_NOBASE( C_ParticleSystem, DT_ParticleSystem ) RecvPropInt( RECVINFO( m_iEffectIndex ) ), RecvPropBool( RECVINFO( m_bActive ) ), + RecvPropInt( RECVINFO( m_nStopType ) ), RecvPropFloat( RECVINFO( m_flStartTime ) ), + RecvPropString( RECVINFO( m_szSnapshotFileName ) ), + RecvPropArray3( RECVINFO_ARRAY(m_vServerControlPoints), RecvPropVector( RECVINFO( m_vServerControlPoints[0] ) ) ), + RecvPropArray3( RECVINFO_ARRAY(m_iServerControlPointAssignments), RecvPropInt( RECVINFO(m_iServerControlPointAssignments[0]))), RecvPropArray3( RECVINFO_ARRAY(m_hControlPointEnts), RecvPropEHandle( RECVINFO( m_hControlPointEnts[0] ) ) ), RecvPropArray3( RECVINFO_ARRAY(m_iControlPointParents), RecvPropInt( RECVINFO(m_iControlPointParents[0]))), - RecvPropBool( RECVINFO( m_bWeatherEffect ) ), END_RECV_TABLE(); //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- -C_ParticleSystem::C_ParticleSystem() +C_ParticleSystem::C_ParticleSystem( void ) + : m_pSnapshot( NULL ) +{ + memset( m_szSnapshotFileName, 0, sizeof( m_szSnapshotFileName ) ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_ParticleSystem::~C_ParticleSystem( void ) { - m_bWeatherEffect = false; + if ( m_pSnapshot ) + { + delete m_pSnapshot; + m_pSnapshot = NULL; + } } //----------------------------------------------------------------------------- @@ -92,6 +126,18 @@ void C_ParticleSystem::PostDataUpdate( DataUpdateType_t updateType ) // FIXME: Does this play fairly with PVS? if ( updateType == DATA_UPDATE_CREATED ) { + // TODO: !!HACK HACK HACK!! .PSF files should be loaded/refcounted through the CParticleSystemMgr (ala .PCFs). + // The current code will duplicate a given .PSF file in memory for every info_particle_system that uses it! + if ( m_szSnapshotFileName[0] ) + { + m_pSnapshot = new CParticleSnapshot(); + if ( !m_pSnapshot->Unserialize( CFmtStr( "particles/%s.psf", m_szSnapshotFileName ) ) ) + { + delete m_pSnapshot; + m_pSnapshot = NULL; + } + } + if ( m_bActive ) { // Delayed here so that we don't get invalid abs queries on level init with active particle systems @@ -109,8 +155,41 @@ void C_ParticleSystem::PostDataUpdate( DataUpdateType_t updateType ) } else { + switch( m_nStopType ) + { + case STOP_NORMAL: + { ParticleProp()->StopEmission(); } + break; + case STOP_DESTROY_IMMEDIATELY: + { + ParticleProp()->StopEmissionAndDestroyImmediately(); + } + break; + case STOP_PLAY_ENDCAP: + { + ParticleProp()->StopEmission( NULL, false, false, false, true); + } + break; + } + } + } + + if( m_bActive && ParticleProp()->IsValidEffect( m_pEffect ) ) + { + //server controlled control points (variables in particle effects instead of literal follow points) + for( int i = 0; i != ARRAYSIZE( m_iServerControlPointAssignments ); ++i ) + { + if( m_iServerControlPointAssignments[i] != 255 ) + { + m_pEffect->SetControlPoint( m_iServerControlPointAssignments[i], m_vServerControlPoints[i] ); + } + else + { + break; + } + } } } } @@ -125,14 +204,9 @@ void C_ParticleSystem::ClientThink( void ) const char *pszName = GetParticleSystemNameFromIndex( m_iEffectIndex ); if ( pszName && pszName[0] ) { - if ( !GameRules()->AllowMapParticleEffect( pszName ) ) - return; - - if ( m_bWeatherEffect && !GameRules()->AllowWeatherParticles() ) - return; - CNewParticleEffect *pEffect = ParticleProp()->Create( pszName, PATTACH_ABSORIGIN_FOLLOW ); - AssertMsg1( pEffect, "Particle system couldn't make %s", pszName ); + m_pEffect = pEffect; + if (pEffect) { for ( int i = 0 ; i < kMAXCONTROLPOINTS ; ++i ) @@ -153,6 +227,26 @@ void C_ParticleSystem::ClientThink( void ) } } + //server controlled control points (variables in particle effects instead of literal follow points) + for( int i = 0; i != ARRAYSIZE( m_iServerControlPointAssignments ); ++i ) + { + if( m_iServerControlPointAssignments[i] != 255 ) + { + pEffect->SetControlPoint( m_iServerControlPointAssignments[i], m_vServerControlPoints[i] ); + } + else + { + break; + } + } + + // Attach our particle snapshot if we have one + Assert( m_pSnapshot || !m_szSnapshotFileName[0] ); // m_szSnapshotFileName shouldn't change after the create update + if ( m_pSnapshot ) + { + pEffect->SetControlPointSnapshot( 0, m_pSnapshot ); + } + // NOTE: What we really want here is to compare our lifetime and that of our children and see if this delta is // already past the end of it, denoting that we're finished. In that case, just destroy us and be done. -- jdw @@ -178,19 +272,24 @@ void C_ParticleSystem::ClientThink( void ) //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- -void ParticleEffectCallback( const CEffectData &data ) +void StartParticleEffect( const CEffectData &data, int nSplitScreenPlayerSlot /*= -1*/ ) { + // this needs to be before using data.m_nHitBox, + // since that may be a serialized value that's past the end of the current particle system string table if ( SuppressingParticleEffects() ) - return; // this needs to be before using data.m_nHitBox, since that may be a serialized value that's past the end of the current particle system string table + return; - const char *pszName = GetParticleSystemNameFromIndex( data.m_nHitBox ); + // Don't crash if we're passed an invalid particle system + if ( data.m_nHitBox == 0 ) + return; - CSmartPtr pEffect = NULL; if ( data.m_fFlags & PARTICLE_DISPATCH_FROM_ENTITY ) { if ( data.m_hEntity.Get() ) { C_BaseEntity *pEnt = C_BaseEntity::Instance( data.m_hEntity ); + // commented out assert. dormant entities have their particle system spawns stopped. + //Assert( pEnt && !pEnt->IsDormant() ); if ( pEnt && !pEnt->IsDormant() ) { if ( data.m_fFlags & PARTICLE_DISPATCH_RESET_PARTICLES ) @@ -198,19 +297,41 @@ void ParticleEffectCallback( const CEffectData &data ) pEnt->ParticleProp()->StopEmission(); } - pEffect = pEnt->ParticleProp()->Create( pszName, (ParticleAttachment_t)data.m_nDamageType, data.m_nAttachmentIndex ); - AssertMsg2( pEffect.IsValid() && pEffect->IsValid(), "%s could not create particle effect %s", - C_BaseEntity::Instance( data.m_hEntity )->GetDebugName(), pszName ); + CUtlReference pEffect = pEnt->ParticleProp()->CreatePrecached( data.m_nHitBox, (ParticleAttachment_t)data.m_nDamageType, data.m_nAttachmentIndex ); + if ( pEffect.IsValid() && pEffect->IsValid() ) { - if ( (ParticleAttachment_t)data.m_nDamageType == PATTACH_CUSTOMORIGIN ) + if ( (ParticleAttachment_t)data.m_nDamageType == PATTACH_CUSTOMORIGIN || (ParticleAttachment_t)data.m_nDamageType == PATTACH_CUSTOMORIGIN_FOLLOW ) { + pEffect->SetDrawOnlyForSplitScreenUser( nSplitScreenPlayerSlot ); pEffect->SetSortOrigin( data.m_vOrigin ); - pEffect->SetControlPoint( 0, data.m_vOrigin ); - pEffect->SetControlPoint( 1, data.m_vStart ); - Vector vecForward, vecRight, vecUp; - AngleVectors( data.m_vAngles, &vecForward, &vecRight, &vecUp ); - pEffect->SetControlPointOrientation( 0, vecForward, vecRight, vecUp ); + if ( (ParticleAttachment_t)data.m_nDamageType == PATTACH_CUSTOMORIGIN_FOLLOW ) + { + Vector vecCtrl1 = (data.m_vStart - pEnt->GetAbsOrigin() ); + pEffect->SetControlPoint( 1, vecCtrl1 ); + pEffect->SetControlPointEntity( 1, pEnt ); + Vector vecCtrl0 = (data.m_vOrigin - pEnt->GetAbsOrigin() ); + matrix3x4_t mat; + AngleMatrix( data.m_vAngles, mat ); + pEnt->ParticleProp()->AddControlPoint( pEffect, 0, pEnt, PATTACH_CUSTOMORIGIN_FOLLOW, NULL, vecCtrl0, &mat ); + } + else + { + pEffect->SetControlPoint( 0, data.m_vOrigin ); + pEffect->SetControlPoint( 1, data.m_vStart ); + Vector vecForward, vecRight, vecUp; + AngleVectors( data.m_vAngles, &vecForward, &vecRight, &vecUp ); + pEffect->SetControlPointOrientation( 0, vecForward, vecRight, vecUp ); + } + } + else if ( data.m_nOtherEntIndex > 0 ) + { + C_BaseEntity *pOtherEnt = ClientEntityList().GetEnt( data.m_nOtherEntIndex ); + + if ( pOtherEnt ) + { + pEnt->ParticleProp()->AddControlPoint( pEffect, 1, pOtherEnt, PATTACH_ABSORIGIN_FOLLOW, NULL, Vector( 0, 0, 50 ) ); + } } } } @@ -218,39 +339,39 @@ void ParticleEffectCallback( const CEffectData &data ) } else { - if ( GameRules() ) + CParticleSystemDefinition *pDef = g_pParticleSystemMgr->FindPrecachedParticleSystem( data.m_nHitBox ); + if ( pDef ) { - pszName = GameRules()->TranslateEffectForVisionFilter( "particles", pszName ); + CUtlReference pEffect = CNewParticleEffect::CreateOrAggregate( NULL, pDef, data.m_vOrigin, NULL, nSplitScreenPlayerSlot ); + if ( pEffect.IsValid() && pEffect->IsValid() ) + { + pEffect->SetSortOrigin( data.m_vOrigin ); + pEffect->SetControlPoint( 0, data.m_vOrigin ); + pEffect->SetControlPoint( 1, data.m_vStart ); + Vector vecForward, vecRight, vecUp; + AngleVectors( data.m_vAngles, &vecForward, &vecRight, &vecUp ); + pEffect->SetControlPointOrientation( 0, vecForward, vecRight, vecUp ); + } } - - pEffect = CNewParticleEffect::Create( NULL, pszName ); - if ( pEffect->IsValid() ) + else { - pEffect->SetSortOrigin( data.m_vOrigin ); - pEffect->SetControlPoint( 0, data.m_vOrigin ); - pEffect->SetControlPoint( 1, data.m_vStart ); - Vector vecForward, vecRight, vecUp; - AngleVectors( data.m_vAngles, &vecForward, &vecRight, &vecUp ); - pEffect->SetControlPointOrientation( 0, vecForward, vecRight, vecUp ); + Warning( "StartParticleEffect: Failed to find precached particle system for %d!!\n", data.m_nHitBox ); } } +} - if ( pEffect.IsValid() && pEffect->IsValid() ) - { - if ( data.m_bCustomColors ) - { - pEffect->SetControlPoint( CUSTOM_COLOR_CP1, data.m_CustomColors.m_vecColor1 ); - pEffect->SetControlPoint( CUSTOM_COLOR_CP2, data.m_CustomColors.m_vecColor2 ); - } +void ParticleEffectCallback( const CEffectData &data ) +{ + // NOTE: This is because this effect doesn't need to participate + // in the precache validation tests. Particle systems used with this + // effect must already be precached. + g_pPrecacheSystem->EndLimitedResourceAccess( ); - if ( data.m_bControlPoint1 ) - { - pEffect->SetControlPoint( 1, data.m_ControlPoint1.m_vecOffset ); - } - } + // From networking always go draw for all local players + StartParticleEffect( data, -1 ); } -DECLARE_CLIENT_EFFECT( "ParticleEffect", ParticleEffectCallback ); +DECLARE_CLIENT_EFFECT( ParticleEffect, ParticleEffectCallback ) //====================================================================================================================== @@ -266,9 +387,31 @@ void ParticleEffectStopCallback( const CEffectData &data ) C_BaseEntity *pEnt = C_BaseEntity::Instance( data.m_hEntity ); if ( pEnt ) { + if ( data.m_nHitBox > 0 ) + { + if ( pEnt->IsWorld() ) + { + if ( data.m_nHitBox > 0 ) + { + CNewParticleEffect::RemoveParticleEffect( data.m_nHitBox ); + } + } + else + { + CParticleSystemDefinition *pDef = g_pParticleSystemMgr->FindPrecachedParticleSystem( data.m_nHitBox ); + + if ( pDef ) + { + pEnt->ParticleProp()->StopParticlesNamed( pDef->GetName(), true ); + } + } + } + else + { pEnt->ParticleProp()->StopEmission(); } } } +} -DECLARE_CLIENT_EFFECT( "ParticleEffectStop", ParticleEffectStopCallback ); +DECLARE_CLIENT_EFFECT( ParticleEffectStop, ParticleEffectStopCallback ); diff --git a/game/client/c_physbox.cpp b/game/client/c_physbox.cpp index 17d352bdd..b28539b01 100644 --- a/game/client/c_physbox.cpp +++ b/game/client/c_physbox.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // diff --git a/game/client/c_physbox.h b/game/client/c_physbox.h index c42a3a9d9..86cf7c410 100644 --- a/game/client/c_physbox.h +++ b/game/client/c_physbox.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // diff --git a/game/client/c_physics_prop_statue.cpp b/game/client/c_physics_prop_statue.cpp new file mode 100644 index 000000000..67da35282 --- /dev/null +++ b/game/client/c_physics_prop_statue.cpp @@ -0,0 +1,63 @@ +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// + +#include "cbase.h" +#include "c_physics_prop_statue.h" +#include "debugoverlay_shared.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +IMPLEMENT_CLIENTCLASS_DT(C_StatueProp, DT_StatueProp, CStatueProp) + RecvPropEHandle( RECVINFO( m_hInitBaseAnimating ) ), + RecvPropBool( RECVINFO( m_bShatter ) ), + RecvPropInt( RECVINFO( m_nShatterFlags ) ), + RecvPropVector( RECVINFO( m_vShatterPosition ) ), + RecvPropVector( RECVINFO( m_vShatterForce ) ), +END_RECV_TABLE() + +C_StatueProp::C_StatueProp() +{ +} + +C_StatueProp::~C_StatueProp() +{ +} + +void C_StatueProp::Spawn( void ) +{ + BaseClass::Spawn(); + + m_EntClientFlags |= ENTCLIENTFLAG_DONTUSEIK; +} + +void C_StatueProp::ComputeWorldSpaceSurroundingBox( Vector *pVecWorldMins, Vector *pVecWorldMaxs ) +{ + CBaseAnimating *pBaseAnimating = m_hInitBaseAnimating; + + if ( pBaseAnimating ) + { + pBaseAnimating->CollisionProp()->WorldSpaceSurroundingBounds( pVecWorldMins, pVecWorldMaxs ); + } +} + + +void C_StatueProp::OnDataChanged( DataUpdateType_t updateType ) +{ + BaseClass::OnDataChanged( updateType ); + + if ( m_bShatter ) + { + // Here's the networked data to use with my effect + //m_nShatterFlags; + //m_vShatterPosition; + //m_vShatterForce; + + //FIXME: shatter effects should call a function so derived classes can make their own + // Do shatter effects here + } +} diff --git a/game/client/c_physics_prop_statue.h b/game/client/c_physics_prop_statue.h new file mode 100644 index 000000000..dfcdcdb05 --- /dev/null +++ b/game/client/c_physics_prop_statue.h @@ -0,0 +1,49 @@ +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_PHYSICS_PROP_STATUE_H +#define C_PHYSICS_PROP_STATUE_H + +#ifdef _WIN32 +#pragma once +#endif + + +#include "c_physicsprop.h" + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_StatueProp : public C_PhysicsProp +{ +public: + DECLARE_CLASS( C_StatueProp, C_PhysicsProp ); + DECLARE_CLIENTCLASS(); + + C_StatueProp(); + virtual ~C_StatueProp(); + + virtual void Spawn( void ); + + virtual void ComputeWorldSpaceSurroundingBox( Vector *pVecWorldMins, Vector *pVecWorldMaxs ); + + virtual void OnDataChanged( DataUpdateType_t updateType ); + +public: + + CHandle m_hInitBaseAnimating; + + bool m_bShatter; + int m_nShatterFlags; + Vector m_vShatterPosition; + Vector m_vShatterForce; +}; + + +#endif // C_PHYSICS_PROP_STATUE_H \ No newline at end of file diff --git a/game/client/c_physicsprop.cpp b/game/client/c_physicsprop.cpp index 515c70cfa..f9b66088f 100644 --- a/game/client/c_physicsprop.cpp +++ b/game/client/c_physicsprop.cpp @@ -1,8 +1,8 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // -//=============================================================================// +//===========================================================================// #include "cbase.h" #include "model_types.h" #include "vcollide.h" @@ -12,7 +12,6 @@ #include "engine/ivmodelinfo.h" #include "physics.h" #include "view.h" -#include "clienteffectprecachesystem.h" #include "c_physicsprop.h" #include "tier0/vprof.h" #include "ivrenderview.h" @@ -20,17 +19,15 @@ // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" -#define PBR_CHANGE - IMPLEMENT_CLIENTCLASS_DT(C_PhysicsProp, DT_PhysicsProp, CPhysicsProp) RecvPropBool( RECVINFO( m_bAwake ) ), + RecvPropInt( RECVINFO( m_spawnflags ) ), END_RECV_TABLE() -#ifdef PBR_CHANGE - ConVar r_PhysPropStaticLighting( "r_PhysPropStaticLighting", "0" ); -#else - ConVar r_PhysPropStaticLighting( "r_PhysPropStaticLighting", "1" ); -#endif +ConVar r_PhysPropStaticLighting( "r_PhysPropStaticLighting", "1" ); + +// @MULTICORE (toml 9/18/2006): this visualization will need to be implemented elsewhere +ConVar r_visualizeproplightcaching( "r_visualizeproplightcaching", "0" ); //----------------------------------------------------------------------------- @@ -43,6 +40,8 @@ C_PhysicsProp::C_PhysicsProp( void ) // default true so static lighting will get recomputed when we go to sleep m_bAwakeLastTime = true; + + m_bCanUseStaticLighting = false; } //----------------------------------------------------------------------------- @@ -53,18 +52,85 @@ C_PhysicsProp::~C_PhysicsProp( void ) } -// @MULTICORE (toml 9/18/2006): this visualization will need to be implemented elsewhere -ConVar r_visualizeproplightcaching( "r_visualizeproplightcaching", "0" ); +// Used to indicate if we can use the static lighting baking +//----------------------------------------------------------------------------- +void C_PhysicsProp::OnDataChanged( DataUpdateType_t type ) +{ + BaseClass::OnDataChanged( type ); + + m_bCanUseStaticLighting = modelinfo->UsesStaticLighting( GetModel() ); + if ( m_bCanUseStaticLighting ) + { + CreateModelInstance(); + } +} + + +//----------------------------------------------------------------------------- +// Hooks for the fast model rendering path +//----------------------------------------------------------------------------- +IClientModelRenderable* C_PhysicsProp::GetClientModelRenderable() +{ + // Can't do this debug mode through the fast path since it uses + // color modulation, which we don't support yet. + if ( !BaseClass::GetClientModelRenderable() ) + return NULL; + + if ( ( m_bAwakeLastTime != m_bAwake ) && r_visualizeproplightcaching.GetBool() ) + return NULL; + + // NOTE: This works because GetClientModelRenderable() is only queried + // if the prop is known by the viewrender system to be opaque already + // so we need no other opacity checks here. + return this; +} + +bool C_PhysicsProp::GetRenderData( void *pData, ModelDataCategory_t nCategory ) +{ + switch ( nCategory ) + { + case MODEL_DATA_LIGHTING_MODEL: + { + // FIXME: Cache bCanBeStaticLit off in OnDataChanged? + if ( !m_bCanUseStaticLighting || !r_PhysPropStaticLighting.GetBool() ) + { + *(RenderableLightingModel_t*)pData = LIGHTING_MODEL_STANDARD; + return true; + } + + if ( m_bAwakeLastTime && !m_bAwake ) + { + // transition to sleep, bake lighting now, once + if ( !modelrender->RecomputeStaticLighting( GetModelInstance() ) ) + { + // Failed to bake, don't indicate it's asleep yet, use normal model + *(RenderableLightingModel_t*)pData = LIGHTING_MODEL_STANDARD; + return true; + } + } + + *(RenderableLightingModel_t*)pData = m_bAwake ? LIGHTING_MODEL_STANDARD : LIGHTING_MODEL_PHYSICS_PROP; + m_bAwakeLastTime = m_bAwake; + } + return true; + + default: + return BaseClass::GetRenderData( pData, nCategory ); + } +} + +//----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // Purpose: Draws the object // Input : flags - //----------------------------------------------------------------------------- bool C_PhysicsProp::OnInternalDrawModel( ClientModelRenderInfo_t *pInfo ) { - CreateModelInstance(); + if ( !m_bCanUseStaticLighting || !r_PhysPropStaticLighting.GetBool() ) + return true; - if ( r_PhysPropStaticLighting.GetBool() && m_bAwakeLastTime != m_bAwake ) + if ( m_bAwakeLastTime != m_bAwake ) { if ( m_bAwakeLastTime && !m_bAwake ) { @@ -88,7 +154,7 @@ bool C_PhysicsProp::OnInternalDrawModel( ClientModelRenderInfo_t *pInfo ) } } - if ( !m_bAwake && r_PhysPropStaticLighting.GetBool() ) + if ( !m_bAwake ) { // going to sleep, have static lighting pInfo->flags |= STUDIO_STATIC_LIGHTING; @@ -96,6 +162,5 @@ bool C_PhysicsProp::OnInternalDrawModel( ClientModelRenderInfo_t *pInfo ) // track state m_bAwakeLastTime = m_bAwake; - return true; } diff --git a/game/client/c_physicsprop.h b/game/client/c_physicsprop.h index 9c8804e4d..c5d073029 100644 --- a/game/client/c_physicsprop.h +++ b/game/client/c_physicsprop.h @@ -1,8 +1,8 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // -//=============================================================================// +//===========================================================================// #ifndef C_PHYSICSPROP_H #define C_PHYSICSPROP_H @@ -11,6 +11,7 @@ #endif #include "c_breakableprop.h" + //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- @@ -20,15 +21,27 @@ class C_PhysicsProp : public C_BreakableProp public: DECLARE_CLIENTCLASS(); + // Inherited from IClientUnknown +public: + virtual IClientModelRenderable* GetClientModelRenderable(); + + // Inherited from IClientModelRenderable +public: + virtual bool GetRenderData( void *pData, ModelDataCategory_t nCategory ); + + // Other public methods +public: C_PhysicsProp(); - ~C_PhysicsProp(); + virtual ~C_PhysicsProp(); + virtual void OnDataChanged( DataUpdateType_t type ); virtual bool OnInternalDrawModel( ClientModelRenderInfo_t *pInfo ); protected: // Networked vars. bool m_bAwake; bool m_bAwakeLastTime; + bool m_bCanUseStaticLighting; }; #endif // C_PHYSICSPROP_H diff --git a/game/client/c_physmagnet.cpp b/game/client/c_physmagnet.cpp index 08a0f0041..77c554155 100644 --- a/game/client/c_physmagnet.cpp +++ b/game/client/c_physmagnet.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // @@ -46,7 +46,7 @@ void RecvProxyArrayLength_MagnetAttachedArray( void *pStruct, int objectID, int { C_PhysMagnet *pMagnet = (C_PhysMagnet*)pStruct; - if ( pMagnet->m_aAttachedObjectsFromServer.Size() != currentArrayLength ) + if ( pMagnet->m_aAttachedObjectsFromServer.Count() != currentArrayLength ) pMagnet->m_aAttachedObjectsFromServer.SetSize( currentArrayLength ); } diff --git a/game/client/c_pixel_visibility.cpp b/game/client/c_pixel_visibility.cpp index d95bb540f..5bce1d867 100644 --- a/game/client/c_pixel_visibility.cpp +++ b/game/client/c_pixel_visibility.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // @@ -10,13 +10,15 @@ #include "c_pixel_visibility.h" #include "materialsystem/imesh.h" #include "materialsystem/imaterial.h" -#include "clienteffectprecachesystem.h" +#include "precache_register.h" #include "view.h" #include "viewrender.h" #include "utlmultilist.h" #include "vprof.h" -#include "icommandline.h" -#include "sourcevr/isourcevirtualreality.h" + +// NOTE: This has to be the last file included! +#include "tier0/memdbgon.h" + static void PixelvisDrawChanged( IConVar *pPixelvisVar, const char *pOld, float flOldValue ); @@ -25,22 +27,6 @@ ConVar r_dopixelvisibility( "r_dopixelvisibility", "1" ); ConVar r_drawpixelvisibility( "r_drawpixelvisibility", "0", 0, "Show the occlusion proxies", PixelvisDrawChanged ); ConVar r_pixelvisibility_spew( "r_pixelvisibility_spew", "0" ); -#ifdef OSX - // GLMgr will set this one to "1" if it senses the new post-10.6.4 driver (m_hasPerfPackage1) - ConVar gl_can_query_fast( "gl_can_query_fast", "0" ); - - static bool HasFastQueries( void ) - { - return gl_can_query_fast.GetBool(); - } -#else - // non OSX path - static bool HasFastQueries( void ) - { - return true; - } -#endif - extern ConVar building_cubemaps; #ifndef _X360 @@ -49,6 +35,38 @@ const float MIN_PROXY_PIXELS = 5.0f; const float MIN_PROXY_PIXELS = 25.0f; #endif + +extern view_id_t CurrentViewID(); + +struct OcclusionHandleViewIDPair_t +{ + OcclusionQueryObjectHandle_t hOcclusionHandle; + int iViewID; + int iLastFrameRendered; +}; + +struct OcclusionQueryHiddenData_t +{ + COcclusionQuerySet *pOwner; + CUtlVector occlusionHandles[MAX_SPLITSCREEN_PLAYERS]; +}; + +static CUtlVector s_OcclusionQueries; +static inline int FindQueryHandlePairIndex( OcclusionQueryHiddenData_t *pData, int iViewID, int iSplitScreenSlot ) +{ + int iPairCount = pData->occlusionHandles[iSplitScreenSlot].Count(); + OcclusionHandleViewIDPair_t *pPairs = pData->occlusionHandles[iSplitScreenSlot].Base(); + + for( int i = 0; i != iPairCount; ++i ) + { + if( pPairs[i].iViewID == iViewID ) + return i; + } + + return pData->occlusionHandles[iSplitScreenSlot].InvalidIndex(); +} + + float PixelVisibility_DrawProxy( IMatRenderContext *pRenderContext, OcclusionQueryObjectHandle_t queryHandle, Vector origin, float scale, float proxyAspect, IMaterial *pMaterial, bool screenspace ) { Vector point; @@ -231,14 +249,18 @@ class CPixelVisibilityQuery CPixelVisibilityQuery(); ~CPixelVisibilityQuery(); bool IsValid(); - bool IsForView( int viewID ); + bool IsForView( int nPlayerSlot, int viewID ); bool IsActive(); float GetFractionVisible( float fadeTimeInv ); void IssueQuery( IMatRenderContext *pRenderContext, float proxySize, float proxyAspect, IMaterial *pMaterial, bool sizeIsScreenSpace ); void IssueCountingQuery( IMatRenderContext *pRenderContext, float proxySize, float proxyAspect, IMaterial *pMaterial, bool sizeIsScreenSpace ); void ResetOcclusionQueries(); - void SetView( int viewID ) - { + void SetView( int nPlayerSlot, int viewID ) + { + // This is necessary since player slot is stored in 2 bits + COMPILE_TIME_ASSERT( MAX_SPLITSCREEN_PLAYERS <= 4 ); + + Assert( nPlayerSlot >= 0 && nPlayerSlot < MAX_SPLITSCREEN_PLAYERS ); m_viewID = viewID; m_brightnessTarget = 0.0f; m_clipFraction = 1.0f; @@ -246,6 +268,7 @@ class CPixelVisibilityQuery m_failed = false; m_wasQueriedThisFrame = false; m_hasValidQueryResults = false; + m_nPlayerSlot = nPlayerSlot; } public: @@ -259,16 +282,17 @@ class CPixelVisibilityQuery unsigned short m_wasQueriedThisFrame : 1; unsigned short m_failed : 1; unsigned short m_hasValidQueryResults : 1; - unsigned short m_pad : 13; + unsigned short m_nPlayerSlot : 2; + unsigned short m_pad : 11; unsigned short m_viewID; - friend void PixelVisibility_ShiftVisibilityViews( int iSourceViewID, int iDestViewID ); //need direct access to private data to make shifting smooth + friend void PixelVisibility_ShiftVisibilityViews( int nPlayerSlot, int iSourceViewID, int iDestViewID ); //need direct access to private data to make shifting smooth }; CPixelVisibilityQuery::CPixelVisibilityQuery() { CMatRenderContextPtr pRenderContext( materials ); - SetView( 0xFFFF ); + SetView( 0, 0xFFFF ); m_queryHandle = pRenderContext->CreateOcclusionQueryObject(); m_queryHandleCount = pRenderContext->CreateOcclusionQueryObject(); } @@ -314,18 +338,20 @@ bool CPixelVisibilityQuery::IsValid() { return (m_queryHandle != INVALID_OCCLUSION_QUERY_OBJECT_HANDLE) ? true : false; } -bool CPixelVisibilityQuery::IsForView( int viewID ) + +bool CPixelVisibilityQuery::IsForView( int nPlayerSlot, int viewID ) { - return m_viewID == viewID ? true : false; + return ( m_viewID == viewID ) && ( nPlayerSlot == m_nPlayerSlot ); } bool CPixelVisibilityQuery::IsActive() { - return (gpGlobals->framecount - m_frameIssued) > 1 ? false : true; + return ( gpGlobals->framecount - m_frameIssued ) > 1 ? false : true; } float CPixelVisibilityQuery::GetFractionVisible( float fadeTimeInv ) { + if ( !IsValid() ) return 0.0f; @@ -345,7 +371,7 @@ float CPixelVisibilityQuery::GetFractionVisible( float fadeTimeInv ) if ( r_pixelvisibility_spew.GetBool() && CurrentViewID() == 0 ) { - DevMsg( 1, "Pixels visible: %d (qh:%d) Pixels possible: %d (qh:%d) (frame:%d)\n", pixels, (int)(intp)m_queryHandle, pixelsPossible, (int)(intp)m_queryHandleCount, gpGlobals->framecount ); + DevMsg( 1, "Pixels visible: %d (qh:%d) Pixels possible: %d (qh:%d) (frame:%d)\n", pixels, m_queryHandle, pixelsPossible, m_queryHandleCount, gpGlobals->framecount ); } if ( pixels < 0 || pixelsPossible < 0 ) @@ -376,7 +402,7 @@ float CPixelVisibilityQuery::GetFractionVisible( float fadeTimeInv ) if ( r_pixelvisibility_spew.GetBool() && CurrentViewID() == 0 ) { - DevMsg( 1, "Pixels visible: %d (qh:%d) (frame:%d)\n", pixels, (int)(intp)m_queryHandle, gpGlobals->framecount ); + DevMsg( 1, "Pixels visible: %d (qh:%d) (frame:%d)\n", pixels, m_queryHandle, gpGlobals->framecount ); } if ( pixels < 0 ) @@ -415,23 +441,24 @@ void CPixelVisibilityQuery::IssueQuery( IMatRenderContext *pRenderContext, float if ( r_pixelvisibility_spew.GetBool() && CurrentViewID() == 0 ) { - DevMsg( 1, "Draw Proxy: qh:%d org:<%d,%d,%d> (frame:%d)\n", (int)(intp)m_queryHandle, (int)m_origin[0], (int)m_origin[1], (int)m_origin[2], gpGlobals->framecount ); + DevMsg( 1, "Draw Proxy: qh:%d org:<%d,%d,%d> (frame:%d)\n", m_queryHandle, (int)m_origin[0], (int)m_origin[1], (int)m_origin[2], gpGlobals->framecount ); } m_clipFraction = PixelVisibility_DrawProxy( pRenderContext, m_queryHandle, m_origin, proxySize, proxyAspect, pMaterial, sizeIsScreenSpace ); if ( m_clipFraction < 0 ) { // NOTE: In this case, the proxy wasn't issued cause it was offscreen - // can't set the m_frameissued field since that would cause it to get marked as failed + // can't set the m_frameissued[ slot ] field since that would cause it to get marked as failed m_clipFraction = 0; m_wasQueriedThisFrame = false; m_failed = false; return; } } -#ifndef PORTAL // FIXME: In portal we query visibility multiple times per frame because of portal renders! - Assert ( ( m_frameIssued != gpGlobals->framecount ) || UseVR() ); -#endif + + // In split screen we can issue these multiple times + Assert( m_frameIssued != gpGlobals->framecount); + m_frameIssued = gpGlobals->framecount; m_wasQueriedThisFrame = false; @@ -458,10 +485,10 @@ void CPixelVisibilityQuery::IssueCountingQuery( IMatRenderContext *pRenderContex } //Precache the effects -CLIENTEFFECT_REGISTER_BEGIN( PrecacheOcclusionProxy ) -CLIENTEFFECT_MATERIAL( "engine/occlusionproxy" ) -CLIENTEFFECT_MATERIAL( "engine/occlusionproxy_countdraw" ) -CLIENTEFFECT_REGISTER_END() +PRECACHE_REGISTER_BEGIN( GLOBAL, PrecacheOcclusionProxy ) +PRECACHE( MATERIAL, "engine/occlusionproxy" ) +PRECACHE( MATERIAL, "engine/occlusionproxy_countdraw" ) +PRECACHE_REGISTER_END() class CPixelVisibilitySystem : public CAutoGameSystem { @@ -476,8 +503,8 @@ class CPixelVisibilitySystem : public CAutoGameSystem float GetFractionVisible( const pixelvis_queryparams_t ¶ms, pixelvis_handle_t *queryHandle ); void EndView(); void EndScene(); - unsigned short FindQueryForView( CPixelVisSet *pSet, int viewID ); - unsigned short FindOrCreateQueryForView( CPixelVisSet *pSet, int viewID ); + unsigned short FindQueryForView( CPixelVisSet *pSet, int nPlayerSlot, int viewID ); + unsigned short FindOrCreateQueryForView( CPixelVisSet *pSet, int nPlayerSlot, int viewID ); void DeleteUnusedQueries( CPixelVisSet *pSet, bool bDeleteAll ); void DeleteUnusedSets( bool bDeleteAll ); @@ -507,7 +534,7 @@ class CPixelVisibilitySystem : public CAutoGameSystem bool m_drawQueries; - friend void PixelVisibility_ShiftVisibilityViews( int iSourceViewID, int iDestViewID ); //need direct access to private data to make shifting smooth + friend void PixelVisibility_ShiftVisibilityViews( int nPlayerSlot, int iSourceViewID, int iDestViewID ); //need direct access to private data to make shifting smooth }; static CPixelVisibilitySystem g_PixelVisibilitySystem; @@ -520,10 +547,7 @@ CPixelVisibilitySystem::CPixelVisibilitySystem() : CAutoGameSystem( "CPixelVisib // Level init, shutdown void CPixelVisibilitySystem::LevelInitPreEntity() { - bool fastqueries = HasFastQueries(); - // printf("\n ** fast queries: %s **", fastqueries?"true":"false" ); - - m_hwCanTestGlows = r_dopixelvisibility.GetBool() && fastqueries && engine->GetDXSupportLevel() >= 80; + m_hwCanTestGlows = r_dopixelvisibility.GetBool(); if ( m_hwCanTestGlows ) { CMatRenderContextPtr pRenderContext( materials ); @@ -568,12 +592,16 @@ float CPixelVisibilitySystem::GetFractionVisible( const pixelvis_queryparams_t & { return GlowSightDistance( params.position, true ) > 0 ? 1.0f : 0.0f; } + if ( CurrentViewID() < 0 ) return 0.0f; + ASSERT_LOCAL_PLAYER_RESOLVABLE(); + int nPlayerSlot = GET_ACTIVE_SPLITSCREEN_SLOT(); + CPixelVisSet *pSet = FindOrCreatePixelVisSet( params, queryHandle ); Assert( pSet ); - unsigned short node = FindOrCreateQueryForView( pSet, CurrentViewID() ); + unsigned short node = FindOrCreateQueryForView( pSet, nPlayerSlot, CurrentViewID() ); m_queryList[node].m_origin = params.position; float fraction = m_queryList[node].GetFractionVisible( pSet->fadeTimeInv ); pSet->MarkActive(); @@ -588,6 +616,9 @@ void CPixelVisibilitySystem::EndView() if ( m_setList.Head( m_activeSetsList ) == m_setList.InvalidIndex() ) return; + ASSERT_LOCAL_PLAYER_RESOLVABLE(); + int nPlayerSlot = GET_ACTIVE_SPLITSCREEN_SLOT(); + CMatRenderContextPtr pRenderContext( materials ); IMaterial *pProxy = m_drawQueries ? m_pDrawMaterial : m_pProxyMaterial; @@ -601,7 +632,7 @@ void CPixelVisibilitySystem::EndView() while( node != m_setList.InvalidIndex() ) { CPixelVisSet *pSet = &m_setList[node]; - unsigned short queryNode = FindQueryForView( pSet, CurrentViewID() ); + unsigned short queryNode = FindQueryForView( pSet, nPlayerSlot, CurrentViewID() ); if ( queryNode != m_queryList.InvalidIndex() ) { m_queryList[queryNode].IssueCountingQuery( pRenderContext, pSet->proxySize, pSet->proxyAspect, pProxy, pSet->sizeIsScreenSpace ); @@ -616,7 +647,7 @@ void CPixelVisibilitySystem::EndView() while( node != m_setList.InvalidIndex() ) { CPixelVisSet *pSet = &m_setList[node]; - unsigned short queryNode = FindQueryForView( pSet, CurrentViewID() ); + unsigned short queryNode = FindQueryForView( pSet, nPlayerSlot, CurrentViewID() ); if ( queryNode != m_queryList.InvalidIndex() ) { m_queryList[queryNode].IssueQuery( pRenderContext, pSet->proxySize, pSet->proxyAspect, pProxy, pSet->sizeIsScreenSpace ); @@ -631,26 +662,26 @@ void CPixelVisibilitySystem::EndScene() DeleteUnusedSets(false); } -unsigned short CPixelVisibilitySystem::FindQueryForView( CPixelVisSet *pSet, int viewID ) +unsigned short CPixelVisibilitySystem::FindQueryForView( CPixelVisSet *pSet, int nPlayerSlot, int viewID ) { unsigned short node = m_queryList.Head( pSet->queryList ); while ( node != m_queryList.InvalidIndex() ) { - if ( m_queryList[node].IsForView( viewID ) ) + if ( m_queryList[node].IsForView( nPlayerSlot, viewID ) ) return node; node = m_queryList.Next( node ); } return m_queryList.InvalidIndex(); } -unsigned short CPixelVisibilitySystem::FindOrCreateQueryForView( CPixelVisSet *pSet, int viewID ) +unsigned short CPixelVisibilitySystem::FindOrCreateQueryForView( CPixelVisSet *pSet, int nPlayerSlot, int viewID ) { - unsigned short node = FindQueryForView( pSet, viewID ); + unsigned short node = FindQueryForView( pSet, nPlayerSlot, viewID ); if ( node != m_queryList.InvalidIndex() ) return node; node = AllocQuery(); m_queryList.LinkToHead( pSet->queryList, node ); - m_queryList[node].SetView( viewID ); + m_queryList[node].SetView( nPlayerSlot, viewID ); return node; } @@ -817,8 +848,6 @@ void PixelVisibility_EndCurrentView() void PixelVisibility_EndScene() { - tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ ); - g_PixelVisibilitySystem.EndScene(); } @@ -836,13 +865,13 @@ float PixelVisibility_FractionVisible( const pixelvis_queryparams_t ¶ms, pix bool PixelVisibility_IsAvailable() { - bool fastqueries = HasFastQueries(); - return r_dopixelvisibility.GetBool() && fastqueries && g_PixelVisibilitySystem.SupportsOcclusion(); + return r_dopixelvisibility.GetBool() && g_PixelVisibilitySystem.SupportsOcclusion(); } + //this originally called a class function of CPixelVisibiltySystem to keep the work clean, but that function needed friend access to CPixelVisibilityQuery //and I didn't want to make the whole class a friend or shift all the functions and class declarations around in this file -void PixelVisibility_ShiftVisibilityViews( int iSourceViewID, int iDestViewID ) +void PixelVisibility_ShiftVisibilityViews( int nPlayerSlot, int iSourceViewID, int iDestViewID ) { unsigned short node = g_PixelVisibilitySystem.m_setList.Head( g_PixelVisibilitySystem.m_activeSetsList ); while ( node != g_PixelVisibilitySystem.m_setList.InvalidIndex() ) @@ -850,8 +879,8 @@ void PixelVisibility_ShiftVisibilityViews( int iSourceViewID, int iDestViewID ) unsigned short next = g_PixelVisibilitySystem.m_setList.Next( node ); CPixelVisSet *pSet = &g_PixelVisibilitySystem.m_setList[node]; - unsigned short iSourceQueryNode = g_PixelVisibilitySystem.FindQueryForView( pSet, iSourceViewID ); - unsigned short iDestQueryNode = g_PixelVisibilitySystem.FindQueryForView( pSet, iDestViewID ); + unsigned short iSourceQueryNode = g_PixelVisibilitySystem.FindQueryForView( pSet, nPlayerSlot, iSourceViewID ); + unsigned short iDestQueryNode = g_PixelVisibilitySystem.FindQueryForView( pSet, nPlayerSlot, iDestViewID ); if( iDestQueryNode != g_PixelVisibilitySystem.m_queryList.InvalidIndex() ) { @@ -873,8 +902,240 @@ void PixelVisibility_ShiftVisibilityViews( int iSourceViewID, int iDestViewID ) node = next; } + + for( int i = 0; i != s_OcclusionQueries.Count(); ++i ) + { + int iPairCount = s_OcclusionQueries[i].occlusionHandles[nPlayerSlot].Count(); + OcclusionHandleViewIDPair_t *pPairs = s_OcclusionQueries[i].occlusionHandles[nPlayerSlot].Base(); + int iSourceIndex, iDestIndex, iInvalidIndex; + iDestIndex = iSourceIndex = iInvalidIndex = s_OcclusionQueries[i].occlusionHandles[nPlayerSlot].InvalidIndex(); + for( int j = 0; j != iPairCount; ++j ) + { + if( pPairs[j].iViewID == iSourceViewID ) + { + iSourceIndex = j; + if( iDestIndex != iInvalidIndex ) + break; + } + + if( pPairs[j].iViewID == iDestViewID ) + { + iDestIndex = j; + if( iSourceIndex != iInvalidIndex ) + break; + } + } + + if( iSourceIndex != iInvalidIndex ) + { + //change view id on source + pPairs[iSourceIndex].iViewID = iDestViewID; + } + + if( iDestIndex != iInvalidIndex ) + { + //destroy dest + materials->GetRenderContext()->DestroyOcclusionQueryObject( pPairs[iDestIndex].hOcclusionHandle ); + s_OcclusionQueries[i].occlusionHandles[nPlayerSlot].FastRemove( iDestIndex ); + } + } +} + + + +COcclusionQuerySet::COcclusionQuerySet( void ) +{ + OcclusionQueryHiddenData_t &data = s_OcclusionQueries[s_OcclusionQueries.AddToTail()]; + data.pOwner = this; + m_pManagedData = &data; + + //handle base address shifting + if( s_OcclusionQueries.Count() > 1 ) + { + OcclusionQueryHiddenData_t &baseData = s_OcclusionQueries[0]; + if( baseData.pOwner->m_pManagedData != &baseData ) + { + for( int i = 0; i != s_OcclusionQueries.Count(); ++i ) + { + s_OcclusionQueries[i].pOwner->m_pManagedData = &s_OcclusionQueries[i]; + } + } + } } +COcclusionQuerySet::~COcclusionQuerySet( void ) +{ + int iIndex; + for( iIndex = 0; iIndex != s_OcclusionQueries.Count(); ++iIndex ) + { + if( &s_OcclusionQueries[iIndex] == m_pManagedData ) + break; + } + if( iIndex != s_OcclusionQueries.Count() ) + { + //destroy query handles + { + CMatRenderContextPtr pRenderContext( materials ); + OcclusionQueryHiddenData_t &data = s_OcclusionQueries[iIndex]; + for( int i = 0; i != MAX_SPLITSCREEN_PLAYERS; ++i ) + { + for( int j = 0; j != data.occlusionHandles[i].Count(); ++j ) + { + pRenderContext->DestroyOcclusionQueryObject( data.occlusionHandles[i].Element(j).hOcclusionHandle ); + } + } + } + + s_OcclusionQueries.FastRemove( iIndex ); + if( s_OcclusionQueries.Count() != 0 ) + { + s_OcclusionQueries[iIndex].pOwner->m_pManagedData = &s_OcclusionQueries[iIndex]; + //handle base address shifting + if( s_OcclusionQueries.Count() > 1 ) + { + OcclusionQueryHiddenData_t &baseData = s_OcclusionQueries[iIndex == 0 ? 1 : 0]; + if( baseData.pOwner->m_pManagedData != &baseData ) + { + for( int i = 0; i != s_OcclusionQueries.Count(); ++i ) + { + s_OcclusionQueries[i].pOwner->m_pManagedData = &s_OcclusionQueries[i]; + } + } + } + } + } +} + + + +void COcclusionQuerySet::BeginQueryDrawing( int iViewID, int iSplitScreenSlot ) +{ + OcclusionQueryHiddenData_t *pData = (OcclusionQueryHiddenData_t *)m_pManagedData; + + int iIndex = FindQueryHandlePairIndex( pData, iViewID, iSplitScreenSlot ); + if( iIndex == pData->occlusionHandles[iSplitScreenSlot].InvalidIndex() ) + { + //create a new one + iIndex = pData->occlusionHandles[iSplitScreenSlot].AddToTail(); + OcclusionHandleViewIDPair_t &Entry = pData->occlusionHandles[iSplitScreenSlot].Element(iIndex); + Entry.iViewID = iViewID; + Entry.hOcclusionHandle = materials->GetRenderContext()->CreateOcclusionQueryObject(); + materials->GetRenderContext()->ResetOcclusionQueryObject( Entry.hOcclusionHandle ); + } + + materials->GetRenderContext()->BeginOcclusionQueryDrawing( pData->occlusionHandles[iSplitScreenSlot].Element(iIndex).hOcclusionHandle ); + pData->occlusionHandles[iSplitScreenSlot].Element(iIndex).iLastFrameRendered = gpGlobals->framecount; +} + +void COcclusionQuerySet::BeginQueryDrawing( void ) +{ + return BeginQueryDrawing( CurrentViewID(), GET_ACTIVE_SPLITSCREEN_SLOT() ); +} + + + +void COcclusionQuerySet::EndQueryDrawing( int iViewID, int iSplitScreenSlot ) +{ + OcclusionQueryHiddenData_t *pData = (OcclusionQueryHiddenData_t *)m_pManagedData; + + int iIndex = FindQueryHandlePairIndex( pData, iViewID, iSplitScreenSlot ); + if( iIndex != pData->occlusionHandles[iSplitScreenSlot].InvalidIndex() ) + { + materials->GetRenderContext()->EndOcclusionQueryDrawing( pData->occlusionHandles[iSplitScreenSlot].Element(iIndex).hOcclusionHandle ); + } +} + +void COcclusionQuerySet::EndQueryDrawing( void ) +{ + return EndQueryDrawing( CurrentViewID(), GET_ACTIVE_SPLITSCREEN_SLOT() ); +} + + + +int COcclusionQuerySet::QueryNumPixelsRendered( int iViewID, int iSplitScreenSlot ) +{ + OcclusionQueryHiddenData_t *pData = (OcclusionQueryHiddenData_t *)m_pManagedData; + + int iIndex = FindQueryHandlePairIndex( pData, iViewID, iSplitScreenSlot ); + if( iIndex != pData->occlusionHandles[iSplitScreenSlot].InvalidIndex() ) + { + return materials->GetRenderContext()->OcclusionQuery_GetNumPixelsRendered( pData->occlusionHandles[iSplitScreenSlot].Element(iIndex).hOcclusionHandle ); + } + + return 0; +} + +int COcclusionQuerySet::QueryNumPixelsRendered( void ) +{ + return QueryNumPixelsRendered( CurrentViewID(), GET_ACTIVE_SPLITSCREEN_SLOT() ); +} + + + +float COcclusionQuerySet::QueryPercentageOfScreenRendered( int iViewID, int iSplitScreenSlot ) +{ + OcclusionQueryHiddenData_t *pData = (OcclusionQueryHiddenData_t *)m_pManagedData; + + int iIndex = FindQueryHandlePairIndex( pData, iViewID, iSplitScreenSlot ); + if( iIndex != pData->occlusionHandles[iSplitScreenSlot].InvalidIndex() ) + { + int iX, iY, iWidth, iHeight; + materials->GetRenderContext()->GetViewport( iX, iY, iWidth, iHeight ); + return ((float)materials->GetRenderContext()->OcclusionQuery_GetNumPixelsRendered( pData->occlusionHandles[iSplitScreenSlot].Element(iIndex).hOcclusionHandle )) / ((float)(iWidth * iHeight)); + } + + return 0.0f; +} + +float COcclusionQuerySet::QueryPercentageOfScreenRendered( void ) +{ + return QueryPercentageOfScreenRendered( CurrentViewID(), GET_ACTIVE_SPLITSCREEN_SLOT() ); +} + +int COcclusionQuerySet::QueryNumPixelsRenderedForAllViewsLastFrame( int iSplitScreenSlot ) +{ + OcclusionQueryHiddenData_t *pData = (OcclusionQueryHiddenData_t *)m_pManagedData; + int iMatchFrame = gpGlobals->framecount - 1; + int iResult = 0; + CMatRenderContextPtr pRenderContext( materials ); + + for( int i = 0; i != pData->occlusionHandles[iSplitScreenSlot].Count(); ++i ) + { + if( pData->occlusionHandles[iSplitScreenSlot].Element(i).iLastFrameRendered == iMatchFrame ) + { + iResult += pRenderContext->OcclusionQuery_GetNumPixelsRendered( pData->occlusionHandles[iSplitScreenSlot].Element(i).hOcclusionHandle ); + } + } + + return iResult; +} + +int COcclusionQuerySet::QueryNumPixelsRenderedForAllViewsLastFrame( void ) +{ + return QueryNumPixelsRenderedForAllViewsLastFrame( GET_ACTIVE_SPLITSCREEN_SLOT() ); +} + + +int COcclusionQuerySet::GetLastFrameDrawn( int iViewID, int iSplitScreenSlot ) +{ + OcclusionQueryHiddenData_t *pData = (OcclusionQueryHiddenData_t *)m_pManagedData; + + int iIndex = FindQueryHandlePairIndex( pData, iViewID, iSplitScreenSlot ); + if( iIndex != pData->occlusionHandles[iSplitScreenSlot].InvalidIndex() ) + { + return pData->occlusionHandles[iSplitScreenSlot].Element(iIndex).iLastFrameRendered; + } + + return -1; +} + +int COcclusionQuerySet::GetLastFrameDrawn( void ) +{ + return GetLastFrameDrawn( CurrentViewID(), GET_ACTIVE_SPLITSCREEN_SLOT() ); +} + + + CON_COMMAND( pixelvis_debug, "Dump debug info" ) { g_PixelVisibilitySystem.DebugInfo(); diff --git a/game/client/c_pixel_visibility.h b/game/client/c_pixel_visibility.h index 3c075140f..d279e9e6a 100644 --- a/game/client/c_pixel_visibility.h +++ b/game/client/c_pixel_visibility.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // @@ -43,7 +43,7 @@ struct pixelvis_queryparams_t float PixelVisibility_FractionVisible( const pixelvis_queryparams_t ¶ms, pixelvis_handle_t *queryHandle ); float StandardGlowBlend( const pixelvis_queryparams_t ¶ms, pixelvis_handle_t *queryHandle, int rendermode, int renderfx, int alpha, float *pscale ); -void PixelVisibility_ShiftVisibilityViews( int iSourceViewID, int iDestViewID ); //mainly needed by portal mod to avoid a pop in visibility when teleporting the player +void PixelVisibility_ShiftVisibilityViews( int nPlayerSlot, int iSourceViewID, int iDestViewID ); //mainly needed by portal mod to avoid a pop in visibility when teleporting the player void PixelVisibility_EndCurrentView(); void PixelVisibility_EndScene(); @@ -52,4 +52,33 @@ float GlowSightDistance( const Vector &glowOrigin, bool bShouldTrace ); // returns true if the video hardware is doing the tests, false is traceline is doing so. bool PixelVisibility_IsAvailable(); +class COcclusionQuerySet //A set of occlusion query handles for the same object in different rendering views. Self-registers and shifts appropriately with portals. +{ +public: + COcclusionQuerySet( void ); + ~COcclusionQuerySet( void ); + + //wrap your draws with these 2 + void BeginQueryDrawing( int iViewID, int iSplitScreenSlot ); + void EndQueryDrawing( int iViewID, int iSplitScreenSlot ); + + //and here's your data, expect a frame of delay for performance reasons + int QueryNumPixelsRendered( int iViewID, int iSplitScreenSlot ); + float QueryPercentageOfScreenRendered( int iViewID, int iSplitScreenSlot ); // (Pixels rendered) / (total screen pixels) + int QueryNumPixelsRenderedForAllViewsLastFrame( int iSplitScreenSlot ); + + int GetLastFrameDrawn( int iViewID, int iSplitScreenSlot ); + + //these implementations call the above with current view id and active splitscreen slot + void BeginQueryDrawing( void ); + void EndQueryDrawing( void ); + int QueryNumPixelsRendered( void ); + float QueryPercentageOfScreenRendered( void ); + int QueryNumPixelsRenderedForAllViewsLastFrame( void ); + int GetLastFrameDrawn( void ); + +private: + void *m_pManagedData; //no need to worry what's under the hood here +}; + #endif // C_PIXEL_VISIBILITY_H diff --git a/game/client/c_plasma.cpp b/game/client/c_plasma.cpp index 71144bf32..75223420c 100644 --- a/game/client/c_plasma.cpp +++ b/game/client/c_plasma.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // @@ -10,7 +10,7 @@ #include "tempent.h" #include "iefx.h" #include "decals.h" -#include "iviewrender.h" +#include "IViewRender.h" #include "engine/ivmodelinfo.h" #include "view.h" @@ -47,7 +47,7 @@ class C_Plasma : public C_BaseEntity C_Plasma(); ~C_Plasma(); - void AddEntity( void ); + bool Simulate( void ); protected: void Update( void ); @@ -198,6 +198,7 @@ C_Plasma::C_Plasma() { m_entFlames[i].Clear(); } + AddToEntityList(ENTITY_LIST_SIMULATE); } C_Plasma::~C_Plasma() @@ -222,11 +223,11 @@ float C_Plasma::GetFlickerScale( void ) //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- -void C_Plasma::AddEntity( void ) +bool C_Plasma::Simulate( void ) { //Only do this if we're active if ( ( m_nFlags & bitsFIRESMOKE_ACTIVE ) == false ) - return; + return false; Update(); AddFlames(); @@ -237,6 +238,7 @@ void C_Plasma::AddEntity( void ) // Note: Sprite renderer assumes scale of 0.0 is 1.0 m_entGlow.SetScale( MAX( 0.0000001f, (m_flScaleRegister*1.5f) + GetFlickerScale() ) ); m_entGlow.SetLocalOriginDim( Z_INDEX, m_entGlow.GetLocalOriginDim( Z_INDEX ) + ( dScale * 32.0f ) ); + return true; } #define FLAME_ALPHA_START 0.8f @@ -269,7 +271,7 @@ void C_Plasma::AddFlames( void ) m_entFlames[i].SetBrightness( 255.0f * alpha ); } - m_entFlames[i].AddToLeafSystem(); + m_entFlames[i].AddToLeafSystem( false ); } } @@ -285,6 +287,11 @@ void C_Plasma::OnDataChanged( DataUpdateType_t updateType ) { Start(); } + + if ( m_nFlags & bitsFIRESMOKE_ACTIVE ) + { + AddToEntityList(ENTITY_LIST_SIMULATE); + } } //----------------------------------------------------------------------------- @@ -331,8 +338,9 @@ void C_Plasma::Start( void ) m_entFlames[i].m_flSpriteFramerate = (float) random->RandomInt( 15, 20 ); m_entFlames[i].SetScale( m_flStartScale ); m_entFlames[i].SetRenderMode( kRenderTransAddFrameBlend ); - m_entFlames[i].m_nRenderFX = kRenderFxNone; - m_entFlames[i].SetRenderColor( 255, 255, 255, 255 ); + m_entFlames[i].SetRenderFX( kRenderFxNone ); + m_entFlames[i].SetRenderColor( 255, 255, 255 ); + m_entFlames[i].SetRenderAlpha( 255 ); m_entFlames[i].SetBrightness( 255 ); m_entFlames[i].index = -1; @@ -352,17 +360,20 @@ void C_Plasma::Start( void ) m_entGlow.SetLocalOrigin( GetLocalOrigin() ); m_entGlow.SetScale( m_flStartScale ); m_entGlow.SetRenderMode( kRenderTransAdd ); - m_entGlow.m_nRenderFX = kRenderFxNone; - m_entGlow.SetRenderColor( 255, 255, 255, 255 ); + m_entGlow.SetRenderFX( kRenderFxNone ); + m_entGlow.SetRenderColor( 255, 255, 255 ); + m_entGlow.SetRenderAlpha( 255 ); m_entGlow.SetBrightness( 255 ); m_entGlow.index = -1; m_flGlowScale = m_flStartScale; - m_entGlow.AddToLeafSystem( RENDER_GROUP_TRANSLUCENT_ENTITY ); + m_entGlow.AddToLeafSystem( false ); for( i=0; i < NUM_CHILD_FLAMES; i++ ) - m_entFlames[i].AddToLeafSystem( RENDER_GROUP_TRANSLUCENT_ENTITY ); + { + m_entFlames[i].AddToLeafSystem( false ); + } } //----------------------------------------------------------------------------- diff --git a/game/client/c_playerlocaldata.h b/game/client/c_playerlocaldata.h index 95b6d48d1..0d0738b18 100644 --- a/game/client/c_playerlocaldata.h +++ b/game/client/c_playerlocaldata.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: Defines the player specific data that is sent only to the player // to whom it belongs. @@ -16,6 +16,14 @@ #include "mathlib/vector.h" #include "playernet_vars.h" +#ifdef CLIENT_DLL +#define CPostProcessController C_PostProcessController +#define CColorCorrection C_ColorCorrection +#endif + +class CPostProcessController; +class CColorCorrection; + //----------------------------------------------------------------------------- // Purpose: Player specific data ( sent only to local player, too ) //----------------------------------------------------------------------------- @@ -30,46 +38,53 @@ class CPlayerLocalData m_iv_vecPunchAngle( "CPlayerLocalData::m_iv_vecPunchAngle" ), m_iv_vecPunchAngleVel( "CPlayerLocalData::m_iv_vecPunchAngleVel" ) { - m_iv_vecPunchAngle.Setup( &m_vecPunchAngle.m_Value, LATCH_SIMULATION_VAR ); - m_iv_vecPunchAngleVel.Setup( &m_vecPunchAngleVel.m_Value, LATCH_SIMULATION_VAR ); + m_iv_vecPunchAngle.Setup( &m_vecPunchAngle, LATCH_SIMULATION_VAR ); + m_iv_vecPunchAngleVel.Setup( &m_vecPunchAngleVel, LATCH_SIMULATION_VAR ); m_flFOVRate = 0; } unsigned char m_chAreaBits[MAX_AREA_STATE_BYTES]; // Area visibility flags. unsigned char m_chAreaPortalBits[MAX_AREA_PORTAL_STATE_BYTES];// Area portal visibility flags. - int m_iHideHUD; // bitfields containing sections of the HUD to hide - +// BEGIN PREDICTION DATA COMPACTION (these fields are together to allow for faster copying in prediction system) + int m_nStepside; + int m_nOldButtons; float m_flFOVRate; // rate at which the FOV changes - + + int m_iHideHUD; // bitfields containing sections of the HUD to hide + int m_nDuckTimeMsecs; + int m_nDuckJumpTimeMsecs; + int m_nJumpTimeMsecs; + + float m_flFallVelocity; + float m_flStepSize; + + CNetworkQAngle( m_vecPunchAngle ); // auto-decaying view angle adjustment + CNetworkQAngle( m_vecPunchAngleVel ); // velocity of auto-decaying view angle adjustment bool m_bDucked; bool m_bDucking; bool m_bInDuckJump; - float m_flDucktime; - float m_flDuckJumpTime; - float m_flJumpTime; - int m_nStepside; - float m_flFallVelocity; - int m_nOldButtons; + bool m_bDrawViewmodel; + bool m_bWearingSuit; + bool m_bPoisoned; + bool m_bAllowAutoMovement; +// END PREDICTION DATA COMPACTION + + bool m_bInLanding; + float m_flLandingTime; + // Base velocity that was passed in to server physics so // client can predict conveyors correctly. Server zeroes it, so we need to store here, too. Vector m_vecClientBaseVelocity; - CNetworkQAngle( m_vecPunchAngle ); // auto-decaying view angle adjustment CInterpolatedVar< QAngle > m_iv_vecPunchAngle; - - CNetworkQAngle( m_vecPunchAngleVel ); // velocity of auto-decaying view angle adjustment CInterpolatedVar< QAngle > m_iv_vecPunchAngleVel; - bool m_bDrawViewmodel; - bool m_bWearingSuit; - bool m_bPoisoned; - float m_flStepSize; - bool m_bAllowAutoMovement; + + // Autoaim + bool m_bAutoAimTarget; // 3d skybox sky3dparams_t m_skybox3d; - // fog params - fogplayerparams_t m_PlayerFog; // audio environment audioparams_t m_audio; diff --git a/game/client/c_playerresource.cpp b/game/client/c_playerresource.cpp index 3732a5471..46db621d8 100644 --- a/game/client/c_playerresource.cpp +++ b/game/client/c_playerresource.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: Entity that propagates general data needed by clients for every player. // @@ -9,21 +9,33 @@ #include "c_team.h" #include "gamestringpool.h" -#ifdef HL2MP -#include "hl2mp_gamerules.h" -#endif - // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" const float PLAYER_RESOURCE_THINK_INTERVAL = 0.2f; +#define PLAYER_UNCONNECTED_NAME "unconnected" +#define PLAYER_DEBUG_NAME "WWWWWWWWWWWWWWW" + +ConVar cl_names_debug( "cl_names_debug", "0", FCVAR_DEVELOPMENTONLY ); + + +void RecvProxy_ChangedTeam( const CRecvProxyData *pData, void *pStruct, void *pOut ) +{ + // Have the regular proxy store the data. + RecvProxy_Int32ToInt32( pData, pStruct, pOut ); + + if ( g_PR ) + { + g_PR->TeamChanged(); + } +} IMPLEMENT_CLIENTCLASS_DT_NOBASE(C_PlayerResource, DT_PlayerResource, CPlayerResource) RecvPropArray3( RECVINFO_ARRAY(m_iPing), RecvPropInt( RECVINFO(m_iPing[0]))), RecvPropArray3( RECVINFO_ARRAY(m_iScore), RecvPropInt( RECVINFO(m_iScore[0]))), RecvPropArray3( RECVINFO_ARRAY(m_iDeaths), RecvPropInt( RECVINFO(m_iDeaths[0]))), RecvPropArray3( RECVINFO_ARRAY(m_bConnected), RecvPropInt( RECVINFO(m_bConnected[0]))), - RecvPropArray3( RECVINFO_ARRAY(m_iTeam), RecvPropInt( RECVINFO(m_iTeam[0]))), + RecvPropArray3( RECVINFO_ARRAY(m_iTeam), RecvPropInt( RECVINFO(m_iTeam[0]), 0, RecvProxy_ChangedTeam )), RecvPropArray3( RECVINFO_ARRAY(m_bAlive), RecvPropInt( RECVINFO(m_bAlive[0]))), RecvPropArray3( RECVINFO_ARRAY(m_iHealth), RecvPropInt( RECVINFO(m_iHealth[0]))), END_RECV_TABLE() @@ -50,6 +62,10 @@ IGameResources * GameResources( void ) { return g_PR; } //----------------------------------------------------------------------------- C_PlayerResource::C_PlayerResource() { + for ( int i=0; iGetPlayerInfo( slot, &sPlayerInfo ) ) + char const *pchPlayerName = PLAYER_UNCONNECTED_NAME; + if ( IsConnected( slot ) && + engine->GetPlayerInfo( slot, &sPlayerInfo ) ) { - m_szName[slot] = AllocPooledString( sPlayerInfo.name ); + pchPlayerName = sPlayerInfo.name; } - else + + if ( !m_szName[slot] || Q_stricmp( m_szName[slot], pchPlayerName ) ) { - m_szName[slot] = m_szUnconnectedName; + m_szName[slot] = AllocPooledString( pchPlayerName ); } } @@ -129,10 +138,13 @@ void C_PlayerResource::ClientThink() //----------------------------------------------------------------------------- const char *C_PlayerResource::GetPlayerName( int iIndex ) { + if ( cl_names_debug.GetInt() ) + return PLAYER_DEBUG_NAME; + if ( iIndex < 1 || iIndex > MAX_PLAYERS ) { Assert( false ); - return PLAYER_ERROR_NAME; + return "ERRORNAME"; } if ( !IsConnected( iIndex ) ) @@ -220,7 +232,6 @@ bool C_PlayerResource::IsHLTV(int index) bool C_PlayerResource::IsReplay(int index) { -#if defined( REPLAY_ENABLED ) if ( !IsConnected( index ) ) return false; @@ -230,7 +241,6 @@ bool C_PlayerResource::IsReplay(int index) { return sPlayerInfo.isreplay; } -#endif return false; } diff --git a/game/client/c_playerresource.h b/game/client/c_playerresource.h index d13f9236c..d6e19da38 100644 --- a/game/client/c_playerresource.h +++ b/game/client/c_playerresource.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: Entity that propagates general data needed by clients for every player. // @@ -16,9 +16,6 @@ #include "c_baseentity.h" #include -#define PLAYER_UNCONNECTED_NAME "unconnected" -#define PLAYER_ERROR_NAME "ERRORNAME" - class C_PlayerResource : public C_BaseEntity, public IGameResources { DECLARE_CLASS( C_PlayerResource, C_BaseEntity ); @@ -55,6 +52,7 @@ public : // IGameResources intreface virtual void ClientThink(); virtual void OnDataChanged(DataUpdateType_t updateType); + virtual void TeamChanged( void ){ } protected: void UpdatePlayerName( int slot ); @@ -70,7 +68,6 @@ public : // IGameResources intreface bool m_bAlive[MAX_PLAYERS+1]; int m_iHealth[MAX_PLAYERS+1]; Color m_Colors[MAX_TEAMS]; - string_t m_szUnconnectedName; }; diff --git a/game/client/c_point_camera.cpp b/game/client/c_point_camera.cpp index 3d6eaa15b..1b5fe4953 100644 --- a/game/client/c_point_camera.cpp +++ b/game/client/c_point_camera.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // @@ -6,10 +6,10 @@ //===========================================================================// #include "cbase.h" -#include "c_point_camera.h" +#include "C_Point_Camera.h" #include "toolframework/itoolframework.h" #include "toolframework_client.h" -#include "tier1/KeyValues.h" +#include "tier1/keyvalues.h" // memdbgon must be the last include file in a .cpp file!!! @@ -19,12 +19,14 @@ IMPLEMENT_CLIENTCLASS_DT( C_PointCamera, DT_PointCamera, CPointCamera ) RecvPropFloat( RECVINFO( m_FOV ) ), RecvPropFloat( RECVINFO( m_Resolution ) ), RecvPropInt( RECVINFO( m_bFogEnable ) ), - RecvPropInt( RECVINFO( m_FogColor ) ), + RecvPropInt( RECVINFO( m_FogColor ), 0, RecvProxy_Int32ToColor32 ), RecvPropFloat( RECVINFO( m_flFogStart ) ), RecvPropFloat( RECVINFO( m_flFogEnd ) ), RecvPropFloat( RECVINFO( m_flFogMaxDensity ) ), - RecvPropInt( RECVINFO( m_bActive ) ), - RecvPropInt( RECVINFO( m_bUseScreenAspectRatio ) ), + RecvPropBool( RECVINFO( m_bActive ) ), + RecvPropBool( RECVINFO( m_bUseScreenAspectRatio ) ), + RecvPropBool( RECVINFO( m_bNoSky ) ), + RecvPropFloat( RECVINFO( m_fBrightness ) ), END_RECV_TABLE() C_EntityClassList g_PointCameraList; diff --git a/game/client/c_point_camera.h b/game/client/c_point_camera.h index 8bca63af4..112eb5d14 100644 --- a/game/client/c_point_camera.h +++ b/game/client/c_point_camera.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // @@ -37,10 +37,12 @@ class C_PointCamera : public C_BaseEntity float GetFogMaxDensity(); float GetFogEnd(); bool UseScreenAspectRatio() const { return m_bUseScreenAspectRatio; } + bool IsSkyEnabled() const { return !m_bNoSky; } + float GetBrightness() const { return m_fBrightness; } virtual void GetToolRecordingState( KeyValues *msg ); -private: +protected: float m_FOV; float m_Resolution; bool m_bFogEnable; @@ -50,6 +52,8 @@ class C_PointCamera : public C_BaseEntity float m_flFogMaxDensity; bool m_bActive; bool m_bUseScreenAspectRatio; + bool m_bNoSky; + float m_fBrightness; public: C_PointCamera *m_pNext; diff --git a/game/client/c_point_commentary_node.cpp b/game/client/c_point_commentary_node.cpp index 47ea96efb..ceb5c4b38 100644 --- a/game/client/c_point_commentary_node.cpp +++ b/game/client/c_point_commentary_node.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======= // // Purpose: // @@ -9,7 +9,7 @@ #include "hudelement.h" #include "clientmode.h" #include -#include +#include #include #include #include @@ -147,8 +147,9 @@ class C_PointCommentaryNode : public C_BaseAnimating { if ( !g_CommentaryNodes.Count() ) { - int iRenderGroup = gHUD.LookupRenderGroupIndexByName( "commentary" ); - gHUD.LockRenderGroup( iRenderGroup ); + HACK_GETLOCALPLAYER_GUARD( "C_PointCommentaryNode::AddAndLockCommentaryHudGroup" ); + int iRenderGroup = GetHud().RegisterForRenderGroup( "commentary" ); + GetHud().LockRenderGroup( iRenderGroup ); } if ( g_CommentaryNodes.Find(this) == g_CommentaryNodes.InvalidIndex() ) @@ -163,8 +164,9 @@ class C_PointCommentaryNode : public C_BaseAnimating if ( !g_CommentaryNodes.Count() ) { - int iRenderGroup = gHUD.LookupRenderGroupIndexByName( "commentary" ); - gHUD.UnlockRenderGroup( iRenderGroup ); + HACK_GETLOCALPLAYER_GUARD( "C_PointCommentaryNode::RemoveAndUnlockCommentaryHudGroup" ); + int iRenderGroup = GetHud().RegisterForRenderGroup( "commentary" ); + GetHud().UnlockRenderGroup( iRenderGroup ); } } @@ -226,6 +228,8 @@ void C_PointCommentaryNode::OnDataChanged( DataUpdateType_t updateType ) if ( m_bWasActive == m_bActive && !m_bRestartAfterRestore ) return; + HACK_GETLOCALPLAYER_GUARD( "C_PointCommentaryNode::OnDataChanged" ); + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); if ( m_bActive && pPlayer ) { @@ -273,10 +277,13 @@ void C_PointCommentaryNode::OnDataChanged( DataUpdateType_t updateType ) (CSoundEnvelopeController::GetController()).Play( m_sndCommentary, 1.0f, 100, m_flStartTime ); } + // Strip the #off of the commentary file path if there is one + char *pcCommentaryWAVPath = V_stristr( (char*)STRING( CSoundEnvelopeController::GetController().SoundGetName( m_sndCommentary ) ) , "commentary" ); + // Get the duration so we know when it finishes - float flDuration = enginesound->GetSoundDuration( STRING( CSoundEnvelopeController::GetController().SoundGetName( m_sndCommentary ) ) ) ; + float flDuration = enginesound->GetSoundDuration( pcCommentaryWAVPath ) ; - CHudCloseCaption *pHudCloseCaption = (CHudCloseCaption *)GET_HUDELEMENT( CHudCloseCaption ); + CHudCloseCaption *pHudCloseCaption = (CHudCloseCaption *)GET_FULLSCREEN_HUDELEMENT( CHudCloseCaption ); if ( pHudCloseCaption ) { // This is where we play the commentary close caption (and lock the other captions out). @@ -353,7 +360,7 @@ bool IsNodeUnderCrosshair( C_BasePlayer *pPlayer ) if ( !tr.m_pEnt ) return false; - return dynamic_cast(tr.m_pEnt); + return dynamic_cast(tr.m_pEnt) ? true : false; } //=================================================================================================================== @@ -366,7 +373,7 @@ DECLARE_HUDELEMENT( CHudCommentary ); //----------------------------------------------------------------------------- CHudCommentary::CHudCommentary( const char *name ) : vgui::Panel( NULL, "HudCommentary" ), CHudElement( name ) { - vgui::Panel *pParent = g_pClientMode->GetViewport(); + vgui::Panel *pParent = GetClientMode()->GetViewport(); SetParent( pParent ); SetPaintBorderEnabled( false ); @@ -392,16 +399,17 @@ void CHudCommentary::ApplySchemeSettings( vgui::IScheme *pScheme ) void CHudCommentary::Paint() { float flDuration = (m_flEndTime - m_flStartTime); - float flPercentage = clamp( ( gpGlobals->curtime - m_flStartTime ) / flDuration, 0.f, 1.f ); + float flPercentage = clamp( ( gpGlobals->curtime - m_flStartTime ) / flDuration, 0, 1 ); if ( !m_hActiveNode ) { if ( !m_bHiding ) { m_bHiding = true; - g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "HideCommentary" ); + GetClientMode()->GetViewportAnimationController()->StartAnimationSequence( "HideCommentary" ); + + CHudCloseCaption *pHudCloseCaption = (CHudCloseCaption *)GET_FULLSCREEN_HUDELEMENT( CHudCloseCaption ); - CHudCloseCaption *pHudCloseCaption = (CHudCloseCaption *)GET_HUDELEMENT( CHudCloseCaption ); if ( pHudCloseCaption ) { pHudCloseCaption->Reset(); @@ -414,7 +422,7 @@ void CHudCommentary::Paint() if ( flPercentage >= 1 && m_hActiveNode ) { m_hActiveNode = NULL; - g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "HideCommentary" ); + GetClientMode()->GetViewportAnimationController()->StartAnimationSequence( "HideCommentary" ); engine->ServerCmd( "commentary_finishnode\n" ); } @@ -546,7 +554,7 @@ void CHudCommentary::StartCommentary( C_PointCommentaryNode *pNode, char *pszSpe // If the commentary just started, play the commentary fade in. if ( fabs(flStartTime - gpGlobals->curtime) < 1.0 ) { - g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "ShowCommentary" ); + GetClientMode()->GetViewportAnimationController()->StartAnimationSequence( "ShowCommentary" ); } else { @@ -583,4 +591,4 @@ bool CommentaryModeShouldSwallowInput( C_BasePlayer *pPlayer ) } return false; -} \ No newline at end of file +} diff --git a/game/client/c_postprocesscontroller.cpp b/game/client/c_postprocesscontroller.cpp new file mode 100644 index 000000000..81e61f395 --- /dev/null +++ b/game/client/c_postprocesscontroller.cpp @@ -0,0 +1,50 @@ +//====== Copyright © 1996-2008, Valve Corporation, All rights reserved. ======= +// +// Purpose: stores map postprocess params +// +//============================================================================= +#include "cbase.h" +#include "C_PostProcessController.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +#ifdef CPostProcessController +#undef CPostProcessController +#endif + +IMPLEMENT_CLIENTCLASS_DT( C_PostProcessController, DT_PostProcessController, CPostProcessController ) + RecvPropArray3( RECVINFO_NAME( m_PostProcessParameters.m_flParameters[0], m_flPostProcessParameters ), POST_PROCESS_PARAMETER_COUNT, RecvPropFloat( RECVINFO_NAME( m_PostProcessParameters.m_flParameters[0], m_flPostProcessParameters[0] ) ) ), + RecvPropBool( RECVINFO(m_bMaster) ) +END_RECV_TABLE() + +C_PostProcessController* C_PostProcessController::ms_pMasterController = NULL; + +//----------------------------------------------------------------------------- +C_PostProcessController::C_PostProcessController( void ) +: m_bMaster( false ) +{ + if ( ms_pMasterController == NULL ) + { + ms_pMasterController = this; + } +} + +//----------------------------------------------------------------------------- +C_PostProcessController::~C_PostProcessController( void ) +{ + if ( ms_pMasterController == this ) + { + ms_pMasterController = NULL; + } +} + +void C_PostProcessController::PostDataUpdate( DataUpdateType_t updateType ) +{ + BaseClass::PostDataUpdate( updateType ); + + if ( m_bMaster ) + { + ms_pMasterController = this; + } +} diff --git a/game/client/c_postprocesscontroller.h b/game/client/c_postprocesscontroller.h new file mode 100644 index 000000000..829694f00 --- /dev/null +++ b/game/client/c_postprocesscontroller.h @@ -0,0 +1,41 @@ +//========= Copyright © 1996-2008, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef C_POSTPROCESSCONTROLLER_H +#define C_POSTPROCESSCONTROLLER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "postprocess_shared.h" + +//============================================================================= +// +// Class Postprocess Controller: +// +class C_PostProcessController : public C_BaseEntity +{ + DECLARE_CLASS( C_PostProcessController, C_BaseEntity ); +public: + DECLARE_CLIENTCLASS(); + + C_PostProcessController(); + virtual ~C_PostProcessController(); + + virtual void PostDataUpdate( DataUpdateType_t updateType ); + + static C_PostProcessController* GetMasterController() { return ms_pMasterController; } + + PostProcessParameters_t m_PostProcessParameters; + +private: + bool m_bMaster; + + static C_PostProcessController* ms_pMasterController; +}; + + +#endif // C_POSTPROCESSCONTROLLER_H diff --git a/game/client/c_prop_hallucination.cpp b/game/client/c_prop_hallucination.cpp new file mode 100644 index 000000000..5fc1abde9 --- /dev/null +++ b/game/client/c_prop_hallucination.cpp @@ -0,0 +1,172 @@ +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + + +#include "cbase.h" +#include "c_baseanimating.h" +#include "materialsystem/imaterialsystem.h" +#include "model_types.h" +#include "viewrender.h" +#include "c_pixel_visibility.h" + +extern view_id_t CurrentViewID(); +extern bool IsMainView( view_id_t id ); + + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + +class C_Prop_Hallucination : public C_BaseAnimating +{ +public: + DECLARE_CLASS( C_Prop_Hallucination, C_BaseAnimating ); + DECLARE_CLIENTCLASS(); + + virtual void Spawn( void ); + virtual void UpdateOnRemove( void ); + //virtual bool ShouldDraw( void ); + virtual int DrawModel( int flags, const RenderableInstance_t &instance ); + virtual ShadowType_t ShadowCastType( void ); + virtual void OnDataChanged( DataUpdateType_t type ); + + + COcclusionQuerySet m_OcclusionSet; + int m_iLastDrawCallFrame; + bool m_bVisibleInAnyViewLastFrame; + //float m_fVisibilityRemaining; //an ill defined measure of how much longer we're visible. When it reaches 0 we no longer show the hallucination until it's recharged to 1. Being occluded before reaching 0 is going to be up in the air on what to do. + double m_fLastStateChangeTime; + bool m_bVisibleEligible; + + bool m_bEnabled; + float m_fVisibleTime; + float m_fRechargeTime; + + static CMaterialReference sm_OcclusionProxyMaterial; +}; + +CMaterialReference C_Prop_Hallucination::sm_OcclusionProxyMaterial; + +IMPLEMENT_CLIENTCLASS_DT( C_Prop_Hallucination, DT_Prop_Hallucination, CProp_Hallucination ) + RecvPropBool( RECVINFO(m_bEnabled) ), + RecvPropFloat( RECVINFO(m_fVisibleTime) ), + RecvPropFloat( RECVINFO(m_fRechargeTime) ), +END_RECV_TABLE() + +//ConVar cl_hallucination_dischargescale( "cl_hallucination_dischargescale", "3000.0", FCVAR_CHEAT, "(delta time) * (percentage of screen drawn to) * (this scale) is how much visibility charge (0.0-1.0) we use up per frame. When it's 0.0 the hallucination is invisible" ); +//ConVar cl_hallucination_visibletime( "cl_hallucination_visibletime", "0.215", FCVAR_CHEAT, "the maximum time (in seconds) from first visible frame to when we stop drawing the hallucination" ); +//ConVar cl_hallucination_rechargetime( "cl_hallucination_rechargetime", "2.0", FCVAR_CHEAT, "How much time must pass without drawing the hallucination before it's eligble to draw again" ); + + +void C_Prop_Hallucination::Spawn( void ) +{ + if( !sm_OcclusionProxyMaterial.IsValid() ) + { + sm_OcclusionProxyMaterial.Init( "engine/occlusionproxy", TEXTURE_GROUP_CLIENT_EFFECTS ); + } + + BaseClass::Spawn(); +} + +void C_Prop_Hallucination::UpdateOnRemove( void ) +{ + BaseClass::UpdateOnRemove(); +} + +void C_Prop_Hallucination::OnDataChanged( DataUpdateType_t type ) +{ + if( !m_bEnabled ) + { + if( m_bVisibleEligible && (m_fLastStateChangeTime != 0.0f) ) + { + m_fLastStateChangeTime = Plat_FloatTime(); + } + m_bVisibleEligible = false; + } +} + +int C_Prop_Hallucination::DrawModel( int flags, const RenderableInstance_t &instance ) +{ + switch( CurrentViewID() ) + { + case VIEW_SHADOW_DEPTH_TEXTURE: + if( m_bVisibleEligible ) + { + return BaseClass::DrawModel( flags, instance ); + } + + default: + if( IsMainView( CurrentViewID() ) ) //VIEW_MAIN and portal views are true + { + break; + } + else + { + return 0; + } + }; + + + bool bSameFrame = (m_iLastDrawCallFrame == gpGlobals->framecount); + + if( (flags & STUDIO_RENDER) && !bSameFrame ) + { + bool bDrewLastFrame = (m_iLastDrawCallFrame == (gpGlobals->framecount - 1)); + if( m_bVisibleEligible ) + { + if( m_fLastStateChangeTime == 0.0 ) //waiting for the first frame of actual visibility mark the state change + { + if( bDrewLastFrame && (m_OcclusionSet.QueryNumPixelsRenderedForAllViewsLastFrame() > 0) ) + { + m_fLastStateChangeTime = Plat_FloatTime();// - gpGlobals->realtime; //state change occurred last frame + } + } + else if( (Plat_FloatTime() - m_fLastStateChangeTime) > m_fVisibleTime ) + { + m_bVisibleEligible = false; + } + } + else + { + if( ((m_fLastStateChangeTime == 0.0f) || (Plat_FloatTime() - m_fLastStateChangeTime) > m_fRechargeTime) && + ((m_OcclusionSet.QueryNumPixelsRenderedForAllViewsLastFrame() == 0) || !bDrewLastFrame) ) + { + m_bVisibleEligible = true; + m_fLastStateChangeTime = 0.0f; + } + } + } + + + if( flags & STUDIO_RENDER ) + { + if( !m_bVisibleEligible ) + { + modelrender->ForcedMaterialOverride( sm_OcclusionProxyMaterial ); + } + m_iLastDrawCallFrame = gpGlobals->framecount; + m_OcclusionSet.BeginQueryDrawing(); + int iRetVal = BaseClass::DrawModel( flags, instance ); + m_OcclusionSet.EndQueryDrawing(); + + if( !m_bVisibleEligible ) + { + modelrender->ForcedMaterialOverride( NULL ); + } + + return iRetVal; + } + else + { + return BaseClass::DrawModel( flags, instance ); + } +} + +ShadowType_t C_Prop_Hallucination::ShadowCastType( void ) +{ + return SHADOWS_NONE; +} diff --git a/game/client/c_prop_vehicle.cpp b/game/client/c_prop_vehicle.cpp index d093656ff..e5b783388 100644 --- a/game/client/c_prop_vehicle.cpp +++ b/game/client/c_prop_vehicle.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // @@ -12,15 +12,9 @@ #include #include #include "view.h" -#include "engine/ivdebugoverlay.h" +#include "engine/IVDebugOverlay.h" #include "movevars_shared.h" #include "iviewrender.h" -#include "vgui/ISurface.h" -#include "client_virtualreality.h" -#include "../hud_crosshair.h" -#include "sourcevr/isourcevirtualreality.h" -// NVNT haptic utils -#include "haptics/haptic_utils.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -149,12 +143,9 @@ void C_PropVehicleDriveable::OnDataChanged( DataUpdateType_t updateType ) { OnEnteredVehicle( m_hPlayer ); SetNextClientThink( CLIENT_THINK_ALWAYS ); - g_ClientVirtualReality.AlignTorsoAndViewToWeapon(); } else if ( !m_hPlayer && m_hPrevPlayer ) { - // NVNT notify haptics system of navigation exit - OnExitedVehicle( m_hPrevPlayer ); // They have just exited the vehicle. // Sometimes we never reach the end of our exit anim, such as if the // animation doesn't have fadeout 0 specified in the QC, so we fail to @@ -247,61 +238,33 @@ void C_PropVehicleDriveable::DrawHudElements( ) if (m_bHasGun) { // draw crosshairs for vehicle gun - pIcon = gHUD.GetIcon( "gunhair" ); + pIcon = HudIcons().GetIcon( "gunhair" ); if ( pIcon != NULL ) { float x, y; + Vector screen; - if( UseVR() ) - { - C_BasePlayer *pPlayer = (C_BasePlayer *)GetPassenger( VEHICLE_ROLE_DRIVER ); - Vector vecStart, vecDirection; - pPlayer->EyePositionAndVectors( &vecStart, &vecDirection, NULL, NULL ); - Vector vecEnd = vecStart + vecDirection * MAX_TRACE_LENGTH; - - trace_t tr; - UTIL_TraceLine( vecStart, vecEnd, MASK_SHOT, this, COLLISION_GROUP_NONE, &tr ); - - Vector screen; - screen.Init(); - ScreenTransform(tr.endpos, screen); - - int vx, vy, vw, vh; - vgui::surface()->GetFullscreenViewport( vx, vy, vw, vh ); - - float screenWidth = vw; - float screenHeight = vh; - - x = 0.5f * ( 1.0f + screen[0] ) * screenWidth + 0.5f; - y = 0.5f * ( 1.0f - screen[1] ) * screenHeight + 0.5f; - } - else - { - Vector screen; - - x = ScreenWidth()/2; - y = ScreenHeight()/2; - -#if TRIANGULATED_CROSSHAIR - ScreenTransform( m_vecGunCrosshair, screen ); - x += 0.5 * screen[0] * ScreenWidth() + 0.5; - y -= 0.5 * screen[1] * ScreenHeight() + 0.5; -#endif - } + x = ScreenWidth()/2; + y = ScreenHeight()/2; + #if TRIANGULATED_CROSSHAIR + ScreenTransform( m_vecGunCrosshair, screen ); + x += 0.5 * screen[0] * ScreenWidth() + 0.5; + y -= 0.5 * screen[1] * ScreenHeight() + 0.5; + #endif x -= pIcon->Width() / 2; y -= pIcon->Height() / 2; - Color clr = ( m_bUnableToFire ) ? gHUD.m_clrCaution : gHUD.m_clrNormal; + Color clr = ( m_bUnableToFire ) ? GetHud().m_clrCaution : GetHud().m_clrNormal; pIcon->DrawSelf( x, y, clr ); } if ( m_nScannerDisabledWeapons ) { // Draw icons for scanners "weps disabled" - pIcon = gHUD.GetIcon( "dmg_bio" ); + pIcon = HudIcons().GetIcon( "dmg_bio" ); if ( pIcon ) { iIconY = 467 - pIcon->Height() / 2; @@ -328,7 +291,7 @@ void C_PropVehicleDriveable::DrawHudElements( ) if ( m_nScannerDisabledVehicle ) { // Draw icons for scanners "vehicle disabled" - pIcon = gHUD.GetIcon( "dmg_bio" ); + pIcon = HudIcons().GetIcon( "dmg_bio" ); if ( pIcon ) { iIconY = 467 - pIcon->Height() / 2; @@ -405,18 +368,5 @@ void C_PropVehicleDriveable::UpdateViewAngles( C_BasePlayer *pLocalPlayer, CUser //----------------------------------------------------------------------------- void C_PropVehicleDriveable::OnEnteredVehicle( C_BaseCombatCharacter *pPassenger ) { -#if defined( WIN32 ) && !defined( _X360 ) - // NVNT notify haptics system of navigation change - HapticsEnteredVehicle(this,pPassenger); -#endif -} - -// NVNT - added function -void C_PropVehicleDriveable::OnExitedVehicle( C_BaseCombatCharacter *pPassenger ) -{ -#if defined( WIN32 ) && !defined( _X360 ) - // NVNT notify haptics system of navigation exit - HapticsExitedVehicle(this,pPassenger); -#endif } diff --git a/game/client/c_prop_vehicle.h b/game/client/c_prop_vehicle.h index 1fb699e48..e11795392 100644 --- a/game/client/c_prop_vehicle.h +++ b/game/client/c_prop_vehicle.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // @@ -8,7 +8,7 @@ #define C_PROP_VEHICLE_H #pragma once -#include "iclientvehicle.h" +#include "IClientVehicle.h" #include "vehicle_viewblend_shared.h" class C_PropVehicleDriveable : public C_BaseAnimating, public IClientVehicle { @@ -77,15 +77,10 @@ class C_PropVehicleDriveable : public C_BaseAnimating, public IClientVehicle public: bool IsRunningEnterExitAnim( void ) { return m_bEnterAnimOn || m_bExitAnimOn; } - // NVNT added to check if the vehicle needs to aim - virtual bool HasGun(void){return m_bHasGun;} protected: virtual void OnEnteredVehicle( C_BaseCombatCharacter *pPassenger ); - // NVNT added to notify haptics system of vehicle exit. - virtual void OnExitedVehicle( C_BaseCombatCharacter *pPassenger ); - virtual void RestrictView( float *pYawBounds, float *pPitchBounds, float *pRollBounds, QAngle &vecViewAngles ); virtual void SetVehicleFOV( float flFOV ) { m_flFOV = flFOV; } diff --git a/game/client/c_props.cpp b/game/client/c_props.cpp index 07f5710d9..e98111165 100644 --- a/game/client/c_props.cpp +++ b/game/client/c_props.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // @@ -118,48 +118,49 @@ unsigned int C_DynamicProp::ComputeClientSideAnimationFlags() // ------------------------------------------------------------------------------------------ // // ------------------------------------------------------------------------------------------ // -class C_BasePropDoor : public C_DynamicProp -{ - DECLARE_CLASS( C_BasePropDoor, C_DynamicProp ); -public: - DECLARE_CLIENTCLASS(); - - // constructor, destructor - C_BasePropDoor( void ); - virtual ~C_BasePropDoor( void ); - - virtual void OnDataChanged( DataUpdateType_t type ); - - virtual bool TestCollision( const Ray_t &ray, unsigned int mask, trace_t& trace ); - -private: - C_BasePropDoor( const C_BasePropDoor & ); -}; - IMPLEMENT_CLIENTCLASS_DT(C_BasePropDoor, DT_BasePropDoor, CBasePropDoor) END_RECV_TABLE() C_BasePropDoor::C_BasePropDoor( void ) { + m_modelChanged = false; } C_BasePropDoor::~C_BasePropDoor( void ) { } +void C_BasePropDoor::PostDataUpdate( DataUpdateType_t updateType ) +{ + if ( updateType == DATA_UPDATE_CREATED ) + { + BaseClass::PostDataUpdate( updateType ); + } + else + { + const model_t *oldModel = GetModel(); + BaseClass::PostDataUpdate( updateType ); + const model_t *newModel = GetModel(); + + if ( oldModel != newModel ) + { + m_modelChanged = true; + } + } +} + void C_BasePropDoor::OnDataChanged( DataUpdateType_t type ) { BaseClass::OnDataChanged( type ); - if ( type == DATA_UPDATE_CREATED ) + bool bCreate = (type == DATA_UPDATE_CREATED) ? true : false; + if ( VPhysicsGetObject() && m_modelChanged ) { - SetSolid(SOLID_VPHYSICS); - VPhysicsInitShadow( false, false ); - } - else if ( VPhysicsGetObject() ) - { - VPhysicsGetObject()->UpdateShadow( GetAbsOrigin(), GetAbsAngles(), false, TICK_INTERVAL ); + VPhysicsDestroyObject(); + m_modelChanged = false; + bCreate = true; } + VPhysicsShadowDataChanged(bCreate, this); } bool C_BasePropDoor::TestCollision( const Ray_t &ray, unsigned int mask, trace_t& trace ) @@ -167,6 +168,7 @@ bool C_BasePropDoor::TestCollision( const Ray_t &ray, unsigned int mask, trace_t if ( !VPhysicsGetObject() ) return false; + MDLCACHE_CRITICAL_SECTION(); CStudioHdr *pStudioHdr = GetModelPtr( ); if (!pStudioHdr) return false; @@ -175,13 +177,29 @@ bool C_BasePropDoor::TestCollision( const Ray_t &ray, unsigned int mask, trace_t if ( trace.DidHit() ) { - trace.surface.surfaceProps = VPhysicsGetObject()->GetMaterialIndex(); + trace.contents = pStudioHdr->contents(); + // use the default surface properties + trace.surface.name = "**studio**"; + trace.surface.flags = 0; + trace.surface.surfaceProps = pStudioHdr->GetSurfaceProp(); + return true; } return false; } +//just need to reference by classname in portal +class C_PropDoorRotating : public C_BasePropDoor +{ +public: + DECLARE_CLASS( C_PropDoorRotating, C_BasePropDoor ); + DECLARE_CLIENTCLASS(); +}; + +IMPLEMENT_CLIENTCLASS_DT(C_PropDoorRotating, DT_PropDoorRotating, CPropDoorRotating) +END_RECV_TABLE() + // ------------------------------------------------------------------------------------------ // // Special version of func_physbox. // ------------------------------------------------------------------------------------------ // diff --git a/game/client/c_props.h b/game/client/c_props.h index bb8af27b7..1509b4c57 100644 --- a/game/client/c_props.h +++ b/game/client/c_props.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======= // // Purpose: // @@ -42,4 +42,27 @@ class C_DynamicProp : public C_BreakableProp Vector m_vecCachedRenderMaxs; }; +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class C_BasePropDoor : public C_DynamicProp +{ + DECLARE_CLASS( C_BasePropDoor, C_DynamicProp ); +public: + DECLARE_CLIENTCLASS(); + + // constructor, destructor + C_BasePropDoor( void ); + virtual ~C_BasePropDoor( void ); + + virtual void OnDataChanged( DataUpdateType_t type ); + virtual void PostDataUpdate( DataUpdateType_t updateType ); + + virtual bool TestCollision( const Ray_t &ray, unsigned int mask, trace_t& trace ); + +private: + C_BasePropDoor( const C_BasePropDoor & ); + bool m_modelChanged; +}; + #endif // C_PROPS_H diff --git a/game/client/c_ragdoll_manager.cpp b/game/client/c_ragdoll_manager.cpp index 6ed0d6351..cbb1deb23 100644 --- a/game/client/c_ragdoll_manager.cpp +++ b/game/client/c_ragdoll_manager.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // diff --git a/game/client/c_recipientfilter.cpp b/game/client/c_recipientfilter.cpp index ece0fabe9..0c29546b5 100644 --- a/game/client/c_recipientfilter.cpp +++ b/game/client/c_recipientfilter.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // @@ -67,7 +67,7 @@ bool C_RecipientFilter::IsReliable( void ) const int C_RecipientFilter::GetRecipientCount( void ) const { - return m_Recipients.Size(); + return m_Recipients.Count(); } int C_RecipientFilter::GetRecipientIndex( int slot ) const @@ -80,17 +80,18 @@ int C_RecipientFilter::GetRecipientIndex( int slot ) const void C_RecipientFilter::AddAllPlayers( void ) { - if ( !C_BasePlayer::GetLocalPlayer() ) + if ( !C_BasePlayer::HasAnyLocalPlayer() ) return; m_Recipients.RemoveAll(); - AddRecipient( C_BasePlayer::GetLocalPlayer() ); + FOR_EACH_VALID_SPLITSCREEN_PLAYER( hh ) + { + AddRecipient( C_BasePlayer::GetLocalPlayer( hh ) ); + } } void C_RecipientFilter::AddRecipient( C_BasePlayer *player ) { - Assert( player ); - if ( !player ) return; @@ -100,7 +101,7 @@ void C_RecipientFilter::AddRecipient( C_BasePlayer *player ) // then don't send it to the local player again. if ( m_bUsingPredictionRules ) { - Assert( player == C_BasePlayer::GetLocalPlayer() ); + Assert( C_BasePlayer::IsLocalPlayer( player ) ); Assert( prediction->InPrediction() ); // Only add local player if this is the first time doing prediction @@ -115,7 +116,7 @@ void C_RecipientFilter::AddRecipient( C_BasePlayer *player ) return; // this is a client side filter, only add the local player - if ( !player->IsLocalPlayer() ) + if ( !C_BasePlayer::IsLocalPlayer( player ) ) return; m_Recipients.AddToTail( index ); @@ -142,18 +143,21 @@ void C_RecipientFilter::RemoveRecipientsByTeam( C_Team *team ) Assert ( 0 ); } -void C_RecipientFilter::AddPlayersFromBitMask( CBitVec< ABSOLUTE_PLAYER_LIMIT >& playerbits ) -{ - C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); - if ( !pPlayer ) - return; +void C_RecipientFilter::AddPlayersFromBitMask( CPlayerBitVec& playerbits ) +{ + FOR_EACH_VALID_SPLITSCREEN_PLAYER( hh ) + { + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer( hh ); + if ( !pPlayer ) + continue; - // only add the local player on client side - if ( !playerbits[ pPlayer->index ] ) - return; + // only add the local player on client side + if ( !playerbits[ pPlayer->index ] ) + continue; - AddRecipient( pPlayer ); + AddRecipient( pPlayer ); + } } void C_RecipientFilter::AddRecipientsByPVS( const Vector& origin ) @@ -177,8 +181,7 @@ void C_RecipientFilter::UsePredictionRules( void ) return; } - C_BasePlayer *local = C_BasePlayer::GetLocalPlayer(); - if ( !local ) + if ( !C_BasePlayer::HasAnyLocalPlayer() ) { Assert( 0 ); return; @@ -193,7 +196,23 @@ void C_RecipientFilter::UsePredictionRules( void ) if ( !g_RecipientFilterPredictionSystem.CanPredict() ) { - RemoveRecipient( local ); + FOR_EACH_VALID_SPLITSCREEN_PLAYER( hh ) + { + RemoveRecipient( C_BasePlayer::GetLocalPlayer( hh ) ); + } + } +} + +void C_RecipientFilter::RemoveSplitScreenPlayers() +{ + for ( int i = GetRecipientCount() - 1; i >= 0; --i ) + { + int idx = m_Recipients[ i ]; + C_BasePlayer *pPlayer = UTIL_PlayerByIndex( idx ); + if ( !pPlayer || !pPlayer->IsSplitScreenPlayer() ) + continue; + + m_Recipients.Remove( i ); } } @@ -212,10 +231,15 @@ void C_RecipientFilter::SetIgnorePredictionCull( bool ignore ) m_bIgnorePredictionCull = ignore; } + CLocalPlayerFilter::CLocalPlayerFilter() { - if ( C_BasePlayer::GetLocalPlayer() ) + for ( int hh = 0; hh < MAX_SPLITSCREEN_PLAYERS; ++hh ) { - AddRecipient( C_BasePlayer::GetLocalPlayer() ); + ACTIVE_SPLITSCREEN_PLAYER_GUARD( hh ); + if ( C_BasePlayer::GetLocalPlayer() ) + { + AddRecipient( C_BasePlayer::GetLocalPlayer() ); + } } -} \ No newline at end of file +} diff --git a/game/client/c_recipientfilter.h b/game/client/c_recipientfilter.h index d501452f8..b2c7d0ba7 100644 --- a/game/client/c_recipientfilter.h +++ b/game/client/c_recipientfilter.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // @@ -58,9 +58,11 @@ class C_RecipientFilter : public IRecipientFilter bool IgnorePredictionCull( void ) const; void SetIgnorePredictionCull( bool ignore ); - void AddPlayersFromBitMask( CBitVec< ABSOLUTE_PLAYER_LIMIT >& playerbits ); + void AddPlayersFromBitMask( CPlayerBitVec& playerbits ); -//private: + void RemoveSplitScreenPlayers(); + +private: bool m_bReliable; bool m_bInitMessage; @@ -175,15 +177,4 @@ class CLocalPlayerFilter : public C_RecipientFilter CLocalPlayerFilter( void ); }; -class CUIFilter : public C_RecipientFilter -{ -public: - CUIFilter( void ) - { - m_Recipients.AddToTail( 1 ); -// AddRecipient( 0 ); - } -}; - - #endif // C_RECIPIENTFILTER_H diff --git a/game/client/c_rope.cpp b/game/client/c_rope.cpp index 9b6e0880c..6a01783f3 100644 --- a/game/client/c_rope.cpp +++ b/game/client/c_rope.cpp @@ -1,18 +1,15 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2007, Valve Corporation, All rights reserved. ======// // // Purpose: // // $NoKeywords: $ -//=====================================================================================// +//===========================================================================// #include "cbase.h" #include "c_rope.h" #include "beamdraw.h" #include "view.h" #include "env_wind_shared.h" #include "input.h" -#ifdef TF_CLIENT_DLL -#include "cdll_util.h" -#endif #include "rope_helpers.h" #include "engine/ivmodelinfo.h" #include "tier0/vprof.h" @@ -28,6 +25,11 @@ // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" +//Precache the rope shadowdepth material +PRECACHE_REGISTER_BEGIN( GLOBAL, PrecacheRopes ) + PRECACHE( MATERIAL, "cable/rope_shadowdepth" ) +PRECACHE_REGISTER_END() + void RecvProxy_RecomputeSprings( const CRecvProxyData *pData, void *pStruct, void *pOut ) { // Have the regular proxy store the data. @@ -39,6 +41,7 @@ void RecvProxy_RecomputeSprings( const CRecvProxyData *pData, void *pStruct, voi IMPLEMENT_CLIENTCLASS_DT_NOBASE( C_RopeKeyframe, DT_RopeKeyframe, CRopeKeyframe ) + RecvPropInt( RECVINFO(m_nChangeCount) ), RecvPropInt( RECVINFO(m_iRopeMaterialModelIndex) ), RecvPropEHandle( RECVINFO(m_hStartPoint) ), RecvPropEHandle( RECVINFO(m_hEndPoint) ), @@ -60,13 +63,22 @@ IMPLEMENT_CLIENTCLASS_DT_NOBASE( C_RopeKeyframe, DT_RopeKeyframe, CRopeKeyframe RecvPropInt( RECVINFO_NAME(m_hNetworkMoveParent, moveparent), 0, RecvProxy_IntToMoveParent ), RecvPropInt( RECVINFO( m_iParentAttachment ) ), + +#if 1 +// #ifndef _X360 -- X360 client and Win32 XLSP dedicated server need equivalent SendTables + RecvPropInt( RECVINFO( m_nMinCPULevel ) ), + RecvPropInt( RECVINFO( m_nMaxCPULevel ) ), + RecvPropInt( RECVINFO( m_nMinGPULevel ) ), + RecvPropInt( RECVINFO( m_nMaxGPULevel ) ), +#endif + END_RECV_TABLE() #define ROPE_IMPULSE_SCALE 20 #define ROPE_IMPULSE_DECAY 0.95 static ConVar rope_shake( "rope_shake", "0" ); -static ConVar rope_subdiv( "rope_subdiv", "2", 0, "Rope subdivision amount", true, 0, true, MAX_ROPE_SUBDIVS ); +static ConVar rope_subdiv( "rope_subdiv", "2", FCVAR_MATERIAL_SYSTEM_THREAD, "Rope subdivision amount", true, 0, true, MAX_ROPE_SUBDIVS ); static ConVar rope_collide( "rope_collide", "1", 0, "Collide rope with the world" ); static ConVar rope_smooth( "rope_smooth", "1", 0, "Do an antialiasing effect on ropes" ); @@ -80,10 +92,7 @@ static ConVar rope_smooth_maxalpha( "rope_smooth_maxalpha", "0.5", 0, "Alpha for static ConVar mat_fullbright( "mat_fullbright", "0", FCVAR_CHEAT ); // get it from the engine static ConVar r_drawropes( "r_drawropes", "1", FCVAR_CHEAT ); -static ConVar r_queued_ropes( "r_queued_ropes", "1" ); static ConVar r_ropetranslucent( "r_ropetranslucent", "1"); -static ConVar r_rope_holiday_light_scale( "r_rope_holiday_light_scale", "0.055", FCVAR_DEVELOPMENTONLY ); -static ConVar r_ropes_holiday_lights_allowed( "r_ropes_holiday_lights_allowed", "1", FCVAR_DEVELOPMENTONLY ); static ConVar rope_wind_dist( "rope_wind_dist", "1000", 0, "Don't use CPU applying small wind gusts to ropes when they're past this distance." ); static ConVar rope_averagelight( "rope_averagelight", "1", 0, "Makes ropes use average of cubemap lighting instead of max intensity." ); @@ -98,11 +107,9 @@ static ConVar rope_solid_minalpha( "rope_solid_minalpha", "0.0" ); static ConVar rope_solid_maxalpha( "rope_solid_maxalpha", "1" ); -static CCycleCount g_RopeCollideTicks; -static CCycleCount g_RopeDrawTicks; -static CCycleCount g_RopeSimulateTicks; static int g_nRopePointsSimulated; +static IMaterial *g_pSplineCableShadowdepth = NULL; // Active ropes. CUtlLinkedList g_Ropes; @@ -118,107 +125,14 @@ class CFullBrightLightValuesInit } } g_FullBrightLightValuesInit; -// Precalculated info for rope subdivision. -static Vector g_RopeSubdivs[MAX_ROPE_SUBDIVS][MAX_ROPE_SUBDIVS]; -class CSubdivInit -{ -public: - CSubdivInit() - { - for ( int iSubdiv=0; iSubdiv < MAX_ROPE_SUBDIVS; iSubdiv++ ) - { - for( int i=0; i <= iSubdiv; i++ ) - { - float t = (float)(i+1) / (iSubdiv+1); - g_RopeSubdivs[iSubdiv][i].Init( t, t*t, t*t*t ); - } - } - } -} g_SubdivInit; - -//interesting barbed-wire-looking effect -static int g_nBarbedSubdivs = 3; -static Vector g_BarbedSubdivs[MAX_ROPE_SUBDIVS] = { Vector(1.5, 1.5*1.5, 1.5*1.5*1.5), - Vector(-0.5, -0.5 * -0.5, -0.5*-0.5*-0.5), - Vector(0.5, 0.5*0.5, 0.5*0.5*0.5) }; - // This can be exposed through the entity if we ever care. static float g_flLockAmount = 0.1; static float g_flLockFalloff = 0.3; - - - -class CQueuedRopeMemoryManager -{ -public: - CQueuedRopeMemoryManager( void ) - { - m_nCurrentStack = 0; - MEM_ALLOC_CREDIT(); - m_QueuedRopeMemory[0].Init( 131072, 0, 16384 ); - m_QueuedRopeMemory[1].Init( 131072, 0, 16384 ); - } - ~CQueuedRopeMemoryManager( void ) - { - m_QueuedRopeMemory[0].FreeAll( true ); - m_QueuedRopeMemory[1].FreeAll( true ); - for( int i = 0; i != 2; ++i ) - { - for( int j = m_DeleteOnSwitch[i].Count(); --j >= 0; ) - { - free( m_DeleteOnSwitch[i].Element(j) ); - } - - m_DeleteOnSwitch[i].RemoveAll(); - } - } - - void SwitchStack( void ) - { - m_nCurrentStack = 1 - m_nCurrentStack; - m_QueuedRopeMemory[m_nCurrentStack].FreeAll( false ); - - for( int i = m_DeleteOnSwitch[m_nCurrentStack].Count(); --i >= 0; ) - { - free( m_DeleteOnSwitch[m_nCurrentStack].Element(i) ); - } - m_DeleteOnSwitch[m_nCurrentStack].RemoveAll(); - } - - inline void *Alloc( size_t bytes ) - { - MEM_ALLOC_CREDIT(); - void *pReturn = m_QueuedRopeMemory[m_nCurrentStack].Alloc( bytes, false ); - if( pReturn == NULL ) - { - int iMaxSize = m_QueuedRopeMemory[m_nCurrentStack].GetMaxSize(); - Warning( "Overflowed rope queued rendering memory stack. Needed %d, have %d/%d\n", bytes, iMaxSize - m_QueuedRopeMemory[m_nCurrentStack].GetUsed(), iMaxSize ); - pReturn = malloc( bytes ); - m_DeleteOnSwitch[m_nCurrentStack].AddToTail( pReturn ); - } - return pReturn; - } - - CMemoryStack m_QueuedRopeMemory[2]; - int m_nCurrentStack; - CUtlVector m_DeleteOnSwitch[2]; //when we overflow the stack, we do new/delete -}; - //============================================================================= // // Rope mananger. // -struct RopeSegData_t -{ - int m_nSegmentCount; - BeamSeg_t m_Segments[MAX_ROPE_SEGMENTS]; - float m_BackWidths[MAX_ROPE_SEGMENTS]; - - // If this is less than rope_solid_minwidth and rope_solid_minalpha is 0, then we can avoid drawing.. - float m_flMaxBackWidth; -}; - class CRopeManager : public IRopeManager { public: @@ -229,65 +143,35 @@ class CRopeManager : public IRopeManager void ResetRenderCache( void ); void AddToRenderCache( C_RopeKeyframe *pRope ); void DrawRenderCache( bool bShadowDepth ); - void OnRenderStart( void ) - { - m_QueuedModeMemory.SwitchStack(); - } - - void SetHolidayLightMode( bool bHoliday ) { m_bDrawHolidayLights = bHoliday; } - bool IsHolidayLightMode( void ); - int GetHolidayLightStyle( void ); - -private: - struct RopeRenderData_t; -public: - void DrawRenderCache_NonQueued( bool bShadowDepth, RopeRenderData_t *pRenderCache, int nRenderCacheCount, const Vector &vCurrentViewForward, const Vector &vCurrentViewOrigin, C_RopeKeyframe::BuildRopeQueuedData_t *pBuildRopeQueuedData ); - void ResetSegmentCache( int nMaxSegments ); - RopeSegData_t *GetNextSegmentFromCache( void ); - enum { MAX_ROPE_RENDERCACHE = 128 }; void RemoveRopeFromQueuedRenderCaches( C_RopeKeyframe *pRope ); private: - - void RenderNonSolidRopes( IMatRenderContext *pRenderContext, IMaterial *pMaterial, int nVertCount, int nIndexCount ); - void RenderSolidRopes( IMatRenderContext *pRenderContext, IMaterial *pMaterial, int nVertCount, int nIndexCount, bool bRenderNonSolid ); - -private: - struct RopeRenderData_t { IMaterial *m_pSolidMaterial; - IMaterial *m_pBackMaterial; int m_nCacheCount; C_RopeKeyframe *m_aCache[MAX_ROPE_RENDERCACHE]; }; - CUtlVector m_aRenderCache; - int m_nSegmentCacheCount; - CUtlVector m_aSegmentCache; - CThreadFastMutex m_RenderCacheMutex; //there's only any contention during the switch from r_queued_ropes on to off - - //in queued material system mode we need to store off data for later use. - CQueuedRopeMemoryManager m_QueuedModeMemory; - - IMaterial* m_pDepthWriteMaterial; - - struct RopeQueuedRenderCache_t { RopeRenderData_t *pCaches; int iCacheCount; + CThreadFastMutex *m_pRopeDataMutex; RopeQueuedRenderCache_t( void ) : pCaches(NULL), iCacheCount(0) { }; }; - CUtlLinkedList m_RopeQueuedRenderCaches; + void DrawRenderCache_NonQueued( bool bShadowDepth, RopeRenderData_t *pRenderCache, int nRenderCacheCount, const Vector &vCurrentViewForward, const Vector &vCurrentViewOrigin, C_RopeKeyframe::BuildRopeQueuedData_t *pBuildRopeQueuedData, CThreadFastMutex *pRopeDataMutex ); - bool m_bDrawHolidayLights; - bool m_bHolidayInitialized; - int m_nHolidayLightsStyle; + CUtlVector m_aRenderCache; + + //in queued material system mode we need to store off data for later use. + IMaterial* m_pDepthWriteMaterial; + CUtlLinkedList m_RopeQueuedRenderCaches; + CThreadFastMutex m_RopeQueuedRenderCaches_Mutex; //mutex just for changing m_RopeQueuedRenderCaches }; static CRopeManager s_RopeManager; @@ -298,24 +182,13 @@ IRopeManager *RopeManager() } -inline bool ShouldUseFakeAA( IMaterial *pBackMaterial ) -{ - return pBackMaterial && rope_smooth.GetInt() && engine->GetDXSupportLevel() > 70 && !g_pMaterialSystemHardwareConfig->IsAAEnabled(); -} - - //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CRopeManager::CRopeManager() { m_aRenderCache.Purge(); - m_aSegmentCache.Purge(); - m_nSegmentCacheCount = 0; m_pDepthWriteMaterial = NULL; - m_bDrawHolidayLights = false; - m_bHolidayInitialized = false; - m_nHolidayLightsStyle = 0; } //----------------------------------------------------------------------------- @@ -323,21 +196,7 @@ CRopeManager::CRopeManager() //----------------------------------------------------------------------------- CRopeManager::~CRopeManager() { - int nRenderCacheCount = m_aRenderCache.Count(); - for ( int iRenderCache = 0; iRenderCache < nRenderCacheCount; ++iRenderCache ) - { - if ( m_aRenderCache[iRenderCache].m_pSolidMaterial ) - { - m_aRenderCache[iRenderCache].m_pSolidMaterial->DecrementReferenceCount(); - } - if ( m_aRenderCache[iRenderCache].m_pBackMaterial ) - { - m_aRenderCache[iRenderCache].m_pBackMaterial->DecrementReferenceCount(); - } - } - m_aRenderCache.Purge(); - m_aSegmentCache.Purge(); } //----------------------------------------------------------------------------- @@ -367,8 +226,7 @@ void CRopeManager::AddToRenderCache( C_RopeKeyframe *pRope ) int nRenderCacheCount = m_aRenderCache.Count(); for ( ; iRenderCache < nRenderCacheCount; ++iRenderCache ) { - if ( ( pRope->GetSolidMaterial() == m_aRenderCache[iRenderCache].m_pSolidMaterial ) && - ( pRope->GetBackMaterial() == m_aRenderCache[iRenderCache].m_pBackMaterial ) ) + if ( pRope->GetSolidMaterial() == m_aRenderCache[iRenderCache].m_pSolidMaterial ) break; } @@ -378,15 +236,6 @@ void CRopeManager::AddToRenderCache( C_RopeKeyframe *pRope ) { int iRenderCache = m_aRenderCache.AddToTail(); m_aRenderCache[iRenderCache].m_pSolidMaterial = pRope->GetSolidMaterial(); - if ( m_aRenderCache[iRenderCache].m_pSolidMaterial ) - { - m_aRenderCache[iRenderCache].m_pSolidMaterial->IncrementReferenceCount(); - } - m_aRenderCache[iRenderCache].m_pBackMaterial = pRope->GetBackMaterial(); - if ( m_aRenderCache[iRenderCache].m_pBackMaterial ) - { - m_aRenderCache[iRenderCache].m_pBackMaterial->IncrementReferenceCount(); - } m_aRenderCache[iRenderCache].m_nCacheCount = 0; } @@ -399,22 +248,30 @@ void CRopeManager::AddToRenderCache( C_RopeKeyframe *pRope ) m_aRenderCache[iRenderCache].m_aCache[m_aRenderCache[iRenderCache].m_nCacheCount] = pRope; ++m_aRenderCache[iRenderCache].m_nCacheCount; } - -void CRopeManager::DrawRenderCache_NonQueued( bool bShadowDepth, RopeRenderData_t *pRenderCache, int nRenderCacheCount, const Vector &vCurrentViewForward, const Vector &vCurrentViewOrigin, C_RopeKeyframe::BuildRopeQueuedData_t *pBuildRopeQueuedData ) +#define OUTPUT_2SPLINE_VERTS( t, u ) \ + meshBuilder.Color4ub( nRed, nGreen, nBlue, nAlpha ); \ + meshBuilder.Position3f( (t), u, 0 ); \ + meshBuilder.TexCoord4fv( 0, vecP0.Base() ); \ + meshBuilder.TexCoord4fv( 1, vecP1.Base() ); \ + meshBuilder.TexCoord4fv( 2, vecP2.Base() ); \ + meshBuilder.TexCoord4fv( 3, vecP3.Base() ); \ + meshBuilder.AdvanceVertexF(); \ + meshBuilder.Color4ub( nRed, nGreen, nBlue, nAlpha ); \ + meshBuilder.Position3f( (t), u, 1 ); \ + meshBuilder.TexCoord4fv( 0, vecP0.Base() ); \ + meshBuilder.TexCoord4fv( 1, vecP1.Base() ); \ + meshBuilder.TexCoord4fv( 2, vecP2.Base() ); \ + meshBuilder.TexCoord4fv( 3, vecP3.Base() ); \ + meshBuilder.AdvanceVertexF(); + + +void CRopeManager::DrawRenderCache_NonQueued( bool bShadowDepth, RopeRenderData_t *pRenderCache, int nRenderCacheCount, const Vector &vCurrentViewForward, const Vector &vCurrentViewOrigin, C_RopeKeyframe::BuildRopeQueuedData_t *pBuildRopeQueuedData, CThreadFastMutex *pRopeDataMutex ) { VPROF_BUDGET( "CRopeManager::DrawRenderCache", VPROF_BUDGETGROUP_ROPES ); - AUTO_LOCK( m_RenderCacheMutex ); //contention cases: Toggling from queued mode on to off. Rope deletion from the cache. - - // Check to see if we want to render the ropes. - if( !r_drawropes.GetBool() ) - { - if( pBuildRopeQueuedData && (m_RopeQueuedRenderCaches.Count() != 0) ) - { - m_RopeQueuedRenderCaches.Remove( m_RopeQueuedRenderCaches.Head() ); - } - - return; - } + + CThreadFastMutex dummyMutex; + if( pRopeDataMutex == NULL ) + pRopeDataMutex = &dummyMutex; if ( bShadowDepth && !m_pDepthWriteMaterial && g_pMaterialSystem ) { @@ -423,102 +280,226 @@ void CRopeManager::DrawRenderCache_NonQueued( bool bShadowDepth, RopeRenderData_ pVMTKeyValues->SetInt( "$alphatest", 0 ); pVMTKeyValues->SetInt( "$nocull", 1 ); m_pDepthWriteMaterial = g_pMaterialSystem->FindProceduralMaterial( "__DepthWrite01", TEXTURE_GROUP_OTHER, pVMTKeyValues ); - m_pDepthWriteMaterial->IncrementReferenceCount(); } - CMatRenderContextPtr pRenderContext( materials ); - C_RopeKeyframe::BuildRopeQueuedData_t stackQueuedData; - Vector vStackPredictedPositions[MAX_ROPE_SEGMENTS]; - - for ( int iRenderCache = 0; iRenderCache < nRenderCacheCount; ++iRenderCache ) + // UNDONE: needs to use the queued data { - int nCacheCount = pRenderCache[iRenderCache].m_nCacheCount; - - if ( nCacheCount == 0 ) - continue; - - ResetSegmentCache( nCacheCount ); - - for ( int iCache = 0; iCache < nCacheCount; ++iCache ) + AUTO_LOCK_FM( *pRopeDataMutex ); + int defaultSubdiv = rope_subdiv.GetInt(); + for ( int iRenderCache = 0; iRenderCache < nRenderCacheCount; ++iRenderCache ) { - C_RopeKeyframe *pRope = pRenderCache[iRenderCache].m_aCache[iCache]; - if ( pRope ) + int nCacheCount = pRenderCache[iRenderCache].m_nCacheCount; + + int nTotalVerts = 0; + int nTotalIndices = 0; + for ( int iCache = 0; iCache < nCacheCount; ++iCache ) { - RopeSegData_t *pRopeSegment = GetNextSegmentFromCache(); - - if( pBuildRopeQueuedData ) + C_RopeKeyframe *pRope = pRenderCache[iRenderCache].m_aCache[iCache]; + if ( pRope ) { - pRope->BuildRope( pRopeSegment, vCurrentViewForward, vCurrentViewOrigin, pBuildRopeQueuedData, true ); - ++pBuildRopeQueuedData; - } - else - { - //to unify the BuildRope code, emulate the queued data - stackQueuedData.m_iNodeCount = pRope->m_RopePhysics.NumNodes(); - stackQueuedData.m_pLightValues = pRope->m_LightValues; - stackQueuedData.m_vColorMod = pRope->m_vColorMod; - stackQueuedData.m_pPredictedPositions = vStackPredictedPositions; - stackQueuedData.m_RopeLength = pRope->m_RopeLength; - stackQueuedData.m_Slack = pRope->m_Slack; - - for( int i = 0; i != stackQueuedData.m_iNodeCount; ++i ) - { - vStackPredictedPositions[i] = pRope->m_RopePhysics.GetNode( i )->m_vPredicted; - } - - pRope->BuildRope( pRopeSegment, vCurrentViewForward, vCurrentViewOrigin, &stackQueuedData, false ); + int segs = pRope->m_RopePhysics.NumNodes()-1; + int nSubdivCount = (pRope->m_Subdiv != 255 ? pRope->m_Subdiv : defaultSubdiv) + 1; + nTotalVerts += ((2 * nSubdivCount) * segs) + 2; + nTotalIndices += (6 * nSubdivCount) * segs; } } - else + if ( nTotalVerts == 0 ) + continue; + + IMaterial *pMaterial = bShadowDepth ? g_pSplineCableShadowdepth : pRenderCache[iRenderCache].m_pSolidMaterial; + + // Need to make sure that all rope materials use the splinerope shader since there are a lot of assumptions about how the shader interfaces with this code. + AssertOnce( V_stricmp( pMaterial->GetShaderName(), "splinerope" ) == 0 ); + + pRenderContext->Bind( pMaterial ); + + int nMaxVertices = pRenderContext->GetMaxVerticesToRender( pMaterial ); + int nMaxIndices = pRenderContext->GetMaxIndicesToRender(); + + IMesh* pMesh = pRenderContext->GetDynamicMesh( true ); + CMeshBuilder meshBuilder; + int meshVertCount = MIN(nTotalVerts, nMaxVertices); + int meshIndexCount = MIN(nTotalIndices, nMaxIndices); + meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, meshVertCount, meshIndexCount ); + int nCurIDX = 0; + + int availableVerts = meshVertCount; + int availableIndices = meshIndexCount; + float flLastU = 1.0f; + + for ( int iCache = 0; iCache < nCacheCount; ++iCache ) { - if( pBuildRopeQueuedData ) + C_RopeKeyframe *pRope = pRenderCache[iRenderCache].m_aCache[iCache]; + if ( pRope ) { - //we should only be here if a rope was in the queue and then deleted. We still have it's relevant data (and need to skip over it). - ++pBuildRopeQueuedData; - } - } - } + CSimplePhysics::CNode *pNode = pRope->m_RopePhysics.GetFirstNode(); + int nSegmentsToRender = pRope->m_RopePhysics.NumNodes()-1; + if ( !nSegmentsToRender ) + continue; - if ( materials->GetRenderContext()->GetCallQueue() != NULL && pBuildRopeQueuedData == NULL ) - { - // We build ropes outside of queued mode for holidy lights - // But we don't want to render them - continue; - } + int nParticles = pRope->m_RopePhysics.NumNodes(); + int nSubdivCount = (pRope->m_Subdiv != 255 ? pRope->m_Subdiv : defaultSubdiv) + 1; - int nVertCount = 0; - int nIndexCount = 0; - for ( int iSegmentCache = 0; iSegmentCache < m_nSegmentCacheCount; ++iSegmentCache ) - { - nVertCount += ( m_aSegmentCache[iSegmentCache].m_nSegmentCount * 2 ); - nIndexCount += ( ( m_aSegmentCache[iSegmentCache].m_nSegmentCount - 1 ) * 6 ); - } + int nNumIndicesPerSegment = 6 * nSubdivCount; + int nNumVerticesPerSegment = 2 * nSubdivCount; - // Render the non-solid portion of the ropes. - bool bRenderNonSolid = !bShadowDepth && ShouldUseFakeAA( pRenderCache[iRenderCache].m_pBackMaterial ); - if ( bRenderNonSolid ) - { - RenderNonSolidRopes( pRenderContext, pRenderCache[iRenderCache].m_pBackMaterial, nVertCount, nIndexCount ); - } + int nSegmentsAvailableInBuffer = MIN( ( availableVerts - 2 ) / nNumVerticesPerSegment, + ( availableIndices ) / nNumIndicesPerSegment ); - // Render the solid portion of the ropes. - if ( rope_rendersolid.GetInt() ) - { - if ( bShadowDepth ) - RenderSolidRopes( pRenderContext, m_pDepthWriteMaterial, nVertCount, nIndexCount, bRenderNonSolid ); - else - RenderSolidRopes( pRenderContext, pRenderCache[iRenderCache].m_pSolidMaterial, nVertCount, nIndexCount, bRenderNonSolid ); + int segmentsInBuffer = MIN(nSegmentsAvailableInBuffer,nSegmentsToRender); + availableIndices -= nNumIndicesPerSegment * segmentsInBuffer; + availableVerts -= 2 + (nNumVerticesPerSegment * segmentsInBuffer); + + float width = pRope->m_Width; + Vector vModColor = pRope->m_vColorMod; + Vector *pColors = pRope->m_LightValues; + + // Figure out texture scale. + float flPixelsPerInch = 4.0f / pRope->m_TextureScale; + // This is the total number of texels for the length of the whole rope. + float flTotalTexCoord = flPixelsPerInch * ( pRope->m_RopeLength + pRope->m_Slack + ROPESLACK_FUDGEFACTOR ); + int nTotalPoints = (nSegmentsToRender * (nSubdivCount-1)) + 1; + float flDU = ( flTotalTexCoord / nTotalPoints ) / ( float )pRope->m_TextureHeight; + float flU = pRope->m_flCurScroll; + float m_flTStep = 1.0f / float(nSubdivCount); + + bool bFirstPoint = true; + + // initialize first spline segment + Vector4D vecP1; + Vector4D vecP2; + vecP1.Init( pNode[0].m_vPredicted, pRope->m_Width ); + vecP2.Init( pNode[1].m_vPredicted, pRope->m_Width ); + Vector4D vecP0 = vecP1; + + uint8 nRed = 0; + uint8 nGreen = 0; + uint8 nBlue = 0; + uint8 nAlpha = 255; + + Vector4D vecDelta = vecP2; + vecDelta -= vecP1; + vecP0 -= vecDelta; + + Vector4D vecP3; + + if ( nParticles < 3 ) + { + vecP3 = vecP2; + vecP3 += vecDelta; + } + else + { + vecP3.Init( pNode[2].m_vPredicted, width ); + } + int nPnt = 3; + int nColor = 1; + Vector vColor0( pColors[0].x * vModColor.x, pColors[0].y * vModColor.y, pColors[0].z * vModColor.z ); + Vector vColor1( pColors[1].x * vModColor.x, pColors[1].y * vModColor.y, pColors[1].z * vModColor.z ); + + float flT = 0; + do + { + if ( ! nSegmentsAvailableInBuffer ) + { + meshBuilder.End(); + pMesh->Draw(); + nTotalVerts -= (meshVertCount - availableVerts); + nTotalIndices -= (meshIndexCount - availableIndices); + meshVertCount = MIN(nTotalVerts, nMaxVertices); + meshIndexCount = MIN(nTotalIndices, nMaxIndices); + meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, meshVertCount, meshIndexCount ); + availableVerts = meshVertCount; + availableIndices = meshIndexCount; + // copy the last emitted points + OUTPUT_2SPLINE_VERTS( flT, flLastU ); + + nSegmentsAvailableInBuffer = MIN( ( availableVerts - 2 ) / nNumVerticesPerSegment, + availableIndices / nNumIndicesPerSegment ); + + nCurIDX = 0; + } + nSegmentsAvailableInBuffer--; + flT = 0.; + for( int nSlice = 0 ; nSlice < nSubdivCount; nSlice++ ) + { + float omt = 1.0f - flT; + nRed = FastFToC( (vColor0.x * omt) + (vColor1.x*flT) ); + nGreen = FastFToC( (vColor0.y * omt) + (vColor1.y*flT) ); + nBlue = FastFToC( (vColor0.z * omt) + (vColor1.z*flT) ); + OUTPUT_2SPLINE_VERTS( flT, flU ); + flT += m_flTStep; + flU += flDU; + if ( ! bFirstPoint ) + { + meshBuilder.FastIndex( nCurIDX ); + meshBuilder.FastIndex( nCurIDX+1 ); + meshBuilder.FastIndex( nCurIDX+2 ); + meshBuilder.FastIndex( nCurIDX+1 ); + meshBuilder.FastIndex( nCurIDX+3 ); + meshBuilder.FastIndex( nCurIDX+2 ); + nCurIDX += 2; + } + bFirstPoint = false; + } + // next segment + vColor0 = vColor1; + if ( nColor < nParticles-1 ) + { + nColor++; + vColor1.Init( pColors[nColor].x * vModColor.x, pColors[nColor].y * vModColor.y, pColors[nColor].z * vModColor.z ); + } + if ( nSegmentsToRender > 1 ) + { + vecP0 = vecP1; + vecP1 = vecP2; + vecP2 = vecP3; + + if ( nPnt < nParticles ) + { + vecP3.AsVector3D() = pNode[nPnt].m_vPredicted; + nPnt++; + } + else + { + // fake last point by extrapolating + vecP3 += vecP2; + vecP3 -= vecP1; + } + } + } while( --nSegmentsToRender ); + + // output last piece + OUTPUT_2SPLINE_VERTS( 1.0, flU ); + meshBuilder.FastIndex( nCurIDX ); + meshBuilder.FastIndex( nCurIDX+1 ); + meshBuilder.FastIndex( nCurIDX+2 ); + meshBuilder.FastIndex( nCurIDX+1 ); + meshBuilder.FastIndex( nCurIDX+3 ); + meshBuilder.FastIndex( nCurIDX+2 ); + nCurIDX += 4; + flLastU = flU; + } + } + + meshBuilder.End(); + pMesh->Draw(); } } - ResetSegmentCache( 0 ); + m_RopeQueuedRenderCaches_Mutex.Lock(); if( pBuildRopeQueuedData && (m_RopeQueuedRenderCaches.Count() != 0) ) { - m_RopeQueuedRenderCaches.Remove( m_RopeQueuedRenderCaches.Head() ); + unsigned short iHeadIndex = m_RopeQueuedRenderCaches.Head(); + delete m_RopeQueuedRenderCaches[iHeadIndex].m_pRopeDataMutex; + m_RopeQueuedRenderCaches.Remove( iHeadIndex ); } + m_RopeQueuedRenderCaches_Mutex.Unlock(); } +ConVar r_queued_ropes( "r_queued_ropes", "1" ); + //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- @@ -529,15 +510,19 @@ void CRopeManager::DrawRenderCache( bool bShadowDepth ) if( iRenderCacheCount == 0 ) return; + // Check to see if we want to render the ropes. + if( !r_drawropes.GetBool() ) + return; + Vector vForward = CurrentViewForward(); Vector vOrigin = CurrentViewOrigin(); + CMatRenderContextPtr pRenderContext(materials); ICallQueue *pCallQueue; - if( r_queued_ropes.GetBool() && (pCallQueue = materials->GetRenderContext()->GetCallQueue()) != NULL ) + if( r_queued_ropes.GetBool() && (pCallQueue = pRenderContext->GetCallQueue()) != NULL ) { //material queue available and desired CRopeManager::RopeRenderData_t *pRenderCache = m_aRenderCache.Base(); - AUTO_LOCK( m_RenderCacheMutex ); int iRopeCount = 0; int iNodeCount = 0; @@ -563,7 +548,8 @@ void CRopeManager::DrawRenderCache( bool bShadowDepth ) (iRopeCount * sizeof(C_RopeKeyframe::BuildRopeQueuedData_t)) + (iNodeCount * (sizeof(Vector) * 2)); - void *pMemory = m_QueuedModeMemory.Alloc( iMemoryNeeded ); + CMatRenderData< byte > rd(pRenderContext, iMemoryNeeded); + void *pMemory = rd.Base(); CRopeManager::RopeRenderData_t *pRenderCachesStart = (CRopeManager::RopeRenderData_t *)pMemory; C_RopeKeyframe::BuildRopeQueuedData_t *pBuildRopeQueuedDataStart = (C_RopeKeyframe::BuildRopeQueuedData_t *)(pRenderCachesStart + iRenderCacheCount); @@ -574,7 +560,7 @@ void CRopeManager::DrawRenderCache( bool bShadowDepth ) RopeQueuedRenderCache_t cache; cache.pCaches = pRenderCachesStart; cache.iCacheCount = iRenderCacheCount; - m_RopeQueuedRenderCaches.AddToTail( cache ); + cache.m_pRopeDataMutex = new CThreadFastMutex; C_RopeKeyframe::BuildRopeQueuedData_t *pWriteRopeQueuedData = pBuildRopeQueuedDataStart; Vector *pVectorWrite = (Vector *)pVectorDataStart; @@ -587,7 +573,6 @@ void CRopeManager::DrawRenderCache( bool bShadowDepth ) int iCacheCount = pReadCache->m_nCacheCount; pWriteCache->m_nCacheCount = 0; pWriteCache->m_pSolidMaterial = pReadCache->m_pSolidMaterial; - pWriteCache->m_pBackMaterial = pReadCache->m_pBackMaterial; for( int j = 0; j != iCacheCount; ++j ) { C_RopeKeyframe *pRope = pReadCache->m_aCache[j]; @@ -618,193 +603,31 @@ void CRopeManager::DrawRenderCache( bool bShadowDepth ) pVectorWrite += iNodes; //so we don't overwrite the light values with the next rope's predicted positions } } - Assert( ((void *)pVectorWrite == (void *)(((uint8 *)pMemory) + iMemoryNeeded)) && ((void *)pWriteRopeQueuedData == (void *)pVectorDataStart)); - pCallQueue->QueueCall( this, &CRopeManager::DrawRenderCache_NonQueued, bShadowDepth, pRenderCachesStart, iRenderCacheCount, vForward, vOrigin, pBuildRopeQueuedDataStart ); - - if ( IsHolidayLightMode() ) - { - // With holiday lights we need to also build the ropes non-queued without rendering them - DrawRenderCache_NonQueued( bShadowDepth, m_aRenderCache.Base(), iRenderCacheCount, vForward, vOrigin, NULL ); - } - } - else - { - DrawRenderCache_NonQueued( bShadowDepth, m_aRenderCache.Base(), iRenderCacheCount, vForward, vOrigin, NULL ); - } -} - -bool CRopeManager::IsHolidayLightMode( void ) -{ - if ( !r_ropes_holiday_lights_allowed.GetBool() ) - { - return false; - } - - bool bDrawHolidayLights = false; - -#ifdef USES_ECON_ITEMS - if ( !m_bHolidayInitialized && GameRules() ) - { - m_bHolidayInitialized = true; - m_bDrawHolidayLights = GameRules()->IsHolidayActive( kHoliday_Christmas ); - } - - bDrawHolidayLights = m_bDrawHolidayLights; - m_nHolidayLightsStyle = 0; -#ifdef TF_CLIENT_DLL - // Turn them on in Pyro-vision too - if ( IsLocalPlayerUsingVisionFilterFlags( TF_VISION_FILTER_PYRO ) ) - { - bDrawHolidayLights = true; - m_nHolidayLightsStyle = 1; - } -#endif // TF_CLIENT_DLL - -#endif // USES_ECON_ITEMS - - return bDrawHolidayLights; -} - -int CRopeManager::GetHolidayLightStyle( void ) -{ - return m_nHolidayLightsStyle; -} + m_RopeQueuedRenderCaches_Mutex.Lock(); + unsigned short iLLIndex = m_RopeQueuedRenderCaches.AddToTail( cache ); + CThreadFastMutex *pRopeDataMutex = m_RopeQueuedRenderCaches[iLLIndex].m_pRopeDataMutex; + m_RopeQueuedRenderCaches_Mutex.Unlock(); -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CRopeManager::RenderNonSolidRopes( IMatRenderContext *pRenderContext, IMaterial *pMaterial, int nVertCount, int nIndexCount ) -{ - // Render the solid portion of the ropes. - CMeshBuilder meshBuilder; - IMesh *pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, pMaterial ); - meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, nVertCount, nIndexCount ); - - CBeamSegDraw beamSegment; - - int nVerts = 0; - for ( int iSegmentCache = 0; iSegmentCache < m_nSegmentCacheCount; ++iSegmentCache ) - { - int nSegmentCount = m_aSegmentCache[iSegmentCache].m_nSegmentCount; - beamSegment.Start( pRenderContext, nSegmentCount, pMaterial, &meshBuilder, nVerts ); - for ( int iSegment = 0; iSegment < nSegmentCount; ++iSegment ) - { - beamSegment.NextSeg( &m_aSegmentCache[iSegmentCache].m_Segments[iSegment] ); - } - beamSegment.End(); - nVerts += ( m_aSegmentCache[iSegmentCache].m_nSegmentCount * 2 ); - } - - meshBuilder.End(); - pMesh->Draw(); -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CRopeManager::RenderSolidRopes( IMatRenderContext *pRenderContext, IMaterial *pMaterial, int nVertCount, int nIndexCount, bool bRenderNonSolid ) -{ - // Render the solid portion of the ropes. - CMeshBuilder meshBuilder; - IMesh *pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, pMaterial ); - meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, nVertCount, nIndexCount ); - - CBeamSegDraw beamSegment; - - if ( bRenderNonSolid ) - { - int nVerts = 0; - for ( int iSegmentCache = 0; iSegmentCache < m_nSegmentCacheCount; ++iSegmentCache ) - { - RopeSegData_t *pSegData = &m_aSegmentCache[iSegmentCache]; - - // If it's all going to be 0 alpha, then just skip drawing this one. - if ( rope_solid_minalpha.GetFloat() == 0.0 && pSegData->m_flMaxBackWidth <= rope_solid_minwidth.GetFloat() ) - continue; - - int nSegmentCount = m_aSegmentCache[iSegmentCache].m_nSegmentCount; - beamSegment.Start( pRenderContext, nSegmentCount, pMaterial, &meshBuilder, nVerts ); - for ( int iSegment = 0; iSegment < nSegmentCount; ++iSegment ) - { - BeamSeg_t *pSeg = &m_aSegmentCache[iSegmentCache].m_Segments[iSegment]; - pSeg->m_flWidth = m_aSegmentCache[iSegmentCache].m_BackWidths[iSegment]; - - // To avoid aliasing, the "solid" version of the rope on xbox is just "more solid", - // and it has its own values controlling its alpha. - pSeg->m_flAlpha = RemapVal( pSeg->m_flWidth, - rope_solid_minwidth.GetFloat(), - rope_solid_maxwidth.GetFloat(), - rope_solid_minalpha.GetFloat(), - rope_solid_maxalpha.GetFloat() ); - - pSeg->m_flAlpha = clamp( pSeg->m_flAlpha, 0.0f, 1.0f ); - - beamSegment.NextSeg( &m_aSegmentCache[iSegmentCache].m_Segments[iSegment] ); - } - beamSegment.End(); - nVerts += ( m_aSegmentCache[iSegmentCache].m_nSegmentCount * 2 ); - } - } - else - { - int nVerts = 0; - for ( int iSegmentCache = 0; iSegmentCache < m_nSegmentCacheCount; ++iSegmentCache ) - { - int nSegmentCount = m_aSegmentCache[iSegmentCache].m_nSegmentCount; - beamSegment.Start( pRenderContext, nSegmentCount, pMaterial, &meshBuilder, nVerts ); - for ( int iSegment = 0; iSegment < nSegmentCount; ++iSegment ) - { - beamSegment.NextSeg( &m_aSegmentCache[iSegmentCache].m_Segments[iSegment] ); - } - beamSegment.End(); - nVerts += ( m_aSegmentCache[iSegmentCache].m_nSegmentCount * 2 ); - } + Assert( ((void *)pVectorWrite == (void *)(((uint8 *)pMemory) + iMemoryNeeded)) && ((void *)pWriteRopeQueuedData == (void *)pVectorDataStart)); + pCallQueue->QueueCall( this, &CRopeManager::DrawRenderCache_NonQueued, bShadowDepth, pRenderCachesStart, iRenderCacheCount, vForward, vOrigin, pBuildRopeQueuedDataStart, pRopeDataMutex ); } - - meshBuilder.End(); - pMesh->Draw(); -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CRopeManager::ResetSegmentCache( int nMaxSegments ) -{ - MEM_ALLOC_CREDIT(); - m_nSegmentCacheCount = 0; - if ( nMaxSegments ) - m_aSegmentCache.EnsureCount( nMaxSegments ); else - m_aSegmentCache.Purge(); - -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -RopeSegData_t *CRopeManager::GetNextSegmentFromCache( void ) -{ - if ( m_nSegmentCacheCount >= m_aSegmentCache.Count() ) { - Warning( "CRopeManager::GetNextSegmentFromCache too many segments for cache!\n" ); - return NULL; + DrawRenderCache_NonQueued( bShadowDepth, m_aRenderCache.Base(), iRenderCacheCount, vForward, vOrigin, NULL, NULL ); } - - ++m_nSegmentCacheCount; - return &m_aSegmentCache[m_nSegmentCacheCount-1]; } - void CRopeManager::RemoveRopeFromQueuedRenderCaches( C_RopeKeyframe *pRope ) { - //remove this rope from queued render caches - AUTO_LOCK( m_RenderCacheMutex ); + //remove this rope from queued render caches + AUTO_LOCK_FM( m_RopeQueuedRenderCaches_Mutex ); + int index = m_RopeQueuedRenderCaches.Head(); while( m_RopeQueuedRenderCaches.IsValidIndex( index ) ) { - RopeQueuedRenderCache_t &RenderCacheData = m_RopeQueuedRenderCaches[index]; + RopeQueuedRenderCache_t &RenderCacheData = m_RopeQueuedRenderCaches[index]; for( int i = 0; i != RenderCacheData.iCacheCount; ++i ) { RopeRenderData_t *pCache = &RenderCacheData.pCaches[i]; @@ -812,13 +635,15 @@ void CRopeManager::RemoveRopeFromQueuedRenderCaches( C_RopeKeyframe *pRope ) { if( pCache->m_aCache[j] == pRope ) { + RenderCacheData.m_pRopeDataMutex->Lock(); pCache->m_aCache[j] = NULL; + RenderCacheData.m_pRopeDataMutex->Unlock(); } } - } + } index = m_RopeQueuedRenderCaches.Next( index ); - } + } } //============================================================================= @@ -829,9 +654,6 @@ void CRopeManager::RemoveRopeFromQueuedRenderCaches( C_RopeKeyframe *pRope ) void Rope_ResetCounters() { - g_RopeCollideTicks.Init(); - g_RopeDrawTicks.Init(); - g_RopeSimulateTicks.Init(); g_nRopePointsSimulated = 0; } @@ -855,9 +677,7 @@ void ShakeRopesCallback( const CEffectData &data ) } } -DECLARE_CLIENT_EFFECT( "ShakeRopes", ShakeRopesCallback ); - - +DECLARE_CLIENT_EFFECT( ShakeRopes, ShakeRopesCallback ) // ------------------------------------------------------------------------------------ // @@ -884,7 +704,7 @@ void C_RopeKeyframe::CPhysicsDelegate::GetNodeForces( CSimplePhysics::CNode *pNo } else { - if (m_pKeyframe->m_flCurrentGustTimer < m_pKeyframe->m_flCurrentGustLifetime ) + if ( ( m_pKeyframe->m_flCurrentGustLifetime != 0.0f ) && ( m_pKeyframe->m_flCurrentGustTimer < m_pKeyframe->m_flCurrentGustLifetime ) ) { float div = m_pKeyframe->m_flCurrentGustTimer / m_pKeyframe->m_flCurrentGustLifetime; float scale = 1 - cos( div * M_PI ); @@ -902,8 +722,12 @@ void C_RopeKeyframe::CPhysicsDelegate::GetNodeForces( CSimplePhysics::CNode *pNo } // Apply any instananeous forces and reset - *pAccel += ROPE_IMPULSE_SCALE * m_pKeyframe->m_flImpulse; - m_pKeyframe->m_flImpulse *= ROPE_IMPULSE_DECAY; + *pAccel += ROPE_IMPULSE_SCALE * m_pKeyframe->m_vecImpulse; + m_pKeyframe->m_vecImpulse *= ROPE_IMPULSE_DECAY; + if ( m_pKeyframe->m_vecImpulse.LengthSqr() < 0.1f ) + { + m_pKeyframe->m_vecImpulse = vec3_origin; + } } @@ -940,21 +764,19 @@ void C_RopeKeyframe::CPhysicsDelegate::ApplyConstraints( CSimplePhysics::CNode * { VPROF( "CPhysicsDelegate::ApplyConstraints" ); - CTraceFilterWorldOnly traceFilter; - // Collide with the world. if( ((m_pKeyframe->m_RopeFlags & ROPE_COLLIDE) && rope_collide.GetInt()) || (rope_collide.GetInt() == 2) ) { - CTimeAdder adder( &g_RopeCollideTicks ); + CTraceFilterWorldOnly traceFilter; for( int i=0; i < nNodes; i++ ) { CSimplePhysics::CNode *pNode = &pNodes[i]; int iIteration; - int nIterations = 10; + const int nIterations = 10; for( iIteration=0; iIteration < nIterations; iIteration++ ) { trace_t trace; @@ -972,7 +794,7 @@ void C_RopeKeyframe::CPhysicsDelegate::ApplyConstraints( CSimplePhysics::CNode * } // Apply some friction. - static float flSlowFactor = 0.3f; + const float flSlowFactor = 0.3f; pNode->m_vPos -= (pNode->m_vPos - pNode->m_vPrevPos) * flSlowFactor; // Move it out along the face normal. @@ -1036,14 +858,16 @@ C_RopeKeyframe::C_RopeKeyframe() m_vColorMod.Init( 1, 1, 1 ); m_nLinksTouchingSomething = 0; m_Subdiv = 255; // default to using the cvar - + m_flCurrentGustLifetime = 0.0f; + m_flCurrentGustTimer = 0.0f; + m_fLockedPoints = 0; m_fPrevLockedPoints = 0; m_iForcePointMoveCounter = 0; m_flCurScroll = m_flScrollSpeed = 0; m_TextureScale = 4; // 4:1 - m_flImpulse.Init(); + m_vecImpulse.Init(); g_Ropes.AddToTail( this ); } @@ -1053,12 +877,6 @@ C_RopeKeyframe::~C_RopeKeyframe() { s_RopeManager.RemoveRopeFromQueuedRenderCaches( this ); g_Ropes.FindAndRemove( this ); - - if ( m_pBackMaterial ) - { - m_pBackMaterial->DecrementReferenceCount(); - m_pBackMaterial = NULL; - } } @@ -1075,7 +893,7 @@ C_RopeKeyframe* C_RopeKeyframe::Create( { C_RopeKeyframe *pRope = new C_RopeKeyframe; - pRope->InitializeAsClientEntity( NULL, RENDER_GROUP_OPAQUE_ENTITY ); + pRope->InitializeAsClientEntity( NULL, false ); if ( pStartEnt ) { @@ -1248,6 +1066,7 @@ void C_RopeKeyframe::RecomputeSprings() void C_RopeKeyframe::ShakeRope( const Vector &vCenter, float flRadius, float flMagnitude ) { // Sum up whatever it would apply to all of our points. + bool bWantsThink = false; for ( int i=0; i < m_nSegments; i++ ) { CSimplePhysics::CNode *pNode = m_RopePhysics.GetNode( i ); @@ -1257,9 +1076,15 @@ void C_RopeKeyframe::ShakeRope( const Vector &vCenter, float flRadius, float flM float flShakeAmount = 1.0f - flDist / flRadius; if ( flShakeAmount >= 0 ) { - m_flImpulse.z += flShakeAmount * flMagnitude; + m_vecImpulse.z += flShakeAmount * flMagnitude; + bWantsThink = true; } } + + if ( bWantsThink ) + { + SetNextClientThink( CLIENT_THINK_ALWAYS ); + } } @@ -1268,6 +1093,7 @@ void C_RopeKeyframe::OnDataChanged( DataUpdateType_t updateType ) BaseClass::OnDataChanged( updateType ); m_bNewDataThisFrame = true; + SetNextClientThink( CLIENT_THINK_ALWAYS ); if( updateType != DATA_UPDATE_CREATED ) return; @@ -1286,7 +1112,7 @@ void C_RopeKeyframe::OnDataChanged( DataUpdateType_t updateType ) } else { - Q_strncpy( str, "asdf", sizeof( str ) ); + Q_strncpy( str, "missing_rope_material", sizeof( str ) ); } FinishInit( str ); @@ -1297,24 +1123,18 @@ void C_RopeKeyframe::FinishInit( const char *pMaterialName ) { // Get the material from the material system. m_pMaterial = materials->FindMaterial( pMaterialName, TEXTURE_GROUP_OTHER ); + + if ( !g_pSplineCableShadowdepth ) + { + g_pSplineCableShadowdepth = g_pMaterialSystem->FindMaterial( "cable/rope_shadowdepth", TEXTURE_GROUP_OTHER ); + g_pSplineCableShadowdepth->IncrementReferenceCount(); + } + if( m_pMaterial ) m_TextureHeight = m_pMaterial->GetMappingHeight(); else m_TextureHeight = 1; - char backName[512]; - Q_snprintf( backName, sizeof( backName ), "%s_back", pMaterialName ); - - m_pBackMaterial = materials->FindMaterial( backName, TEXTURE_GROUP_OTHER, false ); - if ( IsErrorMaterial( m_pBackMaterial ) ) - m_pBackMaterial = NULL; - - if ( m_pBackMaterial ) - { - m_pBackMaterial->IncrementReferenceCount(); - m_pBackMaterial->GetMappingWidth(); - } - // Init rope physics. m_nSegments = clamp( m_nSegments, 2, ROPE_MAX_SEGMENTS ); m_RopePhysics.SetNumNodes( m_nSegments ); @@ -1386,24 +1206,31 @@ void C_RopeKeyframe::ClientThink() m_bEndPointAttachmentPositionsDirty = true; m_bEndPointAttachmentAnglesDirty = true; - if( !r_drawropes.GetBool() ) + if( !InitRopePhysics() ) // init if not already return; - if( !InitRopePhysics() ) // init if not already + if( !r_drawropes.GetBool() ) return; - if( !DetectRestingState( m_bApplyWind ) ) + if ( DetectRestingState( m_bApplyWind ) ) { - // Update the simulation. - CTimeAdder adder( &g_RopeSimulateTicks ); - - RunRopeSimulation( gpGlobals->frametime ); + if ( ( m_RopeFlags & ROPE_USE_WIND ) == 0 ) + { + SetNextClientThink( CLIENT_THINK_NEVER ); + } + return; + } + + // Update the simulation. + RunRopeSimulation( gpGlobals->frametime ); - g_nRopePointsSimulated += m_RopePhysics.NumNodes(); + g_nRopePointsSimulated += m_RopePhysics.NumNodes(); - m_bNewDataThisFrame = false; + m_bNewDataThisFrame = false; - // Setup a new wind gust? + // Setup a new wind gust? + if ( m_bApplyWind ) + { m_flCurrentGustTimer += gpGlobals->frametime; m_flTimeToNextGust -= gpGlobals->frametime; if( m_flTimeToNextGust <= 0 ) @@ -1420,13 +1247,13 @@ void C_RopeKeyframe::ClientThink() m_flTimeToNextGust = RandomFloat( 3.0f, 4.0f ); } - - UpdateBBox(); } + + UpdateBBox(); } -int C_RopeKeyframe::DrawModel( int flags ) +int C_RopeKeyframe::DrawModel( int flags, const RenderableInstance_t &instance ) { VPROF_BUDGET( "C_RopeKeyframe::DrawModel", VPROF_BUDGETGROUP_ROPES ); if( !InitRopePhysics() ) @@ -1463,6 +1290,21 @@ bool C_RopeKeyframe::ShouldDraw() if( !(m_RopeFlags & ROPE_SIMULATE) ) return false; + if ( !IsX360() ) + { + CPULevel_t nCPULevel = GetCPULevel(); + bool bNoDraw = ( GetMinCPULevel() && GetMinCPULevel()-1 > nCPULevel ); + bNoDraw = bNoDraw || ( GetMaxCPULevel() && GetMaxCPULevel()-1 < nCPULevel ); + if ( bNoDraw ) + return false; + + GPULevel_t nGPULevel = GetGPULevel(); + bNoDraw = ( GetMinGPULevel() && GetMinGPULevel()-1 > nGPULevel ); + bNoDraw = bNoDraw || ( GetMaxGPULevel() && GetMaxGPULevel()-1 < nGPULevel ); + if ( bNoDraw ) + return false; + } + return true; } @@ -1545,16 +1387,26 @@ bool C_RopeKeyframe::GetAttachment( int number, Vector &origin, QAngle &angles ) bool C_RopeKeyframe::AnyPointsMoved() { - for( int i=0; i < m_RopePhysics.NumNodes(); i++ ) + int nNodeCount = m_RopePhysics.NumNodes(); + for( int i=0; i < nNodeCount; i++ ) { CSimplePhysics::CNode *pNode = m_RopePhysics.GetNode( i ); - float flMoveDistSqr = (pNode->m_vPos - pNode->m_vPrevPos).LengthSqr(); - if( flMoveDistSqr > 0.03f ) + float flMoveDistSqr = pNode->m_vPos.DistToSqr( pNode->m_vPrevPos ); + if( flMoveDistSqr > 0.25f ) + { + if ( m_iForcePointMoveCounter < 5 ) + { + m_iForcePointMoveCounter = 5; + } return true; + } } - if( --m_iForcePointMoveCounter > 0 ) + if( m_iForcePointMoveCounter >= 0 ) + { + --m_iForcePointMoveCounter; return true; + } return false; } @@ -1611,17 +1463,28 @@ bool C_RopeKeyframe::DetectRestingState( bool &bApplyWind ) Vector &vEnd1 = m_RopePhysics.GetFirstNode()->m_vPos; Vector &vEnd2 = m_RopePhysics.GetLastNode()->m_vPos; - if ( !( m_RopeFlags & ROPE_NO_WIND ) ) + if ( m_RopeFlags & ROPE_USE_WIND ) { // Don't apply wind if more than half of the nodes are touching something. - float flDist1 = CalcDistanceToLineSegment( MainViewOrigin(), vEnd1, vEnd2 ); + float flDist1 = FLT_MAX; + FOR_EACH_VALID_SPLITSCREEN_PLAYER( hh ) + { + // ACTIVE_SPLITSCREEN_PLAYER_GUARD( hh ); + float d = CalcDistanceToLineSegment( MainViewOrigin( hh ), vEnd1, vEnd2 ); + if ( d < flDist1 ) + { + flDist1 = d; + } + } if( m_nLinksTouchingSomething < (m_RopePhysics.NumNodes() >> 1) ) + { bApplyWind = flDist1 < rope_wind_dist.GetFloat(); + } } - if ( m_flPreviousImpulse != m_flImpulse ) + if ( m_vecPreviousImpulse != m_vecImpulse ) { - m_flPreviousImpulse = m_flImpulse; + m_vecPreviousImpulse = m_vecImpulse; return false; } @@ -1657,173 +1520,6 @@ inline void Catmull_Rom_Eval( const catmull_t &spline, const Vector &t, Vector & } -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void C_RopeKeyframe::BuildRope( RopeSegData_t *pSegmentData, const Vector &vCurrentViewForward, const Vector &vCurrentViewOrigin, C_RopeKeyframe::BuildRopeQueuedData_t *pQueuedData, bool bQueued ) -{ - if ( !pSegmentData ) - return; - - // Get the lighting values. - Vector *pLightValues = ( mat_fullbright.GetInt() == 1 ) ? g_FullBright_LightValues : pQueuedData->m_pLightValues; - - // Update the rope subdivisions if necessary. - int nSubdivCount; - Vector *pSubdivVecList = GetRopeSubdivVectors( &nSubdivCount ); - - int nSegmentCount = 0; - int iPrevNode = 0; - const float subdivScale = 1.0f / (nSubdivCount+1); - const int nodeCount = pQueuedData->m_iNodeCount; - const int lastNode = nodeCount-1; - catmull_t spline; - - Vector *pPredictedPositions = pQueuedData->m_pPredictedPositions; - Vector vColorMod = pQueuedData->m_vColorMod; - - for( int iNode = 0; iNode < nodeCount; ++iNode ) - { - pSegmentData->m_Segments[nSegmentCount].m_vPos = pPredictedPositions[iNode]; - pSegmentData->m_Segments[nSegmentCount].m_vColor = pLightValues[iNode] * vColorMod; - - CEffectData data; - - if ( !bQueued && RopeManager()->IsHolidayLightMode() && r_rope_holiday_light_scale.GetFloat() > 0.0f ) - { - data.m_nMaterial = (intp)this; - data.m_nHitBox = ( iNode << 8 ); - data.m_flScale = r_rope_holiday_light_scale.GetFloat(); - data.m_vOrigin = pSegmentData->m_Segments[nSegmentCount].m_vPos; - DispatchEffect( "TF_HolidayLight", data ); - } - - ++nSegmentCount; - - if ( iNode < lastNode ) - { - // Draw a midpoint to the next segment. - int iNext = iNode + 1; - int iNextNext = iNode + 2; - if ( iNext >= nodeCount ) - { - iNext = iNextNext = lastNode; - } - else if ( iNextNext >= nodeCount ) - { - iNextNext = lastNode; - } - - Vector vecColorInc = subdivScale * ( ( pLightValues[iNode+1] - pLightValues[iNode] ) * vColorMod ); - // precompute spline basis - Catmull_Rom_Spline_Matrix( pPredictedPositions[iPrevNode], pPredictedPositions[iNode], - pPredictedPositions[iNext], pPredictedPositions[iNextNext], spline ); - for( int iSubdiv = 0; iSubdiv < nSubdivCount; ++iSubdiv ) - { - pSegmentData->m_Segments[nSegmentCount].m_vColor = pSegmentData->m_Segments[nSegmentCount-1].m_vColor + vecColorInc; - // simple eval using precomputed basis - Catmull_Rom_Eval( spline, pSubdivVecList[iSubdiv], pSegmentData->m_Segments[nSegmentCount].m_vPos ); - - if ( !bQueued && RopeManager()->IsHolidayLightMode() && r_rope_holiday_light_scale.GetFloat() > 0.0f ) - { - data.m_nHitBox++; - data.m_flScale = r_rope_holiday_light_scale.GetFloat(); - data.m_vOrigin = pSegmentData->m_Segments[nSegmentCount].m_vPos; - DispatchEffect( "TF_HolidayLight", data ); - } - - ++nSegmentCount; - Assert( nSegmentCount <= MAX_ROPE_SEGMENTS ); - } - - iPrevNode = iNode; - } - } - pSegmentData->m_nSegmentCount = nSegmentCount; - pSegmentData->m_flMaxBackWidth = 0; - - // Figure out texture scale. - float flPixelsPerInch = 4.0f / m_TextureScale; - float flTotalTexCoord = flPixelsPerInch * ( pQueuedData->m_RopeLength + pQueuedData->m_Slack + ROPESLACK_FUDGEFACTOR ); - int nTotalPoints = ( nodeCount - 1 ) * nSubdivCount + 1; - float flActualInc = ( flTotalTexCoord / nTotalPoints ) / ( float )m_TextureHeight; - - // First draw a translucent rope underneath the solid rope for an antialiasing effect. - if ( ShouldUseFakeAA( m_pBackMaterial ) ) - { - // Compute screen width - float flScreenWidth = ScreenWidth(); - float flHalfScreenWidth = flScreenWidth / 2.0f; - - float flExtraScreenSpaceWidth = rope_smooth_enlarge.GetFloat(); - - float flMinAlpha = rope_smooth_minalpha.GetFloat(); - float flMaxAlpha = rope_smooth_maxalpha.GetFloat(); - - float flMinScreenSpaceWidth = rope_smooth_minwidth.GetFloat(); - float flMaxAlphaScreenSpaceWidth = rope_smooth_maxalphawidth.GetFloat(); - - float flTexCoord = m_flCurScroll; - for ( int iSegment = 0; iSegment < nSegmentCount; ++iSegment ) - { - pSegmentData->m_Segments[iSegment].m_flTexCoord = flTexCoord; - - // Right here, we need to specify a width that will be 1 pixel larger in screen space. - float zCoord = vCurrentViewForward.Dot( pSegmentData->m_Segments[iSegment].m_vPos - vCurrentViewOrigin ); - zCoord = MAX( zCoord, 0.1f ); - - float flScreenSpaceWidth = m_Width * flHalfScreenWidth / zCoord; - if ( flScreenSpaceWidth < flMinScreenSpaceWidth ) - { - pSegmentData->m_Segments[iSegment].m_flAlpha = flMinAlpha; - pSegmentData->m_Segments[iSegment].m_flWidth = flMinScreenSpaceWidth * zCoord / flHalfScreenWidth; - pSegmentData->m_BackWidths[iSegment] = 0.0f; - } - else - { - if ( flScreenSpaceWidth > flMaxAlphaScreenSpaceWidth ) - { - pSegmentData->m_Segments[iSegment].m_flAlpha = flMaxAlpha; - } - else - { - pSegmentData->m_Segments[iSegment].m_flAlpha = RemapVal( flScreenSpaceWidth, flMinScreenSpaceWidth, flMaxAlphaScreenSpaceWidth, flMinAlpha, flMaxAlpha ); - } - - pSegmentData->m_Segments[iSegment].m_flWidth = m_Width; - pSegmentData->m_BackWidths[iSegment] = m_Width - ( zCoord * flExtraScreenSpaceWidth ) / flScreenWidth; - if ( pSegmentData->m_BackWidths[iSegment] < 0.0f ) - { - pSegmentData->m_BackWidths[iSegment] = 0.0f; - } - else - { - pSegmentData->m_flMaxBackWidth = MAX( pSegmentData->m_flMaxBackWidth, pSegmentData->m_BackWidths[iSegment] ); - } - } - - // Get the next texture coordinate. - flTexCoord += flActualInc; - } - } - else - { - float flTexCoord = m_flCurScroll; - - // Build the data with no smoothing. - for ( int iSegment = 0; iSegment < nSegmentCount; ++iSegment ) - { - pSegmentData->m_Segments[iSegment].m_flTexCoord = flTexCoord; - pSegmentData->m_Segments[iSegment].m_flAlpha = 0.3f; - pSegmentData->m_Segments[iSegment].m_flWidth = m_Width; - pSegmentData->m_BackWidths[iSegment] = -1.0f; - - // Get the next texture coordinate. - flTexCoord += flActualInc; - } - } -} - void C_RopeKeyframe::UpdateBBox() { Vector &vStart = m_RopePhysics.GetFirstNode()->m_vPos; @@ -1910,7 +1606,7 @@ bool C_RopeKeyframe::CalculateEndPointAttachment( C_BaseEntity *pEnt, int iAttac if ( m_RopeFlags & ROPE_PLAYER_WPN_ATTACH ) { - C_BasePlayer *pPlayer = dynamic_cast< C_BasePlayer* >( pEnt ); + C_BasePlayer *pPlayer = ToBasePlayer( pEnt ); if ( pPlayer ) { C_BaseAnimating *pModel = pPlayer->GetRenderedWeaponModel(); @@ -1962,25 +1658,6 @@ bool C_RopeKeyframe::GetEndPointPos( int iPt, Vector &vPos ) return true; } -IMaterial* C_RopeKeyframe::GetSolidMaterial( void ) -{ -#ifdef TF_CLIENT_DLL - if ( RopeManager()->IsHolidayLightMode() ) - { - if ( RopeManager()->GetHolidayLightStyle() == 1 ) - { - return materials->FindMaterial( "cable/pure_white", TEXTURE_GROUP_OTHER ); - } - } -#endif - - return m_pMaterial; -} -IMaterial* C_RopeKeyframe::GetBackMaterial( void ) -{ - return m_pBackMaterial; -} - bool C_RopeKeyframe::GetEndPointAttachment( int iPt, Vector &vPos, QAngle &angle ) { // By caching the results here, we avoid doing this a bunch of times per frame. @@ -1999,31 +1676,6 @@ bool C_RopeKeyframe::GetEndPointAttachment( int iPt, Vector &vPos, QAngle &angle } -// Look at the global cvar and recalculate rope subdivision data if necessary. -Vector *C_RopeKeyframe::GetRopeSubdivVectors( int *nSubdivs ) -{ - if( m_RopeFlags & ROPE_BARBED ) - { - *nSubdivs = g_nBarbedSubdivs; - return g_BarbedSubdivs; - } - else - { - int subdiv = m_Subdiv; - if ( subdiv == 255 ) - { - subdiv = rope_subdiv.GetInt(); - } - - if ( subdiv >= MAX_ROPE_SUBDIVS ) - subdiv = MAX_ROPE_SUBDIVS-1; - - *nSubdivs = subdiv; - return g_RopeSubdivs[subdiv]; - } -} - - void C_RopeKeyframe::CalcLightValues() { Vector boxColors[6]; @@ -2070,7 +1722,8 @@ void C_RopeKeyframe::ReceiveMessage( int classID, bf_read &msg ) } // Read instantaneous fore data - m_flImpulse.x = msg.ReadFloat(); - m_flImpulse.y = msg.ReadFloat(); - m_flImpulse.z = msg.ReadFloat(); + m_vecImpulse.x = msg.ReadFloat(); + m_vecImpulse.y = msg.ReadFloat(); + m_vecImpulse.z = msg.ReadFloat(); } + diff --git a/game/client/c_rope.h b/game/client/c_rope.h index f04372f9c..24545a87d 100644 --- a/game/client/c_rope.h +++ b/game/client/c_rope.h @@ -1,9 +1,9 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // // $NoKeywords: $ -//=============================================================================// +//===========================================================================// #ifndef C_ROPE_H #define C_ROPE_H @@ -106,8 +106,7 @@ class C_RopeKeyframe : public C_BaseEntity bool GetEndPointPos( int iPt, Vector &vPos ); // Get the rope material data. - IMaterial *GetSolidMaterial( void ); - IMaterial *GetBackMaterial( void ); + IMaterial *GetSolidMaterial( void ) { return m_pMaterial; } struct BuildRopeQueuedData_t { @@ -119,14 +118,16 @@ class C_RopeKeyframe : public C_BaseEntity float m_Slack; }; - void BuildRope( RopeSegData_t *pRopeSegment, const Vector &vCurrentViewForward, const Vector &vCurrentViewOrigin, BuildRopeQueuedData_t *pQueuedData, bool bQueued ); + void BuildRope( RopeSegData_t *pRopeSegment, const Vector &vCurrentViewForward, const Vector &vCurrentViewOrigin, BuildRopeQueuedData_t *pQueuedData ); // C_BaseEntity overrides. public: virtual void OnDataChanged( DataUpdateType_t updateType ); virtual void ClientThink(); - virtual int DrawModel( int flags ); + virtual int DrawModel( int flags, const RenderableInstance_t &instance ); + virtual RenderableTranslucencyType_t ComputeTranslucencyType() { return RENDERABLE_IS_OPAQUE; } + virtual bool ShouldDraw(); virtual const Vector& WorldSpaceCenter() const; @@ -189,26 +190,26 @@ class C_RopeKeyframe : public C_BaseEntity short m_iStartAttachment; // StartAttachment/EndAttachment are attachment points. short m_iEndAttachment; - unsigned char m_Subdiv; // Number of subdivions in between segments. + int m_Subdiv; // Number of subdivions in between segments. int m_RopeLength; // Length of the rope, used for tension. int m_Slack; // Extra length the rope is given. float m_TextureScale; // pixels per inch int m_fLockedPoints; // Which points are locked down. + int m_nChangeCount; float m_Width; CPhysicsDelegate m_PhysicsDelegate; IMaterial *m_pMaterial; - IMaterial *m_pBackMaterial; // Optional translucent background material for the rope to help reduce aliasing. int m_TextureHeight; // Texture height, for texture scale calculations. // Instantaneous force - Vector m_flImpulse; - Vector m_flPreviousImpulse; + Vector m_vecImpulse; + Vector m_vecPreviousImpulse; // Simulated wind gusts. float m_flCurrentGustTimer; @@ -250,10 +251,6 @@ abstract_class IRopeManager virtual void ResetRenderCache( void ) = 0; virtual void AddToRenderCache( C_RopeKeyframe *pRope ) = 0; virtual void DrawRenderCache( bool bShadowDepth ) = 0; - virtual void OnRenderStart( void ) = 0; - virtual void SetHolidayLightMode( bool bHoliday ) = 0; - virtual bool IsHolidayLightMode( void ) = 0; - virtual int GetHolidayLightStyle( void ) = 0; }; IRopeManager *RopeManager(); diff --git a/game/client/c_rumble.cpp b/game/client/c_rumble.cpp index 478cb8530..a82d1d4f8 100644 --- a/game/client/c_rumble.cpp +++ b/game/client/c_rumble.cpp @@ -1,20 +1,35 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//======= Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: Rumble effects mixer for XBox // // $NoKeywords: $ // //=============================================================================// + #include "cbase.h" #include "c_rumble.h" #include "rumble_shared.h" #include "inputsystem/iinputsystem.h" -ConVar cl_rumblescale( "cl_rumblescale", "1.0", FCVAR_ARCHIVE | FCVAR_ARCHIVE_XBOX, "Scale sensitivity of rumble effects (0 to 1.0)" ); -ConVar cl_debugrumble( "cl_debugrumble", "0", FCVAR_ARCHIVE, "Turn on rumble debugging spew" ); +// NOTE: This has to be the last file included! +#include "tier0/memdbgon.h" + +void StopAllRumbleEffects( int userID ); + +#if !defined( _X360 ) + +// Stub these to nothing on the PC. +void RumbleEffect( int userID, unsigned char effectIndex, unsigned char rumbleData, unsigned char rumbleFlags ) {}; +void UpdateRumbleEffects( int userID ) {}; +void UpdateScreenShakeRumble( int userID, float shake, float balance ) {}; +void EnableRumbleOutput( int userID, bool bEnable ) {}; +void StopAllRumbleEffects( int userID ) {}; +#else -#define MAX_RUMBLE_CHANNELS 3 // Max concurrent rumble effects +ConVar cl_rumblescale( "cl_rumblescale", "1.0", FCVAR_ARCHIVE | FCVAR_ARCHIVE_XBOX | FCVAR_SS, "Scale sensitivity of rumble effects (0 to 1.0)" ); +ConVar cl_debugrumble( "cl_debugrumble", "0", FCVAR_ARCHIVE, "Turn on rumble debugging spew" ); +#define MAX_RUMBLE_CHANNELS 3 // Max concurrent rumble effects per player #define NUM_WAVE_SAMPLES 30 // Effects play at 10hz typedef struct @@ -166,7 +181,7 @@ void GenerateSquareWaveEffect( RumbleWaveform_t *pWaveform, const WaveGenParams_ while( i < NUM_WAVE_SAMPLES ) { - for( j = 0 ; j < steps && i < NUM_WAVE_SAMPLES; j++ ) + for( j = 0 ; j < steps ; j++ ) { if( params.leftChannel ) { @@ -177,7 +192,7 @@ void GenerateSquareWaveEffect( RumbleWaveform_t *pWaveform, const WaveGenParams_ pWaveform->amplitude_right[i++] = params.minAmplitude; } } - for( j = 0 ; j < steps && i < NUM_WAVE_SAMPLES; j++ ) + for( j = 0 ; j < steps ; j++ ) { if( params.leftChannel ) { @@ -255,22 +270,22 @@ class CRumbleEffects void Init(); void SetOutputEnabled( bool bEnable ); - void StartEffect( unsigned char effectIndex, unsigned char rumbleData, unsigned char rumbleFlags ); - void StopEffect( int effectIndex ); - void StopAllEffects(); + void StartEffect( int userID, unsigned char effectIndex, unsigned char rumbleData, unsigned char rumbleFlags ); + void StopEffect( int userID, int effectIndex ); + void StopAllEffects( int userID ); void ComputeAmplitudes( RumbleChannel_t *pChannel, float curtime, float *pLeft, float *pRight ); - void UpdateEffects( float curtime ); - void UpdateScreenShakeRumble( float shake, float balance ); + void UpdateEffects( int userID, float curtime ); + void UpdateScreenShakeRumble( int userID, float shake, float balance ); - RumbleChannel_t *FindExistingChannel( int index ); - RumbleChannel_t *FindAvailableChannel( int priority ); + RumbleChannel_t *FindExistingChannel( int userID, int index ); + RumbleChannel_t *FindAvailableChannel( int userID, int priority ); public: - RumbleChannel_t m_Channels[ MAX_RUMBLE_CHANNELS ]; + RumbleChannel_t m_Channels[ MAX_SPLITSCREEN_PLAYERS ][ MAX_RUMBLE_CHANNELS ]; RumbleWaveform_t m_Waveforms[ NUM_RUMBLE_EFFECTS ]; - float m_flScreenShake; + float m_flScreenShake[ MAX_SPLITSCREEN_PLAYERS ]; bool m_bOutputEnabled; }; @@ -282,17 +297,19 @@ CRumbleEffects g_RumbleEffects; void CRumbleEffects::Init() { SetOutputEnabled( true ); - - int i; - for( i = 0 ; i < MAX_RUMBLE_CHANNELS ; i++ ) + int userID,channel; + for( userID = 0 ; userID < MAX_SPLITSCREEN_PLAYERS ; userID++ ) { - m_Channels[i].in_use = false; - m_Channels[i].priority = 0; + for( channel = 0 ; channel < MAX_RUMBLE_CHANNELS ; channel++ ) + { + m_Channels[userID][channel].in_use = false; + m_Channels[userID][channel].priority = 0; + } } // Every effect defaults to this many samples. Call TerminateWaveform() to trim these. - for ( i = 0 ; i < NUM_RUMBLE_EFFECTS ; i++ ) + for ( int i = 0 ; i < NUM_RUMBLE_EFFECTS ; i++ ) { m_Waveforms[i].numSamples = NUM_WAVE_SAMPLES; } @@ -302,23 +319,23 @@ void CRumbleEffects::Init() GenerateFlatEffect( &m_Waveforms[RUMBLE_JEEP_ENGINE_LOOP], params ); // Pistol - params.Set( 1, 1.0f, false, 0.0f, 0.5f ); + params.Set( 1, 1.0f, false, 0.0f, 0.6f ); GenerateFlatEffect( &m_Waveforms[RUMBLE_PISTOL], params ); - TerminateWaveform( &m_Waveforms[RUMBLE_PISTOL], 3 ); + TerminateWaveform( &m_Waveforms[RUMBLE_PISTOL], 1 ); // SMG1 - params.Set( 1, 1.0f, true, 0.0f, 0.2f ); + params.Set( 1, 1.0f, true, 0.0f, 0.1f ); GenerateFlatEffect( &m_Waveforms[RUMBLE_SMG1], params ); - params.Set( 1, 1.0f, false, 0.0f, 0.4f ); + params.Set( 1, 1.0f, false, 0.0f, 0.3f ); GenerateFlatEffect( &m_Waveforms[RUMBLE_SMG1], params ); - TerminateWaveform( &m_Waveforms[RUMBLE_SMG1], 3 ); + TerminateWaveform( &m_Waveforms[RUMBLE_SMG1], 1 ); // AR2 params.Set( 1, 1.0f, true, 0.0f, 0.5f ); GenerateFlatEffect( &m_Waveforms[RUMBLE_AR2], params ); params.Set( 1, 1.0f, false, 0.0f, 0.3f ); GenerateFlatEffect( &m_Waveforms[RUMBLE_AR2], params ); - TerminateWaveform( &m_Waveforms[RUMBLE_AR2], 3 ); + TerminateWaveform( &m_Waveforms[RUMBLE_AR2], 1 ); // AR2 Alt params.Set( 1, 1.0f, true, 0.0, 0.5f ); @@ -337,9 +354,9 @@ void CRumbleEffects::Init() TerminateWaveform( &m_Waveforms[RUMBLE_357], 2 ); // Shotgun - params.Set( 1, 1.0f, true, 0.0f, 0.8f ); + params.Set( 1, 1.0f, true, 0.0f, 0.7f ); GenerateFlatEffect( &m_Waveforms[RUMBLE_SHOTGUN_SINGLE], params ); - params.Set( 1, 1.0f, false, 0.0f, 0.8f ); + params.Set( 1, 1.0f, false, 0.0f, 0.7f ); GenerateFlatEffect( &m_Waveforms[RUMBLE_SHOTGUN_SINGLE], params ); TerminateWaveform( &m_Waveforms[RUMBLE_SHOTGUN_SINGLE], 3 ); @@ -424,13 +441,13 @@ void CRumbleEffects::Init() //--------------------------------------------------------- //--------------------------------------------------------- -RumbleChannel_t *CRumbleEffects::FindExistingChannel( int index ) +RumbleChannel_t *CRumbleEffects::FindExistingChannel( int userID, int index ) { RumbleChannel_t *pChannel; for( int i = 0 ; i < MAX_RUMBLE_CHANNELS ; i++ ) { - pChannel = &m_Channels[i]; + pChannel = &m_Channels[userID][i]; if( pChannel->in_use && pChannel->waveformIndex == index ) { @@ -446,14 +463,14 @@ RumbleChannel_t *CRumbleEffects::FindExistingChannel( int index ) //--------------------------------------------------------- // priority - the priority of the effect we want to play. //--------------------------------------------------------- -RumbleChannel_t *CRumbleEffects::FindAvailableChannel( int priority ) +RumbleChannel_t *CRumbleEffects::FindAvailableChannel( int userID, int priority ) { RumbleChannel_t *pChannel; int i; for( i = 0 ; i < MAX_RUMBLE_CHANNELS ; i++ ) { - pChannel = &m_Channels[i]; + pChannel = &m_Channels[userID][i]; if( !pChannel->in_use ) { @@ -465,10 +482,10 @@ RumbleChannel_t *CRumbleEffects::FindAvailableChannel( int priority ) RumbleChannel_t *pBestChannel = NULL; float oldestChannel = FLT_MAX; - // All channels already in use. Find a channel to slam. + // All channels already in use. Find a channel to slam. Make sure it belongs to this userID for( i = 0 ; i < MAX_RUMBLE_CHANNELS ; i++ ) { - pChannel = &m_Channels[i]; + pChannel = &m_Channels[userID][i]; if( (pChannel->rumbleFlags & RUMBLE_FLAG_LOOP) ) continue; @@ -515,25 +532,27 @@ void CRumbleEffects::SetOutputEnabled( bool bEnable ) { // Tell the hardware to shut down motors right now, in case this gets called // and some other process blocks us before the next rumble system update. - m_flScreenShake = 0.0f; - - inputsystem->StopRumble(); + for( int i = 0 ; i < MAX_SPLITSCREEN_PLAYERS ; i++ ) + { + m_flScreenShake[ i ] = 0.0f; + StopAllRumbleEffects( i ); + } } } //--------------------------------------------------------- //--------------------------------------------------------- -void CRumbleEffects::StartEffect( unsigned char effectIndex, unsigned char rumbleData, unsigned char rumbleFlags ) +void CRumbleEffects::StartEffect( int userID, unsigned char effectIndex, unsigned char rumbleData, unsigned char rumbleFlags ) { if( effectIndex == RUMBLE_STOP_ALL ) { - StopAllEffects(); + StopAllEffects( userID ); return; } if( rumbleFlags & RUMBLE_FLAG_STOP ) { - StopEffect( effectIndex ); + StopEffect( userID, effectIndex ); return; } @@ -543,12 +562,12 @@ void CRumbleEffects::StartEffect( unsigned char effectIndex, unsigned char rumbl if( (rumbleFlags & RUMBLE_FLAG_RESTART) ) { // Try to find any active instance of this effect and replace it. - pChannel = FindExistingChannel( effectIndex ); + pChannel = FindExistingChannel( userID, effectIndex ); } if( (rumbleFlags & RUMBLE_FLAG_ONLYONE) ) { - pChannel = FindExistingChannel( effectIndex ); + pChannel = FindExistingChannel( userID, effectIndex ); if( pChannel ) { @@ -559,7 +578,7 @@ void CRumbleEffects::StartEffect( unsigned char effectIndex, unsigned char rumbl if( (rumbleFlags & RUMBLE_FLAG_UPDATE_SCALE) ) { - pChannel = FindExistingChannel( effectIndex ); + pChannel = FindExistingChannel( userID, effectIndex ); if( pChannel ) { pChannel->scale = ((float)rumbleData) / 100.0f; @@ -572,7 +591,7 @@ void CRumbleEffects::StartEffect( unsigned char effectIndex, unsigned char rumbl if( !pChannel ) { - pChannel = FindAvailableChannel( priority ); + pChannel = FindAvailableChannel( userID, priority ); } if( pChannel ) @@ -602,27 +621,27 @@ void CRumbleEffects::StartEffect( unsigned char effectIndex, unsigned char rumbl //--------------------------------------------------------- // Find all playing effects of this type and stop them. //--------------------------------------------------------- -void CRumbleEffects::StopEffect( int effectIndex ) +void CRumbleEffects::StopEffect( int userID, int effectIndex ) { for( int i = 0 ; i < MAX_RUMBLE_CHANNELS ; i++ ) { - if( m_Channels[i].in_use && m_Channels[i].waveformIndex == effectIndex ) + if( m_Channels[userID][i].in_use && m_Channels[userID][i].waveformIndex == effectIndex ) { - m_Channels[i].in_use = false; + m_Channels[userID][i].in_use = false; } } } //--------------------------------------------------------- //--------------------------------------------------------- -void CRumbleEffects::StopAllEffects() +void CRumbleEffects::StopAllEffects( int userID ) { for( int i = 0 ; i < MAX_RUMBLE_CHANNELS ; i++ ) { - m_Channels[i].in_use = false; + m_Channels[userID][i].in_use = false; } - m_flScreenShake = 0.0f; + m_flScreenShake[ userID ] = 0.0f; } //--------------------------------------------------------- @@ -708,22 +727,22 @@ void CRumbleEffects::ComputeAmplitudes( RumbleChannel_t *pChannel, float curtime //--------------------------------------------------------- //--------------------------------------------------------- -void CRumbleEffects::UpdateScreenShakeRumble( float shake, float balance ) +void CRumbleEffects::UpdateScreenShakeRumble( int userID, float shake, float balance ) { if( m_bOutputEnabled ) { - m_flScreenShake = shake; + m_flScreenShake[ userID ] = shake; } else { // Silence - m_flScreenShake = 0.0f; + m_flScreenShake[ userID ] = 0.0f; } } //--------------------------------------------------------- //--------------------------------------------------------- -void CRumbleEffects::UpdateEffects( float curtime ) +void CRumbleEffects::UpdateEffects( int userID, float curtime ) { float fLeftMotor = 0.0f; float fRightMotor = 0.0f; @@ -731,7 +750,7 @@ void CRumbleEffects::UpdateEffects( float curtime ) for( int i = 0 ; i < MAX_RUMBLE_CHANNELS ; i++ ) { // Expire old channels - RumbleChannel_t *pChannel = & m_Channels[i]; + RumbleChannel_t *pChannel = &m_Channels[userID][i]; if( pChannel->in_use ) { @@ -747,15 +766,15 @@ void CRumbleEffects::UpdateEffects( float curtime ) // Add in any screenshake float shakeLeft = 0.0f; float shakeRight = 0.0f; - if( m_flScreenShake != 0.0f ) + if( m_flScreenShake[ userID ] != 0.0f ) { - if( m_flScreenShake < 0.0f ) + if( m_flScreenShake[ userID ] < 0.0f ) { - shakeLeft = fabs( m_flScreenShake ); + shakeLeft = fabs( m_flScreenShake[ userID ] ); } else { - shakeRight = m_flScreenShake; + shakeRight = m_flScreenShake[ userID ]; } } @@ -772,50 +791,54 @@ void CRumbleEffects::UpdateEffects( float curtime ) fRightMotor = 0.0f; } - inputsystem->SetRumble( fLeftMotor, fRightMotor ); + inputsystem->SetRumble( fLeftMotor, fRightMotor, userID ); } //--------------------------------------------------------- //--------------------------------------------------------- -void StopAllRumbleEffects( void ) +void StopAllRumbleEffects( int userID ) { - g_RumbleEffects.StopAllEffects(); + // Kill all rumble channels that have effects assigned to this userID, + // and stop the motors. + g_RumbleEffects.StopAllEffects( userID ); - inputsystem->StopRumble(); + inputsystem->StopRumble( userID ); } //--------------------------------------------------------- //--------------------------------------------------------- -void RumbleEffect( unsigned char effectIndex, unsigned char rumbleData, unsigned char rumbleFlags ) +void RumbleEffect( int userID, unsigned char effectIndex, unsigned char rumbleData, unsigned char rumbleFlags ) { - g_RumbleEffects.StartEffect( effectIndex, rumbleData, rumbleFlags ); + g_RumbleEffects.StartEffect( userID, effectIndex, rumbleData, rumbleFlags ); } //--------------------------------------------------------- //--------------------------------------------------------- -void UpdateRumbleEffects() +void UpdateRumbleEffects( int userID ) { - C_BasePlayer *localPlayer = C_BasePlayer::GetLocalPlayer(); - if( !localPlayer || !localPlayer->IsAlive() ) + C_BasePlayer *player = C_BasePlayer::GetLocalPlayer( XBX_GetSlotByUserId( userID ) ); + + if( !player || !player->IsAlive() ) { - StopAllRumbleEffects(); + StopAllRumbleEffects( userID ); return; } - g_RumbleEffects.UpdateEffects( gpGlobals->curtime ); + g_RumbleEffects.UpdateEffects( userID, gpGlobals->curtime ); } //--------------------------------------------------------- //--------------------------------------------------------- -void UpdateScreenShakeRumble( float shake, float balance ) +void UpdateScreenShakeRumble( int userID, float shake, float balance ) { - C_BasePlayer *localPlayer = C_BasePlayer::GetLocalPlayer(); - if( !localPlayer || !localPlayer->IsAlive() ) + C_BasePlayer *player = C_BasePlayer::GetLocalPlayer( XBX_GetSlotByUserId( userID ) ); + + if( !player || !player->IsAlive() ) { return; } - g_RumbleEffects.UpdateScreenShakeRumble( shake, balance ); + g_RumbleEffects.UpdateScreenShakeRumble( userID, shake, balance ); } //--------------------------------------------------------- @@ -824,3 +847,4 @@ void EnableRumbleOutput( bool bEnable ) { g_RumbleEffects.SetOutputEnabled( bEnable ); } +#endif//_X360 \ No newline at end of file diff --git a/game/client/c_rumble.h b/game/client/c_rumble.h index 3772bfb37..3ef6b1e11 100644 --- a/game/client/c_rumble.h +++ b/game/client/c_rumble.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//======= Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: Rumble effects mixer for XBox // @@ -9,10 +9,11 @@ #ifndef C_RUMBLE_H #define C_RUMBLE_H -extern void RumbleEffect( unsigned char effectIndex, unsigned char rumbleData, unsigned char rumbleFlags ); -extern void UpdateRumbleEffects(); -extern void UpdateScreenShakeRumble( float shake, float balance = 0 ); -extern void EnableRumbleOutput( bool bEnable ); +extern void RumbleEffect( int userID, unsigned char effectIndex, unsigned char rumbleData, unsigned char rumbleFlags ); +extern void UpdateRumbleEffects( int userID ); +extern void UpdateScreenShakeRumble( int userID, float shake, float balance = 0 ); +extern void EnableRumbleOutput( int userID, bool bEnable ); +extern void StopAllRumbleEffects( int userID ); #endif//C_RUMBLE_H diff --git a/game/client/c_sceneentity.cpp b/game/client/c_sceneentity.cpp index b44b59fd4..755302c24 100644 --- a/game/client/c_sceneentity.cpp +++ b/game/client/c_sceneentity.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // @@ -10,13 +10,15 @@ #include "choreoevent.h" #include "choreoactor.h" #include "choreochannel.h" +#include "choreoscene.h" #include "filesystem.h" #include "ichoreoeventcallback.h" #include "scenefilecache/ISceneFileCache.h" #include "materialsystem/imaterialsystemhardwareconfig.h" #include "tier2/tier2.h" #include "hud_closecaption.h" -#include "tier0/icommandline.h" +#include "tier1/fmtstr.h" +#include "../../common/blackbox_helper.h" #include "c_sceneentity.h" @@ -69,24 +71,34 @@ C_SceneEntity::~C_SceneEntity( void ) void C_SceneEntity::OnResetClientTime() { - // In TF2 we ignore this as the scene is played entirely client-side. -#ifndef TF_CLIENT_DLL m_flCurrentTime = m_flForceClientTime; -#endif } char const *C_SceneEntity::GetSceneFileName() { - return g_pStringTableClientSideChoreoScenes->GetString( m_nSceneStringIndex ); + char const *pStr = g_pStringTableClientSideChoreoScenes->GetString( m_nSceneStringIndex ); + if ( pStr ) + return pStr; + + static bool bFirst = true; + if ( bFirst ) + { + bFirst = false; + Assert( 0 ); + Warning( "GetSceneFilename() failed for scene index %d\n", m_nSceneStringIndex ); + } + return ""; } + ConVar mp_usehwmvcds( "mp_usehwmvcds", "0", NULL, "Enable the use of the hw morph vcd(s). (-1 = never, 1 = always, 0 = based upon GPU)" ); // -1 = never, 0 = if hasfastvertextextures, 1 = always +ConVar scene_vcdautosave( "scene_vcdautosave", "0", 0, "Create a savegame before VCD playback" ); + bool UseHWMorphVCDs() { -// if ( mp_usehwmvcds.GetInt() == 0 ) -// return g_pMaterialSystemHardwareConfig->HasFastVertexTextures(); -// return mp_usehwmvcds.GetInt() > 0; - return false; + if ( mp_usehwmvcds.GetInt() == 0 ) + return g_pMaterialSystemHardwareConfig->HasFastVertexTextures(); + return mp_usehwmvcds.GetInt() > 0; } //----------------------------------------------------------------------------- @@ -174,7 +186,7 @@ void C_SceneEntity::ResetActorFlexesForScene() } // Reset the prediction interpolation values. - pFlexActor->m_iv_flexWeight.Reset(); + pFlexActor->m_iv_flexWeight.Reset( gpGlobals->curtime ); } } @@ -317,15 +329,8 @@ void C_SceneEntity::PostDataUpdate( DataUpdateType_t updateType ) char const *str = GetSceneFileName(); char szFilename[MAX_PATH]; - if ( str ) - { - Assert( V_strlen( str ) < MAX_PATH ); - V_strcpy( szFilename, str ); - } - else - { - szFilename[0] = '\0'; - } + Assert( V_strlen( str ) < MAX_PATH ); + V_strcpy( szFilename, str ); char szSceneHWM[MAX_PATH]; if ( GetHWMorphSceneFileName( szFilename, szSceneHWM ) ) @@ -420,61 +425,10 @@ void C_SceneEntity::PreDataUpdate( DataUpdateType_t updateType ) //----------------------------------------------------------------------------- void C_SceneEntity::ProcessEvent( float currenttime, CChoreoScene *scene, CChoreoEvent *event ) { - // For now we only need to process events if we go back in time. - if ( currenttime < event->m_flPrevTime ) - { - //if ( !V_strstr( scene->GetFilename(), "idleloop" ) ) - //{ - // Msg( "ProcessEvent( %6.4f, %32s %6.4f ) %6.4f\n", currenttime, event->GetName(), event->m_flPrevTime, m_flCurrentTime ); - //} - - C_BaseFlex *pActor = NULL; - CChoreoActor *actor = event->GetActor(); - if ( actor ) - { - pActor = FindNamedActor( actor ); - if ( NULL == pActor ) - { - // TODO: QueueProcessEvent - // This can occur if we haven't been networked an actor yet... we need to queue it so that we can - // fire off the process event as soon as we have the actor resident on the client. - return; - } - } - - switch ( event->GetType() ) - { - case CChoreoEvent::GESTURE: - { - // Verify data. - Assert( m_bMultiplayer ); - Assert( scene != NULL ); - Assert( event != NULL ); - - if ( pActor ) - { - DispatchProcessGesture( scene, pActor, event ); - } - } - break; - case CChoreoEvent::SEQUENCE: - { - // Verify data. - Assert( m_bMultiplayer ); - Assert( scene != NULL ); - Assert( event != NULL ); + return; +} - if ( pActor ) - { - DispatchProcessSequence( scene, pActor, event ); - } - } - break; - } - } - event->m_flPrevTime = currenttime; -} //----------------------------------------------------------------------------- // Purpose: Called for events that are part of a pause condition @@ -534,7 +488,11 @@ void C_SceneEntity::StartEvent( float currenttime, CChoreoScene *scene, CChoreoE } Scene_Printf( "%s : %8.2f: start %s\n", GetSceneFileName(), currenttime, event->GetDescription() ); - + if ( IsPC() && event ) + { + BlackBox_Record( "vcd", "%s : %8.2f: start %s", GetSceneFileName(), currenttime, event->GetDescription() ); + } + switch ( event->GetType() ) { case CChoreoEvent::FLEXANIMATION: @@ -610,8 +568,6 @@ void C_SceneEntity::StartEvent( float currenttime, CChoreoScene *scene, CChoreoE default: break; } - - event->m_flPrevTime = currenttime; } //----------------------------------------------------------------------------- @@ -674,7 +630,7 @@ void C_SceneEntity::DispatchStartSpeak( CChoreoScene *scene, C_BaseFlex *actor, es.m_pSoundName = event->GetParameters(); EmitSound( filter, actor->entindex(), es ); - actor->AddSceneEvent( scene, event, NULL, IsClientOnly() ); + actor->AddSceneEvent( scene, event, NULL, IsClientOnly(), this ); // Close captioning only on master token no matter what... if ( event->GetCloseCaptionType() == CChoreoEvent::CC_MASTER ) @@ -698,7 +654,7 @@ void C_SceneEntity::DispatchStartSpeak( CChoreoScene *scene, C_BaseFlex *actor, float durationLong = endtime - event->GetStartTime(); float duration = MAX( durationShort, durationLong ); - CHudCloseCaption *hudCloseCaption = GET_HUDELEMENT( CHudCloseCaption ); + CHudCloseCaption *hudCloseCaption = GET_FULLSCREEN_HUDELEMENT( CHudCloseCaption ); if ( hudCloseCaption ) { hudCloseCaption->ProcessCaption( lowercase, duration ); @@ -787,19 +743,32 @@ void C_SceneEntity::EndEvent( float currenttime, CChoreoScene *scene, CChoreoEve } } -bool CChoreoStringPool::GetString( short stringId, char *buff, int buffSize ) +//----------------------------------------------------------------------------- +// Binary compiled VCDs get their strings from a pool +//----------------------------------------------------------------------------- +class CChoreoStringPool : public IChoreoStringPool { - // fetch from compiled pool - const char *pString = scenefilecache->GetSceneString( stringId ); - if ( !pString ) +public: + short FindOrAddString( const char *pString ) { - V_strncpy( buff, "", buffSize ); - return false; + // huh?, no compilation at run time, only fetches + Assert( 0 ); + return -1; } - V_strncpy( buff, pString, buffSize ); - return true; -} + bool GetString( short stringId, char *buff, int buffSize ) + { + // fetch from compiled pool + const char *pString = scenefilecache->GetSceneString( stringId ); + if ( !pString ) + { + V_strncpy( buff, "", buffSize ); + return false; + } + V_strncpy( buff, pString, buffSize ); + return true; + } +}; CChoreoStringPool g_ChoreoStringPool; CChoreoScene *C_SceneEntity::LoadScene( const char *filename ) @@ -855,6 +824,33 @@ CChoreoScene *C_SceneEntity::LoadScene( const char *filename ) //----------------------------------------------------------------------------- void C_SceneEntity::LoadSceneFromFile( const char *filename ) { + // Save game if convar is set - useful when iterating on a scene with Foundry + if ( scene_vcdautosave.GetBool() ) + { + char szVCDFileName[64]; + char szSaveFileName[64]; + char szClientCmd[128]; + + // Create the faceposer sub-directory under the root savegame directory + if (!g_pFullFileSystem->IsDirectory( "SAVE\\faceposer", "MOD" )) + { + g_pFullFileSystem->CreateDirHierarchy( "SAVE\\faceposer", "MOD" ); + } + + // Construct save command to send to the engine + V_FileBase( filename, szVCDFileName, sizeof(szVCDFileName) ); + V_snprintf( szClientCmd, sizeof(szClientCmd), "save faceposer\\%s\n", szVCDFileName ); + + // Construct name of file that would be created if savegame occurs + V_snprintf( szSaveFileName, sizeof(szSaveFileName), "SAVE\\faceposer\\%s.sav", szVCDFileName ); + + // Only create a savegame for this VCD if there isn't one already + if (!g_pFullFileSystem->FileExists( szSaveFileName, "MOD" )) + { + engine->ClientCmd( szClientCmd ); + } + } + UnloadScene(); m_pScene = LoadScene( filename ); } @@ -878,6 +874,7 @@ void C_SceneEntity::ClearSceneEvents( CChoreoScene *scene, bool canceled ) } WipeQueuedEvents(); + OnResetClientTime(); } //----------------------------------------------------------------------------- @@ -911,7 +908,7 @@ void C_SceneEntity::UnloadScene( void ) //----------------------------------------------------------------------------- void C_SceneEntity::DispatchStartFlexAnimation( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event ) { - actor->AddSceneEvent( scene, event, NULL, IsClientOnly() ); + actor->AddSceneEvent( scene, event, NULL, IsClientOnly() || IsMultiplayer(), this ); } //----------------------------------------------------------------------------- @@ -931,7 +928,7 @@ void C_SceneEntity::DispatchEndFlexAnimation( CChoreoScene *scene, C_BaseFlex *a //----------------------------------------------------------------------------- void C_SceneEntity::DispatchStartExpression( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event ) { - actor->AddSceneEvent( scene, event, NULL, IsClientOnly() ); + actor->AddSceneEvent( scene, event, NULL, IsClientOnly() || IsMultiplayer(), this ); } //----------------------------------------------------------------------------- @@ -955,36 +952,7 @@ void C_SceneEntity::DispatchStartGesture( CChoreoScene *scene, C_BaseFlex *actor if ( !Q_stricmp( event->GetName(), "NULL" ) ) return; - actor->AddSceneEvent( scene, event, NULL, IsClientOnly() ); -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : *actor - -// *parameters - -//----------------------------------------------------------------------------- -void C_SceneEntity::DispatchProcessGesture( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event ) -{ - // Ingore null gestures - if ( !Q_stricmp( event->GetName(), "NULL" ) ) - return; - - actor->RemoveSceneEvent( scene, event, false ); - actor->AddSceneEvent( scene, event, NULL, IsClientOnly() ); -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : *actor - -// *parameters - -//----------------------------------------------------------------------------- -void C_SceneEntity::DispatchEndGesture( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event ) -{ - // Ingore null gestures - if ( !Q_stricmp( event->GetName(), "NULL" ) ) - return; - - actor->RemoveSceneEvent( scene, event, false ); + actor->AddSceneEvent( scene, event, NULL, IsClientOnly() || IsMultiplayer(), this ); } //----------------------------------------------------------------------------- @@ -993,25 +961,29 @@ void C_SceneEntity::DispatchEndGesture( CChoreoScene *scene, C_BaseFlex *actor, //----------------------------------------------------------------------------- void C_SceneEntity::DispatchStartSequence( CChoreoScene *scene, CBaseFlex *actor, CChoreoEvent *event ) { - actor->AddSceneEvent( scene, event, NULL, IsClientOnly() ); + actor->AddSceneEvent( scene, event, NULL, IsClientOnly() || IsMultiplayer(), this ); } //----------------------------------------------------------------------------- // Purpose: // Input : *actor - //----------------------------------------------------------------------------- -void C_SceneEntity::DispatchProcessSequence( CChoreoScene *scene, CBaseFlex *actor, CChoreoEvent *event ) +void C_SceneEntity::DispatchEndSequence( CChoreoScene *scene, CBaseFlex *actor, CChoreoEvent *event ) { actor->RemoveSceneEvent( scene, event, false ); - actor->AddSceneEvent( scene, event, NULL, IsClientOnly() ); } //----------------------------------------------------------------------------- // Purpose: // Input : *actor - +// *parameters - //----------------------------------------------------------------------------- -void C_SceneEntity::DispatchEndSequence( CChoreoScene *scene, CBaseFlex *actor, CChoreoEvent *event ) +void C_SceneEntity::DispatchEndGesture( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event ) { + // Ingore null gestures + if ( !Q_stricmp( event->GetName(), "NULL" ) ) + return; + actor->RemoveSceneEvent( scene, event, false ); } @@ -1177,7 +1149,7 @@ void C_SceneEntity::PrefetchAnimBlocks( CChoreoScene *pScene ) // Async load the animation int iFrame = 0; - const mstudioanim_t *panim = animdesc.pAnim( &iFrame ); + const byte *panim = animdesc.pAnim( &iFrame ); if ( panim ) { ++nResident; diff --git a/game/client/c_sceneentity.h b/game/client/c_sceneentity.h index 28efcd191..d0fd3b6ed 100644 --- a/game/client/c_sceneentity.h +++ b/game/client/c_sceneentity.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2007, Valve Corporation, All rights reserved. ============// // // Purpose: // @@ -12,7 +12,6 @@ #endif #include "ichoreoeventcallback.h" -#include "choreoscene.h" class C_SceneEntity : public C_BaseEntity, public IChoreoEventCallback { @@ -48,6 +47,7 @@ class C_SceneEntity : public C_BaseEntity, public IChoreoEventCallback virtual void DispatchEndSpeak( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event ); bool IsClientOnly( void ){ return m_bClientOnly; } + bool IsMultiplayer() const { return m_bMultiplayer; } private: @@ -66,10 +66,8 @@ class C_SceneEntity : public C_BaseEntity, public IChoreoEventCallback virtual void DispatchStartExpression( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event ); virtual void DispatchEndExpression( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event ); virtual void DispatchStartGesture( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event ); - virtual void DispatchProcessGesture( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event ); virtual void DispatchEndGesture( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event ); virtual void DispatchStartSequence( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event ); - virtual void DispatchProcessSequence( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event ); virtual void DispatchEndSequence( CChoreoScene *scene, C_BaseFlex *actor, CChoreoEvent *event ); void DispatchProcessLoop( CChoreoScene *scene, CChoreoEvent *event ); @@ -115,20 +113,4 @@ class C_SceneEntity : public C_BaseEntity, public IChoreoEventCallback CUtlVector< QueuedEvents_t > m_QueuedEvents; }; -//----------------------------------------------------------------------------- -// Binary compiled VCDs get their strings from a pool -//----------------------------------------------------------------------------- -class CChoreoStringPool : public IChoreoStringPool -{ -public: - short FindOrAddString( const char *pString ) - { - // huh?, no compilation at run time, only fetches - Assert( 0 ); - return -1; - } - - bool GetString( short stringId, char *buff, int buffSize ); -}; - #endif // C_SCENEENTITY_H diff --git a/game/client/c_shadowcontrol.cpp b/game/client/c_shadowcontrol.cpp index 801692418..1d2d3b6a6 100644 --- a/game/client/c_shadowcontrol.cpp +++ b/game/client/c_shadowcontrol.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: Shadow control entity. // @@ -32,13 +32,15 @@ class C_ShadowControl : public C_BaseEntity color32 m_shadowColor; float m_flShadowMaxDist; bool m_bDisableShadows; + bool m_bEnableLocalLightShadows; }; IMPLEMENT_CLIENTCLASS_DT(C_ShadowControl, DT_ShadowControl, CShadowControl) RecvPropVector(RECVINFO(m_shadowDirection)), - RecvPropInt(RECVINFO(m_shadowColor)), + RecvPropInt(RECVINFO(m_shadowColor), 0, RecvProxy_Int32ToColor32), RecvPropFloat(RECVINFO(m_flShadowMaxDist)), RecvPropBool(RECVINFO(m_bDisableShadows)), + RecvPropBool(RECVINFO(m_bEnableLocalLightShadows)), END_RECV_TABLE() @@ -54,6 +56,7 @@ void C_ShadowControl::OnDataChanged(DataUpdateType_t updateType) g_pClientShadowMgr->SetShadowColor( m_shadowColor.r, m_shadowColor.g, m_shadowColor.b ); g_pClientShadowMgr->SetShadowDistance( m_flShadowMaxDist ); g_pClientShadowMgr->SetShadowsDisabled( m_bDisableShadows ); + g_pClientShadowMgr->SetShadowFromWorldLightsEnabled( m_bEnableLocalLightShadows ); } //------------------------------------------------------------------------------ diff --git a/game/client/c_slideshow_display.cpp b/game/client/c_slideshow_display.cpp index 90ee0a743..7a5318a60 100644 --- a/game/client/c_slideshow_display.cpp +++ b/game/client/c_slideshow_display.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // @@ -12,7 +12,7 @@ #include "engine/IEngineSound.h" #include "dlight.h" #include "iefx.h" -#include "SoundEmitterSystem/isoundemittersystembase.h" +#include "soundemittersystem/isoundemittersystembase.h" #include "filesystem.h" #include "KeyValues.h" diff --git a/game/client/c_slideshow_display.h b/game/client/c_slideshow_display.h index 0a88d57c3..059ca443e 100644 --- a/game/client/c_slideshow_display.h +++ b/game/client/c_slideshow_display.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // diff --git a/game/client/c_smoke_trail.cpp b/game/client/c_smoke_trail.cpp index 7f4b60787..5968155ea 100644 --- a/game/client/c_smoke_trail.cpp +++ b/game/client/c_smoke_trail.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // @@ -8,15 +8,15 @@ #include "cbase.h" #include "c_smoke_trail.h" #include "fx.h" -#include "engine/ivdebugoverlay.h" -#include "engine/IEngineSound.h" +#include "engine/IVDebugOverlay.h" +#include "engine/ienginesound.h" #include "c_te_effect_dispatch.h" #include "glow_overlay.h" #include "fx_explosion.h" -#include "tier1/KeyValues.h" +#include "tier1/keyvalues.h" #include "toolframework_client.h" #include "view.h" -#include "clienteffectprecachesystem.h" +#include "precache_register.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -418,7 +418,7 @@ void C_SmokeTrail::CleanupToolRecordingState( KeyValues *msg ) // FIXME: Until we can interpolate ent logs during emission, this can't work KeyValues *pPosition = pInitializers->FindKey( "DmePositionPointToEntityInitializer", true ); - pPosition->SetPtr( "entindex", (void*)(intp)pEnt->entindex() ); + pPosition->SetPtr( "entindex", (void*)pEnt->entindex() ); pPosition->SetInt( "attachmentIndex", m_nAttachment ); pPosition->SetFloat( "randomDist", m_SpawnRadius ); pPosition->SetFloat( "startx", pEnt->GetAbsOrigin().x ); @@ -430,7 +430,7 @@ void C_SmokeTrail::CleanupToolRecordingState( KeyValues *msg ) pLifetime->SetFloat( "maxLifetime", m_ParticleLifetime ); KeyValues *pVelocity = pInitializers->FindKey( "DmeAttachmentVelocityInitializer", true ); - pVelocity->SetPtr( "entindex", (void*)(intp)entindex() ); + pVelocity->SetPtr( "entindex", (void*)entindex() ); pVelocity->SetFloat( "minAttachmentSpeed", m_MinDirectedSpeed ); pVelocity->SetFloat( "maxAttachmentSpeed", m_MaxDirectedSpeed ); pVelocity->SetFloat( "minRandomSpeed", m_MinSpeed ); @@ -445,11 +445,10 @@ void C_SmokeTrail::CleanupToolRecordingState( KeyValues *msg ) pRollSpeed->SetFloat( "maxRollSpeed", 1.0f ); KeyValues *pColor = pInitializers->FindKey( "DmeRandomValueColorInitializer", true ); - Color c( - FastFToC( clamp( m_StartColor.x, 0.f, 1.f ) ), - FastFToC( clamp( m_StartColor.y, 0.f, 1.f ) ), - FastFToC( clamp( m_StartColor.z, 0.f, 1.f ) ), - 255 ); + Color c( + clamp( m_StartColor.x * 255.0f, 0, 255 ), + clamp( m_StartColor.y * 255.0f, 0, 255 ), + clamp( m_StartColor.z * 255.0f, 0, 255 ), 255 ); pColor->SetColor( "startColor", c ); pColor->SetFloat( "minStartValueDelta", -0.2f ); pColor->SetFloat( "maxStartValueDelta", 0.2f ); @@ -1050,9 +1049,10 @@ void C_SporeExplosion::Update( float fTimeDelta ) { if( m_bEmit ) { + int nSlot = GET_ACTIVE_SPLITSCREEN_SLOT(); float tempDelta = fTimeDelta; - float flDist = (MainViewOrigin() - GetAbsOrigin()).Length(); + float flDist = (MainViewOrigin(nSlot) - GetAbsOrigin()).Length(); //Lower the spawnrate by half if we're far away from it. if ( cl_sporeclipdistance.GetFloat() <= flDist ) @@ -1124,7 +1124,9 @@ void RPGShotDownCallback( const CEffectData &data ) } } -DECLARE_CLIENT_EFFECT( "RPGShotDown", RPGShotDownCallback ); +DECLARE_CLIENT_EFFECT_BEGIN( RPGShotDown, RPGShotDownCallback ) + PRECACHE( GAMESOUND, "Missile.ShotDown" ) +DECLARE_CLIENT_EFFECT_END() @@ -1582,47 +1584,7 @@ void C_FireTrail::Update( float fTimeDelta ) m_vecLastPosition = GetAbsOrigin(); } -//----------------------------------------------------------------------------- -// Purpose: High drag, non color changing particle -//----------------------------------------------------------------------------- - - -class CDustFollower : public CSimpleEmitter -{ -public: - - CDustFollower( const char *pDebugName ) : CSimpleEmitter( pDebugName ) {} - - //Create - static CDustFollower *Create( const char *pDebugName ) - { - return new CDustFollower( pDebugName ); - } - - //Alpha - virtual float UpdateAlpha( const SimpleParticle *pParticle ) - { - return ( ((float)pParticle->m_uchStartAlpha/255.0f) * sin( M_PI * (pParticle->m_flLifetime / pParticle->m_flDieTime) ) ); - } - - virtual void UpdateVelocity( SimpleParticle *pParticle, float timeDelta ) - { - pParticle->m_vecVelocity = pParticle->m_vecVelocity * ExponentialDecay( 0.3, timeDelta ); - } - - //Roll - virtual float UpdateRoll( SimpleParticle *pParticle, float timeDelta ) - { - pParticle->m_flRoll += pParticle->m_flRollDelta * timeDelta; - - pParticle->m_flRollDelta *= ExponentialDecay( 0.5, timeDelta ); - - return pParticle->m_flRoll; - } -private: - CDustFollower( const CDustFollower & ); -}; // Datatable.. this can have all the smoketrail parameters when we need it to. @@ -1728,26 +1690,26 @@ void C_DustTrail::OnDataChanged(DataUpdateType_t updateType) // FIXME: These all have to be moved out of this old system and into the new to leverage art assets! -CLIENTEFFECT_REGISTER_BEGIN( PrecacheEffectDusttrail ) -CLIENTEFFECT_MATERIAL( "particle/smokesprites_0001" ) +PRECACHE_REGISTER_BEGIN( GLOBAL, PrecacheEffectDusttrail ) +PRECACHE( MATERIAL, "particle/smokesprites_0001" ) /* -CLIENTEFFECT_MATERIAL( "particle/smokesprites_0002" ) -CLIENTEFFECT_MATERIAL( "particle/smokesprites_0003" ) -CLIENTEFFECT_MATERIAL( "particle/smokesprites_0004" ) -CLIENTEFFECT_MATERIAL( "particle/smokesprites_0005" ) -CLIENTEFFECT_MATERIAL( "particle/smokesprites_0006" ) -CLIENTEFFECT_MATERIAL( "particle/smokesprites_0007" ) -CLIENTEFFECT_MATERIAL( "particle/smokesprites_0008" ) -CLIENTEFFECT_MATERIAL( "particle/smokesprites_0009" ) -CLIENTEFFECT_MATERIAL( "particle/smokesprites_0010" ) -CLIENTEFFECT_MATERIAL( "particle/smokesprites_0011" ) -CLIENTEFFECT_MATERIAL( "particle/smokesprites_0012" ) -CLIENTEFFECT_MATERIAL( "particle/smokesprites_0013" ) -CLIENTEFFECT_MATERIAL( "particle/smokesprites_0014" ) -CLIENTEFFECT_MATERIAL( "particle/smokesprites_0015" ) -CLIENTEFFECT_MATERIAL( "particle/smokesprites_0016" ) +PRECACHE( MATERIAL, "particle/smokesprites_0002" ) +PRECACHE( MATERIAL, "particle/smokesprites_0003" ) +PRECACHE( MATERIAL, "particle/smokesprites_0004" ) +PRECACHE( MATERIAL, "particle/smokesprites_0005" ) +PRECACHE( MATERIAL, "particle/smokesprites_0006" ) +PRECACHE( MATERIAL, "particle/smokesprites_0007" ) +PRECACHE( MATERIAL, "particle/smokesprites_0008" ) +PRECACHE( MATERIAL, "particle/smokesprites_0009" ) +PRECACHE( MATERIAL, "particle/smokesprites_0010" ) +PRECACHE( MATERIAL, "particle/smokesprites_0011" ) +PRECACHE( MATERIAL, "particle/smokesprites_0012" ) +PRECACHE( MATERIAL, "particle/smokesprites_0013" ) +PRECACHE( MATERIAL, "particle/smokesprites_0014" ) +PRECACHE( MATERIAL, "particle/smokesprites_0015" ) +PRECACHE( MATERIAL, "particle/smokesprites_0016" ) */ -CLIENTEFFECT_REGISTER_END() +PRECACHE_REGISTER_END() //----------------------------------------------------------------------------- @@ -1933,7 +1895,7 @@ void C_DustTrail::CleanupToolRecordingState( KeyValues *msg ) // FIXME: Until we can interpolate ent logs during emission, this can't work KeyValues *pPosition = pInitializers->FindKey( "DmePositionPointToEntityInitializer", true ); - pPosition->SetPtr( "entindex", (void*)(intp)pEnt->entindex() ); + pPosition->SetPtr( "entindex", (void*)pEnt->entindex() ); pPosition->SetInt( "attachmentIndex", GetParentAttachment() ); pPosition->SetFloat( "randomDist", m_SpawnRadius ); pPosition->SetFloat( "startx", pEnt->GetAbsOrigin().x ); @@ -1961,10 +1923,9 @@ void C_DustTrail::CleanupToolRecordingState( KeyValues *msg ) KeyValues *pColor = pInitializers->FindKey( "DmeRandomValueColorInitializer", true ); Color c( - FastFToC( clamp( m_Color.x, 0.f, 1.f ) ), - FastFToC( clamp( m_Color.y, 0.f, 1.f ) ), - FastFToC( clamp( m_Color.z, 0.f, 1.f ) ), - 255 ); + clamp( m_Color.x * 255.0f, 0, 255 ), + clamp( m_Color.y * 255.0f, 0, 255 ), + clamp( m_Color.z * 255.0f, 0, 255 ), 255 ); pColor->SetColor( "startColor", c ); pColor->SetFloat( "minStartValueDelta", 0.0f ); pColor->SetFloat( "maxStartValueDelta", 0.0f ); diff --git a/game/client/c_smoke_trail.h b/game/client/c_smoke_trail.h index 501ab73c3..135c1eb87 100644 --- a/game/client/c_smoke_trail.h +++ b/game/client/c_smoke_trail.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // @@ -303,8 +303,48 @@ class C_FireTrail : public C_ParticleTrail +//----------------------------------------------------------------------------- +// Purpose: High drag, non color changing particle +//----------------------------------------------------------------------------- +class CDustFollower : public CSimpleEmitter +{ +public: + + CDustFollower( const char *pDebugName ) : CSimpleEmitter( pDebugName ) {} + + //Create + static CDustFollower *Create( const char *pDebugName ) + { + return new CDustFollower( pDebugName ); + } + + //Alpha + virtual float UpdateAlpha( const SimpleParticle *pParticle ) + { + return ( ((float)pParticle->m_uchStartAlpha/255.0f) * sin( M_PI * (pParticle->m_flLifetime / pParticle->m_flDieTime) ) ); + } + + virtual void UpdateVelocity( SimpleParticle *pParticle, float timeDelta ) + { + pParticle->m_vecVelocity = pParticle->m_vecVelocity * ExponentialDecay( 0.3, timeDelta ); + } + + //Roll + virtual float UpdateRoll( SimpleParticle *pParticle, float timeDelta ) + { + pParticle->m_flRoll += pParticle->m_flRollDelta * timeDelta; + + pParticle->m_flRollDelta *= ExponentialDecay( 0.5, timeDelta ); + + return pParticle->m_flRoll; + } + +private: + CDustFollower( const CDustFollower & ); +}; + diff --git a/game/client/c_smokestack.cpp b/game/client/c_smokestack.cpp index 2c66dcf53..3244a411a 100644 --- a/game/client/c_smokestack.cpp +++ b/game/client/c_smokestack.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: Implements a particle system steam jet. // @@ -179,7 +179,8 @@ C_SmokeStack::C_SmokeStack() // Lighting is (base color) + (ambient / dist^2) + bump(directional / dist^2) // By default, we use bottom-up lighting for the directional. - SetRenderColor( 0, 0, 0, 255 ); + SetRenderColor( 0, 0, 0 ); + SetRenderAlpha( 255 ); m_AmbientLight.m_vPos.Init(0,0,-100); m_AmbientLight.m_vColor.Init( 40, 40, 40 ); @@ -218,8 +219,6 @@ void C_SmokeStack::OnDataChanged(DataUpdateType_t updateType) } -static ConVar mat_reduceparticles( "mat_reduceparticles", "0" ); - //----------------------------------------------------------------------------- // Purpose: Starts the effect // Input : *pParticleMgr - @@ -262,14 +261,12 @@ void C_SmokeStack::Start(CParticleMgr *pParticleMgr, IPrototypeArgAccess *pArgs) m_MaterialHandle[iCount] = m_ParticleEffect.FindOrAddMaterial( szNames ); iCount++; } - + m_iMaxFrames = iCount-1; - - m_ParticleSpawn.Init( mat_reduceparticles.GetBool() ? m_Rate / 4 : m_Rate ); // Obey mat_reduceparticles in episodic -#else - m_ParticleSpawn.Init( m_Rate ); #endif + m_ParticleSpawn.Init(m_Rate); + m_InvLifetime = m_Speed / m_JetLength; m_pParticleMgr = pParticleMgr; @@ -366,7 +363,7 @@ void C_SmokeStack::Update(float fTimeDelta) // Setup the twist matrix. float flTwist = (m_flTwist * (M_PI_F * 2.f) / 360.0f) * Helper_GetFrameTime(); - if( ( m_bTwist = !!flTwist ) ) + if( m_bTwist = !!flTwist ) { m_TwistMat[0][0] = cos(flTwist); m_TwistMat[0][1] = sin(flTwist); @@ -386,10 +383,10 @@ void C_SmokeStack::StartRender( VMatrix &effectMatrix ) void C_SmokeStack::QueueLightParametersInRenderer() { - m_Renderer.SetBaseColor( Vector( m_clrRender->r / 255.0f, m_clrRender->g / 255.0f, m_clrRender->b / 255.0f ) ); + m_Renderer.SetBaseColor( Vector( GetRenderColorR() / 255.0f, GetRenderColorG() / 255.0f, GetRenderColorB() / 255.0f ) ); m_Renderer.SetAmbientLight( m_AmbientLight ); m_Renderer.SetDirectionalLight( m_DirLight ); - m_flAlphaScale = (float)m_clrRender->a; + m_flAlphaScale = (float)GetRenderAlpha(); } @@ -429,7 +426,7 @@ void C_SmokeStack::SimulateParticles( CParticleSimulateIterator *pIterator ) bool bSortNow = true; // Change this to false if we see sorting issues. bool bQuickTest = false; - bool bDrawn = m_ParticleEffect.WasDrawnPrevFrame(); + bool bDrawn = m_ParticleEffect.WasDrawnPrevFrame() ? true : false; if ( bDrawn == true && m_bInView == false ) { diff --git a/game/client/c_soundscape.cpp b/game/client/c_soundscape.cpp index 3196eb941..e5e54bd1c 100644 --- a/game/client/c_soundscape.cpp +++ b/game/client/c_soundscape.cpp @@ -2,19 +2,19 @@ // // Purpose: Soundscapes.txt resource file processor // -// $NoKeywords: $ //=============================================================================// #include "cbase.h" #include -#include "engine/IEngineSound.h" +#include "engine/ienginesound.h" #include "filesystem.h" #include "SoundEmitterSystem/isoundemittersystembase.h" #include "soundchars.h" #include "view.h" #include "engine/ivdebugoverlay.h" #include "tier0/icommandline.h" +#include "strtools.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -27,21 +27,98 @@ const float DEFAULT_SOUND_RADIUS = 36.0f; // Keep an array of all looping sounds so they can be faded in/out // OPTIMIZE: Get a handle/pointer to the engine's sound channel instead // of searching each frame! +enum soundfadestyle_t +{ + FADE_VOLUME_LINEAR = 0, + FADE_VOLUME_SINE = 1, +}; + +// contains a set of data to implement a simple envelope to fade in/out sounds +struct soundfader_t +{ + float m_flCurrent; + float m_flTarget; + float m_flRate; + float m_flStart; + float m_flFadeT; + int m_nType; + + bool IsFading() + { + return ( m_flCurrent != m_flTarget ) ? true : false; + } + + void FadeToValue( float flTarget, float flRate, soundfadestyle_t fadeType ) + { + m_flStart = m_flCurrent; + m_flFadeT = 0; + m_flTarget = flTarget; + m_flRate = flRate; + m_nType = fadeType; + } + + void ForceToTargetValue( float flTarget ) + { + m_flFadeT = 1.0f; + m_flCurrent = m_flTarget = flTarget; + m_flRate = 0; + } + + void UpdateFade( float flDt ) + { + m_flFadeT += flDt * m_flRate; + if ( m_flFadeT >= 1.0f ) + { + ForceToTargetValue( m_flTarget ); + return; + } + float flFactor = m_flFadeT; + float flDelta = m_flTarget - m_flStart; + switch ( m_nType ) + { + case FADE_VOLUME_LINEAR: + break; + case FADE_VOLUME_SINE: + if ( flDelta >= 0 ) + { + flFactor = sin( m_flFadeT * M_PI * 0.5f ); + } + else + { + flFactor = 1.0f - cos( m_flFadeT * M_PI * 0.5f ); + } + break; + } + m_flCurrent = m_flStart + flDelta * flFactor; + } +}; + struct loopingsound_t { Vector position; // position (if !isAmbient) const char *pWaveName; // name of the wave file - float volumeTarget; // target volume level (fading towards this) - float volumeCurrent; // current volume level + soundfader_t m_volume; soundlevel_t soundlevel; // sound level (if !isAmbient) int pitch; // pitch shift int id; // Used to fade out sounds that don't belong to the most current setting + int engineGuid; + float radius; // if set, sound plays at full volume inside the radius and fallsoff as you move out of the radius. Sound will lose directionality as you move inside the radius bool isAmbient; // Ambient sounds have no spatialization - they play from everywhere }; ConVar soundscape_fadetime( "soundscape_fadetime", "3.0", FCVAR_CHEAT, "Time to crossfade sound effects between soundscapes" ); +ConVar soundscape_message("soundscape_message","0"); +ConVar soundscape_radius_debug( "soundscape_radius_debug", "0", FCVAR_CHEAT, "Prints current volume of radius sounds" ); -#include "interval.h" +float GetSoundscapeFadeRate() +{ + float flFadeTime = soundscape_fadetime.GetFloat(); + float flFadeRate = 1.0f / (flFadeTime > 0 ? flFadeTime : 3.0f); + + return flFadeRate; +} + +#include "tier2/interval.h" struct randomsound_t { @@ -67,6 +144,7 @@ struct subsoundscapeparams_t { int recurseLevel; // test for infinite loops in the script / circular refs float masterVolume; + float flFadeRate; int startingPosition; int positionOverride; // forces all sounds to this position int ambientPositionOverride; // forces all ambient sounds to this position @@ -75,6 +153,22 @@ struct subsoundscapeparams_t bool wroteDSPVolume; }; +Vector getVectorFromString(const char *pString) +{ + char tempString[128]; + Q_strncpy( tempString, pString, sizeof(tempString) ); + + Vector result; + int i = 0; + char *token = strtok( tempString, "," ); + while( token ) + { + result[i] = atof( token ); + token = strtok( NULL, "," ); + i++; + } + return result; +} class C_SoundscapeSystem : public CBaseGameSystemPerFrame { public: @@ -89,10 +183,14 @@ class C_SoundscapeSystem : public CBaseGameSystemPerFrame void OnStopAllSounds() { - m_params.ent.Set( NULL ); - m_params.soundscapeIndex = -1; - m_loopingSounds.Purge(); - m_randomSounds.Purge(); + for ( int hh = 0; hh < MAX_SPLITSCREEN_PLAYERS; ++hh ) + { + ACTIVE_SPLITSCREEN_PLAYER_GUARD( hh ); + GetPerUser(hh).m_params.entIndex = 0; + GetPerUser(hh).m_params.soundscapeIndex = -1; + GetPerUser(hh).m_loopingSounds.Purge(); + GetPerUser(hh).m_randomSounds.Purge(); + } } // IClientSystem hooks, not needed @@ -150,31 +248,36 @@ class C_SoundscapeSystem : public CBaseGameSystemPerFrame { Msg( "- %d: %s\n", i, m_soundscapes[i]->GetName() ); } - if ( m_forcedSoundscapeIndex ) + + Split_t &slot = GetPerUser(GET_ACTIVE_SPLITSCREEN_SLOT()); + + if ( slot.m_forcedSoundscapeIndex ) { - Msg( "- PLAYING DEBUG SOUNDSCAPE: %d [%s]\n", m_forcedSoundscapeIndex, SoundscapeNameByIndex(m_forcedSoundscapeIndex) ); + Msg( "- PLAYING DEBUG SOUNDSCAPE: %d [%s]\n", slot.m_forcedSoundscapeIndex, SoundscapeNameByIndex(slot.m_forcedSoundscapeIndex) ); } - Msg( "- CURRENT SOUNDSCAPE: %d [%s]\n", m_params.soundscapeIndex.Get(), SoundscapeNameByIndex(m_params.soundscapeIndex) ); + Msg( "- CURRENT SOUNDSCAPE: %d [%s]\n", slot.m_params.soundscapeIndex, SoundscapeNameByIndex(slot.m_params.soundscapeIndex) ); Msg( "----------------------------------\n\n" ); } - + // local functions void UpdateAudioParams( audioparams_t &audio ); - void GetAudioParams( audioparams_t &out ) const { out = m_params; } + void GetAudioParams( audioparams_t &out ) const { out = GetPerUser(GET_ACTIVE_SPLITSCREEN_SLOT()).m_params; } int GetCurrentSoundscape() { - if ( m_forcedSoundscapeIndex >= 0 ) - return m_forcedSoundscapeIndex; - return m_params.soundscapeIndex; + Split_t &slot = GetPerUser(GET_ACTIVE_SPLITSCREEN_SLOT()); + + if ( slot.m_forcedSoundscapeIndex >= 0 ) + return slot.m_forcedSoundscapeIndex; + return slot.m_params.soundscapeIndex; } void DevReportSoundscapeName( int index ); void UpdateLoopingSounds( float frametime ); - int AddLoopingAmbient( const char *pSoundName, float volume, int pitch ); + int AddLoopingAmbient( const char *pSoundName, float volume, int pitch, float radius, float flFadeRate ); void UpdateLoopingSound( loopingsound_t &loopSound ); void StopLoopingSound( loopingsound_t &loopSound ); int AddLoopingSound( const char *pSoundName, bool isAmbient, float volume, - soundlevel_t soundLevel, int pitch, const Vector &position ); + soundlevel_t soundLevel, int pitch, const Vector &position, float radius, float flFadeRate ); int AddRandomSound( const randomsound_t &sound ); void PlayRandomSound( randomsound_t &sound ); void UpdateRandomSounds( float gameClock ); @@ -185,7 +288,7 @@ class C_SoundscapeSystem : public CBaseGameSystemPerFrame int FindSoundscapeByName( const char *pSoundscapeName ); const char *SoundscapeNameByIndex( int index ); KeyValues *SoundscapeByIndex( int index ); - + // main-level soundscape processing, called on new soundscape void StartNewSoundscape( KeyValues *pSoundscape ); void StartSubSoundscape( KeyValues *pSoundscape, subsoundscapeparams_t ¶ms ); @@ -196,6 +299,8 @@ class C_SoundscapeSystem : public CBaseGameSystemPerFrame void ProcessDSP( KeyValues *pDSP ); // "dsp_player" void ProcessDSPPlayer( KeyValues *pDSPPlayer ); + // "fadetime" + void ProcessSoundscapeFadetime( KeyValues *pKey, subsoundscapeparams_t ¶ms ); // "playlooping" void ProcessPlayLooping( KeyValues *pPlayLooping, const subsoundscapeparams_t ¶ms ); // "playrandom" @@ -223,18 +328,34 @@ class C_SoundscapeSystem : public CBaseGameSystemPerFrame void TouchSoundFile( char const *wavefile ); void TouchSoundFiles(); - + int m_nRestoreFrame; CUtlVector< KeyValues * > m_SoundscapeScripts; // The whole script file in memory CUtlVector m_soundscapes; // Lookup by index of each root section - audioparams_t m_params; // current player audio params - CUtlVector m_loopingSounds; // list of currently playing sounds - CUtlVector m_randomSounds; // list of random sound commands - float m_nextRandomTime; // next time to play a random sound - int m_loopingSoundId; // marks when the sound was issued - int m_forcedSoundscapeIndex;// >= 0 if this a "forced" soundscape? i.e. debug mode? - float m_forcedSoundscapeRadius;// distance to spatialized sounds + struct Split_t + { + audioparams_t m_params; // current player audio params + CUtlVector m_loopingSounds; // list of currently playing sounds + CUtlVector m_randomSounds; // list of random sound commands + float m_nextRandomTime; // next time to play a random sound + int m_loopingSoundId; // marks when the sound was issued + int m_forcedSoundscapeIndex;// >= 0 if this a "forced" soundscape? i.e. debug mode? + float m_forcedSoundscapeRadius;// distance to spatialized sounds + }; + + Split_t m_PerUser[ MAX_SPLITSCREEN_PLAYERS ]; + + Split_t &GetPerUser( int nSlot ) + { + return m_PerUser[ nSlot ]; + } + + const Split_t &GetPerUser( int nSlot ) const + { + return m_PerUser[ nSlot ]; + } + static ConVar *m_pDSPVolumeVar; static ConVar *m_pSoundMixerVar; @@ -252,17 +373,21 @@ IGameSystem *ClientSoundscapeSystem() return &g_SoundscapeSystem; } +C_SoundscapeSystem *GetClientSoundscapeSystem() +{ + return &g_SoundscapeSystem; +} void Soundscape_OnStopAllSounds() { - g_SoundscapeSystem.OnStopAllSounds(); + GetClientSoundscapeSystem()->OnStopAllSounds(); } // player got a network update void Soundscape_Update( audioparams_t &audio ) { - g_SoundscapeSystem.UpdateAudioParams( audio ); + GetClientSoundscapeSystem()->UpdateAudioParams( audio ); } #define SOUNDSCAPE_MANIFEST_FILE "scripts/soundscapes_manifest.txt" @@ -270,11 +395,7 @@ void Soundscape_Update( audioparams_t &audio ) void C_SoundscapeSystem::AddSoundScapeFile( const char *filename ) { KeyValues *script = new KeyValues( filename ); -#ifndef _XBOX - if ( script->LoadFromFile( filesystem, filename ) ) -#else if ( filesystem->LoadKeyValues( *script, IFileSystem::TYPE_SOUNDSCAPE, filename, "GAME" ) ) -#endif { // parse out all of the top level sections and save their names KeyValues *pKeys = script; @@ -301,7 +422,11 @@ void C_SoundscapeSystem::AddSoundScapeFile( const char *filename ) // parse the script file, setup index table bool C_SoundscapeSystem::Init() { - m_loopingSoundId = 0; + for ( int hh = 0; hh < MAX_SPLITSCREEN_PLAYERS; ++hh ) + { + ACTIVE_SPLITSCREEN_PLAYER_GUARD( hh ); + GetPerUser(hh).m_loopingSoundId = 0; + } const char *mapname = MapName(); const char *mapSoundscapeFilename = NULL; @@ -377,21 +502,26 @@ const char *C_SoundscapeSystem::SoundscapeNameByIndex( int index ) void C_SoundscapeSystem::Shutdown() { - for ( int i = m_loopingSounds.Count() - 1; i >= 0; --i ) + for ( int hh = 0; hh < MAX_SPLITSCREEN_PLAYERS; ++hh ) { - loopingsound_t &sound = m_loopingSounds[i]; + ACTIVE_SPLITSCREEN_PLAYER_GUARD( hh ); + for ( int i = GetPerUser(hh).m_loopingSounds.Count() - 1; i >= 0; --i ) + { + loopingsound_t &sound = GetPerUser(hh).m_loopingSounds[i]; - // sound is done, remove from list. - StopLoopingSound( sound ); + // sound is done, remove from list. + StopLoopingSound( sound ); + } + + // These are only necessary so we can use shutdown/init calls + // to flush soundscape data + GetPerUser(hh).m_loopingSounds.RemoveAll(); + GetPerUser(hh).m_randomSounds.RemoveAll(); + GetPerUser(hh).m_params.entIndex = 0; + GetPerUser(hh).m_params.soundscapeIndex = -1; } - - // These are only necessary so we can use shutdown/init calls - // to flush soundscape data - m_loopingSounds.RemoveAll(); - m_randomSounds.RemoveAll(); + m_soundscapes.RemoveAll(); - m_params.ent.Set( NULL ); - m_params.soundscapeIndex = -1; while ( m_SoundscapeScripts.Count() > 0 ) { @@ -405,23 +535,29 @@ void C_SoundscapeSystem::Shutdown() // soundscapes from the list, only change their parameters!!!! CON_COMMAND_F(cl_soundscape_flush, "Flushes the client side soundscapes", FCVAR_SERVER_CAN_EXECUTE|FCVAR_CHEAT) { - // save the current soundscape - audioparams_t tmp; - g_SoundscapeSystem.GetAudioParams( tmp ); + FOR_EACH_VALID_SPLITSCREEN_PLAYER( hh ) + { + ACTIVE_SPLITSCREEN_PLAYER_GUARD( hh ); + // save the current soundscape + audioparams_t tmp; + GetClientSoundscapeSystem()->GetAudioParams( tmp ); - // kill the system - g_SoundscapeSystem.Shutdown(); + // kill the system + GetClientSoundscapeSystem()->Shutdown(); - // restart the system - g_SoundscapeSystem.Init(); + // restart the system + GetClientSoundscapeSystem()->Init(); - // reload the soundscape params from the temp copy - Soundscape_Update( tmp ); + // reload the soundscape params from the temp copy + Soundscape_Update( tmp ); + } } static int SoundscapeCompletion( const char *partial, char commands[ COMMAND_COMPLETION_MAXITEMS ][ COMMAND_COMPLETION_ITEM_LENGTH ] ) { + // Autocomplete can just look at the base system + ACTIVE_SPLITSCREEN_PLAYER_GUARD( 0 ); int current = 0; const char *cmdname = "playsoundscape"; @@ -432,9 +568,9 @@ static int SoundscapeCompletion( const char *partial, char commands[ COMMAND_COM substring = (char *)partial + strlen( cmdname ) + 1; substringLen = strlen(substring); } - + int i = 0; - const char *pSoundscapeName = g_SoundscapeSystem.SoundscapeNameByIndex( i ); + const char *pSoundscapeName = GetClientSoundscapeSystem()->SoundscapeNameByIndex( i ); while ( pSoundscapeName && current < COMMAND_COMPLETION_MAXITEMS ) { if ( !substring || !Q_strncasecmp( pSoundscapeName, substring, substringLen ) ) @@ -443,38 +579,52 @@ static int SoundscapeCompletion( const char *partial, char commands[ COMMAND_COM current++; } i++; - pSoundscapeName = g_SoundscapeSystem.SoundscapeNameByIndex( i ); + pSoundscapeName = GetClientSoundscapeSystem()->SoundscapeNameByIndex( i ); } return current; } +void ForceSoundscape( const char *pSoundscapeName, float radius ) +{ + GetClientSoundscapeSystem()->ForceSoundscape( pSoundscapeName, radius ); +} + CON_COMMAND_F_COMPLETION( playsoundscape, "Forces a soundscape to play", FCVAR_CHEAT, SoundscapeCompletion ) { - if ( args.ArgC() < 2 ) + FOR_EACH_VALID_SPLITSCREEN_PLAYER( hh ) { - g_SoundscapeSystem.DevReportSoundscapeName( g_SoundscapeSystem.GetCurrentSoundscape() ); - return; + ACTIVE_SPLITSCREEN_PLAYER_GUARD( hh ); + if ( args.ArgC() < 2 ) + { + GetClientSoundscapeSystem()->DevReportSoundscapeName( GetClientSoundscapeSystem()->GetCurrentSoundscape() ); + continue; + } + const char *pSoundscapeName = args[1]; + float radius = args.ArgC() > 2 ? atof( args[2] ) : DEFAULT_SOUND_RADIUS; + GetClientSoundscapeSystem()->ForceSoundscape( pSoundscapeName, radius ); } - const char *pSoundscapeName = args[1]; - float radius = args.ArgC() > 2 ? atof( args[2] ) : DEFAULT_SOUND_RADIUS; - g_SoundscapeSystem.ForceSoundscape( pSoundscapeName, radius ); } CON_COMMAND_F( stopsoundscape, "Stops all soundscape processing and fades current looping sounds", FCVAR_CHEAT ) { - g_SoundscapeSystem.StartNewSoundscape( NULL ); + FOR_EACH_VALID_SPLITSCREEN_PLAYER( hh ) + { + ACTIVE_SPLITSCREEN_PLAYER_GUARD( hh ); + GetClientSoundscapeSystem()->StartNewSoundscape( NULL ); + } } void C_SoundscapeSystem::ForceSoundscape( const char *pSoundscapeName, float radius ) { - int index = g_SoundscapeSystem.FindSoundscapeByName( pSoundscapeName ); + int index = FindSoundscapeByName( pSoundscapeName ); if ( index >= 0 ) { - m_forcedSoundscapeIndex = index; - m_forcedSoundscapeRadius = radius; - g_SoundscapeSystem.StartNewSoundscape( SoundscapeByIndex(index) ); + int nSlot = GET_ACTIVE_SPLITSCREEN_SLOT(); + GetPerUser(nSlot).m_forcedSoundscapeIndex = index; + GetPerUser(nSlot).m_forcedSoundscapeRadius = radius; + StartNewSoundscape( SoundscapeByIndex(index) ); } else { @@ -489,34 +639,71 @@ void C_SoundscapeSystem::DevReportSoundscapeName( int index ) { pName = m_soundscapes[index]->GetName(); } - DevMsg( 1, "Soundscape: %s\n", pName ); + + if ( soundscape_message.GetBool() ) + { + Msg( "Soundscape[%d]: %s\n", GET_ACTIVE_SPLITSCREEN_SLOT(), pName ); + } } // This makes all currently playing loops fade toward their target volume void C_SoundscapeSystem::UpdateLoopingSounds( float frametime ) { - float period = soundscape_fadetime.GetFloat(); - float amount = frametime; - if ( period > 0 ) - { - amount *= 1.0 / period; - } - - int fadeCount = m_loopingSounds.Count(); + Split_t &slot = GetPerUser(GET_ACTIVE_SPLITSCREEN_SLOT()); + int fadeCount = slot.m_loopingSounds.Count(); while ( fadeCount > 0 ) { fadeCount--; - loopingsound_t &sound = m_loopingSounds[fadeCount]; + loopingsound_t &sound = slot.m_loopingSounds[fadeCount]; - if ( sound.volumeCurrent != sound.volumeTarget ) + bool bUpdateSound = sound.m_volume.IsFading(); + + // for radius looping sounds, volume is manually set based on listener's distance + if ( sound.radius > 0 ) { - sound.volumeCurrent = Approach( sound.volumeTarget, sound.volumeCurrent, amount ); - if ( sound.volumeTarget == 0 && sound.volumeCurrent == 0 ) + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + if ( pPlayer ) + { + C_BaseEntity *pEnt = pPlayer->GetSoundscapeListener(); + if ( pEnt ) + { + float distance = pEnt->GetAbsOrigin().DistTo( sound.position ); + + if ( distance > sound.radius * 100.0f ) + { + // long way away, let sound fade to silence + sound.m_volume.FadeToValue( 0.01f, 1.0f, FADE_VOLUME_LINEAR ); // HACK: Don't set sound to zero volume else it'll be removed and never started again! + } + else + { + float flTarget = 1.0f; + // inside the radius, full volume, outside fade out + if ( distance >= sound.radius ) + { + flTarget = 1.0f / ( 1 + 0.5f * ( distance - sound.radius ) / sound.radius ); + } + sound.m_volume.ForceToTargetValue( flTarget ); + } + + if ( soundscape_radius_debug.GetBool() ) + { + DevMsg( 1, "Updated looping radius sound %d to vol=%f\n", fadeCount, sound.m_volume.m_flTarget ); + } + + bUpdateSound = true; + } + } + } + + if ( bUpdateSound ) + { + sound.m_volume.UpdateFade( frametime ); + if ( sound.m_volume.m_flTarget == 0 && sound.m_volume.m_flCurrent == 0 ) { // sound is done, remove from list. StopLoopingSound( sound ); - m_loopingSounds.FastRemove( fadeCount ); + slot.m_loopingSounds.FastRemove( fadeCount ); } else { @@ -529,37 +716,42 @@ void C_SoundscapeSystem::UpdateLoopingSounds( float frametime ) void C_SoundscapeSystem::Update( float frametime ) { - if ( m_forcedSoundscapeIndex >= 0 ) - { - // generate fake positional sources - C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); - if ( pPlayer ) - { - Vector origin, forward, right; - pPlayer->EyePositionAndVectors( &origin, &forward, &right, NULL ); - - // put the sound origins at the corners of a box around the player - m_params.localSound.Set( 0, origin + m_forcedSoundscapeRadius * (forward-right) ); - m_params.localSound.Set( 1, origin + m_forcedSoundscapeRadius * (forward+right) ); - m_params.localSound.Set( 2, origin + m_forcedSoundscapeRadius * (-forward-right) ); - m_params.localSound.Set( 3, origin + m_forcedSoundscapeRadius * (-forward+right) ); - m_params.localBits = 0x0007; - } - } - // fade out the old sounds over soundscape_fadetime seconds - UpdateLoopingSounds( frametime ); - UpdateRandomSounds( gpGlobals->curtime ); + FOR_EACH_VALID_SPLITSCREEN_PLAYER( hh ) + { + ACTIVE_SPLITSCREEN_PLAYER_GUARD( hh ); + if ( GetPerUser(hh).m_forcedSoundscapeIndex >= 0 ) + { + // generate fake positional sources + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + if ( pPlayer ) + { + Vector origin, forward, right; + pPlayer->EyePositionAndVectors( &origin, &forward, &right, NULL ); + + // put the sound origins at the corners of a box around the player + GetPerUser(hh).m_params.localSound.Set( 0, origin + GetPerUser(hh).m_forcedSoundscapeRadius * (forward-right) ); + GetPerUser(hh).m_params.localSound.Set( 1, origin + GetPerUser(hh).m_forcedSoundscapeRadius * (forward+right) ); + GetPerUser(hh).m_params.localSound.Set( 2, origin + GetPerUser(hh).m_forcedSoundscapeRadius * (-forward-right) ); + GetPerUser(hh).m_params.localSound.Set( 3, origin + GetPerUser(hh).m_forcedSoundscapeRadius * (-forward+right) ); + GetPerUser(hh).m_params.localBits = 0x0007; + } + } + // fade out the old sounds over soundscape_fadetime seconds + UpdateLoopingSounds( frametime ); + UpdateRandomSounds( gpGlobals->curtime ); + } } void C_SoundscapeSystem::UpdateAudioParams( audioparams_t &audio ) { - if ( m_params.soundscapeIndex == audio.soundscapeIndex && m_params.ent.Get() == audio.ent.Get() ) + Split_t &slot = GetPerUser(GET_ACTIVE_SPLITSCREEN_SLOT()); + if ( slot.m_params.soundscapeIndex == audio.soundscapeIndex && slot.m_params.entIndex == audio.entIndex ) return; - m_params = audio; - m_forcedSoundscapeIndex = -1; - if ( audio.ent.Get() && audio.soundscapeIndex >= 0 && audio.soundscapeIndex < m_soundscapes.Count() ) + slot.m_params = audio; + slot.m_forcedSoundscapeIndex = -1; + if ( audio.entIndex > 0 && audio.soundscapeIndex >= 0 && audio.soundscapeIndex < m_soundscapes.Count() ) { DevReportSoundscapeName( audio.soundscapeIndex ); StartNewSoundscape( m_soundscapes[audio.soundscapeIndex] ); @@ -567,8 +759,8 @@ void C_SoundscapeSystem::UpdateAudioParams( audioparams_t &audio ) else { // bad index (and the soundscape file actually existed...) - if ( audio.ent.Get() != 0 && - audio.soundscapeIndex != -1 ) + if ( audio.entIndex > 0 && + audio.soundscapeIndex != -1 ) { DevMsg(1, "Error: Bad soundscape!\n"); } @@ -582,23 +774,28 @@ void C_SoundscapeSystem::StartNewSoundscape( KeyValues *pSoundscape ) { int i; + float flFadeRate = GetSoundscapeFadeRate(); + Split_t &slot = GetPerUser(GET_ACTIVE_SPLITSCREEN_SLOT()); + // Reset the system // fade out the current loops - for ( i = m_loopingSounds.Count()-1; i >= 0; --i ) + // save off the count of old looping sounds + int nOldLoopingSoundMax = slot.m_loopingSounds.Count()-1; + for ( i = slot.m_loopingSounds.Count()-1; i >= 0; --i ) { - m_loopingSounds[i].volumeTarget = 0; + slot.m_loopingSounds[i].m_volume.FadeToValue( 0, flFadeRate, FADE_VOLUME_SINE ); if ( !pSoundscape ) { // if we're cancelling the soundscape, stop the sound immediately - m_loopingSounds[i].volumeCurrent = 0; + slot.m_loopingSounds[i].m_volume.ForceToTargetValue( 0 ); } } // update ID - m_loopingSoundId++; + slot.m_loopingSoundId++; // clear all random sounds - m_randomSounds.RemoveAll(); - m_nextRandomTime = gpGlobals->curtime; + slot.m_randomSounds.RemoveAll(); + slot.m_nextRandomTime = gpGlobals->curtime; if ( pSoundscape ) { @@ -612,6 +809,7 @@ void C_SoundscapeSystem::StartNewSoundscape( KeyValues *pSoundscape ) params.recurseLevel = 0; params.positionOverride = -1; params.ambientPositionOverride = -1; + params.flFadeRate = flFadeRate; StartSubSoundscape( pSoundscape, params ); if ( !params.wroteDSPVolume ) @@ -622,6 +820,20 @@ void C_SoundscapeSystem::StartNewSoundscape( KeyValues *pSoundscape ) { m_pSoundMixerVar->Revert(); } + // if we processed a fade rate, update the fade + // This is a little bit of a hack but since we don't pre-parse soundscapes + // into structs we can't know if there is a rate change on this soundscape + if ( params.flFadeRate != flFadeRate ) + { + for ( i = nOldLoopingSoundMax; i >= 0; --i ) + { + // if we're still fading out at the old rate, fade at the new rate + if ( slot.m_loopingSounds[i].m_volume.m_flTarget == 0.0f && slot.m_loopingSounds[i].m_volume.m_flRate == flFadeRate ) + { + slot.m_loopingSounds[i].m_volume.m_flRate = params.flFadeRate; + } + } + } } } @@ -645,6 +857,14 @@ void C_SoundscapeSystem::StartSubSoundscape( KeyValues *pSoundscape, subsoundsca ProcessDSPPlayer( pKey ); } } + else if ( !Q_strcasecmp( pKey->GetName(), "fadetime" ) ) + { + // don't allow setting these recursively since they are order dependent + if ( params.recurseLevel < 1 ) + { + ProcessSoundscapeFadetime( pKey, params ); + } + } else if ( !Q_strcasecmp( pKey->GetName(), "playlooping" ) ) { ProcessPlayLooping( pKey, params ); @@ -718,6 +938,15 @@ void C_SoundscapeSystem::ProcessDSPVolume( KeyValues *pKey, subsoundscapeparams_ params.wroteDSPVolume = true; } +void C_SoundscapeSystem::ProcessSoundscapeFadetime( KeyValues *pKey, subsoundscapeparams_t ¶ms ) +{ + float flFadeTime = pKey->GetFloat(); + if ( flFadeTime > 0.0f ) + { + params.flFadeRate = 1.0f / flFadeTime; + } +} + // start a new looping sound void C_SoundscapeSystem::ProcessPlayLooping( KeyValues *pAmbient, const subsoundscapeparams_t ¶ms ) { @@ -726,7 +955,14 @@ void C_SoundscapeSystem::ProcessPlayLooping( KeyValues *pAmbient, const subsound const char *pSoundName = NULL; int pitch = PITCH_NORM; int positionIndex = -1; + bool randomPosition = false; bool suppress = false; + bool useTextOrigin = false; + Vector textOrigin; + float radius = 0; + + Split_t &slot = GetPerUser(GET_ACTIVE_SPLITSCREEN_SLOT()); + KeyValues *pKey = pAmbient->GetFirstSubKey(); while ( pKey ) { @@ -742,9 +978,22 @@ void C_SoundscapeSystem::ProcessPlayLooping( KeyValues *pAmbient, const subsound { pSoundName = pKey->GetString(); } + else if ( !Q_strcasecmp( pKey->GetName(), "origin" ) ) + { + textOrigin = getVectorFromString(pKey->GetString()); + useTextOrigin = true; + } else if ( !Q_strcasecmp( pKey->GetName(), "position" ) ) { - positionIndex = params.startingPosition + pKey->GetInt(); + if ( !Q_strcasecmp( pKey->GetString(), "random" ) ) + { + randomPosition = true; + } + else + { + positionIndex = params.startingPosition + pKey->GetInt(); + } + // positionIndex = params.startingPosition + pKey->GetInt(); } else if ( !Q_strcasecmp( pKey->GetName(), "attenuation" ) ) { @@ -765,6 +1014,10 @@ void C_SoundscapeSystem::ProcessPlayLooping( KeyValues *pAmbient, const subsound { suppress = Q_atoi( pKey->GetString() ) != 0 ? true : false; } + else if ( !Q_strcasecmp( pKey->GetName(), "radius" ) ) + { + radius = (float) atof( pKey->GetString() ); + } else { DevMsg( 1, "Ambient %s:Unknown command %s\n", pAmbient->GetName(), pKey->GetName() ); @@ -789,19 +1042,27 @@ void C_SoundscapeSystem::ProcessPlayLooping( KeyValues *pAmbient, const subsound if ( volume != 0 && pSoundName != NULL ) { - if ( positionIndex < 0 ) + if ( randomPosition ) + { + AddLoopingSound( pSoundName, false, volume, soundlevel, pitch, GenerateRandomSoundPosition(), radius, params.flFadeRate ); + } + else if ( useTextOrigin ) + { + AddLoopingSound( pSoundName, false, volume, soundlevel, pitch, textOrigin, radius, params.flFadeRate ); + } + else if ( positionIndex < 0 ) { - AddLoopingAmbient( pSoundName, volume, pitch ); + AddLoopingAmbient( pSoundName, volume, pitch, radius, params.flFadeRate ); } else { - if ( positionIndex > 31 || !(m_params.localBits & (1< 31 || !(slot.m_params.localBits & (1<GetFirstSubKey(); while ( pKey ) { @@ -964,6 +1229,12 @@ void C_SoundscapeSystem::ProcessPlayRandom( KeyValues *pPlayRandom, const subsou positionIndex = params.startingPosition + pKey->GetInt(); } } + else if ( !Q_strcasecmp( pKey->GetName(), "origin" ) ) + { + const char *originString = pKey->GetString(); + textOrigin = getVectorFromString(originString); + useTextOrigin = true; + } else if ( !Q_strcasecmp( pKey->GetName(), "suppress_on_restore" ) ) { suppress = Q_atoi( pKey->GetString() ) != 0 ? true : false; @@ -994,7 +1265,7 @@ void C_SoundscapeSystem::ProcessPlayRandom( KeyValues *pPlayRandom, const subsou if ( sound.waveCount != 0 ) { - if ( positionIndex < 0 && !randomPosition ) + if ( positionIndex < 0 && !randomPosition && !useTextOrigin ) { sound.isAmbient = true; AddRandomSound( sound ); @@ -1006,15 +1277,19 @@ void C_SoundscapeSystem::ProcessPlayRandom( KeyValues *pPlayRandom, const subsou { sound.isRandom = true; } + else if ( useTextOrigin ) + { + sound.position = textOrigin; + } else { - if ( positionIndex > 31 || !(m_params.localBits & (1< 31 || !(slot.m_params.localBits & (1<= 0 ) { - loopingsound_t &sound = m_loopingSounds[soundSlot]; + loopingsound_t &sound = slot.m_loopingSounds[soundSlot]; // NOTE: Will always restart/crossfade positional sounds - if ( sound.id != m_loopingSoundId && + if ( sound.id != slot.m_loopingSoundId && sound.pitch == pitch && !Q_strcasecmp( pSoundName, sound.pWaveName ) ) { @@ -1131,21 +1408,6 @@ int C_SoundscapeSystem::AddLoopingSound( const char *pSoundName, bool isAmbient, pSoundSlot = &sound; break; } - else - { - // If it's trying to fade out one positional sound and fade in another, then it gets screwy - // because it'll be sending alternating commands to the sound engine, referencing the same sound - // (SOUND_FROM_WORLD, CHAN_STATIC, pSoundName). One of the alternating commands will be as - // it fades the sound out, and one will be fading the sound in. - // Because this will occasionally cause the sound to vanish entirely, we stop the old sound immediately. - StopLoopingSound(sound); - pSoundSlot = &sound; - - // make a note to update the sound immediately. Otherwise, if its volume happens to be - // the same as the old sound's volume, it will never update at all. - bForceSoundUpdate = true; - break; - } } } soundSlot--; @@ -1154,12 +1416,12 @@ int C_SoundscapeSystem::AddLoopingSound( const char *pSoundName, bool isAmbient, if ( soundSlot < 0 ) { // can't find the sound in the list, make a new one - soundSlot = m_loopingSounds.AddToTail(); + soundSlot = slot.m_loopingSounds.AddToTail(); if ( isAmbient ) { // start at 0 and fade in enginesound->EmitAmbientSound( pSoundName, 0, pitch ); - m_loopingSounds[soundSlot].volumeCurrent = 0.0; + slot.m_loopingSounds[soundSlot].m_volume.m_flCurrent = 0.0; } else { @@ -1175,19 +1437,29 @@ int C_SoundscapeSystem::AddLoopingSound( const char *pSoundName, bool isAmbient, ep.m_pOrigin = &position; C_BaseEntity::EmitSound( filter, SOUND_FROM_WORLD, ep ); - m_loopingSounds[soundSlot].volumeCurrent = 0.05; + slot.m_loopingSounds[soundSlot].m_volume.m_flCurrent = 0.05; } + slot.m_loopingSounds[soundSlot].engineGuid = enginesound->GetGuidForLastSoundEmitted(); } - loopingsound_t &sound = m_loopingSounds[soundSlot]; + + loopingsound_t &sound = slot.m_loopingSounds[soundSlot]; // fill out the slot sound.pWaveName = pSoundName; - sound.volumeTarget = volume; + sound.m_volume.FadeToValue( volume, flFadeRate, FADE_VOLUME_SINE ); sound.pitch = pitch; - sound.id = m_loopingSoundId; + sound.id = slot.m_loopingSoundId; sound.isAmbient = isAmbient; sound.position = position; - sound.soundlevel = soundlevel; - + sound.radius = radius; + if ( radius > 0 ) + { + sound.soundlevel = SNDLVL_NONE; // play without attenuation if sound has a radius (volume will be manually set based on distance of listener to the radius) + } + else + { + sound.soundlevel = soundlevel; + } + if (bForceSoundUpdate) { UpdateLoopingSound(sound); @@ -1199,22 +1471,21 @@ int C_SoundscapeSystem::AddLoopingSound( const char *pSoundName, bool isAmbient, // stop this loop forever void C_SoundscapeSystem::StopLoopingSound( loopingsound_t &loopSound ) { - if ( loopSound.isAmbient ) - { - enginesound->EmitAmbientSound( loopSound.pWaveName, 0, 0, SND_STOP ); - } - else - { - C_BaseEntity::StopSound( SOUND_FROM_WORLD, CHAN_STATIC, loopSound.pWaveName ); - } + enginesound->StopSoundByGuid( loopSound.engineGuid ); } // update with new volume void C_SoundscapeSystem::UpdateLoopingSound( loopingsound_t &loopSound ) { + if ( enginesound->IsSoundStillPlaying(loopSound.engineGuid) ) + { + enginesound->SetVolumeByGuid( loopSound.engineGuid, loopSound.m_volume.m_flCurrent ); + return; + } + if ( loopSound.isAmbient ) { - enginesound->EmitAmbientSound( loopSound.pWaveName, loopSound.volumeCurrent, loopSound.pitch, SND_CHANGE_VOL ); + enginesound->EmitAmbientSound( loopSound.pWaveName, loopSound.m_volume.m_flCurrent, loopSound.pitch, SND_CHANGE_VOL ); } else { @@ -1223,7 +1494,7 @@ void C_SoundscapeSystem::UpdateLoopingSound( loopingsound_t &loopSound ) EmitSound_t ep; ep.m_nChannel = CHAN_STATIC; ep.m_pSoundName = loopSound.pWaveName; - ep.m_flVolume = loopSound.volumeCurrent; + ep.m_flVolume = loopSound.m_volume.m_flCurrent; ep.m_SoundLevel = loopSound.soundlevel; ep.m_nFlags = SND_CHANGE_VOL; ep.m_nPitch = loopSound.pitch; @@ -1231,14 +1502,16 @@ void C_SoundscapeSystem::UpdateLoopingSound( loopingsound_t &loopSound ) C_BaseEntity::EmitSound( filter, SOUND_FROM_WORLD, ep ); } + loopSound.engineGuid = enginesound->GetGuidForLastSoundEmitted(); } // add a recurring random sound event int C_SoundscapeSystem::AddRandomSound( const randomsound_t &sound ) { - int index = m_randomSounds.AddToTail( sound ); - m_randomSounds[index].nextPlayTime = gpGlobals->curtime + 0.5 * RandomInterval( sound.time ); - + Split_t &slot = GetPerUser(GET_ACTIVE_SPLITSCREEN_SLOT()); + int index = slot.m_randomSounds.AddToTail( sound ); + slot.m_randomSounds[index].nextPlayTime = gpGlobals->curtime + 0.5 * RandomInterval( sound.time ); + return index; } @@ -1256,9 +1529,9 @@ void C_SoundscapeSystem::PlayRandomSound( randomsound_t &sound ) } if ( !pWaves ) return; - + const char *pWaveName = pWaves->GetString(); - + if ( !pWaveName ) return; @@ -1289,29 +1562,30 @@ void C_SoundscapeSystem::PlayRandomSound( randomsound_t &sound ) // walk the list of random sound commands and update void C_SoundscapeSystem::UpdateRandomSounds( float gameTime ) { - if ( gameTime < m_nextRandomTime ) + Split_t &slot = GetPerUser(GET_ACTIVE_SPLITSCREEN_SLOT()); + if ( gameTime < slot.m_nextRandomTime ) return; - m_nextRandomTime = gameTime + 3600; // add some big time to check again (an hour) + slot.m_nextRandomTime = gameTime + 3600; // add some big time to check again (an hour) - for ( int i = m_randomSounds.Count()-1; i >= 0; i-- ) + for ( int i = slot.m_randomSounds.Count()-1; i >= 0; i-- ) { // time to play? - if ( gameTime >= m_randomSounds[i].nextPlayTime ) + if ( gameTime >= slot.m_randomSounds[i].nextPlayTime ) { // UNDONE: add this in to fix range? // float dt = m_randomSounds[i].nextPlayTime - gameTime; - PlayRandomSound( m_randomSounds[i] ); + PlayRandomSound( slot.m_randomSounds[i] ); // now schedule the next occurrance // UNDONE: add support for "play once" sounds? FastRemove() here. - m_randomSounds[i].nextPlayTime = gameTime + RandomInterval( m_randomSounds[i].time ); + slot.m_randomSounds[i].nextPlayTime = gameTime + RandomInterval( slot.m_randomSounds[i].time ); } // update next time to check the queue - if ( m_randomSounds[i].nextPlayTime < m_nextRandomTime ) + if ( slot.m_randomSounds[i].nextPlayTime < slot.m_nextRandomTime ) { - m_nextRandomTime = m_randomSounds[i].nextPlayTime; + slot.m_nextRandomTime = slot.m_randomSounds[i].nextPlayTime; } } } @@ -1320,5 +1594,16 @@ void C_SoundscapeSystem::UpdateRandomSounds( float gameTime ) CON_COMMAND(cl_soundscape_printdebuginfo, "print soundscapes") { - g_SoundscapeSystem.PrintDebugInfo(); + FOR_EACH_VALID_SPLITSCREEN_PLAYER( hh ) + { + ACTIVE_SPLITSCREEN_PLAYER_GUARD( hh ); + GetClientSoundscapeSystem()->PrintDebugInfo(); + } +} + + +CON_COMMAND(cl_ss_origin, "print origin in script format") +{ + Vector org = MainViewOrigin( GET_ACTIVE_SPLITSCREEN_SLOT() ); + Warning("\"origin\"\t\"%.1f, %.1f, %.1f\"\n", org.x, org.y, org.z ); } diff --git a/game/client/c_soundscape.h b/game/client/c_soundscape.h index 8c5f45e9f..f36a46aae 100644 --- a/game/client/c_soundscape.h +++ b/game/client/c_soundscape.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // diff --git a/game/client/c_spatialentity.cpp b/game/client/c_spatialentity.cpp new file mode 100644 index 000000000..0d5aea16f --- /dev/null +++ b/game/client/c_spatialentity.cpp @@ -0,0 +1,88 @@ +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// +// +// Purpose: Spatial entity with simple radial falloff +// +// $NoKeywords: $ +//===========================================================================// +#include "cbase.h" + +#include "c_spatialentity.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + +IMPLEMENT_CLIENTCLASS_DT(C_SpatialEntity, DT_SpatialEntity, CSpatialEntity) + RecvPropVector( RECVINFO(m_vecOrigin) ), + RecvPropFloat( RECVINFO(m_minFalloff) ), + RecvPropFloat( RECVINFO(m_maxFalloff) ), + RecvPropFloat( RECVINFO(m_flCurWeight) ), + RecvPropBool( RECVINFO(m_bEnabled) ), +END_RECV_TABLE() + + +void C_SpatialEntity::OnDataChanged(DataUpdateType_t updateType) +{ + BaseClass::OnDataChanged( updateType ); + + if ( updateType == DATA_UPDATE_CREATED ) + { + InitSpatialEntity(); + } +} + +void C_SpatialEntity::InitSpatialEntity() +{ + SetNextClientThink( CLIENT_THINK_ALWAYS ); + + AddToPersonalSpatialEntityMgr(); + m_flWeight = 0.0f; + m_flInfluence = 0.0f; +} + +void C_SpatialEntity::UpdateOnRemove( void ) +{ + BaseClass::UpdateOnRemove(); + + RemoveFromPersonalSpatialEntityMgr(); +} + + +//------------------------------------------------------------------------------ +// We don't draw... +//------------------------------------------------------------------------------ +bool C_SpatialEntity::ShouldDraw() +{ + return false; +} + +void C_SpatialEntity::ClientThink() +{ + if( !m_bEnabled && m_flCurWeight == 0.0f ) + { + m_flWeight = 0.0f; + return; + } + + CBaseEntity *pPlayer = C_BasePlayer::GetLocalPlayer( 0 ); + if( !pPlayer ) + return; + + Vector playerOrigin = pPlayer->GetAbsOrigin(); + + m_flWeight = 0.0f; + + if ( ( m_minFalloff != -1 ) && ( m_maxFalloff != -1 ) && m_minFalloff != m_maxFalloff ) + { + float dist = (playerOrigin - m_vecOrigin).Length(); + m_flWeight = (dist-m_minFalloff) / (m_maxFalloff-m_minFalloff); + m_flWeight = fpmax( 0.0f, m_flWeight ); + m_flWeight = fpmin( 1.0f, m_flWeight ); + + m_flInfluence = fpmax( 0.0f, m_minFalloff - dist ); + } + + m_flWeight = m_flCurWeight * ( 1.0f - m_flWeight ); + + BaseClass::ClientThink(); +} diff --git a/game/client/c_spatialentity.h b/game/client/c_spatialentity.h new file mode 100644 index 000000000..1657d56b0 --- /dev/null +++ b/game/client/c_spatialentity.h @@ -0,0 +1,144 @@ +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// +// +// Purpose: Spatial entity with simple radial falloff +// +// $NoKeywords: $ +//===========================================================================// + +#ifndef C_SPATIALENTITY_H +#define C_SPATIALENTITY_H + +#ifdef _WIN32 +#pragma once +#endif + +#define SPATIAL_ENTITY_FORCED_VALUE_BLEND_DISTANCE 128.0f + +//------------------------------------------------------------------------------ +// Purpose : Spatial entity with radial falloff +//------------------------------------------------------------------------------ +class C_SpatialEntity : public C_BaseEntity +{ +public: + DECLARE_CLASS( C_SpatialEntity, C_BaseEntity ); + DECLARE_CLIENTCLASS(); + + virtual void OnDataChanged(DataUpdateType_t updateType); + virtual void UpdateOnRemove( void ); + virtual bool ShouldDraw(); + + virtual void ClientThink(); + virtual void InitSpatialEntity(); + + virtual void ResetAccumulation( void ) {}; + virtual void Accumulate( void ) {}; + virtual void ApplyAccumulation( void ) {}; + + float GetMinFalloff( void ) { return m_minFalloff; } + float GetMaxFalloff( void ) { return m_maxFalloff; } + + void SetFalloff( float flMinFalloff, float flMaxFalloff ) { m_minFalloff = flMinFalloff; m_maxFalloff = flMaxFalloff; } + void SetEnabled( bool bEnabled ) { m_bEnabled = bEnabled; } + void SetCurWeight( float flWeight ) { m_flCurWeight = flWeight; } + +protected: + virtual void AddToPersonalSpatialEntityMgr( void ) {}; + virtual void RemoveFromPersonalSpatialEntityMgr( void ) {}; + +private: + Vector m_vecOrigin; + + float m_minFalloff; + float m_maxFalloff; + float m_flCurWeight; + char m_netLookupFilename[MAX_PATH]; + + bool m_bEnabled; + +protected: + float m_flWeight; // Interpolator for how much it's value adds to the total + float m_flInfluence; // Distance within the inner radius +}; + + +template +class C_SpatialEntityTemplate : public C_SpatialEntity +{ + DECLARE_CLASS( C_SpatialEntityTemplate, C_SpatialEntity ); +public: + virtual void ResetAccumulation( void ) + { + m_AccumulatedValue = 0; + m_ForcedValue = 0; + m_ForcedMinFalloff = GetMinFalloff(); + m_ForcedInfluence = 0.0f; + } + + virtual void Accumulate( void ) + { + if ( m_flInfluence > m_ForcedInfluence ) + { + // This value is in control unless a stronger influence is accumulated + m_ForcedValue = m_Value; + m_ForcedMinFalloff = GetMinFalloff(); + m_ForcedInfluence = m_flInfluence; + } + + // Contribute to the total + m_AccumulatedValue += m_Value * m_flWeight; + } + + T BlendedValue( void ) + { + if ( m_ForcedInfluence <= 0.0f ) + { + // No forced value + return m_AccumulatedValue; + } + + // Check if we're fully inside the forced area + if ( m_ForcedInfluence >= SPATIAL_ENTITY_FORCED_VALUE_BLEND_DISTANCE ) + { + // Fully inside the forced area + return m_ForcedValue; + } + + // Blend between the accumulated value and the forced value + float flInterp = ( SPATIAL_ENTITY_FORCED_VALUE_BLEND_DISTANCE - m_ForcedInfluence ) / SPATIAL_ENTITY_FORCED_VALUE_BLEND_DISTANCE; + + return ( m_AccumulatedValue * flInterp ) + ( m_ForcedValue * ( 1.0f - flInterp ) ); + } + +protected: + + T m_Value; + +private: + static T m_AccumulatedValue; + static T m_ForcedValue; + static float m_ForcedMinFalloff; + static float m_ForcedInfluence; +}; + +template +T C_SpatialEntityTemplate::m_AccumulatedValue; + +template +T C_SpatialEntityTemplate::m_ForcedValue; + +template +float C_SpatialEntityTemplate::m_ForcedMinFalloff; + +template +float C_SpatialEntityTemplate::m_ForcedInfluence; + +template <> +void C_SpatialEntityTemplate::ResetAccumulation( void ) +{ + m_AccumulatedValue.Init(); + m_ForcedValue.Init(); + m_ForcedMinFalloff = GetMinFalloff(); + m_ForcedInfluence = 0.0f; +} + +#endif // C_SPATIALENTITY_H \ No newline at end of file diff --git a/game/client/c_spotlight_end.cpp b/game/client/c_spotlight_end.cpp index d47d4aa05..b9007df57 100644 --- a/game/client/c_spotlight_end.cpp +++ b/game/client/c_spotlight_end.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // @@ -100,10 +100,12 @@ void C_SpotlightEnd::ClientThink(void) if ( m_flLightScale <= 0 ) return; + color24 c = GetRenderColor(); + float a = GetRenderAlpha() / 255.0f; ColorRGBExp32 color; - color.r = m_clrRender->r * m_clrRender->a; - color.g = m_clrRender->g * m_clrRender->a; - color.b = m_clrRender->b * m_clrRender->a; + color.r = c.r * a; + color.g = c.g * a; + color.b = c.b * a; color.exponent = 0; if ( color.r == 0 && color.g == 0 && color.b == 0 ) return; @@ -134,9 +136,9 @@ void C_SpotlightEnd::ClientThink(void) m_pModelLight->radius = m_Radius; m_pModelLight->flags = DLIGHT_NO_WORLD_ILLUMINATION; - m_pModelLight->color.r = m_clrRender->r * m_clrRender->a; - m_pModelLight->color.g = m_clrRender->g * m_clrRender->a; - m_pModelLight->color.b = m_clrRender->b * m_clrRender->a; + m_pModelLight->color.r = c.r * c.a; + m_pModelLight->color.g = c.g * c.a; + m_pModelLight->color.b = c.b * c.a; m_pModelLight->color.exponent = 1; m_pModelLight->origin = m_vSpotlightOrg; m_pModelLight->m_InnerAngle = 6; diff --git a/game/client/c_sprite.cpp b/game/client/c_sprite.cpp index 9146eefc0..a9c9d9423 100644 --- a/game/client/c_sprite.cpp +++ b/game/client/c_sprite.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // @@ -14,7 +14,7 @@ #include "util_shared.h" #include "tier0/vprof.h" #include "materialsystem/imaterial.h" -#include "materialsystem/imaterialvar.h" +#include "materialsystem/IMaterialVar.h" #include "view_shared.h" #include "viewrender.h" #include "tier1/KeyValues.h" @@ -395,8 +395,7 @@ int C_SpriteRenderer::DrawSprite( // don't draw viewmodel effects in reflections if ( CurrentViewID() == VIEW_REFLECTION ) { - int group = ent->GetRenderGroup(); - if ( group == RENDER_GROUP_VIEW_MODEL_TRANSLUCENT || group == RENDER_GROUP_VIEW_MODEL_OPAQUE ) + if ( g_pClientLeafSystem->IsRenderingWithViewModels( ent->RenderHandle() ) ) return 0; } QAngle temp; @@ -474,7 +473,7 @@ void CSprite::GetToolRecordingState( KeyValues *msg ) ent->GetAttachment( m_nAttachment, pState->m_vecRenderOrigin, temp ); // override viewmodel if we're driven by an attachment - bool bViewModel = dynamic_cast< C_BaseViewModel* >( ent ) != NULL; + bool bViewModel = ToBaseViewModel( ent ) != NULL; msg->SetInt( "viewmodel", bViewModel ); } } @@ -487,14 +486,16 @@ void CSprite::GetToolRecordingState( KeyValues *msg ) renderscale /= flMinSize; } + color24 c = GetRenderColor(); + // sprite params static SpriteRecordingState_t state; state.m_flRenderScale = renderscale; state.m_flFrame = m_flFrame; state.m_flProxyRadius = m_flGlowProxySize; state.m_nRenderMode = GetRenderMode(); - state.m_nRenderFX = m_nRenderFX; - state.m_Color.SetColor( m_clrRender.GetR(), m_clrRender.GetG(), m_clrRender.GetB(), GetRenderBrightness() ); + state.m_nRenderFX = GetRenderFX() ? true : false; + state.m_Color.SetColor( c.r, c.g, c.b, GetRenderBrightness() ); msg->SetPtr( "sprite", &state ); } diff --git a/game/client/c_sprite.h b/game/client/c_sprite.h index d367eaebf..43755b386 100644 --- a/game/client/c_sprite.h +++ b/game/client/c_sprite.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // @@ -10,7 +10,7 @@ #pragma once #endif -#include "Sprite.h" +#include "sprite.h" #include "c_pixel_visibility.h" #endif // C_SPRITE_H diff --git a/game/client/c_sprite_perfmonitor.cpp b/game/client/c_sprite_perfmonitor.cpp index 3994d14fc..eb278bd37 100644 --- a/game/client/c_sprite_perfmonitor.cpp +++ b/game/client/c_sprite_perfmonitor.cpp @@ -1,10 +1,15 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======= // // Purpose: // //============================================================================= + #include "cbase.h" +// NOTE: This has to be the last file included! +#include "tier0/memdbgon.h" + + extern bool g_bMeasureParticlePerformance; extern bool g_bDisplayParticlePerformance; diff --git a/game/client/c_steamjet.cpp b/game/client/c_steamjet.cpp index f36ccc638..fc3895022 100644 --- a/game/client/c_steamjet.cpp +++ b/game/client/c_steamjet.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: Implements a particle system steam jet. // @@ -8,7 +8,6 @@ #include "particle_prototype.h" #include "particle_util.h" #include "baseparticleentity.h" -#include "clienteffectprecachesystem.h" #include "fx.h" // memdbgon must be the last include file in a .cpp file!!! @@ -415,7 +414,7 @@ void C_SteamJet::RenderParticles( CParticleRenderIterator *pIterator ) pIterator->GetParticleDraw(), tPos, vRampColor, - sinLifetime * (m_clrRender->a/255.0f), + sinLifetime * (GetRenderAlpha()/255.0f), FLerp(m_StartSize, m_EndSize, pParticle->m_Lifetime)); } else @@ -424,7 +423,7 @@ void C_SteamJet::RenderParticles( CParticleRenderIterator *pIterator ) pIterator->GetParticleDraw(), tPos, vRampColor, - sinLifetime * (m_clrRender->a/255.0f), + sinLifetime * (GetRenderAlpha()/255.0f), FLerp(pParticle->m_uchStartSize, pParticle->m_uchEndSize, pParticle->m_Lifetime), pParticle->m_flRoll ); } @@ -498,9 +497,9 @@ void C_SteamJet::UpdateLightingRamp() if ( IsEmissive() ) { - pRamp->x += (m_clrRender->r/255.0f); - pRamp->y += (m_clrRender->g/255.0f); - pRamp->z += (m_clrRender->b/255.0f); + pRamp->x += (GetRenderColorR()/255.0f); + pRamp->y += (GetRenderColorG()/255.0f); + pRamp->z += (GetRenderColorB()/255.0f); pRamp->x = clamp( pRamp->x, 0.0f, 1.0f ); pRamp->y = clamp( pRamp->y, 0.0f, 1.0f ); @@ -508,9 +507,9 @@ void C_SteamJet::UpdateLightingRamp() } else { - pRamp->x *= (m_clrRender->r/255.0f); - pRamp->y *= (m_clrRender->g/255.0f); - pRamp->z *= (m_clrRender->b/255.0f); + pRamp->x *= (GetRenderColorR()/255.0f); + pRamp->y *= (GetRenderColorG()/255.0f); + pRamp->z *= (GetRenderColorB()/255.0f); } // Renormalize? diff --git a/game/client/c_stickybolt.cpp b/game/client/c_stickybolt.cpp index 7b710f790..7db6ae5f9 100644 --- a/game/client/c_stickybolt.cpp +++ b/game/client/c_stickybolt.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: Implements the Sticky Bolt code. This constraints ragdolls to the world // after being hit by a crossbow bolt. If something here is acting funny @@ -18,8 +18,8 @@ #include "decals.h" #include "iefx.h" #include "engine/IEngineSound.h" -#include "materialsystem/imaterialvar.h" -#include "IEffects.h" +#include "materialsystem/IMaterialVar.h" +#include "ieffects.h" #include "engine/IEngineTrace.h" #include "vphysics/constraints.h" #include "engine/ivmodelinfo.h" @@ -126,9 +126,10 @@ class CRagdollBoltEnumerator : public IPartitionEnumerator Vector m_vWorld; }; +#define CROSSBOW_BOLT_MODEL "models/crossbow_bolt.mdl" void CreateCrossbowBolt( const Vector &vecOrigin, const Vector &vecDirection ) { - model_t *pModel = (model_t *)engine->LoadModel( "models/crossbow_bolt.mdl" ); + model_t *pModel = (model_t *)engine->LoadModel( CROSSBOW_BOLT_MODEL ); QAngle vAngles; @@ -173,4 +174,6 @@ void StickyBoltCallback( const CEffectData &data ) StickRagdollNow( data.m_vOrigin, data.m_vNormal ); } -DECLARE_CLIENT_EFFECT( "BoltImpact", StickyBoltCallback ); \ No newline at end of file +DECLARE_CLIENT_EFFECT_BEGIN( BoltImpact, StickyBoltCallback ) + PRECACHE( MODEL, CROSSBOW_BOLT_MODEL ) +DECLARE_CLIENT_EFFECT_END() \ No newline at end of file diff --git a/game/client/c_sun.cpp b/game/client/c_sun.cpp index 265bb53a5..8e2d3400f 100644 --- a/game/client/c_sun.cpp +++ b/game/client/c_sun.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // @@ -20,8 +20,8 @@ static void RecvProxy_HDRColorScale( const CRecvProxyData *pData, void *pStruct, IMPLEMENT_CLIENTCLASS_DT_NOBASE( C_Sun, DT_Sun, CSun ) - RecvPropInt( RECVINFO(m_clrRender), 0, RecvProxy_IntToColor32 ), - RecvPropInt( RECVINFO(m_clrOverlay), 0, RecvProxy_IntToColor32 ), + RecvPropInt( RECVINFO(m_clrRender), 0, RecvProxy_Int32ToColor32 ), + RecvPropInt( RECVINFO(m_clrOverlay), 0, RecvProxy_Int32ToColor32 ), RecvPropVector( RECVINFO( m_vDirection ) ), RecvPropInt( RECVINFO( m_bOn ) ), RecvPropInt( RECVINFO( m_nSize ) ), @@ -56,8 +56,8 @@ void C_Sun::OnDataChanged( DataUpdateType_t updateType ) // will change and that will cause the material to become more translucent This would be incorrect // for the sun, which should always be completely opaque at its core. Here, we renormalize the // components to make sure only hue is altered. - - float maxComponent = MAX ( m_clrRender->r, MAX ( m_clrRender->g, m_clrRender->b ) ); + color24 c = GetRenderColor(); + float maxComponent = MAX( c.r, MAX( c.g, c.b ) ); Vector vOverlayColor; Vector vMainColor; @@ -70,9 +70,9 @@ void C_Sun::OnDataChanged( DataUpdateType_t updateType ) } else { - vMainColor.x = m_clrRender->r / maxComponent; - vMainColor.y = m_clrRender->g / maxComponent; - vMainColor.z = m_clrRender->b / maxComponent; + vMainColor.x = c.r / maxComponent; + vMainColor.y = c.g / maxComponent; + vMainColor.z = c.b / maxComponent; } // If we're non-zero, use the value (otherwise use the value we calculated above) diff --git a/game/client/c_sun.h b/game/client/c_sun.h index 5f15e35f6..0485e6338 100644 --- a/game/client/c_sun.h +++ b/game/client/c_sun.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // diff --git a/game/client/c_sunlightshadowcontrol.cpp b/game/client/c_sunlightshadowcontrol.cpp new file mode 100644 index 000000000..dac2848d5 --- /dev/null +++ b/game/client/c_sunlightshadowcontrol.cpp @@ -0,0 +1,237 @@ +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: Sunlight shadow control entity. +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" + +#include "c_baseplayer.h" +#ifdef INFESTED_DLL +#include "c_asw_marine.h" +#endif + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + +ConVar cl_sunlight_ortho_size("cl_sunlight_ortho_size", "0.0", FCVAR_CHEAT, "Set to values greater than 0 for ortho view render projections."); +ConVar cl_sunlight_depthbias( "cl_sunlight_depthbias", "0.02" ); + +//------------------------------------------------------------------------------ +// Purpose : Sunlights shadow control entity +//------------------------------------------------------------------------------ +class C_SunlightShadowControl : public C_BaseEntity +{ +public: + DECLARE_CLASS( C_SunlightShadowControl, C_BaseEntity ); + + DECLARE_CLIENTCLASS(); + + virtual ~C_SunlightShadowControl(); + + void OnDataChanged( DataUpdateType_t updateType ); + void Spawn(); + bool ShouldDraw(); + + void ClientThink(); + +private: + Vector m_shadowDirection; + bool m_bEnabled; + char m_TextureName[ MAX_PATH ]; + CTextureReference m_SpotlightTexture; + color32 m_LightColor; + Vector m_CurrentLinearFloatLightColor; + float m_flCurrentLinearFloatLightAlpha; + float m_flColorTransitionTime; + float m_flSunDistance; + float m_flFOV; + float m_flNearZ; + float m_flNorthOffset; + bool m_bEnableShadows; + bool m_bOldEnableShadows; + + static ClientShadowHandle_t m_LocalFlashlightHandle; +}; + + +ClientShadowHandle_t C_SunlightShadowControl::m_LocalFlashlightHandle = CLIENTSHADOW_INVALID_HANDLE; + + +IMPLEMENT_CLIENTCLASS_DT(C_SunlightShadowControl, DT_SunlightShadowControl, CSunlightShadowControl) + RecvPropVector(RECVINFO(m_shadowDirection)), + RecvPropBool(RECVINFO(m_bEnabled)), + RecvPropString(RECVINFO(m_TextureName)), + RecvPropInt(RECVINFO(m_LightColor), 0, RecvProxy_Int32ToColor32), + RecvPropFloat(RECVINFO(m_flColorTransitionTime)), + RecvPropFloat(RECVINFO(m_flSunDistance)), + RecvPropFloat(RECVINFO(m_flFOV)), + RecvPropFloat(RECVINFO(m_flNearZ)), + RecvPropFloat(RECVINFO(m_flNorthOffset)), + RecvPropBool(RECVINFO(m_bEnableShadows)), +END_RECV_TABLE() + + +C_SunlightShadowControl::~C_SunlightShadowControl() +{ + if ( m_LocalFlashlightHandle != CLIENTSHADOW_INVALID_HANDLE ) + { + g_pClientShadowMgr->DestroyFlashlight( m_LocalFlashlightHandle ); + m_LocalFlashlightHandle = CLIENTSHADOW_INVALID_HANDLE; + } +} + +void C_SunlightShadowControl::OnDataChanged( DataUpdateType_t updateType ) +{ + if ( updateType == DATA_UPDATE_CREATED ) + { + m_SpotlightTexture.Init( m_TextureName, TEXTURE_GROUP_OTHER, true ); + } + + BaseClass::OnDataChanged( updateType ); +} + +void C_SunlightShadowControl::Spawn() +{ + BaseClass::Spawn(); + + m_bOldEnableShadows = m_bEnableShadows; + + SetNextClientThink( CLIENT_THINK_ALWAYS ); +} + +//------------------------------------------------------------------------------ +// We don't draw... +//------------------------------------------------------------------------------ +bool C_SunlightShadowControl::ShouldDraw() +{ + return false; +} + +void C_SunlightShadowControl::ClientThink() +{ + VPROF("C_SunlightShadowControl::ClientThink"); + if ( m_bEnabled ) + { + Vector vLinearFloatLightColor( m_LightColor.r, m_LightColor.g, m_LightColor.b ); + float flLinearFloatLightAlpha = m_LightColor.a; + + if ( m_CurrentLinearFloatLightColor != vLinearFloatLightColor || m_flCurrentLinearFloatLightAlpha != flLinearFloatLightAlpha ) + { + float flColorTransitionSpeed = gpGlobals->frametime * m_flColorTransitionTime * 255.0f; + + m_CurrentLinearFloatLightColor.x = Approach( vLinearFloatLightColor.x, m_CurrentLinearFloatLightColor.x, flColorTransitionSpeed ); + m_CurrentLinearFloatLightColor.y = Approach( vLinearFloatLightColor.y, m_CurrentLinearFloatLightColor.y, flColorTransitionSpeed ); + m_CurrentLinearFloatLightColor.z = Approach( vLinearFloatLightColor.z, m_CurrentLinearFloatLightColor.z, flColorTransitionSpeed ); + m_flCurrentLinearFloatLightAlpha = Approach( flLinearFloatLightAlpha, m_flCurrentLinearFloatLightAlpha, flColorTransitionSpeed ); + } + + FlashlightState_t state; + + Vector vDirection = m_shadowDirection; + VectorNormalize( vDirection ); + + QAngle angView; + engine->GetViewAngles( angView ); + + //Vector vViewUp = Vector( 0.0f, 1.0f, 0.0f ); + Vector vSunDirection2D = vDirection; + vSunDirection2D.z = 0.0f; + + HACK_GETLOCALPLAYER_GUARD( "C_SunlightShadowControl::ClientThink" ); + +#ifdef INFESTED_DLL // shine sun on your current marine, rather than the player entity + C_ASW_Marine *pMarine = C_ASW_Marine::GetLocalMarine(); + if ( !pMarine ) + return; + + Vector vPos = ( pMarine->GetAbsOrigin() + vSunDirection2D * m_flNorthOffset ) - vDirection * m_flSunDistance; +#else + if ( !C_BasePlayer::GetLocalPlayer() ) + return; + + Vector vPos = ( C_BasePlayer::GetLocalPlayer()->GetAbsOrigin() + vSunDirection2D * m_flNorthOffset ) - vDirection * m_flSunDistance; +#endif + + QAngle angAngles; + VectorAngles( vDirection, angAngles ); + + Vector vForward, vRight, vUp; + AngleVectors( angAngles, &vForward, &vRight, &vUp ); + + state.m_fHorizontalFOVDegrees = m_flFOV; + state.m_fVerticalFOVDegrees = m_flFOV; + + state.m_vecLightOrigin = vPos; + BasisToQuaternion( vForward, vRight, vUp, state.m_quatOrientation ); + + state.m_fQuadraticAtten = 0.0f; + state.m_fLinearAtten = m_flSunDistance / 2.0f; + state.m_fConstantAtten = 0.0f; + state.m_FarZAtten = m_flSunDistance + 300.0f; + state.m_Color[0] = m_CurrentLinearFloatLightColor.x * ( 1.0f / 255.0f ) * m_flCurrentLinearFloatLightAlpha; + state.m_Color[1] = m_CurrentLinearFloatLightColor.y * ( 1.0f / 255.0f ) * m_flCurrentLinearFloatLightAlpha; + state.m_Color[2] = m_CurrentLinearFloatLightColor.z * ( 1.0f / 255.0f ) * m_flCurrentLinearFloatLightAlpha; + state.m_Color[3] = 0.0f; // fixme: need to make ambient work m_flAmbient; + state.m_NearZ = fpmax( 4.0f, m_flSunDistance - m_flNearZ ); + state.m_FarZ = m_flSunDistance + 300.0f; + + float flOrthoSize = cl_sunlight_ortho_size.GetFloat(); + + if ( flOrthoSize > 0 ) + { + state.m_bOrtho = true; + state.m_fOrthoLeft = -flOrthoSize; + state.m_fOrthoTop = -flOrthoSize; + state.m_fOrthoRight = flOrthoSize; + state.m_fOrthoBottom = flOrthoSize; + } + else + { + state.m_bOrtho = false; + } + + state.m_flShadowSlopeScaleDepthBias = 2; + state.m_flShadowDepthBias = cl_sunlight_depthbias.GetFloat(); + state.m_bEnableShadows = m_bEnableShadows; + state.m_pSpotlightTexture = m_SpotlightTexture; + state.m_pProjectedMaterial = NULL; + state.m_nSpotlightTextureFrame = 0; + + state.m_nShadowQuality = 1; // Allow entity to affect shadow quality + state.m_bShadowHighRes = true; + + if ( m_bOldEnableShadows != m_bEnableShadows ) + { + // If they change the shadow enable/disable, we need to make a new handle + if ( m_LocalFlashlightHandle != CLIENTSHADOW_INVALID_HANDLE ) + { + g_pClientShadowMgr->DestroyFlashlight( m_LocalFlashlightHandle ); + m_LocalFlashlightHandle = CLIENTSHADOW_INVALID_HANDLE; + } + + m_bOldEnableShadows = m_bEnableShadows; + } + + if( m_LocalFlashlightHandle == CLIENTSHADOW_INVALID_HANDLE ) + { + m_LocalFlashlightHandle = g_pClientShadowMgr->CreateFlashlight( state ); + } + else + { + g_pClientShadowMgr->UpdateFlashlightState( m_LocalFlashlightHandle, state ); +#ifndef INFESTED_DLL +#pragma message("TODO: rebuild sunlight projected texture after sunlight control changes.") + g_pClientShadowMgr->UpdateProjectedTexture( m_LocalFlashlightHandle, true ); +#endif + } + } + else if ( m_LocalFlashlightHandle != CLIENTSHADOW_INVALID_HANDLE ) + { + g_pClientShadowMgr->DestroyFlashlight( m_LocalFlashlightHandle ); + m_LocalFlashlightHandle = CLIENTSHADOW_INVALID_HANDLE; + } + + BaseClass::ClientThink(); +} diff --git a/game/client/c_surfacerender.cpp b/game/client/c_surfacerender.cpp new file mode 100644 index 000000000..0402b4c53 --- /dev/null +++ b/game/client/c_surfacerender.cpp @@ -0,0 +1,19 @@ +//========= Copyright © 1996-2007, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" + +#include "c_surfacerender.h" + +#include "view.h" +#include "view_shared.h" +#include "iviewrender.h" +#include "engine/IVDebugOverlay.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + diff --git a/game/client/c_surfacerender.h b/game/client/c_surfacerender.h new file mode 100644 index 000000000..47accd635 --- /dev/null +++ b/game/client/c_surfacerender.h @@ -0,0 +1,18 @@ +//========= Copyright © 1996-2007, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef C_SURFACERENDER_H +#define C_SURFACERENDER_H + +#if defined( _WIN32 ) +#pragma once +#endif + + + + +#endif // C_SURFACERENDER_H diff --git a/game/client/c_te.cpp b/game/client/c_te.cpp index 113e71e45..c07438c73 100644 --- a/game/client/c_te.cpp +++ b/game/client/c_te.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//=== Copyright © 1996-2005, Valve Corporation, All rights reserved. ========// // // Purpose: // @@ -7,11 +7,12 @@ #include "cbase.h" #include "itempents.h" #include "effect_dispatch_data.h" -#include "tier1/KeyValues.h" +#include "tier1/keyvalues.h" #include "iefx.h" -#include "IEffects.h" +#include "ieffects.h" #include "toolframework_client.h" #include "cdll_client_int.h" +#include "c_te_effect_dispatch.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -118,11 +119,8 @@ void TE_Dust( IRecipientFilter& filter, float delay, const Vector &pos, const Vector &dir, float size, float speed ); void TE_GaussExplosion( IRecipientFilter& filter, float delayt, const Vector &pos, const Vector &dir, int type ); -void TE_DispatchEffect( IRecipientFilter& filter, float delay, - const Vector &pos, const char *pName, const CEffectData &data ); -void TE_DispatchEffect( IRecipientFilter& filter, float delay, KeyValues *pKeyValues ); void TE_PhysicsProp( IRecipientFilter& filter, float delay, - int modelindex, int skin, const Vector& pos, const QAngle &angles, const Vector& vel, bool breakmodel, int effects ); + int modelindex, int skin, const Vector& pos, const QAngle &angles, const Vector& vel, int flags, int effects ); void TE_PhysicsProp( IRecipientFilter& filter, float delay, KeyValues *pKeyValues ); void TE_ConcussiveExplosion( IRecipientFilter& filter, float delay, KeyValues *pKeyValues ); void TE_ClientProjectile( IRecipientFilter& filter, float delay, @@ -500,14 +498,6 @@ class C_TempEntsSystem : public ITempEntsSystem TE_GaussExplosion( filter, delay, pos, dir, type ); } } - virtual void DispatchEffect( IRecipientFilter& filter, float delay, - const Vector &pos, const char *pName, const CEffectData &data ) - { - if ( !SuppressTE( filter ) ) - { - TE_DispatchEffect( filter, delay, pos, pName, data ); - } - } virtual void PhysicsProp( IRecipientFilter& filter, float delay, int modelindex, int skin, const Vector& pos, const QAngle &angles, const Vector& vel, int flags, int effects ) { @@ -549,7 +539,7 @@ class C_TempEntsSystem : public ITempEntsSystem break; case TE_DISPATCH_EFFECT: - TE_DispatchEffect( filter, 0.0f, pKeyValues ); + DispatchEffect( filter, 0.0f, pKeyValues ); break; case TE_MUZZLE_FLASH: diff --git a/game/client/c_te_armorricochet.cpp b/game/client/c_te_armorricochet.cpp index c84afc854..d92c9aa0c 100644 --- a/game/client/c_te_armorricochet.cpp +++ b/game/client/c_te_armorricochet.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // @@ -9,7 +9,7 @@ #include "cbase.h" #include "c_basetempentity.h" #include "IEffects.h" -#include "tier1/KeyValues.h" +#include "tier1/keyvalues.h" #include "tier0/vprof.h" #include "toolframework_client.h" diff --git a/game/client/c_te_basebeam.cpp b/game/client/c_te_basebeam.cpp index f49b94f94..a4d106ada 100644 --- a/game/client/c_te_basebeam.cpp +++ b/game/client/c_te_basebeam.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // diff --git a/game/client/c_te_basebeam.h b/game/client/c_te_basebeam.h index 1fd17b206..c00d8be0e 100644 --- a/game/client/c_te_basebeam.h +++ b/game/client/c_te_basebeam.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // diff --git a/game/client/c_te_beamentpoint.cpp b/game/client/c_te_beamentpoint.cpp index 41b15b40f..d8653bb59 100644 --- a/game/client/c_te_beamentpoint.cpp +++ b/game/client/c_te_beamentpoint.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // diff --git a/game/client/c_te_beaments.cpp b/game/client/c_te_beaments.cpp index 76d39e718..ee5c98288 100644 --- a/game/client/c_te_beaments.cpp +++ b/game/client/c_te_beaments.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // diff --git a/game/client/c_te_beamfollow.cpp b/game/client/c_te_beamfollow.cpp index a8e6f4f21..703f75ef3 100644 --- a/game/client/c_te_beamfollow.cpp +++ b/game/client/c_te_beamfollow.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // diff --git a/game/client/c_te_beamlaser.cpp b/game/client/c_te_beamlaser.cpp index a081e5c7c..fe8b293dc 100644 --- a/game/client/c_te_beamlaser.cpp +++ b/game/client/c_te_beamlaser.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: Beam that's used for the sniper's laser sight // diff --git a/game/client/c_te_beampoints.cpp b/game/client/c_te_beampoints.cpp index b2f4369c9..0baa8d12e 100644 --- a/game/client/c_te_beampoints.cpp +++ b/game/client/c_te_beampoints.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // diff --git a/game/client/c_te_beamring.cpp b/game/client/c_te_beamring.cpp index eced22367..1448f0205 100644 --- a/game/client/c_te_beamring.cpp +++ b/game/client/c_te_beamring.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // diff --git a/game/client/c_te_beamringpoint.cpp b/game/client/c_te_beamringpoint.cpp index 832ba2f14..b4a2e1e3c 100644 --- a/game/client/c_te_beamringpoint.cpp +++ b/game/client/c_te_beamringpoint.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // diff --git a/game/client/c_te_beamspline.cpp b/game/client/c_te_beamspline.cpp index 443b23c3a..a31f331f6 100644 --- a/game/client/c_te_beamspline.cpp +++ b/game/client/c_te_beamspline.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // diff --git a/game/client/c_te_bloodsprite.cpp b/game/client/c_te_bloodsprite.cpp index 4e6e3eb01..47db44117 100644 --- a/game/client/c_te_bloodsprite.cpp +++ b/game/client/c_te_bloodsprite.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // @@ -10,15 +10,15 @@ #include "c_basetempentity.h" #include "c_te_legacytempents.h" #include "fx.h" -#include "tier1/KeyValues.h" +#include "tier1/keyvalues.h" #include "tier0/vprof.h" #include "toolframework_client.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" -extern short g_sModelIndexBloodDrop; -extern short g_sModelIndexBloodSpray; +extern int g_sModelIndexBloodDrop; +extern int g_sModelIndexBloodSpray; //----------------------------------------------------------------------------- // Purpose: Blood sprite diff --git a/game/client/c_te_bloodstream.cpp b/game/client/c_te_bloodstream.cpp index d543d1110..0bf825589 100644 --- a/game/client/c_te_bloodstream.cpp +++ b/game/client/c_te_bloodstream.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // @@ -7,7 +7,7 @@ //===========================================================================// #include "cbase.h" #include "c_te_particlesystem.h" -#include "tier1/KeyValues.h" +#include "tier1/keyvalues.h" #include "toolframework_client.h" // memdbgon must be the last include file in a .cpp file!!! @@ -114,7 +114,7 @@ void TE_BloodStream( IRecipientFilter& filter, float delay, float arc = 0.05; int count, count2; float num; - float speedCopy = amount; + int speedCopy = amount; Vector dir; VectorCopy( *direction, dir ); diff --git a/game/client/c_te_breakmodel.cpp b/game/client/c_te_breakmodel.cpp index d09fe31d2..28950c4ef 100644 --- a/game/client/c_te_breakmodel.cpp +++ b/game/client/c_te_breakmodel.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // @@ -9,7 +9,7 @@ #include "cbase.h" #include "c_basetempentity.h" #include "c_te_legacytempents.h" -#include "tier1/KeyValues.h" +#include "tier1/keyvalues.h" #include "tier0/vprof.h" #include "toolframework_client.h" diff --git a/game/client/c_te_bspdecal.cpp b/game/client/c_te_bspdecal.cpp index 445912c2c..a237dd024 100644 --- a/game/client/c_te_bspdecal.cpp +++ b/game/client/c_te_bspdecal.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // diff --git a/game/client/c_te_bubbles.cpp b/game/client/c_te_bubbles.cpp index 7d406fa46..58e2784ba 100644 --- a/game/client/c_te_bubbles.cpp +++ b/game/client/c_te_bubbles.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // diff --git a/game/client/c_te_bubbletrail.cpp b/game/client/c_te_bubbletrail.cpp index ab0a7f216..2f3fc529e 100644 --- a/game/client/c_te_bubbletrail.cpp +++ b/game/client/c_te_bubbletrail.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // diff --git a/game/client/c_te_clientprojectile.cpp b/game/client/c_te_clientprojectile.cpp index f2a173923..375b020bd 100644 --- a/game/client/c_te_clientprojectile.cpp +++ b/game/client/c_te_clientprojectile.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======= // // Purpose: // diff --git a/game/client/c_te_decal.cpp b/game/client/c_te_decal.cpp index f0212ee1a..894e190d0 100644 --- a/game/client/c_te_decal.cpp +++ b/game/client/c_te_decal.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // @@ -10,7 +10,7 @@ #include "c_basetempentity.h" #include "iefx.h" #include "engine/IStaticPropMgr.h" -#include "tier1/KeyValues.h" +#include "tier1/keyvalues.h" #include "tier0/vprof.h" #include "toolframework_client.h" @@ -139,7 +139,7 @@ void TE_Decal( IRecipientFilter& filter, float delay, // Only decal the world + brush models // Here we deal with decals on entities. C_BaseEntity* ent; - if ( ( ent = cl_entitylist->GetEnt( entity ) ) == NULL ) + if ( ( ent = cl_entitylist->GetEnt( entity ) ) == false ) return; ent->AddDecal( *start, *pos, *pos, hitbox, diff --git a/game/client/c_te_dynamiclight.cpp b/game/client/c_te_dynamiclight.cpp index b53765df2..cfd5e5fb7 100644 --- a/game/client/c_te_dynamiclight.cpp +++ b/game/client/c_te_dynamiclight.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // @@ -10,7 +10,7 @@ #include "c_basetempentity.h" #include "dlight.h" #include "iefx.h" -#include "tier1/KeyValues.h" +#include "tier1/keyvalues.h" #include "toolframework_client.h" #include "tier0/vprof.h" diff --git a/game/client/c_te_effect_dispatch.cpp b/game/client/c_te_effect_dispatch.cpp index 9c2557fe7..d852108db 100644 --- a/game/client/c_te_effect_dispatch.cpp +++ b/game/client/c_te_effect_dispatch.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // @@ -11,9 +11,10 @@ #include "networkstringtable_clientdll.h" #include "effect_dispatch_data.h" #include "c_te_effect_dispatch.h" -#include "tier1/KeyValues.h" +#include "tier1/keyvalues.h" #include "toolframework_client.h" #include "tier0/vprof.h" +#include "particles_new.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -26,6 +27,9 @@ CClientEffectRegistration *CClientEffectRegistration::s_pHead = NULL; CClientEffectRegistration::CClientEffectRegistration( const char *pEffectName, ClientEffectCallback fn ) { + AssertMsg1( pEffectName[0] != '\"', "Error: Effect %s. " + "Remove quotes around the effect name in DECLARE_CLIENT_EFFECT.\n", pEffectName ); + m_pEffectName = pEffectName; m_pFunction = fn; m_pNext = s_pHead; @@ -70,19 +74,40 @@ C_TEEffectDispatch::~C_TEEffectDispatch( void ) //----------------------------------------------------------------------------- void DispatchEffectToCallback( const char *pEffectName, const CEffectData &m_EffectData ) { - // Look through all the registered callbacks - for ( CClientEffectRegistration *pReg = CClientEffectRegistration::s_pHead; pReg; pReg = pReg->m_pNext ) + // Built a faster lookup + static CUtlStringMap< CClientEffectRegistration* > map; + static bool bInitializedMap = false; + if ( !bInitializedMap ) { - // If the name matches, call it - if ( Q_stricmp( pReg->m_pEffectName, pEffectName ) == 0 ) + for ( CClientEffectRegistration *pReg = CClientEffectRegistration::s_pHead; pReg; pReg = pReg->m_pNext ) { - pReg->m_pFunction( m_EffectData ); - return; + // If the name matches, call it + if ( map.Defined( pReg->m_pEffectName ) ) + { + Warning( "Encountered multiple different effects with the same name \"%s\"!\n", pReg->m_pEffectName ); + continue; + } + + map[ pReg->m_pEffectName ] = pReg; } + bInitializedMap = true; } - DevMsg("DispatchEffect: effect '%s' not found on client\n", pEffectName ); + // Look through all the registered callbacks + UtlSymId_t nSym = map.Find( pEffectName ); + if ( nSym == UTL_INVAL_SYMBOL ) + { + Warning("DispatchEffect: effect \"%s\" not found on client\n", pEffectName ); + return; + } + // NOTE: Here, we want to scope resource access to only be able to use + // those resources specified as being dependencies of this effect + g_pPrecacheSystem->LimitResourceAccess( DISPATCH_EFFECT, pEffectName ); + map[nSym]->m_pFunction( m_EffectData ); + + // NOTE: Here, we no longer need to restrict resource access + g_pPrecacheSystem->EndLimitedResourceAccess( ); } @@ -132,7 +157,7 @@ static void RecordEffect( const char *pEffectName, const CEffectData &data ) msg->SetInt( "attachmentindex", data.m_nAttachmentIndex ); // NOTE: Ptrs are our way of indicating it's an entindex - msg->SetPtr( "entindex", (void*)(intp)data.entindex() ); + msg->SetPtr( "entindex", (void*)data.entindex() ); ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, msg ); msg->deleteThis(); @@ -164,26 +189,32 @@ IMPLEMENT_CLIENTCLASS_EVENT_DT( C_TEEffectDispatch, DT_TEEffectDispatch, CTEEffe END_RECV_TABLE() //----------------------------------------------------------------------------- -// Purpose: Clientside version +// Client version of dispatch effect, for predicted weapons //----------------------------------------------------------------------------- -void TE_DispatchEffect( IRecipientFilter& filter, float delay, const Vector &pos, const char *pName, const CEffectData &data ) +void DispatchEffect( IRecipientFilter& filter, float delay, const char *pName, const CEffectData &data ) { - DispatchEffectToCallback( pName, data ); - RecordEffect( pName, data ); + if ( !te->SuppressTE( filter ) ) + { + DispatchEffectToCallback( pName, data ); + RecordEffect( pName, data ); + } } -// Client version of dispatch effect, for predicted weapons void DispatchEffect( const char *pName, const CEffectData &data ) { CPASFilter filter( data.m_vOrigin ); - te->DispatchEffect( filter, 0.0, data.m_vOrigin, pName, data ); + if ( !te->SuppressTE( filter ) ) + { + DispatchEffectToCallback( pName, data ); + RecordEffect( pName, data ); + } } //----------------------------------------------------------------------------- // Playback //----------------------------------------------------------------------------- -void TE_DispatchEffect( IRecipientFilter& filter, float delay, KeyValues *pKeyValues ) +void DispatchEffect( IRecipientFilter& filter, float delay, KeyValues *pKeyValues ) { CEffectData data; data.m_nMaterial = 0; @@ -213,9 +244,31 @@ void TE_DispatchEffect( IRecipientFilter& filter, float delay, KeyValues *pKeyVa // NOTE: Ptrs are our way of indicating it's an entindex ClientEntityHandle_t hWorld = ClientEntityList().EntIndexToHandle( 0 ); - data.m_hEntity = (intp)pKeyValues->GetPtr( "entindex", (void*)(intp)hWorld.ToInt() ); + data.m_hEntity = (int)pKeyValues->GetPtr( "entindex", (void*)hWorld.ToInt() ); const char *pEffectName = pKeyValues->GetString( "effectname" ); - TE_DispatchEffect( filter, 0.0f, data.m_vOrigin, pEffectName, data ); + DispatchEffect( filter, 0.0f, pEffectName, data ); } + + +//----------------------------------------------------------------------------- +// Purpose: Displays an error effect in case of missing precache +//----------------------------------------------------------------------------- +void ErrorEffectCallback( const CEffectData &data ) +{ + CSmartPtr pEffect = CNewParticleEffect::Create( NULL, "error" ); + if ( pEffect->IsValid() ) + { + pEffect->SetSortOrigin( data.m_vOrigin ); + pEffect->SetControlPoint( 0, data.m_vOrigin ); + pEffect->SetControlPoint( 1, data.m_vStart ); + Vector vecForward, vecRight, vecUp; + AngleVectors( data.m_vAngles, &vecForward, &vecRight, &vecUp ); + pEffect->SetControlPointOrientation( 0, vecForward, vecRight, vecUp ); + } +} + +DECLARE_CLIENT_EFFECT_BEGIN( Error, ErrorEffectCallback ) + PRECACHE( PARTICLE_SYSTEM, "error" ) +DECLARE_CLIENT_EFFECT_END() diff --git a/game/client/c_te_effect_dispatch.h b/game/client/c_te_effect_dispatch.h index 63fa61730..c6108887b 100644 --- a/game/client/c_te_effect_dispatch.h +++ b/game/client/c_te_effect_dispatch.h @@ -1,9 +1,9 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ -//=============================================================================// +//===========================================================================// #ifndef C_TE_EFFECT_DISPATCH_H #define C_TE_EFFECT_DISPATCH_H @@ -11,9 +11,8 @@ #pragma once #endif - #include "effect_dispatch_data.h" - +#include "precache_register.h" typedef void (*ClientEffectCallback)( const CEffectData &data ); @@ -34,13 +33,26 @@ class CClientEffectRegistration // // Use this macro to register a client effect callback. -// If you do DECLARE_CLIENT_EFFECT( "MyEffectName", MyCallback ), then MyCallback will be -// called when the server does DispatchEffect( "MyEffect", data ) +// If you do DECLARE_CLIENT_EFFECT( MyEffectName, MyCallback ), then MyCallback will be +// called when the server does DispatchEffect( "MyEffectName", data ) // -#define DECLARE_CLIENT_EFFECT( effectName, callbackFunction ) \ - static CClientEffectRegistration ClientEffectReg_##callbackFunction( effectName, callbackFunction ); +#define DECLARE_CLIENT_EFFECT_INTERNAL( effectName, callbackFunction ) \ + static CClientEffectRegistration ClientEffectReg_##callbackFunction( #effectName, callbackFunction ); + +#define DECLARE_CLIENT_EFFECT( effectName, callbackFunction ) \ + DECLARE_CLIENT_EFFECT_INTERNAL( effectName, callbackFunction ) \ + PRECACHE_REGISTER_BEGIN( DISPATCH_EFFECT, effectName ) \ + PRECACHE_REGISTER_END() + +#define DECLARE_CLIENT_EFFECT_BEGIN( effectName, callbackFunction ) \ + DECLARE_CLIENT_EFFECT_INTERNAL( effectName, callbackFunction ) \ + PRECACHE_REGISTER_BEGIN( DISPATCH_EFFECT, effectName ) + +#define DECLARE_CLIENT_EFFECT_END() PRECACHE_REGISTER_END() void DispatchEffectToCallback( const char *pEffectName, const CEffectData &m_EffectData ); void DispatchEffect( const char *pName, const CEffectData &data ); +void DispatchEffect( IRecipientFilter& filter, float flDelay, const char *pName, const CEffectData &data ); +void DispatchEffect( IRecipientFilter& filter, float delay, KeyValues *pKeyValues ); #endif // C_TE_EFFECT_DISPATCH_H diff --git a/game/client/c_te_energysplash.cpp b/game/client/c_te_energysplash.cpp index b88aea7dc..c4c972b17 100644 --- a/game/client/c_te_energysplash.cpp +++ b/game/client/c_te_energysplash.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // diff --git a/game/client/c_te_explosion.cpp b/game/client/c_te_explosion.cpp index 7c52a0359..630e41028 100644 --- a/game/client/c_te_explosion.cpp +++ b/game/client/c_te_explosion.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: Client explosions // @@ -7,12 +7,11 @@ #include "cbase.h" #include "tempentity.h" // FLAGS #include "c_te_particlesystem.h" -#include "ragdollexplosionenumerator.h" +#include "RagdollExplosionEnumerator.h" #include "glow_overlay.h" #include "fx_explosion.h" -#include "clienteffectprecachesystem.h" #include "engine/ivdebugoverlay.h" -#include "tier1/KeyValues.h" +#include "tier1/keyvalues.h" #include "toolframework_client.h" // memdbgon must be the last include file in a .cpp file!!! @@ -254,7 +253,7 @@ void C_TEExplosion::PostDataUpdate( DataUpdateType_t updateType ) AffectRagdolls(); // Filter out a water explosion - if ( UTIL_PointContents( m_vecOrigin ) & CONTENTS_WATER ) + if ( UTIL_PointContents( m_vecOrigin, MASK_WATER ) & CONTENTS_WATER ) { WaterExplosionEffect().Create( m_vecOrigin, m_nMagnitude, m_fScale, m_nFlags ); return; diff --git a/game/client/c_te_fizz.cpp b/game/client/c_te_fizz.cpp index 93d801749..89411ad68 100644 --- a/game/client/c_te_fizz.cpp +++ b/game/client/c_te_fizz.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // diff --git a/game/client/c_te_footprint.cpp b/game/client/c_te_footprint.cpp index 50bbc3143..a100be624 100644 --- a/game/client/c_te_footprint.cpp +++ b/game/client/c_te_footprint.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // diff --git a/game/client/c_te_glassshatter.cpp b/game/client/c_te_glassshatter.cpp index 9cd5cd6f7..2a4538955 100644 --- a/game/client/c_te_glassshatter.cpp +++ b/game/client/c_te_glassshatter.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // @@ -7,8 +7,8 @@ //===========================================================================// #include "cbase.h" #include "c_basetempentity.h" -#include "particle_simple3d.h" -#include "tier1/KeyValues.h" +#include "particle_simple3D.h" +#include "tier1/keyvalues.h" #include "toolframework_client.h" #include "fx.h" #include "tier0/vprof.h" @@ -23,15 +23,17 @@ #define GLASS_SHARD_NOISE 0.3 #define GLASS_SHARD_GRAVITY 500 #define GLASS_SHARD_DAMPING 0.3 + +#include "precache_register.h" -#include "clienteffectprecachesystem.h" +PRECACHE_REGISTER_BEGIN( GLOBAL, PrecacheEffectGlassShatter ) +PRECACHE( MATERIAL, "effects/fleck_glass1" ) +PRECACHE( MATERIAL, "effects/fleck_glass2" ) +PRECACHE( MATERIAL, "effects/fleck_tile1" ) +PRECACHE( MATERIAL, "effects/fleck_tile2" ) +PRECACHE_REGISTER_END() -CLIENTEFFECT_REGISTER_BEGIN( PrecacheEffectGlassShatter ) -CLIENTEFFECT_MATERIAL( "effects/fleck_glass1" ) -CLIENTEFFECT_MATERIAL( "effects/fleck_glass2" ) -CLIENTEFFECT_MATERIAL( "effects/fleck_tile1" ) -CLIENTEFFECT_MATERIAL( "effects/fleck_tile2" ) -CLIENTEFFECT_REGISTER_END() +ConVar fx_glass_velocity_cap("fx_glass_velocity_cap", "0", 0, "Maximum downwards speed of shattered glass particles"); //################################################### // > C_TEShatterSurface @@ -224,6 +226,12 @@ void C_TEShatterSurface::PostDataUpdate( DataUpdateType_t updateType ) } } + // cap the Z velocity of the shards + if (fx_glass_velocity_cap.GetFloat() > 0 && vForceVel.z < -fx_glass_velocity_cap.GetFloat()) + { + vForceVel.z = random->RandomFloat(-fx_glass_velocity_cap.GetFloat(), -(fx_glass_velocity_cap.GetFloat() * 0.66f)); + } + if (pParticle) { pParticle->m_flLifeRemaining = random->RandomFloat(GLASS_SHARD_MIN_LIFE,GLASS_SHARD_MAX_LIFE); diff --git a/game/client/c_te_glowsprite.cpp b/game/client/c_te_glowsprite.cpp index 35920c02a..b6067f705 100644 --- a/game/client/c_te_glowsprite.cpp +++ b/game/client/c_te_glowsprite.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // @@ -9,7 +9,7 @@ #include "c_basetempentity.h" #include "c_te_legacytempents.h" #include "tempent.h" -#include "tier1/KeyValues.h" +#include "tier1/keyvalues.h" #include "toolframework_client.h" #include "tier0/vprof.h" diff --git a/game/client/c_te_impact.cpp b/game/client/c_te_impact.cpp index 554e8b20f..3057df6d4 100644 --- a/game/client/c_te_impact.cpp +++ b/game/client/c_te_impact.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // diff --git a/game/client/c_te_killplayerattachments.cpp b/game/client/c_te_killplayerattachments.cpp index ebb2436aa..0d17fc054 100644 --- a/game/client/c_te_killplayerattachments.cpp +++ b/game/client/c_te_killplayerattachments.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // diff --git a/game/client/c_te_largefunnel.cpp b/game/client/c_te_largefunnel.cpp index 25430db06..193018be0 100644 --- a/game/client/c_te_largefunnel.cpp +++ b/game/client/c_te_largefunnel.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // diff --git a/game/client/c_te_legacytempents.cpp b/game/client/c_te_legacytempents.cpp index 831715a81..1570146bf 100644 --- a/game/client/c_te_legacytempents.cpp +++ b/game/client/c_te_legacytempents.cpp @@ -1,10 +1,10 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // // $Workfile: $ // $NoKeywords: $ -//=============================================================================// +//===========================================================================// #include "cbase.h" #include "model_types.h" #include "view_shared.h" @@ -18,7 +18,7 @@ #include "iefx.h" #include "engine/IEngineSound.h" #include "env_wind_shared.h" -#include "clienteffectprecachesystem.h" +#include "precache_register.h" #include "fx_sparks.h" #include "fx.h" #include "movevars_shared.h" @@ -28,13 +28,11 @@ #include "tier0/vprof.h" #include "particles_localspace.h" #include "physpropclientside.h" -#include "tier0/icommandline.h" +#include "tier0/ICommandLine.h" #include "datacache/imdlcache.h" -#include "engine/ivdebugoverlay.h" +#include "engine/IVDebugOverlay.h" #include "effect_dispatch_data.h" #include "c_te_effect_dispatch.h" -#include "c_props.h" -#include "c_basedoor.h" // NOTE: Always include this last! #include "tier0/memdbgon.h" @@ -44,40 +42,34 @@ extern ConVar muzzleflash_light; #define TENT_WIND_ACCEL 50 //Precache the effects -#ifndef TF_CLIENT_DLL -CLIENTEFFECT_REGISTER_BEGIN( PrecacheEffectMuzzleFlash ) - - CLIENTEFFECT_MATERIAL( "effects/muzzleflash1" ) - CLIENTEFFECT_MATERIAL( "effects/muzzleflash2" ) - CLIENTEFFECT_MATERIAL( "effects/muzzleflash3" ) - CLIENTEFFECT_MATERIAL( "effects/muzzleflash4" ) - CLIENTEFFECT_MATERIAL( "effects/muzzleflash1_noz" ) - CLIENTEFFECT_MATERIAL( "effects/muzzleflash2_noz" ) - CLIENTEFFECT_MATERIAL( "effects/muzzleflash3_noz" ) - CLIENTEFFECT_MATERIAL( "effects/muzzleflash4_noz" ) -#ifndef CSTRIKE_DLL - CLIENTEFFECT_MATERIAL( "effects/combinemuzzle1" ) - CLIENTEFFECT_MATERIAL( "effects/combinemuzzle2" ) - CLIENTEFFECT_MATERIAL( "effects/combinemuzzle1_noz" ) - CLIENTEFFECT_MATERIAL( "effects/combinemuzzle2_noz" ) - CLIENTEFFECT_MATERIAL( "effects/strider_muzzle" ) -#endif -CLIENTEFFECT_REGISTER_END() -#endif -//Whether or not to eject brass from weapons -ConVar cl_ejectbrass( "cl_ejectbrass", "1" ); +PRECACHE_REGISTER_BEGIN( GLOBAL, PrecacheEffectMuzzleFlash ) + PRECACHE( MATERIAL, "effects/combinemuzzle1" ) + PRECACHE( MATERIAL, "effects/combinemuzzle2" ) + PRECACHE( MATERIAL, "effects/combinemuzzle1_noz" ) + PRECACHE( MATERIAL, "effects/combinemuzzle2_noz" ) + + PRECACHE( MATERIAL, "effects/muzzleflash1" ) + PRECACHE( MATERIAL, "effects/muzzleflash2" ) + PRECACHE( MATERIAL, "effects/muzzleflash3" ) + PRECACHE( MATERIAL, "effects/muzzleflash4" ) + PRECACHE( MATERIAL, "effects/muzzleflash1_noz" ) + PRECACHE( MATERIAL, "effects/muzzleflash2_noz" ) + PRECACHE( MATERIAL, "effects/muzzleflash3_noz" ) + PRECACHE( MATERIAL, "effects/muzzleflash4_noz" ) + + PRECACHE( MATERIAL, "effects/strider_muzzle" ) +PRECACHE_REGISTER_END() + ConVar func_break_max_pieces( "func_break_max_pieces", "15", FCVAR_ARCHIVE | FCVAR_REPLICATED ); ConVar cl_fasttempentcollision( "cl_fasttempentcollision", "5" ); -#if !defined( HL1_CLIENT_DLL ) // HL1 implements a derivative of CTempEnts // Temp entity interface static CTempEnts g_TempEnts; // Expose to rest of the client .dll ITempEnts *tempents = ( ITempEnts * )&g_TempEnts; -#endif @@ -96,7 +88,7 @@ C_LocalTempEntity::C_LocalTempEntity() } -#if defined( CSTRIKE_DLL ) || defined (SDK_DLL ) +#if defined (SDK_DLL ) #define TE_RIFLE_SHELL 1024 #define TE_PISTOL_SHELL 2048 @@ -109,7 +101,7 @@ C_LocalTempEntity::C_LocalTempEntity() // Input : time - // *model - //----------------------------------------------------------------------------- -void C_LocalTempEntity::Prepare( const model_t *pmodel, float time ) +void C_LocalTempEntity::Prepare( model_t *pmodel, float time ) { Interp_SetupMappings( GetVarMapping() ); @@ -121,9 +113,9 @@ void C_LocalTempEntity::Prepare( const model_t *pmodel, float time ) die = time + 0.75; SetModelPointer( pmodel ); SetRenderMode( kRenderNormal ); - m_nRenderFX = kRenderFxNone; - m_nBody = 0; - m_nSkin = 0; + SetRenderFX( kRenderFxNone ); + SetBody( 0 ); + SetSkin( 0 ); fadeSpeed = 0.5; hitSound = 0; clientIndex = -1; @@ -180,8 +172,8 @@ int C_LocalTempEntity::DrawStudioModel( int flags ) GetModel(), GetAbsOrigin(), GetAbsAngles(), - m_nSkin, - m_nBody, + GetSkin(), + GetBody(), m_nHitboxSet ); } return drawn; @@ -191,7 +183,7 @@ int C_LocalTempEntity::DrawStudioModel( int flags ) // Purpose: // Input : flags - //----------------------------------------------------------------------------- -int C_LocalTempEntity::DrawModel( int flags ) +int C_LocalTempEntity::DrawModel( int flags, const RenderableInstance_t &instance ) { int drawn = 0; @@ -200,20 +192,18 @@ int C_LocalTempEntity::DrawModel( int flags ) return drawn; } - if ( GetRenderMode() == kRenderNone ) - return drawn; - if ( this->flags & FTENT_BEOCCLUDED ) { + int nSlot = GET_ACTIVE_SPLITSCREEN_SLOT(); // Check normal - Vector vecDelta = (GetAbsOrigin() - MainViewOrigin()); + Vector vecDelta = (GetAbsOrigin() - MainViewOrigin(nSlot)); VectorNormalize( vecDelta ); float flDot = DotProduct( m_vecNormal, vecDelta ); if ( flDot > 0 ) { float flAlpha = RemapVal( MIN(flDot,0.3), 0, 0.3, 0, 1 ); flAlpha = MAX( 1.0, tempent_renderamt - (tempent_renderamt * flAlpha) ); - SetRenderColorA( flAlpha ); + SetRenderAlpha( flAlpha ); } } @@ -226,14 +216,14 @@ int C_LocalTempEntity::DrawModel( int flags ) GetAbsOrigin(), GetAbsAngles(), m_flFrame, // sprite frame to render - m_nBody > 0 ? cl_entitylist->GetBaseEntity( m_nBody ) : NULL, // attach to - m_nSkin, // attachment point + GetBody() > 0 ? cl_entitylist->GetBaseEntity( GetBody() ) : NULL, // attach to + GetSkin(), // attachment point GetRenderMode(), // rendermode - m_nRenderFX, // renderfx - m_clrRender->a, // alpha - m_clrRender->r, - m_clrRender->g, - m_clrRender->b, + GetRenderFX(), // renderfx + GetRenderAlpha(), // alpha + GetRenderColorR(), + GetRenderColorG(), + GetRenderColorB(), m_flSpriteScale // sprite scale ); break; @@ -275,7 +265,7 @@ bool C_LocalTempEntity::IsActive( void ) alpha = 0; } - SetRenderColorA( alpha ); + SetRenderAlpha( alpha ); } else { @@ -295,7 +285,7 @@ bool C_LocalTempEntity::IsActive( void ) bool C_LocalTempEntity::Frame( float frametime, int framenumber ) { float fastFreq = gpGlobals->curtime * 5.5; - float gravity = -frametime * GetCurrentGravity(); + float gravity = -frametime * sv_gravity.GetFloat(); float gravitySlow = gravity * 0.5; float traceFraction = 1; @@ -381,7 +371,7 @@ bool C_LocalTempEntity::Frame( float frametime, int framenumber ) } } - if ( flags & (FTENT_COLLIDEALL | FTENT_COLLIDEWORLD | FTENT_COLLIDEPROPS ) ) + if ( flags & (FTENT_COLLIDEALL | FTENT_COLLIDEWORLD) ) { Vector traceNormal; traceNormal.Init(); @@ -389,7 +379,7 @@ bool C_LocalTempEntity::Frame( float frametime, int framenumber ) trace_t trace; - if ( flags & (FTENT_COLLIDEALL | FTENT_COLLIDEPROPS) ) + if ( flags & FTENT_COLLIDEALL ) { Vector vPrevOrigin = m_vecPrevLocalOrigin; @@ -422,14 +412,6 @@ bool C_LocalTempEntity::Frame( float frametime, int framenumber ) UTIL_TraceLine( vPrevOrigin, GetLocalOrigin(), MASK_SOLID, GetOwnerEntity(), collisionGroup, &trace ); - if ( (flags & FTENT_COLLIDEPROPS) && trace.m_pEnt ) - { - bool bIsDynamicProp = ( NULL != dynamic_cast( trace.m_pEnt ) ); - bool bIsDoor = ( NULL != dynamic_cast( trace.m_pEnt ) ); - if ( !bIsDynamicProp && !bIsDoor && !trace.m_pEnt->IsWorld() ) // Die on props, doors, and the world. - return true; - } - // Make sure it didn't bump into itself... (?!?) if ( (trace.fraction != 1) && @@ -479,7 +461,7 @@ bool C_LocalTempEntity::Frame( float frametime, int framenumber ) if ( flags & (FTENT_CHANGERENDERONCOLLIDE) ) { - m_RenderGroup = RENDER_GROUP_OTHER; + OnTranslucencyTypeChanged(); flags &= ~FTENT_CHANGERENDERONCOLLIDE; } @@ -627,25 +609,23 @@ bool C_LocalTempEntity::Frame( float frametime, int framenumber ) //----------------------------------------------------------------------------- // Purpose: Attach a particle effect to a temp entity. //----------------------------------------------------------------------------- -CNewParticleEffect* C_LocalTempEntity::AddParticleEffect( const char *pszParticleEffect ) +void C_LocalTempEntity::AddParticleEffect( const char *pszParticleEffect ) { // Do we have a valid particle effect. if ( !pszParticleEffect || ( pszParticleEffect[0] == '\0' ) ) - return NULL; + return; // Check to see that we don't already have a particle effect. if ( ( flags & FTENT_CLIENTSIDEPARTICLES ) != 0 ) - return NULL; + return; // Add the entity to the ClientEntityList and create the particle system. ClientEntityList().AddNonNetworkableEntity( this ); - CNewParticleEffect* pEffect = ParticleProp()->Create( pszParticleEffect, PATTACH_ABSORIGIN_FOLLOW ); + ParticleProp()->Create( pszParticleEffect, PATTACH_ABSORIGIN_FOLLOW ); // Set the particle flag on the temp entity and save the name of the particle effect. flags |= FTENT_CLIENTSIDEPARTICLES; SetParticleEffect( pszParticleEffect ); - - return pEffect; } //----------------------------------------------------------------------------- @@ -824,7 +804,7 @@ void CTempEnts::FizzEffect( C_BaseEntity *pent, int modelIndex, int density, int origin[0] = mins[0] + random->RandomInt(0,width-1); origin[1] = mins[1] + random->RandomInt(0,depth-1); origin[2] = mins[2]; - pTemp = TempEntAlloc( origin, model ); + pTemp = TempEntAlloc( origin, (model_t *)model ); if (!pTemp) return; @@ -840,7 +820,7 @@ void CTempEnts::FizzEffect( C_BaseEntity *pent, int modelIndex, int density, int // Set sprite scale pTemp->m_flSpriteScale = 1.0 / random->RandomFloat(2,5); pTemp->SetRenderMode( kRenderTransAlpha ); - pTemp->SetRenderColorA( 255 ); + pTemp->SetRenderAlpha( 255 ); } } @@ -875,7 +855,7 @@ void CTempEnts::Bubbles( const Vector &mins, const Vector &maxs, float height, i origin[0] = random->RandomInt( mins[0], maxs[0] ); origin[1] = random->RandomInt( mins[1], maxs[1] ); origin[2] = random->RandomInt( mins[2], maxs[2] ); - pTemp = TempEntAlloc( origin, model ); + pTemp = TempEntAlloc( origin, ( model_t * )model ); if (!pTemp) return; @@ -883,7 +863,7 @@ void CTempEnts::Bubbles( const Vector &mins, const Vector &maxs, float height, i pTemp->x = origin[0]; pTemp->y = origin[1]; - SinCos( random->RandomInt( -3, 3 ), &sine, &cosine ); + SinCos( random->RandomInt( -M_PI, M_PI ), &sine, &cosine ); float zspeed = random->RandomInt(80,140); pTemp->SetVelocity( Vector(speed * cosine, speed * sine, zspeed) ); @@ -894,7 +874,8 @@ void CTempEnts::Bubbles( const Vector &mins, const Vector &maxs, float height, i pTemp->m_flSpriteScale = 1.0 / random->RandomFloat(4,16); pTemp->SetRenderMode( kRenderTransAlpha ); - pTemp->SetRenderColor( 255, 255, 255, 192 ); + pTemp->SetRenderColor( 255, 255, 255 ); + pTemp->SetRenderAlpha( 192 ); } } @@ -928,7 +909,7 @@ void CTempEnts::BubbleTrail( const Vector &start, const Vector &end, float flWat { dist = random->RandomFloat( 0, 1.0 ); VectorLerp( start, end, dist, origin ); - pTemp = TempEntAlloc( origin, model ); + pTemp = TempEntAlloc( origin, ( model_t * )model ); if (!pTemp) return; @@ -936,7 +917,7 @@ void CTempEnts::BubbleTrail( const Vector &start, const Vector &end, float flWat pTemp->x = origin[0]; pTemp->y = origin[1]; - angle = random->RandomInt( -3, 3 ); + angle = random->RandomInt( -M_PI, M_PI ); float zspeed = random->RandomInt(80,140); pTemp->SetVelocity( Vector(speed * cos(angle), speed * sin(angle), zspeed) ); @@ -946,7 +927,8 @@ void CTempEnts::BubbleTrail( const Vector &start, const Vector &end, float flWat pTemp->m_flSpriteScale = 1.0 / random->RandomFloat(4,8); pTemp->SetRenderMode( kRenderTransAlpha ); - pTemp->SetRenderColor( 255, 255, 255, 192 ); + pTemp->SetRenderColor( 255, 255, 255 ); + pTemp->SetRenderAlpha( 192 ); } } @@ -970,8 +952,8 @@ int BreakModelDrawHelper( C_LocalTempEntity *entity, int flags ) sInfo.pModel = entity->GetModel(); sInfo.origin = entity->GetRenderOrigin(); sInfo.angles = entity->GetRenderAngles(); - sInfo.skin = entity->m_nSkin; - sInfo.body = entity->m_nBody; + sInfo.skin = entity->GetSkin(); + sInfo.body = entity->GetBody(); sInfo.hitboxset = entity->m_nHitboxSet; // This is the main change, look up a lighting origin from the helper singleton @@ -1038,7 +1020,7 @@ void CTempEnts::BreakModel( const Vector &pos, const QAngle &angles, const Vecto vecLocalSpot[2] = random->RandomFloat(-0.5,0.5) * size[2]; VectorTransform( vecLocalSpot, transform, vecSpot ); - pTemp = TempEntAlloc(vecSpot, pModel); + pTemp = TempEntAlloc(vecSpot, ( model_t * )pModel); if (!pTemp) return; @@ -1052,7 +1034,7 @@ void CTempEnts::BreakModel( const Vector &pos, const QAngle &angles, const Vecto } else if ( modelinfo->GetModelType( pModel ) == mod_studio ) { - pTemp->m_nBody = random->RandomInt(0,frameCount-1); + pTemp->SetBody( random->RandomInt(0,frameCount-1) ); } pTemp->flags |= FTENT_COLLIDEWORLD | FTENT_FADEOUT | FTENT_SLOWGRAVITY; @@ -1073,7 +1055,7 @@ void CTempEnts::BreakModel( const Vector &pos, const QAngle &angles, const Vecto if ((flags & BREAK_GLASS) || (flags & BREAK_TRANS)) { pTemp->SetRenderMode( kRenderTransTexture ); - pTemp->SetRenderColorA( 128 ); + pTemp->SetRenderAlpha( 128 ); pTemp->tempent_renderamt = 128; pTemp->bounceFactor = 0.3f; } @@ -1108,17 +1090,28 @@ void CTempEnts::PhysicsProp( int modelindex, int skin, const Vector& pos, const if ( !model ) { - DevMsg("CTempEnts::PhysicsProp: model index %i not found\n", modelindex ); + DevMsg("CTempEnts::PhysicsProp: model index %i not found\n", modelinfo ); return; } pEntity->SetModelName( modelinfo->GetModelName(model) ); - pEntity->m_nSkin = skin; + pEntity->SetSkin( skin ); pEntity->SetAbsOrigin( pos ); pEntity->SetAbsAngles( angles ); pEntity->SetPhysicsMode( PHYSICS_MULTIPLAYER_CLIENTSIDE ); pEntity->SetEffects( effects ); + if ( flags & 1 ) + { + pEntity->SetModelIndex( modelindex ); + pEntity->SetCollisionGroup( COLLISION_GROUP_PUSHAWAY ); + pEntity->SetAbsVelocity( vel ); + pEntity->Spawn(); + pEntity->SetHealth( 0 ); + pEntity->Break(); + return; + } + if ( !pEntity->Initialize() ) { pEntity->Release(); @@ -1138,10 +1131,10 @@ void CTempEnts::PhysicsProp( int modelindex, int skin, const Vector& pos, const return; } - if ( flags & 1 ) + if ( flags & 2 ) { - pEntity->SetHealth( 0 ); - pEntity->Break(); + int numBodygroups = pEntity->GetBodygroupCount( 0 ); + pEntity->SetBodygroup( 0, RandomInt( 0, numBodygroups - 1 ) ); } } @@ -1168,7 +1161,7 @@ C_LocalTempEntity *CTempEnts::ClientProjectile( const Vector& vecOrigin, const V return NULL; } - pTemp = TempEntAlloc( vecOrigin, model ); + pTemp = TempEntAlloc( vecOrigin, ( model_t * )model ); if (!pTemp) return NULL; @@ -1227,18 +1220,19 @@ C_LocalTempEntity *CTempEnts::TempSprite( const Vector &pos, const Vector &dir, frameCount = modelinfo->GetModelFrameCount( model ); - pTemp = TempEntAlloc( pos, model ); + pTemp = TempEntAlloc( pos, ( model_t * )model ); if (!pTemp) return NULL; pTemp->m_flFrameMax = frameCount - 1; pTemp->m_flFrameRate = 10; pTemp->SetRenderMode( (RenderMode_t)rendermode ); - pTemp->m_nRenderFX = renderfx; + pTemp->SetRenderFX( (RenderFx_t)renderfx ); pTemp->m_flSpriteScale = scale; pTemp->tempent_renderamt = a * 255; pTemp->m_vecNormal = normal; - pTemp->SetRenderColor( 255, 255, 255, a * 255 ); + pTemp->SetRenderColor( 255, 255, 255 ); + pTemp->SetRenderAlpha( a * 255 ); pTemp->flags |= flags; @@ -1293,14 +1287,15 @@ void CTempEnts::Sprite_Spray( const Vector &pos, const Vector &dir, int modelInd for ( i = 0; i < count; i++ ) { - pTemp = TempEntAlloc( pos, pModel ); + pTemp = TempEntAlloc( pos, ( model_t * )pModel ); if (!pTemp) return; pTemp->SetRenderMode( kRenderTransAlpha ); - pTemp->SetRenderColor( 255, 255, 255, 255 ); + pTemp->SetRenderColor( 255, 255, 255 ); + pTemp->SetRenderAlpha( 255 ); pTemp->tempent_renderamt = 255; - pTemp->m_nRenderFX = kRenderFxNoDissipation; + pTemp->SetRenderFX( kRenderFxNoDissipation ); //pTemp->scale = random->RandomFloat( 0.1, 0.25 ); pTemp->m_flSpriteScale = 0.5; pTemp->flags |= FTENT_FADEOUT | FTENT_SLOWGRAVITY; @@ -1361,7 +1356,7 @@ void CTempEnts::Sprite_Trail( const Vector &vecStart, const Vector &vecEnd, int VectorMA( vecStart, i / (nCount - 1.0), vecDelta, vecPos ); } - pTemp = TempEntAlloc( vecPos, pModel ); + pTemp = TempEntAlloc( vecPos, ( model_t * )pModel ); if (!pTemp) return; @@ -1376,7 +1371,7 @@ void CTempEnts::Sprite_Trail( const Vector &vecStart, const Vector &vecEnd, int pTemp->m_flSpriteScale = flSize; pTemp->SetRenderMode( kRenderGlow ); - pTemp->m_nRenderFX = kRenderFxNoDissipation; + pTemp->SetRenderFX( kRenderFxNoDissipation ); pTemp->tempent_renderamt = nRenderamt; pTemp->SetRenderColor( 255, 255, 255 ); @@ -1424,7 +1419,7 @@ void CTempEnts::AttachTentToPlayer( int client, int modelIndex, float zoffset, f VectorCopy( clientClass->GetAbsOrigin(), position ); position[ 2 ] += zoffset; - pTemp = TempEntAllocHigh( position, pModel ); + pTemp = TempEntAllocHigh( position, ( model_t * )pModel ); if (!pTemp) { Warning("No temp ent.\n"); @@ -1432,9 +1427,9 @@ void CTempEnts::AttachTentToPlayer( int client, int modelIndex, float zoffset, f } pTemp->SetRenderMode( kRenderNormal ); - pTemp->SetRenderColorA( 255 ); + pTemp->SetRenderAlpha( 255 ); pTemp->tempent_renderamt = 255; - pTemp->m_nRenderFX = kRenderFxNoDissipation; + pTemp->SetRenderFX( kRenderFxNoDissipation ); pTemp->clientIndex = client; pTemp->tentOffset[ 0 ] = 0; @@ -1500,13 +1495,13 @@ void CTempEnts::RicochetSprite( const Vector &pos, model_t *pmodel, float durati { C_LocalTempEntity *pTemp; - pTemp = TempEntAlloc( pos, pmodel ); + pTemp = TempEntAlloc( pos, ( model_t * )pmodel ); if (!pTemp) return; pTemp->SetRenderMode( kRenderGlow ); - pTemp->m_nRenderFX = kRenderFxNoDissipation; - pTemp->SetRenderColorA( 200 ); + pTemp->SetRenderFX( kRenderFxNoDissipation ); + pTemp->SetRenderAlpha( 200 ); pTemp->tempent_renderamt = 200; pTemp->m_flSpriteScale = scale; pTemp->flags = FTENT_FADEOUT; @@ -1539,18 +1534,18 @@ void CTempEnts::BloodSprite( const Vector &org, int r, int g, int b, int a, int { C_LocalTempEntity *pTemp; int frameCount = modelinfo->GetModelFrameCount( model ); - color32 impactcolor = { (uint8)r, (uint8)g, (uint8)b, (uint8)a }; //Large, single blood sprite is a high-priority tent - if ( ( pTemp = TempEntAllocHigh( org, model ) ) != NULL ) + if ( ( pTemp = TempEntAllocHigh( org, ( model_t * )model ) ) != NULL ) { pTemp->SetRenderMode( kRenderTransTexture ); - pTemp->m_nRenderFX = kRenderFxClampMinScale; + pTemp->SetRenderFX( kRenderFxNone ); pTemp->m_flSpriteScale = random->RandomFloat( size / 25, size / 35); pTemp->flags = FTENT_SPRANIMATE; - pTemp->m_clrRender = impactcolor; - pTemp->tempent_renderamt= pTemp->m_clrRender->a; + pTemp->SetRenderColor( r, g, b ); + pTemp->SetRenderAlpha( a ); + pTemp->tempent_renderamt= pTemp->GetRenderAlpha(); pTemp->SetVelocity( vec3_origin ); @@ -1591,7 +1586,7 @@ C_LocalTempEntity *CTempEnts::DefaultSprite( const Vector &pos, int spriteIndex, frameCount = modelinfo->GetModelFrameCount( pSprite ); - pTemp = TempEntAlloc( pos, pSprite ); + pTemp = TempEntAlloc( pos, ( model_t * )pSprite ); if (!pTemp) return NULL; @@ -1620,81 +1615,22 @@ void CTempEnts::Sprite_Smoke( C_LocalTempEntity *pTemp, float scale ) return; pTemp->SetRenderMode( kRenderTransAlpha ); - pTemp->m_nRenderFX = kRenderFxNone; + pTemp->SetRenderFX( kRenderFxNone ); pTemp->SetVelocity( Vector( 0, 0, 30 ) ); int iColor = random->RandomInt(20,35); - pTemp->SetRenderColor( iColor, - iColor, - iColor, - 255 ); + pTemp->SetRenderColor( iColor, iColor, iColor ); + pTemp->SetRenderAlpha( 255 ); pTemp->SetLocalOriginDim( Z_INDEX, pTemp->GetLocalOriginDim( Z_INDEX ) + 20 ); pTemp->m_flSpriteScale = scale; pTemp->flags = FTENT_WINDBLOWN; } -//----------------------------------------------------------------------------- -// Purpose: -// Input : pos1 - -// angles - -// type - -//----------------------------------------------------------------------------- -void CTempEnts::EjectBrass( const Vector &pos1, const QAngle &angles, const QAngle &gunAngles, int type ) -{ - if ( cl_ejectbrass.GetBool() == false ) - return; - - const model_t *pModel = m_pShells[type]; - - if ( pModel == NULL ) - return; - - C_LocalTempEntity *pTemp = TempEntAlloc( pos1, pModel ); - - if ( pTemp == NULL ) - return; - - //Keep track of shell type - if ( type == 2 ) - { - pTemp->hitSound = BOUNCE_SHOTSHELL; - } - else - { - pTemp->hitSound = BOUNCE_SHELL; - } - - pTemp->m_nBody = 0; - - pTemp->flags |= ( FTENT_COLLIDEWORLD | FTENT_FADEOUT | FTENT_GRAVITY | FTENT_ROTATE ); - - pTemp->m_vecTempEntAngVelocity[0] = random->RandomFloat(-1024,1024); - pTemp->m_vecTempEntAngVelocity[1] = random->RandomFloat(-1024,1024); - pTemp->m_vecTempEntAngVelocity[2] = random->RandomFloat(-1024,1024); - - //Face forward - pTemp->SetAbsAngles( gunAngles ); - - pTemp->SetRenderMode( kRenderNormal ); - pTemp->tempent_renderamt = 255; // Set this for fadeout - - Vector dir; - - AngleVectors( angles, &dir ); - - dir *= random->RandomFloat( 150.0f, 200.0f ); - - pTemp->SetVelocity( Vector(dir[0] + random->RandomFloat(-64,64), - dir[1] + random->RandomFloat(-64,64), - dir[2] + random->RandomFloat( 0,64) ) ); - - pTemp->die = gpGlobals->curtime + 1.0f + random->RandomFloat( 0.0f, 1.0f ); // Add an extra 0-1 secs of life -} //----------------------------------------------------------------------------- // Purpose: Create some simple physically simulated models //----------------------------------------------------------------------------- -C_LocalTempEntity * CTempEnts::SpawnTempModel( const model_t *pModel, const Vector &vecOrigin, const QAngle &vecAngles, const Vector &vecVelocity, float flLifeTime, int iFlags ) +C_LocalTempEntity * CTempEnts::SpawnTempModel( model_t *pModel, const Vector &vecOrigin, const QAngle &vecAngles, const Vector &vecVelocity, float flLifeTime, int iFlags ) { Assert( pModel ); @@ -1704,7 +1640,7 @@ C_LocalTempEntity * CTempEnts::SpawnTempModel( const model_t *pModel, const Vect return NULL; pTemp->SetAbsAngles( vecAngles ); - pTemp->m_nBody = 0; + pTemp->SetBody( 0 ); pTemp->flags |= iFlags; pTemp->m_vecTempEntAngVelocity[0] = random->RandomFloat(-255,255); pTemp->m_vecTempEntAngVelocity[1] = random->RandomFloat(-255,255); @@ -1803,12 +1739,6 @@ void CTempEnts::MuzzleFlash( int type, ClientEntityHandle_t hEntity, int attachm //----------------------------------------------------------------------------- void CTempEnts::MuzzleFlash( const Vector& pos1, const QAngle& angles, int type, ClientEntityHandle_t hEntity, bool firstPerson ) { -#ifdef CSTRIKE_DLL - - return; - -#else - //NOTENOTE: This function is becoming obsolete as the muzzles are moved over to being local to attachments switch ( type ) @@ -1868,12 +1798,9 @@ void CTempEnts::MuzzleFlash( const Vector& pos1, const QAngle& angles, int type, default: // There's no supported muzzle flash for the type specified! - Assert(0); + Warning( "Attempted to use an unsupported muzzle flash type.. new particle effect needed here!\n" ); break; } - -#endif - } //----------------------------------------------------------------------------- @@ -1891,19 +1818,19 @@ void CTempEnts::Sprite_Explode( C_LocalTempEntity *pTemp, float scale, int flags { // solid sprite pTemp->SetRenderMode( kRenderNormal ); - pTemp->SetRenderColorA( 255 ); + pTemp->SetRenderAlpha( 255 ); } else if( flags & TE_EXPLFLAG_DRAWALPHA ) { // alpha sprite pTemp->SetRenderMode( kRenderTransAlpha ); - pTemp->SetRenderColorA( 180 ); + pTemp->SetRenderAlpha( 180 ); } else { // additive sprite pTemp->SetRenderMode( kRenderTransAdd ); - pTemp->SetRenderColorA( 180 ); + pTemp->SetRenderAlpha( 180 ); } if ( flags & TE_EXPLFLAG_ROTATE ) @@ -1911,7 +1838,7 @@ void CTempEnts::Sprite_Explode( C_LocalTempEntity *pTemp, float scale, int flags pTemp->SetLocalAnglesDim( Z_INDEX, random->RandomInt( 0, 360 ) ); } - pTemp->m_nRenderFX = kRenderFxNone; + pTemp->SetRenderFX( kRenderFxNone ); pTemp->SetVelocity( Vector( 0, 0, 8 ) ); pTemp->SetRenderColor( 255, 255, 255 ); pTemp->SetLocalOriginDim( Z_INDEX, pTemp->GetLocalOriginDim( Z_INDEX ) + 10 ); @@ -1942,28 +1869,13 @@ void CTempEnts::Clear( void ) g_BreakableHelper.Clear(); } -C_LocalTempEntity *CTempEnts::FindTempEntByID( int nID, int nSubID ) -{ - // HACK HACK: We're using skin and hitsounds as a hacky way to store an ID and sub-ID for later identification - FOR_EACH_LL( m_TempEnts, i ) - { - C_LocalTempEntity *p = m_TempEnts[ i ]; - if ( p && p->m_nSkin == nID && p->hitSound == nSubID ) - { - return p; - } - } - - return NULL; -} - //----------------------------------------------------------------------------- // Purpose: Allocate temp entity ( normal/low priority ) // Input : *org - // *model - // Output : C_LocalTempEntity //----------------------------------------------------------------------------- -C_LocalTempEntity *CTempEnts::TempEntAlloc( const Vector& org, const model_t *model ) +C_LocalTempEntity *CTempEnts::TempEntAlloc( const Vector& org, model_t *model ) { C_LocalTempEntity *pTemp; @@ -1974,7 +1886,6 @@ C_LocalTempEntity *CTempEnts::TempEntAlloc( const Vector& org, const model_t *mo } pTemp = TempEntAlloc(); - if ( !pTemp ) { DevWarning( 1, "Overflow %d temporary ents!\n", MAX_TEMP_ENTITIES ); @@ -1988,8 +1899,7 @@ C_LocalTempEntity *CTempEnts::TempEntAlloc( const Vector& org, const model_t *mo pTemp->priority = TENTPRIORITY_LOW; pTemp->SetAbsOrigin( org ); - pTemp->m_RenderGroup = RENDER_GROUP_OTHER; - pTemp->AddToLeafSystem( pTemp->m_RenderGroup ); + pTemp->AddToLeafSystem( false ); if ( CommandLine()->CheckParm( "-tools" ) != NULL ) { @@ -2016,6 +1926,7 @@ C_LocalTempEntity *CTempEnts::TempEntAlloc() if ( m_TempEnts.Count() >= MAX_TEMP_ENTITIES ) return NULL; + MEM_ALLOC_CREDIT(); C_LocalTempEntity *pTemp = m_TempEntsPool.AllocZero(); return pTemp; } @@ -2077,7 +1988,7 @@ bool CTempEnts::FreeLowPriorityTempEnt() // *model - // Output : C_LocalTempEntity //----------------------------------------------------------------------------- -C_LocalTempEntity *CTempEnts::TempEntAllocHigh( const Vector& org, const model_t *model ) +C_LocalTempEntity *CTempEnts::TempEntAllocHigh( const Vector& org, model_t *model ) { C_LocalTempEntity *pTemp; @@ -2113,8 +2024,7 @@ C_LocalTempEntity *CTempEnts::TempEntAllocHigh( const Vector& org, const model_t pTemp->priority = TENTPRIORITY_HIGH; pTemp->SetLocalOrigin( org ); - pTemp->m_RenderGroup = RENDER_GROUP_OTHER; - pTemp->AddToLeafSystem( pTemp->m_RenderGroup ); + pTemp->AddToLeafSystem( false ); if ( CommandLine()->CheckParm( "-tools" ) != NULL ) { @@ -2190,27 +2100,6 @@ void CTempEnts::PlaySound ( C_LocalTempEntity *pTemp, float damp ) soundname = "Bounce.Concrete"; } break; - -#ifdef CSTRIKE_DLL - - case TE_PISTOL_SHELL: - { - soundname = "Bounce.PistolShell"; - } - break; - - case TE_RIFLE_SHELL: - { - soundname = "Bounce.RifleShell"; - } - break; - - case TE_SHOTGUN_SHELL: - { - soundname = "Bounce.ShotgunShell"; - } - break; -#endif } zvel = abs( pTemp->GetVelocity()[2] ); @@ -2241,11 +2130,11 @@ void CTempEnts::PlaySound ( C_LocalTempEntity *pTemp, float damp ) if ( isshellcasing ) { - fvol *= MIN (1.0, ((float)zvel) / 350.0); + fvol *= MIN(1.0, ((float)zvel) / 350.0); } else { - fvol *= MIN (1.0, ((float)zvel) / 450.0); + fvol *= MIN(1.0, ((float)zvel) / 450.0); } if ( !random->RandomInt(0,3) && !isshellcasing ) @@ -2303,15 +2192,7 @@ int CTempEnts::AddVisibleTempEntity( C_LocalTempEntity *pEntity ) pEntity->index = -1; // Add to list - if( pEntity->m_RenderGroup == RENDER_GROUP_OTHER ) - { - pEntity->AddToLeafSystem(); - } - else - { - pEntity->AddToLeafSystem( pEntity->m_RenderGroup ); - } - + pEntity->AddToLeafSystem( false ); return 1; } return 0; @@ -2389,7 +2270,6 @@ void CTempEnts::Update(void) // Recache tempents which might have been flushed void CTempEnts::LevelInit() { -#ifndef TF_CLIENT_DLL m_pSpriteMuzzleFlash[0] = (model_t *)engine->LoadModel( "sprites/ar2_muzzle1.vmt" ); m_pSpriteMuzzleFlash[1] = (model_t *)engine->LoadModel( "sprites/muzzleflash4.vmt" ); m_pSpriteMuzzleFlash[2] = (model_t *)engine->LoadModel( "sprites/muzzleflash4.vmt" ); @@ -2405,14 +2285,8 @@ void CTempEnts::LevelInit() m_pShells[0] = (model_t *) engine->LoadModel( "models/weapons/shell.mdl" ); m_pShells[1] = (model_t *) engine->LoadModel( "models/weapons/rifleshell.mdl" ); m_pShells[2] = (model_t *) engine->LoadModel( "models/weapons/shotgun_shell.mdl" ); -#endif -#if defined( HL1_CLIENT_DLL ) - m_pHL1Shell = (model_t *)engine->LoadModel( "models/shell.mdl" ); - m_pHL1ShotgunShell = (model_t *)engine->LoadModel( "models/shotgunshell.mdl" ); -#endif - -#if defined( CSTRIKE_DLL ) || defined ( SDK_DLL ) +#if defined ( SDK_DLL ) m_pCS_9MMShell = (model_t *)engine->LoadModel( "models/Shells/shell_9mm.mdl" ); m_pCS_57Shell = (model_t *)engine->LoadModel( "models/Shells/shell_57.mdl" ); m_pCS_12GaugeShell = (model_t *)engine->LoadModel( "models/Shells/shell_12gauge.mdl" ); @@ -2444,12 +2318,7 @@ void CTempEnts::Init (void) m_pShells[1] = NULL; m_pShells[2] = NULL; -#if defined( HL1_CLIENT_DLL ) - m_pHL1Shell = NULL; - m_pHL1ShotgunShell = NULL; -#endif - -#if defined( CSTRIKE_DLL ) || defined ( SDK_DLL ) +#if defined ( SDK_DLL ) m_pCS_9MMShell = NULL; m_pCS_57Shell = NULL; m_pCS_12GaugeShell = NULL; @@ -2598,13 +2467,6 @@ void CTempEnts::MuzzleFlash_Combine_Player( ClientEntityHandle_t hEntity, int at void CTempEnts::MuzzleFlash_Combine_NPC( ClientEntityHandle_t hEntity, int attachmentIndex ) { VPROF_BUDGET( "MuzzleFlash_Combine_NPC", VPROF_BUDGETGROUP_PARTICLE_RENDERING ); - - // If the material isn't available, let's not do anything. - if ( g_Mat_Combine_Muzzleflash[0] == NULL ) - { - return; - } - CSmartPtr pSimple = CLocalSpaceEmitter::Create( "MuzzleFlash_Combine_NPC", hEntity, attachmentIndex ); SimpleParticle *pParticle; @@ -2932,12 +2794,6 @@ void CTempEnts::MuzzleFlash_Shotgun_NPC( ClientEntityHandle_t hEntity, int attac //Draw the cloud of fire FX_MuzzleEffectAttached( 0.75f, hEntity, attachmentIndex ); - // If the material isn't available, let's not do anything else. - if ( g_Mat_SMG_Muzzleflash[0] == NULL ) - { - return; - } - QAngle angles; Vector forward; @@ -3253,13 +3109,13 @@ void CTempEnts::RocketFlare( const Vector& pos ) nframeCount = modelinfo->GetModelFrameCount( model ); - pTemp = TempEntAlloc( pos, model ); + pTemp = TempEntAlloc( pos, (model_t *)model ); if ( !pTemp ) return; pTemp->m_flFrameMax = nframeCount - 1; pTemp->SetRenderMode( kRenderGlow ); - pTemp->m_nRenderFX = kRenderFxNoDissipation; + pTemp->SetRenderFX( kRenderFxNoDissipation ); pTemp->tempent_renderamt = 255; pTemp->m_flFrameRate = 1.0; pTemp->m_flFrame = random->RandomInt( 0, nframeCount - 1); @@ -3269,171 +3125,3 @@ void CTempEnts::RocketFlare( const Vector& pos ) } -void CTempEnts::HL1EjectBrass( const Vector &vecPosition, const QAngle &angAngles, const Vector &vecVelocity, int nType ) -{ - const model_t *pModel = NULL; - -#if defined( HL1_CLIENT_DLL ) - switch ( nType ) - { - case 0: - default: - pModel = m_pHL1Shell; - break; - case 1: - pModel = m_pHL1ShotgunShell; - break; - } -#endif - if ( pModel == NULL ) - return; - - C_LocalTempEntity *pTemp = TempEntAlloc( vecPosition, pModel ); - - if ( pTemp == NULL ) - return; - - switch ( nType ) - { - case 0: - default: - pTemp->hitSound = BOUNCE_SHELL; - break; - case 1: - pTemp->hitSound = BOUNCE_SHOTSHELL; - break; - } - - pTemp->m_nBody = 0; - pTemp->flags |= ( FTENT_COLLIDEWORLD | FTENT_FADEOUT | FTENT_GRAVITY | FTENT_ROTATE ); - - pTemp->m_vecTempEntAngVelocity[0] = random->RandomFloat( -512,511 ); - pTemp->m_vecTempEntAngVelocity[1] = random->RandomFloat( -256,255 ); - pTemp->m_vecTempEntAngVelocity[2] = random->RandomFloat( -256,255 ); - - //Face forward - pTemp->SetAbsAngles( angAngles ); - - pTemp->SetRenderMode( kRenderNormal ); - pTemp->tempent_renderamt = 255; // Set this for fadeout - - pTemp->SetVelocity( vecVelocity ); - - pTemp->die = gpGlobals->curtime + 2.5; -} - -#define SHELLTYPE_PISTOL 0 -#define SHELLTYPE_RIFLE 1 -#define SHELLTYPE_SHOTGUN 2 - - -void CTempEnts::CSEjectBrass( const Vector &vecPosition, const QAngle &angVelocity, int nVelocity, int shellType, CBasePlayer *pShooter ) -{ - const model_t *pModel = NULL; - int hitsound = TE_BOUNCE_SHELL; - -#if defined ( CSTRIKE_DLL ) || defined ( SDK_DLL ) - - switch( shellType ) - { - default: - case CS_SHELL_9MM: - hitsound = TE_PISTOL_SHELL; - pModel = m_pCS_9MMShell; - break; - case CS_SHELL_57: - hitsound = TE_PISTOL_SHELL; - pModel = m_pCS_57Shell; - break; - case CS_SHELL_12GAUGE: - hitsound = TE_SHOTGUN_SHELL; - pModel = m_pCS_12GaugeShell; - break; - case CS_SHELL_556: - hitsound = TE_RIFLE_SHELL; - pModel = m_pCS_556Shell; - break; - case CS_SHELL_762NATO: - hitsound = TE_RIFLE_SHELL; - pModel = m_pCS_762NATOShell; - break; - case CS_SHELL_338MAG: - hitsound = TE_RIFLE_SHELL; - pModel = m_pCS_338MAGShell; - break; - } -#endif - - if ( pModel == NULL ) - return; - - Vector forward, right, up; - Vector velocity; - Vector origin; - QAngle angle; - - // Add some randomness to the velocity - - AngleVectors( angVelocity, &forward, &right, &up ); - - velocity = forward * nVelocity * random->RandomFloat( 1.2, 2.8 ) + - up * random->RandomFloat( -10, 10 ) + - right * random->RandomFloat( -20, 20 ); - - if( pShooter ) - velocity += pShooter->GetAbsVelocity(); - - C_LocalTempEntity *pTemp = TempEntAlloc( vecPosition, pModel ); - if ( !pTemp ) - return; - - if( pShooter ) - pTemp->SetAbsAngles( pShooter->EyeAngles() ); - else - pTemp->SetAbsAngles( vec3_angle ); - - pTemp->SetVelocity( velocity ); - - pTemp->hitSound = hitsound; - - pTemp->SetGravity( 0.4 ); - - pTemp->m_nBody = 0; - pTemp->flags = FTENT_FADEOUT | FTENT_GRAVITY | FTENT_COLLIDEALL | FTENT_HITSOUND | FTENT_ROTATE | FTENT_CHANGERENDERONCOLLIDE; - - pTemp->m_vecTempEntAngVelocity[0] = random->RandomFloat(-256,256); - pTemp->m_vecTempEntAngVelocity[1] = random->RandomFloat(-256,256); - pTemp->m_vecTempEntAngVelocity[2] = 0; - pTemp->SetRenderMode( kRenderNormal ); - pTemp->tempent_renderamt = 255; - - pTemp->die = gpGlobals->curtime + 10; - - bool bViewModelBrass = false; - - if ( pShooter && pShooter->GetObserverMode() == OBS_MODE_IN_EYE ) - { - // we are spectating the shooter in first person view - pShooter = ToBasePlayer( pShooter->GetObserverTarget() ); - bViewModelBrass = true; - } - - if ( pShooter ) - { - pTemp->clientIndex = pShooter->entindex(); - bViewModelBrass |= pShooter->IsLocalPlayer(); - } - else - { - pTemp->clientIndex = 0; - } - - if ( bViewModelBrass ) - { - // for viewmodel brass put it in the viewmodel renderer group - pTemp->m_RenderGroup = RENDER_GROUP_VIEW_MODEL_OPAQUE; - } - - -} - diff --git a/game/client/c_te_legacytempents.h b/game/client/c_te_legacytempents.h index 038eeccd3..758a405b9 100644 --- a/game/client/c_te_legacytempents.h +++ b/game/client/c_te_legacytempents.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // @@ -17,9 +17,9 @@ class C_LocalTempEntity; struct model_t; #include "mempool.h" -#include "utllinkedlist.h" +#include "UtlLinkedList.h" -#if defined( CSTRIKE_DLL ) || defined( SDK_DLL ) +#if defined( SDK_DLL ) enum { CS_SHELL_9MM = 0, @@ -27,7 +27,7 @@ enum CS_SHELL_12GAUGE, CS_SHELL_556, CS_SHELL_762NATO, - CS_SHELL_338MAG + CS_SHELL_338MAG, }; #endif @@ -47,14 +47,11 @@ abstract_class ITempEnts virtual void Update( void ) = 0; virtual void Clear( void ) = 0; - virtual C_LocalTempEntity *FindTempEntByID( int nID, int nSubID ) = 0; - virtual void BloodSprite( const Vector &org, int r, int g, int b, int a, int modelIndex, int modelIndex2, float size ) = 0; virtual void RicochetSprite( const Vector &pos, model_t *pmodel, float duration, float scale ) = 0; virtual void MuzzleFlash( int type, ClientEntityHandle_t hEntity, int attachmentIndex, bool firstPerson ) = 0; virtual void MuzzleFlash( const Vector &pos1, const QAngle &angles, int type, ClientEntityHandle_t hEntity, bool firstPerson ) = 0; - virtual void EjectBrass( const Vector& pos1, const QAngle& angles, const QAngle& gunAngles, int type ) = 0; - virtual C_LocalTempEntity *SpawnTempModel( const model_t *pModel, const Vector &vecOrigin, const QAngle &vecAngles, const Vector &vecVelocity, float flLifeTime, int iFlags ) = 0; + virtual C_LocalTempEntity *SpawnTempModel( model_t *pModel, const Vector &vecOrigin, const QAngle &vecAngles, const Vector &vecVelocity, float flLifeTime, int iFlags ) = 0; virtual void BreakModel( const Vector &pos, const QAngle &angles, const Vector &size, const Vector &dir, float random, float life, int count, int modelIndex, char flags) = 0; virtual void Bubbles( const Vector &mins, const Vector &maxs, float height, int modelIndex, int count, float speed ) = 0; virtual void BubbleTrail( const Vector &start, const Vector &end, float flWaterZ, int modelIndex, int count, float speed ) = 0; @@ -67,10 +64,7 @@ abstract_class ITempEnts virtual void KillAttachedTents( int client ) = 0; virtual void Sprite_Spray( const Vector &pos, const Vector &dir, int modelIndex, int count, int speed, int iRand ) = 0; virtual void Sprite_Trail( const Vector &vecStart, const Vector &vecEnd, int modelIndex, int nCount, float flLife, float flSize, float flAmplitude, int nRenderamt, float flSpeed ) = 0; - virtual void RocketFlare( const Vector& pos ) = 0; - virtual void HL1EjectBrass( const Vector &vecPosition, const QAngle &angAngles, const Vector &vecVelocity, int nType ) = 0; - virtual void CSEjectBrass( const Vector &vecPosition, const QAngle &angVelocity, int nType, int nShellType, CBasePlayer *pShooter ) = 0; - + virtual void RocketFlare( const Vector& pos ) = 0; virtual void PlaySound ( C_LocalTempEntity *pTemp, float damp ) = 0; virtual void PhysicsProp( int modelindex, int skin, const Vector& pos, const QAngle &angles, const Vector& vel, int flags, int effects = 0 ) = 0; virtual C_LocalTempEntity *ClientProjectile( const Vector& vecOrigin, const Vector& vecVelocity, const Vector& vecAccel, int modelindex, int lifetime, CBaseEntity *pOwner, const char *pszImpactEffect = NULL, const char *pszParticleEffect = NULL ) = 0; @@ -98,8 +92,6 @@ class CTempEnts : public ITempEnts virtual void Update( void ); virtual void Clear( void ); - virtual C_LocalTempEntity *FindTempEntByID( int nID, int nSubID ); - // Legacy temp entities still supported virtual void BloodSprite( const Vector &org, int r, int g, int b, int a, int modelIndex, int modelIndex2, float size ); virtual void RicochetSprite( const Vector &pos, model_t *pmodel, float duration, float scale ); @@ -121,16 +113,13 @@ class CTempEnts : public ITempEnts void Sprite_Trail( const Vector &vecStart, const Vector &vecEnd, int modelIndex, int nCount, float flLife, float flSize, float flAmplitude, int nRenderamt, float flSpeed ); virtual void PlaySound ( C_LocalTempEntity *pTemp, float damp ); - virtual void EjectBrass( const Vector &pos1, const QAngle &angles, const QAngle &gunAngles, int type ); - virtual C_LocalTempEntity *SpawnTempModel( const model_t *pModel, const Vector &vecOrigin, const QAngle &vecAngles, const Vector &vecVelocity, float flLifeTime, int iFlags ); + virtual C_LocalTempEntity *SpawnTempModel( model_t *pModel, const Vector &vecOrigin, const QAngle &vecAngles, const Vector &vecVelocity, float flLifeTime, int iFlags ); void RocketFlare( const Vector& pos ); - void HL1EjectBrass( const Vector &vecPosition, const QAngle &angAngles, const Vector &vecVelocity, int nType ); - void CSEjectBrass( const Vector &vecPosition, const QAngle &angAngles, int nType, int nShellType, CBasePlayer *pShooter ); void PhysicsProp( int modelindex, int skin, const Vector& pos, const QAngle &angles, const Vector& vel, int flags, int effects = 0 ); C_LocalTempEntity *ClientProjectile( const Vector& vecOrigin, const Vector& vecVelocity, const Vector& vecAcceleration, int modelindex, int lifetime, CBaseEntity *pOwner, const char *pszImpactEffect = NULL, const char *pszParticleEffect = NULL ); // Data -public: +private: enum { MAX_TEMP_ENTITIES = 500, @@ -138,7 +127,6 @@ class CTempEnts : public ITempEnts MAX_TEMP_ENTITY_STUDIOMODEL = 50, }; -private: // Global temp entity pool CClassMemoryPool< C_LocalTempEntity > m_TempEntsPool; CUtlLinkedList< C_LocalTempEntity *, unsigned short > m_TempEnts; @@ -149,12 +137,7 @@ class CTempEnts : public ITempEnts struct model_t *m_pShells[3]; struct model_t *m_pSpriteCombineFlash[2]; -#if defined( HL1_CLIENT_DLL ) - struct model_t *m_pHL1Shell; - struct model_t *m_pHL1ShotgunShell; -#endif - -#if defined( CSTRIKE_DLL ) || defined ( SDK_DLL ) +#if defined ( SDK_DLL ) struct model_t *m_pCS_9MMShell; struct model_t *m_pCS_57Shell; struct model_t *m_pCS_12GaugeShell; @@ -165,8 +148,8 @@ class CTempEnts : public ITempEnts // Internal methods also available to children protected: - C_LocalTempEntity *TempEntAlloc( const Vector& org, const model_t *model ); - C_LocalTempEntity *TempEntAllocHigh( const Vector& org, const model_t *model ); + C_LocalTempEntity *TempEntAlloc( const Vector& org, model_t *model ); + C_LocalTempEntity *TempEntAllocHigh( const Vector& org, model_t *model ); // Material handle caches private: diff --git a/game/client/c_te_muzzleflash.cpp b/game/client/c_te_muzzleflash.cpp index 529aa7816..be67f06a3 100644 --- a/game/client/c_te_muzzleflash.cpp +++ b/game/client/c_te_muzzleflash.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: Muzzle flash temp ent // @@ -7,7 +7,7 @@ #include "cbase.h" #include "c_basetempentity.h" #include "IEffects.h" -#include "tier1/KeyValues.h" +#include "tier1/keyvalues.h" #include "toolframework_client.h" #include "tier0/vprof.h" diff --git a/game/client/c_te_particlesystem.cpp b/game/client/c_te_particlesystem.cpp index b89b7b416..6c6304ac2 100644 --- a/game/client/c_te_particlesystem.cpp +++ b/game/client/c_te_particlesystem.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // @@ -169,7 +169,7 @@ void CTEParticleRenderer::SimulateParticles( CParticleSimulateIterator *pIterato float time1 = 5.0 * ft; float dvel = 4* ft ; - float grav = ft * GetCurrentGravity() * 0.05f; + float grav = ft * sv_gravity.GetFloat() * 0.05f; int (*colorIndex)[3]; int iRamp; diff --git a/game/client/c_te_particlesystem.h b/game/client/c_te_particlesystem.h index 7bd7b4ba4..e1e8c0ea9 100644 --- a/game/client/c_te_particlesystem.h +++ b/game/client/c_te_particlesystem.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // diff --git a/game/client/c_te_physicsprop.cpp b/game/client/c_te_physicsprop.cpp index 8505171b3..9c018e50d 100644 --- a/game/client/c_te_physicsprop.cpp +++ b/game/client/c_te_physicsprop.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // @@ -9,7 +9,7 @@ #include "cbase.h" #include "c_basetempentity.h" #include "c_te_legacytempents.h" -#include "tier1/KeyValues.h" +#include "tier1/keyvalues.h" #include "toolframework_client.h" #include "tier0/vprof.h" @@ -84,7 +84,7 @@ C_TEPhysicsProp::~C_TEPhysicsProp( void ) // Recording //----------------------------------------------------------------------------- static inline void RecordPhysicsProp( const Vector& start, const QAngle &angles, - const Vector& vel, int nModelIndex, bool bBreakModel, int nSkin, int nEffects ) + const Vector& vel, int nModelIndex, int flags, int nSkin, int nEffects ) { if ( !ToolsEnabled() ) return; @@ -109,7 +109,7 @@ static inline void RecordPhysicsProp( const Vector& start, const QAngle &angles, msg->SetFloat( "vely", vel.y ); msg->SetFloat( "velz", vel.z ); msg->SetString( "model", pModelName ); - msg->SetInt( "breakmodel", bBreakModel ); + msg->SetInt( "breakmodel", flags ); msg->SetInt( "skin", nSkin ); msg->SetInt( "effects", nEffects ); @@ -123,10 +123,10 @@ static inline void RecordPhysicsProp( const Vector& start, const QAngle &angles, // Purpose: //----------------------------------------------------------------------------- void TE_PhysicsProp( IRecipientFilter& filter, float delay, - int modelindex, int skin, const Vector& pos, const QAngle &angles, const Vector& vel, bool breakmodel, int effects ) + int modelindex, int skin, const Vector& pos, const QAngle &angles, const Vector& vel, int flags, int effects ) { - tempents->PhysicsProp( modelindex, skin, pos, angles, vel, breakmodel, effects ); - RecordPhysicsProp( pos, angles, vel, modelindex, breakmodel, skin, effects ); + tempents->PhysicsProp( modelindex, skin, pos, angles, vel, flags, effects ); + RecordPhysicsProp( pos, angles, vel, modelindex, flags, skin, effects ); } //----------------------------------------------------------------------------- @@ -157,9 +157,9 @@ void TE_PhysicsProp( IRecipientFilter& filter, float delay, KeyValues *pKeyValue vecVel.z = pKeyValues->GetFloat( "velz" ); const char *pModelName = pKeyValues->GetString( "model" ); int nModelIndex = pModelName[0] ? modelinfo->GetModelIndex( pModelName ) : 0; - bool bBreakModel = pKeyValues->GetInt( "breakmodel" ) != 0; + int flags = pKeyValues->GetInt( "breakmodel" ); int nEffects = pKeyValues->GetInt( "effects" ); - TE_PhysicsProp( filter, delay, nModelIndex, nSkin, vecOrigin, angles, vecVel, bBreakModel, nEffects ); + TE_PhysicsProp( filter, delay, nModelIndex, nSkin, vecOrigin, angles, vecVel, flags, nEffects ); } diff --git a/game/client/c_te_playerdecal.cpp b/game/client/c_te_playerdecal.cpp index f8d503b66..ac02f6e68 100644 --- a/game/client/c_te_playerdecal.cpp +++ b/game/client/c_te_playerdecal.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // @@ -11,12 +11,12 @@ #include "iefx.h" #include "fx.h" #include "decals.h" -#include "materialsystem/imaterialsystem.h" +#include "materialsystem/IMaterialSystem.h" #include "filesystem.h" #include "materialsystem/imaterial.h" #include "materialsystem/itexture.h" #include "materialsystem/imaterialvar.h" -#include "clienteffectprecachesystem.h" +#include "precache_register.h" #include "tier0/vprof.h" // memdbgon must be the last include file in a .cpp file!!! @@ -25,84 +25,84 @@ static ConVar cl_playerspraydisable( "cl_playerspraydisable", "0", FCVAR_CLIENTDLL | FCVAR_ARCHIVE, "Disable player sprays." ); #ifndef _XBOX -CLIENTEFFECT_REGISTER_BEGIN( PrecachePlayerDecal ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo01" ) -#if !defined(HL2_DLL) || defined(HL2MP) -CLIENTEFFECT_MATERIAL( "decals/playerlogo02" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo03" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo04" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo05" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo06" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo07" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo08" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo09" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo10" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo11" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo12" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo13" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo14" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo15" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo16" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo17" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo18" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo19" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo20" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo21" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo22" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo23" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo24" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo25" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo26" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo27" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo28" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo29" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo30" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo31" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo32" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo33" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo34" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo35" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo36" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo37" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo38" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo39" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo40" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo41" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo42" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo43" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo44" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo45" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo46" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo47" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo48" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo49" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo40" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo41" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo42" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo43" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo44" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo45" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo46" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo47" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo48" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo49" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo50" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo51" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo52" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo53" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo54" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo55" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo56" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo57" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo58" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo59" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo60" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo61" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo62" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo63" ) -CLIENTEFFECT_MATERIAL( "decals/playerlogo64" ) +PRECACHE_REGISTER_BEGIN( GLOBAL, PrecachePlayerDecal ) +PRECACHE( MATERIAL, "decals/playerlogo01" ) +#if !defined(HL2_DLL) +PRECACHE( MATERIAL, "decals/playerlogo02" ) +PRECACHE( MATERIAL, "decals/playerlogo03" ) +PRECACHE( MATERIAL, "decals/playerlogo04" ) +PRECACHE( MATERIAL, "decals/playerlogo05" ) +PRECACHE( MATERIAL, "decals/playerlogo06" ) +PRECACHE( MATERIAL, "decals/playerlogo07" ) +PRECACHE( MATERIAL, "decals/playerlogo08" ) +PRECACHE( MATERIAL, "decals/playerlogo09" ) +PRECACHE( MATERIAL, "decals/playerlogo10" ) +PRECACHE( MATERIAL, "decals/playerlogo11" ) +PRECACHE( MATERIAL, "decals/playerlogo12" ) +PRECACHE( MATERIAL, "decals/playerlogo13" ) +PRECACHE( MATERIAL, "decals/playerlogo14" ) +PRECACHE( MATERIAL, "decals/playerlogo15" ) +PRECACHE( MATERIAL, "decals/playerlogo16" ) +PRECACHE( MATERIAL, "decals/playerlogo17" ) +PRECACHE( MATERIAL, "decals/playerlogo18" ) +PRECACHE( MATERIAL, "decals/playerlogo19" ) +PRECACHE( MATERIAL, "decals/playerlogo20" ) +PRECACHE( MATERIAL, "decals/playerlogo21" ) +PRECACHE( MATERIAL, "decals/playerlogo22" ) +PRECACHE( MATERIAL, "decals/playerlogo23" ) +PRECACHE( MATERIAL, "decals/playerlogo24" ) +PRECACHE( MATERIAL, "decals/playerlogo25" ) +PRECACHE( MATERIAL, "decals/playerlogo26" ) +PRECACHE( MATERIAL, "decals/playerlogo27" ) +PRECACHE( MATERIAL, "decals/playerlogo28" ) +PRECACHE( MATERIAL, "decals/playerlogo29" ) +PRECACHE( MATERIAL, "decals/playerlogo30" ) +PRECACHE( MATERIAL, "decals/playerlogo31" ) +PRECACHE( MATERIAL, "decals/playerlogo32" ) +PRECACHE( MATERIAL, "decals/playerlogo33" ) +PRECACHE( MATERIAL, "decals/playerlogo34" ) +PRECACHE( MATERIAL, "decals/playerlogo35" ) +PRECACHE( MATERIAL, "decals/playerlogo36" ) +PRECACHE( MATERIAL, "decals/playerlogo37" ) +PRECACHE( MATERIAL, "decals/playerlogo38" ) +PRECACHE( MATERIAL, "decals/playerlogo39" ) +PRECACHE( MATERIAL, "decals/playerlogo40" ) +PRECACHE( MATERIAL, "decals/playerlogo41" ) +PRECACHE( MATERIAL, "decals/playerlogo42" ) +PRECACHE( MATERIAL, "decals/playerlogo43" ) +PRECACHE( MATERIAL, "decals/playerlogo44" ) +PRECACHE( MATERIAL, "decals/playerlogo45" ) +PRECACHE( MATERIAL, "decals/playerlogo46" ) +PRECACHE( MATERIAL, "decals/playerlogo47" ) +PRECACHE( MATERIAL, "decals/playerlogo48" ) +PRECACHE( MATERIAL, "decals/playerlogo49" ) +PRECACHE( MATERIAL, "decals/playerlogo40" ) +PRECACHE( MATERIAL, "decals/playerlogo41" ) +PRECACHE( MATERIAL, "decals/playerlogo42" ) +PRECACHE( MATERIAL, "decals/playerlogo43" ) +PRECACHE( MATERIAL, "decals/playerlogo44" ) +PRECACHE( MATERIAL, "decals/playerlogo45" ) +PRECACHE( MATERIAL, "decals/playerlogo46" ) +PRECACHE( MATERIAL, "decals/playerlogo47" ) +PRECACHE( MATERIAL, "decals/playerlogo48" ) +PRECACHE( MATERIAL, "decals/playerlogo49" ) +PRECACHE( MATERIAL, "decals/playerlogo50" ) +PRECACHE( MATERIAL, "decals/playerlogo51" ) +PRECACHE( MATERIAL, "decals/playerlogo52" ) +PRECACHE( MATERIAL, "decals/playerlogo53" ) +PRECACHE( MATERIAL, "decals/playerlogo54" ) +PRECACHE( MATERIAL, "decals/playerlogo55" ) +PRECACHE( MATERIAL, "decals/playerlogo56" ) +PRECACHE( MATERIAL, "decals/playerlogo57" ) +PRECACHE( MATERIAL, "decals/playerlogo58" ) +PRECACHE( MATERIAL, "decals/playerlogo59" ) +PRECACHE( MATERIAL, "decals/playerlogo60" ) +PRECACHE( MATERIAL, "decals/playerlogo61" ) +PRECACHE( MATERIAL, "decals/playerlogo62" ) +PRECACHE( MATERIAL, "decals/playerlogo63" ) +PRECACHE( MATERIAL, "decals/playerlogo64" ) #endif -CLIENTEFFECT_REGISTER_END() +PRECACHE_REGISTER_END() #endif //----------------------------------------------------------------------------- @@ -151,45 +151,6 @@ void C_TEPlayerDecal::Precache( void ) { } -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -IMaterial *CreateTempMaterialForPlayerLogo( int iPlayerIndex, player_info_t *info, char *texname, int nchars ) -{ - // Doesn't have a logo? - if ( !info->customFiles[0] ) - return NULL; - - IMaterial *logo = materials->FindMaterial( VarArgs("decals/playerlogo%2.2d", iPlayerIndex), TEXTURE_GROUP_DECAL ); - if ( IsErrorMaterial( logo ) ) - return NULL; - - char logohex[ 16 ]; - Q_binarytohex( (byte *)&info->customFiles[0], sizeof( info->customFiles[0] ), logohex, sizeof( logohex ) ); - - // See if logo has been downloaded. - Q_snprintf( texname, nchars, "temp/%s", logohex ); - char fulltexname[ 512 ]; - Q_snprintf( fulltexname, sizeof( fulltexname ), "materials/temp/%s.vtf", logohex ); - - if ( !filesystem->FileExists( fulltexname ) ) - { - char custname[ 512 ]; - Q_snprintf( custname, sizeof( custname ), "download/user_custom/%c%c/%s.dat", logohex[0], logohex[1], logohex ); - // it may have been downloaded but not copied under materials folder - if ( !filesystem->FileExists( custname ) ) - return NULL; // not downloaded yet - - // copy from download folder to materials/temp folder - // this is done since material system can access only materials/*.vtf files - - if ( !engine->CopyLocalFile( custname, fulltexname) ) - return NULL; - } - - return logo; -} - //----------------------------------------------------------------------------- // Purpose: // Input : filter - @@ -213,12 +174,38 @@ void TE_PlayerDecal( IRecipientFilter& filter, float delay, player_info_t info; engine->GetPlayerInfo( player, &info ); - // Make sure we've got the material for this player's logo - char texname[ 512 ]; - IMaterial *logo = CreateTempMaterialForPlayerLogo( player, &info, texname, 512 ); - if ( !logo ) + // Doesn't have a logo + if ( !info.customFiles[0] ) + return; + + IMaterial *logo = materials->FindMaterial( VarArgs("decals/playerlogo%2.2d", player), TEXTURE_GROUP_DECAL ); + if ( IsErrorMaterial( logo ) ) return; + char logohex[ 16 ]; + Q_binarytohex( (byte *)&info.customFiles[0], sizeof( info.customFiles[0] ), logohex, sizeof( logohex ) ); + + // See if logo has been downloaded. + char texname[ 512 ]; + Q_snprintf( texname, sizeof( texname ), "temp/%s", logohex ); + char fulltexname[ 512 ]; + Q_snprintf( fulltexname, sizeof( fulltexname ), "materials/temp/%s.vtf", logohex ); + + if ( !filesystem->FileExists( fulltexname ) ) + { + char custname[ 512 ]; + Q_snprintf( custname, sizeof( custname ), "downloads/%s.dat", logohex ); + // it may have been downloaded but not copied under materials folder + if ( !filesystem->FileExists( custname ) ) + return; // not downloaded yet + + // copy from download folder to materials/temp folder + // this is done since material system can access only materials/*.vtf files + + if ( !engine->CopyFile( custname, fulltexname) ) + return; + } + ITexture *texture = materials->FindTexture( texname, TEXTURE_GROUP_DECAL ); if ( IsErrorTexture( texture ) ) { @@ -240,7 +227,7 @@ void TE_PlayerDecal( IRecipientFilter& filter, float delay, color32 rgbaColor = { 255, 255, 255, 255 }; effects->PlayerDecalShoot( logo, - (void *)(intp)player, + (void *)player, entity, ent->GetModel(), ent->GetAbsOrigin(), diff --git a/game/client/c_te_projecteddecal.cpp b/game/client/c_te_projecteddecal.cpp index ec8e4b7b2..60c6e8292 100644 --- a/game/client/c_te_projecteddecal.cpp +++ b/game/client/c_te_projecteddecal.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // @@ -10,7 +10,7 @@ #include "c_basetempentity.h" #include "iefx.h" #include "engine/IStaticPropMgr.h" -#include "tier1/KeyValues.h" +#include "tier1/keyvalues.h" #include "toolframework_client.h" #include "tier0/vprof.h" diff --git a/game/client/c_te_showline.cpp b/game/client/c_te_showline.cpp index 294d3cde0..ef23ae88e 100644 --- a/game/client/c_te_showline.cpp +++ b/game/client/c_te_showline.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // diff --git a/game/client/c_te_smoke.cpp b/game/client/c_te_smoke.cpp index 5d664cd6b..cc136c39e 100644 --- a/game/client/c_te_smoke.cpp +++ b/game/client/c_te_smoke.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // @@ -9,7 +9,7 @@ #include "cbase.h" #include "c_basetempentity.h" #include "IEffects.h" -#include "tier1/KeyValues.h" +#include "tier1/keyvalues.h" #include "toolframework_client.h" #include "tier0/vprof.h" diff --git a/game/client/c_te_sparks.cpp b/game/client/c_te_sparks.cpp index 7f1310a69..3da55601e 100644 --- a/game/client/c_te_sparks.cpp +++ b/game/client/c_te_sparks.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // @@ -7,7 +7,7 @@ #include "cbase.h" #include "c_te_particlesystem.h" #include "IEffects.h" -#include "tier1/KeyValues.h" +#include "tier1/keyvalues.h" #include "toolframework_client.h" // memdbgon must be the last include file in a .cpp file!!! diff --git a/game/client/c_te_sprite.cpp b/game/client/c_te_sprite.cpp index 36cf6b2e6..d61eba886 100644 --- a/game/client/c_te_sprite.cpp +++ b/game/client/c_te_sprite.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // @@ -10,7 +10,7 @@ #include "c_basetempentity.h" #include "c_te_legacytempents.h" #include "tempent.h" -#include "tier1/KeyValues.h" +#include "tier1/keyvalues.h" #include "toolframework_client.h" #include "tier0/vprof.h" diff --git a/game/client/c_te_spritespray.cpp b/game/client/c_te_spritespray.cpp index 149a812fd..500491688 100644 --- a/game/client/c_te_spritespray.cpp +++ b/game/client/c_te_spritespray.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // $NoKeywords: $ @@ -7,7 +7,7 @@ #include "cbase.h" #include "c_basetempentity.h" #include "c_te_legacytempents.h" -#include "tier1/KeyValues.h" +#include "tier1/keyvalues.h" #include "toolframework_client.h" #include "tier0/vprof.h" diff --git a/game/client/c_te_worlddecal.cpp b/game/client/c_te_worlddecal.cpp index b6bad25dc..5403853fa 100644 --- a/game/client/c_te_worlddecal.cpp +++ b/game/client/c_te_worlddecal.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // @@ -7,10 +7,9 @@ #include "cbase.h" #include "c_basetempentity.h" #include "iefx.h" -#include "tier1/KeyValues.h" +#include "tier1/keyvalues.h" #include "toolframework_client.h" #include "fx.h" -#include "decals.h" #include "tier0/vprof.h" // memdbgon must be the last include file in a .cpp file!!! @@ -107,22 +106,7 @@ void C_TEWorldDecal::PostDataUpdate( DataUpdateType_t updateType ) C_BaseEntity *ent = cl_entitylist->GetEnt( 0 ); if ( ent ) { - bool bNoBlood = UTIL_IsLowViolence(); - bool bIsBlood = false; - - if ( bNoBlood ) - { - const char *pchDecalName = decalsystem->GetDecalNameForIndex( m_nIndex ); - if ( pchDecalName && V_stristr( pchDecalName, "blood" ) ) - { - bIsBlood = true; - } - } - - if ( !( bNoBlood && bIsBlood ) ) - { - effects->DecalShoot( m_nIndex, 0, ent->GetModel(), ent->GetAbsOrigin(), ent->GetAbsAngles(), m_vecOrigin, 0, 0 ); - } + effects->DecalShoot( m_nIndex, 0, ent->GetModel(), ent->GetAbsOrigin(), ent->GetAbsAngles(), m_vecOrigin, 0, 0 ); } } RecordWorldDecal( &m_vecOrigin, m_nIndex ); diff --git a/game/client/c_team.cpp b/game/client/c_team.cpp index ba688cc7f..65395496b 100644 --- a/game/client/c_team.cpp +++ b/game/client/c_team.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: Client side CTeam class // @@ -24,7 +24,7 @@ void RecvProxyArrayLength_PlayerArray( void *pStruct, int objectID, int currentA { C_Team *pTeam = (C_Team*)pStruct; - if ( pTeam->m_aPlayers.Size() != currentArrayLength ) + if ( pTeam->m_aPlayers.Count() != currentArrayLength ) pTeam->m_aPlayers.SetSize( currentArrayLength ); } @@ -151,7 +151,7 @@ int C_Team::Get_Ping( void ) //----------------------------------------------------------------------------- int C_Team::Get_Number_Players( void ) { - return m_aPlayers.Size(); + return m_aPlayers.Count(); } //----------------------------------------------------------------------------- @@ -159,7 +159,7 @@ int C_Team::Get_Number_Players( void ) //----------------------------------------------------------------------------- bool C_Team::ContainsPlayer( int iPlayerIndex ) { - for (int i = 0; i < m_aPlayers.Size(); i++ ) + for (int i = 0; i < m_aPlayers.Count(); i++ ) { if ( m_aPlayers[i] == iPlayerIndex ) return true; @@ -252,5 +252,5 @@ bool ArePlayersOnSameTeam( int iPlayerIndex1, int iPlayerIndex2 ) //----------------------------------------------------------------------------- int GetNumberOfTeams( void ) { - return g_Teams.Size(); + return g_Teams.Count(); } \ No newline at end of file diff --git a/game/client/c_team.h b/game/client/c_team.h index 5f26917b5..1957f2a07 100644 --- a/game/client/c_team.h +++ b/game/client/c_team.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: Client side CTeam class // diff --git a/game/client/c_team_objectiveresource.cpp b/game/client/c_team_objectiveresource.cpp index 76dd3e168..c3975d0f2 100644 --- a/game/client/c_team_objectiveresource.cpp +++ b/game/client/c_team_objectiveresource.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======= // // Purpose: An entity that networks the state of the game's objectives. // @@ -72,14 +72,6 @@ IMPLEMENT_CLIENTCLASS_DT_NOBASE(C_BaseTeamObjectiveResource, DT_BaseTeamObjectiv RecvPropArray3( RECVINFO_ARRAY(m_iWarnOnCap), RecvPropInt( RECVINFO(m_iWarnOnCap[0]) ) ), RecvPropArray( RecvPropString( RECVINFO( m_iszWarnSound[0]) ), m_iszWarnSound ), RecvPropArray3( RECVINFO_ARRAY(m_flPathDistance), RecvPropFloat( RECVINFO(m_flPathDistance[0]) ) ), - RecvPropArray3( RECVINFO_ARRAY(m_iCPGroup), RecvPropInt( RECVINFO(m_iCPGroup[0]) ) ), - RecvPropArray3( RECVINFO_ARRAY(m_bCPLocked), RecvPropBool( RECVINFO(m_bCPLocked[0]) ) ), - RecvPropArray3( RECVINFO_ARRAY(m_nNumNodeHillData), RecvPropInt( RECVINFO(m_nNumNodeHillData[0]) ) ), - RecvPropArray3( RECVINFO_ARRAY(m_flNodeHillData), RecvPropFloat( RECVINFO(m_flNodeHillData[0]) ) ), - RecvPropArray3( RECVINFO_ARRAY(m_bTrackAlarm), RecvPropBool( RECVINFO(m_bTrackAlarm[0]) ) ), - RecvPropArray3( RECVINFO_ARRAY(m_flUnlockTimes), RecvPropFloat( RECVINFO(m_flUnlockTimes[0]) ) ), - RecvPropArray3( RECVINFO_ARRAY(m_bHillIsDownhill), RecvPropBool( RECVINFO(m_bHillIsDownhill[0]) ) ), - RecvPropArray3( RECVINFO_ARRAY(m_flCPTimerTimes), RecvPropFloat( RECVINFO(m_flCPTimerTimes[0]) ) ), // state variables RecvPropArray3( RECVINFO_ARRAY(m_iNumTeamMembers), RecvPropInt( RECVINFO(m_iNumTeamMembers[0]) ) ), @@ -87,10 +79,7 @@ IMPLEMENT_CLIENTCLASS_DT_NOBASE(C_BaseTeamObjectiveResource, DT_BaseTeamObjectiv RecvPropArray3( RECVINFO_ARRAY(m_iTeamInZone), RecvPropInt( RECVINFO(m_iTeamInZone[0]) ) ), RecvPropArray3( RECVINFO_ARRAY(m_bBlocked), RecvPropInt( RECVINFO(m_bBlocked[0]) ) ), RecvPropArray3( RECVINFO_ARRAY(m_iOwner), RecvPropInt( RECVINFO(m_iOwner[0]), 0, RecvProxy_Owner ) ), - RecvPropArray3( RECVINFO_ARRAY(m_bCPCapRateScalesWithPlayers), RecvPropBool( RECVINFO(m_bCPCapRateScalesWithPlayers[0]) ) ), RecvPropString( RECVINFO(m_pszCapLayoutInHUD), 0, RecvProxy_CapLayout ), - RecvPropFloat( RECVINFO(m_flCustomPositionX) ), - RecvPropFloat( RECVINFO(m_flCustomPositionY) ), END_RECV_TABLE() C_BaseTeamObjectiveResource *g_pObjectiveResource = NULL; @@ -106,20 +95,15 @@ C_BaseTeamObjectiveResource::C_BaseTeamObjectiveResource() m_iUpdateCapHudParity = 0; m_bControlPointsReset = false; - int i; - - for ( i=0; i < MAX_CONTROL_POINTS; i++ ) + for ( int i=0; i < MAX_CONTROL_POINTS; i++ ) { m_flCapTimeLeft[i] = 0; m_flCapLastThinkTime[i] = 0; m_flLastCapWarningTime[i] = 0; m_bWarnedOnFinalCap[i] = false; // have we warned m_iWarnOnCap[i] = CP_WARN_NORMAL; // should we warn - m_iCPGroup[i] = -1; m_iszWarnSound[i][0] = 0; // what sound should be played m_flLazyCapPerc[i] = 0.0; - m_flUnlockTimes[i] = 0.0; - m_flCPTimerTimes[i] = -1.0; for ( int team = 0; team < MAX_CONTROL_POINT_TEAMS; team++ ) { @@ -143,20 +127,6 @@ C_BaseTeamObjectiveResource::C_BaseTeamObjectiveResource() m_iTeamBaseIcons[team] = 0; } - for ( i=0; i < TEAM_TRAIN_MAX_TEAMS; i++ ) - { - m_nNumNodeHillData[i] = 0; - m_bTrainOnHill[i] = false; - } - - for ( i=0; i < TEAM_TRAIN_HILLS_ARRAY_SIZE; i++ ) - { - m_flNodeHillData[i] = 0; - } - - m_flCustomPositionX = -1.f; - m_flCustomPositionY = -1.f; - g_pObjectiveResource = this; } @@ -179,12 +149,7 @@ void C_BaseTeamObjectiveResource::OnPreDataChanged( DataUpdateType_t updateType m_iOldUpdateCapHudParity = m_iUpdateCapHudParity; m_bOldControlPointsReset = m_bControlPointsReset; - m_flOldCustomPositionX = m_flCustomPositionX; - m_flOldCustomPositionY = m_flCustomPositionY; - memcpy( m_flOldLazyCapPerc, m_flLazyCapPerc, sizeof(float)*m_iNumControlPoints ); - memcpy( m_flOldUnlockTimes, m_flUnlockTimes, sizeof(float)*m_iNumControlPoints ); - memcpy( m_flOldCPTimerTimes, m_flCPTimerTimes, sizeof(float)*m_iNumControlPoints ); } //----------------------------------------------------------------------------- @@ -215,33 +180,6 @@ void C_BaseTeamObjectiveResource::OnDataChanged( DataUpdateType_t updateType ) { m_flCapTimeLeft[i] = m_flLazyCapPerc[i] * m_flTeamCapTime[ TEAM_ARRAY(i,m_iCappingTeam[i]) ]; } - - if ( m_flOldUnlockTimes[i] != m_flUnlockTimes[i] ) - { - IGameEvent *event = gameeventmanager->CreateEvent( "controlpoint_unlock_updated" ); - if ( event ) - { - event->SetInt( "index", i ); - event->SetFloat( "time", m_flUnlockTimes[i] ); - gameeventmanager->FireEventClientSide( event ); - } - } - - if ( m_flOldCPTimerTimes[i] != m_flCPTimerTimes[i] ) - { - IGameEvent *event = gameeventmanager->CreateEvent( "controlpoint_timer_updated" ); - if ( event ) - { - event->SetInt( "index", i ); - event->SetFloat( "time", m_flCPTimerTimes[i] ); - gameeventmanager->FireEventClientSide( event ); - } - } - } - - if ( m_flOldCustomPositionX != m_flCustomPositionX || m_flOldCustomPositionY != m_flCustomPositionY ) - { - UpdateControlPoint( "controlpoint_updatelayout" ); } } @@ -387,7 +325,7 @@ void C_BaseTeamObjectiveResource::ClientThink() if ( iPlayersCapping > 0 ) { float flReduction = gpGlobals->curtime - m_flCapLastThinkTime[i]; - if ( mp_capstyle.GetInt() == 1 && m_bCPCapRateScalesWithPlayers[i] ) + if ( mp_capstyle.GetInt() == 1 ) { // Diminishing returns for successive players. for ( int iPlayer = 1; iPlayer < iPlayersCapping; iPlayer++ ) @@ -403,21 +341,26 @@ void C_BaseTeamObjectiveResource::ClientThink() if ( !m_bWarnedOnFinalCap[i] ) { - // If this the local player's team, warn him - C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); - if ( pPlayer ) + FOR_EACH_VALID_SPLITSCREEN_PLAYER( hh ) { - if ( m_iCappingTeam[i] != TEAM_UNASSIGNED && - pPlayer->GetTeamNumber() != m_iCappingTeam[i] && - GetCapWarningLevel( i ) == CP_WARN_FINALCAP ) + ACTIVE_SPLITSCREEN_PLAYER_GUARD( hh ); + + // If this the local player's team, warn him + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + if ( pPlayer ) { - // Prevent spam - if ( gpGlobals->curtime > ( m_flLastCapWarningTime[i] + 5 ) ) + if ( m_iCappingTeam[i] != TEAM_UNASSIGNED && + pPlayer->GetTeamNumber() != m_iCappingTeam[i] && + GetCapWarningLevel( i ) == CP_WARN_FINALCAP ) { - pPlayer->EmitSound( GetWarnSound( i ) ); - - m_bWarnedOnFinalCap[i] = true; - m_flLastCapWarningTime[i] = gpGlobals->curtime; + // Prevent spam + if ( gpGlobals->curtime > ( m_flLastCapWarningTime[i] + 5 ) ) + { + pPlayer->EmitSound( GetWarnSound( i ) ); + + m_bWarnedOnFinalCap[i] = true; + m_flLastCapWarningTime[i] = gpGlobals->curtime; + } } } } @@ -437,8 +380,7 @@ void C_BaseTeamObjectiveResource::ClientThink() if ( TeamplayRoundBasedRules() && TeamplayRoundBasedRules()->TeamMayCapturePoint(m_iCappingTeam[i],i) ) { float flCapLength = m_flTeamCapTime[ TEAM_ARRAY(i,m_iCappingTeam[i]) ]; - float flDecreaseScale = m_bCPCapRateScalesWithPlayers[i] ? mp_capdeteriorate_time.GetFloat() : flCapLength; - float flDecrease = (flCapLength / flDecreaseScale) * (gpGlobals->curtime - m_flCapLastThinkTime[i]); + float flDecrease = (flCapLength / mp_capdeteriorate_time.GetFloat()) * (gpGlobals->curtime - m_flCapLastThinkTime[i]); if ( TeamplayRoundBasedRules() && TeamplayRoundBasedRules()->InOvertime() ) { flDecrease *= 6; diff --git a/game/client/c_team_objectiveresource.h b/game/client/c_team_objectiveresource.h index b71398028..03cb2aa89 100644 --- a/game/client/c_team_objectiveresource.h +++ b/game/client/c_team_objectiveresource.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======= // // Purpose: // @@ -163,7 +163,6 @@ class C_BaseTeamObjectiveResource : public C_BaseEntity } const char *GetCapLayoutInHUD( void ) { return m_pszCapLayoutInHUD; } - void GetCapLayoutCustomPosition( float& flCustomPositionX, float& flCustomPositionY ) { flCustomPositionX = m_flCustomPositionX; flCustomPositionY = m_flCustomPositionY; } bool PlayingMiniRounds( void ){ return m_bPlayingMiniRounds; } bool IsInMiniRound( int index ) { return m_bInMiniRound[index]; } @@ -174,12 +173,6 @@ class C_BaseTeamObjectiveResource : public C_BaseEntity return m_iWarnOnCap[index]; } - int GetCPGroup( int index ) - { - Assert( index < m_iNumControlPoints ); - return m_iCPGroup[index]; - } - const char *GetWarnSound( int index ) { Assert( index < m_iNumControlPoints ); @@ -216,62 +209,6 @@ class C_BaseTeamObjectiveResource : public C_BaseEntity return m_flPathDistance[index]; } - bool GetCPLocked( int index ) - { - Assert( index < m_iNumControlPoints ); - return m_bCPLocked[index]; - } - - bool GetTrackAlarm( int index ) - { - Assert( index < TEAM_TRAIN_MAX_TEAMS ); - return m_bTrackAlarm[index]; - } - - int GetNumNodeHillData( int team ){ return ( team < TEAM_TRAIN_MAX_TEAMS ) ? m_nNumNodeHillData[team] : 0; } - - void GetHillData( int team, int hill, float &flStart, float &flEnd ) - { - if ( hill < TEAM_TRAIN_MAX_HILLS && team < TEAM_TRAIN_MAX_TEAMS ) - { - int index = ( hill * TEAM_TRAIN_FLOATS_PER_HILL ) + ( team * TEAM_TRAIN_MAX_HILLS * TEAM_TRAIN_FLOATS_PER_HILL ); - if ( index < TEAM_TRAIN_HILLS_ARRAY_SIZE - 1 ) // - 1 because we want to look at 2 entries - { - flStart = m_flNodeHillData[index]; - flEnd = m_flNodeHillData[index+1]; - } - } - } - - void SetTrainOnHill( int team, int hill, bool state ) - { - if ( team < TEAM_TRAIN_MAX_TEAMS && hill < TEAM_TRAIN_MAX_HILLS ) - { - int index = hill + ( team * TEAM_TRAIN_MAX_HILLS ); - m_bTrainOnHill[index] = state; - } - } - - bool IsTrainOnHill( int team, int hill ) - { - if ( team < TEAM_TRAIN_MAX_TEAMS && hill < TEAM_TRAIN_MAX_HILLS ) - { - return m_bTrainOnHill[hill + ( team * TEAM_TRAIN_MAX_HILLS )]; - } - - return false; - } - - bool IsHillDownhill( int team, int hill ) - { - if ( team < TEAM_TRAIN_MAX_TEAMS && hill < TEAM_TRAIN_MAX_HILLS ) - { - return m_bHillIsDownhill[hill + ( team * TEAM_TRAIN_MAX_HILLS )]; - } - - return true; - } - protected: int m_iTimerToShowInHUD; int m_iStopWatchTimer; @@ -301,12 +238,6 @@ class C_BaseTeamObjectiveResource : public C_BaseEntity int m_iWarnOnCap[MAX_CONTROL_POINTS]; char m_iszWarnSound[MAX_CONTROL_POINTS][255]; float m_flPathDistance[MAX_CONTROL_POINTS]; - int m_iCPGroup[MAX_CONTROL_POINTS]; - bool m_bCPLocked[MAX_CONTROL_POINTS]; - float m_flUnlockTimes[MAX_CONTROL_POINTS]; - float m_flOldUnlockTimes[MAX_CONTROL_POINTS]; - float m_flCPTimerTimes[MAX_CONTROL_POINTS]; - float m_flOldCPTimerTimes[MAX_CONTROL_POINTS]; // state variables int m_iNumTeamMembers[MAX_CONTROL_POINTS * MAX_CONTROL_POINT_TEAMS]; @@ -314,7 +245,6 @@ class C_BaseTeamObjectiveResource : public C_BaseEntity int m_iTeamInZone[MAX_CONTROL_POINTS]; bool m_bBlocked[MAX_CONTROL_POINTS]; int m_iOwner[MAX_CONTROL_POINTS]; - bool m_bCPCapRateScalesWithPlayers[MAX_CONTROL_POINTS]; // client calculated state float m_flCapTimeLeft[MAX_CONTROL_POINTS]; @@ -323,18 +253,6 @@ class C_BaseTeamObjectiveResource : public C_BaseEntity bool m_bWarnedOnFinalCap[MAX_CONTROL_POINTS]; float m_flLastCapWarningTime[MAX_CONTROL_POINTS]; char m_pszCapLayoutInHUD[MAX_CAPLAYOUT_LENGTH]; - float m_flOldCustomPositionX; - float m_flOldCustomPositionY; - float m_flCustomPositionX; - float m_flCustomPositionY; - - // hill data for multi-escort payload maps - int m_nNumNodeHillData[TEAM_TRAIN_MAX_TEAMS]; - float m_flNodeHillData[TEAM_TRAIN_HILLS_ARRAY_SIZE]; - bool m_bTrainOnHill[TEAM_TRAIN_MAX_HILLS*TEAM_TRAIN_MAX_TEAMS]; - - bool m_bTrackAlarm[TEAM_TRAIN_MAX_TEAMS]; - bool m_bHillIsDownhill[TEAM_TRAIN_MAX_HILLS*TEAM_TRAIN_MAX_TEAMS]; }; extern C_BaseTeamObjectiveResource *g_pObjectiveResource; diff --git a/game/client/c_team_train_watcher.cpp b/game/client/c_team_train_watcher.cpp index da3fa880d..ec55bd647 100644 --- a/game/client/c_team_train_watcher.cpp +++ b/game/client/c_team_train_watcher.cpp @@ -1,48 +1,36 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2006, Valve Corporation, All rights reserved. ============// // -// Purpose: Entity that propagates train data for escort game type +// Purpose: Entity that propagates train data for escort gametype // // $NoKeywords: $ //=============================================================================// #include "cbase.h" #include "c_team_train_watcher.h" #include "igameevents.h" -#include "c_team_objectiveresource.h" - -#ifdef TF_CLIENT_DLL -#include "tf_shareddefs.h" -#include "teamplayroundbased_gamerules.h" -#endif // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" -IMPLEMENT_CLIENTCLASS_DT(C_TeamTrainWatcher, DT_TeamTrainWatcher, CTeamTrainWatcher) +IMPLEMENT_CLIENTCLASS_DT_NOBASE(C_TeamTrainWatcher, DT_TeamTrainWatcher, CTeamTrainWatcher) RecvPropFloat( RECVINFO( m_flTotalProgress ) ), RecvPropInt( RECVINFO( m_iTrainSpeedLevel ) ), RecvPropFloat( RECVINFO( m_flRecedeTime ) ), RecvPropInt( RECVINFO( m_nNumCappers ) ), -#ifdef GLOWS_ENABLE - RecvPropEHandle( RECVINFO( m_hGlowEnt ) ), -#endif // GLOWS_ENABLE END_RECV_TABLE() -CUtlVector< CHandle > g_hTrainWatchers; +C_TeamTrainWatcher *g_pTrainWatcher = NULL; C_TeamTrainWatcher::C_TeamTrainWatcher() { + g_pTrainWatcher = this; + // force updates when we get our baseline m_iTrainSpeedLevel = -2; m_flTotalProgress = -1; m_flRecedeTime = -1; -#ifdef GLOWS_ENABLE - m_pGlowEffect = NULL; - m_hGlowEnt = NULL; - m_hOldGlowEnt = NULL; -#endif // GLOWS_ENABLE } //----------------------------------------------------------------------------- @@ -50,59 +38,11 @@ C_TeamTrainWatcher::C_TeamTrainWatcher() //----------------------------------------------------------------------------- C_TeamTrainWatcher::~C_TeamTrainWatcher() { -#ifdef GLOWS_ENABLE - DestroyGlowEffect(); -#endif // GLOWS_ENABLE -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void C_TeamTrainWatcher::ClientThink() -{ -#ifdef GLOWS_ENABLE - if ( IsDormant() || ( m_hGlowEnt.Get() == NULL ) ) - { - DestroyGlowEffect(); - m_hOldGlowEnt = NULL; - m_hGlowEnt = NULL; - } -#endif // GLOWS_ENABLE -} - -#ifdef GLOWS_ENABLE -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void C_TeamTrainWatcher::UpdateGlowEffect( void ) -{ - // destroy the existing effect - if ( m_pGlowEffect ) - { - DestroyGlowEffect(); - } - - // create a new effect if we have a cart - if ( m_hGlowEnt ) - { - float r, g, b; - TeamplayRoundBasedRules()->GetTeamGlowColor( GetTeamNumber(), r, g, b ); - m_pGlowEffect = new CGlowObject( m_hGlowEnt, Vector( r, g, b ), 1.0, true ); - } -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void C_TeamTrainWatcher::DestroyGlowEffect( void ) -{ - if ( m_pGlowEffect ) + if ( g_pTrainWatcher == this ) { - delete m_pGlowEffect; - m_pGlowEffect = NULL; + g_pTrainWatcher = NULL; } } -#endif // GLOWS_ENABLE void C_TeamTrainWatcher::OnPreDataChanged( DataUpdateType_t updateType ) { @@ -112,9 +52,6 @@ void C_TeamTrainWatcher::OnPreDataChanged( DataUpdateType_t updateType ) m_flOldProgress = m_flTotalProgress; m_flOldRecedeTime = m_flRecedeTime; m_nOldNumCappers = m_nNumCappers; -#ifdef GLOWS_ENABLE - m_hOldGlowEnt = m_hGlowEnt; -#endif // GLOWS_ENABLE } //----------------------------------------------------------------------------- @@ -122,19 +59,11 @@ void C_TeamTrainWatcher::OnPreDataChanged( DataUpdateType_t updateType ) //----------------------------------------------------------------------------- void C_TeamTrainWatcher::OnDataChanged( DataUpdateType_t updateType ) { - BaseClass::OnDataChanged( updateType ); - - if ( updateType == DATA_UPDATE_CREATED ) - { - SetNextClientThink( CLIENT_THINK_ALWAYS ); - } - if ( m_iOldTrainSpeedLevel != m_iTrainSpeedLevel || m_nOldNumCappers != m_nNumCappers ) { IGameEvent *event = gameeventmanager->CreateEvent( "escort_speed" ); if ( event ) { - event->SetInt( "team", GetTeamNumber() ); event->SetInt( "speed", m_iTrainSpeedLevel ); event->SetInt( "players", m_nNumCappers ); gameeventmanager->FireEventClientSide( event ); @@ -146,7 +75,6 @@ void C_TeamTrainWatcher::OnDataChanged( DataUpdateType_t updateType ) IGameEvent *event = gameeventmanager->CreateEvent( "escort_progress" ); if ( event ) { - event->SetInt( "team", GetTeamNumber() ); event->SetFloat( "progress", m_flTotalProgress ); if ( m_flOldProgress <= -1 ) @@ -156,28 +84,6 @@ void C_TeamTrainWatcher::OnDataChanged( DataUpdateType_t updateType ) gameeventmanager->FireEventClientSide( event ); } - - // check to see if the train is now on a hill - if ( ObjectiveResource() ) - { - int nNumHills = ObjectiveResource()->GetNumNodeHillData( GetTeamNumber() ); - if ( nNumHills > 0 ) - { - float flStart, flEnd; - for ( int i = 0 ; i < nNumHills ; i++ ) - { - ObjectiveResource()->GetHillData( GetTeamNumber(), i, flStart, flEnd ); - if ( m_flTotalProgress >= flStart && m_flTotalProgress<= flEnd ) - { - ObjectiveResource()->SetTrainOnHill( GetTeamNumber(), i, true ); - } - else - { - ObjectiveResource()->SetTrainOnHill( GetTeamNumber(), i, false ); - } - } - } - } } if ( m_flOldRecedeTime != m_flRecedeTime ) @@ -185,38 +91,8 @@ void C_TeamTrainWatcher::OnDataChanged( DataUpdateType_t updateType ) IGameEvent *event = gameeventmanager->CreateEvent( "escort_recede" ); if ( event ) { - event->SetInt( "team", GetTeamNumber() ); event->SetFloat( "recedetime", m_flRecedeTime ); gameeventmanager->FireEventClientSide( event ); } } -#ifdef GLOWS_ENABLE - if ( m_hOldGlowEnt != m_hGlowEnt ) - { - UpdateGlowEffect(); - } -#endif // GLOWS_ENABLE -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void C_TeamTrainWatcher::Spawn( void ) -{ - BaseClass::Spawn(); - - if ( g_hTrainWatchers.Find( this ) == g_hTrainWatchers.InvalidIndex() ) - { - g_hTrainWatchers.AddToTail( this ); - } -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void C_TeamTrainWatcher::UpdateOnRemove( void ) -{ - BaseClass::UpdateOnRemove(); - - g_hTrainWatchers.FindAndRemove( this ); -} +} \ No newline at end of file diff --git a/game/client/c_team_train_watcher.h b/game/client/c_team_train_watcher.h index 8887d22b0..041d63dd3 100644 --- a/game/client/c_team_train_watcher.h +++ b/game/client/c_team_train_watcher.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======= // // Purpose: // @@ -11,10 +11,6 @@ #endif #include "c_baseentity.h" -#include "c_physicsprop.h" -#ifdef GLOWS_ENABLE -#include "glow_outline_effect.h" -#endif // GLOWS_ENABLE class C_TeamTrainWatcher : public C_BaseEntity { @@ -28,22 +24,9 @@ class C_TeamTrainWatcher : public C_BaseEntity virtual void OnPreDataChanged( DataUpdateType_t updateType ); virtual void OnDataChanged( DataUpdateType_t updateType ); - virtual void Spawn( void ); - virtual void UpdateOnRemove( void ); - float GetTotalProgress( void ) { return m_flTotalProgress; } int GetSpeedLevel( void ) { return m_iTrainSpeedLevel; } - // IClientThinkable overrides. -public: - virtual void ClientThink(); - -#ifdef GLOWS_ENABLE -private: - void UpdateGlowEffect( void ); - void DestroyGlowEffect( void ); -#endif // GLOWS_ENABLE - private: // === Networked Data === @@ -64,14 +47,13 @@ class C_TeamTrainWatcher : public C_BaseEntity CNetworkVar( int, m_nNumCappers ); int m_nOldNumCappers; - -#ifdef GLOWS_ENABLE - EHANDLE m_hGlowEnt; - EHANDLE m_hOldGlowEnt; - CGlowObject *m_pGlowEffect; -#endif // GLOWS_ENABLE }; -extern CUtlVector< CHandle > g_hTrainWatchers; +extern C_TeamTrainWatcher *g_pTrainWatcher; + +inline C_TeamTrainWatcher *TrainWatcher() +{ + return g_pTrainWatcher; +} #endif //C_TEAM_TRAIN_WATCHER_H \ No newline at end of file diff --git a/game/client/c_tesla.cpp b/game/client/c_tesla.cpp index 691192a14..375dc0348 100644 --- a/game/client/c_tesla.cpp +++ b/game/client/c_tesla.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // diff --git a/game/client/c_tesla.h b/game/client/c_tesla.h index 5fce1898f..3cb761460 100644 --- a/game/client/c_tesla.h +++ b/game/client/c_tesla.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // diff --git a/game/client/c_test_proxytoggle.cpp b/game/client/c_test_proxytoggle.cpp index 45405e108..1923600dd 100644 --- a/game/client/c_test_proxytoggle.cpp +++ b/game/client/c_test_proxytoggle.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // diff --git a/game/client/c_testtraceline.cpp b/game/client/c_testtraceline.cpp index 6475fff9f..550a22eca 100644 --- a/game/client/c_testtraceline.cpp +++ b/game/client/c_testtraceline.cpp @@ -1,12 +1,12 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // // $NoKeywords: $ -//=============================================================================// +//===========================================================================// #include "cbase.h" -#include "materialsystem/imesh.h" +#include "materialsystem/IMesh.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -25,7 +25,7 @@ class C_TestTraceline : public C_BaseEntity // IClientEntity overrides. public: - virtual int DrawModel( int flags ); + virtual int DrawModel( int flags, const RenderableInstance_t &instance ); virtual bool ShouldDraw() { return true; } private: @@ -37,7 +37,7 @@ class C_TestTraceline : public C_BaseEntity IMPLEMENT_CLIENTCLASS(C_TestTraceline, DT_TestTraceline, CTestTraceline); BEGIN_RECV_TABLE_NOBASE(C_TestTraceline, DT_TestTraceline) - RecvPropInt(RECVINFO(m_clrRender)), + RecvPropInt(RECVINFO(m_clrRender), 0, RecvProxy_Int32ToColor32 ), RecvPropVector( RECVINFO_NAME( m_vecNetworkOrigin, m_vecOrigin ) ), RecvPropFloat( RECVINFO_NAME( m_angNetworkAngles[0], m_angRotation[0] ) ), RecvPropFloat( RECVINFO_NAME( m_angNetworkAngles[1], m_angRotation[1] ) ), @@ -52,7 +52,7 @@ END_RECV_TABLE() C_TestTraceline::C_TestTraceline() { - m_pWireframe = materials->FindMaterial("shadertest/wireframevertexcolor", TEXTURE_GROUP_OTHER); + m_pWireframe = materials->FindMaterial("debug/debugwireframevertexcolor", TEXTURE_GROUP_OTHER); } C_TestTraceline::~C_TestTraceline() @@ -138,7 +138,7 @@ void C_TestTraceline::DrawCube( Vector& center, unsigned char* pColor ) } } -int C_TestTraceline::DrawModel( int flags ) +int C_TestTraceline::DrawModel( int flags, const RenderableInstance_t &instance ) { trace_t tr; Vector forward, right, up, endpos, hitpos; diff --git a/game/client/c_tracer.cpp b/game/client/c_tracer.cpp index ea6600a29..772c84a40 100644 --- a/game/client/c_tracer.cpp +++ b/game/client/c_tracer.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // @@ -7,7 +7,7 @@ //=============================================================================// #include "cbase.h" #include "particledraw.h" -#include "materialsystem/imesh.h" +#include "materialsystem/IMesh.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" diff --git a/game/client/c_tracer.h b/game/client/c_tracer.h index bb9e13fee..48deb6b5f 100644 --- a/game/client/c_tracer.h +++ b/game/client/c_tracer.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // diff --git a/game/client/c_triggers.cpp b/game/client/c_triggers.cpp new file mode 100644 index 000000000..99f8eae8d --- /dev/null +++ b/game/client/c_triggers.cpp @@ -0,0 +1,198 @@ +//========= Copyright © 1996-2008, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#include "cbase.h" +#include "c_triggers.h" +#include "in_buttons.h" +#include "c_func_brush.h" +#include "collisionutils.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +IMPLEMENT_CLIENTCLASS_DT( C_BaseTrigger, DT_BaseTrigger, CBaseTrigger ) + RecvPropBool( RECVINFO( m_bClientSidePredicted ) ), + RecvPropInt( RECVINFO( m_spawnflags ) ), +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: Disables auto movement on players that touch it +//----------------------------------------------------------------------------- +class C_TriggerPlayerMovement : public C_BaseTrigger +{ + DECLARE_CLASS( C_TriggerPlayerMovement, C_BaseTrigger ); + DECLARE_CLIENTCLASS(); +public: + + C_TriggerPlayerMovement(); + ~C_TriggerPlayerMovement(); + + void StartTouch( C_BaseEntity *pOther ); + void EndTouch( C_BaseEntity *pOther ); + +protected: + + virtual void UpdatePartitionListEntry(); + +public: + C_TriggerPlayerMovement *m_pNext; +}; + +IMPLEMENT_CLIENTCLASS_DT( C_TriggerPlayerMovement, DT_TriggerPlayerMovement, CTriggerPlayerMovement ) +END_RECV_TABLE() + +C_EntityClassList< C_TriggerPlayerMovement > g_TriggerPlayerMovementList; +C_TriggerPlayerMovement *C_EntityClassList::m_pClassList = NULL; + +C_TriggerPlayerMovement::C_TriggerPlayerMovement() +{ + g_TriggerPlayerMovementList.Insert( this ); +} + +C_TriggerPlayerMovement::~C_TriggerPlayerMovement() +{ + g_TriggerPlayerMovementList.Remove( this ); +} + +//----------------------------------------------------------------------------- +// Little enumeration class used to try touching all triggers +//----------------------------------------------------------------------------- +template< class T > +class CFastTouchTriggers +{ +public: + CFastTouchTriggers( C_BaseEntity *pEnt, T *pTriggers ) : m_pEnt( pEnt ), m_pTriggers( pTriggers ) + { + m_pCollide = pEnt->GetCollideable(); + Assert( m_pCollide ); + + Vector vecMins, vecMaxs; + CM_GetCollideableTriggerTestBox( m_pCollide, &vecMins, &vecMaxs ); + const Vector &vecStart = m_pCollide->GetCollisionOrigin(); + m_Ray.Init( vecStart, vecStart, vecMins, vecMaxs ); + } + + FORCEINLINE void CM_GetCollideableTriggerTestBox( ICollideable *pCollide, Vector *pMins, Vector *pMaxs ) + { + if ( pCollide->GetSolid() == SOLID_BBOX ) + { + *pMins = pCollide->OBBMins(); + *pMaxs = pCollide->OBBMaxs(); + } + else + { + const Vector &vecStart = pCollide->GetCollisionOrigin(); + pCollide->WorldSpaceSurroundingBounds( pMins, pMaxs ); + *pMins -= vecStart; + *pMaxs -= vecStart; + } + } + + FORCEINLINE void Check( T *pEntity ) + { + // Hmmm.. everything in this list should be a trigger.... + ICollideable *pTriggerCollideable = pEntity->GetCollideable(); + if ( !m_pCollide->ShouldTouchTrigger(pTriggerCollideable->GetSolidFlags()) ) + return; + + if ( pTriggerCollideable->GetSolidFlags() & FSOLID_USE_TRIGGER_BOUNDS ) + { + Vector vecTriggerMins, vecTriggerMaxs; + pTriggerCollideable->WorldSpaceTriggerBounds( &vecTriggerMins, &vecTriggerMaxs ); + if ( !IsBoxIntersectingRay( vecTriggerMins, vecTriggerMaxs, m_Ray ) ) + { + return; + } + } + else + { + trace_t tr; + enginetrace->ClipRayToCollideable( m_Ray, MASK_SOLID, pTriggerCollideable, &tr ); + if ( !(tr.contents & MASK_SOLID) ) + return; + } + + trace_t tr; + UTIL_ClearTrace( tr ); + tr.endpos = (m_pEnt->GetAbsOrigin() + pEntity->GetAbsOrigin()) * 0.5; + m_pEnt->PhysicsMarkEntitiesAsTouching( pEntity, tr ); + } + + FORCEINLINE void Run() + { + for ( T *trigger = m_pTriggers; trigger ; trigger = trigger->m_pNext ) + { + if ( trigger->IsDormant() ) + continue; + Check( trigger ); + } + } + + Ray_t m_Ray; + +private: + C_BaseEntity *m_pEnt; + ICollideable *m_pCollide; + T *m_pTriggers; +}; + +void TouchTriggerPlayerMovement( C_BaseEntity *pEntity ) +{ + CFastTouchTriggers< C_TriggerPlayerMovement > helper( pEntity, g_TriggerPlayerMovementList.m_pClassList ); + helper.Run(); +} + + +void C_TriggerPlayerMovement::UpdatePartitionListEntry() +{ + if ( !m_bClientSidePredicted ) + { + BaseClass::UpdatePartitionListEntry(); + return; + } + + partition->RemoveAndInsert( + PARTITION_CLIENT_SOLID_EDICTS | PARTITION_CLIENT_RESPONSIVE_EDICTS | PARTITION_CLIENT_NON_STATIC_EDICTS, // remove + PARTITION_CLIENT_TRIGGER_ENTITIES, // add + CollisionProp()->GetPartitionHandle() ); +} + +void C_TriggerPlayerMovement::StartTouch( C_BaseEntity *pOther ) +{ + C_BasePlayer *pPlayer = ToBasePlayer( pOther ); + + if ( !pPlayer ) + return; + + if ( HasSpawnFlags( SF_TRIGGER_AUTO_DUCK ) ) + { + pPlayer->ForceButtons( IN_DUCK ); + } + + // UNDONE: Currently this is the only operation this trigger can do + if ( HasSpawnFlags( SF_TRIGGER_MOVE_AUTODISABLE ) ) + { + pPlayer->m_Local.m_bAllowAutoMovement = false; + } +} + +void C_TriggerPlayerMovement::EndTouch( C_BaseEntity *pOther ) +{ + C_BasePlayer *pPlayer = ToBasePlayer( pOther ); + if ( !pPlayer ) + return; + + if ( HasSpawnFlags( SF_TRIGGER_AUTO_DUCK ) ) + { + pPlayer->UnforceButtons( IN_DUCK ); + } + + if ( HasSpawnFlags( SF_TRIGGER_MOVE_AUTODISABLE ) ) + { + pPlayer->m_Local.m_bAllowAutoMovement = true; + } +} + diff --git a/game/client/c_triggers.h b/game/client/c_triggers.h new file mode 100644 index 000000000..40d3e4cc7 --- /dev/null +++ b/game/client/c_triggers.h @@ -0,0 +1,26 @@ +//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======= +// +// Purpose: +// +//============================================================================= + +#ifndef C_TRIGGERS_H +#define C_TRIGGERS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "c_basetoggle.h" +#include "triggers_shared.h" + +class C_BaseTrigger : public C_BaseToggle +{ + DECLARE_CLASS( C_BaseTrigger, C_BaseToggle ); + DECLARE_CLIENTCLASS(); + +public: + + bool m_bClientSidePredicted; +}; + +#endif // C_TRIGGERS_H diff --git a/game/client/c_user_message_register.cpp b/game/client/c_user_message_register.cpp index 73d275542..28ec95ffd 100644 --- a/game/client/c_user_message_register.cpp +++ b/game/client/c_user_message_register.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // diff --git a/game/client/c_user_message_register.h b/game/client/c_user_message_register.h index bf4c4d62d..f4b1df90b 100644 --- a/game/client/c_user_message_register.h +++ b/game/client/c_user_message_register.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // diff --git a/game/client/c_vehicle_choreo_generic.cpp b/game/client/c_vehicle_choreo_generic.cpp index 52eba09e1..c79b03fb5 100644 --- a/game/client/c_vehicle_choreo_generic.cpp +++ b/game/client/c_vehicle_choreo_generic.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // @@ -7,13 +7,11 @@ #include "cbase.h" #include "hud.h" #include "c_props.h" -#include "iclientvehicle.h" +#include "IClientVehicle.h" #include #include #include "vehicle_choreo_generic_shared.h" #include "vehicle_viewblend_shared.h" -// NVNT haptic utils -#include "haptics/haptic_utils.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -147,21 +145,8 @@ void C_PropVehicleChoreoGeneric::PostDataUpdate( DataUpdateType_t updateType ) { BaseClass::PostDataUpdate( updateType ); - // NVNT if we have entered this vehicle notify the haptics system - if ( m_hPlayer && !m_hPrevPlayer ) - { -#if defined( WIN32 ) && !defined( _X360 ) - //They have just entered the vehicle. - HapticsEnteredVehicle(this,m_hPlayer); -#endif - } - if ( !m_hPlayer && m_hPrevPlayer ) { -#if defined( WIN32 ) && !defined( _X360 ) - // NVNT we have just exited this vehicle so we notify the haptics system - HapticsExitedVehicle(this,m_hPrevPlayer); -#endif // They have just exited the vehicle. // Sometimes we never reach the end of our exit anim, such as if the // animation doesn't have fadeout 0 specified in the QC, so we fail to @@ -229,12 +214,12 @@ void C_PropVehicleChoreoGeneric::UpdateViewAngles( C_BasePlayer *pLocalPlayer, C // Limit the yaw. float flAngleDiff = AngleDiff( pCmd->viewangles.y, vehicleEyeAngles.y ); - flAngleDiff = clamp( flAngleDiff, (float) m_vehicleView.flYawMin, (float) m_vehicleView.flYawMax ); + flAngleDiff = clamp( flAngleDiff, m_vehicleView.flYawMin, m_vehicleView.flYawMax ); pCmd->viewangles.y = vehicleEyeAngles.y + flAngleDiff; // Limit the pitch -- don't let them look down into the empty pod! flAngleDiff = AngleDiff( pCmd->viewangles.x, vehicleEyeAngles.x ); - flAngleDiff = clamp( flAngleDiff, (float) m_vehicleView.flPitchMin, (float) m_vehicleView.flPitchMax ); + flAngleDiff = clamp( flAngleDiff, m_vehicleView.flPitchMin, m_vehicleView.flPitchMax ); pCmd->viewangles.x = vehicleEyeAngles.x + flAngleDiff; } diff --git a/game/client/c_vehicle_jeep.cpp b/game/client/c_vehicle_jeep.cpp index a59e291ee..b546d51af 100644 --- a/game/client/c_vehicle_jeep.cpp +++ b/game/client/c_vehicle_jeep.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // @@ -54,7 +54,7 @@ C_PropJeep::~C_PropJeep() } } -void C_PropJeep::Simulate( void ) +bool C_PropJeep::Simulate( void ) { // The dim light is the flashlight. if ( m_bHeadlightIsOn ) @@ -65,7 +65,7 @@ void C_PropJeep::Simulate( void ) m_pHeadlight = new CHeadlightEffect; if ( m_pHeadlight == NULL ) - return; + return true; m_pHeadlight->TurnOn(); } @@ -76,7 +76,7 @@ void C_PropJeep::Simulate( void ) int iAttachment = LookupAttachment( "headlight" ); - if ( iAttachment != INVALID_PARTICLE_ATTACHMENT ) + if ( iAttachment != -1 ) { GetAttachment( iAttachment, vVector, vAngle ); AngleVectors( vAngle, &vecForward, &vecRight, &vecUp ); @@ -92,6 +92,7 @@ void C_PropJeep::Simulate( void ) } BaseClass::Simulate(); + return true; } //----------------------------------------------------------------------------- @@ -323,4 +324,4 @@ void WheelDustCallback( const CEffectData &data ) } } -DECLARE_CLIENT_EFFECT( "WheelDust", WheelDustCallback ); \ No newline at end of file +DECLARE_CLIENT_EFFECT( WheelDust, WheelDustCallback ); \ No newline at end of file diff --git a/game/client/c_vehicle_jeep.h b/game/client/c_vehicle_jeep.h index d7e53c1f5..ad4ef02a8 100644 --- a/game/client/c_vehicle_jeep.h +++ b/game/client/c_vehicle_jeep.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // @@ -41,7 +41,7 @@ class C_PropJeep : public C_PropVehicleDriveable void DampenEyePosition( Vector &vecVehicleEyePos, QAngle &vecVehicleEyeAngles ); void OnEnteredVehicle( C_BasePlayer *pPlayer ); - void Simulate( void ); + bool Simulate( void ); private: @@ -63,4 +63,4 @@ class C_PropJeep : public C_PropVehicleDriveable bool m_bHeadlightIsOn; }; -#endif // C_VEHICLE_JEEP_H +#endif C_VEHICLE_JEEP_H \ No newline at end of file diff --git a/game/client/c_vguiscreen.cpp b/game/client/c_vguiscreen.cpp index adf8830c2..317729c1b 100644 --- a/game/client/c_vguiscreen.cpp +++ b/game/client/c_vguiscreen.cpp @@ -1,29 +1,29 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // // $NoKeywords: $ -//=============================================================================// +//===========================================================================// #include "cbase.h" #include "networkstringtable_clientdll.h" #include -#include "panelmetaclassmgr.h" +#include "PanelMetaClassMgr.h" #include -#include "mathlib/vmatrix.h" -#include "VGuiMatSurface/IMatSystemSurface.h" +#include "mathlib/VMatrix.h" +#include "VGUIMatSurface/IMatSystemSurface.h" #include "view.h" -#include "collisionutils.h" +#include "CollisionUtils.h" #include #include #include #include "ienginevgui.h" #include "in_buttons.h" -#include -#include "materialsystem/imesh.h" -#include "clienteffectprecachesystem.h" -#include "c_vguiscreen.h" -#include "iclientmode.h" +#include +#include "materialsystem/IMesh.h" +#include "precache_register.h" +#include "C_VGuiScreen.h" +#include "IClientMode.h" #include "vgui_bitmapbutton.h" #include "vgui_bitmappanel.h" #include "filesystem.h" @@ -38,9 +38,9 @@ extern vgui::IInputInternal *g_InputInternal; #define VGUI_SCREEN_MODE_RADIUS 80 //Precache the materials -CLIENTEFFECT_REGISTER_BEGIN( PrecacheEffectVGuiScreen ) -CLIENTEFFECT_MATERIAL( "engine/writez" ) -CLIENTEFFECT_REGISTER_END() +PRECACHE_REGISTER_BEGIN( GLOBAL, PrecacheEffectVGuiScreen ) +PRECACHE( MATERIAL, "engine/writez" ) +PRECACHE_REGISTER_END() // ----------------------------------------------------------------------------- // @@ -82,7 +82,7 @@ IMPLEMENT_CLIENTCLASS_DT(C_VGuiScreen, DT_VGuiScreen, CVGuiScreen) RecvPropFloat( RECVINFO(m_flHeight) ), RecvPropInt( RECVINFO(m_fScreenFlags) ), RecvPropInt( RECVINFO(m_nPanelName) ), - RecvPropInt( RECVINFO(m_nAttachmentIndex) ), + RecvPropIntWithMinusOneFlag( RECVINFO(m_nAttachmentIndex) ), RecvPropInt( RECVINFO(m_nOverlayMaterial) ), RecvPropEHandle( RECVINFO(m_hPlayerOwner) ), END_RECV_TABLE() @@ -129,6 +129,9 @@ void C_VGuiScreen::OnDataChanged( DataUpdateType_t type ) m_nButtonState = 0; } + RenderWithViewModels( IsAttachedToViewModel() ); + OnTranslucencyTypeChanged(); + // Set up the overlay material if (m_nOldOverlayMaterial != m_nOverlayMaterial) { @@ -146,7 +149,7 @@ void C_VGuiScreen::OnDataChanged( DataUpdateType_t type ) } } -void FormatViewModelAttachment( Vector &vOrigin, bool bInverse ); +void FormatViewModelAttachment( C_BasePlayer *pPlayer, Vector &vOrigin, bool bInverse ); //----------------------------------------------------------------------------- // Returns the attachment render origin + origin @@ -163,7 +166,9 @@ void C_VGuiScreen::GetAimEntOrigin( IClientEntity *pAttachedTo, Vector *pOrigin, if ( IsAttachedToViewModel() ) { - FormatViewModelAttachment( *pOrigin, true ); + C_BasePlayer *pOwner = ToBasePlayer( ((C_BaseViewModel *)pEnt)->GetOwner() ); + Assert( pOwner ); + FormatViewModelAttachment( pOwner, *pOrigin, true ); } } else @@ -241,18 +246,6 @@ void C_VGuiScreen::SetAcceptsInput( bool acceptsinput ) } -//----------------------------------------------------------------------------- -// Purpose: -// Output : RenderGroup_t -//----------------------------------------------------------------------------- -RenderGroup_t C_VGuiScreen::GetRenderGroup() -{ - if ( IsAttachedToViewModel() ) - return RENDER_GROUP_VIEW_MODEL_TRANSLUCENT; - - return BaseClass::GetRenderGroup(); -} - //----------------------------------------------------------------------------- // Are we only visible to teammates? //----------------------------------------------------------------------------- @@ -335,7 +328,7 @@ void ScreenToWorld( int mousex, int mousey, float fov, float dist; Vector vpn, vup, vright; - float scaled_fov = ScaleFOVByWidthRatio( fov, engine->GetScreenAspectRatio() * 0.75f ); + float scaled_fov = ScaleFOVByWidthRatio( fov, engine->GetScreenAspectRatio( ScreenWidth(), ScreenHeight() ) * 0.75f ); c_x = ScreenWidth() / 2; c_y = ScreenHeight() / 2; @@ -410,7 +403,7 @@ void C_VGuiScreen::ClientThink( void ) return; // This will cause our panel to grab all input! - g_pClientMode->ActivateInGameVGuiContext( pPanel ); + GetClientMode()->ActivateInGameVGuiContext( pPanel ); // Convert (u,v) into (px,py) int px = (int)(u * m_nPixelWidth + 0.5f); @@ -451,7 +444,7 @@ void C_VGuiScreen::ClientThink( void ) SetNextClientThink( CLIENT_THINK_NEVER ); } - g_pClientMode->DeactivateInGameVGuiContext( ); + GetClientMode()->DeactivateInGameVGuiContext( ); } @@ -562,7 +555,7 @@ void C_VGuiScreen::DrawScreenOverlay() //----------------------------------------------------------------------------- // Draws the panel using a 3D transform... //----------------------------------------------------------------------------- -int C_VGuiScreen::DrawModel( int flags ) +int C_VGuiScreen::DrawModel( int flags, const RenderableInstance_t &instance ) { vgui::Panel *pPanel = m_PanelWrapper.GetPanel(); if (!pPanel || !IsActive()) @@ -609,11 +602,12 @@ bool C_VGuiScreen::IsVisibleToPlayer( C_BasePlayer *pViewingPlayer ) return true; } -bool C_VGuiScreen::IsTransparent( void ) +RenderableTranslucencyType_t C_VGuiScreen::ComputeTranslucencyType( void ) { - return (m_fScreenFlags & VGUI_SCREEN_TRANSPARENT) != 0; + return ( (m_fScreenFlags & VGUI_SCREEN_TRANSPARENT) != 0 ) ? RENDERABLE_IS_TRANSLUCENT : RENDERABLE_IS_OPAQUE; } + //----------------------------------------------------------------------------- // Purpose: Sometimes we only want a specific player to be able to input to a panel //----------------------------------------------------------------------------- @@ -835,7 +829,7 @@ bool CVGuiScreenPanel::Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitD C_VGuiScreen *screen = dynamic_cast< C_VGuiScreen * >( pInitData->m_pEntity ); if ( screen ) { - bool acceptsInput = pKeyValues->GetInt( "acceptsinput", 1 ) ? true : false; + bool acceptsInput = pKeyValues->GetBool( "acceptsinput", true ); screen->SetAcceptsInput( acceptsInput ); } } @@ -875,4 +869,4 @@ void CVGuiScreenPanel::OnCommand( const char *command) BaseClass::OnCommand(command); } -DECLARE_VGUI_SCREEN_FACTORY( CVGuiScreenPanel, "vgui_screen_panel" ); \ No newline at end of file +DECLARE_VGUI_SCREEN_FACTORY( CVGuiScreenPanel, "vgui_screen_panel" ); diff --git a/game/client/c_vguiscreen.h b/game/client/c_vguiscreen.h index d304f5c9e..3f0af1edf 100644 --- a/game/client/c_vguiscreen.h +++ b/game/client/c_vguiscreen.h @@ -1,9 +1,9 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // // $NoKeywords: $ -//=============================================================================// +//===========================================================================// #ifndef C_VGUISCREEN_H #define C_VGUISCREEN_H @@ -14,8 +14,8 @@ #include -#include "c_baseentity.h" -#include "panelmetaclassmgr.h" +#include "C_BaseEntity.h" +#include "PanelMetaClassMgr.h" class KeyValues; @@ -71,12 +71,12 @@ class C_VGuiScreen : public C_BaseEntity virtual void PreDataUpdate( DataUpdateType_t updateType ); virtual void OnDataChanged( DataUpdateType_t type ); - virtual int DrawModel( int flags ); + virtual int DrawModel( int flags, const RenderableInstance_t &instance ); virtual bool ShouldDraw( void ); virtual void ClientThink( ); virtual void GetAimEntOrigin( IClientEntity *pAttachedTo, Vector *pOrigin, QAngle *pAngles ); virtual bool IsVisibleToPlayer( C_BasePlayer *pViewingPlayer ); - virtual bool IsTransparent( void ); + virtual RenderableTranslucencyType_t ComputeTranslucencyType(); const char *PanelName() const; @@ -104,8 +104,6 @@ class C_VGuiScreen : public C_BaseEntity bool IsAttachedToViewModel() const; - virtual RenderGroup_t GetRenderGroup(); - bool AcceptsInput() const; void SetAcceptsInput( bool acceptsinput ); diff --git a/game/client/c_vote_controller.cpp b/game/client/c_vote_controller.cpp deleted file mode 100644 index b750c2a97..000000000 --- a/game/client/c_vote_controller.cpp +++ /dev/null @@ -1,189 +0,0 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// -// -// Purpose: CS's custom C_VoteController -// -// $NoKeywords: $ -//=============================================================================// -#include "cbase.h" -#include "c_vote_controller.h" -#include "shareddefs.h" -#include "hud.h" -#include "cdll_client_int.h" -#include "igameevents.h" -#include "hud_vote.h" - -// memdbgon must be the last include file in a .cpp file!!! -#include "tier0/memdbgon.h" - -IMPLEMENT_CLIENTCLASS_DT( C_VoteController, DT_VoteController, CVoteController ) - RecvPropInt( RECVINFO( m_iActiveIssueIndex ), 0, C_VoteController::RecvProxy_VoteType ), - RecvPropInt( RECVINFO( m_iOnlyTeamToVote ) ), - RecvPropArray3( RECVINFO_ARRAY( m_nVoteOptionCount ), RecvPropInt( RECVINFO( m_nVoteOptionCount[0] ), 0, C_VoteController::RecvProxy_VoteOption ) ), - RecvPropInt( RECVINFO( m_nPotentialVotes ) ), - RecvPropBool( RECVINFO( m_bIsYesNoVote ) ) -END_RECV_TABLE() - - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void C_VoteController::RecvProxy_VoteType( const CRecvProxyData *pData, void *pStruct, void *pOut ) -{ - C_VoteController *pMe = (C_VoteController *)pStruct; - if( memcmp( &pMe->m_iActiveIssueIndex, &pData->m_Value.m_Int, sizeof(pData->m_Value.m_Int)) == 0 ) - return; - - memcpy( &pMe->m_iActiveIssueIndex, &pData->m_Value.m_Int, sizeof(pData->m_Value.m_Int) ); - pMe->m_bTypeDirty = true; - - // Since the contents of a new vote are in three parts, we can't directly send an event to the Hud - // because we don't really know if we have all three parts yet. So we'll mark dirty, and our think - // can notice that and send the event. -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void C_VoteController::RecvProxy_VoteOption( const CRecvProxyData *pData, void *pStruct, void *pOut ) -{ - int index = pData->m_pRecvProp->GetOffset() / sizeof(int); - - size_t offset = offsetof( C_VoteController, m_nVoteOptionCount ); - C_VoteController *pMe = (C_VoteController *)((byte *)pStruct - offset ); - if( pMe->m_nVoteOptionCount[index] == pData->m_Value.m_Int ) - return; - - pMe->m_nVoteOptionCount[index] = pData->m_Value.m_Int; - pMe->m_bVotesDirty = true; - pMe->SetNextClientThink( gpGlobals->curtime + 0.001 ); -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -C_VoteController::C_VoteController() -{ - ResetData(); - - ListenForGameEvent( "vote_cast" ); -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -C_VoteController::~C_VoteController() -{ -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void C_VoteController::ResetData() -{ - m_iActiveIssueIndex = INVALID_ISSUE; - m_iOnlyTeamToVote = TEAM_INVALID; - for( int index = 0; index < MAX_VOTE_OPTIONS; index++ ) - { - m_nVoteOptionCount[index] = 0; - } - m_nPotentialVotes = 0; - m_bVotesDirty = false; - m_bTypeDirty = false; -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void C_VoteController::Spawn( void ) -{ - ResetData(); - BaseClass::Spawn(); - SetNextClientThink( gpGlobals->curtime ); -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void C_VoteController::ClientThink() -{ - BaseClass::ClientThink(); - - if( m_bTypeDirty ) - { - m_bTypeDirty = false; - m_bVotesDirty = true; - } - - if( m_bVotesDirty ) - { - if ( m_nPotentialVotes > 0 ) - { - // Currently hard-coded to MAX_VOTE_COUNT options per issue - DevMsg( "Votes: Option1 - %d, Option2 - %d, Option3 - %d, Option4 - %d, Option5 - %d\n", - m_nVoteOptionCount[0], m_nVoteOptionCount[1], m_nVoteOptionCount[2], m_nVoteOptionCount[3], m_nVoteOptionCount[4] ); - - IGameEvent *event = gameeventmanager->CreateEvent( "vote_changed" ); - if ( event ) - { - for ( int index = 0; index < MAX_VOTE_OPTIONS; index++ ) - { - char szOption[2]; - Q_snprintf( szOption, sizeof( szOption ), "%i", index + 1 ); - - char szVoteOption[13] = "vote_option"; - Q_strncat( szVoteOption, szOption, sizeof( szVoteOption ), COPY_ALL_CHARACTERS ); - - event->SetInt( szVoteOption, m_nVoteOptionCount[index] ); - } - event->SetInt( "potentialVotes", m_nPotentialVotes ); - gameeventmanager->FireEventClientSide( event ); - } - } - - m_bVotesDirty = false; - } - - SetNextClientThink( gpGlobals->curtime + 0.5f ); -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void C_VoteController::FireGameEvent( IGameEvent *event ) -{ - CHudVote *pHudVote = GET_HUDELEMENT( CHudVote ); - if ( pHudVote && pHudVote->IsVisible() ) - { - const char *eventName = event->GetName(); - if ( !eventName ) - return; - - C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer(); - if ( !pLocalPlayer ) - return; - - int team = event->GetInt( "team", TEAM_UNASSIGNED ); - if ( team > TEAM_UNASSIGNED && team != pLocalPlayer->GetTeamNumber() ) - return; - - if ( FStrEq( eventName, "vote_cast" ) ) - { - if ( m_bIsYesNoVote ) - { - int vote_option = event->GetInt( "vote_option", TEAM_UNASSIGNED ); - if( vote_option == VOTE_OPTION2 ) - { - pLocalPlayer->EmitSound( "Vote.Cast.No" ); - } - else if( vote_option == VOTE_OPTION1 ) - { - pLocalPlayer->EmitSound( "Vote.Cast.Yes" ); - } - } - else - { - pLocalPlayer->EmitSound( "Vote.Cast.Yes" ); - } - } - } -} diff --git a/game/client/c_vote_controller.h b/game/client/c_vote_controller.h deleted file mode 100644 index 5c1a4c5e8..000000000 --- a/game/client/c_vote_controller.h +++ /dev/null @@ -1,46 +0,0 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// -// -// Purpose: Client VoteController -// -// $NoKeywords: $ -//=============================================================================// - -#ifndef C_VoteController_H -#define C_VoteController_H -#ifdef _WIN32 -#pragma once -#endif - -#include "shareddefs.h" -#include "GameEventListener.h" - -class C_VoteController : public C_BaseEntity, public CGameEventListener -{ - DECLARE_CLASS( C_VoteController, C_BaseEntity ); -public: - DECLARE_CLIENTCLASS(); - - C_VoteController(); - virtual ~C_VoteController(); - - virtual void Spawn( void ); - virtual void ClientThink( void ); - - static void RecvProxy_VoteType( const CRecvProxyData *pData, void *pStruct, void *pOut ); - static void RecvProxy_VoteOption( const CRecvProxyData *pData, void *pStruct, void *pOut ); - - void FireGameEvent( IGameEvent *event ); -protected: - void ResetData(); - - int m_iActiveIssueIndex; - int m_iOnlyTeamToVote; - int m_nVoteOptionCount[MAX_VOTE_OPTIONS]; - int m_iVoteChoiceIndex; - int m_nPotentialVotes; - bool m_bVotesDirty; // Received a vote, so remember to tell the Hud - bool m_bTypeDirty; // Vote type changed, so show or hide the Hud - bool m_bIsYesNoVote; -}; - -#endif // C_VoteController_H diff --git a/game/client/c_weapon__stubs.h b/game/client/c_weapon__stubs.h index 287211b90..edd333dca 100644 --- a/game/client/c_weapon__stubs.h +++ b/game/client/c_weapon__stubs.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // @@ -28,7 +28,7 @@ public: \ DECLARE_PREDICTABLE(); \ DECLARE_CLIENTCLASS(); \ - C_##className() = default; \ + C_##className() {}; \ private: \ C_##className( const C_##className & ); \ }; \ diff --git a/game/client/c_world.cpp b/game/client/c_world.cpp index 3ae6bdccf..61dd19225 100644 --- a/game/client/c_world.cpp +++ b/game/client/c_world.cpp @@ -1,20 +1,17 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ -//=============================================================================// +//===========================================================================// #include "cbase.h" #include "c_world.h" #include "ivmodemanager.h" -#include "activitylist.h" #include "decals.h" #include "engine/ivmodelinfo.h" #include "ivieweffects.h" #include "shake.h" -#include "eventlist.h" -// NVNT haptic include for notification of world precache -#include "haptics/haptic_utils.h" +#include "precache_register.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -59,6 +56,7 @@ BEGIN_RECV_TABLE( C_World, DT_World ) RecvPropFloat(RECVINFO(m_flMinPropScreenSpaceWidth)), RecvPropString(RECVINFO(m_iszDetailSpriteMaterial)), RecvPropInt(RECVINFO(m_bColdWorld)), + RecvPropInt(RECVINFO(m_iTimeOfDay)), END_RECV_TABLE() @@ -73,15 +71,12 @@ C_World::~C_World( void ) bool C_World::Init( int entnum, int iSerialNum ) { m_flWaveHeight = 0.0f; - ActivityList_Init(); - EventList_Init(); return BaseClass::Init( entnum, iSerialNum ); } void C_World::Release() { - ActivityList_Free(); Term(); } @@ -110,7 +105,11 @@ void C_World::OnDataChanged( DataUpdateType_t updateType ) sf.duration = (float)(1<Fade( sf ); + FOR_EACH_VALID_SPLITSCREEN_PLAYER( hh ) + { + ACTIVE_SPLITSCREEN_PLAYER_GUARD( hh ); + GetViewEffects()->Fade( sf ); + } } OcclusionParams_t params; @@ -122,61 +121,41 @@ void C_World::OnDataChanged( DataUpdateType_t updateType ) } } -void C_World::RegisterSharedActivities( void ) -{ - ActivityList_RegisterSharedActivities(); - EventList_RegisterSharedEvents(); -} - // ----------------------------------------- // Sprite Index info // ----------------------------------------- -short g_sModelIndexLaser; // holds the index for the laser beam -const char *g_pModelNameLaser = "sprites/laserbeam.vmt"; -short g_sModelIndexLaserDot; // holds the index for the laser beam dot -short g_sModelIndexFireball; // holds the index for the fireball -short g_sModelIndexSmoke; // holds the index for the smoke cloud -short g_sModelIndexWExplosion; // holds the index for the underwater explosion -short g_sModelIndexBubbles; // holds the index for the bubbles model -short g_sModelIndexBloodDrop; // holds the sprite index for the initial blood -short g_sModelIndexBloodSpray; // holds the sprite index for splattered blood +int g_sModelIndexLaser; // holds the index for the laser beam +int g_sModelIndexLaserDot; // holds the index for the laser beam dot +int g_sModelIndexFireball; // holds the index for the fireball +int g_sModelIndexSmoke; // holds the index for the smoke cloud +int g_sModelIndexWExplosion; // holds the index for the underwater explosion +int g_sModelIndexBubbles; // holds the index for the bubbles model +int g_sModelIndexBloodDrop; // holds the sprite index for the initial blood +int g_sModelIndexBloodSpray; // holds the sprite index for splattered blood //----------------------------------------------------------------------------- -// Purpose: Precache global weapon sounds +// Purpose: Precache global weapon resources //----------------------------------------------------------------------------- +PRECACHE_REGISTER_BEGIN( GLOBAL, WeaponSprites ) + PRECACHE_INDEX( MODEL, "sprites/zerogxplode.vmt", g_sModelIndexFireball ) + PRECACHE_INDEX( MODEL, "sprites/WXplo1.vmt", g_sModelIndexWExplosion ) + PRECACHE_INDEX( MODEL, "sprites/steam1.vmt", g_sModelIndexSmoke ) + PRECACHE_INDEX( MODEL, "sprites/bubble.vmt", g_sModelIndexBubbles ) + PRECACHE_INDEX( MODEL, "sprites/bloodspray.vmt", g_sModelIndexBloodSpray ) + PRECACHE_INDEX( MODEL, "sprites/blood.vmt", g_sModelIndexBloodDrop ) + PRECACHE_INDEX( MODEL, "sprites/laserbeam.vmt", g_sModelIndexLaser ) + PRECACHE_INDEX( MODEL, "sprites/laserdot.vmt", g_sModelIndexLaserDot ) +PRECACHE_REGISTER_END() + void W_Precache(void) { PrecacheFileWeaponInfoDatabase( filesystem, g_pGameRules->GetEncryptionKey() ); - - g_sModelIndexFireball = modelinfo->GetModelIndex ("sprites/zerogxplode.vmt");// fireball - g_sModelIndexWExplosion = modelinfo->GetModelIndex ("sprites/WXplo1.vmt");// underwater fireball - g_sModelIndexSmoke = modelinfo->GetModelIndex ("sprites/steam1.vmt");// smoke - g_sModelIndexBubbles = modelinfo->GetModelIndex ("sprites/bubble.vmt");//bubbles - g_sModelIndexBloodSpray = modelinfo->GetModelIndex ("sprites/bloodspray.vmt"); // initial blood - g_sModelIndexBloodDrop = modelinfo->GetModelIndex ("sprites/blood.vmt"); // splattered blood - g_sModelIndexLaser = modelinfo->GetModelIndex( (char *)g_pModelNameLaser ); - g_sModelIndexLaserDot = modelinfo->GetModelIndex("sprites/laserdot.vmt"); } void C_World::Precache( void ) { - // UNDONE: Make most of these things server systems or precache_registers - // ================================================= - // Activities - // ================================================= - ActivityList_Free(); - EventList_Free(); - - RegisterSharedActivities(); - // Get weapon precaches W_Precache(); - - // Call all registered precachers. - CPrecacheRegister::Precache(); - // NVNT notify system of precache - if (haptics) - haptics->WorldPrecache(); } void C_World::Spawn( void ) diff --git a/game/client/c_world.h b/game/client/c_world.h index 3cdbd6a02..128f2f8e1 100644 --- a/game/client/c_world.h +++ b/game/client/c_world.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // @@ -56,9 +56,9 @@ class C_World : public C_BaseEntity float m_flMinPropScreenSpaceWidth; float m_flMaxPropScreenSpaceWidth; bool m_bColdWorld; + int m_iTimeOfDay; private: - void RegisterSharedActivities( void ); char m_iszDetailSpriteMaterial[MAX_DETAIL_SPRITE_MATERIAL_NAME_LENGTH]; }; diff --git a/game/client/camomaterialproxy.cpp b/game/client/camomaterialproxy.cpp index 77828c897..1e6527b86 100644 --- a/game/client/camomaterialproxy.cpp +++ b/game/client/camomaterialproxy.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // @@ -10,15 +10,16 @@ // identifier was truncated to '255' characters in the debug information #pragma warning(disable: 4786) -#include "proxyentity.h" -#include "materialsystem/imaterialvar.h" -#include "materialsystem/itexture.h" -#include "bitmap/tgaloader.h" +#include "ProxyEntity.h" +#include "materialsystem/IMaterialVar.h" +#include "materialsystem/ITexture.h" +#include "bitmap/TGALoader.h" #include "view.h" #include "datacache/idatacache.h" -#include "materialsystem/imaterial.h" +#include "materialsystem/IMaterial.h" #include "vtf/vtf.h" +#include "imaterialproxydict.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -299,20 +300,20 @@ void CCamoMaterialProxy::GetColors( Vector &diffuseColor, Vector &baseColor, int #endif #if 0 - float max; - max = diffuseColor[0]; - if( diffuseColor[1] > max ) + float MAX; + MAX = diffuseColor[0]; + if( diffuseColor[1] > MAX ) { - max = diffuseColor[1]; + MAX = diffuseColor[1]; } - if( diffuseColor[2] > max ) + if( diffuseColor[2] > MAX ) { - max = diffuseColor[2]; + MAX = diffuseColor[2]; } - if( max > 1.0f ) + if( MAX > 1.0f ) { - max = 1.0f / max; - diffuseColor = diffuseColor * max; + MAX = 1.0f / MAX; + diffuseColor = diffuseColor * MAX; } #else if( diffuseColor[0] > 1.0f ) @@ -579,4 +580,4 @@ IMaterial *CCamoMaterialProxy::GetMaterial() return m_pMaterial; } -EXPOSE_INTERFACE( CCamoMaterialProxy, IMaterialProxy, "Camo" IMATERIAL_PROXY_INTERFACE_VERSION ); +EXPOSE_MATERIAL_PROXY( CCamoMaterialProxy, Camo ); diff --git a/game/client/cbase.h b/game/client/cbase.h index 57e3260bd..a6200db2d 100644 --- a/game/client/cbase.h +++ b/game/client/cbase.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // @@ -16,26 +16,28 @@ struct studiohdr_t; #include #include -#include -#include +#include "tier0/platform.h" +#include "tier0/dbg.h" +#include "vprof.h" -#include -#include -#include +#include "tier1/strtools.h" +#include "vstdlib/random.h" +#include "tier1/utlvector.h" -#include +#include "const.h" #include "string_t.h" // These two have to be included very early -#include -#include +#include "predictableid.h" +#include "predictable_entity.h" #include "cdll_util.h" -#include +#include "util_shared.h" -#include -#include +#include "icvar.h" +#include "sharedvar.h" +#include "baseentity_shared.h" // This is a precompiled header. Include a bunch of common stuff. @@ -49,10 +51,13 @@ struct studiohdr_t; #include "c_baseplayer.h" #include "itempents.h" #include "vphysics_interface.h" +//#include "vphysics2_interface.h" #include "physics.h" #include "c_recipientfilter.h" #include "cdll_client_int.h" #include "worldsize.h" #include "engine/ivmodelinfo.h" +#include "npcevent.h" +#include "debugoverlay_shared.h" #endif // CBASE_H diff --git a/game/client/cdll_bounded_cvars.cpp b/game/client/cdll_bounded_cvars.cpp index 0928b7748..26e62c642 100644 --- a/game/client/cdll_bounded_cvars.cpp +++ b/game/client/cdll_bounded_cvars.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // @@ -10,6 +10,9 @@ #include "convar_serverbounded.h" #include "tier0/icommandline.h" +// NOTE: This has to be the last file included! +#include "tier0/memdbgon.h" + bool g_bForceCLPredictOff = false; @@ -23,10 +26,10 @@ class CBoundedCvar_Predict : public ConVar_ServerBounded CBoundedCvar_Predict() : ConVar_ServerBounded( "cl_predict", "1.0", -#if defined(DOD_DLL) || defined(CSTRIKE_DLL) - FCVAR_USERINFO | FCVAR_CHEAT, +#ifdef INFESTED_DLL + FCVAR_USERINFO, #else - FCVAR_USERINFO | FCVAR_NOT_CONNECTED, + FCVAR_USERINFO | FCVAR_CHEAT, #endif "Perform client side prediction." ) { @@ -38,7 +41,7 @@ class CBoundedCvar_Predict : public ConVar_ServerBounded if ( g_bForceCLPredictOff ) return 0; - static const ConVar *pClientPredict = g_pCVar->FindVar( "sv_client_predict" ); + static const ConVar *pClientPredict = dynamic_cast< const ConVar* >( g_pCVar->FindCommandBase( "sv_client_predict" ) ); if ( pClientPredict && pClientPredict->GetInt() != -1 ) { // Ok, the server wants to control this value. @@ -66,15 +69,15 @@ class CBoundedCvar_InterpRatio : public ConVar_ServerBounded CBoundedCvar_InterpRatio() : ConVar_ServerBounded( "cl_interp_ratio", "2.0", - FCVAR_USERINFO | FCVAR_NOT_CONNECTED, + FCVAR_USERINFO, "Sets the interpolation amount (final amount is cl_interp_ratio / cl_updaterate)." ) { } virtual float GetFloat() const { - static const ConVar *pMin = g_pCVar->FindVar( "sv_client_min_interp_ratio" ); - static const ConVar *pMax = g_pCVar->FindVar( "sv_client_max_interp_ratio" ); + static const ConVar *pMin = dynamic_cast< const ConVar* >( g_pCVar->FindCommandBase( "sv_client_min_interp_ratio" ) ); + static const ConVar *pMax = dynamic_cast< const ConVar* >( g_pCVar->FindCommandBase( "sv_client_max_interp_ratio" ) ); if ( pMin && pMax && pMin->GetFloat() != -1 ) { return clamp( GetBaseFloatValue(), pMin->GetFloat(), pMax->GetFloat() ); @@ -100,15 +103,15 @@ class CBoundedCvar_Interp : public ConVar_ServerBounded CBoundedCvar_Interp() : ConVar_ServerBounded( "cl_interp", "0.1", - FCVAR_USERINFO | FCVAR_NOT_CONNECTED, + FCVAR_USERINFO, "Sets the interpolation amount (bounded on low side by server interp ratio settings).", true, 0.0f, true, 0.5f ) { } virtual float GetFloat() const { - static const ConVar *pUpdateRate = g_pCVar->FindVar( "cl_updaterate" ); - static const ConVar *pMin = g_pCVar->FindVar( "sv_client_min_interp_ratio" ); + static const ConVar_ServerBounded *pUpdateRate = dynamic_cast< const ConVar_ServerBounded* >( g_pCVar->FindCommandBase( "cl_updaterate" ) ); + static const ConVar *pMin = dynamic_cast< const ConVar* >( g_pCVar->FindCommandBase( "sv_client_min_interp_ratio" ) ); if ( pUpdateRate && pMin && pMin->GetFloat() != -1 ) { return MAX( GetBaseFloatValue(), pMin->GetFloat() / pUpdateRate->GetFloat() ); @@ -125,7 +128,7 @@ ConVar_ServerBounded *cl_interp = &cl_interp_var; float GetClientInterpAmount() { - static const ConVar *pUpdateRate = g_pCVar->FindVar( "cl_updaterate" ); + static const ConVar_ServerBounded *pUpdateRate = dynamic_cast< const ConVar_ServerBounded* >( g_pCVar->FindCommandBase( "cl_updaterate" ) ); if ( pUpdateRate ) { // #define FIXME_INTERP_RATIO diff --git a/game/client/cdll_bounded_cvars.h b/game/client/cdll_bounded_cvars.h index 1b08f007c..a94bfc27b 100644 --- a/game/client/cdll_bounded_cvars.h +++ b/game/client/cdll_bounded_cvars.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: Provides access to cvars that are bounded in the client DLL. // diff --git a/game/client/cdll_client_int.cpp b/game/client/cdll_client_int.cpp index ab16bd7c3..9b0c26ec6 100644 --- a/game/client/cdll_client_int.cpp +++ b/game/client/cdll_client_int.cpp @@ -1,9 +1,8 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//======= Copyright (c) 1996-2009, Valve Corporation, All rights reserved. ====== // -// Purpose: // -// $NoKeywords: $ -//===========================================================================// +//=============================================================================== + #include "cbase.h" #include #include "vgui_int.h" @@ -16,7 +15,6 @@ #include "clientsideeffects.h" #include "particlemgr.h" #include "steam/steam_api.h" -#include "initializer.h" #include "smoke_fog_overlay.h" #include "view.h" #include "ienginevgui.h" @@ -24,24 +22,23 @@ #include "enginesprite.h" #include "networkstringtable_clientdll.h" #include "voice_status.h" -#include "filesystem.h" +#include "FileSystem.h" #include "c_te_legacytempents.h" #include "c_rope.h" -#include "engine/ishadowmgr.h" +#include "engine/IShadowMgr.h" #include "engine/IStaticPropMgr.h" #include "hud_basechat.h" #include "hud_crosshair.h" #include "view_shared.h" #include "env_wind_shared.h" #include "detailobjectsystem.h" -#include "clienteffectprecachesystem.h" -#include "soundenvelope.h" +#include "soundEnvelope.h" #include "c_basetempentity.h" #include "materialsystem/imaterialsystemstub.h" -#include "VGuiMatSurface/IMatSystemSurface.h" +#include "vguimatsurface/IMatSystemSurface.h" #include "materialsystem/imaterialsystemhardwareconfig.h" #include "c_soundscape.h" -#include "engine/ivdebugoverlay.h" +#include "engine/IVDebugOverlay.h" #include "vguicenterprint.h" #include "iviewrender_beams.h" #include "tier0/vprof.h" @@ -51,7 +48,7 @@ #include "usermessages.h" #include "gamestringpool.h" #include "c_user_message_register.h" -#include "IGameUIFuncs.h" +#include "igameuifuncs.h" #include "saverestoretypes.h" #include "saverestore.h" #include "physics_saverestore.h" @@ -60,12 +57,14 @@ #include "datacache/imdlcache.h" #include "kbutton.h" #include "tier0/icommandline.h" +#include "vstdlib/jobthread.h" #include "gamerules_register.h" +#include "game/client/iviewport.h" #include "vgui_controls/AnimationController.h" #include "bitmap/tgawriter.h" #include "c_world.h" #include "perfvisualbenchmark.h" -#include "SoundEmitterSystem/isoundemittersystembase.h" +#include "soundemittersystem/isoundemittersystembase.h" #include "hud_closecaption.h" #include "colorcorrectionmgr.h" #include "physpropclientside.h" @@ -82,94 +81,63 @@ #include "inputsystem/iinputsystem.h" #include "appframework/IAppSystemGroup.h" #include "scenefilecache/ISceneFileCache.h" -#include "tier2/tier2dm.h" #include "tier3/tier3.h" +#include "avi/iavi.h" #include "ihudlcd.h" #include "toolframework_client.h" #include "hltvcamera.h" #if defined( REPLAY_ENABLED ) -#include "replay/replaycamera.h" -#include "replay/replay_ragdoll.h" +#include "replaycamera.h" +#include "replay_ragdoll.h" +#include "replay_ragdoll.h" #include "qlimits.h" -#include "replay/replay.h" -#include "replay/ireplaysystem.h" -#include "replay/iclientreplay.h" -#include "replay/ienginereplay.h" -#include "replay/ireplaymanager.h" -#include "replay/ireplayscreenshotmanager.h" -#include "replay/iclientreplaycontext.h" -#include "replay/vgui/replayconfirmquitdlg.h" -#include "replay/vgui/replaybrowsermainpanel.h" -#include "replay/vgui/replayinputpanel.h" -#include "replay/vgui/replayperformanceeditor.h" +#include "engine/ireplayhistorymanager.h" #endif -#include "vgui/ILocalize.h" -#include "vgui/IVGui.h" #include "ixboxsystem.h" -#include "ipresence.h" -#include "engine/imatchmaking.h" +#include "matchmaking/imatchframework.h" #include "cdll_bounded_cvars.h" #include "matsys_controls/matsyscontrols.h" -#include "gamestats.h" -#include "particle_parse.h" -#if defined( TF_CLIENT_DLL ) -#include "rtime.h" -#include "tf_hud_disconnect_prompt.h" -#include "../engine/audio/public/sound.h" -#include "tf_shared_content_manager.h" +#include "GameStats.h" +#include "videocfg/videocfg.h" +#include "tier2/tier2_logging.h" +#include "vscript/ivscript.h" +#include "activitylist.h" +#include "eventlist.h" +#ifdef GAMEUI_UISYSTEM2_ENABLED +#include "gameui.h" #endif -#include "clientsteamcontext.h" -#include "renamed_recvtable_compat.h" -#include "mouthinfo.h" -#include "sourcevr/isourcevirtualreality.h" -#include "client_virtualreality.h" -#include "mumble.h" - -// NVNT includes -#include "hud_macros.h" -#include "haptics/ihaptics.h" -#include "haptics/haptic_utils.h" -#include "haptics/haptic_msgs.h" - -#if defined( TF_CLIENT_DLL ) -#include "abuse_report.h" -#endif - -#ifdef USES_ECON_ITEMS -#include "econ_item_system.h" -#endif // USES_ECON_ITEMS +#ifdef GAMEUI_EMBEDDED -#if defined( TF_CLIENT_DLL ) -#include "econ/tool_items/custom_texture_cache.h" +#if defined( SWARM_DLL ) +#include "swarm/gameui/swarm/basemodpanel.h" +#else +#error "GAMEUI_EMBEDDED" #endif - -#ifdef WORKSHOP_IMPORT_ENABLED -#include "fbxsystem/fbxsystem.h" #endif -#include "touch.h" +#ifdef DEMOPOLISH_ENABLED +#include "demo_polish/demo_polish.h" +#endif -extern vgui::IInputInternal *g_InputInternal; +#include "imaterialproxydict.h" +#include "tier0/miniprofiler.h" +#include "../../engine/iblackbox.h" +#include "c_rumble.h" +#include "viewpostprocess.h" -//============================================================================= -// HPE_BEGIN -// [dwenger] Necessary for stats display -//============================================================================= -#include "achievements_and_stats_interface.h" -//============================================================================= -// HPE_END -//============================================================================= +#ifdef INFESTED_PARTICLES +#include "c_asw_generic_emitter.h" +#endif +#ifdef INFESTED_DLL +#include "missionchooser/iasw_mission_chooser.h" -#ifdef PORTAL -#include "PortalRender.h" #endif -#ifdef SIXENSE -#include "sixense/in_sixense.h" -#endif +#include "tier1/UtlDict.h" +#include "keybindinglistener.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -197,57 +165,35 @@ static CGaussianRandomStream s_GaussianRandomStream; CGaussianRandomStream *randomgaussian = &s_GaussianRandomStream; ISharedGameRules *sharedgamerules = NULL; IEngineTrace *enginetrace = NULL; +IFileLoggingListener *filelogginglistener = NULL; IGameUIFuncs *gameuifuncs = NULL; IGameEventManager2 *gameeventmanager = NULL; ISoundEmitterSystemBase *soundemitterbase = NULL; IInputSystem *inputsystem = NULL; ISceneFileCache *scenefilecache = NULL; IXboxSystem *xboxsystem = NULL; // Xbox 360 only -IMatchmaking *matchmaking = NULL; +IAvi *avi = NULL; +IBik *bik = NULL; IUploadGameStats *gamestatsuploader = NULL; -IClientReplayContext *g_pClientReplayContext = NULL; +IBlackBox *blackboxrecorder = NULL; +#ifdef INFESTED_DLL +IASW_Mission_Chooser *missionchooser = NULL; +#endif #if defined( REPLAY_ENABLED ) -IReplayManager *g_pReplayManager = NULL; -IReplayMovieManager *g_pReplayMovieManager = NULL; -IReplayScreenshotManager *g_pReplayScreenshotManager = NULL; -IReplayPerformanceManager *g_pReplayPerformanceManager = NULL; -IReplayPerformanceController *g_pReplayPerformanceController = NULL; -IEngineReplay *g_pEngineReplay = NULL; -IEngineClientReplay *g_pEngineClientReplay = NULL; -IReplaySystem *g_pReplay = NULL; +IReplayHistoryManager *g_pReplayHistoryManager = NULL; #endif -IHaptics* haptics = NULL;// NVNT haptics system interface singleton - -//============================================================================= -// HPE_BEGIN -// [dwenger] Necessary for stats display -//============================================================================= - -AchievementsAndStatsInterface* g_pAchievementsAndStatsInterface = NULL; - -//============================================================================= -// HPE_END -//============================================================================= +IScriptManager *scriptmanager = NULL; IGameSystem *SoundEmitterSystem(); IGameSystem *ToolFrameworkClientSystem(); +IViewRender *GetViewRenderInstance(); -// Engine player info, no game related infos here -BEGIN_BYTESWAP_DATADESC( player_info_s ) - DEFINE_ARRAY( name, FIELD_CHARACTER, MAX_PLAYER_NAME_LENGTH ), - DEFINE_FIELD( userID, FIELD_INTEGER ), - DEFINE_ARRAY( guid, FIELD_CHARACTER, SIGNED_GUID_LEN + 1 ), - DEFINE_FIELD( friendsID, FIELD_INTEGER ), - DEFINE_ARRAY( friendsName, FIELD_CHARACTER, MAX_PLAYER_NAME_LENGTH ), - DEFINE_FIELD( fakeplayer, FIELD_BOOLEAN ), - DEFINE_FIELD( ishltv, FIELD_BOOLEAN ), -#if defined( REPLAY_ENABLED ) - DEFINE_FIELD( isreplay, FIELD_BOOLEAN ), -#endif - DEFINE_ARRAY( customFiles, FIELD_INTEGER, MAX_CUSTOM_FILES ), - DEFINE_FIELD( filesDownloaded, FIELD_INTEGER ), -END_BYTESWAP_DATADESC() +static CSteamAPIContext g_SteamAPIContext; +CSteamAPIContext *steamapicontext = &g_SteamAPIContext; + + +bool g_bEngineIsHLTV = false; static bool g_bRequestCacheUsedMaterials = false; void RequestCacheUsedMaterials() @@ -267,19 +213,27 @@ void ProcessCacheUsedMaterials() } } +static bool g_bHeadTrackingEnabled = false; + +bool IsHeadTrackingEnabled() +{ +#if defined( HL2_CLIENT_DLL ) + return g_bHeadTrackingEnabled; +#else + return false; +#endif +} + +void VGui_ClearVideoPanels(); + // String tables INetworkStringTable *g_pStringTableParticleEffectNames = NULL; +INetworkStringTable *g_pStringTableExtraParticleFiles = NULL; INetworkStringTable *g_StringTableEffectDispatch = NULL; INetworkStringTable *g_StringTableVguiScreen = NULL; INetworkStringTable *g_pStringTableMaterials = NULL; INetworkStringTable *g_pStringTableInfoPanel = NULL; INetworkStringTable *g_pStringTableClientSideChoreoScenes = NULL; -INetworkStringTable *g_pStringTableServerMapCycle = NULL; - -#ifdef TF_CLIENT_DLL -INetworkStringTable *g_pStringTableServerPopFiles = NULL; -INetworkStringTable *g_pStringTableServerMapCycleMvM = NULL; -#endif static CGlobalVarsBase dummyvars( true ); // So stuff that might reference gpGlobals during DLL initialization won't have a NULL pointer. @@ -287,9 +241,6 @@ static CGlobalVarsBase dummyvars( true ); CGlobalVarsBase *gpGlobals = &dummyvars; class CHudChat; class CViewRender; -extern CViewRender g_DefaultViewRender; - -extern void StopAllRumbleEffects( void ); static C_BaseEntityClassList *s_pClassLists = NULL; C_BaseEntityClassList::C_BaseEntityClassList() @@ -305,7 +256,7 @@ C_BaseEntityClassList::~C_BaseEntityClassList() class CDataChangedEvent { public: - CDataChangedEvent() = default; + CDataChangedEvent() {} CDataChangedEvent( IClientNetworkable *ent, DataUpdateType_t updateType, int *pStoredEvent ) { m_pEntity = ent; @@ -333,18 +284,176 @@ static ConVar s_CV_ShowParticleCounts("showparticlecounts", "0", 0, "Display num static ConVar s_cl_team("cl_team", "default", FCVAR_USERINFO|FCVAR_ARCHIVE, "Default team when joining a game"); static ConVar s_cl_class("cl_class", "default", FCVAR_USERINFO|FCVAR_ARCHIVE, "Default class when joining a game"); -#ifdef HL1MP_CLIENT_DLL -static ConVar s_cl_load_hl1_content("cl_load_hl1_content", "0", FCVAR_ARCHIVE, "Mount the content from Half-Life: Source if possible"); -#endif - - // Physics system bool g_bLevelInitialized; bool g_bTextMode = false; -class IClientPurchaseInterfaceV2 *g_pClientPurchaseInterface = (class IClientPurchaseInterfaceV2 *)(&g_bTextMode + 156); static ConVar *g_pcv_ThreadMode = NULL; +// implements ACTIVE_SPLITSCREEN_PLAYER_GUARD (cdll_client_int.h) +CSetActiveSplitScreenPlayerGuard::CSetActiveSplitScreenPlayerGuard( char const *pchContext, int nLine, int slot, int nOldSlot, bool bSetVguiScreenSize ) : + CVGuiScreenSizeSplitScreenPlayerGuard( bSetVguiScreenSize, slot, nOldSlot ) +{ + if ( nOldSlot == slot && engine->IsLocalPlayerResolvable() ) + { + m_bChanged = false; + return; + } + + m_bChanged = true; + m_pchContext = pchContext; + m_nLine = nLine; + m_nSaveSlot = engine->SetActiveSplitScreenPlayerSlot( slot >= 0 ? slot : 0 ); + m_bSaveGetLocalPlayerAllowed = engine->SetLocalPlayerIsResolvable( pchContext, nLine, slot >= 0 ); +} + +CSetActiveSplitScreenPlayerGuard::CSetActiveSplitScreenPlayerGuard( char const *pchContext, int nLine, C_BaseEntity *pEntity, int nOldSlot, bool bSetVguiScreenSize ) : + CVGuiScreenSizeSplitScreenPlayerGuard( bSetVguiScreenSize, pEntity, nOldSlot ) +{ + int slot = C_BasePlayer::GetSplitScreenSlotForPlayer( pEntity ); + if ( slot == -1 ) + { + m_bChanged = false; + return; + } + + if ( nOldSlot == slot && engine->IsLocalPlayerResolvable()) + { + m_bChanged = false; + return; + } + + m_bChanged = true; + m_pchContext = pchContext; + m_nLine = nLine; + m_nSaveSlot = engine->SetActiveSplitScreenPlayerSlot( slot >= 0 ? slot : 0 ); + m_bSaveGetLocalPlayerAllowed = engine->SetLocalPlayerIsResolvable( pchContext, nLine, slot >= 0 ); +} + + +CSetActiveSplitScreenPlayerGuard::~CSetActiveSplitScreenPlayerGuard() +{ + if ( !m_bChanged ) + return; + + engine->SetActiveSplitScreenPlayerSlot( m_nSaveSlot ); + engine->SetLocalPlayerIsResolvable( m_pchContext, m_nLine, m_bSaveGetLocalPlayerAllowed ); +} + +static CUtlRBTree< const char *, int > g_Hacks( 0, 0, DefLessFunc( char const * ) ); + +CON_COMMAND( cl_dumpsplithacks, "Dump split screen workarounds." ) +{ + for ( int i = g_Hacks.FirstInorder(); i != g_Hacks.InvalidIndex(); i = g_Hacks.NextInorder( i ) ) + { + Msg( "%s\n", g_Hacks[ i ] ); + } +} + +CHackForGetLocalPlayerAccessAllowedGuard::CHackForGetLocalPlayerAccessAllowedGuard( char const *pszContext, bool bOldState ) +{ + if ( bOldState ) + { + m_bChanged = false; + return; + } + + m_bChanged = true; + m_pszContext = pszContext; + if ( g_Hacks.Find( pszContext ) == g_Hacks.InvalidIndex() ) + { + g_Hacks.Insert( pszContext ); + } + m_bSaveGetLocalPlayerAllowed = engine->SetLocalPlayerIsResolvable( pszContext, 0, true ); +} + +CHackForGetLocalPlayerAccessAllowedGuard::~CHackForGetLocalPlayerAccessAllowedGuard() +{ + if ( !m_bChanged ) + return; + engine->SetLocalPlayerIsResolvable( m_pszContext, 0, m_bSaveGetLocalPlayerAllowed ); +} + +CVGuiScreenSizeSplitScreenPlayerGuard::CVGuiScreenSizeSplitScreenPlayerGuard( bool bActive, int slot, int nOldSlot ) +{ + if ( !bActive ) + { + m_bNoRestore = true; + return; + } + + if ( vgui::surface()->IsScreenSizeOverrideActive() && nOldSlot == slot && engine->IsLocalPlayerResolvable() ) + { + m_bNoRestore = true; + return; + } + + m_bNoRestore = false; + vgui::surface()->GetScreenSize( m_nOldSize[ 0 ], m_nOldSize[ 1 ] ); + int x, y, w, h; + VGui_GetHudBounds( slot >= 0 ? slot : 0, x, y, w, h ); + m_bOldSetting = vgui::surface()->ForceScreenSizeOverride( true, w, h ); +} + +CVGuiScreenSizeSplitScreenPlayerGuard::CVGuiScreenSizeSplitScreenPlayerGuard( bool bActive, C_BaseEntity *pEntity, int nOldSlot ) +{ + if ( !bActive ) + { + m_bNoRestore = true; + return; + } + + int slot = C_BasePlayer::GetSplitScreenSlotForPlayer( pEntity ); + if ( vgui::surface()->IsScreenSizeOverrideActive() && nOldSlot == slot && engine->IsLocalPlayerResolvable() ) + { + m_bNoRestore = true; + return; + } + + m_bNoRestore = false; + vgui::surface()->GetScreenSize( m_nOldSize[ 0 ], m_nOldSize[ 1 ] ); + // Get size for this user + int x, y, w, h; + VGui_GetHudBounds( slot >= 0 ? slot : 0, x, y, w, h ); + m_bOldSetting = vgui::surface()->ForceScreenSizeOverride( true, w, h ); +} + +CVGuiScreenSizeSplitScreenPlayerGuard::~CVGuiScreenSizeSplitScreenPlayerGuard() +{ + if ( m_bNoRestore ) + return; + vgui::surface()->ForceScreenSizeOverride( m_bOldSetting, m_nOldSize[ 0 ], m_nOldSize[ 1 ] ); +} + +CVGuiAbsPosSplitScreenPlayerGuard::CVGuiAbsPosSplitScreenPlayerGuard( int slot, int nOldSlot, bool bInvert /*=false*/ ) +{ + if ( nOldSlot == slot && engine->IsLocalPlayerResolvable() && vgui::surface()->IsScreenPosOverrideActive() ) + { + m_bNoRestore = true; + return; + } + + m_bNoRestore = false; + + // Get size for this user + int x, y, w, h; + VGui_GetHudBounds( slot, x, y, w, h ); + if ( bInvert ) + { + x = -x; + y = -y; + } + + vgui::surface()->ForceScreenPosOffset( true, x, y ); +} + +CVGuiAbsPosSplitScreenPlayerGuard::~CVGuiAbsPosSplitScreenPlayerGuard() +{ + if ( m_bNoRestore ) + return; + vgui::surface()->ForceScreenPosOffset( false, 0, 0 ); +} + //----------------------------------------------------------------------------- // Purpose: interface for gameui to modify voice bans //----------------------------------------------------------------------------- @@ -366,6 +475,7 @@ class CGameClientExports : public IGameClientExports { GetClientVoiceMgr()->SetPlayerBlockedState(playerIndex, false); } + void OnGameUIActivated( void ) { @@ -385,52 +495,14 @@ class CGameClientExports : public IGameClientExports } } - //============================================================================= - // HPE_BEGIN - // [dwenger] Necessary for stats display - //============================================================================= - - void CreateAchievementsPanel( vgui::Panel* pParent ) - { - if (g_pAchievementsAndStatsInterface) - { - g_pAchievementsAndStatsInterface->CreatePanel( pParent ); - } - } - - void DisplayAchievementPanel() - { - if (g_pAchievementsAndStatsInterface) - { - g_pAchievementsAndStatsInterface->DisplayPanel(); - } - } - - void ShutdownAchievementPanel() - { - if (g_pAchievementsAndStatsInterface) - { - g_pAchievementsAndStatsInterface->ReleasePanel(); - } - } - - int GetAchievementsPanelMinWidth( void ) const + // if true, the gameui applies the blur effect + bool ClientWantsBlurEffect( void ) { - if ( g_pAchievementsAndStatsInterface ) - { - return g_pAchievementsAndStatsInterface->GetAchievementsPanelMinWidth(); - } - - return 0; - } - - //============================================================================= - // HPE_END - //============================================================================= + ACTIVE_SPLITSCREEN_PLAYER_GUARD( 0 ); + if ( GetViewPortInterface()->GetActivePanel() && GetViewPortInterface()->GetActivePanel()->WantsBackgroundBlurred() ) + return true; - const char *GetHolidayString() - { - return UTIL_GetActiveHolidayString(); + return false; } }; @@ -441,8 +513,14 @@ class CClientDLLSharedAppSystems : public IClientDLLSharedAppSystems public: CClientDLLSharedAppSystems() { - AddAppSystem( "soundemittersystem" DLL_EXT_STRING, SOUNDEMITTERSYSTEM_INTERFACE_VERSION ); - AddAppSystem( "scenefilecache" DLL_EXT_STRING, SCENE_FILE_CACHE_INTERFACE_VERSION ); + AddAppSystem( "soundemittersystem", SOUNDEMITTERSYSTEM_INTERFACE_VERSION ); + AddAppSystem( "scenefilecache", SCENE_FILE_CACHE_INTERFACE_VERSION ); +#ifdef GAMEUI_UISYSTEM2_ENABLED + AddAppSystem( "client", GAMEUISYSTEMMGR_INTERFACE_VERSION ); +#endif +#ifdef INFESTED_DLL + AddAppSystem( "missionchooser", ASW_MISSION_CHOOSER_VERSION ); +#endif } virtual int Count() @@ -519,9 +597,6 @@ CUtlRBTree g_BoneSetupEnts( BoneSetupCompare ); void TrackBoneSetupEnt( C_BaseAnimating *pEnt ) { #ifdef _DEBUG - if ( IsRetail() ) - return; - if ( !cl_ShowBoneSetupEnts.GetInt() ) return; @@ -544,9 +619,6 @@ void TrackBoneSetupEnt( C_BaseAnimating *pEnt ) void DisplayBoneSetupEnts() { #ifdef _DEBUG - if ( IsRetail() ) - return; - if ( !cl_ShowBoneSetupEnts.GetInt() ) return; @@ -590,6 +662,7 @@ void DisplayBoneSetupEnts() #endif } + //----------------------------------------------------------------------------- // Purpose: engine to client .dll interface //----------------------------------------------------------------------------- @@ -598,14 +671,12 @@ class CHLClient : public IBaseClientDLL public: CHLClient(); - virtual int Init( CreateInterfaceFn appSystemFactory, CreateInterfaceFn physicsFactory, CGlobalVarsBase *pGlobals ); + virtual int Connect( CreateInterfaceFn appSystemFactory, CGlobalVarsBase *pGlobals ); + virtual int Init( CreateInterfaceFn appSystemFactory, CGlobalVarsBase *pGlobals ); virtual void PostInit(); virtual void Shutdown( void ); - virtual bool ReplayInit( CreateInterfaceFn fnReplayFactory ); - virtual bool ReplayPostInit(); - virtual void LevelInitPreEntity( const char *pMapName ); virtual void LevelInitPostEntity(); virtual void LevelShutdown( void ); @@ -624,16 +695,15 @@ class CHLClient : public IBaseClientDLL virtual void IN_Accumulate( void ); virtual void IN_ClearStates( void ); virtual bool IN_IsKeyDown( const char *name, bool& isdown ); - virtual void IN_OnMouseWheeled( int nDelta ); // Raw signal virtual int IN_KeyEvent( int eventcode, ButtonCode_t keynum, const char *pszCurrentBinding ); virtual void IN_SetSampleTime( float frametime ); // Create movement command virtual void CreateMove ( int sequence_number, float input_sample_frametime, bool active ); virtual void ExtraMouseSample( float frametime, bool active ); - virtual bool WriteUsercmdDeltaToBuffer( bf_write *buf, int from, int to, bool isnewcommand ); - virtual void EncodeUserCmdToBuffer( bf_write& buf, int slot ); - virtual void DecodeUserCmdFromBuffer( bf_read& buf, int slot ); + virtual bool WriteUsercmdDeltaToBuffer( int nSlot, bf_write *buf, int from, int to, bool isnewcommand ); + virtual void EncodeUserCmdToBuffer( int nSlot, bf_write& buf, int slot ); + virtual void DecodeUserCmdFromBuffer( int nSlot, bf_read& buf, int slot ); virtual void View_Render( vrect_t *rect ); @@ -647,7 +717,7 @@ class CHLClient : public IBaseClientDLL virtual int GetSpriteSize( void ) const; - virtual void VoiceStatus( int entindex, qboolean bTalking ); + virtual void VoiceStatus( int entindex, int iSsSlot, qboolean bTalking ); virtual void InstallStringTableCallback( const char *tableName ); @@ -681,61 +751,50 @@ class CHLClient : public IBaseClientDLL virtual void OnDemoPlaybackStart( char const* pDemoBaseName ); virtual void OnDemoPlaybackStop(); - virtual bool ShouldDrawDropdownConsole(); + virtual void RecordDemoPolishUserInput( int nCmdIndex ); - // Get client screen dimensions - virtual int GetScreenWidth(); - virtual int GetScreenHeight(); + // Cache replay ragdolls + virtual bool CacheReplayRagdolls( const char* pFilename, int nStartTick ); // save game screenshot writing - virtual void WriteSaveGameScreenshotOfSize( const char *pFilename, int width, int height, bool bCreatePowerOf2Padded/*=false*/, bool bWriteVTF/*=false*/ ); + virtual void WriteSaveGameScreenshotOfSize( const char *pFilename, int width, int height ); // Gets the location of the player viewpoint virtual bool GetPlayerView( CViewSetup &playerView ); - // Matchmaking - virtual void SetupGameProperties( CUtlVector< XUSER_CONTEXT > &contexts, CUtlVector< XUSER_PROPERTY > &properties ); - virtual uint GetPresenceID( const char *pIDName ); - virtual const char *GetPropertyIdString( const uint id ); - virtual void GetPropertyDisplayString( uint id, uint value, char *pOutput, int nBytes ); - virtual void StartStatsReporting( HANDLE handle, bool bArbitrated ); + virtual bool ShouldHideLoadingPlaque( void ); virtual void InvalidateMdlCache(); - virtual void ReloadFilesInList( IFileList *pFilesToReload ); - - // Let the client handle UI toggle - if this function returns false, the UI will toggle, otherwise it will not. - virtual bool HandleUiToggle(); - - // Allow the console to be shown? - virtual bool ShouldAllowConsole(); + virtual void OnActiveSplitscreenPlayerChanged( int nNewSlot ); + virtual void OnSplitScreenStateChanged(); + virtual void CenterStringOff(); - // Get renamed recv tables - virtual CRenamedRecvTableInfo *GetRenamedRecvTableInfos(); - // Get the mouthinfo for the sound being played inside UI panels - virtual CMouthInfo *GetClientUIMouthInfo(); + virtual void OnScreenSizeChanged( int nOldWidth, int nOldHeight ); + virtual IMaterialProxy *InstantiateMaterialProxy( const char *proxyName ); - // Notify the client that a file has been received from the game server - virtual void FileReceived( const char * fileName, unsigned int transferID ); + virtual vgui::VPANEL GetFullscreenClientDLLVPanel( void ); + virtual void MarkEntitiesAsTouching( IClientEntity *e1, IClientEntity *e2 ); + virtual void OnKeyBindingChanged( ButtonCode_t buttonCode, char const *pchKeyName, char const *pchNewBinding ); + virtual bool HandleGameUIEvent( const InputEvent_t &event ); - virtual const char* TranslateEffectForVisionFilter( const char *pchEffectType, const char *pchEffectName ); - - virtual void ClientAdjustStartSoundParams( struct StartSoundParams_t& params ); - - // Returns true if the disconnect command has been handled by the client - virtual bool DisconnectAttempt( void ); public: void PrecacheMaterial( const char *pMaterialName ); - virtual bool IsConnectedUserInfoChangeAllowed( IConVar *pCvar ); - virtual void IN_TouchEvent( int type, int fingerId, int x, int y ); + virtual void SetBlurFade( float scale ); + + virtual void ResetHudCloseCaption(); + + virtual bool SupportsRandomMaps(); private: void UncacheAllMaterials( ); void ResetStringTablePointers(); - CUtlVector< IMaterial * > m_CachedMaterials; + CUtlRBTree< IMaterial * > m_CachedMaterials; + + CHudCloseCaption *m_pHudCloseCaption; }; @@ -789,10 +848,11 @@ const char *GetMaterialNameFromIndex( int nIndex ) //----------------------------------------------------------------------------- // Precaches a particle system //----------------------------------------------------------------------------- -void PrecacheParticleSystem( const char *pParticleSystemName ) +int PrecacheParticleSystem( const char *pParticleSystemName ) { - g_pStringTableParticleEffectNames->AddString( false, pParticleSystemName ); - g_pParticleSystemMgr->PrecacheParticleSystem( pParticleSystemName ); + int nIndex = g_pStringTableParticleEffectNames->AddString( false, pParticleSystemName ); + g_pParticleSystemMgr->PrecacheParticleSystem( nIndex, pParticleSystemName ); + return nIndex; } @@ -823,6 +883,17 @@ const char *GetParticleSystemNameFromIndex( int nIndex ) return "error"; } + +//----------------------------------------------------------------------------- +// Precache-related methods for effects +//----------------------------------------------------------------------------- +void PrecacheEffect( const char *pEffectName ) +{ + // Bring in dependent resources + g_pPrecacheSystem->Cache( g_pPrecacheHandler, DISPATCH_EFFECT, pEffectName, true, RESOURCE_LIST_INVALID, true ); +} + + //----------------------------------------------------------------------------- // Returns true if host_thread_mode is set to non-zero (and engine is running in threaded mode) //----------------------------------------------------------------------------- @@ -838,218 +909,125 @@ bool IsEngineThreaded() //----------------------------------------------------------------------------- // Constructor //----------------------------------------------------------------------------- - CHLClient::CHLClient() { // Kinda bogus, but the logic in the engine is too convoluted to put it there g_bLevelInitialized = false; + m_pHudCloseCaption = NULL; + + SetDefLessFunc( m_CachedMaterials ); } extern IGameSystem *ViewportClientSystem(); +// enable threaded init functions on x360 +static ConVar cl_threaded_init("cl_threaded_init", IsX360() ? "1" : "0"); -//----------------------------------------------------------------------------- -ISourceVirtualReality *g_pSourceVR = NULL; - -// Purpose: Called when the DLL is first loaded. -// Input : engineFactory - -// Output : int -//----------------------------------------------------------------------------- -int CHLClient::Init( CreateInterfaceFn appSystemFactory, CreateInterfaceFn physicsFactory, CGlobalVarsBase *pGlobals ) +bool InitParticleManager() { - InitCRTMemDebug(); - MathLib_Init( 2.2f, 2.2f, 0.0f, 2.0f ); + if (!ParticleMgr()->Init(MAX_TOTAL_PARTICLES, materials)) + return false; + return true; +} -#ifdef SIXENSE - g_pSixenseInput = new SixenseInput; -#endif +bool InitGameSystems( CreateInterfaceFn appSystemFactory ) +{ - // Hook up global variables - gpGlobals = pGlobals; + if (!VGui_Startup( appSystemFactory )) + return false; - ConnectTier1Libraries( &appSystemFactory, 1 ); - ConnectTier2Libraries( &appSystemFactory, 1 ); - ConnectTier3Libraries( &appSystemFactory, 1 ); + vgui::VGui_InitMatSysInterfacesList( "ClientDLL", &appSystemFactory, 1 ); -#ifndef NO_STEAM - ClientSteamContext().Activate(); -#endif + // Add the client systems. - // We aren't happy unless we get all of our interfaces. - // please don't collapse this into one monolithic boolean expression (impossible to debug) - if ( (engine = (IVEngineClient *)appSystemFactory( VENGINE_CLIENT_INTERFACE_VERSION, NULL )) == NULL ) - return false; - if ( (modelrender = (IVModelRender *)appSystemFactory( VENGINE_HUDMODEL_INTERFACE_VERSION, NULL )) == NULL ) - return false; - if ( (effects = (IVEfx *)appSystemFactory( VENGINE_EFFECTS_INTERFACE_VERSION, NULL )) == NULL ) - return false; - if ( (enginetrace = (IEngineTrace *)appSystemFactory( INTERFACEVERSION_ENGINETRACE_CLIENT, NULL )) == NULL ) - return false; - if ( (render = (IVRenderView *)appSystemFactory( VENGINE_RENDERVIEW_INTERFACE_VERSION, NULL )) == NULL ) - return false; - if ( (debugoverlay = (IVDebugOverlay *)appSystemFactory( VDEBUG_OVERLAY_INTERFACE_VERSION, NULL )) == NULL ) - return false; - if ( (datacache = (IDataCache*)appSystemFactory(DATACACHE_INTERFACE_VERSION, NULL )) == NULL ) - return false; - if ( !mdlcache ) - return false; - if ( (modelinfo = (IVModelInfoClient *)appSystemFactory(VMODELINFO_CLIENT_INTERFACE_VERSION, NULL )) == NULL ) - return false; - if ( (enginevgui = (IEngineVGui *)appSystemFactory(VENGINE_VGUI_VERSION, NULL )) == NULL ) - return false; - if ( (networkstringtable = (INetworkStringTableContainer *)appSystemFactory(INTERFACENAME_NETWORKSTRINGTABLECLIENT,NULL)) == NULL ) - return false; - if ( (partition = (ISpatialPartition *)appSystemFactory(INTERFACEVERSION_SPATIALPARTITION, NULL)) == NULL ) - return false; - if ( (shadowmgr = (IShadowMgr *)appSystemFactory(ENGINE_SHADOWMGR_INTERFACE_VERSION, NULL)) == NULL ) - return false; - if ( (staticpropmgr = (IStaticPropMgrClient *)appSystemFactory(INTERFACEVERSION_STATICPROPMGR_CLIENT, NULL)) == NULL ) - return false; - if ( (enginesound = (IEngineSound *)appSystemFactory(IENGINESOUND_CLIENT_INTERFACE_VERSION, NULL)) == NULL ) - return false; - if ( (filesystem = (IFileSystem *)appSystemFactory(FILESYSTEM_INTERFACE_VERSION, NULL)) == NULL ) - return false; - if ( (random = (IUniformRandomStream *)appSystemFactory(VENGINE_CLIENT_RANDOM_INTERFACE_VERSION, NULL)) == NULL ) - return false; - if ( (gameuifuncs = (IGameUIFuncs * )appSystemFactory( VENGINE_GAMEUIFUNCS_VERSION, NULL )) == NULL ) - return false; - if ( (gameeventmanager = (IGameEventManager2 *)appSystemFactory(INTERFACEVERSION_GAMEEVENTSMANAGER2,NULL)) == NULL ) - return false; - if ( (soundemitterbase = (ISoundEmitterSystemBase *)appSystemFactory(SOUNDEMITTERSYSTEM_INTERFACE_VERSION, NULL)) == NULL ) - return false; - if ( (inputsystem = (IInputSystem *)appSystemFactory(INPUTSYSTEM_INTERFACE_VERSION, NULL)) == NULL ) - return false; - if ( (scenefilecache = (ISceneFileCache *)appSystemFactory( SCENE_FILE_CACHE_INTERFACE_VERSION, NULL )) == NULL ) - return false; - if ( IsX360() && (xboxsystem = (IXboxSystem *)appSystemFactory( XBOXSYSTEM_INTERFACE_VERSION, NULL )) == NULL ) - return false; - if ( IsX360() && (matchmaking = (IMatchmaking *)appSystemFactory( VENGINE_MATCHMAKING_VERSION, NULL )) == NULL ) - return false; -#ifndef _XBOX - if ( ( gamestatsuploader = (IUploadGameStats *)appSystemFactory( INTERFACEVERSION_UPLOADGAMESTATS, NULL )) == NULL ) - return false; + // Client Leaf System has to be initialized first, since DetailObjectSystem uses it + IGameSystem::Add( GameStringSystem() ); + IGameSystem::Add( g_pPrecacheRegister ); + IGameSystem::Add( SoundEmitterSystem() ); + IGameSystem::Add( ToolFrameworkClientSystem() ); + IGameSystem::Add( ClientLeafSystem() ); + IGameSystem::Add( DetailObjectSystem() ); + IGameSystem::Add( ViewportClientSystem() ); + IGameSystem::Add( g_pClientShadowMgr ); + IGameSystem::Add( g_pColorCorrectionMgr ); +#ifdef GAMEUI_UISYSTEM2_ENABLED + IGameSystem::Add( g_pGameUIGameSystem ); #endif + IGameSystem::Add( ClientThinkList() ); + IGameSystem::Add( ClientSoundscapeSystem() ); + IGameSystem::Add( PerfVisualBenchmark() ); -#if defined( REPLAY_ENABLED ) - if ( IsPC() && (g_pEngineReplay = (IEngineReplay *)appSystemFactory( ENGINE_REPLAY_INTERFACE_VERSION, NULL )) == NULL ) - return false; - if ( IsPC() && (g_pEngineClientReplay = (IEngineClientReplay *)appSystemFactory( ENGINE_REPLAY_CLIENT_INTERFACE_VERSION, NULL )) == NULL ) - return false; +#if defined( CLIENT_DLL ) && defined( COPY_CHECK_STRESSTEST ) + IGameSystem::Add( GetPredictionCopyTester() ); #endif - if (!g_pMatSystemSurface) - return false; - -#ifdef WORKSHOP_IMPORT_ENABLED - if ( !ConnectDataModel( appSystemFactory ) ) - return false; - if ( InitDataModel() != INIT_OK ) - return false; - InitFbx(); -#endif + ActivityList_Init(); + ActivityList_RegisterSharedActivities(); + EventList_Init(); + EventList_RegisterSharedEvents(); - // it's ok if this is NULL. That just means the sourcevr.dll wasn't found - g_pSourceVR = (ISourceVirtualReality *)appSystemFactory(SOURCE_VIRTUAL_REALITY_INTERFACE_VERSION, NULL); + modemanager->Init( ); - factorylist_t factories; - factories.appSystemFactory = appSystemFactory; - factories.physicsFactory = physicsFactory; - FactoryList_Store( factories ); + // Load the ClientScheme just once + vgui::scheme()->LoadSchemeFromFileEx( VGui_GetFullscreenRootVPANEL(), "resource/ClientScheme.res", "ClientScheme"); - // Yes, both the client and game .dlls will try to Connect, the soundemittersystem.dll will handle this gracefully - if ( !soundemitterbase->Connect( appSystemFactory ) ) + for ( int hh = 0; hh < MAX_SPLITSCREEN_PLAYERS; ++hh ) { - return false; - } + ACTIVE_SPLITSCREEN_PLAYER_GUARD_VGUI( hh ); + GetClientMode()->InitViewport(); - if ( CommandLine()->FindParm( "-textmode" ) ) - g_bTextMode = true; - - if ( CommandLine()->FindParm( "-makedevshots" ) ) - g_MakingDevShots = true; - - // Not fatal if the material system stub isn't around. - materials_stub = (IMaterialSystemStub*)appSystemFactory( MATERIAL_SYSTEM_STUB_INTERFACE_VERSION, NULL ); - - if( !g_pMaterialSystemHardwareConfig ) - return false; - - // Hook up the gaussian random number generator - s_GaussianRandomStream.AttachToStream( random ); - - // Initialize the console variables. - ConVar_Register( FCVAR_CLIENTDLL ); - - g_pcv_ThreadMode = g_pCVar->FindVar( "host_thread_mode" ); - - if (!Initializer::InitializeAllObjects()) - return false; - - if (!ParticleMgr()->Init(MAX_TOTAL_PARTICLES, materials)) - return false; - - - if (!VGui_Startup( appSystemFactory )) - return false; - - vgui::VGui_InitMatSysInterfacesList( "ClientDLL", &appSystemFactory, 1 ); - - // Add the client systems. - - // Client Leaf System has to be initialized first, since DetailObjectSystem uses it - IGameSystem::Add( GameStringSystem() ); - IGameSystem::Add( SoundEmitterSystem() ); - IGameSystem::Add( ToolFrameworkClientSystem() ); - IGameSystem::Add( ClientLeafSystem() ); - IGameSystem::Add( DetailObjectSystem() ); - IGameSystem::Add( ViewportClientSystem() ); - IGameSystem::Add( ClientEffectPrecacheSystem() ); - IGameSystem::Add( g_pClientShadowMgr ); - IGameSystem::Add( g_pColorCorrectionMgr ); // NOTE: This must happen prior to ClientThinkList (color correction is updated there) - IGameSystem::Add( ClientThinkList() ); - IGameSystem::Add( ClientSoundscapeSystem() ); - IGameSystem::Add( PerfVisualBenchmark() ); - IGameSystem::Add( MumbleSystem() ); - - #if defined( TF_CLIENT_DLL ) - IGameSystem::Add( CustomTextureToolCacheGameSystem() ); - IGameSystem::Add( TFSharedContentManager() ); - #endif + if ( hh == 0 ) + { + GetFullscreenClientMode()->InitViewport(); + } + } -#if defined( TF_CLIENT_DLL ) - if ( g_AbuseReportMgr != NULL ) + for ( int hh = 0; hh < MAX_SPLITSCREEN_PLAYERS; ++hh ) { - IGameSystem::Add( g_AbuseReportMgr ); + ACTIVE_SPLITSCREEN_PLAYER_GUARD_VGUI( hh ); + GetHud().Init(); } -#endif - -#if defined( CLIENT_DLL ) && defined( COPY_CHECK_STRESSTEST ) - IGameSystem::Add( GetPredictionCopyTester() ); -#endif - - modemanager->Init( ); - g_pClientMode->InitViewport(); - - gHUD.Init(); - gTouch.Init(); + for ( int hh = 0; hh < MAX_SPLITSCREEN_PLAYERS; ++hh ) + { + ACTIVE_SPLITSCREEN_PLAYER_GUARD_VGUI( hh ); + GetClientMode()->Init(); - g_pClientMode->Init(); + if ( hh == 0 ) + { + GetFullscreenClientMode()->Init(); + } + } if ( !IGameSystem::InitAllSystems() ) return false; - g_pClientMode->Enable(); + for ( int hh = 0; hh < MAX_SPLITSCREEN_PLAYERS; ++hh ) + { + ACTIVE_SPLITSCREEN_PLAYER_GUARD_VGUI( hh ); + GetClientMode()->Enable(); + if ( hh == 0 ) + { + GetFullscreenClientMode()->EnableWithRootPanel( VGui_GetFullscreenRootVPANEL() ); + } + } + + // Each mod is required to implement this + view = GetViewRenderInstance(); if ( !view ) { - view = ( IViewRender * )&g_DefaultViewRender; + Error( "GetViewRenderInstance() must be implemented by game." ); } view->Init(); - vieweffects->Init(); + for ( int hh = 0; hh < MAX_SPLITSCREEN_PLAYERS; ++hh ) + { + ACTIVE_SPLITSCREEN_PLAYER_GUARD_VGUI( hh ); + GetViewEffects()->Init(); + } C_BaseTempEntity::PrecacheTempEnts(); @@ -1060,7 +1038,11 @@ int CHLClient::Init( CreateInterfaceFn appSystemFactory, CreateInterfaceFn physi InitSmokeFogOverlay(); // Register user messages.. - CUserMessageRegister::RegisterAll(); + for ( int hh = 0; hh < MAX_SPLITSCREEN_PLAYERS; ++hh ) + { + ACTIVE_SPLITSCREEN_PLAYER_GUARD( hh ); + CUserMessageRegister::RegisterAll(); + } ClientVoiceMgr_Init(); @@ -1070,7 +1052,7 @@ int CHLClient::Init( CreateInterfaceFn appSystemFactory, CreateInterfaceFn physi GetClientVoiceMgr()->Init( &g_VoiceStatusHelper, parent ); } - if ( !PhysicsDLLInit( physicsFactory ) ) + if ( !PhysicsDLLInit( appSystemFactory ) ) return false; g_pGameSaveRestoreBlockSet->AddBlockHandler( GetEntitySaveRestoreBlockHandler() ); @@ -1079,52 +1061,193 @@ int CHLClient::Init( CreateInterfaceFn appSystemFactory, CreateInterfaceFn physi ClientWorldFactoryInit(); - C_BaseAnimating::InitBoneSetupThreadPool(); + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: Called when the DLL is first loaded. +// Input : engineFactory - +// Output : int +//----------------------------------------------------------------------------- +int CHLClient::Connect( CreateInterfaceFn appSystemFactory, CGlobalVarsBase *pGlobals ) +{ + InitCRTMemDebug(); + MathLib_Init( 2.2f, 2.2f, 0.0f, 2.0f ); + + // Hook up global variables + gpGlobals = pGlobals; + + ConnectTier1Libraries( &appSystemFactory, 1 ); + ConnectTier2Libraries( &appSystemFactory, 1 ); + ConnectTier3Libraries( &appSystemFactory, 1 ); -#if defined( WIN32 ) && !defined( _X360 ) - // NVNT connect haptics sytem - ConnectHaptics(appSystemFactory); -#endif #ifndef _X360 - HookHapticMessages(); // Always hook the messages + SteamAPI_InitSafe(); + g_SteamAPIContext.Init(); + +#ifdef INFESTED_DLL + +#endif #endif + // Initialize the console variables. + ConVar_Register( FCVAR_CLIENTDLL ); + return true; } -bool CHLClient::ReplayInit( CreateInterfaceFn fnReplayFactory ) +int CHLClient::Init( CreateInterfaceFn appSystemFactory, CGlobalVarsBase *pGlobals ) { -#if defined( REPLAY_ENABLED ) - if ( !IsPC() ) + + COM_TimestampedLog( "ClientDLL factories - Start" ); + // We aren't happy unless we get all of our interfaces. + // please don't collapse this into one monolithic boolean expression (impossible to debug) + if ( (engine = (IVEngineClient *)appSystemFactory( VENGINE_CLIENT_INTERFACE_VERSION, NULL )) == NULL ) return false; - if ( (g_pReplay = (IReplaySystem *)fnReplayFactory( REPLAY_INTERFACE_VERSION, NULL ) ) == NULL ) + if ( (modelrender = (IVModelRender *)appSystemFactory( VENGINE_HUDMODEL_INTERFACE_VERSION, NULL )) == NULL ) return false; - if ( (g_pClientReplayContext = g_pReplay->CL_GetContext()) == NULL ) + if ( (effects = (IVEfx *)appSystemFactory( VENGINE_EFFECTS_INTERFACE_VERSION, NULL )) == NULL ) + return false; + if ( (enginetrace = (IEngineTrace *)appSystemFactory( INTERFACEVERSION_ENGINETRACE_CLIENT, NULL )) == NULL ) + return false; + if ( (filelogginglistener = (IFileLoggingListener *)appSystemFactory(FILELOGGINGLISTENER_INTERFACE_VERSION, NULL)) == NULL ) + return false; + if ( (render = (IVRenderView *)appSystemFactory( VENGINE_RENDERVIEW_INTERFACE_VERSION, NULL )) == NULL ) + return false; + if ( (debugoverlay = (IVDebugOverlay *)appSystemFactory( VDEBUG_OVERLAY_INTERFACE_VERSION, NULL )) == NULL ) + return false; + if ( (datacache = (IDataCache*)appSystemFactory(DATACACHE_INTERFACE_VERSION, NULL )) == NULL ) + return false; + if ( !mdlcache ) + return false; + if ( (modelinfo = (IVModelInfoClient *)appSystemFactory(VMODELINFO_CLIENT_INTERFACE_VERSION, NULL )) == NULL ) + return false; + if ( (enginevgui = (IEngineVGui *)appSystemFactory(VENGINE_VGUI_VERSION, NULL )) == NULL ) + return false; + if ( (networkstringtable = (INetworkStringTableContainer *)appSystemFactory(INTERFACENAME_NETWORKSTRINGTABLECLIENT,NULL)) == NULL ) + return false; + if ( (partition = (ISpatialPartition *)appSystemFactory(INTERFACEVERSION_SPATIALPARTITION, NULL)) == NULL ) + return false; + if ( (shadowmgr = (IShadowMgr *)appSystemFactory(ENGINE_SHADOWMGR_INTERFACE_VERSION, NULL)) == NULL ) + return false; + if ( (staticpropmgr = (IStaticPropMgrClient *)appSystemFactory(INTERFACEVERSION_STATICPROPMGR_CLIENT, NULL)) == NULL ) + return false; + if ( (enginesound = (IEngineSound *)appSystemFactory(IENGINESOUND_CLIENT_INTERFACE_VERSION, NULL)) == NULL ) + return false; + if ( (filesystem = (IFileSystem *)appSystemFactory(FILESYSTEM_INTERFACE_VERSION, NULL)) == NULL ) + return false; + if ( (random = (IUniformRandomStream *)appSystemFactory(VENGINE_CLIENT_RANDOM_INTERFACE_VERSION, NULL)) == NULL ) + return false; + if ( (gameuifuncs = (IGameUIFuncs * )appSystemFactory( VENGINE_GAMEUIFUNCS_VERSION, NULL )) == NULL ) + return false; + if ( (gameeventmanager = (IGameEventManager2 *)appSystemFactory(INTERFACEVERSION_GAMEEVENTSMANAGER2,NULL)) == NULL ) + return false; + if ( (soundemitterbase = (ISoundEmitterSystemBase *)appSystemFactory(SOUNDEMITTERSYSTEM_INTERFACE_VERSION, NULL)) == NULL ) + return false; + if ( (inputsystem = (IInputSystem *)appSystemFactory(INPUTSYSTEM_INTERFACE_VERSION, NULL)) == NULL ) + return false; + if ( IsPC() && !IsPosix() && (avi = (IAvi *)appSystemFactory(AVI_INTERFACE_VERSION, NULL)) == NULL ) + return false; +#if !defined( _X360 ) || defined( BINK_ENABLED_FOR_X360 ) + if ( (bik = (IBik *)appSystemFactory(BIK_INTERFACE_VERSION, NULL)) == NULL ) return false; - - return true; -#else - return false; #endif -} - -bool CHLClient::ReplayPostInit() -{ + if ( (scenefilecache = (ISceneFileCache *)appSystemFactory( SCENE_FILE_CACHE_INTERFACE_VERSION, NULL )) == NULL ) + return false; + if ( (blackboxrecorder = (IBlackBox *)appSystemFactory(BLACKBOX_INTERFACE_VERSION, NULL)) == NULL ) + return false; + if ( (xboxsystem = (IXboxSystem *)appSystemFactory( XBOXSYSTEM_INTERFACE_VERSION, NULL )) == NULL ) + return false; #if defined( REPLAY_ENABLED ) - if ( ( g_pReplayManager = g_pClientReplayContext->GetReplayManager() ) == NULL ) + if ( IsPC() && (g_pReplayHistoryManager = (IReplayHistoryManager *)appSystemFactory( REPLAYHISTORYMANAGER_INTERFACE_VERSION, NULL )) == NULL ) return false; - if ( ( g_pReplayScreenshotManager = g_pClientReplayContext->GetScreenshotManager() ) == NULL ) +#endif +#ifndef _XBOX + if ( ( gamestatsuploader = (IUploadGameStats *)appSystemFactory( INTERFACEVERSION_UPLOADGAMESTATS, NULL )) == NULL ) return false; - if ( ( g_pReplayPerformanceManager = g_pClientReplayContext->GetPerformanceManager() ) == NULL ) +#endif + if (!g_pMatSystemSurface) return false; - if ( ( g_pReplayPerformanceController = g_pClientReplayContext->GetPerformanceController() ) == NULL ) + +#ifdef INFESTED_DLL + if ( (missionchooser = (IASW_Mission_Chooser *)appSystemFactory(ASW_MISSION_CHOOSER_VERSION, NULL)) == NULL ) return false; - if ( ( g_pReplayMovieManager = g_pClientReplayContext->GetMovieManager() ) == NULL ) +#endif + + + if ( !CommandLine()->CheckParm( "-noscripting") ) + { + scriptmanager = (IScriptManager *)appSystemFactory( VSCRIPT_INTERFACE_VERSION, NULL ); + } + + factorylist_t factories; + factories.appSystemFactory = appSystemFactory; + FactoryList_Store( factories ); + + COM_TimestampedLog( "soundemitterbase->Connect" ); + // Yes, both the client and game .dlls will try to Connect, the soundemittersystem.dll will handle this gracefully + if ( !soundemitterbase->Connect( appSystemFactory ) ) + { return false; - return true; -#else - return false; + } + + if ( CommandLine()->FindParm( "-textmode" ) ) + g_bTextMode = true; + + if ( CommandLine()->FindParm( "-makedevshots" ) ) + g_MakingDevShots = true; + + if ( CommandLine()->FindParm( "-headtracking" ) ) + g_bHeadTrackingEnabled = true; + + // Not fatal if the material system stub isn't around. + materials_stub = (IMaterialSystemStub*)appSystemFactory( MATERIAL_SYSTEM_STUB_INTERFACE_VERSION, NULL ); + + if( !g_pMaterialSystemHardwareConfig ) + return false; + + // Hook up the gaussian random number generator + s_GaussianRandomStream.AttachToStream( random ); + + g_pcv_ThreadMode = g_pCVar->FindVar( "host_thread_mode" ); + + + + + COM_TimestampedLog( "InitGameSystems" ); + + bool bInitSuccess = false; + if ( cl_threaded_init.GetBool() ) + { + CFunctorJob *pGameJob = new CFunctorJob( CreateFunctor( InitParticleManager ) ); + g_pThreadPool->AddJob( pGameJob ); + bInitSuccess = InitGameSystems( appSystemFactory ); + pGameJob->WaitForFinishAndRelease(); + } + else + { + COM_TimestampedLog( "ParticleMgr()->Init" ); + if (!ParticleMgr()->Init(MAX_TOTAL_PARTICLES, materials)) + return false; + COM_TimestampedLog( "InitGameSystems - Start" ); + bInitSuccess = InitGameSystems( appSystemFactory ); + COM_TimestampedLog( "InitGameSystems - End" ); + } + + +#ifdef INFESTED_PARTICLES // let the emitter cache load in our standard + g_ASWGenericEmitterCache.PrecacheTemplates(); #endif + + COM_TimestampedLog( "C_BaseAnimating::InitBoneSetupThreadPool" ); + + C_BaseAnimating::InitBoneSetupThreadPool(); + + // This is a fullscreen element, so only lives on slot 0!!! + m_pHudCloseCaption = GET_FULLSCREEN_HUDELEMENT( CHudCloseCaption ); + + COM_TimestampedLog( "ClientDLL Init - Finish" ); + return true; } //----------------------------------------------------------------------------- @@ -1132,30 +1255,9 @@ bool CHLClient::ReplayPostInit() //----------------------------------------------------------------------------- void CHLClient::PostInit() { + COM_TimestampedLog( "IGameSystem::PostInitAllSystems - Start" ); IGameSystem::PostInitAllSystems(); - -#ifdef SIXENSE - // allow sixnese input to perform post-init operations - g_pSixenseInput->PostInit(); -#endif - - g_ClientVirtualReality.StartupComplete(); - -#ifdef HL1MP_CLIENT_DLL - if ( s_cl_load_hl1_content.GetBool() && steamapicontext && steamapicontext->SteamApps() ) - { - char szPath[ MAX_PATH*2 ]; - int ccFolder= steamapicontext->SteamApps()->GetAppInstallDir( 280, szPath, sizeof(szPath) ); - if ( ccFolder > 0 ) - { - V_AppendSlash( szPath, sizeof(szPath) ); - V_strncat( szPath, "hl1", sizeof( szPath ) ); - - g_pFullFileSystem->AddSearchPath( szPath, "HL1" ); - g_pFullFileSystem->AddSearchPath( szPath, "GAME" ); - } - } -#endif + COM_TimestampedLog( "IGameSystem::PostInitAllSystems - Finish" ); } //----------------------------------------------------------------------------- @@ -1163,16 +1265,12 @@ void CHLClient::PostInit() //----------------------------------------------------------------------------- void CHLClient::Shutdown( void ) { - if (g_pAchievementsAndStatsInterface) - { - g_pAchievementsAndStatsInterface->ReleasePanel(); - } -#ifdef SIXENSE - g_pSixenseInput->Shutdown(); - delete g_pSixenseInput; - g_pSixenseInput = NULL; -#endif + + ActivityList_Free(); + EventList_Free(); + + VGui_ClearVideoPanels(); C_BaseAnimating::ShutdownBoneSetupThreadPool(); ClientWorldFactoryShutdown(); @@ -1183,10 +1281,28 @@ void CHLClient::Shutdown( void ) ClientVoiceMgr_Shutdown(); - Initializer::FreeAllObjects(); - g_pClientMode->Disable(); - g_pClientMode->Shutdown(); + for ( int hh = 0; hh < MAX_SPLITSCREEN_PLAYERS; ++hh ) + { + ACTIVE_SPLITSCREEN_PLAYER_GUARD_VGUI( hh ); + GetClientMode()->Disable(); + + if ( hh == 0 ) + { + GetFullscreenClientMode()->Disable(); + } + } + + for ( int hh = 0; hh < MAX_SPLITSCREEN_PLAYERS; ++hh ) + { + ACTIVE_SPLITSCREEN_PLAYER_GUARD_VGUI( hh ); + GetClientMode()->Shutdown(); + + if ( hh == 0 ) + { + GetFullscreenClientMode()->Shutdown(); + } + } input->Shutdown_All(); C_BaseTempEntity::ClearDynamicTempEnts(); @@ -1196,37 +1312,29 @@ void CHLClient::Shutdown( void ) UncacheAllMaterials(); IGameSystem::ShutdownAllSystems(); - - gHUD.Shutdown(); - VGui_Shutdown(); - gTouch.Shutdown(); - ParticleMgr()->Term(); + for ( int hh = 0; hh < MAX_SPLITSCREEN_PLAYERS; ++hh ) + { + ACTIVE_SPLITSCREEN_PLAYER_GUARD_VGUI( hh ); + GetHud().Shutdown(); + } + + VGui_Shutdown(); ClearKeyValuesCache(); #ifndef NO_STEAM - ClientSteamContext().Shutdown(); + g_SteamAPIContext.Clear(); + // SteamAPI_Shutdown(); << Steam shutdown is controlled by engine +#ifdef INFESTED_DLL + #endif - -#ifdef WORKSHOP_IMPORT_ENABLED - ShutdownDataModel(); - DisconnectDataModel(); - ShutdownFbx(); #endif - // This call disconnects the VGui libraries which we rely on later in the shutdown path, so don't do it -// DisconnectTier3Libraries( ); + DisconnectTier3Libraries( ); DisconnectTier2Libraries( ); ConVar_Unregister(); DisconnectTier1Libraries( ); - - gameeventmanager = NULL; - -#if defined( WIN32 ) && !defined( _X360 ) - // NVNT Disconnect haptics system - DisconnectHaptics(); -#endif } @@ -1239,7 +1347,11 @@ void CHLClient::Shutdown( void ) //----------------------------------------------------------------------------- int CHLClient::HudVidInit( void ) { - gHUD.VidInit(); + for ( int hh = 0; hh < MAX_SPLITSCREEN_PLAYERS; ++hh ) + { + ACTIVE_SPLITSCREEN_PLAYER_GUARD( hh ); + GetHud().VidInit(); + } GetClientVoiceMgr()->VidInit(); @@ -1252,7 +1364,7 @@ int CHLClient::HudVidInit( void ) //----------------------------------------------------------------------------- void CHLClient::HudProcessInput( bool bActive ) { - g_pClientMode->ProcessInput( bActive ); + GetClientMode()->ProcessInput( bActive ); } //----------------------------------------------------------------------------- @@ -1263,13 +1375,17 @@ void CHLClient::HudUpdate( bool bActive ) { float frametime = gpGlobals->frametime; -#if defined( TF_CLIENT_DLL ) - CRTime::UpdateRealTime(); -#endif - GetClientVoiceMgr()->Frame( frametime ); - gHUD.UpdateHud( bActive ); + ASSERT_LOCAL_PLAYER_NOT_RESOLVABLE(); + + FOR_EACH_VALID_SPLITSCREEN_PLAYER( hh ) + { + ACTIVE_SPLITSCREEN_PLAYER_GUARD( hh ); + GetHud().UpdateHud( bActive ); + } + + ASSERT_LOCAL_PLAYER_NOT_RESOLVABLE(); { C_BaseAnimating::AutoAllowBoneAccess boneaccess( true, false ); @@ -1277,7 +1393,7 @@ void CHLClient::HudUpdate( bool bActive ) } // run vgui animations - vgui::GetAnimationController()->UpdateAnimations( engine->Time() ); + vgui::GetAnimationController()->UpdateAnimations( Plat_FloatTime() ); hudlcd->SetGlobalStat( "(time_int)", VarArgs( "%d", (int)gpGlobals->curtime ) ); hudlcd->SetGlobalStat( "(time_float)", VarArgs( "%.2f", gpGlobals->curtime ) ); @@ -1285,14 +1401,6 @@ void CHLClient::HudUpdate( bool bActive ) // I don't think this is necessary any longer, but I will leave it until // I can check into this further. C_BaseTempEntity::CheckDynamicTempEnts(); - -#ifdef SIXENSE - // If we're not connected, update sixense so we can move the mouse cursor when in the menus - if( !engine->IsConnected() || engine->IsPaused() ) - { - g_pSixenseInput->SixenseFrame( 0, NULL ); - } -#endif } //----------------------------------------------------------------------------- @@ -1300,7 +1408,12 @@ void CHLClient::HudUpdate( bool bActive ) //----------------------------------------------------------------------------- void CHLClient::HudReset( void ) { - gHUD.VidInit(); + for ( int hh = 0; hh < MAX_SPLITSCREEN_PLAYERS; ++hh ) + { + ACTIVE_SPLITSCREEN_PLAYER_GUARD( hh ); + GetHud().VidInit(); + } + PhysicsReset(); } @@ -1309,27 +1422,34 @@ void CHLClient::HudReset( void ) //----------------------------------------------------------------------------- void CHLClient::HudText( const char * message ) { - DispatchHudText( message ); + for ( int hh = 0; hh < MAX_SPLITSCREEN_PLAYERS; ++hh ) + { + ACTIVE_SPLITSCREEN_PLAYER_GUARD( hh ); + DispatchHudText( message ); + } } + //----------------------------------------------------------------------------- -// Purpose: +// Handler for input events for the new game ui system //----------------------------------------------------------------------------- -bool CHLClient::ShouldDrawDropdownConsole() +bool CHLClient::HandleGameUIEvent( const InputEvent_t &inputEvent ) { -#if defined( REPLAY_ENABLED ) - extern ConVar hud_freezecamhide; - extern bool IsTakingAFreezecamScreenshot(); - - if ( hud_freezecamhide.GetBool() && IsTakingAFreezecamScreenshot() ) - { +#ifdef GAMEUI_UISYSTEM2_ENABLED + // TODO: when embedded UI will be used for HUD, we will need it to maintain + // a separate screen for HUD and a separate screen stack for pause menu & main menu. + // for now only render embedded UI in pause menu & main menu + BaseModUI::CBaseModPanel *pBaseModPanel = BaseModUI::CBaseModPanel::GetSingletonPtr(); + if ( !pBaseModPanel || !pBaseModPanel->IsVisible() ) return false; - } -#endif - return true; + return g_pGameUIGameSystem->RegisterInputEvent( inputEvent ); +#else + return false; +#endif } + //----------------------------------------------------------------------------- // Purpose: // Output : ClientClass @@ -1355,12 +1475,14 @@ void CHLClient::IN_DeactivateMouse( void ) input->DeactivateMouse(); } +extern ConVar in_forceuser; //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CHLClient::IN_Accumulate ( void ) { - input->AccumulateMouse(); + ACTIVE_SPLITSCREEN_PLAYER_GUARD( in_forceuser.GetInt() ); + input->AccumulateMouse( GET_ACTIVE_SPLITSCREEN_SLOT() ); } //----------------------------------------------------------------------------- @@ -1383,28 +1505,12 @@ bool CHLClient::IN_IsKeyDown( const char *name, bool& isdown ) return false; } - isdown = ( key->state & 1 ) ? true : false; + isdown = ( key->GetPerUser().state & 1 ) ? true : false; // Found the key by name return true; } -//----------------------------------------------------------------------------- -// Purpose: Engine can issue a key event -// Input : eventcode - -// keynum - -// *pszCurrentBinding - -void CHLClient::IN_OnMouseWheeled( int nDelta ) -{ -#if defined( REPLAY_ENABLED ) - CReplayPerformanceEditorPanel *pPerfEditor = ReplayUI_GetPerformanceEditor(); - if ( pPerfEditor ) - { - pPerfEditor->OnInGameMouseWheelEvent( nDelta ); - } -#endif -} - //----------------------------------------------------------------------------- // Purpose: Engine can issue a key event // Input : eventcode - @@ -1419,23 +1525,23 @@ int CHLClient::IN_KeyEvent( int eventcode, ButtonCode_t keynum, const char *pszC void CHLClient::ExtraMouseSample( float frametime, bool active ) { - Assert( C_BaseEntity::IsAbsRecomputationsEnabled() ); - Assert( C_BaseEntity::IsAbsQueriesValid() ); + bool bSave = C_BaseEntity::IsAbsRecomputationsEnabled(); + C_BaseEntity::EnableAbsRecomputations( true ); + + ABS_QUERY_GUARD( true ); C_BaseAnimating::AutoAllowBoneAccess boneaccess( true, false ); MDLCACHE_CRITICAL_SECTION(); input->ExtraMouseSample( frametime, active ); + + C_BaseEntity::EnableAbsRecomputations( bSave ); } void CHLClient::IN_SetSampleTime( float frametime ) { input->Joystick_SetSampleTime( frametime ); input->IN_SetSampleTime( frametime ); - -#ifdef SIXENSE - g_pSixenseInput->ResetFrameTime( frametime ); -#endif } //----------------------------------------------------------------------------- // Purpose: Fills in usercmd_s structure based on current view angles and key/controller inputs @@ -1461,20 +1567,19 @@ void CHLClient::CreateMove ( int sequence_number, float input_sample_frametime, // from - // to - //----------------------------------------------------------------------------- -bool CHLClient::WriteUsercmdDeltaToBuffer( bf_write *buf, int from, int to, bool isnewcommand ) +bool CHLClient::WriteUsercmdDeltaToBuffer( int nSlot, bf_write *buf, int from, int to, bool isnewcommand ) { - return input->WriteUsercmdDeltaToBuffer( buf, from, to, isnewcommand ); + return input->WriteUsercmdDeltaToBuffer( nSlot, buf, from, to, isnewcommand ); } //----------------------------------------------------------------------------- // Purpose: // Input : buf - // buffersize - -// slot - //----------------------------------------------------------------------------- -void CHLClient::EncodeUserCmdToBuffer( bf_write& buf, int slot ) +void CHLClient::EncodeUserCmdToBuffer( int nSlot, bf_write& buf, int slot ) { - input->EncodeUserCmdToBuffer( buf, slot ); + input->EncodeUserCmdToBuffer( nSlot, buf, slot ); } //----------------------------------------------------------------------------- @@ -1483,9 +1588,9 @@ void CHLClient::EncodeUserCmdToBuffer( bf_write& buf, int slot ) // buffersize - // slot - //----------------------------------------------------------------------------- -void CHLClient::DecodeUserCmdFromBuffer( bf_read& buf, int slot ) +void CHLClient::DecodeUserCmdFromBuffer( int nSlot, bf_read& buf, int slot ) { - input->DecodeUserCmdFromBuffer( buf, slot ); + input->DecodeUserCmdFromBuffer( nSlot, buf, slot ); } //----------------------------------------------------------------------------- @@ -1514,59 +1619,172 @@ bool CHLClient::GetPlayerView( CViewSetup &playerView ) } //----------------------------------------------------------------------------- -// Matchmaking +// //----------------------------------------------------------------------------- -void CHLClient::SetupGameProperties( CUtlVector< XUSER_CONTEXT > &contexts, CUtlVector< XUSER_PROPERTY > &properties ) +void CHLClient::InvalidateMdlCache() { - presence->SetupGameProperties( contexts, properties ); + C_BaseAnimating *pAnimating; + for ( C_BaseEntity *pEntity = ClientEntityList().FirstBaseEntity(); pEntity; pEntity = ClientEntityList().NextBaseEntity(pEntity) ) + { + pAnimating = pEntity->GetBaseAnimating(); + if ( pAnimating ) + { + pAnimating->InvalidateMdlCache(); + } + } + CStudioHdr::CActivityToSequenceMapping::ResetMappings(); } -uint CHLClient::GetPresenceID( const char *pIDName ) +//----------------------------------------------------------------------------- +// Purpose: +// Input : *pSF - +//----------------------------------------------------------------------------- +void CHLClient::View_Fade( ScreenFade_t *pSF ) +{ + if ( pSF != NULL ) + { + FOR_EACH_VALID_SPLITSCREEN_PLAYER( hh ) + { + ACTIVE_SPLITSCREEN_PLAYER_GUARD( hh ); + GetViewEffects()->Fade( *pSF ); + } + } +} + +// CPU level +//----------------------------------------------------------------------------- +void ConfigureCurrentSystemLevel( ); +void OnCPULevelChanged( IConVar *var, const char *pOldValue, float flOldValue ) +{ + ConfigureCurrentSystemLevel(); +} + +static ConVar cpu_level( "cpu_level", "2", 0, "CPU Level - Default: High", OnCPULevelChanged ); +CPULevel_t GetCPULevel() { - return presence->GetPresenceID( pIDName ); + if ( IsX360() ) + return CPU_LEVEL_360; + + return GetActualCPULevel(); } -const char *CHLClient::GetPropertyIdString( const uint id ) +CPULevel_t GetActualCPULevel() +{ + // Should we cache system_level off during level init? + CPULevel_t nSystemLevel = (CPULevel_t)clamp( cpu_level.GetInt(), 0, CPU_LEVEL_PC_COUNT-1 ); + return nSystemLevel; +} + + + +//----------------------------------------------------------------------------- +// GPU level +//----------------------------------------------------------------------------- +void OnGPULevelChanged( IConVar *var, const char *pOldValue, float flOldValue ) +{ + ConfigureCurrentSystemLevel(); +} + +static ConVar gpu_level( "gpu_level", "3", 0, "GPU Level - Default: High", OnGPULevelChanged ); +GPULevel_t GetGPULevel() +{ + if ( IsX360() ) + return GPU_LEVEL_360; + + // Should we cache system_level off during level init? + GPULevel_t nSystemLevel = (GPULevel_t)clamp( gpu_level.GetInt(), 0, GPU_LEVEL_PC_COUNT-1 ); + return nSystemLevel; +} + + +//----------------------------------------------------------------------------- +// System Memory level +//----------------------------------------------------------------------------- +void OnMemLevelChanged( IConVar *var, const char *pOldValue, float flOldValue ) +{ + ConfigureCurrentSystemLevel(); +} + +static ConVar mem_level( "mem_level", "2", 0, "Memory Level - Default: High", OnMemLevelChanged ); +MemLevel_t GetMemLevel() +{ + if ( IsX360() ) + return MEM_LEVEL_360; + + // Should we cache system_level off during level init? + MemLevel_t nSystemLevel = (MemLevel_t)clamp( mem_level.GetInt(), 0, MEM_LEVEL_PC_COUNT-1 ); + return nSystemLevel; +} + +//----------------------------------------------------------------------------- +// GPU Memory level +//----------------------------------------------------------------------------- +void OnGPUMemLevelChanged( IConVar *var, const char *pOldValue, float flOldValue ) { - return presence->GetPropertyIdString( id ); + ConfigureCurrentSystemLevel(); } -void CHLClient::GetPropertyDisplayString( uint id, uint value, char *pOutput, int nBytes ) +static ConVar gpu_mem_level( "gpu_mem_level", "2", 0, "Memory Level - Default: High", OnGPUMemLevelChanged ); +GPUMemLevel_t GetGPUMemLevel() { - presence->GetPropertyDisplayString( id, value, pOutput, nBytes ); -} + if ( IsX360() ) + return GPU_MEM_LEVEL_360; -void CHLClient::StartStatsReporting( HANDLE handle, bool bArbitrated ) -{ - presence->StartStatsReporting( handle, bArbitrated ); + // Should we cache system_level off during level init? + GPUMemLevel_t nSystemLevel = (GPUMemLevel_t)clamp( gpu_mem_level.GetInt(), 0, GPU_MEM_LEVEL_PC_COUNT-1 ); + return nSystemLevel; } -//----------------------------------------------------------------------------- -// -//----------------------------------------------------------------------------- -void CHLClient::InvalidateMdlCache() +void ConfigureCurrentSystemLevel() { - C_BaseAnimating *pAnimating; - for ( C_BaseEntity *pEntity = ClientEntityList().FirstBaseEntity(); pEntity; pEntity = ClientEntityList().NextBaseEntity(pEntity) ) + int nCPULevel = GetCPULevel(); + if ( nCPULevel == CPU_LEVEL_360 ) { - pAnimating = dynamic_cast(pEntity); - if ( pAnimating ) - { - pAnimating->InvalidateMdlCache(); - } + nCPULevel = 360; } -} -//----------------------------------------------------------------------------- -// Purpose: -// Input : *pSF - -//----------------------------------------------------------------------------- -void CHLClient::View_Fade( ScreenFade_t *pSF ) -{ - if ( pSF != NULL ) - vieweffects->Fade( *pSF ); + int nGPULevel = GetGPULevel(); + if ( nGPULevel == GPU_LEVEL_360 ) + { + nGPULevel = 360; + } + + int nMemLevel = GetMemLevel(); + if ( nMemLevel == MEM_LEVEL_360 ) + { + nMemLevel = 360; + } + + int nGPUMemLevel = GetGPUMemLevel(); + if ( nGPUMemLevel == GPU_MEM_LEVEL_360 ) + { + nGPUMemLevel = 360; + } + +#if defined( SWARM_DLL ) + char szModName[32] = "swarm"; +#elif defined ( HL2_EPISODIC ) + char szModName[32] = "ep2"; +#elif defined ( SDK_CLIENT_DLL ) + char szModName[32] = "sdk"; +#endif + + UpdateSystemLevel( nCPULevel, nGPULevel, nMemLevel, nGPUMemLevel, VGui_IsSplitScreen(), szModName ); + + if ( engine ) + { + engine->ConfigureSystemLevel( nCPULevel, nGPULevel ); + } + + C_BaseEntity::UpdateVisibilityAllEntities(); + if ( view ) + { + view->InitFadeData(); + } } + + //----------------------------------------------------------------------------- // Purpose: Per level init //----------------------------------------------------------------------------- @@ -1577,34 +1795,35 @@ void CHLClient::LevelInitPreEntity( char const* pMapName ) return; g_bLevelInitialized = true; + engine->TickProgressBar(); + input->LevelInit(); - vieweffects->LevelInit(); - - //Tony; loadup per-map manifests. - ParseParticleEffectsMap( pMapName, true ); + for ( int hh = 0; hh < MAX_SPLITSCREEN_PLAYERS; ++hh ) + { + ACTIVE_SPLITSCREEN_PLAYER_GUARD( hh ); + GetViewEffects()->LevelInit(); + } // Tell mode manager that map is changing modemanager->LevelInit( pMapName ); ParticleMgr()->LevelInit(); + ClientVoiceMgr_LevelInit(); + hudlcd->SetGlobalStat( "(mapname)", pMapName ); C_BaseTempEntity::ClearDynamicTempEnts(); clienteffects->Flush(); view->LevelInit(); tempents->LevelInit(); - ResetToneMapping(1.0); - - IGameSystem::LevelInitPreEntityAllSystems(pMapName); - -#ifdef USES_ECON_ITEMS - GameItemSchema_t *pItemSchema = ItemSystem()->GetItemSchema(); - if ( pItemSchema ) + for ( int hh = 0; hh < MAX_SPLITSCREEN_PLAYERS; ++hh ) { - pItemSchema->BInitFromDelayedBuffer(); + ACTIVE_SPLITSCREEN_PLAYER_GUARD( hh ); + ResetToneMapping(1.0); } -#endif // USES_ECON_ITEMS + + IGameSystem::LevelInitPreEntityAllSystems(pMapName); ResetWindspeed(); @@ -1630,8 +1849,14 @@ void CHLClient::LevelInitPreEntity( char const* pMapName ) // Check low violence settings for this map g_RagdollLVManager.SetLowViolence( pMapName ); - gHUD.LevelInit(); - gTouch.LevelInit(); + for ( int hh = 0; hh < MAX_SPLITSCREEN_PLAYERS; ++hh ) + { + ACTIVE_SPLITSCREEN_PLAYER_GUARD( hh ); + + engine->TickProgressBar(); + + GetHud().LevelInit(); + } #if defined( REPLAY_ENABLED ) // Initialize replay ragdoll recorder @@ -1648,9 +1873,15 @@ void CHLClient::LevelInitPreEntity( char const* pMapName ) //----------------------------------------------------------------------------- void CHLClient::LevelInitPostEntity( ) { + ABS_QUERY_GUARD( true ); + IGameSystem::LevelInitPostEntityAllSystems(); C_PhysPropClientside::RecreateAll(); - internalCenterPrint->Clear(); + for ( int hh = 0; hh < MAX_SPLITSCREEN_PLAYERS; ++hh ) + { + ACTIVE_SPLITSCREEN_PLAYER_GUARD( hh ); + GetCenterPrint()->Clear(); + } } //----------------------------------------------------------------------------- @@ -1664,12 +1895,6 @@ void CHLClient::ResetStringTablePointers() g_pStringTableMaterials = NULL; g_pStringTableInfoPanel = NULL; g_pStringTableClientSideChoreoScenes = NULL; - g_pStringTableServerMapCycle = NULL; - -#ifdef TF_CLIENT_DLL - g_pStringTableServerPopFiles = NULL; - g_pStringTableServerMapCycleMvM = NULL; -#endif } //----------------------------------------------------------------------------- @@ -1679,7 +1904,10 @@ void CHLClient::LevelShutdown( void ) { // HACK: Bogus, but the logic is too complicated in the engine if (!g_bLevelInitialized) + { + ResetStringTablePointers(); return; + } g_bLevelInitialized = false; @@ -1715,19 +1943,29 @@ void CHLClient::LevelShutdown( void ) beams->ClearBeams(); ParticleMgr()->RemoveAllEffects(); - StopAllRumbleEffects(); + for ( int hh = 0; hh < MAX_SPLITSCREEN_PLAYERS; ++hh ) + { + StopAllRumbleEffects( hh ); + } + + for ( int hh = 0; hh < MAX_SPLITSCREEN_PLAYERS; ++hh ) + { + ACTIVE_SPLITSCREEN_PLAYER_GUARD( hh ); + GetHud().LevelShutdown(); + } - gHUD.LevelShutdown(); + for ( int hh = 0; hh < MAX_SPLITSCREEN_PLAYERS; ++hh ) + { + ACTIVE_SPLITSCREEN_PLAYER_GUARD( hh ); + GetCenterPrint()->Clear(); + } - internalCenterPrint->Clear(); + ClientVoiceMgr_LevelShutdown(); messagechars->Clear(); -#ifndef TF_CLIENT_DLL - // don't want to do this for TF2 because we have particle systems in our - // character loadout screen that can be viewed when we're not connected to a server + g_pParticleSystemMgr->LevelShutdown(); g_pParticleSystemMgr->UncacheAllParticleSystems(); -#endif UncacheAllMaterials(); #ifdef _XBOX @@ -1737,6 +1975,8 @@ void CHLClient::LevelShutdown( void ) // string tables are cleared on disconnect from a server, so reset our global pointers to NULL ResetStringTablePointers(); + CStudioHdr::CActivityToSequenceMapping::ResetMappings(); + #if defined( REPLAY_ENABLED ) // Shutdown the ragdoll recorder CReplayRagdollRecorder::Instance().Shutdown(); @@ -1751,11 +1991,13 @@ void CHLClient::LevelShutdown( void ) //----------------------------------------------------------------------------- void CHLClient::SetCrosshairAngle( const QAngle& angle ) { +#ifndef INFESTED_DLL CHudCrosshair *crosshair = GET_HUDELEMENT( CHudCrosshair ); if ( crosshair ) { crosshair->SetCrosshairAngle( angle ); } +#endif } //----------------------------------------------------------------------------- @@ -1798,9 +2040,9 @@ int CHLClient::GetSpriteSize( void ) const // Input : entindex - // bTalking - //----------------------------------------------------------------------------- -void CHLClient::VoiceStatus( int entindex, qboolean bTalking ) +void CHLClient::VoiceStatus( int entindex, int iSsSlot, qboolean bTalking ) { - GetClientVoiceMgr()->UpdateSpeakerStatus( entindex, !!bTalking ); + GetClientVoiceMgr()->UpdateSpeakerStatus( entindex, iSsSlot, !!bTalking ); } @@ -1815,16 +2057,36 @@ void OnMaterialStringTableChanged( void *object, INetworkStringTable *stringTabl } +//----------------------------------------------------------------------------- +// Called when the string table for dispatch effects changes +//----------------------------------------------------------------------------- +void OnEffectStringTableChanged( void *object, INetworkStringTable *stringTable, int stringNumber, const char *newString, void const *newData ) +{ + // Make sure this puppy is precached + g_pPrecacheSystem->Cache( g_pPrecacheHandler, DISPATCH_EFFECT, newString, true, RESOURCE_LIST_INVALID, true ); + RequestCacheUsedMaterials(); +} + + //----------------------------------------------------------------------------- // Called when the string table for particle systems changes //----------------------------------------------------------------------------- void OnParticleSystemStringTableChanged( void *object, INetworkStringTable *stringTable, int stringNumber, const char *newString, void const *newData ) { // Make sure this puppy is precached - g_pParticleSystemMgr->PrecacheParticleSystem( newString ); + g_pParticleSystemMgr->PrecacheParticleSystem( stringNumber, newString ); RequestCacheUsedMaterials(); } +//----------------------------------------------------------------------------- +// Called when the string table for particle files changes +//----------------------------------------------------------------------------- +void OnPrecacheParticleFile( void *object, INetworkStringTable *stringTable, int stringNumber, const char *newString, void const *newData ) +{ + g_pParticleSystemMgr->ShouldLoadSheets( true ); + g_pParticleSystemMgr->ReadParticleConfigFile( newString, true, false ); + g_pParticleSystemMgr->DecommitTempMemory(); +} //----------------------------------------------------------------------------- // Called when the string table for VGUI changes @@ -1875,6 +2137,9 @@ void CHLClient::InstallStringTableCallback( const char *tableName ) else if ( !Q_strcasecmp( tableName, "EffectDispatch" ) ) { g_StringTableEffectDispatch = networkstringtable->FindTable( tableName ); + + // When the material list changes, we need to know immediately + g_StringTableEffectDispatch->SetStringChangedCallback( NULL, OnEffectStringTableChanged ); } else if ( !Q_strcasecmp( tableName, "InfoPanel" ) ) { @@ -1883,6 +2148,7 @@ void CHLClient::InstallStringTableCallback( const char *tableName ) else if ( !Q_strcasecmp( tableName, "Scenes" ) ) { g_pStringTableClientSideChoreoScenes = networkstringtable->FindTable( tableName ); + networkstringtable->SetAllowClientSideAddString( g_pStringTableClientSideChoreoScenes, true ); g_pStringTableClientSideChoreoScenes->SetStringChangedCallback( NULL, OnSceneStringTableChanged ); } else if ( !Q_strcasecmp( tableName, "ParticleEffectNames" ) ) @@ -1892,22 +2158,19 @@ void CHLClient::InstallStringTableCallback( const char *tableName ) // When the particle system list changes, we need to know immediately g_pStringTableParticleEffectNames->SetStringChangedCallback( NULL, OnParticleSystemStringTableChanged ); } - else if ( !Q_strcasecmp( tableName, "ServerMapCycle" ) ) + else if ( !Q_strcasecmp( tableName, "ExtraParticleFilesTable" ) ) { - g_pStringTableServerMapCycle = networkstringtable->FindTable( tableName ); - } -#ifdef TF_CLIENT_DLL - else if ( !Q_strcasecmp( tableName, "ServerPopFiles" ) ) - { - g_pStringTableServerPopFiles = networkstringtable->FindTable( tableName ); + g_pStringTableExtraParticleFiles = networkstringtable->FindTable( tableName ); + networkstringtable->SetAllowClientSideAddString( g_pStringTableExtraParticleFiles, true ); + // When the particle system list changes, we need to know immediately + g_pStringTableExtraParticleFiles->SetStringChangedCallback( NULL, OnPrecacheParticleFile ); } - else if ( !Q_strcasecmp( tableName, "ServerMapCycleMvM" ) ) + else { - g_pStringTableServerMapCycleMvM = networkstringtable->FindTable( tableName ); + // Pass tablename to gamerules last if all other checks fail + InstallStringTableCallback_GameRules( tableName ); } -#endif - InstallStringTableCallback_GameRules(); } @@ -1930,21 +2193,18 @@ void CHLClient::PrecacheMaterial( const char *pMaterialName ) IMaterial *pMaterial = materials->FindMaterial( pTempBuf, TEXTURE_GROUP_PRECACHED ); if ( !IsErrorMaterial( pMaterial ) ) { - pMaterial->IncrementReferenceCount(); - m_CachedMaterials.AddToTail( pMaterial ); - } - else - { - if (IsOSX()) + int idx = m_CachedMaterials.Find( pMaterial ); + if ( idx == m_CachedMaterials.InvalidIndex() ) { - printf("\n ##### CHLClient::PrecacheMaterial could not find material %s (%s)", pMaterialName, pTempBuf ); + pMaterial->IncrementReferenceCount(); + m_CachedMaterials.Insert( pMaterial ); } } } void CHLClient::UncacheAllMaterials( ) { - for (int i = m_CachedMaterials.Count(); --i >= 0; ) + for ( int i = m_CachedMaterials.FirstInorder(); i != m_CachedMaterials.InvalidIndex(); i = m_CachedMaterials.NextInorder( i ) ) { m_CachedMaterials[i]->DecrementReferenceCount(); } @@ -1971,23 +2231,12 @@ void SimulateEntities() // Service timer events (think functions). ClientThinkList()->PerformThinkFunctions(); - // TODO: make an ISimulateable interface so C_BaseNetworkables can simulate? - { - VPROF_("C_BaseEntity::Simulate", 1, VPROF_BUDGETGROUP_CLIENT_SIM, false, BUDGETFLAG_CLIENT); - C_BaseEntityIterator iterator; - C_BaseEntity *pEnt; - while ( (pEnt = iterator.Next()) != NULL ) - { - pEnt->Simulate(); - } - } + C_BaseEntity::SimulateEntities(); } bool AddDataChangeEvent( IClientNetworkable *ent, DataUpdateType_t updateType, int *pStoredEvent ) { - VPROF( "AddDataChangeEvent" ); - Assert( ent ); // Make sure we don't already have an event queued for this guy. if ( *pStoredEvent >= 0 ) @@ -2018,6 +2267,9 @@ void ClearDataChangedEvent( int iStoredEvent ) void ProcessOnDataChangedEvents() { VPROF_("ProcessOnDataChangedEvents", 1, VPROF_BUDGETGROUP_CLIENT_SIM, false, BUDGETFLAG_CLIENT); + int nSave = GET_ACTIVE_SPLITSCREEN_SLOT(); + bool bSaveAccess = engine->SetLocalPlayerIsResolvable( __FILE__, __LINE__, false ); + FOR_EACH_LL( g_DataChangedEvents, i ) { CDataChangedEvent *pEvent = &g_DataChangedEvents[i]; @@ -2025,12 +2277,17 @@ void ProcessOnDataChangedEvents() // Reset their stored event identifier. *pEvent->m_pStoredEvent = -1; + // Send the event. IClientNetworkable *pNetworkable = pEvent->m_pEntity; + pNetworkable->OnDataChanged( pEvent->m_UpdateType ); } g_DataChangedEvents.Purge(); + + engine->SetActiveSplitScreenPlayerSlot( nSave ); + engine->SetLocalPlayerIsResolvable( __FILE__, __LINE__, bSaveAccess ); } @@ -2107,9 +2364,7 @@ void OnRenderStart() MDLCACHE_CRITICAL_SECTION(); MDLCACHE_COARSE_LOCK(); -#ifdef PORTAL - g_pPortalRender->UpdatePortalPixelVisibility(); //updating this one or two lines before querying again just isn't cutting it. Update as soon as it's cheap to do so. -#endif + partition->SuppressLists( PARTITION_ALL_CLIENT_EDICTS, true ); C_BaseEntity::SetAbsQueriesValid( false ); @@ -2127,6 +2382,7 @@ void OnRenderStart() VPROF( "OnRenderStart: dirty bone caches"); // Invalidate any bone information. C_BaseAnimating::InvalidateBoneCaches(); + C_BaseFlex::InvalidateFlexCaches(); C_BaseEntity::SetAbsQueriesValid( true ); C_BaseEntity::EnableAbsRecomputations( true ); @@ -2142,18 +2398,33 @@ void OnRenderStart() // Make sure the camera simulation happens before OnRenderStart, where it's used. // NOTE: the only thing that happens in CAM_Think is thirdperson related code. - input->CAM_Think(); + for ( int hh = 0; hh < MAX_SPLITSCREEN_PLAYERS; ++hh ) + { + ACTIVE_SPLITSCREEN_PLAYER_GUARD( hh ); + input->CAM_Think(); + } + + C_BaseAnimating::PopBoneAccess( "OnRenderStart->CViewRender::SetUpView" ); // pops the (true, false) bone access set in OnRenderStart + + // Enable access to all model bones until rendering is done + C_BaseAnimating::PushAllowBoneAccess( true, true, "CViewRender::SetUpView->OnRenderEnd" ); // pop is in OnRenderEnd() + - // This will place the player + the view models + all parent - // entities at the correct abs position so that their attachment points - // are at the correct location - view->OnRenderStart(); - RopeManager()->OnRenderStart(); +#ifdef DEMOPOLISH_ENABLED + // Update demo polish subsystem if necessary + DemoPolish_Think(); +#endif // This will place all entities in the correct position in world space and in the KD-tree + // NOTE: Doing this before view->OnRenderStart() because the player can be in hierarchy with + // a client-side animated entity. So the viewport position is dependent on this animation sometimes. C_BaseAnimating::UpdateClientSideAnimations(); + // This will place the player + the view models + all parent + // entities at the correct abs position so that their attachment points + // are at the correct location + view->OnRenderStart(); partition->SuppressLists( PARTITION_ALL_CLIENT_EDICTS, false ); // Process OnDataChanged events. @@ -2167,14 +2438,13 @@ void OnRenderStart() // update the color correction weights. // FIXME: The place where IGameSystem::Update is called should be in here // so we don't have to explicitly call ResetColorCorrectionWeights + SimulateEntities, etc. - g_pColorCorrectionMgr->ResetColorCorrectionWeights(); + + C_BaseAnimating::ThreadedBoneSetup(); // Simulate all the entities. SimulateEntities(); PhysicsSimulate(); - C_BaseAnimating::ThreadedBoneSetup(); - { VPROF_("Client TempEnts", 0, VPROF_BUDGETGROUP_CLIENT_SIM, false, BUDGETFLAG_CLIENT); // This creates things like temp entities. @@ -2193,9 +2463,6 @@ void OnRenderStart() // Update particle effects (eventually, the effects should use Simulate() instead of having // their own update system). { - // Enable FP exceptions here when FP_EXCEPTIONS_ENABLED is defined, - // to help track down bad math. - FPExceptionEnabler enableExceptions; VPROF_BUDGET( "ParticleMgr()->Simulate", VPROF_BUDGETGROUP_PARTICLE_SIMULATION ); ParticleMgr()->Simulate( gpGlobals->frametime ); } @@ -2216,13 +2483,22 @@ void OnRenderStart() CReplayRagdollCache::Instance().Think(); #endif + // update dynamic light state. Necessary for light cache to work properly for d- and elights + engine->UpdateDAndELights(); + // Finally, link all the entities into the leaf system right before rendering. C_BaseEntity::AddVisibleEntities(); -} + g_pClientLeafSystem->RecomputeRenderableLeaves(); + g_pClientShadowMgr->ReprojectShadows(); + g_pClientShadowMgr->AdvanceFrame(); + g_pClientLeafSystem->DisableLeafReinsertion( true ); +} void OnRenderEnd() { + g_pClientLeafSystem->DisableLeafReinsertion( false ); + // Disallow access to bones (access is enabled in CViewRender::SetUpView). C_BaseAnimating::PopBoneAccess( "CViewRender::SetUpView->OnRenderEnd" ); @@ -2236,6 +2512,7 @@ void OnRenderEnd() void CHLClient::FrameStageNotify( ClientFrameStage_t curStage ) { g_CurFrameStage = curStage; + g_bEngineIsHLTV = engine->IsHLTV(); switch( curStage ) { @@ -2246,6 +2523,8 @@ void CHLClient::FrameStageNotify( ClientFrameStage_t curStage ) { VPROF( "CHLClient::FrameStageNotify FRAME_RENDER_START" ); + engine->SetLocalPlayerIsResolvable( __FILE__, __LINE__, false ); + // Last thing before rendering, run simulation. OnRenderStart(); } @@ -2256,6 +2535,8 @@ void CHLClient::FrameStageNotify( ClientFrameStage_t curStage ) VPROF( "CHLClient::FrameStageNotify FRAME_RENDER_END" ); OnRenderEnd(); + engine->SetLocalPlayerIsResolvable( __FILE__, __LINE__, false ); + PREDICTION_SPEWVALUECHANGES(); } break; @@ -2308,6 +2589,7 @@ void CHLClient::FrameStageNotify( ClientFrameStage_t curStage ) SetFXCreationAllowed( true ); SetBeamCreationAllowed( true ); C_BaseEntity::CheckCLInterpChanged(); + engine->SetLocalPlayerIsResolvable( __FILE__, __LINE__, false ); } break; } @@ -2390,6 +2672,8 @@ void CHLClient::DispatchOnRestore() void CHLClient::WriteSaveGameScreenshot( const char *pFilename ) { + // Single player doesn't support split screen yet!!! + ACTIVE_SPLITSCREEN_PLAYER_GUARD( 0 ); view->WriteSaveGameScreenshot( pFilename ); } @@ -2402,10 +2686,9 @@ void CHLClient::EmitSentenceCloseCaption( char const *tokenstream ) if ( !closecaption.GetBool() ) return; - CHudCloseCaption *hudCloseCaption = GET_HUDELEMENT( CHudCloseCaption ); - if ( hudCloseCaption ) + if ( m_pHudCloseCaption ) { - hudCloseCaption->ProcessSentenceCaptionStream( tokenstream ); + m_pHudCloseCaption->ProcessSentenceCaptionStream( tokenstream ); } } @@ -2417,10 +2700,9 @@ void CHLClient::EmitCloseCaption( char const *captionname, float duration ) if ( !closecaption.GetBool() ) return; - CHudCloseCaption *hudCloseCaption = GET_HUDELEMENT( CHudCloseCaption ); - if ( hudCloseCaption ) + if ( m_pHudCloseCaption ) { - hudCloseCaption->ProcessCaption( captionname, duration ); + m_pHudCloseCaption->ProcessCaption( captionname, duration ); } } @@ -2441,14 +2723,40 @@ bool CHLClient::CanRecordDemo( char *errorMsg, int length ) const void CHLClient::OnDemoRecordStart( char const* pDemoBaseName ) { +#ifdef DEMOPOLISH_ENABLED + if ( IsDemoPolishEnabled() ) + { + if ( !CDemoPolishRecorder::Instance().Init( pDemoBaseName ) ) + { + CDemoPolishRecorder::Instance().Shutdown(); + } + } +#endif } void CHLClient::OnDemoRecordStop() { +#ifdef DEMOPOLISH_ENABLED + if ( DemoPolish_GetRecorder().m_bInit ) + { + DemoPolish_GetRecorder().Shutdown(); + } +#endif } void CHLClient::OnDemoPlaybackStart( char const* pDemoBaseName ) { +#ifdef DEMOPOLISH_ENABLED + if ( IsDemoPolishEnabled() ) + { + Assert( pDemoBaseName ); + if ( !DemoPolish_GetController().Init( pDemoBaseName ) ) + { + DemoPolish_GetController().Shutdown(); + } + } +#endif + #if defined( REPLAY_ENABLED ) // Load any ragdoll override frames from disk char szRagdollFile[MAX_OSPATH]; @@ -2471,187 +2779,291 @@ void CHLClient::OnDemoPlaybackStop() #endif } -int CHLClient::GetScreenWidth() +void CHLClient::RecordDemoPolishUserInput( int nCmdIndex ) { - return ScreenWidth(); +#ifdef DEMOPOLISH_ENABLED + ASSERT_LOCAL_PLAYER_RESOLVABLE(); + int nSlot = GET_ACTIVE_SPLITSCREEN_SLOT(); + + Assert( engine->IsRecordingDemo() ); + Assert( IsDemoPolishEnabled() ); // NOTE: cl_demo_polish_enabled checked in engine. + + CUserCmd const* pUserCmd = input->GetUserCmd( nSlot, nCmdIndex ); + Assert( pUserCmd ); + if ( pUserCmd ) + { + DemoPolish_GetRecorder().RecordUserInput( pUserCmd ); + } +#endif } -int CHLClient::GetScreenHeight() +bool CHLClient::CacheReplayRagdolls( const char* pFilename, int nStartTick ) { - return ScreenHeight(); +#if defined( REPLAY_ENABLED ) + return Replay_CacheRagdolls( pFilename, nStartTick ); +#else + return false; +#endif } // NEW INTERFACES // save game screenshot writing -void CHLClient::WriteSaveGameScreenshotOfSize( const char *pFilename, int width, int height, bool bCreatePowerOf2Padded/*=false*/, - bool bWriteVTF/*=false*/ ) +void CHLClient::WriteSaveGameScreenshotOfSize( const char *pFilename, int width, int height ) { - view->WriteSaveGameScreenshotOfSize( pFilename, width, height, bCreatePowerOf2Padded, bWriteVTF ); + view->WriteSaveGameScreenshotOfSize( pFilename, width, height ); } // See RenderViewInfo_t void CHLClient::RenderView( const CViewSetup &setup, int nClearFlags, int whatToDraw ) { VPROF("RenderView"); - view->RenderView( setup, nClearFlags, whatToDraw ); + view->RenderView( setup, setup, nClearFlags, whatToDraw ); } -void ReloadSoundEntriesInList( IFileList *pFilesToReload ); +bool CHLClient::ShouldHideLoadingPlaque( void ) +{ + return false; -//----------------------------------------------------------------------------- -// For sv_pure mode. The filesystem figures out which files the client needs to reload to be "pure" ala the server's preferences. -//----------------------------------------------------------------------------- -void CHLClient::ReloadFilesInList( IFileList *pFilesToReload ) +} + +void CHLClient::OnActiveSplitscreenPlayerChanged( int nNewSlot ) { - ReloadParticleEffectsInList( pFilesToReload ); - ReloadSoundEntriesInList( pFilesToReload ); } -bool CHLClient::HandleUiToggle() +void CHLClient::OnSplitScreenStateChanged() { -#if defined( REPLAY_ENABLED ) - if ( !g_pEngineReplay || !g_pEngineReplay->IsSupportedModAndPlatform() ) - return false; + VGui_OnSplitScreenStateChanged(); + IterateRemoteSplitScreenViewSlots_Push( true ); + FOR_EACH_VALID_SPLITSCREEN_PLAYER( i ) + { + ACTIVE_SPLITSCREEN_PLAYER_GUARD_VGUI( i ); + GetClientMode()->Layout(); + GetHud().OnSplitScreenStateChanged(); + } + IterateRemoteSplitScreenViewSlots_Pop(); - CReplayPerformanceEditorPanel *pEditor = ReplayUI_GetPerformanceEditor(); - if ( !pEditor ) - return false; + GetFullscreenClientMode()->Layout( true ); - pEditor->HandleUiToggle(); + vgui::surface()->ResetFontCaches(); - return true; + // Update visibility for all ents so that the second viewport for the split player guy looks right, etc. + C_BaseEntityIterator iterator; + C_BaseEntity *pEnt; + while ( (pEnt = iterator.Next()) != NULL ) + { + pEnt->UpdateVisibility(); + } +} + +void CHLClient::CenterStringOff() +{ + FOR_EACH_VALID_SPLITSCREEN_PLAYER( i ) + { + ACTIVE_SPLITSCREEN_PLAYER_GUARD( i ); + GetCenterPrint()->Clear(); + } -#else - return false; -#endif } -bool CHLClient::ShouldAllowConsole() +void CHLClient::OnScreenSizeChanged( int nOldWidth, int nOldHeight ) { - return true; + // Tell split screen system + VGui_OnScreenSizeChanged(); +} + +IMaterialProxy *CHLClient::InstantiateMaterialProxy( const char *proxyName ) +{ +#ifdef GAMEUI_UISYSTEM2_ENABLED + IMaterialProxy *pProxy = g_pGameUIGameSystem->CreateProxy( proxyName ); + if ( pProxy ) + return pProxy; +#endif + return GetMaterialProxyDict().CreateProxy( proxyName ); } -CRenamedRecvTableInfo *CHLClient::GetRenamedRecvTableInfos() +vgui::VPANEL CHLClient::GetFullscreenClientDLLVPanel( void ) { - return g_pRenamedRecvTableInfoHead; + return VGui_GetFullscreenRootVPANEL(); } -CMouthInfo g_ClientUIMouth; -// Get the mouthinfo for the sound being played inside UI panels -CMouthInfo *CHLClient::GetClientUIMouthInfo() +int XBX_GetActiveUserId() { - return &g_ClientUIMouth; + ASSERT_LOCAL_PLAYER_RESOLVABLE(); + return XBX_GetUserId( GET_ACTIVE_SPLITSCREEN_SLOT() ); } -void CHLClient::FileReceived( const char * fileName, unsigned int transferID ) +//----------------------------------------------------------------------------- +// Purpose: Marks entities as touching +// Input : *e1 - +// *e2 - +//----------------------------------------------------------------------------- +void CHLClient::MarkEntitiesAsTouching( IClientEntity *e1, IClientEntity *e2 ) { - if ( g_pGameRules ) + CBaseEntity *entity = e1->GetBaseEntity(); + CBaseEntity *entityTouched = e2->GetBaseEntity(); + if ( entity && entityTouched ) { - g_pGameRules->OnFileReceived( fileName, transferID ); + trace_t tr; + UTIL_ClearTrace( tr ); + tr.endpos = (entity->GetAbsOrigin() + entityTouched->GetAbsOrigin()) * 0.5; + entity->PhysicsMarkEntitiesAsTouching( entityTouched, tr ); } } -void CHLClient::ClientAdjustStartSoundParams( StartSoundParams_t& params ) +class CKeyBindingListenerMgr : public IKeyBindingListenerMgr { -#ifdef TF_CLIENT_DLL - CBaseEntity *pEntity = ClientEntityList().GetEnt( params.soundsource ); +public: + struct BindingListeners_t + { + BindingListeners_t() + { + } + + BindingListeners_t( const BindingListeners_t &other ) + { + m_List.CopyArray( other.m_List.Base(), other.m_List.Count() ); + } + + CUtlVector< IKeyBindingListener * > m_List; + }; - // A player speaking - if ( params.entchannel == CHAN_VOICE && GameRules() && pEntity && pEntity->IsPlayer() ) + // Callback when button is bound + virtual void AddListenerForCode( IKeyBindingListener *pListener, ButtonCode_t buttonCode ) { - // Use high-pitched voices for other players if the local player has an item that allows them to hear it (Pyro Goggles) - if ( !GameRules()->IsLocalPlayer( params.soundsource ) && IsLocalPlayerUsingVisionFilterFlags( TF_VISION_FILTER_PYRO ) ) + CUtlVector< IKeyBindingListener * > &list = m_CodeListeners[ buttonCode ]; + if ( list.Find( pListener ) != list.InvalidIndex() ) + return; + list.AddToTail( pListener ); + } + + // Callback whenver binding is set to a button + virtual void AddListenerForBinding( IKeyBindingListener *pListener, char const *pchBindingString ) + { + int idx = m_BindingListeners.Find( pchBindingString ); + if ( idx == m_BindingListeners.InvalidIndex() ) { - params.pitch *= 1.3f; + idx = m_BindingListeners.Insert( pchBindingString ); } - // Halloween voice futzery? - else + + CUtlVector< IKeyBindingListener * > &list = m_BindingListeners[ idx ].m_List; + if ( list.Find( pListener ) != list.InvalidIndex() ) + return; + list.AddToTail( pListener ); + } + + virtual void RemoveListener( IKeyBindingListener *pListener ) + { + for ( int i = 0; i < ARRAYSIZE( m_CodeListeners ); ++i ) { - float flHeadScale = 1.f; - CALL_ATTRIB_HOOK_FLOAT_ON_OTHER( pEntity, flHeadScale, head_scale ); + CUtlVector< IKeyBindingListener * > &list = m_CodeListeners[ i ]; + list.FindAndRemove( pListener ); + } - int iHalloweenVoiceSpell = 0; - CALL_ATTRIB_HOOK_INT_ON_OTHER( pEntity, iHalloweenVoiceSpell, halloween_voice_modulation ); - if ( iHalloweenVoiceSpell > 0 ) - { - params.pitch *= 0.8f; - } - else if( flHeadScale != 1.f ) + for ( int i = m_BindingListeners.First(); i != m_BindingListeners.InvalidIndex(); i = m_BindingListeners.Next( i ) ) + { + CUtlVector< IKeyBindingListener * > &list = m_BindingListeners[ i ].m_List; + list.FindAndRemove( pListener ); + } + } + + void OnKeyBindingChanged( ButtonCode_t buttonCode, char const *pchKeyName, char const *pchNewBinding ) + { + int nSplitScreenSlot = GET_ACTIVE_SPLITSCREEN_SLOT(); + + CUtlVector< IKeyBindingListener * > &list = m_CodeListeners[ buttonCode ]; + for ( int i = 0 ; i < list.Count(); ++i ) + { + list[ i ]->OnKeyBindingChanged( nSplitScreenSlot, buttonCode, pchKeyName, pchNewBinding ); + } + + int idx = m_BindingListeners.Find( pchNewBinding ); + if ( idx != m_BindingListeners.InvalidIndex() ) + { + CUtlVector< IKeyBindingListener * > &list = m_BindingListeners[ idx ].m_List; + for ( int i = 0 ; i < list.Count(); ++i ) { - // Big head, deep voice - if( flHeadScale > 1.f ) - { - params.pitch *= 0.8f; - } - else // Small head, high voice - { - params.pitch *= 1.3f; - } + list[ i ]->OnKeyBindingChanged( nSplitScreenSlot, buttonCode, pchKeyName, pchNewBinding ); } } } -#endif -} -const char* CHLClient::TranslateEffectForVisionFilter( const char *pchEffectType, const char *pchEffectName ) -{ - if ( !GameRules() ) - return pchEffectName; +private: + CUtlVector< IKeyBindingListener * > m_CodeListeners[ BUTTON_CODE_COUNT ]; + CUtlDict< BindingListeners_t, int > m_BindingListeners; +}; - return GameRules()->TranslateEffectForVisionFilter( pchEffectType, pchEffectName ); -} +static CKeyBindingListenerMgr g_KeyBindingListenerMgr; -bool CHLClient::DisconnectAttempt( void ) +IKeyBindingListenerMgr *g_pKeyBindingListenerMgr = &g_KeyBindingListenerMgr; +void CHLClient::OnKeyBindingChanged( ButtonCode_t buttonCode, char const *pchKeyName, char const *pchNewBinding ) { - bool bRet = false; - -#if defined( TF_CLIENT_DLL ) - bRet = HandleDisconnectAttempt(); -#endif - - return bRet; + g_KeyBindingListenerMgr.OnKeyBindingChanged( buttonCode, pchKeyName, pchNewBinding ); } -bool CHLClient::IsConnectedUserInfoChangeAllowed( IConVar *pCvar ) +void CHLClient::SetBlurFade( float scale ) { - return GameRules() ? GameRules()->IsConnectedUserInfoChangeAllowed( NULL ) : true; + FOR_EACH_VALID_SPLITSCREEN_PLAYER( hh ) + { + ACTIVE_SPLITSCREEN_PLAYER_GUARD( hh ); + GetClientMode()->SetBlurFade( scale ); + } } -#ifndef NO_STEAM - -CSteamID GetSteamIDForPlayerIndex( int iPlayerIndex ) +void CHLClient::ResetHudCloseCaption() { - player_info_t pi; - if ( steamapicontext && steamapicontext->SteamUtils() ) + if ( !IsX360() ) { - if ( engine->GetPlayerInfo( iPlayerIndex, &pi ) ) - { - if ( pi.friendsID ) - { - return CSteamID( pi.friendsID, 1, steamapicontext->SteamUtils()->GetConnectedUniverse(), k_EAccountTypeIndividual ); - } - } + // only xbox needs to force the close caption system to remount + return; + } + + if ( m_pHudCloseCaption ) + { + // force the caption dictionary to remount + m_pHudCloseCaption->InitCaptionDictionary( NULL, true ); } - return CSteamID(); } +bool CHLClient::SupportsRandomMaps() +{ +#ifdef INFESTED_DLL + return true; +#else + return false; #endif +} + +extern IViewRender *view; - -void CHLClient::IN_TouchEvent( int type, int fingerId, int x, int y ) +//----------------------------------------------------------------------------- +// Purpose: interface from materialsystem to client, currently just for recording into tools +//----------------------------------------------------------------------------- +class CClientMaterialSystem : public IClientMaterialSystem { - if( enginevgui->IsGameUIVisible() ) - return; + virtual HTOOLHANDLE GetCurrentRecordingEntity() + { + if ( !ToolsEnabled() ) + return HTOOLHANDLE_INVALID; - touch_event_t ev; + if ( !clienttools->IsInRecordingMode() ) + return HTOOLHANDLE_INVALID; - ev.type = type; - ev.fingerid = fingerId; - memcpy( &ev.x, &x, sizeof(ev.x) ); - memcpy( &ev.y, &y, sizeof(ev.y) ); + C_BaseEntity *pEnt = view->GetCurrentlyDrawingEntity(); + if ( !pEnt || !pEnt->IsToolRecording() ) + return HTOOLHANDLE_INVALID; - if( type == IE_FingerMotion ) - inputsystem->GetTouchAccumulators( fingerId, ev.dx, ev.dy ); + return pEnt->GetToolHandle(); + } + virtual void PostToolMessage( HTOOLHANDLE hEntity, KeyValues *pMsg ) + { + ToolFramework_PostToolMessage( hEntity, pMsg ); + } +}; + +//----------------------------------------------------------------------------- +// Singleton instance +//----------------------------------------------------------------------------- +static CClientMaterialSystem s_ClientMaterialSystem; +IClientMaterialSystem *g_pClientMaterialSystem = &s_ClientMaterialSystem; +EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CClientMaterialSystem, IClientMaterialSystem, VCLIENTMATERIALSYSTEM_INTERFACE_VERSION, s_ClientMaterialSystem ); - gTouch.ProcessEvent( &ev ); -} diff --git a/game/client/cdll_client_int.h b/game/client/cdll_client_int.h index c24563324..bd6a003bb 100644 --- a/game/client/cdll_client_int.h +++ b/game/client/cdll_client_int.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // @@ -14,8 +14,10 @@ #include "iclientnetworkable.h" #include "utllinkedlist.h" #include "cdll_int.h" +#include "shareddefs.h" #include "eiface.h" - +#include "tier3/tier3.h" +#include "tier2/tier2_logging.h" class IVModelRender; class IVEngineClient; @@ -50,26 +52,13 @@ class IColorCorrectionSystem; class IInputSystem; class ISceneFileCache; class IXboxSystem; // Xbox 360 only -class IMatchmaking; -class IVideoServices; +class IAvi; +class IBik; class CSteamAPIContext; -class IClientReplayContext; -class IReplayManager; -class IEngineReplay; -class IEngineClientReplay; -class IReplayScreenshotManager; -class CSteamID; - -//============================================================================= -// HPE_BEGIN -// [dwenger] Necessary for stats display -//============================================================================= - -class AchievementsAndStatsInterface; - -//============================================================================= -// HPE_END -//============================================================================= +class IReplayHistoryManager; +class ISoundEmitterSystemBase; +enum CPULevel_t; +enum GPULevel_t; extern IVModelRender *modelrender; extern IVEngineClient *engine; @@ -77,11 +66,7 @@ extern IVModelRender *modelrender; extern IVEfx *effects; extern IVRenderView *render; extern IVDebugOverlay *debugoverlay; -extern IMaterialSystem *materials; extern IMaterialSystemStub *materials_stub; -extern IMaterialSystemHardwareConfig *g_pMaterialSystemHardwareConfig; -extern IDataCache *datacache; -extern IMDLCache *mdlcache; extern IVModelInfoClient *modelinfo; extern IEngineVGui *enginevgui; extern ISpatialPartition* partition; @@ -90,8 +75,8 @@ extern IFileSystem *filesystem; extern IStaticPropMgrClient *staticpropmgr; extern IShadowMgr *shadowmgr; extern IEngineSound *enginesound; -extern IMatSystemSurface *g_pMatSystemSurface; extern IEngineTrace *enginetrace; +extern IFileLoggingListener *filelogginglistener; extern IGameUIFuncs *gameuifuncs; extern IGameEventManager2 *gameeventmanager; extern IPhysicsGameTrace *physgametrace; @@ -100,39 +85,31 @@ extern IClientTools *clienttools; extern IInputSystem *inputsystem; extern ISceneFileCache *scenefilecache; extern IXboxSystem *xboxsystem; // Xbox 360 only -extern IMatchmaking *matchmaking; -extern IVideoServices *g_pVideo; +extern IAvi *avi; +extern IBik *bik; extern IUploadGameStats *gamestatsuploader; extern CSteamAPIContext *steamapicontext; -extern IReplaySystem *g_pReplay; -extern IClientReplayContext *g_pClientReplayContext; -extern IReplayManager *g_pReplayManager; -extern IReplayScreenshotManager *g_pReplayScreenshotManager; -extern IEngineReplay *g_pEngineReplay; -extern IEngineClientReplay *g_pEngineClientReplay; - -//============================================================================= -// HPE_BEGIN -// [dwenger] Necessary for stats display -//============================================================================= +extern ISoundEmitterSystemBase *soundemitterbase; -extern AchievementsAndStatsInterface* g_pAchievementsAndStatsInterface; +#ifdef INFESTED_DLL +class IASW_Mission_Chooser; +extern IASW_Mission_Chooser *missionchooser; +#endif +#if defined( REPLAY_ENABLED ) +extern IReplayHistoryManager *g_pReplayHistoryManager; +#endif -//============================================================================= -// HPE_END -//============================================================================= +// Returns the CPU/GPU level +CPULevel_t GetCPULevel(); +// Returns the actual value of the CPU level convar, even on the 360 +CPULevel_t GetActualCPULevel(); +GPULevel_t GetGPULevel(); +void ConfigureCurrentSystemLevel(); // Set to true between LevelInit and LevelShutdown. extern bool g_bLevelInitialized; extern bool g_bTextMode; - -// Kyle says: this is here to obsfucate our accessing of the g_bTextMode variable and for no other purpose. -// See the mess of TF_ANTI_IDLEBOT_VERIFICATION code. If that code doesn't exist anymore, this -// probably also doesn't need to exist anymore. -// -// On a suggestion from Joe, we also point it to an incomplete type. -extern class IClientPurchaseInterfaceV2 *g_pClientPurchaseInterface; - +extern bool g_bEngineIsHLTV; // Returns true if a new OnDataChanged event is registered for this frame. bool AddDataChangeEvent( IClientNetworkable *ent, DataUpdateType_t updateType, int *pStoredEvent ); @@ -157,11 +134,17 @@ const char *GetMaterialNameFromIndex( int nIndex ); //----------------------------------------------------------------------------- // Precache-related methods for particle systems //----------------------------------------------------------------------------- -void PrecacheParticleSystem( const char *pParticleSystemName ); +int PrecacheParticleSystem( const char *pParticleSystemName ); int GetParticleSystemIndex( const char *pParticleSystemName ); const char *GetParticleSystemNameFromIndex( int nIndex ); +//----------------------------------------------------------------------------- +// Precache-related methods for effects +//----------------------------------------------------------------------------- +void PrecacheEffect( const char *pEffectName ); + + //----------------------------------------------------------------------------- // Called during bone setup to test perf //----------------------------------------------------------------------------- @@ -169,12 +152,153 @@ void TrackBoneSetupEnt( C_BaseAnimating *pEnt ); bool IsEngineThreaded(); -#ifndef NO_STEAM +class CVGuiScreenSizeSplitScreenPlayerGuard +{ +public: + CVGuiScreenSizeSplitScreenPlayerGuard( bool bActive, int slot, int nOldSlot ); + CVGuiScreenSizeSplitScreenPlayerGuard( bool bActive, C_BaseEntity *pEntity, int nOldSlot ); + ~CVGuiScreenSizeSplitScreenPlayerGuard(); +private: + + bool m_bNoRestore; + bool m_bOldSetting; + int m_nOldSize[ 2 ]; +}; + +class CSetActiveSplitScreenPlayerGuard : public CVGuiScreenSizeSplitScreenPlayerGuard +{ +public: + CSetActiveSplitScreenPlayerGuard( char const *pchContext, int nLine, int slot, int nOldSlot, bool bSetVguiScreenSize ); + CSetActiveSplitScreenPlayerGuard( char const *pchContext, int nLine, C_BaseEntity *pEntity, int nOldSlot, bool bSetVguiScreenSize ); + ~CSetActiveSplitScreenPlayerGuard(); +private: + bool m_bChanged; + char const *m_pchContext; + int m_nLine; + int m_nSaveSlot; + bool m_bSaveGetLocalPlayerAllowed; +}; + +class CHackForGetLocalPlayerAccessAllowedGuard +{ +public: + CHackForGetLocalPlayerAccessAllowedGuard( char const *pszContext, bool bOldSlot ); + ~CHackForGetLocalPlayerAccessAllowedGuard(); +private: + bool m_bChanged; + char const *m_pszContext; + bool m_bSaveGetLocalPlayerAllowed; +}; + +class CVGuiAbsPosSplitScreenPlayerGuard +{ +public: + CVGuiAbsPosSplitScreenPlayerGuard( int slot, int nOldSlot, bool bInvert = false ); + ~CVGuiAbsPosSplitScreenPlayerGuard(); +private: + bool m_bNoRestore; +}; + +int FirstValidSplitScreenSlot(); +int NextValidSplitScreenSlot( int i ); +bool IsValidSplitScreenSlot( int i ); +void IterateRemoteSplitScreenViewSlots_Push( bool bSet ); //some split screen loops should be made aware of remote views we'd like to use +void IterateRemoteSplitScreenViewSlots_Pop( void ); +class C_BasePlayer; +void AddRemoteSplitScreenViewPlayer( C_BasePlayer *pPlayer ); //adds a nonlocal player as a view we'd like to see in split screen +void RemoveRemoteSplitScreenViewPlayer( C_BasePlayer *pPlayer ); //removes a nonlocal player view from split screen +C_BasePlayer *GetSplitScreenViewPlayer( int nSlot ); //allows return of split screen views of nonlocal players +bool IsLocalSplitScreenPlayer( int nSlot ); //true is a full splitscreen player. false is just a view of a remote player + +#if defined( SPLIT_SCREEN_STUBS ) + +#define VGUI_SCREENSIZE_SPLITSCREEN_GUARD( slot ) +#define ACTIVE_SPLITSCREEN_PLAYER_GUARD( slot ) +#define ACTIVE_SPLITSCREEN_PLAYER_GUARD_ENT( entity ) + +#define ACTIVE_SPLITSCREEN_PLAYER_GUARD_VGUI( slot ) +#define ACTIVE_SPLITSCREEN_PLAYER_GUARD_ENT_VGUI( entity ) -/// Returns Steam ID, given player index. Returns an invalid SteamID upon -/// failure -extern CSteamID GetSteamIDForPlayerIndex( int iPlayerIndex ); +#define HACK_GETLOCALPLAYER_GUARD( desc ) +#define VGUI_ABSPOS_SPLITSCREEN_GUARD( slot ) +#define VGUI_ABSPOS_SPLITSCREEN_GUARD_INVERT( slot ) +#define FOR_EACH_VALID_SPLITSCREEN_PLAYER( iteratorName ) for ( int iteratorName = 0; iteratorName == 0; ++iteratorName ) + +#define ASSERT_LOCAL_PLAYER_RESOLVABLE() +#define ASSERT_LOCAL_PLAYER_NOT_RESOLVABLE() +#define GET_ACTIVE_SPLITSCREEN_SLOT() ( 0 ) + +FORCEINLINE uint32 ComputeSplitscreenRenderingFlags( IClientRenderable *pRenderable ) +{ + return 0xFFFFFFFF; +} + +#else + +#define VGUI_SCREENSIZE_SPLITSCREEN_GUARD( slot ) CVGuiScreenSizeSplitScreenPlayerGuard s_VGuiSSGuard( slot, engine->GetActiveSplitScreenPlayerSlot() ); +#define ACTIVE_SPLITSCREEN_PLAYER_GUARD( slot ) CSetActiveSplitScreenPlayerGuard g_SSGuard( __FILE__, __LINE__, slot, engine->GetActiveSplitScreenPlayerSlot(), false ); +#define ACTIVE_SPLITSCREEN_PLAYER_GUARD_ENT( entity ) CSetActiveSplitScreenPlayerGuard g_SSEGuard( __FILE__, __LINE__, entity, engine->GetActiveSplitScreenPlayerSlot(), false ); + +#define ACTIVE_SPLITSCREEN_PLAYER_GUARD_VGUI( slot ) CSetActiveSplitScreenPlayerGuard g_SSGuardNoVgui( __FILE__, __LINE__, slot, engine->GetActiveSplitScreenPlayerSlot(), true ); +#define ACTIVE_SPLITSCREEN_PLAYER_GUARD_ENT_VGUI( entity ) CSetActiveSplitScreenPlayerGuard g_SSEGuardNoVgui( __FILE__, __LINE__, entity, engine->GetActiveSplitScreenPlayerSlot(), true ); + + +#define HACK_GETLOCALPLAYER_GUARD( desc ) CHackForGetLocalPlayerAccessAllowedGuard g_HackGLPGuard( desc, engine->IsLocalPlayerResolvable() ); +#define VGUI_ABSPOS_SPLITSCREEN_GUARD( slot ) CVGuiAbsPosSplitScreenPlayerGuard s_VGuiAbsPosGuard( slot, engine->GetActiveSplitScreenPlayerSlot() ); +#define VGUI_ABSPOS_SPLITSCREEN_GUARD_INVERT( slot ) CVGuiAbsPosSplitScreenPlayerGuard s_VGuiAbsPosGuard( slot, engine->GetActiveSplitScreenPlayerSlot(), true ); + +#define FOR_EACH_VALID_SPLITSCREEN_PLAYER( iteratorName ) \ + for ( int iteratorName = FirstValidSplitScreenSlot(); \ + iteratorName != -1; \ + iteratorName = NextValidSplitScreenSlot( iteratorName ) ) + +// Uncomment this to be able to look for guard asserts in release builds +// #define SS_SHIPPING_ASSERTS + +#if defined( SS_SHIPPING_ASSERTS ) +#define ASSERT_LOCAL_PLAYER_RESOLVABLE() _AssertMsg( engine->IsLocalPlayerResolvable(), _T("Assertion Failed: ") _T("engine->IsLocalPlayerResolvable()"), ((void)0), false ) +#else +#define ASSERT_LOCAL_PLAYER_RESOLVABLE() Assert( engine->IsLocalPlayerResolvable() ); +#endif + +#if defined( SS_SHIPPING_ASSERTS ) +#define ASSERT_LOCAL_PLAYER_NOT_RESOLVABLE() _AssertMsg( !engine->IsLocalPlayerResolvable(), _T("Assertion Failed: ") _T("!engine->IsLocalPlayerResolvable()"), ((void)0), false ) +#else +#define ASSERT_LOCAL_PLAYER_NOT_RESOLVABLE() Assert( !engine->IsLocalPlayerResolvable() ); #endif +#define GET_ACTIVE_SPLITSCREEN_SLOT() engine->GetActiveSplitScreenPlayerSlot() + +//----------------------------------------------------------------------------- +// Default implementation of compute splitscreen rendering flags +//----------------------------------------------------------------------------- +FORCEINLINE uint32 ComputeSplitscreenRenderingFlags( IClientRenderable *pRenderable ) +{ + if ( IsSplitScreenSupported() ) + { + int nFlags = 0; + for ( int i = 0; i < MAX_SPLITSCREEN_PLAYERS; ++i ) + { + if ( pRenderable->ShouldDrawForSplitScreenUser( i ) ) + { + nFlags |= 1 << i; + } + } + return nFlags; + } + + return 0xFFFFFFFF; +} + +#endif + +inline C_BasePlayer *GetSplitScreenViewPlayer( void ) { return GetSplitScreenViewPlayer( GET_ACTIVE_SPLITSCREEN_SLOT() ); }; +inline bool IsLocalSplitScreenPlayer( void ) { return IsLocalSplitScreenPlayer( GET_ACTIVE_SPLITSCREEN_SLOT() ); }; + +// Returns XBX_GetUserId( GET_ACTIVE_SPLITSCREEN_SLOT() ) +int XBX_GetActiveUserId(); + +#define XBX_GetPrimaryUserId() _Use_XBX_GetActiveUserId_Instead + #endif // CDLL_CLIENT_INT_H diff --git a/game/client/cdll_util.cpp b/game/client/cdll_util.cpp index 4e877530b..ef87bd9c6 100644 --- a/game/client/cdll_util.cpp +++ b/game/client/cdll_util.cpp @@ -1,17 +1,17 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // // $Workfile: $ // $NoKeywords: $ -//=============================================================================// +//===========================================================================// #include "cbase.h" #include #include "hud.h" #include "itextmessage.h" -#include "materialsystem/imaterial.h" -#include "materialsystem/itexture.h" -#include "materialsystem/imaterialsystem.h" +#include "materialsystem/IMaterial.h" +#include "materialsystem/ITexture.h" +#include "materialsystem/IMaterialSystem.h" #include "imovehelper.h" #include "checksum_crc.h" #include "decals.h" @@ -27,12 +27,15 @@ #include #include "view.h" #include "ixboxsystem.h" +#include +#include +#include "vgui_int.h" +#include "cdll_client_int.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" - -ConVar localplayer_visionflags( "localplayer_visionflags", "0", FCVAR_DEVELOPMENTONLY ); - + + //----------------------------------------------------------------------------- // ConVars //----------------------------------------------------------------------------- @@ -79,39 +82,7 @@ int GetLocalPlayerIndex( void ) if ( player ) return player->entindex(); else - return 0; // game not started yet -} - -int GetLocalPlayerVisionFilterFlags( bool bWeaponsCheck /*= false */ ) -{ - C_BasePlayer * player = C_BasePlayer::GetLocalPlayer(); - - if ( player ) - return player->GetVisionFilterFlags( bWeaponsCheck ); - else - return 0; -} - -bool IsLocalPlayerUsingVisionFilterFlags( int nFlags, bool bWeaponsCheck /* = false */ ) -{ - int nLocalPlayerFlags = GetLocalPlayerVisionFilterFlags( bWeaponsCheck ); - - if ( !bWeaponsCheck ) - { - // We can only modify the RJ flags with normal checks that won't take the forced kill cam flags that can happen in weapon checks - int nRJShaderFlags = nLocalPlayerFlags; - if ( nRJShaderFlags != 0 && GameRules() && !GameRules()->AllowMapVisionFilterShaders() ) - { - nRJShaderFlags = 0; - } - - if ( nRJShaderFlags != localplayer_visionflags.GetInt() ) - { - localplayer_visionflags.SetValue( nRJShaderFlags ); - } - } - - return ( nLocalPlayerFlags & nFlags ) == nFlags; + return 0; // game not started yet } bool IsLocalPlayerSpectator( void ) @@ -283,18 +254,18 @@ float UTIL_WaterLevel( const Vector &position, float minz, float maxz ) Vector midUp = position; midUp.z = minz; - if ( !(UTIL_PointContents(midUp) & MASK_WATER) ) + if ( !(UTIL_PointContents(midUp, MASK_WATER) & MASK_WATER) ) return minz; midUp.z = maxz; - if ( UTIL_PointContents(midUp) & MASK_WATER ) + if ( UTIL_PointContents(midUp, MASK_WATER) & MASK_WATER ) return maxz; float diff = maxz - minz; while (diff > 1.0) { midUp.z = minz + diff/2.0; - if ( UTIL_PointContents(midUp) & MASK_WATER ) + if ( UTIL_PointContents(midUp, MASK_WATER) & MASK_WATER ) { minz = midUp.z; } @@ -376,7 +347,7 @@ void UTIL_Tracer( const Vector &vecStart, const Vector &vecEnd, int iEntIndex, i // Input : // Output : //------------------------------------------------------------------------------ -void UTIL_ImpactTrace( trace_t *pTrace, int iDamageType, const char *pCustomImpactName ) +void UTIL_ImpactTrace( trace_t *pTrace, int iDamageType, char *pCustomImpactName ) { C_BaseEntity *pEntity = pTrace->m_pEnt; @@ -402,7 +373,7 @@ int UTIL_PrecacheDecal( const char *name, bool preload ) return effects->Draw_DecalIndexFromName( (char*)name ); } -extern short g_sModelIndexSmoke; +extern int g_sModelIndexSmoke; void UTIL_Smoke( const Vector &origin, const float scale, const float framerate ) { @@ -484,7 +455,7 @@ void UTIL_PrecacheOther( const char *szClassname ) } // Bye bye - pEntity->Release(); + UTIL_Remove( pEntity ); } static csurface_t g_NullSurface = { "**empty**", 0 }; @@ -518,38 +489,20 @@ bool GetVectorInScreenSpace( Vector pos, int& iX, int& iY, Vector *vecOffset ) pos += *vecOffset; // Transform to screen space - int iFacing = ScreenTransform( pos, screen ); - iX = 0.5f * ( 1.0f + screen[0] ) * ScreenWidth(); - iY = 0.5f * ( 1.0f - screen[1] ) * ScreenHeight(); + int x, y, screenWidth, screenHeight; + int insetX, insetY; + VGui_GetEngineRenderBounds( GET_ACTIVE_SPLITSCREEN_SLOT(), x, y, screenWidth, screenHeight, insetX, insetY ); - // Make sure the player's facing it - if ( iFacing ) - { - // We're actually facing away from the Target. Stomp the screen position. - iX = -640; - iY = -640; - return false; - } - - return true; -} - -//----------------------------------------------------------------------------- -// Purpose: Get the x & y positions of a world position in HUD space -// Returns true if it's onscreen -//----------------------------------------------------------------------------- -bool GetVectorInHudSpace( Vector pos, int& iX, int& iY, Vector *vecOffset ) -{ - Vector screen; + // Transform to screen space + int iFacing = ScreenTransform( pos, screen ); - // Apply the offset, if one was specified - if ( vecOffset != NULL ) - pos += *vecOffset; + iX = 0.5 * screen[0] * screenWidth; + iY = -0.5 * screen[1] * screenHeight; + iX += 0.5 * screenWidth; + iY += 0.5 * screenHeight; - // Transform to HUD space - int iFacing = HudTransform( pos, screen ); - iX = 0.5f * ( 1.0f + screen[0] ) * ScreenWidth(); - iY = 0.5f * ( 1.0f - screen[1] ) * ScreenHeight(); + iX += insetX; + iY += insetY; // Make sure the player's facing it if ( iFacing ) @@ -572,15 +525,6 @@ bool GetTargetInScreenSpace( C_BaseEntity *pTargetEntity, int& iX, int& iY, Vect return GetVectorInScreenSpace( pTargetEntity->WorldSpaceCenter(), iX, iY, vecOffset ); } -//----------------------------------------------------------------------------- -// Purpose: Get the x & y positions of an entity in Vgui space -// Returns true if it's onscreen -//----------------------------------------------------------------------------- -bool GetTargetInHudSpace( C_BaseEntity *pTargetEntity, int& iX, int& iY, Vector *vecOffset ) -{ - return GetVectorInHudSpace( pTargetEntity->WorldSpaceCenter(), iX, iY, vecOffset ); -} - //----------------------------------------------------------------------------- // Purpose: @@ -596,60 +540,7 @@ void ClientPrint( C_BasePlayer *player, int msg_dest, const char *msg_name, cons { } -//----------------------------------------------------------------------------- -// class CFlaggedEntitiesEnum -//----------------------------------------------------------------------------- -// enumerate entities that match a set of edict flags into a static array -class CFlaggedEntitiesEnum : public IPartitionEnumerator -{ -public: - CFlaggedEntitiesEnum( C_BaseEntity **pList, int listMax, int flagMask ); - // This gets called by the enumeration methods with each element - // that passes the test. - virtual IterationRetval_t EnumElement( IHandleEntity *pHandleEntity ); - - int GetCount() { return m_count; } - bool AddToList( C_BaseEntity *pEntity ); - -private: - C_BaseEntity **m_pList; - int m_listMax; - int m_flagMask; - int m_count; -}; - -CFlaggedEntitiesEnum::CFlaggedEntitiesEnum( C_BaseEntity **pList, int listMax, int flagMask ) -{ - m_pList = pList; - m_listMax = listMax; - m_flagMask = flagMask; - m_count = 0; -} - -bool CFlaggedEntitiesEnum::AddToList( C_BaseEntity *pEntity ) -{ - if ( m_count >= m_listMax ) - return false; - m_pList[m_count] = pEntity; - m_count++; - return true; -} - -IterationRetval_t CFlaggedEntitiesEnum::EnumElement( IHandleEntity *pHandleEntity ) -{ - IClientEntity *pClientEntity = cl_entitylist->GetClientEntityFromHandle( pHandleEntity->GetRefEHandle() ); - C_BaseEntity *pEntity = pClientEntity ? pClientEntity->GetBaseEntity() : NULL; - if ( pEntity ) - { - if ( m_flagMask && !(pEntity->GetFlags() & m_flagMask) ) // Does it meet the criteria? - return ITERATION_CONTINUE; - if ( !AddToList( pEntity ) ) - return ITERATION_STOP; - } - - return ITERATION_CONTINUE; -} //----------------------------------------------------------------------------- // Purpose: Pass in an array of pointers and an array size, it fills the array and returns the number inserted @@ -687,22 +578,6 @@ int UTIL_EntitiesInSphere( C_BaseEntity **pList, int listMax, const Vector ¢ } -//----------------------------------------------------------------------------- -// Purpose: Pass in an array of pointers and an array size, it fills the array and returns the number inserted -// Input : **pList - -// listMax - -// &ray - -// flagMask - -// Output : int -//----------------------------------------------------------------------------- -int UTIL_EntitiesAlongRay( C_BaseEntity **pList, int listMax, const Ray_t &ray, int flagMask, int partitionMask ) -{ - CFlaggedEntitiesEnum rayEnum( pList, listMax, flagMask ); - partition->EnumerateElementsAlongRay( partitionMask, ray, false, &rayEnum ); - - return rayEnum.GetCount(); -} - CEntitySphereQuery::CEntitySphereQuery( const Vector ¢er, float radius, int flagMask, int partitionMask ) { m_listIndex = 0; @@ -766,27 +641,13 @@ const char *nexttoken(char *token, const char *str, char sep) //----------------------------------------------------------------------------- int UTIL_ComputeStringWidth( vgui::HFont& font, const char *str ) { - float pixels = 0; - const char *p = str; - const char *pAfter = p + 1; - const char *pBefore = "\0"; + int pixels = 0; + char *p = (char *)str; while ( *p ) { -#if USE_GETKERNEDCHARWIDTH - float wide, abcA; - vgui::surface()->GetKernedCharWidth( font, *p, *pBefore, *pAfter, wide, abcA ); - pixels += wide; -#else - pixels += vgui::surface()->GetCharacterWidth( font, *p ); -#endif - pBefore = p; - p++; - if ( *p ) - pAfter = p + 1; - else - pAfter = "\0"; + pixels += vgui::surface()->GetCharacterWidth( font, *p++ ); } - return (int)ceil(pixels); + return pixels; } @@ -798,27 +659,13 @@ int UTIL_ComputeStringWidth( vgui::HFont& font, const char *str ) //----------------------------------------------------------------------------- int UTIL_ComputeStringWidth( vgui::HFont& font, const wchar_t *str ) { - float pixels = 0; - const wchar_t *p = str; - const wchar_t *pAfter = p + 1; - const wchar_t *pBefore = L"\0"; + int pixels = 0; + wchar_t *p = (wchar_t *)str; while ( *p ) { -#if USE_GETKERNEDCHARWIDTH - float wide, abcA; - vgui::surface()->GetKernedCharWidth( font, *p, *pBefore, *pAfter, wide, abcA ); - pixels += wide; -#else - pixels += vgui::surface()->GetCharacterWidth( font, *p ); -#endif - pBefore = p; - p++; - if ( *p ) - pAfter = p + 1; - else - pAfter = L"\0"; + pixels += vgui::surface()->GetCharacterWidth( font, *p++ ); } - return (int)ceil(pixels); + return pixels; } //----------------------------------------------------------------------------- @@ -831,8 +678,6 @@ int UTIL_ComputeStringWidth( vgui::HFont& font, const wchar_t *str ) void UTIL_MakeSafeName( const char *oldName, char *newName, int newNameBufSize ) { - Assert( newNameBufSize >= sizeof(newName[0]) ); - int newpos = 0; for( const char *p=oldName; *p != 0 && newpos < newNameBufSize-1; p++ ) @@ -892,15 +737,16 @@ const char * UTIL_SafeName( const char *oldName ) // input buffer is assumed, or you can pass the size of the input buffer if // not NULL-terminated. //----------------------------------------------------------------------------- -void UTIL_ReplaceKeyBindings( const wchar_t *inbuf, int inbufsizebytes, OUT_Z_BYTECAP(outbufsizebytes) wchar_t *outbuf, int outbufsizebytes ) +void UTIL_ReplaceKeyBindings( const wchar_t *inbuf, int inbufsizebytes, wchar_t *outbuf, int outbufsizebytes ) { - Assert( outbufsizebytes >= sizeof(outbuf[0]) ); - // copy to a new buf if there are vars - outbuf[0]=0; - if ( !inbuf || !inbuf[0] ) return; + ASSERT_LOCAL_PLAYER_RESOLVABLE(); + int nSlot = GET_ACTIVE_SPLITSCREEN_SLOT(); + + // copy to a new buf if there are vars + outbuf[0]=0; int pos = 0; const wchar_t *inbufend = NULL; if ( inbufsizebytes > 0 ) @@ -928,7 +774,7 @@ void UTIL_ReplaceKeyBindings( const wchar_t *inbuf, int inbufsizebytes, OUT_Z_BY char binding[64]; g_pVGuiLocalize->ConvertUnicodeToANSI( token, binding, sizeof(binding) ); - const char *key = engine->Key_LookupBinding( *binding == '+' ? binding + 1 : binding ); + const char *key = engine->Key_LookupBindingEx( *binding == '+' ? binding + 1 : binding, nSlot ); if ( !key ) { key = IsX360() ? "" : "< not bound >"; @@ -999,6 +845,27 @@ void UTIL_ReplaceKeyBindings( const wchar_t *inbuf, int inbufsizebytes, OUT_Z_BY outbuf[pos] = '\0'; } +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void UTIL_SetControlStringWithKeybindings( vgui::EditablePanel *panel, const char *controlName, const char *str ) +{ + if ( !panel || !controlName || !str ) + return; + + const wchar_t *unicodeStr = g_pVGuiLocalize->Find( str ); + if ( unicodeStr ) + { + wchar_t buf[512]; + UTIL_ReplaceKeyBindings( unicodeStr, 0, buf, sizeof( buf ) ); + panel->SetControlString( controlName, buf ); + } + else + { + panel->SetControlString( controlName, str ); + } +} + //----------------------------------------------------------------------------- // Purpose: // Input : *filename - @@ -1060,7 +927,7 @@ static unsigned char ComputeDistanceFade( C_BaseEntity *pEntity, float flMinDist if( flMinDist > flMaxDist ) { - ::V_swap( flMinDist, flMaxDist ); + V_swap( flMinDist, flMaxDist ); } // If a negative value is provided for the min fade distance, then base it off the max. @@ -1180,25 +1047,106 @@ void UTIL_BoundToWorldSize( Vector *pVecPos ) #else #define MAP_KEY_FILE_DIR "media" #endif +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_BasePlayer* UTIL_PlayerByUserId( int userID ) +{ + for (int i = 1; i<=gpGlobals->maxClients; i++ ) + { + C_BasePlayer *pPlayer = UTIL_PlayerByIndex( i ); + + if ( !pPlayer ) + continue; + + if ( pPlayer->GetUserID() == userID ) + { + return pPlayer; + } + } + + return NULL; +} + +C_BaseEntity* UTIL_EntityFromUserMessageEHandle( long nEncodedEHandle ) +{ + int nEntity, nSerialNum; + if( nEncodedEHandle == INVALID_NETWORKED_EHANDLE_VALUE ) + return NULL; + + nEntity = nEncodedEHandle & ((1 << MAX_EDICT_BITS) - 1); + nSerialNum = nEncodedEHandle >> MAX_EDICT_BITS; + + EHANDLE hEntity( nEntity, nSerialNum ); + return hEntity.Get(); +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void UTIL_ApproachTarget( float target, float increaseSpeed, float decreaseSpeed, float *val ) +{ + if ( *val < target ) + { + *val += gpGlobals->frametime*increaseSpeed; + *val = MIN( *val, target ); + } + else if ( *val > target ) + { + *val -= gpGlobals->frametime*decreaseSpeed; + *val = MAX( *val, target ); + } +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void UTIL_ApproachTarget( const Vector &target, float increaseSpeed, float decreaseSpeed, Vector *val ) +{ + UTIL_ApproachTarget( target.x, increaseSpeed, decreaseSpeed, &val->x ); + UTIL_ApproachTarget( target.y, increaseSpeed, decreaseSpeed, &val->y ); + UTIL_ApproachTarget( target.z, increaseSpeed, decreaseSpeed, &val->z ); +} //----------------------------------------------------------------------------- // Purpose: Returns the filename to count map loads in //----------------------------------------------------------------------------- -bool UTIL_GetMapLoadCountFileName( const char *pszFilePrependName, char *pszBuffer, int iBuflen ) +bool UTIL_GetMapLoadCountFileName( int iController, const char *pszFilePrependName, char *pszBuffer, int iBuflen ) { if ( IsX360() ) { #ifdef _X360 - if ( XBX_GetStorageDeviceId() == XBX_INVALID_STORAGE_ID || XBX_GetStorageDeviceId() == XBX_STORAGE_DECLINED ) + if ( iController < 0 || iController >= XUSER_MAX_COUNT ) + return false; + + int iSlot = -1; + for ( unsigned int k = 0; k < XBX_GetNumGameUsers(); ++ k ) + { + if ( XBX_GetUserId( k ) == iController ) + { + iSlot = k; + if ( XBX_GetUserIsGuest( k ) ) + return false; + } + } + if ( iSlot < 0 ) + return false; + + DWORD nStorageDevice = XBX_GetStorageDeviceId( iController ); + if ( !XBX_DescribeStorageDevice( nStorageDevice ) ) return false; #endif } +#ifdef _X360 if ( IsX360() ) { - Q_snprintf( pszBuffer, iBuflen, "%s:/%s", MAP_KEY_FILE_DIR, pszFilePrependName ); + XBX_MakeStorageContainerRoot( iController, XBX_USER_SETTINGS_CONTAINER_DRIVE, pszBuffer, iBuflen ); + int nLen = strlen( pszBuffer ); + Q_snprintf( pszBuffer + nLen, iBuflen - nLen, ":/%s", pszFilePrependName ); } else +#endif { Q_snprintf( pszBuffer, iBuflen, "%s/%s", MAP_KEY_FILE_DIR, pszFilePrependName ); } @@ -1206,19 +1154,23 @@ bool UTIL_GetMapLoadCountFileName( const char *pszFilePrependName, char *pszBuff return true; } -#ifdef TF_CLIENT_DLL -#define MAP_KEY_FILE "viewed.res" -#else + #define MAP_KEY_FILE "mapkeys.res" -#endif + void UTIL_IncrementMapKey( const char *pszCustomKey ) { +#ifdef _X360 + // TODO: controller-specific code required + return; +#endif + int iController = -1; + if ( !pszCustomKey ) return; char szFilename[ _MAX_PATH ]; - if ( !UTIL_GetMapLoadCountFileName( MAP_KEY_FILE, szFilename, _MAX_PATH ) ) + if ( !UTIL_GetMapLoadCountFileName( iController, MAP_KEY_FILE, szFilename, _MAX_PATH ) ) return; int iCount = 1; @@ -1261,21 +1213,27 @@ void UTIL_IncrementMapKey( const char *pszCustomKey ) kvMapLoadFile->deleteThis(); } - if ( IsX360() ) - { #ifdef _X360 - xboxsystem->FinishContainerWrites(); -#endif + if ( xboxsystem ) + { + xboxsystem->FinishContainerWrites( iController ); } +#endif } int UTIL_GetMapKeyCount( const char *pszCustomKey ) { +#ifdef _X360 + // TODO: controller-specific code required + return 0; +#endif + int iController = -1; + if ( !pszCustomKey ) return 0; char szFilename[ _MAX_PATH ]; - if ( !UTIL_GetMapLoadCountFileName( MAP_KEY_FILE, szFilename, _MAX_PATH ) ) + if ( !UTIL_GetMapLoadCountFileName( iController, MAP_KEY_FILE, szFilename, _MAX_PATH ) ) return 0; int iCount = 0; @@ -1311,11 +1269,54 @@ int UTIL_GetMapKeyCount( const char *pszCustomKey ) return iCount; } -bool UTIL_HasLoadedAnyMap() + +wchar_t *UTIL_GetLocalizedKeyString( const char *command, const char *fmt, const wchar_t *arg1, const wchar_t *arg2, const wchar_t *arg3 ) { - char szFilename[ _MAX_PATH ]; - if ( !UTIL_GetMapLoadCountFileName( MAP_KEY_FILE, szFilename, _MAX_PATH ) ) - return false; + static wchar_t useString[4][256]; + static int index = 0; + + index = index + 1; + if ( index > 3 ) + index = 0; + + const char *lowercaseKey = engine->Key_LookupBinding( command ); + if ( !lowercaseKey ) + { + lowercaseKey = ""; + } + + char szKey[64]; + V_strncpy( szKey, lowercaseKey, sizeof( szKey ) ); + for ( char *tmp = szKey; *tmp; ++tmp ) + { + *tmp = toupper( *tmp ); + } - return g_pFullFileSystem->FileExists( szFilename, "MOD" ); + wchar_t wszKey[64]; + g_pVGuiLocalize->ConvertANSIToUnicode( szKey, wszKey, sizeof(wszKey) ); + + int argCount = 1; + if ( arg1 ) + { + ++argCount; + if ( arg2 ) + { + ++argCount; + if ( arg3 ) + { + ++argCount; + } + } + } + + g_pVGuiLocalize->ConstructString( useString[index], sizeof( useString[index] ), g_pVGuiLocalize->Find( fmt ), argCount, wszKey, arg1, arg2, arg3 ); + return useString[index]; +} + +void UTIL_ClearTrace( trace_t &trace ) +{ + memset( &trace, 0, sizeof(trace)); + trace.fraction = 1.f; + trace.fractionleftsolid = 0; + trace.surface = g_NullSurface; } diff --git a/game/client/cdll_util.h b/game/client/cdll_util.h index 64beb5fbc..ab79c099a 100644 --- a/game/client/cdll_util.h +++ b/game/client/cdll_util.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // @@ -6,8 +6,8 @@ // $Date: $ // $NoKeywords: $ //=============================================================================// -#if !defined( UTIL_H ) -#define UTIL_H +#if !defined( CDLL_UTIL_H ) +#define CDLL_UTIL_H #ifdef _WIN32 #pragma once @@ -16,11 +16,12 @@ #include #include "mathlib/vector.h" #include +#include "Color.h" #include "shake.h" #include "bitmap/imageformat.h" #include "ispatialpartition.h" -#include "materialsystem/MaterialSystemUtil.h" +#include "materialsystem/materialsystemutil.h" class Vector; class QAngle; @@ -30,6 +31,7 @@ class IClientEntity; class CHudTexture; class CGameTrace; class C_BaseEntity; +class C_BasePlayer; struct Ray_t; struct client_textmessage_t; @@ -38,9 +40,10 @@ typedef CGameTrace trace_t; namespace vgui { typedef unsigned long HFont; + class EditablePanel; }; - +#define UTIL_VarArgs VarArgs extern bool g_MakingDevShots; @@ -57,23 +60,26 @@ int UTIL_ComputeStringWidth( vgui::HFont& font, const wchar_t *str ); float UTIL_AngleDiff( float destAngle, float srcAngle ); void UTIL_Bubbles( const Vector& mins, const Vector& maxs, int count ); void UTIL_Smoke( const Vector &origin, const float scale, const float framerate ); -void UTIL_ImpactTrace( trace_t *pTrace, int iDamageType, const char *pCustomImpactName = NULL ); +void UTIL_ImpactTrace( trace_t *pTrace, int iDamageType, char *pCustomImpactName = NULL ); int UTIL_PrecacheDecal( const char *name, bool preload = false ); void UTIL_EmitAmbientSound( C_BaseEntity *entity, const Vector &vecOrigin, const char *samp, float vol, soundlevel_t soundlevel, int fFlags, int pitch ); void UTIL_SetOrigin( C_BaseEntity *entity, const Vector &vecOrigin ); void UTIL_ScreenShake( const Vector ¢er, float amplitude, float frequency, float duration, float radius, ShakeCommand_t eCommand, bool bAirShake=false ); byte *UTIL_LoadFileForMe( const char *filename, int *pLength ); void UTIL_FreeFile( byte *buffer ); -void UTIL_MakeSafeName( const char *oldName, OUT_Z_CAP(newNameBufSize) char *newName, int newNameBufSize ); ///< Cleans up player names for putting in vgui controls (cleaned names can be up to original*2+1 in length) +void UTIL_MakeSafeName( const char *oldName, char *newName, int newNameBufSize ); ///< Cleans up player names for putting in vgui controls (cleaned names can be up to original*2+1 in length) const char *UTIL_SafeName( const char *oldName ); ///< Wraps UTIL_MakeSafeName, and returns a static buffer -void UTIL_ReplaceKeyBindings( const wchar_t *inbuf, int inbufsizebytes, OUT_Z_BYTECAP(outbufsizebytes) wchar_t *outbuf, int outbufsizebytes ); +void UTIL_ReplaceKeyBindings( const wchar_t *inbuf, int inbufsizebytes, wchar_t *outbuf, int outbufsizebytes ); +void UTIL_SetControlStringWithKeybindings( vgui::EditablePanel *panel, const char *controlName, const char *str ); + +void UTIL_MessageText( C_BasePlayer *player, const char *text, Color color = Color( 0, 0, 0, 0 ) ); // Fade out an entity based on distance fades unsigned char UTIL_ComputeEntityFade( C_BaseEntity *pEntity, float flMinDist, float flMaxDist, float flFadeScale ); client_textmessage_t *TextMessageGet( const char *pName ); -char *VarArgs( PRINTF_FORMAT_STRING const char *format, ... ); +char *VarArgs( const char *format, ... ); // Get the entity the local player is spectating (can be a player or a ragdoll entity). @@ -81,8 +87,6 @@ int GetSpectatorTarget(); int GetSpectatorMode( void ); bool IsPlayerIndex( int index ); int GetLocalPlayerIndex( void ); -int GetLocalPlayerVisionFilterFlags( bool bWeaponsCheck = false ); -bool IsLocalPlayerUsingVisionFilterFlags( int nFlags, bool bWeaponsCheck = false ); int GetLocalPlayerTeam( void ); bool IsLocalPlayerSpectator( void ); void NormalizeAngles( QAngle& angles ); @@ -91,34 +95,24 @@ void InterpolateVector( float frac, const Vector& src, const Vector& dest, Vecto const char *nexttoken(char *token, const char *str, char sep); -//----------------------------------------------------------------------------- -// Base light indices to avoid index collision -//----------------------------------------------------------------------------- - -enum -{ - LIGHT_INDEX_TE_DYNAMIC = 0x10000000, - LIGHT_INDEX_PLAYER_BRIGHT = 0x20000000, - LIGHT_INDEX_MUZZLEFLASH = 0x40000000, -}; - void UTIL_PrecacheOther( const char *szClassname ); void UTIL_SetTrace(trace_t& tr, const Ray_t& ray, C_BaseEntity *edict, float fraction, int hitgroup, unsigned int contents, const Vector& normal, float intercept ); bool GetVectorInScreenSpace( Vector pos, int& iX, int& iY, Vector *vecOffset = NULL ); -bool GetVectorInHudSpace( Vector pos, int& iX, int& iY, Vector *vecOffset = NULL ); bool GetTargetInScreenSpace( C_BaseEntity *pTargetEntity, int& iX, int& iY, Vector *vecOffset = NULL ); -bool GetTargetInHudSpace( C_BaseEntity *pTargetEntity, int& iX, int& iY, Vector *vecOffset = NULL ); // prints messages through the HUD (stub in client .dll right now ) class C_BasePlayer; void ClientPrint( C_BasePlayer *player, int msg_dest, const char *msg_name, const char *param1 = NULL, const char *param2 = NULL, const char *param3 = NULL, const char *param4 = NULL ); +C_BasePlayer* UTIL_PlayerByUserId( int userID ); + +C_BaseEntity* UTIL_EntityFromUserMessageEHandle( long nEncodedEHandle ); + // Pass in an array of pointers and an array size, it fills the array and returns the number inserted int UTIL_EntitiesInBox( C_BaseEntity **pList, int listMax, const Vector &mins, const Vector &maxs, int flagMask, int partitionMask = PARTITION_CLIENT_NON_STATIC_EDICTS ); int UTIL_EntitiesInSphere( C_BaseEntity **pList, int listMax, const Vector ¢er, float radius, int flagMask, int partitionMask = PARTITION_CLIENT_NON_STATIC_EDICTS ); -int UTIL_EntitiesAlongRay( C_BaseEntity **pList, int listMax, const Ray_t &ray, int flagMask, int partitionMask = PARTITION_CLIENT_NON_STATIC_EDICTS ); // make this a fixed size so it just sits on the stack #define MAX_SPHERE_QUERY 256 @@ -148,7 +142,7 @@ T *_CreateEntity( T *newClass, const char *className ) T *newEnt = dynamic_cast( CreateEntityByName(className) ); if ( !newEnt ) { - Warning( "classname %s used to create wrong class type\n", className ); + Warning( "classname %s used to create wrong class type\n" ); Assert(0); } @@ -161,12 +155,16 @@ T *_CreateEntity( T *newClass, const char *className ) // Misc useful inline bool FStrEq(const char *sz1, const char *sz2) { - return (sz1 == sz2 || V_stricmp(sz1, sz2) == 0); + return(stricmp(sz1, sz2) == 0); } // Given a vector, clamps the scalar axes to MAX_COORD_FLOAT ranges from worldsize.h void UTIL_BoundToWorldSize( Vector *pVecPos ); +void UTIL_ApproachTarget( float target, float increaseSpeed, float decreaseSpeed, float *val ); +void UTIL_ApproachTarget( const Vector &target, float increaseSpeed, float decreaseSpeed, Vector *val ); + + // Increments the passed key for the current map, eg "viewed" if TF holds the number of times the player has // viewed the intro movie for this map void UTIL_IncrementMapKey( const char *pszCustomKey ); @@ -175,7 +173,10 @@ void UTIL_IncrementMapKey( const char *pszCustomKey ); // the intro movie for this map int UTIL_GetMapKeyCount( const char *pszCustomKey ); -// Returns true if the user has loaded any maps, false otherwise. -bool UTIL_HasLoadedAnyMap(); +wchar_t *UTIL_GetLocalizedKeyString( const char *command, const char *fmt, const wchar_t *arg1 = NULL, const wchar_t *arg2 = NULL, const wchar_t *arg3 = NULL ); + +class CGameTrace; +typedef CGameTrace trace_t; +void UTIL_ClearTrace ( trace_t &trace ); -#endif // !UTIL_H +#endif // !CDLL_UTIL_H diff --git a/game/client/cl_animevent.h b/game/client/cl_animevent.h index 29c95b7b4..b1f4f7a39 100644 --- a/game/client/cl_animevent.h +++ b/game/client/cl_animevent.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: Hold definitions for all client animation events // diff --git a/game/client/cl_mat_stub.cpp b/game/client/cl_mat_stub.cpp index a0caec8d4..319bf1192 100644 --- a/game/client/cl_mat_stub.cpp +++ b/game/client/cl_mat_stub.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // diff --git a/game/client/cl_mat_stub.h b/game/client/cl_mat_stub.h index 8b0951dc1..1c3b44d02 100644 --- a/game/client/cl_mat_stub.h +++ b/game/client/cl_mat_stub.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // diff --git a/game/client/classmap.cpp b/game/client/classmap.cpp index a6790a0fe..7ed2c4d23 100644 --- a/game/client/classmap.cpp +++ b/game/client/classmap.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // diff --git a/game/client/client_base.vpc b/game/client/client_base.vpc index 90e16cb81..e364f3085 100644 --- a/game/client/client_base.vpc +++ b/game/client/client_base.vpc @@ -6,26 +6,17 @@ $Macro OUTBINNAME "client" $Macro OUTBINDIR "$SRCDIR\..\game\$GAMENAME\bin" -$Macro DEVKITBINDIR "$GAMENAME\bin" [$X360] -// It's important to include $GAMENAME in the generated_proto directory -// to avoid race conditions when multiple games are in one solution. -$Macro GENERATED_PROTO_DIR "$SRCDIR\game\client\generated_proto_$GAMENAME" $MacroRequired "GAMENAME" $Include "$SRCDIR\vpc_scripts\source_dll_base.vpc" -$include "$SRCDIR\vpc_scripts\protobuf_builder.vpc" -$Include "$SRCDIR\vpc_scripts\source_replay.vpc" [$TF] $Configuration "Debug" { $General { - $OutputDirectory ".\Debug_$GAMENAME" [$WIN32] - $IntermediateDirectory ".\Debug_$GAMENAME" [$WIN32] - - $OutputDirectory ".\Debug_$GAMENAME_360" [$X360] - $IntermediateDirectory ".\Debug_$GAMENAME_360" [$X360] + $OutputDirectory ".\Debug_$GAMENAME" + $IntermediateDirectory ".\Debug_$GAMENAME" } } @@ -33,29 +24,18 @@ $Configuration "Release" { $General { - $OutputDirectory ".\Release_$GAMENAME" [$WIN32] - $IntermediateDirectory ".\Release_$GAMENAME" [$WIN32] - - $OutputDirectory ".\Release_$GAMENAME_360" [$X360] - $IntermediateDirectory ".\Release_$GAMENAME_360" [$X360] + $OutputDirectory ".\Release_$GAMENAME" + $IntermediateDirectory ".\Release_$GAMENAME" } } $Configuration { - $General - { - $OutputDirectory ".\$GAMENAME" [$OSXALL] - } - $Compiler { - $AdditionalIncludeDirectories ".\;$BASE;$SRCDIR\vgui2\include;$SRCDIR\vgui2\controls;$SRCDIR\game\shared;.\game_controls;$SRCDIR\thirdparty\sixensesdk\include" + $AdditionalIncludeDirectories ".\;$BASE;$SRCDIR\game\shared;.\game_controls" $PreprocessorDefinitions "$BASE;NO_STRING_T;CLIENT_DLL;VECTOR;VERSION_SAFE_STEAM_API_INTERFACES;PROTECTED_THINGS_ENABLE;strncpy=use_Q_strncpy_instead;_snprintf=use_Q_snprintf_instead" - $PreprocessorDefinitions "$BASE;ENABLE_CHROMEHTMLWINDOW;fopen=dont_use_fopen" [$WIN32] - $PreprocessorDefinitions "$BASE;ENABLE_CHROMEHTMLWINDOW;" [$OSXALL] - $PreprocessorDefinitions "$BASE;ENABLE_CHROMEHTMLWINDOW;USE_WEBM_FOR_REPLAY;" [$LINUXALL] - $PreprocessorDefinitions "$BASE;CURL_STATICLIB" [$WIN32 && $BUILD_REPLAY] + $PreprocessorDefinitions "$BASE;fopen=dont_use_fopen" $Create/UsePrecompiledHeader "Use Precompiled Header (/Yu)" $Create/UsePCHThroughFile "cbase.h" $PrecompiledHeaderFile "$(IntDir)/client.pch" @@ -63,108 +43,83 @@ $Configuration $Linker { - $SystemLibraries "iconv" [$OSXALL] - $SystemFrameworks "Carbon" [$OSXALL] - $SystemLibraries "rt" [$LINUXALL] $IgnoreImportLibrary "TRUE" - $AdditionalDependencies "$BASE winmm.lib" [$WIN32] - $AdditionalDependencies "$BASE wsock32.lib Ws2_32.lib" [$BUILD_REPLAY] + $AdditionalDependencies "$BASE winmm.lib" } } $Project { - $Folder "Replay" - { - $File "replay/replaycamera.cpp" - $File "replay/replaycamera.h" - $File "replay/cdll_replay.cpp" - $File "replay/cdll_replay.h" - - $File "replay/gamedefs.h" [$BUILD_REPLAY] - $File "replay/gamedefs.cpp" [$BUILD_REPLAY] - $File "replay/replay_ragdoll.cpp" [$BUILD_REPLAY] - $File "replay/replay_ragdoll.h" [$BUILD_REPLAY] - $File "replay/replay_screenshot.cpp" [$BUILD_REPLAY] - $File "replay/replay_screenshot.h" [$BUILD_REPLAY] - $File "replay/replayperformanceplaybackhandler.h" [$BUILD_REPLAY] - $File "replay/replayperformanceplaybackhandler.cpp" [$BUILD_REPLAY] - $File "replay/replayrenderer.cpp" [$BUILD_REPLAY] - $File "replay/replayrenderer.h" [$BUILD_REPLAY] - $File "replay/replayvideo.cpp" [$BUILD_REPLAY] - $File "replay/replayvideo.h" [$BUILD_REPLAY] - - $File "replay/genericclassbased_replay.cpp" [$BUILD_REPLAY] - $File "replay/genericclassbased_replay.h" [$BUILD_REPLAY] - - $File "$SRCDIR\game\shared\replay_gamestats_shared.cpp" [$BUILD_REPLAY] - $File "$SRCDIR\game\shared\replay_gamestats_shared.h" [$BUILD_REPLAY] - - $Configuration - { - $Compiler - { - $Create/UsePrecompiledHeader "Not Using Precompiled Headers" - } - } - } - - $Folder "UI" [$BUILD_REPLAY] - { - $File "replay\vgui\replaybrowserbasepage.cpp" - $File "replay\vgui\replaybrowserbasepage.h" - $File "replay\vgui\replaybrowserbasepanel.cpp" - $File "replay\vgui\replaybrowserbasepanel.h" - $File "replay\vgui\replayconfirmquitdlg.cpp" - $File "replay\vgui\replayconfirmquitdlg.h" - $File "replay\vgui\replaybrowserdetailspanel.cpp" - $File "replay\vgui\replaybrowserdetailspanel.h" - $File "replay\vgui\replaybrowseritemmanager.cpp" - $File "replay\vgui\replaybrowseritemmanager.h" - $File "replay\vgui\replaybrowserlistitempanel.cpp" - $File "replay\vgui\replaybrowserlistitempanel.h" - $File "replay\vgui\replaybrowserlistpanel.cpp" - $File "replay\vgui\replaybrowserlistpanel.h" - $File "replay\vgui\replaybrowsermainpanel.cpp" - $File "replay\vgui\replaybrowsermainpanel.h" - $File "replay\vgui\replaybrowsermovieplayerpanel.cpp" - $File "replay\vgui\replaybrowsermovieplayerpanel.h" - $File "replay\vgui\replaybrowserpreviewpanel.cpp" - $File "replay\vgui\replaybrowserpreviewpanel.h" - $File "replay\vgui\replaybrowserrenderdialog.cpp" - $File "replay\vgui\replaybrowserrenderdialog.h" - $File "replay\vgui\replayinputpanel.cpp" - $File "replay\vgui\replayinputpanel.h" - $File "replay\vgui\replaymessagepanel.cpp" - $File "replay\vgui\replaymessagepanel.h" - $File "replay\vgui\replayperformanceeditor.cpp" - $File "replay\vgui\replayperformanceeditor.h" - $File "replay\vgui\replayperformancesavedlg.cpp" - $File "replay\vgui\replayperformancesavedlg.h" - $File "replay\vgui\replayrenderoverlay.cpp" - $File "replay\vgui\replayrenderoverlay.h" - $File "replay\vgui\replayreminderpanel.cpp" - $File "replay\vgui\replayreminderpanel.h" - - $File "game_controls\slideshowpanel.cpp" - $File "game_controls\slideshowpanel.h" - - $File "$SRCDIR\common\movieobjects\timeutils.cpp" - { - $Configuration - { - $Compiler - { - $Create/UsePrecompiledHeader "Not Using Precompiled Headers" - } - } - } - $File "$SRCDIR\public\movieobjects\timeutils.h" - } - } - $Folder "Source Files" { + $File "$SRCDIR\game\shared\ai_criteria.cpp" + $File "$SRCDIR\game\shared\ai_criteria.h" + $File "$SRCDIR\game\shared\ai_responsesystem.cpp" + $File "$SRCDIR\game\shared\ai_responsesystem.h" + $File "$SRCDIR\game\shared\ai_speechconcept.cpp" + $File "$SRCDIR\game\shared\ai_speechconcept.h" + $File "$SRCDIR\common\blackbox_helper.cpp" + $File "$SRCDIR\common\blackbox_helper.h" + $File "c_baselesson.cpp" + $File "c_baselesson.h" + $File "c_basetoggle.cpp" + $File "c_basetoggle.h" + $File "c_beamspotlight.cpp" + $File "c_colorcorrection.h" + $File "c_entityflame.cpp" + $File "c_entityfreezing.cpp" + $File "c_env_ambient_light.cpp" + $File "c_env_ambient_light.h" + $File "c_env_dof_controller.cpp" + $File "c_env_global_light.cpp" + $File "c_env_projectedtexture.h" + $File "c_func_brush.cpp" + $File "c_func_movelinear.cpp" + $File "c_gameinstructor.cpp" + $File "c_gameinstructor.h" + $File "c_movie_display.cpp" + $File "c_physics_prop_statue.cpp" + $File "c_physics_prop_statue.h" + $File "c_postprocesscontroller.cpp" + $File "c_postprocesscontroller.h" + $File "c_prop_hallucination.cpp" + $File "c_spatialentity.cpp" + $File "c_spatialentity.h" + $File "c_sunlightshadowcontrol.cpp" + $File "c_surfacerender.cpp" + $File "c_triggers.cpp" + $File "clientalphaproperty.cpp" + $File "convarproxy.cpp" + $File "cycleproxy.cpp" + $File "foundryhelpers_client.cpp" + $File "foundryhelpers_client.h" + $File "$SRCDIR\game\shared\game_timescale_shared.cpp" + $File "$SRCDIR\game\shared\game_timescale_shared.h" + $File "hud_locator_target.cpp" + $File "hud_locator_target.h" + $File "$SRCDIR\engine\iblackbox.h" + $File "$SRCDIR\public\tier1\interpolatedvar.cpp" + $File "materialproxydict.cpp" + $File "modelrendersystem.cpp" + $File "modelrendersystem.h" + $File "object_motion_blur_effect.cpp" + $File "$SRCDIR\game\shared\postprocess_shared.h" + $File "$SRCDIR\game\shared\predictioncopy_helpers.cpp" + $File "$SRCDIR\game\shared\predictioncopy_test.cpp" + $File "replaycamera.cpp" + $File "$SRCDIR\game\shared\sharedvar.h" + $File "spatialentitymgr.cpp" + $File "spatialentitymgr.h" + $File "$SRCDIR\game\shared\steamworks_gamestats.cpp" + $File "vgui_bindpanel.cpp" + $File "vgui_hudvideo.cpp" + $File "vgui_movie_display.cpp" + $File "vscript_client.cpp" + $File "vscript_client.h" + $File "vscript_client.nut" + $File "$SRCDIR\game\shared\vscript_shared.cpp" + $File "$SRCDIR\game\shared\vscript_shared.h" + $File "hl2\C_Func_Monitor.cpp" $File "geiger.cpp" $File "history_resource.cpp" @@ -175,12 +130,9 @@ $Project $File "$SRCDIR\game\shared\achievement_saverestore.h" $File "$SRCDIR\game\shared\achievementmgr.cpp" $File "$SRCDIR\game\shared\achievementmgr.h" - $File "$SRCDIR\game\shared\achievements_and_stats_interface.h" - $File "$SRCDIR\game\shared\achievements_hlx.cpp" $File "achievement_notification_panel.cpp" $File "achievement_notification_panel.h" $File "$SRCDIR\game\shared\activitylist.cpp" - $File "alphamaterialproxy.cpp" $File "$SRCDIR\game\shared\ammodef.cpp" $File "animatedentitytextureproxy.cpp" $File "animatedoffsettextureproxy.cpp" @@ -198,8 +150,6 @@ $Project $File "$SRCDIR\game\shared\basegrenade_shared.cpp" $File "$SRCDIR\game\shared\baseparticleentity.cpp" $File "$SRCDIR\game\shared\baseplayer_shared.cpp" - $File "$SRCDIR\game\shared\baseprojectile.cpp" - $File "$SRCDIR\game\shared\baseprojectile.h" $File "$SRCDIR\game\shared\baseviewmodel_shared.cpp" $File "beamdraw.cpp" $File "$SRCDIR\game\shared\beam_shared.cpp" @@ -275,11 +225,8 @@ $Project $File "c_vehicle_jeep.cpp" $File "c_vguiscreen.cpp" $File "hl2\c_waterbullet.cpp" - $File "hl2\hud_autoaim.cpp" $File "C_WaterLODControl.cpp" $File "c_world.cpp" - $File "$SRCDIR\game\shared\cam_thirdperson.cpp" - $File "$SRCDIR\game\shared\cam_thirdperson.h" $File "camomaterialproxy.cpp" $File "cdll_client_int.cpp" $File "cdll_bounded_cvars.cpp" @@ -289,17 +236,12 @@ $Project $File "classmap.cpp" $File "client_factorylist.cpp" $File "client_thinklist.cpp" - $File "client_virtualreality.cpp" - $File "client_virtualreality.h" - $File "clienteffectprecachesystem.cpp" $File "cliententitylist.cpp" $File "clientleafsystem.cpp" $File "clientmode_shared.cpp" $File "clientshadowmgr.cpp" $File "clientsideeffects.cpp" $File "clientsideeffects_test.cpp" - $File "clientsteamcontext.cpp" - $File "clientsteamcontext.h" $File "colorcorrectionmgr.cpp" $File "commentary_modelviewer.cpp" $File "commentary_modelviewer.h" @@ -353,8 +295,6 @@ $Project $File "hud_closecaption.cpp" $File "hud_crosshair.cpp" $File "hud_element_helper.cpp" - $File "hl2\hud_filmdemo.cpp" - $File "hl2\hud_hdrdemo.cpp" $File "hud_hintdisplay.cpp" $File "hud_msg.cpp" $File "hud_numericdisplay.cpp" @@ -366,7 +306,6 @@ $Project $File "in_joystick.cpp" $File "in_main.cpp" $File "initializer.cpp" - $File "interpolatedvar.cpp" $File "IsNPCProxy.cpp" $File "lampbeamproxy.cpp" $File "lamphaloproxy.cpp" @@ -403,7 +342,6 @@ $Project $File "$SRCDIR\game\shared\physics_shared.cpp" $File "physpropclientside.cpp" $File "playerandobjectenumerator.cpp" - $File "playerspawncache.cpp" $File "$SRCDIR\game\shared\point_bonusmaps_accessor.cpp" $File "$SRCDIR\game\shared\point_bonusmaps_accessor.h" $File "$SRCDIR\game\shared\point_posecontroller.cpp" @@ -419,8 +357,6 @@ $Project $File "ragdoll.cpp" $File "$SRCDIR\game\shared\ragdoll_shared.cpp" $File "recvproxy.cpp" - $File "basepresence.cpp" [$WIN32||$POSIX] - $File "basepresence_xbox.cpp" [$X360] $File "$SRCDIR\game\shared\rope_helpers.cpp" $File "$SRCDIR\game\shared\saverestore.cpp" $File "$SRCDIR\game\shared\sceneentity_shared.cpp" @@ -437,8 +373,6 @@ $Project $File "spritemodel.cpp" $File "$SRCDIR\game\shared\SpriteTrail.cpp" $File "$SRCDIR\game\shared\studio_shared.cpp" - $File "studio_stats.cpp" - $File "studio_stats.h" $File "$SRCDIR\game\shared\takedamageinfo.cpp" $File "$SRCDIR\game\shared\teamplay_gamerules.cpp" $File "$SRCDIR\game\shared\teamplayroundbased_gamerules.cpp" @@ -457,7 +391,6 @@ $Project $File "vgui_bitmapbutton.cpp" $File "vgui_bitmapimage.cpp" $File "vgui_bitmappanel.cpp" - $File "vgui_schemevisualizer.cpp" $File "vgui_centerstringpanel.cpp" $File "vgui_consolepanel.cpp" $File "vgui_debugoverlaypanel.cpp" @@ -489,30 +422,11 @@ $Project $File "weapons_resource.cpp" $File "WorldDimsProxy.cpp" $File "vgui_video.cpp" - $File "vgui_video_player.cpp" $File "$SRCDIR\game\shared\mp_shareddefs.cpp" - $File "$SRCDIR\game\client\c_vote_controller.h" - $File "$SRCDIR\game\client\c_vote_controller.cpp" - //Haptics - $File "$SRCDIR\public\haptics\haptic_msgs.cpp" [!$X360] - $File "$SRCDIR\public\haptics\haptic_utils.cpp" [$WIN32&&!$X360] - - $File "$SRCDIR\game\client\touch.cpp" - - $Folder "Sixense" - { - $File "sixense\in_sixense.cpp" - $File "sixense\in_sixense.h" - $File "sixense\in_sixense_gesture_bindings.cpp" - $File "sixense\in_sixense_gesture_bindings.h" - $File "$SRCDIR\game\shared\sixense\sixense_convars.cpp" - $File "$SRCDIR\game\shared\sixense\sixense_convars_extern.h" - } // Files not using precompiled header cbase.h - $File "$SRCDIR\public\bone_setup.cpp" \ - "$SRCDIR\public\posedebugger.cpp" \ + $File "$SRCDIR\public\posedebugger.cpp" \ "$SRCDIR\public\client_class.cpp" \ "$SRCDIR\common\compiledcaptionswap.cpp" \ "$SRCDIR\public\collisionutils.cpp" \ @@ -522,8 +436,6 @@ $Project "$SRCDIR\public\dt_utlvector_recv.cpp" \ "$SRCDIR\public\filesystem_helpers.cpp" \ "$SRCDIR\public\interpolatortypes.cpp" \ - "$SRCDIR\game\shared\interval.cpp" \ - "$SRCDIR\common\language.cpp" \ "$SRCDIR\public\networkvar.cpp" \ "$SRCDIR\common\randoverride.cpp" \ "$SRCDIR\public\rope_physics.cpp" \ @@ -537,10 +449,11 @@ $Project "$SRCDIR\public\vallocator.cpp" \ "$SRCDIR\public\vgui_controls\vgui_controls.cpp" \ "$SRCDIR\public\jigglebones.cpp" \ + "$SRCDIR\public\closedcaptions.cpp" \ + "$SRCDIR\public\phonemeconverter.cpp" \ + "in_trackir.cpp" \ "hud_lcd.cpp" \ "in_mouse.cpp" \ - "mumble.cpp" \ - "$SRCDIR\public\renamed_recvtable_compat.cpp" \ "rendertexture.cpp" { $Configuration @@ -636,8 +549,6 @@ $Project $Folder "game_controls" { $File "game_controls\baseviewport.cpp" - $File "game_controls\basemodelpanel.cpp" - $File "game_controls\basemodelpanel.h" $File "game_controls\basemodel_panel.cpp" $File "game_controls\basemodel_panel.h" $File "game_controls\ClientScoreBoardDialog.cpp" @@ -653,7 +564,7 @@ $Project } - $Folder "MP3" [$WIN32||$POSIX] + $Folder "MP3" { $File "mp3player.cpp" $File "mp3player.h" @@ -689,12 +600,15 @@ $Project $File "c_breakableprop.h" $File "c_effects.h" $File "c_entitydissolve.h" + $File "c_entityflame.h" + $File "c_entityfreezing.h" $File "c_env_fog_controller.h" $File "c_fire_smoke.h" $File "c_func_dust.h" $File "c_func_reflective_glass.h" $File "c_gib.h" $File "c_impact_effects.h" + $File "c_movie_display.h" $File "c_physbox.h" $File "c_physicsprop.h" $File "c_pixel_visibility.h" @@ -710,6 +624,7 @@ $Project $File "c_soundscape.h" $File "c_sprite.h" $File "c_sun.h" + $File "c_surfacerender.h" $File "c_te_basebeam.h" $File "c_te_effect_dispatch.h" $File "c_te_legacytempents.h" @@ -717,6 +632,7 @@ $Project $File "c_team.h" $File "c_tesla.h" $File "c_tracer.h" + $File "c_triggers.h" $File "c_vehicle_jeep.h" $File "c_user_message_register.h" $File "c_vguiscreen.h" @@ -729,7 +645,7 @@ $Project $File "cl_mat_stub.h" $File "client_factorylist.h" $File "client_thinklist.h" - $File "clienteffectprecachesystem.h" + $File "clientalphaproperty.h" $File "cliententitylist.h" $File "clientleafsystem.h" $File "clientmode.h" @@ -774,7 +690,6 @@ $Project $File "hud_macros.h" $File "hud_numericdisplay.h" $File "hud_pdump.h" - $File "basepresence.h" $File "hud_vehicle.h" $File "hudelement.h" $File "hudtexturehandle.h" @@ -786,17 +701,16 @@ $Project $File "iconsole.h" $File "idebugoverlaypanel.h" $File "ifpspanel.h" - $File "$SRCDIR\game\shared\econ\ihasowner.h" $File "ihudlcd.h" - $File "ipresence.h" $File "iinput.h" $File "iloadingdisc.h" + $File "imaterialproxydict.h" $File "imessagechars.h" $File "in_main.h" $File "inetgraphpanel.h" $File "initializer.h" $File "input.h" - $File "interpolatedvar.h" + $File "$SRCDIR\public\tier1\interpolatedvar.h" $File "iprofiling.h" $File "itextmessage.h" $File "ivieweffects.h" @@ -804,12 +718,12 @@ $Project $File "iviewrender_beams.h" $File "ivmodemanager.h" $File "kbutton.h" - $File "$SRCDIR\common\language.h" - $File "lerp_functions.h" + $File "keybindinglistener.h" + $File "$SRCDIR\common\language.h" // Source2013? $File "menu.h" $File "movehelper_client.h" - $File "mumble.h" $File "networkstringtable_clientdll.h" + $File "object_motion_blur_effect.h" $File "panelmetaclassmgr.h" $File "particle_collision.h" $File "particle_iterators.h" @@ -830,7 +744,6 @@ $Project $File "physpropclientside.h" $File "playerandobjectenumerator.h" $File "playerenumerator.h" - $File "playerspawncache.h" $File "prediction.h" $File "prediction_private.h" $File "proxyentity.h" @@ -838,6 +751,7 @@ $Project $File "ragdollexplosionenumerator.h" $File "recvproxy.h" $File "rendertexture.h" + $File "replaycamera.h" $File "ScreenSpaceEffects.h" $File "simple_keys.h" $File "smoke_fog_overlay.h" @@ -849,14 +763,15 @@ $Project $File "timedevent.h" $File "toggletextureproxy.h" $File "vgui_basepanel.h" + $File "vgui_bindpanel.h" $File "vgui_bitmapbutton.h" $File "vgui_bitmapimage.h" $File "vgui_bitmappanel.h" - $File "vgui_schemevisualizer.h" $File "vgui_entityimagepanel.h" $File "vgui_entitypanel.h" $File "vgui_grid.h" $File "vgui_helpers.h" + $File "vgui_hudvideo.h" $File "vgui_imagehealthpanel.h" $File "vgui_int.h" $File "vguicenterprint.h" @@ -868,12 +783,11 @@ $Project $File "weapon_selection.h" $File "weapons_resource.h" $File "vgui_video.h" - $File "vgui_video_player.h" } $Folder "Public Header Files" { - $File "$SRCDIR\public\mathlib\amd3dx.h" + $File "$SRCDIR\public\vgui_controls\CircularProgressBar.h" $File "$SRCDIR\public\vgui_controls\AnimationController.h" $File "$SRCDIR\public\basehandle.h" $File "$SRCDIR\public\tier0\basetypes.h" @@ -897,6 +811,7 @@ $Project $File "$SRCDIR\public\vphysics\collision_set.h" $File "$SRCDIR\public\collisionutils.h" $File "$SRCDIR\public\Color.h" + $File "$SRCDIR\public\closedcaptions.h" $File "$SRCDIR\public\vgui_controls\ComboBox.h" $File "$SRCDIR\public\tier0\commonmacros.h" $File "$SRCDIR\public\mathlib\compressed_light_cube.h" @@ -932,6 +847,9 @@ $Project $File "$SRCDIR\public\vgui_controls\HTML.h" $File "$SRCDIR\public\iachievementmgr.h" $File "$SRCDIR\public\appframework\IAppSystem.h" + $File "$SRCDIR\public\tier2\interval.h" + $File "$SRCDIR\public\tier1\lerp_functions.h" + $File "$SRCDIR\public\iclientalphaproperty.h" $File "$SRCDIR\public\icliententity.h" $File "$SRCDIR\public\icliententitylist.h" $File "$SRCDIR\public\engine\IClientLeafSystem.h" @@ -992,7 +910,6 @@ $Project $File "$SRCDIR\public\materialsystem\itexture.h" $File "$SRCDIR\public\engine\ivdebugoverlay.h" $File "$SRCDIR\public\vgui\IVGui.h" - $File "$SRCDIR\public\ivguicenterprint.h" $File "$SRCDIR\public\game\client\iviewport.h" $File "$SRCDIR\public\engine\ivmodelinfo.h" $File "$SRCDIR\public\engine\ivmodelrender.h" @@ -1032,7 +949,6 @@ $Project $File "$SRCDIR\public\r_efx.h" $File "$SRCDIR\public\vstdlib\random.h" $File "$SRCDIR\public\tier1\rangecheckedvar.h" - $File "$SRCDIR\public\renamed_recvtable_compat.h" $File "$SRCDIR\public\vgui_controls\RichText.h" $File "$SRCDIR\public\rope_physics.h" $File "$SRCDIR\public\rope_shared.h" @@ -1093,9 +1009,6 @@ $Project $File "$SRCDIR\public\vgui_controls\WizardSubPanel.h" $File "$SRCDIR\public\worldsize.h" $File "$SRCDIR\public\zip_uncompressed.h" - //Haptics - $File "$SRCDIR\public\haptics\ihaptics.h" [$WIN32] - $File "$SRCDIR\public\haptics\haptic_utils.h" [$WIN32] } $Folder "Game Shared Header Files" @@ -1149,7 +1062,6 @@ $Project $File "$SRCDIR\game\shared\igamesystem.h" $File "$SRCDIR\game\shared\imovehelper.h" $File "$SRCDIR\game\shared\in_buttons.h" - $File "$SRCDIR\game\shared\interval.h" $File "$SRCDIR\game\shared\iplayeranimstate.h" $File "$SRCDIR\game\shared\ipredictionsystem.h" $File "$SRCDIR\game\shared\itempents.h" @@ -1187,7 +1099,6 @@ $Project $File "$SRCDIR\game\shared\shot_manipulator.h" $File "$SRCDIR\game\shared\simtimer.h" $File "$SRCDIR\game\shared\singleplay_gamerules.h" - $File "$SRCDIR\game\shared\smoke_fog_overlay_shared.h" $File "$SRCDIR\game\shared\solidsetdefaults.h" $File "$SRCDIR\game\shared\soundenvelope.h" $File "$SRCDIR\game\shared\Sprite.h" @@ -1212,7 +1123,6 @@ $Project $File "$SRCDIR\game\shared\vphysics_sound.h" $File "$SRCDIR\game\shared\weapon_parse.h" $File "$SRCDIR\game\shared\weapon_proficiency.h" - $File "$SRCDIR\game\shared\weapon_ifmsteadycam.h" $File "$SRCDIR\game\shared\mp_shareddefs.h" } @@ -1226,6 +1136,7 @@ $Project $File "game_controls\mapoverview.h" $File "game_controls\mouseoverhtmlbutton.h" $File "game_controls\mouseoverpanelbutton.h" + $File "game_controls\navprogress.h" $File "game_controls\spectatorgui.h" $File "game_controls\teammenu.h" $File "game_controls\vguitextwindow.h" @@ -1235,29 +1146,20 @@ $Project $Folder "Link Libraries" { $Lib bitmap + $Lib bonesetup $Lib choreoobjects $Lib dmxloader $Lib mathlib $Lib matsys_controls + $Lib npsclient $Lib particles - $Lib tier1 + $Lib raytrace + $Lib responserules_runtime $Lib tier2 $Lib tier3 $Lib vgui_controls + $Lib videocfg $Lib vtf $ImpLib steam_api - - $Lib $LIBCOMMON/libcrypto [$POSIX] - - $ImpLib "$LIBCOMMON\curl" [$OSXALL] - - $Lib "$LIBCOMMON\libcurl" [$WIN32] - $Lib "libz" [$WIN32] - - $Libexternal libz [$LINUXALL] - $Libexternal "$LIBCOMMON/libcurl" [$LINUXALL] - $Libexternal "$LIBCOMMON/libcurlssl" [$LINUXALL] - $Libexternal "$LIBCOMMON/libssl" [$LINUXALL] } - -} +} \ No newline at end of file diff --git a/game/client/client_cstrike.vpc b/game/client/client_cstrike.vpc deleted file mode 100644 index 19429718a..000000000 --- a/game/client/client_cstrike.vpc +++ /dev/null @@ -1,275 +0,0 @@ -//----------------------------------------------------------------------------- -// CLIENT_CSTRIKE.VPC -// -// Project Script -//----------------------------------------------------------------------------- - -$Macro SRCDIR "..\.." -$Macro GAMENAME "cstrike" - -$Include "$SRCDIR\game\client\client_base.vpc" - -$Configuration -{ - $Compiler - { - $AdditionalIncludeDirectories "$BASE;$SRCDIR\game\shared\cstrike\control,.\cstrike,.\cstrike\control,.\cstrike\VGUI,$SRCDIR\game\shared\cstrike" - $PreprocessorDefinitions "$BASE;CSTRIKE_DLL;NEXT_BOT" - } -} - -$Project "Client (CStrike)" -{ - $Folder "Replay" - { - $File "cstrike\cs_replay.cpp" - $File "cstrike\cs_replay.h" - } - - $Folder "Source Files" - { - -$File "$SRCDIR\game\shared\weapon_parse_default.cpp" - - $File "c_team_objectiveresource.cpp" - $File "c_team_objectiveresource.h" - $File "c_team_train_watcher.cpp" - $File "c_team_train_watcher.h" - $File "hud_base_account.cpp" - $File "hud_base_account.h" - $File "hud_voicestatus.cpp" - $File "hud_baseachievement_tracker.cpp" - $File "hud_baseachievement_tracker.h" - $File "$SRCDIR\game\client\hud_vote.h" - $File "$SRCDIR\game\client\hud_vote.cpp" - $File "$SRCDIR\game\shared\predicted_viewmodel.cpp" - $File "$SRCDIR\game\shared\predicted_viewmodel.h" - - $Folder "CounterStrike DLL" - { - $File "$SRCDIR\game\shared\cstrike\cs_achievement_constants.h" - $File "$SRCDIR\game\shared\cstrike\cs_achievementdefs.h" - $File "$SRCDIR\game\shared\cs_achievements_and_stats_interface.cpp" - $File "$SRCDIR\game\shared\cs_achievements_and_stats_interface.h" - $File "$SRCDIR\game\shared\cstrike\achievements_cs.cpp" - $File "$SRCDIR\game\shared\cstrike\achievements_cs.h" - $File "$SRCDIR\game\shared\cstrike\basecsgrenade_projectile.cpp" - $File "$SRCDIR\game\shared\cstrike\basecsgrenade_projectile.h" - $File "cstrike\buy_presets\buy_preset.cpp" - $File "cstrike\buy_presets\buy_preset_debug.cpp" - $File "cstrike\buy_presets\buy_preset_debug.h" - $File "cstrike\buy_presets\buy_preset_weapon_info.cpp" - $File "cstrike\buy_presets\buy_presets.cpp" - $File "cstrike\buy_presets\buy_presets.h" - $File "cstrike\c_cs_hostage.cpp" - $File "cstrike\c_cs_hostage.h" - $File "cstrike\c_cs_player.cpp" - $File "cstrike\c_cs_player.h" - $File "cstrike\c_cs_playerresource.cpp" - $File "cstrike\c_cs_playerresource.h" - $File "cstrike\c_cs_team.cpp" - $File "cstrike\c_cs_team.h" - $File "cstrike\c_csrootpanel.cpp" - $File "cstrike\c_csrootpanel.h" - $File "cstrike\c_plantedc4.cpp" - $File "cstrike\c_plantedc4.h" - $File "cstrike\c_te_radioicon.cpp" - $File "cstrike\c_te_shotgun_shot.cpp" - $File "cstrike\clientmode_csnormal.cpp" - $File "cstrike\clientmode_csnormal.h" - $File "$SRCDIR\game\shared\cstrike\cs_ammodef.cpp" - $File "$SRCDIR\game\shared\cstrike\cs_ammodef.h" - $File "$SRCDIR\game\shared\cstrike\cs_gamemovement.cpp" - $File "$SRCDIR\game\shared\cstrike\cs_gamerules.cpp" - $File "$SRCDIR\game\shared\cstrike\cs_gamerules.h" - $File "$SRCDIR\game\shared\cstrike\cs_gamestats_shared.cpp" - $File "$SRCDIR\game\shared\cstrike\cs_gamestats_shared.h" - $File "$SRCDIR\game\shared\steamworks_gamestats.cpp" - $File "$SRCDIR\game\shared\steamworks_gamestats.h" - $File "cstrike\cs_in_main.cpp" - $File "$SRCDIR\game\shared\cstrike\cs_player_shared.cpp" - $File "$SRCDIR\game\shared\cstrike\cs_playeranimstate.cpp" - $File "$SRCDIR\game\shared\cstrike\cs_playeranimstate.h" - $File "cstrike\cs_prediction.cpp" - $File "$SRCDIR\game\shared\cstrike\cs_shareddefs.cpp" - $File "cstrike\cs_client_gamestats.cpp" - $File "cstrike\cs_client_gamestats.h" - $File "$SRCDIR\game\shared\cstrike\cs_usermessages.cpp" - $File "cstrike\cs_view_scene.cpp" - $File "cstrike\cs_view_scene.h" - $File "$SRCDIR\game\shared\cstrike\cs_weapon_parse.cpp" - $File "$SRCDIR\game\shared\cstrike\cs_weapon_parse.h" - $File "cstrike\fx_cs_blood.cpp" - $File "cstrike\fx_cs_blood.h" - $File "cstrike\fx_cs_impacts.cpp" - $File "cstrike\fx_cs_knifeslash.cpp" - $File "cstrike\fx_cs_muzzleflash.cpp" - $File "$SRCDIR\game\shared\cstrike\fx_cs_shared.cpp" - $File "$SRCDIR\game\shared\cstrike\fx_cs_shared.h" - $File "cstrike\fx_cs_weaponfx.cpp" - $File "$SRCDIR\game\shared\cstrike\bot\shared_util.cpp" - $File "$SRCDIR\game\shared\cstrike\bot\shared_util.h" - $File "cstrike\vgui_rootpanel_cs.cpp" - - $Folder "HUD Elements" - { - $File "cstrike\cs_hud_ammo.cpp" - $File "cstrike\cs_hud_chat.cpp" - $File "cstrike\cs_hud_chat.h" - $File "cstrike\cs_hud_damageindicator.cpp" - $File "cstrike\cs_hud_freezepanel.cpp" - $File "cstrike\cs_hud_freezepanel.h" - $File "cstrike\cs_hud_playerhealth.cpp" - $File "cstrike\cs_hud_playerhealth.h" - $File "cstrike\cs_hud_health.cpp" - $File "cstrike\cs_hud_scope.cpp" - $File "cstrike\cs_hud_target_id.cpp" - $File "cstrike\cs_hud_weaponselection.cpp" - $File "cstrike\hud_account.cpp" - $File "cstrike\hud_armor.cpp" - $File "cstrike\hud_c4.cpp" - $File "cstrike\hud_deathnotice.cpp" - $File "cstrike\hud_defuser.cpp" - $File "cstrike\hud_flashbang.cpp" - $File "cstrike\hud_hostagerescue.cpp" - $File "cstrike\hud_progressbar.cpp" - $File "cstrike\hud_radar.cpp" - $File "cstrike\hud_radar.h" - $File "cstrike\hud_roundtimer.cpp" - $File "cstrike\hud_scenarioicon.cpp" - $File "cstrike\hud_shopping_cart.cpp" - $File "cstrike\cs_hud_achievement_announce.cpp" - $File "cstrike\cs_hud_achievement_announce.h" - $File "cstrike\cs_hud_achievement_tracker.cpp" - $File "cstrike\radio_status.cpp" - $File "cstrike\radio_status.h" - } - - $Folder "Weapon" - { - $File "$SRCDIR\game\shared\cstrike\weapon_ak47.cpp" - $File "$SRCDIR\game\shared\cstrike\weapon_aug.cpp" - $File "$SRCDIR\game\shared\cstrike\weapon_awp.cpp" - $File "$SRCDIR\game\shared\cstrike\weapon_basecsgrenade.cpp" - $File "$SRCDIR\game\shared\cstrike\weapon_basecsgrenade.h" - $File "$SRCDIR\game\shared\cstrike\weapon_c4.cpp" - $File "$SRCDIR\game\shared\cstrike\weapon_c4.h" - $File "$SRCDIR\game\shared\cstrike\weapon_csbase.cpp" - $File "$SRCDIR\game\shared\cstrike\weapon_csbase.h" - $File "$SRCDIR\game\shared\cstrike\weapon_csbasegun.cpp" - $File "$SRCDIR\game\shared\cstrike\weapon_csbasegun.h" - $File "$SRCDIR\game\shared\cstrike\weapon_deagle.cpp" - $File "$SRCDIR\game\shared\cstrike\weapon_elite.cpp" - $File "$SRCDIR\game\shared\cstrike\weapon_famas.cpp" - $File "$SRCDIR\game\shared\cstrike\weapon_fiveseven.cpp" - $File "$SRCDIR\game\shared\cstrike\weapon_flashbang.cpp" - $File "$SRCDIR\game\shared\cstrike\weapon_flashbang.h" - $File "$SRCDIR\game\shared\cstrike\weapon_g3sg1.cpp" - $File "$SRCDIR\game\shared\cstrike\weapon_galil.cpp" - $File "$SRCDIR\game\shared\cstrike\weapon_glock.cpp" - $File "$SRCDIR\game\shared\cstrike\weapon_hegrenade.cpp" - $File "$SRCDIR\game\shared\cstrike\weapon_hegrenade.h" - $File "$SRCDIR\game\shared\cstrike\weapon_knife.cpp" - $File "$SRCDIR\game\shared\cstrike\weapon_knife.h" - $File "$SRCDIR\game\shared\cstrike\weapon_m249.cpp" - $File "$SRCDIR\game\shared\cstrike\weapon_m3.cpp" - $File "$SRCDIR\game\shared\cstrike\weapon_m4a1.cpp" - $File "$SRCDIR\game\shared\cstrike\weapon_mac10.cpp" - $File "$SRCDIR\game\shared\cstrike\weapon_mp5navy.cpp" - $File "$SRCDIR\game\shared\cstrike\weapon_p228.cpp" - $File "$SRCDIR\game\shared\cstrike\weapon_p90.cpp" - $File "$SRCDIR\game\shared\cstrike\weapon_scout.cpp" - $File "$SRCDIR\game\shared\cstrike\weapon_sg550.cpp" - $File "$SRCDIR\game\shared\cstrike\weapon_sg552.cpp" - $File "$SRCDIR\game\shared\cstrike\weapon_smokegrenade.cpp" - $File "$SRCDIR\game\shared\cstrike\weapon_smokegrenade.h" - $File "$SRCDIR\game\shared\cstrike\weapon_tmp.cpp" - $File "$SRCDIR\game\shared\cstrike\weapon_ump45.cpp" - $File "$SRCDIR\game\shared\cstrike\weapon_usp.cpp" - $File "$SRCDIR\game\shared\cstrike\weapon_xm1014.cpp" - } - - $Folder "vgui" - { - $File "cstrike\VGUI\achievement_stats_summary.cpp" - $File "cstrike\VGUI\achievement_stats_summary.h" - $File "cstrike\VGUI\achievements_page.cpp" - $File "cstrike\VGUI\achievements_page.h" - $File "cstrike\VGUI\stats_summary.cpp" - $File "cstrike\VGUI\stats_summary.h" - $File "cstrike\VGUI\stat_card.cpp" - $File "cstrike\VGUI\stat_card.h" - $File "cstrike\VGUI\base_stats_page.cpp" - $File "cstrike\VGUI\base_stats_page.h" - $File "cstrike\VGUI\match_stats_page.cpp" - $File "cstrike\VGUI\match_stats_page.h" - $File "cstrike\VGUI\lifetime_stats_page.cpp" - $File "cstrike\VGUI\lifetime_stats_page.h" - $File "cstrike\VGUI\bordered_panel.cpp" - $File "cstrike\VGUI\bordered_panel.h" - $File "cstrike\VGUI\backgroundpanel.cpp" - $File "cstrike\VGUI\backgroundpanel.h" - $File "cstrike\VGUI\buymouseoverpanelbutton.h" - $File "cstrike\VGUI\buypreset_imageinfo.cpp" - $File "cstrike\VGUI\buypreset_listbox.cpp" - $File "cstrike\VGUI\buypreset_listbox.h" - $File "cstrike\VGUI\buypreset_panel.cpp" - $File "cstrike\VGUI\buypreset_weaponsetlabel.h" - $File "cstrike\VGUI\career_box.cpp" - $File "cstrike\VGUI\career_box.h" - $File "cstrike\VGUI\career_button.cpp" - $File "cstrike\VGUI\career_button.h" - $File "cstrike\VGUI\counterstrikeviewport.cpp" - $File "cstrike\VGUI\counterstrikeviewport.h" - $File "cstrike\VGUI\cstrikebuyequipmenu.cpp" - $File "cstrike\VGUI\cstrikebuyequipmenu.h" - $File "cstrike\VGUI\cstrikebuymenu.cpp" - $File "cstrike\VGUI\cstrikebuymenu.h" - $File "cstrike\VGUI\cstrikebuysubmenu.h" - $File "cstrike\VGUI\cstrikeclassmenu.cpp" - $File "cstrike\VGUI\cstrikeclassmenu.h" - $File "cstrike\VGUI\cstrikeclientscoreboard.cpp" - $File "cstrike\VGUI\cstrikeclientscoreboard.h" - $File "cstrike\VGUI\cstrikespectatorgui.cpp" - $File "cstrike\VGUI\cstrikespectatorgui.h" - $File "cstrike\VGUI\cstriketeammenu.cpp" - $File "cstrike\VGUI\cstriketeammenu.h" - $File "cstrike\VGUI\cstriketextwindow.cpp" - $File "cstrike\VGUI\cstriketextwindow.h" - $File "cstrike\vgui_c4panel.cpp" - $File "cstrike\vgui_viewc4panel.cpp" - $File "cstrike\VGUI\win_panel_round.cpp" - $File "cstrike\VGUI\win_panel_round.h" - } - - $Folder "NextBot" - { - $File "NextBot\C_NextBot.cpp" - $File "NextBot\C_NextBot.h" - } - } - - $Folder "game_controls" - { - $File "game_controls\buymenu.cpp" - $File "game_controls\buysubmenu.cpp" - $File "game_controls\classmenu.cpp" - } - } - - $Folder "Header Files" - { - - $Folder "game_controls header files" - { - $File "game_controls\buymenu.h" - $File "game_controls\buysubmenu.h" - $File "game_controls\classmenu.h" - } - } - - $Folder "Link Libraries" - { - $Lib vtf - } - -} diff --git a/game/client/client_dod.vpc b/game/client/client_dod.vpc deleted file mode 100644 index 94f093c09..000000000 --- a/game/client/client_dod.vpc +++ /dev/null @@ -1,246 +0,0 @@ -//----------------------------------------------------------------------------- -// CLIENT_DOD.VPC -// -// Project Script -//----------------------------------------------------------------------------- - -$Macro SRCDIR "..\.." -$Macro GAMENAME "dod" - -$Include "$SRCDIR\game\client\client_base.vpc" - -$Configuration -{ - $Compiler - { - $AdditionalIncludeDirectories "$BASE;dod,.\dod\VGUI,$SRCDIR\game\shared\dod" - $PreprocessorDefinitions "$BASE;DOD_DLL;ENABLE_HTML_WINDOW" - } -} - -$Project "Client (DOD)" -{ - $Folder "Source Files" - { - -$File "$SRCDIR\game\shared\weapon_parse_default.cpp" - -$File "history_resource.cpp" - -$File "hud_hintdisplay.cpp" - - $File "hud_voicestatus.cpp" - - $File "$SRCDIR\game\shared\playerclass_info_parse.cpp" - $File "$SRCDIR\game\shared\playerclass_info_parse.h" - - $Folder "Day of Defeat DLL" - { - $File "$SRCDIR\game\shared\dod\achievements_dod.cpp" - $File "dod\c_dod_basegrenade.cpp" - $File "dod\c_dod_basegrenade.h" - $File "dod\c_dod_baserocket.cpp" - $File "dod\c_dod_bombdispenser.cpp" - $File "dod\c_dod_bombtarget.cpp" - $File "dod\c_dod_objective_resource.cpp" - $File "dod\c_dod_objective_resource.h" - $File "dod\c_dod_player.cpp" - $File "dod\c_dod_player.h" - $File "dod\c_dod_playerresource.cpp" - $File "dod\c_dod_playerresource.h" - $File "dod\c_dod_smokegrenade.cpp" - $File "dod\c_dod_smokegrenade.h" - $File "dod\c_dod_team.cpp" - $File "dod\c_dod_team.h" - $File "dod\c_grenadetrail.cpp" - $File "dod\c_grenadetrail.h" - $File "dod\c_te_firebullets.cpp" - $File "dod\clientmode_dod.cpp" - $File "dod\clientmode_dod.h" - $File "dod\dod_fx_explosions.cpp" - $File "$SRCDIR\game\shared\dod\dod_gamemovement.cpp" - $File "$SRCDIR\game\shared\dod\dod_gamerules.cpp" - $File "$SRCDIR\game\shared\dod\dod_gamerules.h" - $File "dod\dod_headiconmanager.cpp" - $File "dod\dod_headiconmanager.h" - $File "dod\dod_hud_ammo.cpp" - $File "dod\dod_hud_areacapicon.cpp" - $File "dod\dod_hud_capturepanel.cpp" - $File "dod\dod_hud_capturepanel.h" - $File "dod\dod_hud_chat.cpp" - $File "dod\dod_hud_chat.h" - $File "dod\dod_hud_crosshair.cpp" - $File "dod\dod_hud_crosshair.h" - $File "dod\dod_hud_damageindicator.cpp" - $File "dod\dod_hud_deathnotice.cpp" - $File "dod\dod_hud_freezepanel.cpp" - $File "dod\dod_hud_freezepanel.h" - $File "dod\dod_hud_health.cpp" - $File "dod\dod_hud_hintdisplay.cpp" - $File "dod\dod_hud_history_resource.cpp" - $File "dod\dod_hud_objectiveicons.cpp" - $File "dod\dod_hud_playerstatus_ammo.cpp" - $File "dod\dod_hud_playerstatus_ammo.h" - $File "dod\dod_hud_playerstatus_fireselect.cpp" - $File "dod\dod_hud_playerstatus_fireselect.h" - $File "dod\dod_hud_playerstatus_health.cpp" - $File "dod\dod_hud_playerstatus_health.h" - $File "dod\dod_hud_playerstatus_mgheat.cpp" - $File "dod\dod_hud_playerstatus_mgheat.h" - $File "dod\dod_hud_playerstatus_stamina.cpp" - $File "dod\dod_hud_playerstatus_stamina.h" - $File "dod\dod_hud_playerstatus_tnt.cpp" - $File "dod\dod_hud_playerstatus_weapon.cpp" - $File "dod\dod_hud_playerstatus_weapon.h" - $File "dod\dod_hud_playerstatuspanel.cpp" - $File "dod\dod_hud_readyrestart.cpp" - $File "dod\dod_hud_restartround.cpp" - $File "dod\dod_hud_scope.cpp" - $File "dod\dod_hud_spec_crosshair.cpp" - $File "dod\dod_hud_spec_crosshair.h" - $File "dod\dod_hud_target_id.cpp" - $File "dod\dod_hud_tnt_pickup.cpp" - $File "dod\dod_hud_warmuplabel.cpp" - $File "dod\dod_hud_weaponselection.cpp" - $File "dod\dod_hud_winpanel.cpp" - $File "dod\dod_hud_winpanel.h" - $File "dod\dod_in_main.cpp" - $File "$SRCDIR\game\shared\dod\dod_player_shared.cpp" - $File "$SRCDIR\game\shared\dod\dod_player_shared.h" - $File "$SRCDIR\game\shared\dod\dod_playeranimstate.cpp" - $File "$SRCDIR\game\shared\dod\dod_playeranimstate.h" - $File "$SRCDIR\game\shared\dod\dod_playerclass_info_parse.cpp" - $File "$SRCDIR\game\shared\dod\dod_playerclass_info_parse.h" - $File "dod\dod_playerstats.cpp" - $File "dod\dod_playerstats.h" - $File "dod\dod_prediction.cpp" - $File "$SRCDIR\game\shared\dod\dod_round_timer.cpp" - $File "$SRCDIR\game\shared\dod\dod_shareddefs.cpp" - $File "$SRCDIR\game\shared\dod\dod_shareddefs.h" - $File "$SRCDIR\game\shared\dod\dod_usermessages.cpp" - $File "dod\dod_view_scene.cpp" - $File "dod\dod_view_scene.h" - $File "$SRCDIR\game\shared\dod\dod_viewmodel.cpp" - $File "$SRCDIR\game\shared\dod\dod_viewmodel.h" - $File "$SRCDIR\game\shared\dod\dod_weapon_parse.cpp" - $File "$SRCDIR\game\shared\dod\dod_weapon_parse.h" - $File "dod\VGUI\backgroundpanel.cpp" - $File "dod\VGUI\backgroundpanel.h" - $File "dod\VGUI\dodbutton.cpp" - $File "dod\VGUI\dodbutton.h" - $File "dod\VGUI\dodclassmenu.cpp" - $File "dod\VGUI\dodclassmenu.h" - $File "dod\VGUI\dodclientscoreboard.cpp" - $File "dod\VGUI\dodclientscoreboard.h" - $File "dod\VGUI\dodcornercutpanel.cpp" - $File "dod\VGUI\dodcornercutpanel.h" - $File "dod\VGUI\dodmenubackground.cpp" - $File "dod\VGUI\dodmenubackground.h" - $File "dod\VGUI\dodmouseoverpanelbutton.h" - $File "dod\VGUI\dodoverview.cpp" - $File "dod\VGUI\dodoverview.h" - $File "dod\VGUI\dodrandombutton.h" - $File "dod\VGUI\dodspectatorgui.cpp" - $File "dod\VGUI\dodspectatorgui.h" - $File "dod\VGUI\dodteammenu.cpp" - $File "dod\VGUI\dodteammenu.h" - $File "dod\VGUI\dodtextwindow.cpp" - $File "dod\VGUI\dodtextwindow.h" - $File "dod\VGUI\dodviewport.cpp" - $File "dod\VGUI\dodviewport.h" - $File "dod\fx_dod_blood.cpp" - $File "dod\fx_dod_blood.h" - $File "dod\fx_dod_ejectbrass.cpp" - $File "dod\fx_dod_filmgrain.cpp" - $File "dod\fx_dod_impact.cpp" - $File "dod\fx_dod_knifeslash.cpp" - $File "dod\fx_dod_muzzleflash.cpp" - $File "dod\fx_dod_muzzleflash.h" - $File "$SRCDIR\game\shared\dod\fx_dod_shared.cpp" - $File "$SRCDIR\game\shared\dod\fx_dod_shared.h" - $File "dod\fx_dod_tracers.cpp" - $File "dod\VGUI\idodviewportmsgs.h" - $File "dod\VGUI\vgui_rootpanel_dod.cpp" - $File "dod\VGUI\vgui_rootpanel_dod.h" - $File "$SRCDIR\game\shared\dod\weapon_30cal.cpp" - $File "$SRCDIR\game\shared\dod\weapon_amerknife.cpp" - $File "$SRCDIR\game\shared\dod\weapon_bar.cpp" - $File "$SRCDIR\game\shared\dod\weapon_bazooka.cpp" - $File "$SRCDIR\game\shared\dod\weapon_c96.cpp" - $File "$SRCDIR\game\shared\dod\weapon_colt.cpp" - $File "$SRCDIR\game\shared\dod\weapon_dodbase.cpp" - $File "$SRCDIR\game\shared\dod\weapon_dodbase.h" - $File "$SRCDIR\game\shared\dod\weapon_dodbasebomb.cpp" - $File "$SRCDIR\game\shared\dod\weapon_dodbasebomb.h" - $File "$SRCDIR\game\shared\dod\weapon_dodbasegrenade.cpp" - $File "$SRCDIR\game\shared\dod\weapon_dodbasegrenade.h" - $File "$SRCDIR\game\shared\dod\weapon_dodbasegun.cpp" - $File "$SRCDIR\game\shared\dod\weapon_dodbasegun.h" - $File "$SRCDIR\game\shared\dod\weapon_dodbasemelee.cpp" - $File "$SRCDIR\game\shared\dod\weapon_dodbasemelee.h" - $File "$SRCDIR\game\shared\dod\weapon_dodbaserpg.cpp" - $File "$SRCDIR\game\shared\dod\weapon_dodbaserpg.h" - $File "$SRCDIR\game\shared\dod\weapon_dodbipodgun.cpp" - $File "$SRCDIR\game\shared\dod\weapon_dodbipodgun.h" - $File "$SRCDIR\game\shared\dod\weapon_dodfireselect.cpp" - $File "$SRCDIR\game\shared\dod\weapon_dodfireselect.h" - $File "$SRCDIR\game\shared\dod\weapon_dodfullauto.cpp" - $File "$SRCDIR\game\shared\dod\weapon_dodfullauto.h" - $File "$SRCDIR\game\shared\dod\weapon_dodfullauto_punch.cpp" - $File "$SRCDIR\game\shared\dod\weapon_dodfullauto_punch.h" - $File "$SRCDIR\game\shared\dod\weapon_dodsemiauto.cpp" - $File "$SRCDIR\game\shared\dod\weapon_dodsemiauto.h" - $File "$SRCDIR\game\shared\dod\weapon_dodsniper.cpp" - $File "$SRCDIR\game\shared\dod\weapon_dodsniper.h" - $File "$SRCDIR\game\shared\dod\weapon_explodinghandgrenade.cpp" - $File "$SRCDIR\game\shared\dod\weapon_explodingstickgrenade.cpp" - $File "$SRCDIR\game\shared\dod\weapon_garand.cpp" - $File "$SRCDIR\game\shared\dod\weapon_handgrenade.cpp" - $File "$SRCDIR\game\shared\dod\weapon_k98.cpp" - $File "$SRCDIR\game\shared\dod\weapon_k98_scoped.cpp" - $File "$SRCDIR\game\shared\dod\weapon_m1carbine.cpp" - $File "$SRCDIR\game\shared\dod\weapon_mg42.cpp" - $File "$SRCDIR\game\shared\dod\weapon_mg42.h" - $File "$SRCDIR\game\shared\dod\weapon_mp40.cpp" - $File "$SRCDIR\game\shared\dod\weapon_mp44.cpp" - $File "$SRCDIR\game\shared\dod\weapon_p38.cpp" - $File "$SRCDIR\game\shared\dod\weapon_pschreck.cpp" - $File "$SRCDIR\game\shared\dod\weapon_riflegrenade.cpp" - $File "$SRCDIR\game\shared\dod\weapon_riflegrenade.h" - $File "$SRCDIR\game\shared\dod\weapon_riflegrenade_ger.cpp" - $File "$SRCDIR\game\shared\dod\weapon_riflegrenade_ger_live.cpp" - $File "$SRCDIR\game\shared\dod\weapon_riflegrenade_us.cpp" - $File "$SRCDIR\game\shared\dod\weapon_riflegrenade_us_live.cpp" - $File "$SRCDIR\game\shared\dod\weapon_smokegrenade_ger.cpp" - $File "$SRCDIR\game\shared\dod\weapon_smokegrenade_us.cpp" - $File "$SRCDIR\game\shared\dod\weapon_spade.cpp" - $File "$SRCDIR\game\shared\dod\weapon_spring.cpp" - $File "$SRCDIR\game\shared\dod\weapon_stickgrenade.cpp" - $File "$SRCDIR\game\shared\dod\weapon_thompson.cpp" - } - - $Folder "game_controls" - { - $File "game_controls\buymenu.cpp" - $File "game_controls\buysubmenu.cpp" - $File "game_controls\classmenu.cpp" - } - - $Folder "IFM" - { - $File "$SRCDIR\game\shared\weapon_ifmbase.cpp" - $File "$SRCDIR\game\shared\weapon_ifmbase.h" - $File "$SRCDIR\game\shared\weapon_ifmbasecamera.cpp" - $File "$SRCDIR\game\shared\weapon_ifmbasecamera.h" - $File "$SRCDIR\game\shared\weapon_ifmsteadycam.cpp" - } - } - - $Folder "Header Files" - { - - $Folder "game_controls header files" - { - $File "game_controls\buymenu.h" - $File "game_controls\buysubmenu.h" - $File "game_controls\classmenu.h" - } - } -} diff --git a/game/client/client_episodic.vpc b/game/client/client_episodic.vpc deleted file mode 100644 index 5c89d9409..000000000 --- a/game/client/client_episodic.vpc +++ /dev/null @@ -1,132 +0,0 @@ -//----------------------------------------------------------------------------- -// CLIENT_EPISODIC.VPC -// -// Project Script -//----------------------------------------------------------------------------- - -$Macro SRCDIR "..\.." -$Macro GAMENAME "episodic" [!$SOURCESDK] -$Macro GAMENAME "mod_episodic" [$SOURCESDK] - -$Include "$SRCDIR\game\client\client_base.vpc" - -$Configuration -{ - $Compiler - { - $AdditionalIncludeDirectories ".\hl2;.\hl2\elements;$SRCDIR\game\shared\hl2;$SRCDIR\game\shared\episodic;..\..\public;$BASE" - $PreprocessorDefinitions "$BASE;HL2_CLIENT_DLL;HL2_EPISODIC" - } -} - -$Project "Client (Episodic)" -{ - $Folder "Source Files" - { - $File "hud_chat.cpp" - $File "c_team_objectiveresource.cpp" - $File "c_team_objectiveresource.h" - - $Folder "HL2 DLL" - { - $File "$SRCDIR\game\shared\hl2\basehlcombatweapon_shared.cpp" - $File "$SRCDIR\game\shared\episodic\achievements_ep1.cpp" - $File "$SRCDIR\game\shared\episodic\achievements_ep2.cpp" - $File "$SRCDIR\game\shared\episodic\achievements_epx.cpp" - $File "hl2\c_antlion_dust.cpp" - $File "hl2\c_ar2_explosion.cpp" - $File "hl2\c_barnacle.cpp" - $File "hl2\c_barney.cpp" - $File "hl2\c_basehelicopter.cpp" - $File "hl2\c_basehelicopter.h" - $File "hl2\c_basehlcombatweapon.cpp" - $File "hl2\c_basehlcombatweapon.h" - $File "hl2\c_basehlplayer.cpp" - $File "hl2\c_basehlplayer.h" - $File "hl2\c_citadel_effects.cpp" - $File "hl2\c_corpse.cpp" - $File "hl2\c_corpse.h" - $File "hl2\c_env_alyxtemp.cpp" - $File "hl2\c_env_headcrabcanister.cpp" - $File "hl2\c_env_starfield.cpp" - $File "hl2\c_func_tankmortar.cpp" - $File "hl2\c_hl2_playerlocaldata.cpp" - $File "hl2\c_hl2_playerlocaldata.h" - $File "hl2\c_info_teleporter_countdown.cpp" - $File "hl2\c_npc_antlionguard.cpp" - $File "hl2\c_npc_combinegunship.cpp" - $File "hl2\c_npc_manhack.cpp" - $File "hl2\c_npc_rollermine.cpp" - $File "hl2\c_plasma_beam_node.cpp" - $File "hl2\c_prop_combine_ball.cpp" - $File "hl2\c_prop_combine_ball.h" - $File "episodic\c_prop_scalable.cpp" - $File "hl2\c_rotorwash.cpp" - $File "hl2\c_script_intro.cpp" - $File "$SRCDIR\game\shared\script_intro_shared.cpp" - $File "hl2\c_strider.cpp" - $File "hl2\c_te_concussiveexplosion.cpp" - $File "hl2\c_te_flare.cpp" - $File "hl2\c_thumper_dust.cpp" - $File "hl2\c_vehicle_airboat.cpp" - $File "hl2\c_vehicle_cannon.cpp" - $File "hl2\c_vehicle_crane.cpp" - $File "hl2\c_vehicle_crane.h" - $File "episodic\c_vehicle_jeep_episodic.cpp" - $File "hl2\c_vehicle_prisoner_pod.cpp" - $File "episodic\c_vort_charge_token.cpp" - $File "hl2\c_weapon__stubs_hl2.cpp" - $File "hl2\c_weapon_crossbow.cpp" - $File "episodic\c_weapon_hopwire.cpp" - $File "hl2\c_weapon_physcannon.cpp" - $File "hl2\c_weapon_stunstick.cpp" - $File "$SRCDIR\game\shared\hl2\citadel_effects_shared.h" - $File "hl2\clientmode_hlnormal.cpp" - $File "hl2\clientmode_hlnormal.h" - $File "death.cpp" - $File "$SRCDIR\game\shared\hl2\env_headcrabcanister_shared.cpp" - $File "$SRCDIR\game\shared\hl2\env_headcrabcanister_shared.h" - $File "$SRCDIR\game\shared\episodic\npc_advisor_shared.h" - $File "episodic\c_npc_advisor.cpp" - $File "episodic\episodic_screenspaceeffects.cpp" - $File "episodic\episodic_screenspaceeffects.h" - $File "episodic\flesh_internal_material_proxy.cpp" - $File "hl2\fx_antlion.cpp" - $File "hl2\fx_bugbait.cpp" - $File "hl2\fx_hl2_impacts.cpp" - $File "hl2\fx_hl2_tracers.cpp" - $File "hl2\hl2_clientmode.cpp" - $File "$SRCDIR\game\shared\hl2\hl2_gamerules.cpp" - $File "$SRCDIR\game\shared\hl2\hl2_gamerules.h" - $File "$SRCDIR\game\shared\hl2\hl2_shareddefs.h" - $File "$SRCDIR\game\shared\hl2\hl2_usermessages.cpp" - $File "$SRCDIR\game\shared\hl2\hl_gamemovement.cpp" - $File "$SRCDIR\game\shared\hl2\hl_gamemovement.h" - $File "hl2\hl_in_main.cpp" - $File "hl2\hl_prediction.cpp" - $File "hl2\hud_ammo.cpp" - $File "hl2\hud_battery.cpp" - $File "hl2\hud_blood.cpp" - $File "hl2\hud_credits.cpp" - $File "hl2\hud_damageindicator.cpp" - $File "hl2\hud_flashlight.cpp" - $File "hl2\hud_locator.cpp" - $File "hl2\hud_health.cpp" - $File "hl2\hud_poisondamageindicator.cpp" - $File "hud_posture.cpp" - $File "hl2\hud_quickinfo.cpp" - $File "hl2\hud_radar.cpp" - $File "hl2\hud_radar.h" - $File "hud_squadstatus.cpp" - $File "hl2\hud_suitpower.cpp" - $File "hl2\hud_suitpower.h" - $File "hl2\hud_weaponselection.cpp" - $File "hl2\hud_zoom.cpp" - $File "hl2\shieldproxy.cpp" - $File "$SRCDIR\game\shared\hl2\survival_gamerules.cpp" - $File "hl2\vgui_rootpanel_hl2.cpp" - $File "episodic\c_npc_puppet.cpp" - } - } - -} diff --git a/game/client/client_factorylist.cpp b/game/client/client_factorylist.cpp index 9275bc5e9..33e214d40 100644 --- a/game/client/client_factorylist.cpp +++ b/game/client/client_factorylist.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // diff --git a/game/client/client_factorylist.h b/game/client/client_factorylist.h index 6cb27b1b2..7cb206877 100644 --- a/game/client/client_factorylist.h +++ b/game/client/client_factorylist.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======= // // Purpose: // @@ -15,7 +15,6 @@ struct factorylist_t { CreateInterfaceFn appSystemFactory; - CreateInterfaceFn physicsFactory; }; // Store off the factories diff --git a/game/client/client_hl1.vpc b/game/client/client_hl1.vpc deleted file mode 100644 index d9a9f37fd..000000000 --- a/game/client/client_hl1.vpc +++ /dev/null @@ -1,103 +0,0 @@ -//----------------------------------------------------------------------------- -// CLIENT_HL1.VPC -// -// Project Script -//----------------------------------------------------------------------------- - -$Macro SRCDIR "..\.." -$Macro GAMENAME "hl1" - -$Include "$SRCDIR\game\client\client_base.vpc" - -$Configuration -{ - $Compiler - { - $AdditionalIncludeDirectories "$BASE;.\hl1,.\hl2,.\hl2\elements,$SRCDIR\game\shared\hl1,$SRCDIR\game\shared\hl2" - $PreprocessorDefinitions "$BASE;HL1_CLIENT_DLL" - } -} - -$Project "Client (HL1)" -{ - $Folder "Source Files" - { - -$File "geiger.cpp" - -$File "history_resource.cpp" - -$File "train.cpp" - - $File "c_team_objectiveresource.cpp" - $File "c_team_objectiveresource.h" - $File "hud_chat.cpp" - $File "$SRCDIR\game\shared\predicted_viewmodel.cpp" - $File "$SRCDIR\game\shared\predicted_viewmodel.h" - - $Folder "HL2 DLL" - { - $File "hl2\c_antlion_dust.cpp" - $File "hl2\c_basehelicopter.cpp" - $File "hl2\c_basehelicopter.h" - $File "hl2\c_basehlcombatweapon.h" - $File "hl2\c_corpse.cpp" - $File "hl2\c_corpse.h" - $File "hl2\c_hl2_playerlocaldata.h" - $File "hl2\c_rotorwash.cpp" - $File "$SRCDIR\game\shared\hl2\citadel_effects_shared.h" - $File "$SRCDIR\game\shared\hl2\env_headcrabcanister_shared.h" - $File "hl2\fx_bugbait.cpp" - $File "$SRCDIR\game\shared\hl2\hl2_shareddefs.h" - $File "hl2\hl_in_main.cpp" - $File "hl2\hl_prediction.cpp" - $File "hl2\vgui_rootpanel_hl2.cpp" - } - - $Folder "HL1 DLL" - { - $File "hl1\c_hl1mp_player.cpp" - $File "$SRCDIR\game\shared\hl1\hl1_basecombatweapon_shared.cpp" - $File "$SRCDIR\game\shared\hl1\hl1_basecombatweapon_shared.h" - $File "hl1\hl1_c_legacytempents.cpp" - $File "hl1\hl1_c_player.cpp" - $File "hl1\hl1_c_player.h" - $File "hl1\hl1_c_rpg_rocket.cpp" - $File "hl1\hl1_c_weapon__stubs.cpp" - $File "hl1\hl1_clientmode.cpp" - $File "hl1\hl1_clientmode.h" - $File "hl1\hl1_fx_gauss.cpp" - $File "hl1\hl1_fx_gibs.cpp" - $File "hl1\hl1_fx_impacts.cpp" - $File "hl1\hl1_fx_shelleject.cpp" - $File "$SRCDIR\game\shared\hl1\hl1_gamemovement.cpp" - $File "$SRCDIR\game\shared\hl1\hl1_gamemovement.h" - $File "$SRCDIR\game\shared\hl1\hl1_gamerules.cpp" - $File "hl1\hl1_hud_ammo.cpp" - $File "hl1\hl1_hud_battery.cpp" - $File "hl1\hl1_hud_damageindicator.cpp" - $File "hl1\hl1_hud_damagetiles.cpp" - $File "hl1\hl1_hud_flashlight.cpp" - $File "hl1\hl1_hud_geiger.cpp" - $File "hl1\hl1_hud_health.cpp" - $File "hl1\hl1_hud_history_resource.cpp" - $File "hl1\hl1_hud_numbers.cpp" - $File "hl1\hl1_hud_numbers.h" - $File "hl1\hl1_hud_train.cpp" - $File "hl1\hl1_hud_weaponselection.cpp" - $File "$SRCDIR\game\shared\hl1\hl1_player_shared.cpp" - $File "$SRCDIR\game\shared\hl1\hl1_player_shared.h" - $File "$SRCDIR\game\shared\hl1\hl1_usermessages.cpp" - $File "$SRCDIR\game\shared\hl1\hl1mp_basecombatweapon_shared.cpp" - $File "$SRCDIR\game\shared\hl1\hl1mp_weapon_357.cpp" - $File "$SRCDIR\game\shared\hl1\hl1mp_weapon_crossbow.cpp" - $File "$SRCDIR\game\shared\hl1\hl1mp_weapon_egon.cpp" - $File "$SRCDIR\game\shared\hl1\hl1mp_weapon_gauss.cpp" - $File "$SRCDIR\game\shared\hl1\hl1mp_weapon_glock.cpp" - $File "$SRCDIR\game\shared\hl1\hl1mp_weapon_handgrenade.cpp" - $File "$SRCDIR\game\shared\hl1\hl1mp_weapon_hornetgun.cpp" - $File "$SRCDIR\game\shared\hl1\hl1mp_weapon_mp5.cpp" - $File "$SRCDIR\game\shared\hl1\hl1mp_weapon_rpg.cpp" - $File "$SRCDIR\game\shared\hl1\hl1mp_weapon_sachel.cpp" - $File "$SRCDIR\game\shared\hl1\hl1mp_weapon_shotgun.cpp" - $File "$SRCDIR\game\server\hl1\hl1_weapon_crowbar.cpp" - } - } -} diff --git a/game/client/client_hl1mp.vpc b/game/client/client_hl1mp.vpc deleted file mode 100644 index ef5eddf40..000000000 --- a/game/client/client_hl1mp.vpc +++ /dev/null @@ -1,109 +0,0 @@ -//----------------------------------------------------------------------------- -// CLIENT_HL1MP.VPC -// -// Project Script -//----------------------------------------------------------------------------- - -$Macro SRCDIR "..\.." -$Macro GAMENAME "hl1mp" - -$Include "$SRCDIR\game\client\client_base.vpc" - -$Configuration -{ - $Compiler - { - $AdditionalIncludeDirectories "$BASE;.\hl1,.\hl2,.\hl2\elements,$SRCDIR\game\shared\hl1,$SRCDIR\game\shared\hl2" - $PreprocessorDefinitions "$BASE;HL1_CLIENT_DLL;HL1MP_CLIENT_DLL" - } -} - -$Project "Client (HL1MP)" -{ - $Folder "Source Files" - { - -$File "geiger.cpp" - -$File "history_resource.cpp" - -$File "train.cpp" - - $File "c_team_objectiveresource.cpp" - $File "c_team_objectiveresource.h" - $File "hud_chat.cpp" - $File "$SRCDIR\game\shared\predicted_viewmodel.cpp" - $File "$SRCDIR\game\shared\predicted_viewmodel.h" - - $Folder "HL2 DLL" - { - $File "hl2\c_antlion_dust.cpp" - $File "hl2\c_basehelicopter.cpp" - $File "hl2\c_basehelicopter.h" - $File "hl2\c_basehlcombatweapon.h" - $File "hl2\c_corpse.cpp" - $File "hl2\c_corpse.h" - $File "hl2\c_hl2_playerlocaldata.h" - $File "hl2\c_rotorwash.cpp" - $File "$SRCDIR\game\shared\hl2\citadel_effects_shared.h" - $File "$SRCDIR\game\shared\hl2\env_headcrabcanister_shared.h" - $File "hl2\fx_bugbait.cpp" - $File "$SRCDIR\game\shared\hl2\hl2_shareddefs.h" - $File "hl2\hl_in_main.cpp" - $File "hl2\hl_prediction.cpp" - $File "hl2\vgui_rootpanel_hl2.cpp" - } - - $Folder "HL1 DLL" - { - $File "hl1\hl1_c_legacytempents.cpp" - $File "hl1\hl1_c_player.cpp" - $File "hl1\hl1_c_player.h" - $File "hl1\hl1_c_rpg_rocket.cpp" - $File "hl1\hl1_c_weapon__stubs.cpp" - $File "hl1\hl1_clientmode.cpp" - $File "hl1\hl1_clientmode.h" - $File "hl1\hl1_clientscoreboard.cpp" - $File "hl1\hl1_hud_deathnotice.cpp" - $File "hl1\hl1_fx_gauss.cpp" - $File "hl1\hl1_fx_gibs.cpp" - $File "hl1\hl1_fx_impacts.cpp" - $File "hl1\hl1_fx_shelleject.cpp" - $File "$SRCDIR\game\shared\hl1\hl1_gamemovement.cpp" - $File "$SRCDIR\game\shared\hl1\hl1_gamemovement.h" - $File "hl1\hl1_hud_ammo.cpp" - $File "hl1\hl1_hud_battery.cpp" - $File "hl1\hl1_hud_damageindicator.cpp" - $File "hl1\hl1_hud_damagetiles.cpp" - $File "hl1\hl1_hud_flashlight.cpp" - $File "hl1\hl1_hud_geiger.cpp" - $File "hl1\hl1_hud_health.cpp" - $File "hl1\hl1_hud_history_resource.cpp" - $File "hl1\hl1_hud_numbers.cpp" - $File "hl1\hl1_hud_numbers.h" - $File "hl1\hl1_hud_train.cpp" - $File "hl1\hl1_hud_weaponselection.cpp" - $File "$SRCDIR\game\shared\hl1\hl1_basecombatweapon_shared.cpp" - $File "$SRCDIR\game\shared\hl1\hl1_gamerules.cpp" - $File "$SRCDIR\game\shared\hl1\hl1_player_shared.cpp" - $File "$SRCDIR\game\shared\hl1\hl1_player_shared.h" - $File "$SRCDIR\game\shared\hl1\hl1_usermessages.cpp" - $File "$SRCDIR\game\shared\hl1\hl1mp_weapon_357.cpp" - $File "$SRCDIR\game\shared\hl1\hl1mp_weapon_crossbow.cpp" - $File "$SRCDIR\game\shared\hl1\hl1mp_weapon_egon.cpp" - $File "$SRCDIR\game\shared\hl1\hl1mp_weapon_gauss.cpp" - $File "$SRCDIR\game\shared\hl1\hl1mp_weapon_glock.cpp" - $File "$SRCDIR\game\shared\hl1\hl1mp_weapon_handgrenade.cpp" - $File "$SRCDIR\game\shared\hl1\hl1mp_weapon_hornetgun.cpp" - $File "$SRCDIR\game\shared\hl1\hl1mp_weapon_mp5.cpp" - $File "$SRCDIR\game\shared\hl1\hl1mp_weapon_rpg.cpp" - $File "$SRCDIR\game\shared\hl1\hl1mp_weapon_sachel.cpp" - $File "$SRCDIR\game\shared\hl1\hl1mp_weapon_shotgun.cpp" - $File "$SRCDIR\game\server\hl1\hl1_weapon_crowbar.cpp" - } - - $Folder "HL1MP DLL" - { - $File "hl1\c_hl1mp_player.cpp" - $File "$SRCDIR\game\shared\hl1\hl1mp_basecombatweapon_shared.cpp" - $File "$SRCDIR\game\shared\hl1\hl1mp_gamerules.cpp" - } - } -} diff --git a/game/client/client_hl2.vpc b/game/client/client_hl2.vpc deleted file mode 100644 index 112dec032..000000000 --- a/game/client/client_hl2.vpc +++ /dev/null @@ -1,116 +0,0 @@ -//----------------------------------------------------------------------------- -// CLIENT_HL2.VPC -// -// Project Script -//----------------------------------------------------------------------------- - -$Macro SRCDIR "..\.." -$Macro GAMENAME "hl2" [!$SOURCESDK] -$Macro GAMENAME "mod_hl2" [$SOURCESDK] - -$Include "$SRCDIR\game\client\client_base.vpc" - -$Configuration -{ - $Compiler - { - $AdditionalIncludeDirectories ".\hl2;.\hl2\elements;$SRCDIR\game\shared\hl2;$BASE" - $PreprocessorDefinitions "$BASE;HL2_CLIENT_DLL" - } -} - -$Project "Client (HL2)" -{ - $Folder "Source Files" - { - $File "hud_chat.cpp" - $File "c_team_objectiveresource.cpp" - $File "c_team_objectiveresource.h" - - $Folder "HL2 DLL" - { - $File "$SRCDIR\game\shared\hl2\basehlcombatweapon_shared.cpp" - $File "$SRCDIR\game\shared\hl2\achievements_hl2.cpp" - $File "hl2\c_antlion_dust.cpp" - $File "hl2\c_ar2_explosion.cpp" - $File "hl2\c_barnacle.cpp" - $File "hl2\c_barney.cpp" - $File "hl2\c_basehelicopter.cpp" - $File "hl2\c_basehelicopter.h" - $File "hl2\c_basehlcombatweapon.cpp" - $File "hl2\c_basehlcombatweapon.h" - $File "hl2\c_basehlplayer.cpp" - $File "hl2\c_basehlplayer.h" - $File "hl2\c_citadel_effects.cpp" - $File "hl2\c_corpse.cpp" - $File "hl2\c_corpse.h" - $File "hl2\c_env_alyxtemp.cpp" - $File "hl2\c_env_headcrabcanister.cpp" - $File "hl2\c_env_starfield.cpp" - $File "hl2\c_func_tankmortar.cpp" - $File "hl2\c_hl2_playerlocaldata.cpp" - $File "hl2\c_hl2_playerlocaldata.h" - $File "hl2\c_info_teleporter_countdown.cpp" - $File "hl2\c_npc_antlionguard.cpp" - $File "hl2\c_npc_combinegunship.cpp" - $File "hl2\c_npc_manhack.cpp" - $File "hl2\c_npc_rollermine.cpp" - $File "hl2\c_plasma_beam_node.cpp" - $File "hl2\c_prop_combine_ball.cpp" - $File "hl2\c_prop_combine_ball.h" - $File "hl2\c_rotorwash.cpp" - $File "hl2\c_script_intro.cpp" - $File "$SRCDIR\game\shared\script_intro_shared.cpp" - $File "hl2\c_strider.cpp" - $File "hl2\c_te_concussiveexplosion.cpp" - $File "hl2\c_te_flare.cpp" - $File "hl2\c_thumper_dust.cpp" - $File "hl2\c_vehicle_airboat.cpp" - $File "hl2\c_vehicle_cannon.cpp" - $File "hl2\c_vehicle_crane.cpp" - $File "hl2\c_vehicle_crane.h" - $File "hl2\c_vehicle_prisoner_pod.cpp" - $File "hl2\c_weapon__stubs_hl2.cpp" - $File "hl2\c_weapon_crossbow.cpp" - $File "hl2\c_weapon_physcannon.cpp" - $File "hl2\c_weapon_stunstick.cpp" - $File "$SRCDIR\game\shared\hl2\citadel_effects_shared.h" - $File "hl2\clientmode_hlnormal.cpp" - $File "hl2\clientmode_hlnormal.h" - $File "death.cpp" - $File "$SRCDIR\game\shared\hl2\env_headcrabcanister_shared.cpp" - $File "$SRCDIR\game\shared\hl2\env_headcrabcanister_shared.h" - $File "hl2\fx_antlion.cpp" - $File "hl2\fx_bugbait.cpp" - $File "hl2\fx_hl2_impacts.cpp" - $File "hl2\fx_hl2_tracers.cpp" - $File "hl2\hl2_clientmode.cpp" - $File "$SRCDIR\game\shared\hl2\hl2_gamerules.cpp" - $File "$SRCDIR\game\shared\hl2\hl2_gamerules.h" - $File "$SRCDIR\game\shared\hl2\hl2_shareddefs.h" - $File "$SRCDIR\game\shared\hl2\hl2_usermessages.cpp" - $File "$SRCDIR\game\shared\hl2\hl_gamemovement.cpp" - $File "$SRCDIR\game\shared\hl2\hl_gamemovement.h" - $File "hl2\hl_in_main.cpp" - $File "hl2\hl_prediction.cpp" - $File "hl2\hud_ammo.cpp" - $File "hl2\hud_battery.cpp" - $File "hl2\hud_blood.cpp" - $File "hl2\hud_credits.cpp" - $File "hl2\hud_damageindicator.cpp" - $File "hl2\hud_flashlight.cpp" - $File "hl2\hud_health.cpp" - $File "hl2\hud_poisondamageindicator.cpp" - $File "hud_posture.cpp" - $File "hl2\hud_quickinfo.cpp" - $File "hud_squadstatus.cpp" - $File "hl2\hud_suitpower.cpp" - $File "hl2\hud_suitpower.h" - $File "hl2\hud_weaponselection.cpp" - $File "hl2\hud_zoom.cpp" - $File "hl2\shieldproxy.cpp" - $File "hl2\vgui_rootpanel_hl2.cpp" - $File "episodic\c_vort_charge_token.cpp" - } - } -} diff --git a/game/client/client_hl2mp.vpc b/game/client/client_hl2mp.vpc deleted file mode 100644 index 88e18a8ec..000000000 --- a/game/client/client_hl2mp.vpc +++ /dev/null @@ -1,174 +0,0 @@ -//----------------------------------------------------------------------------- -// CLIENT_HL2MP.VPC -// -// Project Script -//----------------------------------------------------------------------------- - -$Macro SRCDIR "..\.." -$Macro GAMENAME "hl2mp" [!$SOURCESDK] -$Macro GAMENAME "mod_hl2mp" [$SOURCESDK] - -$Include "$SRCDIR\game\client\client_base.vpc" - -$Configuration -{ - $Compiler - { - $AdditionalIncludeDirectories "$BASE;hl2mp\ui,.\hl2mp,$SRCDIR\game\shared\hl2mp,.\hl2,.\hl2\elements,$SRCDIR\game\shared\hl2" - $PreprocessorDefinitions "$BASE;HL2MP;HL2_CLIENT_DLL" - } -} - -$Project "Client (HL2MP)" -{ - $Folder "Source Files" - { - -$File "$SRCDIR\game\shared\weapon_parse_default.cpp" - - $File "c_team_objectiveresource.cpp" - $File "c_team_objectiveresource.h" - $File "c_team_train_watcher.cpp" - $File "c_team_train_watcher.h" - $File "hud_voicestatus.cpp" - $File "$SRCDIR\game\shared\predicted_viewmodel.cpp" - $File "$SRCDIR\game\shared\predicted_viewmodel.h" - $File "$SRCDIR\game\shared\teamplay_round_timer.cpp" - $File "$SRCDIR\game\shared\teamplay_round_timer.h" - - $Folder "HL2 DLL" - { - $File "episodic\c_vort_charge_token.cpp" - $File "$SRCDIR\game\shared\hl2\basehlcombatweapon_shared.cpp" - $File "hl2\c_antlion_dust.cpp" - $File "hl2\c_ar2_explosion.cpp" - $File "hl2\c_barnacle.cpp" - $File "hl2\c_barney.cpp" - $File "hl2\c_basehelicopter.cpp" - $File "hl2\c_basehelicopter.h" - $File "hl2\c_basehlcombatweapon.cpp" - $File "hl2\c_basehlcombatweapon.h" - $File "hl2\c_basehlplayer.cpp" - $File "hl2\c_basehlplayer.h" - $File "hl2\c_citadel_effects.cpp" - $File "hl2\c_corpse.cpp" - $File "hl2\c_corpse.h" - $File "hl2\c_env_alyxtemp.cpp" - $File "hl2\c_env_headcrabcanister.cpp" - $File "hl2\c_env_starfield.cpp" - $File "hl2\c_func_tankmortar.cpp" - $File "hl2\c_hl2_playerlocaldata.cpp" - $File "hl2\c_hl2_playerlocaldata.h" - $File "hl2\c_info_teleporter_countdown.cpp" - $File "hl2\c_npc_antlionguard.cpp" - $File "hl2\c_npc_combinegunship.cpp" - $File "hl2\c_npc_manhack.cpp" - $File "hl2\c_npc_rollermine.cpp" - $File "hl2\c_plasma_beam_node.cpp" - $File "hl2\c_prop_combine_ball.cpp" - $File "hl2\c_prop_combine_ball.h" - $File "hl2\c_rotorwash.cpp" - $File "hl2\c_script_intro.cpp" - $File "$SRCDIR\game\shared\script_intro_shared.cpp" - $File "hl2\c_strider.cpp" - $File "hl2\c_te_concussiveexplosion.cpp" - $File "hl2\c_te_flare.cpp" - $File "hl2\c_thumper_dust.cpp" - $File "hl2\c_vehicle_airboat.cpp" - $File "hl2\c_vehicle_cannon.cpp" - $File "hl2\c_vehicle_crane.cpp" - $File "hl2\c_vehicle_crane.h" - $File "hl2\c_vehicle_prisoner_pod.cpp" - $File "hl2\c_weapon__stubs_hl2.cpp" - $File "hl2\c_weapon_crossbow.cpp" - $File "$SRCDIR\game\shared\hl2\citadel_effects_shared.h" - $File "$SRCDIR\game\shared\hl2\env_headcrabcanister_shared.cpp" - $File "$SRCDIR\game\shared\hl2\env_headcrabcanister_shared.h" - $File "hl2\fx_antlion.cpp" - $File "hl2\fx_bugbait.cpp" - $File "hl2\fx_hl2_impacts.cpp" - $File "hl2\fx_hl2_tracers.cpp" - $File "hl2\hl2_clientmode.cpp" - $File "$SRCDIR\game\shared\hl2\hl2_gamerules.cpp" - $File "$SRCDIR\game\shared\hl2\hl2_gamerules.h" - $File "$SRCDIR\game\shared\hl2\hl2_shareddefs.h" - $File "$SRCDIR\game\shared\hl2\hl2_usermessages.cpp" - $File "$SRCDIR\game\shared\hl2\hl_gamemovement.cpp" - $File "$SRCDIR\game\shared\hl2\hl_gamemovement.h" - $File "hl2\hl_in_main.cpp" - $File "hl2\hl_prediction.cpp" - $File "hl2\hud_ammo.cpp" - $File "hl2\hud_battery.cpp" - $File "hl2\hud_blood.cpp" - $File "hl2\hud_credits.cpp" - $File "hl2\hud_damageindicator.cpp" - $File "hl2\hud_flashlight.cpp" - $File "hl2\hud_health.cpp" - $File "hl2\hud_poisondamageindicator.cpp" - $File "hl2\hud_quickinfo.cpp" - $File "hud_squadstatus.cpp" - $File "hl2\hud_suitpower.cpp" - $File "hl2\hud_suitpower.h" - $File "hl2\hud_weaponselection.cpp" - $File "hl2\hud_zoom.cpp" - $File "hl2\shieldproxy.cpp" - $File "hl2\vgui_rootpanel_hl2.cpp" - } - - $Folder "HL2MP" - { - $File "hl2mp\c_hl2mp_player.cpp" - $File "hl2mp\c_hl2mp_player.h" - $File "hl2mp\c_te_hl2mp_shotgun_shot.cpp" - $File "hl2mp\clientmode_hl2mpnormal.cpp" - $File "hl2mp\clientmode_hl2mpnormal.h" - $File "$SRCDIR\game\shared\hl2mp\hl2mp_gamerules.cpp" - $File "$SRCDIR\game\shared\hl2mp\hl2mp_gamerules.h" - $File "$SRCDIR\game\shared\hl2mp\hl2mp_player_shared.cpp" - $File "$SRCDIR\game\shared\hl2mp\hl2mp_player_shared.h" - $File "$SRCDIR\game\shared\hl2mp\hl2mp_weapon_parse.cpp" - $File "$SRCDIR\game\shared\hl2mp\hl2mp_weapon_parse.h" - - $Folder "Weapons" - { - $File "$SRCDIR\game\shared\hl2mp\weapon_357.cpp" - $File "$SRCDIR\game\shared\hl2mp\weapon_ar2.cpp" - $File "$SRCDIR\game\shared\hl2mp\weapon_ar2.h" - $File "$SRCDIR\game\shared\hl2mp\weapon_crossbow.cpp" - $File "$SRCDIR\game\shared\hl2mp\weapon_crowbar.cpp" - $File "$SRCDIR\game\shared\hl2mp\weapon_frag.cpp" - $File "$SRCDIR\game\shared\hl2mp\weapon_hl2mpbase.cpp" - $File "$SRCDIR\game\shared\hl2mp\weapon_hl2mpbase.h" - $File "$SRCDIR\game\shared\hl2mp\weapon_hl2mpbase_machinegun.cpp" - $File "$SRCDIR\game\shared\hl2mp\weapon_hl2mpbase_machinegun.h" - $File "$SRCDIR\game\shared\hl2mp\weapon_hl2mpbasebasebludgeon.cpp" - $File "$SRCDIR\game\shared\hl2mp\weapon_hl2mpbasehlmpcombatweapon.cpp" - $File "$SRCDIR\game\shared\hl2mp\weapon_hl2mpbasehlmpcombatweapon.h" - $File "$SRCDIR\game\shared\hl2mp\weapon_physcannon.cpp" - $File "$SRCDIR\game\shared\hl2mp\weapon_physcannon.h" - $File "$SRCDIR\game\shared\hl2mp\weapon_pistol.cpp" - $File "$SRCDIR\game\shared\hl2mp\weapon_rpg.cpp" - $File "$SRCDIR\game\shared\hl2mp\weapon_rpg.h" - $File "$SRCDIR\game\shared\hl2mp\weapon_shotgun.cpp" - $File "$SRCDIR\game\shared\hl2mp\weapon_slam.cpp" - $File "$SRCDIR\game\shared\hl2mp\weapon_slam.h" - $File "$SRCDIR\game\shared\hl2mp\weapon_smg1.cpp" - $File "$SRCDIR\game\shared\hl2mp\weapon_stunstick.cpp" - } - - $Folder "UI" - { - $File "hl2mp\ui\backgroundpanel.cpp" - $File "hl2mp\ui\backgroundpanel.h" - $File "hl2mp\hl2mp_hud_chat.cpp" - $File "hl2mp\hl2mp_hud_chat.h" - $File "hl2mp\hl2mp_hud_target_id.cpp" - $File "hl2mp\hl2mp_hud_team.cpp" - $File "hl2mp\ui\hl2mpclientscoreboard.cpp" - $File "hl2mp\ui\hl2mpclientscoreboard.h" - $File "hl2mp\ui\hl2mptextwindow.cpp" - $File "hl2mp\ui\hl2mptextwindow.h" - $File "hl2mp\hud_deathnotice.cpp" - } - } - } -} diff --git a/game/client/client_portal.vpc b/game/client/client_portal.vpc deleted file mode 100644 index 78dc9649a..000000000 --- a/game/client/client_portal.vpc +++ /dev/null @@ -1,196 +0,0 @@ -//----------------------------------------------------------------------------- -// CLIENT_PORTAL.VPC -// -// Project Script -//----------------------------------------------------------------------------- - -$Macro SRCDIR "..\.." -$Macro GAMENAME "portal" - -$Include "$SRCDIR\game\client\client_base.vpc" - -$Configuration -{ - $Compiler - { - $AdditionalIncludeDirectories ".\hl2;.\hl2\elements;.\portal;.\portal\vgui;$SRCDIR\game\shared\hl2;$SRCDIR\game\shared\Multiplayer;$SRCDIR\gcsdk\steamextra;$SRCDIR\game\shared\portal;$BASE" - $PreprocessorDefinitions "$BASE;PORTAL;HL2_EPISODIC;HL2_CLIENT_DLL" - } -} - -$Project "Client (Portal)" -{ - $Folder "Source Files" - { - -$File "$SRCDIR\game\shared\weapon_parse_default.cpp" - $File "hud_chat.cpp" - $File "c_team_objectiveresource.cpp" - $File "c_team_objectiveresource.h" - - $Folder "HL2 DLL" - { - $File "episodic\flesh_internal_material_proxy.cpp" - $File "$SRCDIR\game\shared\hl2\basehlcombatweapon_shared.cpp" - $File "hl2\c_antlion_dust.cpp" - $File "hl2\c_ar2_explosion.cpp" - $File "hl2\c_barnacle.cpp" - $File "hl2\c_barney.cpp" - $File "hl2\c_basehelicopter.cpp" - $File "hl2\c_basehelicopter.h" - $File "hl2\c_basehlcombatweapon.cpp" - $File "hl2\c_basehlcombatweapon.h" - $File "hl2\c_basehlplayer.cpp" - $File "hl2\c_basehlplayer.h" - $File "hl2\c_citadel_effects.cpp" - $File "hl2\c_corpse.cpp" - $File "hl2\c_corpse.h" - $File "hl2\c_env_alyxtemp.cpp" - $File "hl2\c_env_headcrabcanister.cpp" - $File "hl2\c_env_starfield.cpp" - $File "hl2\c_func_tankmortar.cpp" - $File "hl2\c_hl2_playerlocaldata.cpp" - $File "hl2\c_hl2_playerlocaldata.h" - $File "hl2\c_info_teleporter_countdown.cpp" - $File "hl2\c_npc_antlionguard.cpp" - $File "hl2\c_npc_combinegunship.cpp" - $File "hl2\c_npc_manhack.cpp" - $File "hl2\c_npc_rollermine.cpp" - $File "hl2\c_plasma_beam_node.cpp" - $File "hl2\c_prop_combine_ball.cpp" - $File "hl2\c_prop_combine_ball.h" - $File "hl2\c_rotorwash.cpp" - $File "hl2\c_script_intro.cpp" - $File "$SRCDIR\game\shared\script_intro_shared.cpp" - $File "hl2\c_strider.cpp" - $File "hl2\c_te_concussiveexplosion.cpp" - $File "hl2\c_te_flare.cpp" - $File "hl2\c_thumper_dust.cpp" - $File "hl2\c_vehicle_airboat.cpp" - $File "hl2\c_vehicle_cannon.cpp" - $File "hl2\c_vehicle_crane.cpp" - $File "hl2\c_vehicle_crane.h" - $File "hl2\c_vehicle_prisoner_pod.cpp" - $File "episodic\c_vort_charge_token.cpp" - $File "hl2\c_weapon_crossbow.cpp" - $File "episodic\c_weapon_hopwire.cpp" - $File "episodic\c_vehicle_jeep_episodic.cpp" - $File "hl2\hud_radar.cpp" - $File "hl2\c_weapon_stunstick.cpp" - $File "$SRCDIR\game\shared\hl2\citadel_effects_shared.h" - $File "hl2\clientmode_hlnormal.h" - $File "death.cpp" - $File "$SRCDIR\game\shared\hl2\env_headcrabcanister_shared.cpp" - $File "$SRCDIR\game\shared\hl2\env_headcrabcanister_shared.h" - $File "hl2\fx_antlion.cpp" - $File "hl2\fx_bugbait.cpp" - $File "hl2\fx_hl2_impacts.cpp" - $File "hl2\fx_hl2_tracers.cpp" - $File "$SRCDIR\game\shared\hl2\hl2_gamerules.cpp" - $File "$SRCDIR\game\shared\hl2\hl2_gamerules.h" - $File "$SRCDIR\game\shared\hl2\hl2_shareddefs.h" - $File "$SRCDIR\game\shared\hl2\hl_gamemovement.cpp" - $File "$SRCDIR\game\shared\hl2\hl_gamemovement.h" - $File "hl2\hl_in_main.cpp" - $File "hl2\hl_prediction.cpp" - $File "hl2\hud_ammo.cpp" - $File "hl2\hud_battery.cpp" - $File "hl2\hud_blood.cpp" - $File "hl2\hud_bonusprogress.cpp" - $File "hl2\hud_credits.cpp" - $File "hl2\hud_damageindicator.cpp" - $File "hl2\hud_flashlight.cpp" - $File "hl2\hud_health.cpp" - $File "hl2\hud_poisondamageindicator.cpp" - $File "hud_squadstatus.cpp" - $File "hl2\hud_suitpower.cpp" - $File "hl2\hud_suitpower.h" - $File "hl2\hud_weaponselection.cpp" - $File "hl2\hud_zoom.cpp" - $File "hl2\shieldproxy.cpp" - $File "$SRCDIR\game\shared\hl2\survival_gamerules.cpp" - $File "hl2\vgui_rootpanel_hl2.cpp" - } - - $Folder "Portal" - { - $File "$SRCDIR\game\shared\portal\achievements_portal.cpp" - $File "portal\c_env_lightraill_endpoint.cpp" - $File "portal\c_env_portal_path_track.cpp" - $File "portal\c_func_liquidportal.cpp" - $File "portal\c_func_liquidportal.h" - $File "portal\c_neurotoxin_countdown.cpp" - $File "portal\c_neurotoxin_countdown.h" - $File "portal\c_npc_portal_turret_floor.cpp" - $File "portal\c_npc_rocket_turret.cpp" - $File "portal\c_portal_player.cpp" - $File "portal\c_portal_player.h" - $File "portal\C_PortalGhostRenderable.cpp" - $File "portal\C_PortalGhostRenderable.h" - $File "portal\c_prop_energy_ball.cpp" - $File "portal\c_prop_portal.cpp" - $File "portal\c_prop_portal.h" - $File "portal\c_prop_portal_stats_display.cpp" - $File "portal\c_prop_portal_stats_display.h" - $File "portal\clientmode_portal.cpp" - $File "portal\clientmode_portal.h" - $File "$SRCDIR\game\shared\portal\env_lightrail_endpoint_shared.h" - $File "$SRCDIR\game\shared\portal\env_portal_path_track_shared.h" - $File "portal\fx_portal.cpp" - $File "portal\hud_quickinfo.cpp" - $File "portal\MaterialProxy_Portal_PickAlphaMask.cpp" - $File "portal\materialproxy_portalstatic.cpp" - $File "$SRCDIR\game\shared\Multiplayer\multiplayer_animstate.cpp" - $File "$SRCDIR\game\shared\Multiplayer\multiplayer_animstate.h" - $File "$SRCDIR\game\shared\portal\portal_collideable_enumerator.cpp" - $File "$SRCDIR\game\shared\portal\portal_collideable_enumerator.h" - $File "portal\portal_credits.cpp" - $File "portal\Portal_DynamicMeshRenderingUtils.cpp" - $File "portal\Portal_DynamicMeshRenderingUtils.h" - $File "$SRCDIR\game\shared\portal\portal_gamemovement.cpp" - $File "$SRCDIR\game\shared\portal\portal_gamerules.cpp" - $File "$SRCDIR\game\shared\portal\portal_gamerules.h" - $File "portal\portal_hud_crosshair.cpp" - $File "portal\portal_hud_crosshair.h" - $File "$SRCDIR\game\shared\portal\portal_player_shared.cpp" - $File "$SRCDIR\game\shared\portal\portal_player_shared.h" - $File "$SRCDIR\game\shared\portal\portal_playeranimstate.cpp" - $File "$SRCDIR\game\shared\portal\portal_playeranimstate.h" - $File "portal\portal_render_targets.cpp" - $File "portal\portal_render_targets.h" - $File "$SRCDIR\game\shared\portal\portal_shareddefs.cpp" - $File "$SRCDIR\game\shared\portal\portal_shareddefs.h" - $File "$SRCDIR\game\shared\portal\portal_usermessages.cpp" - $File "$SRCDIR\game\shared\portal\portal_util_shared.cpp" - $File "$SRCDIR\game\shared\portal\portal_util_shared.h" - $File "$SRCDIR\game\shared\portal\prop_portal_shared.cpp" - $File "$SRCDIR\game\shared\portal\prop_portal_shared.h" - $File "$SRCDIR\game\shared\portal\PortalSimulation.cpp" - $File "$SRCDIR\game\shared\portal\PortalSimulation.h" - $File "$SRCDIR\game\shared\portal\StaticCollisionPolyhedronCache.cpp" - $File "$SRCDIR\game\shared\portal\StaticCollisionPolyhedronCache.h" - $File "portal\PortalRender.cpp" - $File "portal\PortalRender.h" - $File "portal\c_portal_radio.cpp" - $File "portal\portalrenderable_flatbasic.cpp" - $File "portal\portalrenderable_flatbasic.h" - $File "portal\vgui_portal_stats_display_screen.cpp" - $File "portal\vgui_neurotoxin_countdown_screen.cpp" - $File "$SRCDIR\game\shared\portal\portal_weapon_parse.cpp" - - $Folder "Weapons" - { - $File "portal\c_weapon_physcannon.cpp" - $File "portal\c_weapon_portalgun.cpp" - $File "portal\c_weapon_portalgun.h" - $File "portal\c_weapon_stubs_portal.cpp" - $File "$SRCDIR\game\shared\portal\weapon_portalbase.cpp" - $File "$SRCDIR\game\shared\portal\weapon_portalbase.h" - $File "$SRCDIR\game\shared\portal\weapon_portalbasecombatweapon.cpp" - $File "$SRCDIR\game\shared\portal\weapon_portalbasecombatweapon.h" - $File "$SRCDIR\game\shared\portal\weapon_portalgun_shared.cpp" - $File "$SRCDIR\game\shared\portal\weapon_portalgun_shared.h" - } - } - } -} - diff --git a/game/client/client_swarm.vpc b/game/client/client_swarm.vpc new file mode 100644 index 000000000..f6cc737dc --- /dev/null +++ b/game/client/client_swarm.vpc @@ -0,0 +1,1054 @@ +//----------------------------------------------------------------------------- +// CLIENT_SWARM.VPC +// +// Project Script +//----------------------------------------------------------------------------- + +$Macro SRCDIR "..\.." +$Macro GAMENAME "mod_swarm" + +$Include "$SRCDIR\game\client\client_base.vpc" + +$Configuration +{ + $Compiler + { + $AdditionalIncludeDirectories "$BASE;.\hl2;.\swarm;.\swarm\vgui;$SRCDIR\game\client\swarm\gameui;..\statemachine;$SRCDIR\game\shared\multiplayer;$SRCDIR\game\shared\swarm" + $PreprocessorDefinitions "$BASE;INFESTED_PARTICLES;INFESTED_DLL;SWARM_DLL;GAMEUI_EMBEDDED;GAMEUI_EXPORTS" + } +} + +$Project "Client (Swarm)" +{ + $Folder "Source Files" + { + -$File "$SRCDIR\game\shared\weapon_parse_default.cpp" + -$File "hud_animationinfo.cpp" + -$File "hud_crosshair.cpp" + -$File "hud_hintdisplay.cpp" + -$File "hud_weapon.cpp" + -$File "hud_vehicle.cpp" + } + + $Folder "Source Files" + { + $File "voice_menu.cpp" + + $Folder "From HL2" + { + $File "hl2\c_antlion_dust.cpp" + $File "hl2\c_ar2_explosion.cpp" + $File "hl2\c_basehelicopter.cpp" + $File "hl2\c_basehelicopter.h" + $File "hl2\c_npc_combinegunship.cpp" + $File "hl2\c_rotorwash.cpp" + } + + $Folder "Swarm" + { + $Folder "GameUI - Embedded" + { + $Folder "Base GameUI" + { + $Folder "Headers" + { + $File "swarm\gameui\backgroundmenubutton.h" \ + "swarm\gameui\basepanel.h" \ + "swarm\gameui\basesavegamedialog.h" \ + "swarm\gameui\bitmapimagepanel.h" \ + "swarm\gameui\commandcheckbutton.h" \ + "swarm\gameui\contentcontroldialog.h" \ + "swarm\gameui\createmultiplayergamebotpage.h" \ + "swarm\gameui\createmultiplayergamedialog.h" \ + "swarm\gameui\createmultiplayergamegameplaypage.h" \ + "swarm\gameui\createmultiplayergameserverpage.h" \ + "swarm\gameui\customtabexplanationdialog.h" \ + "swarm\gameui\cvarnegatecheckbutton.h" \ + "swarm\gameui\cvarslider.h" \ + "swarm\gameui\cvartextentry.h" \ + "swarm\gameui\cvartogglecheckbutton.h" \ + "swarm\gameui\engineinterface.h" \ + "swarm\gameui\gameconsole.h" \ + "swarm\gameui\gameconsoledialog.h" \ + "swarm\gameui\gameui_interface.h" \ + "swarm\gameui\gameui_util.h" \ + "swarm\gameui\keytogglecheckbutton.h" \ + "swarm\gameui\labeledcommandcombobox.h" \ + "swarm\gameui\loadingdialog.h" \ + "swarm\gameui\loadingtippanel.h" \ + "swarm\gameui\modinfo.h" \ + "swarm\gameui\mousemessageforwardingpanel.h" \ + "swarm\gameui\multiplayeradvanceddialog.h" \ + "swarm\gameui\optionsdialog.h" \ + "swarm\gameui\optionssubaudio.h" \ + "swarm\gameui\optionssubdifficulty.h" \ + "swarm\gameui\optionssubgame.h" \ + "swarm\gameui\optionssubkeyboard.h" \ + "swarm\gameui\optionssubmouse.h" \ + "swarm\gameui\optionssubmultiplayer.h" \ + "swarm\gameui\optionssubportal.h" \ + "swarm\gameui\optionssubvideo.h" \ + "swarm\gameui\optionssubvoice.h" \ + "swarm\gameui\panellistpanel.h" \ + "swarm\gameui\playerlistdialog.h" \ + "swarm\gameui\rungameengine.h" \ + "swarm\gameui\scriptobject.h" \ + "swarm\gameui\sys_utils.h" \ + "swarm\gameui\textentrybox.h" \ + "swarm\gameui\urlbutton.h" \ + "swarm\gameui\vcontrolslistpanel.h" \ + "swarm\gameui\vguisystemmoduleloader.h" + } + $File "swarm\gameui\backgroundmenubutton.cpp" \ + "swarm\gameui\basesavegamedialog.cpp" \ + "swarm\gameui\bitmapimagepanel.cpp" \ + "swarm\gameui\commandcheckbutton.cpp" \ + "swarm\gameui\contentcontroldialog.cpp" \ + "swarm\gameui\createmultiplayergamebotpage.cpp" \ + "swarm\gameui\createmultiplayergamedialog.cpp" \ + "swarm\gameui\createmultiplayergamegameplaypage.cpp" \ + "swarm\gameui\createmultiplayergameserverpage.cpp" \ + "swarm\gameui\customtabexplanationdialog.cpp" \ + "swarm\gameui\cvarnegatecheckbutton.cpp" \ + "swarm\gameui\cvarslider.cpp" \ + "swarm\gameui\cvartextentry.cpp" \ + "swarm\gameui\cvartogglecheckbutton.cpp" \ + "swarm\gameui\gameconsole.cpp" \ + "swarm\gameui\gameconsoledialog.cpp" \ + "swarm\gameui\gameui_interface.cpp" \ + "swarm\gameui\gameui_util.cpp" \ + "swarm\gameui\keytogglecheckbutton.cpp" \ + "swarm\gameui\labeledcommandcombobox.cpp" \ + "swarm\gameui\loadingdialog.cpp" \ + "swarm\gameui\loadingtippanel.cpp" \ + "swarm\gameui\logofile.cpp" \ + "swarm\gameui\modinfo.cpp" \ + "swarm\gameui\mousemessageforwardingpanel.cpp" \ + "swarm\gameui\multiplayeradvanceddialog.cpp" \ + "swarm\gameui\optionsdialog.cpp" \ + "swarm\gameui\optionssubaudio.cpp" \ + "swarm\gameui\optionssubdifficulty.cpp" \ + "swarm\gameui\optionssubgame.cpp" \ + "swarm\gameui\optionssubkeyboard.cpp" \ + "swarm\gameui\optionssubmouse.cpp" \ + "swarm\gameui\optionssubmultiplayer.cpp" \ + "swarm\gameui\optionssubportal.cpp" \ + "swarm\gameui\optionssubvideo.cpp" \ + "swarm\gameui\optionssubvoice.cpp" \ + "swarm\gameui\panellistpanel.cpp" \ + "swarm\gameui\playerlistdialog.cpp" \ + "swarm\gameui\rungameengine.cpp" \ + "swarm\gameui\scriptobject.cpp" \ + "swarm\gameui\sys_utils.cpp" \ + "swarm\gameui\textentrybox.cpp" \ + "swarm\gameui\urlbutton.cpp" \ + "swarm\gameui\vcontrolslistpanel.cpp" \ + "swarm\gameui\vguisystemmoduleloader.cpp" + { + $Configuration + { + $Compiler + { + $Create/UsePrecompiledHeader "Not Using Precompiled Headers" + } + } + } + } + + $Folder "External Stuff" + { + $File "$SRCDIR\common\language.cpp" + { + $Configuration + { + $Compiler + { + $Create/UsePrecompiledHeader "Not Using Precompiled Headers" + } + } + } + } + + $Folder "Swarm GameUI" + { + $Folder "Headers" + { + $File "swarm\gameui\swarm\basemodframe.h" \ + "swarm\gameui\swarm\basemodpanel.h" \ + "swarm\gameui\swarm\basemodui.h" \ + "swarm\gameui\swarm\gamemodes.h" \ + "swarm\gameui\swarm\uiavatarimage.h" \ + "swarm\gameui\swarm\uigamedata.h" \ + "swarm\gameui\swarm\vachievements.h" \ + "swarm\gameui\swarm\vaddonassociation.h" \ + "swarm\gameui\swarm\vaddons.h" \ + "swarm\gameui\swarm\vattractscreen.h" \ + "swarm\gameui\swarm\vaudio.h" \ + "swarm\gameui\swarm\vaudiovideo.h" \ + "swarm\gameui\swarm\vcloud.h" \ + "swarm\gameui\swarm\vcontrolleroptions.h" \ + "swarm\gameui\swarm\vcontrolleroptionsbuttons.h" \ + "swarm\gameui\swarm\vcontrolleroptionssticks.h" \ + "swarm\gameui\swarm\vcustomcampaigns.h" \ + "swarm\gameui\swarm\vdownloadcampaign.h" \ + "swarm\gameui\swarm\vdownloads.h" \ + "swarm\gameui\swarm\vdropdownmenu.h" \ + "swarm\gameui\swarm\vflyoutmenu.h" \ + "swarm\gameui\swarm\vfooterpanel.h" \ + "swarm\gameui\swarm\vfoundgames.h" \ + "swarm\gameui\swarm\vfoundgroupgames.h" \ + "swarm\gameui\swarm\vfoundpublicgames.h" \ + "swarm\gameui\swarm\vgamelobby.h" \ + "swarm\gameui\swarm\vgamelobbychat.h" \ + "swarm\gameui\swarm\vgameoptions.h" \ + "swarm\gameui\swarm\vgamesettings.h" \ + "swarm\gameui\swarm\vgenericconfirmation.h" \ + "swarm\gameui\swarm\vgenericpanellist.h" \ + "swarm\gameui\swarm\vgenericwaitscreen.h" \ + "swarm\gameui\swarm\vgetlegacydata.h" \ + "swarm\gameui\swarm\vhybridbutton.h" \ + "swarm\gameui\swarm\vingamechapterselect.h" \ + "swarm\gameui\swarm\vingamedifficultyselect.h" \ + "swarm\gameui\swarm\vingamekickplayerlist.h" \ + "swarm\gameui\swarm\vingamemainmenu.h" \ + "swarm\gameui\swarm\vjukebox.h" \ + "swarm\gameui\swarm\vkeyboard.h" \ + "swarm\gameui\swarm\vkeyboardmouse.h" \ + "swarm\gameui\swarm\vleaderboard.h" \ + "swarm\gameui\swarm\vloadingprogress.h" \ + "swarm\gameui\swarm\vmainmenu.h" \ + "swarm\gameui\swarm\vmultiplayer.h" \ + "swarm\gameui\swarm\voptions.h" \ + "swarm\gameui\swarm\vpasswordentry.h" \ + "swarm\gameui\swarm\vquickjoin.h" \ + "swarm\gameui\swarm\vquickjoingroups.h" \ + "swarm\gameui\swarm\vsignindialog.h" \ + "swarm\gameui\swarm\vslidercontrol.h" \ + "swarm\gameui\swarm\vspinnercontrol.h" \ + "swarm\gameui\swarm\vsteamcloudconfirmation.h" \ + "swarm\gameui\swarm\vtransitionscreen.h" \ + "swarm\gameui\swarm\vvideo.h" \ + "swarm\gameui\swarm\vvoteoptions.h" + } + $Folder "Win32" + { + $File "swarm\gameui\swarm\uiavatarimage.cpp" \ + "swarm\gameui\swarm\vaddonassociation.cpp" \ + "swarm\gameui\swarm\vaddons.cpp" \ + "swarm\gameui\swarm\vcloud.cpp" \ + "swarm\gameui\swarm\vcustomcampaigns.cpp" \ + "swarm\gameui\swarm\vdownloadcampaign.cpp" \ + "swarm\gameui\swarm\vdownloads.cpp" \ + "swarm\gameui\swarm\vgetlegacydata.cpp" \ + "swarm\gameui\swarm\vjukebox.cpp" \ + "swarm\gameui\swarm\vkeyboard.cpp" \ + "swarm\gameui\swarm\vkeyboardmouse.cpp" \ + "swarm\gameui\swarm\vsteamcloudconfirmation.cpp" + { + $Configuration + { + $Compiler + { + $Create/UsePrecompiledHeader "Not Using Precompiled Headers" + } + } + } + } + $File "swarm\gameui\swarm\basemodframe.cpp" \ + "swarm\gameui\swarm\basemodpanel.cpp" \ + "swarm\gameui\swarm\gamemodes.cpp" \ + "swarm\gameui\swarm\uigamedata.cpp" \ + "swarm\gameui\swarm\uigamedata_invite.cpp" \ + "swarm\gameui\swarm\uigamedata_storage.cpp" \ + "swarm\gameui\swarm\vachievements.cpp" \ + "swarm\gameui\swarm\vattractscreen.cpp" \ + "swarm\gameui\swarm\vaudio.cpp" \ + "swarm\gameui\swarm\vaudiovideo.cpp" \ + "swarm\gameui\swarm\vcontrolleroptions.cpp" \ + "swarm\gameui\swarm\vcontrolleroptionsbuttons.cpp" \ + "swarm\gameui\swarm\vcontrolleroptionssticks.cpp" \ + "swarm\gameui\swarm\vdropdownmenu.cpp" \ + "swarm\gameui\swarm\vflyoutmenu.cpp" \ + "swarm\gameui\swarm\vfooterpanel.cpp" \ + "swarm\gameui\swarm\vfoundgames.cpp" \ + "swarm\gameui\swarm\vfoundgroupgames.cpp" \ + "swarm\gameui\swarm\vfoundpublicgames.cpp" \ + "swarm\gameui\swarm\vgamelobby.cpp" \ + "swarm\gameui\swarm\vgamelobbychat.cpp" \ + "swarm\gameui\swarm\vgameoptions.cpp" \ + "swarm\gameui\swarm\vgamesettings.cpp" \ + "swarm\gameui\swarm\vgenericconfirmation.cpp" \ + "swarm\gameui\swarm\vgenericpanellist.cpp" \ + "swarm\gameui\swarm\vgenericwaitscreen.cpp" \ + "swarm\gameui\swarm\vhybridbutton.cpp" \ + "swarm\gameui\swarm\vingamechapterselect.cpp" \ + "swarm\gameui\swarm\vingamedifficultyselect.cpp" \ + "swarm\gameui\swarm\vingamekickplayerlist.cpp" \ + "swarm\gameui\swarm\vingamemainmenu.cpp" \ + "swarm\gameui\swarm\vleaderboard.cpp" \ + "swarm\gameui\swarm\vloadingprogress.cpp" \ + "swarm\gameui\swarm\vmainmenu.cpp" \ + "swarm\gameui\swarm\vmenubackground.cpp" \ + "swarm\gameui\swarm\vmultiplayer.cpp" \ + "swarm\gameui\swarm\voptions.cpp" \ + "swarm\gameui\swarm\vpasswordentry.cpp" \ + "swarm\gameui\swarm\vquickjoin.cpp" \ + "swarm\gameui\swarm\vquickjoingroups.cpp" \ + "swarm\gameui\swarm\vsignindialog.cpp" \ + "swarm\gameui\swarm\vslidercontrol.cpp" \ + "swarm\gameui\swarm\vspinnercontrol.cpp" \ + "swarm\gameui\swarm\vtransitionscreen.cpp" \ + "swarm\gameui\swarm\vvideo.cpp" \ + "swarm\gameui\swarm\vvoteoptions.cpp" + { + $Configuration + { + $Compiler + { + $Create/UsePrecompiledHeader "Not Using Precompiled Headers" + } + } + } + } + } + + $File "swarm\asw_bone_merge.cpp" + $File "swarm\asw_bone_merge.h" + $File "swarm\c_asw_steamstats.cpp" + $File "swarm\c_asw_steamstats.h" + + $File "swarm\asw_briefing.cpp" + $File "swarm\asw_briefing.h" + $File "swarm\ibriefing.h" + $File "swarm\asw_client_entities.cpp" + $File "swarm\asw_client_entities.h" + $File "swarm\asw_fx_impacts.cpp" + $File "swarm\asw_in_camera.cpp" + $File "swarm\asw_in_main.cpp" + $File "swarm\asw_in_mouse.cpp" + $File "swarm\asw_input.cpp" + $File "swarm\asw_input.h" + $File "swarm\asw_marineandobjectenumerator.cpp" + $File "swarm\asw_marineandobjectenumerator.h" + $File "swarm\asw_medal_store.cpp" + $File "swarm\asw_medal_store.h" + $File "swarm\asw_prediction.cpp" + $File "swarm\asw_room_thumbnails.cpp" + $File "swarm\asw_video.cpp" + $File "swarm\asw_video.h" + $File "swarm\asw_view_scene.cpp" + $File "swarm\asw_view_scene.h" + $File "swarm\clientmode_asw.cpp" + $File "swarm\clientmode_asw.h" + $File "swarm\c_asw_alien.cpp" + $File "swarm\c_asw_alien.h" + $File "swarm\c_asw_ammo.cpp" + $File "swarm\c_asw_ammo.h" + $File "swarm\c_asw_ammo_drop.cpp" + $File "swarm\c_asw_ammo_drop.h" + $File "swarm\c_asw_boomer.cpp" + $File "swarm\c_asw_boomer.h" + $File "swarm\c_asw_button_area.cpp" + $File "swarm\c_asw_button_area.h" + $File "swarm\c_asw_buzzer.cpp" + $File "swarm\c_asw_buzzer.h" + $File "swarm\c_asw_camera_volume.cpp" + $File "swarm\c_asw_camera_volume.h" + $File "swarm\c_asw_campaign_save.cpp" + $File "swarm\c_asw_campaign_save.h" + $File "swarm\c_asw_concommands.cpp" + $File "swarm\c_asw_client_corpse.cpp" + $File "swarm\c_asw_client_corpse.h" + $File "swarm\c_asw_clientragdoll.cpp" + $File "swarm\c_asw_clientragdoll.h" + $File "swarm\c_asw_computer_area.cpp" + $File "swarm\c_asw_computer_area.h" + $File "swarm\c_asw_debrief_stats.cpp" + $File "swarm\c_asw_debrief_stats.h" + $File "swarm\c_asw_door.cpp" + $File "swarm\c_asw_door.h" + $File "swarm\c_asw_door_area.cpp" + $File "swarm\c_asw_door_area.h" + $File "swarm\c_asw_drone_advanced.cpp" + $File "swarm\c_asw_drone_advanced.h" + $File "swarm\c_asw_dummy_vehicle.cpp" + $File "swarm\c_asw_dummy_vehicle.h" + $File "swarm\c_asw_dynamic_light.cpp" + $File "swarm\c_asw_dynamic_light.h" + $File "swarm\c_asw_egg.cpp" + $File "swarm\c_asw_egg.h" + $File "swarm\c_asw_entity_dissolve.cpp" + $File "swarm\c_asw_entity_dissolve.h" + $File "swarm\c_asw_extinguisher_projectile.cpp" + $File "swarm\c_asw_extinguisher_projectile.h" + $File "swarm\c_asw_firewall_piece.cpp" + $File "swarm\c_asw_firewall_piece.h" + $File "swarm\c_asw_flamer_projectile.cpp" + $File "swarm\c_asw_flamer_projectile.h" + $File "swarm\c_asw_flare_projectile.cpp" + $File "swarm\c_asw_flare_projectile.h" + $File "swarm\c_asw_fourwheelvehiclephysics.cpp" + $File "swarm\c_asw_fourwheelvehiclephysics.h" + $File "swarm\c_asw_fire.cpp" + $File "swarm\c_asw_fire.h" + $File "swarm\c_asw_fx.cpp" + $File "swarm\c_asw_fx.h" + $File "swarm\c_asw_fx_proxy.cpp" + $File "swarm\c_asw_aoegrenade_projectile.cpp" + $File "swarm\c_asw_aoegrenade_projectile.h" + $File "swarm\c_asw_buffgrenade_projectile.cpp" + $File "swarm\c_asw_buffgrenade_projectile.h" + $File "swarm\c_asw_game_resource.cpp" + $File "swarm\c_asw_game_resource.h" + $File "swarm\c_asw_generic_emitter.cpp" + $File "swarm\c_asw_generic_emitter.h" + $File "swarm\c_asw_generic_emitter_entity.cpp" + $File "swarm\c_asw_generic_emitter_entity.h" + $File "swarm\c_asw_grub.cpp" + $File "swarm\c_asw_grub.h" + $File "swarm\c_asw_gun_smoke_emitter.cpp" + $File "swarm\c_asw_gun_smoke_emitter.h" + $File "swarm\c_asw_hack.cpp" + $File "swarm\c_asw_hack.h" + $File "swarm\c_asw_hack_computer.cpp" + $File "swarm\c_asw_hack_computer.h" + $File "swarm\c_asw_hack_wire_tile.cpp" + $File "swarm\c_asw_hack_wire_tile.h" + $File "swarm\c_asw_jeep.cpp" + $File "swarm\c_asw_jeep.h" + $File "swarm\c_asw_jeep_clientside.cpp" + $File "swarm\c_asw_jeep_clientside.h" + $File "swarm\c_asw_jukebox.cpp" + $File "swarm\c_asw_jukebox.h" + $File "swarm\c_asw_laser_mine.cpp" + $File "swarm\c_asw_laser_mine.h" + $File "swarm\c_asw_lesson.cpp" + $File "swarm\c_asw_level_exploder.cpp" + $File "swarm\c_asw_level_exploder.h" + $File "swarm\c_asw_marine.cpp" + $File "swarm\c_asw_marine.h" + $File "swarm\c_asw_marine_resource.cpp" + $File "swarm\c_asw_marine_resource.h" + $File "swarm\c_asw_marine_speech.cpp" + $File "swarm\c_asw_marker.cpp" + $File "swarm\c_asw_marker.h" + $File "swarm\c_asw_mesh_emitter_entity.cpp" + $File "swarm\c_asw_mesh_emitter_entity.h" + $File "swarm\c_asw_mine.cpp" + $File "swarm\c_asw_mine.h" + $File "swarm\c_asw_objective.cpp" + $File "swarm\c_asw_objective.h" + $File "swarm\c_asw_objective_countdown.cpp" + $File "swarm\c_asw_objective_countdown.h" + $File "swarm\c_asw_objective_kill_aliens.cpp" + $File "swarm\c_asw_objective_kill_aliens.h" + $File "swarm\c_asw_objective_kill_eggs.cpp" + $File "swarm\c_asw_objective_kill_eggs.h" + $File "swarm\c_asw_objective_kill_goo.cpp" + $File "swarm\c_asw_objective_kill_goo.h" + $File "swarm\c_asw_objective_kill_queen.cpp" + $File "swarm\c_asw_objective_kill_queen.h" + $File "swarm\c_asw_order_arrow.cpp" + $File "swarm\c_asw_order_arrow.h" + $File "swarm\c_asw_parasite.cpp" + $File "swarm\c_asw_parasite.h" + $File "swarm\c_asw_pickup.cpp" + $File "swarm\c_asw_pickup.h" + $File "swarm\c_asw_pickup_equipment.cpp" + $File "swarm\c_asw_pickup_equipment.h" + $File "swarm\c_asw_pickup_money.cpp" + $File "swarm\c_asw_pickup_money.h" + $File "swarm\c_asw_pickup_weapon.cpp" + $File "swarm\c_asw_pickup_weapon.h" + $File "swarm\c_asw_player.cpp" + $File "swarm\c_asw_player.h" + $File "swarm\c_asw_playerlocaldata.cpp" + $File "swarm\c_asw_playerlocaldata.h" + $File "swarm\c_asw_point_camera.cpp" + $File "swarm\c_asw_point_camera.h" + $File "swarm\c_asw_prop_physics.cpp" + $File "swarm\c_asw_prop_physics.h" + $File "swarm\c_asw_physics_prop_statue.cpp" + $File "swarm\c_asw_physics_prop_statue.h" + + $File "swarm\c_asw_queen.cpp" + $File "swarm\c_asw_queen.h" + $File "swarm\c_asw_queen_spit.cpp" + $File "swarm\c_asw_queen_spit.h" + $File "swarm\c_asw_railgun_beam.cpp" + $File "swarm\c_asw_railgun_beam.h" + $File "swarm\c_asw_ranger.cpp" + $File "swarm\c_asw_ranger.h" + $File "swarm\c_asw_render_targets.cpp" + $File "swarm\c_asw_render_targets.h" + $File "swarm\c_asw_rocket.cpp" + $File "swarm\c_asw_rocket.h" + $File "swarm\c_asw_scanner_info.cpp" + $File "swarm\c_asw_scanner_info.h" + $File "swarm\c_asw_scanner_noise.cpp" + $File "swarm\c_asw_scanner_noise.h" + $File "swarm\c_asw_sentry_base.cpp" + $File "swarm\c_asw_sentry_base.h" + $File "swarm\c_asw_sentry_top.cpp" + $File "swarm\c_asw_sentry_top.h" + $File "swarm\c_asw_sentry_top_flamer.cpp" + $File "swarm\c_asw_sentry_top_flamer.h" + $File "swarm\c_asw_sentry_top_icer.cpp" + $File "swarm\c_asw_sentry_top_icer.h" + $File "swarm\c_asw_shaman.cpp" + $File "swarm\c_asw_shaman.h" + $File "swarm\c_asw_shieldbug.cpp" + $File "swarm\c_asw_shieldbug.h" + $File "swarm\c_asw_simple_alien.cpp" + $File "swarm\c_asw_simple_alien.h" + $File "swarm\c_asw_simple_drone.cpp" + $File "swarm\c_asw_simple_drone.h" + $File "swarm\c_asw_snow_emitter.cpp" + $File "swarm\c_asw_snow_emitter.h" + $File "swarm\c_asw_snow_volume.cpp" + $File "swarm\c_asw_snow_volume.h" + $File "swarm\c_asw_t75.cpp" + $File "swarm\c_asw_t75.h" + $File "swarm\c_asw_tesla_trap.cpp" + $File "swarm\c_asw_tesla_trap.h" + $File "swarm\c_asw_trail_beam.cpp" + $File "swarm\c_asw_trail_beam.h" + $File "swarm\c_asw_use_area.cpp" + $File "swarm\c_asw_use_area.h" + $File "swarm\c_asw_voting_missions.cpp" + $File "swarm\c_asw_voting_missions.h" + $File "swarm\c_asw_voting_mission_chooser_source.cpp" + $File "swarm\c_asw_voting_mission_chooser_source.h" + $File "swarm\c_asw_vphysics_npc.cpp" + $File "swarm\c_asw_vphysics_npc.h" + $File "swarm\c_asw_weapon.cpp" + $File "swarm\c_asw_weapon.h" + $File "swarm\c_asw_weapon_rifle.cpp" + $File "swarm\c_asw_weapon_rifle.h" + $File "swarm\iasw_client_aim_target.h" + $File "swarm\iasw_client_usable_entity.h" + $File "swarm\iasw_client_vehicle.h" + $File "swarm\vgui_rootpanel_asw.cpp" + + $Folder "vgui" + { + $file "swarm\vgui\asw_vgui_music_importer.cpp" + $file "swarm\vgui\asw_vgui_music_importer.h" + $file "swarm\vgui\mission_complete_message.cpp" + $file "swarm\vgui\mission_complete_message.h" + $file "swarm\vgui\nb_promotion_panel.cpp" + $file "swarm\vgui\nb_promotion_panel.h" + $file "swarm\vgui\nb_vote_panel.cpp" + $file "swarm\vgui\nb_vote_panel.h" + $file "swarm\vgui\polygonbutton.cpp" + $file "swarm\vgui\polygonbutton.h" + $file "swarm\vgui\radialmenu.cpp" + $file "swarm\vgui\radialmenu.h" + + $file "swarm\vgui\asw_build_map_frame.cpp" + $file "swarm\vgui\asw_build_map_frame.h" + $File "swarm\vgui\asw_circularprogressbar.cpp" + $File "swarm\vgui\asw_circularprogressbar.h" + $file "swarm\vgui\asw_hud_floating_number.cpp" + $file "swarm\vgui\asw_hud_floating_number.h" + $file "swarm\vgui\asw_hudelement.cpp" + $file "swarm\vgui\asw_hudelement.h" + $file "swarm\vgui\asw_hud_3dmarinenames.cpp" + $file "swarm\vgui\asw_hud_3dmarinenames.h" + $file "swarm\vgui\asw_hud_ammo.cpp" + $file "swarm\vgui\asw_hud_chat.cpp" + $file "swarm\vgui\asw_hud_chat.h" + $file "swarm\vgui\asw_hud_crosshair.cpp" + $file "swarm\vgui\asw_hud_crosshair.h" + $file "swarm\vgui\asw_hud_damageindicator.cpp" + $file "swarm\vgui\asw_hud_emotes.cpp" + $file "swarm\vgui\asw_hud_health.cpp" + $file "swarm\vgui\asw_hud_health_cross.cpp" + $file "swarm\vgui\asw_hud_health_cross.h" + $file "swarm\vgui\asw_hud_holdout.cpp" + $file "swarm\vgui\asw_hud_holdout.h" + $file "swarm\vgui\asw_hud_marine_portrait.cpp" + $file "swarm\vgui\asw_hud_marine_portrait.h" + $file "swarm\vgui\asw_hud_master.cpp" + $file "swarm\vgui\asw_hud_master.h" + $file "swarm\vgui\asw_hud_minimap.cpp" + $file "swarm\vgui\asw_hud_minimap.h" + $file "swarm\vgui\asw_hud_money.cpp" + $file "swarm\vgui\asw_hud_objective.cpp" + $file "swarm\vgui\asw_hud_objective.h" + $file "swarm\vgui\asw_hud_overlay_messages.cpp" + $file "swarm\vgui\asw_hud_portraits.cpp" + $file "swarm\vgui\asw_hud_portraits.h" + $file "swarm\vgui\asw_hud_powerups.cpp" + $file "swarm\vgui\asw_hud_powerups.h" + $file "swarm\vgui\asw_hud_squad_hotbar.cpp" + $file "swarm\vgui\asw_hud_squad_hotbar.h" + $file "swarm\vgui\asw_hud_use_area.cpp" + $file "swarm\vgui\asw_hud_use_area.h" + $file "swarm\vgui\asw_hud_use_icon.cpp" + $file "swarm\vgui\asw_hud_use_icon.h" + $file "swarm\vgui\asw_hud_voice.cpp" + $file "swarm\vgui\asw_hud_weapons.cpp" + $file "swarm\vgui\asw_loading_panel.cpp" + $file "swarm\vgui\asw_loading_panel.h" + $file "swarm\vgui\asw_logo_panel.cpp" + $file "swarm\vgui\asw_logo_panel.h" + $file "swarm\vgui\asw_model_panel.cpp" + $file "swarm\vgui\asw_model_panel.h" + $file "swarm\vgui\asw_vgui_ammo_list.cpp" + $file "swarm\vgui\asw_vgui_ammo_list.h" + $file "swarm\vgui\asw_vgui_computer_camera.cpp" + $file "swarm\vgui\asw_vgui_computer_camera.h" + $file "swarm\vgui\asw_vgui_computer_download_docs.cpp" + $file "swarm\vgui\asw_vgui_computer_download_docs.h" + $file "swarm\vgui\asw_vgui_computer_frame.cpp" + $file "swarm\vgui\asw_vgui_computer_frame.h" + $file "swarm\vgui\asw_vgui_computer_mail.cpp" + $file "swarm\vgui\asw_vgui_computer_mail.h" + $file "swarm\vgui\asw_vgui_computer_menu.cpp" + $file "swarm\vgui\asw_vgui_computer_menu.h" + $file "swarm\vgui\asw_vgui_computer_news.cpp" + $file "swarm\vgui\asw_vgui_computer_news.h" + $file "swarm\vgui\asw_vgui_computer_plant.cpp" + $file "swarm\vgui\asw_vgui_computer_plant.h" + $file "swarm\vgui\asw_vgui_computer_splash.cpp" + $file "swarm\vgui\asw_vgui_computer_splash.h" + $file "swarm\vgui\asw_vgui_computer_stocks.cpp" + $file "swarm\vgui\asw_vgui_computer_stocks.h" + $file "swarm\vgui\asw_vgui_computer_tumbler_hack.cpp" + $file "swarm\vgui\asw_vgui_computer_tumbler_hack.h" + $file "swarm\vgui\asw_vgui_computer_weather.cpp" + $file "swarm\vgui\asw_vgui_computer_weather.h" + $file "swarm\vgui\asw_vgui_countdown.cpp" + $file "swarm\vgui\asw_vgui_countdown.h" + $file "swarm\vgui\asw_vgui_door_tooltip.cpp" + $file "swarm\vgui\asw_vgui_door_tooltip.h" + $file "swarm\vgui\asw_vgui_edit_emitter.cpp" + $file "swarm\vgui\asw_vgui_edit_emitter.h" + $file "swarm\vgui\asw_vgui_edit_emitter_dialogs.cpp" + $file "swarm\vgui\asw_vgui_edit_emitter_dialogs.h" + $file "swarm\vgui\asw_vgui_fast_reload.cpp" + $file "swarm\vgui\asw_vgui_fast_reload.h" + $file "swarm\vgui\asw_vgui_frame.cpp" + $file "swarm\vgui\asw_vgui_frame.h" + $file "swarm\vgui\asw_vgui_hack_wire_tile.cpp" + $file "swarm\vgui\asw_vgui_hack_wire_tile.h" + $file "swarm\vgui\asw_vgui_info_message.cpp" + $file "swarm\vgui\asw_vgui_info_message.h" + $file "swarm\vgui\asw_vgui_ingame_panel.cpp" + $file "swarm\vgui\asw_vgui_ingame_panel.h" + $file "swarm\vgui\asw_vgui_manipulator.cpp" + $file "swarm\vgui\asw_vgui_manipulator.h" + $file "swarm\vgui\asw_vgui_marine_ammo_report.cpp" + $file "swarm\vgui\asw_vgui_marine_ammo_report.h" + $file "swarm\vgui\asw_vgui_queen_health.cpp" + $file "swarm\vgui\asw_vgui_queen_health.h" + $file "swarm\vgui\asw_vgui_skip_intro.cpp" + $file "swarm\vgui\asw_vgui_skip_intro.h" + $file "swarm\vgui\asw_vgui_stylin_cam.cpp" + $file "swarm\vgui\asw_vgui_stylin_cam.h" + $file "swarm\vgui\briefingdialog.cpp" + $file "swarm\vgui\briefingdialog.h" + $file "swarm\vgui\briefingframe.cpp" + $file "swarm\vgui\briefingframe.h" + $file "swarm\vgui\briefingimagepanel.cpp" + $file "swarm\vgui\briefingimagepanel.h" + $file "swarm\vgui\briefingpropertysheet.cpp" + $file "swarm\vgui\briefingpropertysheet.h" + $file "swarm\vgui\briefingtooltip.cpp" + $file "swarm\vgui\briefingtooltip.h" + $file "swarm\vgui\cainmailpanel.cpp" + $file "swarm\vgui\cainmailpanel.h" + $file "swarm\vgui\campaignframe.cpp" + $file "swarm\vgui\campaignframe.h" + $file "swarm\vgui\campaignmaplocation.cpp" + $file "swarm\vgui\campaignmaplocation.h" + $file "swarm\vgui\campaignmapsearchlights.cpp" + $file "swarm\vgui\campaignmapsearchlights.h" + $file "swarm\vgui\campaignpanel.cpp" + $file "swarm\vgui\campaignpanel.h" + $file "swarm\vgui\chatechopanel.cpp" + $file "swarm\vgui\chatechopanel.h" + $file "swarm\vgui\creditspanel.cpp" + $file "swarm\vgui\creditspanel.h" + $File "swarm\vgui\controller_focus.cpp" + $File "swarm\vgui\controller_focus.h" + $file "swarm\vgui\debrieftextpage.cpp" + $file "swarm\vgui\debrieftextpage.h" + $file "swarm\vgui\experience_bar.cpp" + $file "swarm\vgui\experience_bar.h" + $file "swarm\vgui\experience_report.cpp" + $file "swarm\vgui\experience_report.h" + $file "swarm\vgui\experience_stat_line.cpp" + $file "swarm\vgui\experience_stat_line.h" + $file "swarm\vgui\fadeinpanel.cpp" + $file "swarm\vgui\fadeinpanel.h" + $file "swarm\vgui\fonttestpanel.cpp" + $file "swarm\vgui\fonttestpanel.h" + $file "swarm\vgui\forcereadypanel.cpp" + $file "swarm\vgui\forcereadypanel.h" + $file "swarm\vgui\holdout_end_score_panel.cpp" + $file "swarm\vgui\holdout_end_score_panel.h" + $file "swarm\vgui\holdout_hud_wave_panel.cpp" + $file "swarm\vgui\holdout_hud_wave_panel.h" + $file "swarm\vgui\holdout_resupply_frame.cpp" + $file "swarm\vgui\holdout_resupply_frame.h" + $file "swarm\vgui\holdout_wave_announce_panel.cpp" + $file "swarm\vgui\holdout_wave_announce_panel.h" + $file "swarm\vgui\holdout_wave_end_panel.cpp" + $file "swarm\vgui\holdout_wave_end_panel.h" + $file "swarm\vgui\imagebutton.cpp" + $file "swarm\vgui\imagebutton.h" + $file "swarm\vgui\mapedgesbox.cpp" + $file "swarm\vgui\mapedgesbox.h" + $file "swarm\vgui\medalarea.cpp" + $file "swarm\vgui\medalarea.h" + $file "swarm\vgui\medalcollectionpanel.cpp" + $file "swarm\vgui\medalcollectionpanel.h" + $file "swarm\vgui\medalpanel.cpp" + $file "swarm\vgui\medalpanel.h" + $file "swarm\vgui\missioncompleteframe.cpp" + $file "swarm\vgui\missioncompleteframe.h" + $file "swarm\vgui\missioncompletepanel.cpp" + $file "swarm\vgui\missioncompletepanel.h" + $file "swarm\vgui\missioncompletestatsline.cpp" + $file "swarm\vgui\missioncompletestatsline.h" + $file "swarm\vgui\missionstatspanel.cpp" + $file "swarm\vgui\missionstatspanel.h" + $file "swarm\vgui\objectivedetailspanel.cpp" + $file "swarm\vgui\objectivedetailspanel.h" + $file "swarm\vgui\objectiveicons.cpp" + $file "swarm\vgui\objectiveicons.h" + $file "swarm\vgui\objectivelistbox.cpp" + $file "swarm\vgui\objectivelistbox.h" + $file "swarm\vgui\objectivemap.cpp" + $file "swarm\vgui\objectivemap.h" + $file "swarm\vgui\objectivemapmarkpanel.cpp" + $file "swarm\vgui\objectivemapmarkpanel.h" + $file "swarm\vgui\objectivepanel.cpp" + $file "swarm\vgui\objectivepanel.h" + $file "swarm\vgui\objectivetitlepanel.cpp" + $file "swarm\vgui\objectivetitlepanel.h" + $file "swarm\vgui\outroframe.cpp" + $file "swarm\vgui\outroframe.h" + $file "swarm\vgui\playerlistcontainer.cpp" + $file "swarm\vgui\playerlistcontainer.h" + $file "swarm\vgui\playerlistline.cpp" + $file "swarm\vgui\playerlistline.h" + $file "swarm\vgui\playerlistpanel.cpp" + $file "swarm\vgui\playerlistpanel.h" + $file "swarm\vgui\playerswaitingpanel.cpp" + $file "swarm\vgui\playerswaitingpanel.h" + $file "swarm\vgui\restartmissionbutton.cpp" + $file "swarm\vgui\restartmissionbutton.h" + $file "swarm\vgui\returncampaignmapbutton.cpp" + $file "swarm\vgui\returncampaignmapbutton.h" + $file "swarm\vgui\scanlinepanel.cpp" + $file "swarm\vgui\scanlinepanel.h" + $file "swarm\vgui\skillanimpanel.cpp" + $file "swarm\vgui\skillanimpanel.h" + $file "swarm\vgui\softline.cpp" + $file "swarm\vgui\softline.h" + $file "swarm\vgui\squad_inventory_panel.cpp" + $file "swarm\vgui\squad_inventory_panel.h" + $file "swarm\vgui\stat_graph.cpp" + $file "swarm\vgui\stat_graph.h" + $file "swarm\vgui\stat_graph_player.cpp" + $file "swarm\vgui\stat_graph_player.h" + $file "swarm\vgui\stats_report.cpp" + $file "swarm\vgui\stats_report.h" + $file "swarm\vgui\statsbar.cpp" + $file "swarm\vgui\statsbar.h" + $file "swarm\vgui\stimmusicselectdialog.cpp" + $file "swarm\vgui\stimmusicselectdialog.h" + $file "swarm\vgui\techmarinefailpanel.cpp" + $file "swarm\vgui\techmarinefailpanel.h" + $file "swarm\vgui\wrappedlabel.cpp" + $file "swarm\vgui\wrappedlabel.h" + $file "swarm\vgui\weapon_unlock_panel.cpp" + $file "swarm\vgui\weapon_unlock_panel.h" + + $file "swarm\vgui\asw_difficulty_chooser.cpp" + $file "swarm\vgui\asw_difficulty_chooser.h" + $file "swarm\vgui\asw_mission_chooser_entry.cpp" + $file "swarm\vgui\asw_mission_chooser_entry.h" + $file "swarm\vgui\asw_mission_chooser_frame.cpp" + $file "swarm\vgui\asw_mission_chooser_frame.h" + $file "swarm\vgui\asw_mission_chooser_list.cpp" + $file "swarm\vgui\asw_mission_chooser_list.h" + $file "swarm\vgui\serveroptionspanel.cpp" + $file "swarm\vgui\serveroptionspanel.h" + + $file "swarm\vgui\asw_scalable_text.cpp" + $file "swarm\vgui\asw_scalable_text.h" + + $file "swarm\vgui\medalstooltip.cpp" + $file "swarm\vgui\medalstooltip.h" + + $File "$SRCDIR\public\missionchooser\iasw_mission_chooser.h" + $File "$SRCDIR\public\missionchooser\iasw_mission_chooser_source.h" + $File "$SRCDIR\public\missionchooser\iasw_random_missions.h" + + $Folder "ManagedPanels" + { + $file "swarm/vgui/nb_button.cpp" + $file "swarm/vgui/nb_button.h" + $file "swarm/vgui/nb_campaign_map.cpp" + $file "swarm/vgui/nb_campaign_map.h" + $file "swarm/vgui/nb_campaign_mission_details.cpp" + $file "swarm/vgui/nb_campaign_mission_details.h" + $file "swarm/vgui/nb_commander_list.cpp" + $file "swarm/vgui/nb_commander_list.h" + $file "swarm/vgui/nb_commander_list_entry.cpp" + $file "swarm/vgui/nb_commander_list_entry.h" + $file "swarm/vgui/nb_island.cpp" + $file "swarm/vgui/nb_island.h" + $file "swarm/vgui/nb_suggest_difficulty.cpp" + $file "swarm/vgui/nb_suggest_difficulty.h" + $file "swarm/vgui/nb_weapon_unlocked.cpp" + $file "swarm/vgui/nb_weapon_unlocked.h" + + $file "swarm/vgui/nb_select_save_entry.cpp" + $file "swarm/vgui/nb_select_save_entry.h" + $file "swarm/vgui/nb_select_save_panel.cpp" + $file "swarm/vgui/nb_select_save_panel.h" + $file "swarm/vgui/nb_select_mission_entry.cpp" + $file "swarm/vgui/nb_select_mission_entry.h" + $file "swarm/vgui/nb_select_mission_panel.cpp" + $file "swarm/vgui/nb_select_mission_panel.h" + $file "swarm/vgui/nb_select_campaign_entry.cpp" + $file "swarm/vgui/nb_select_campaign_entry.h" + $file "swarm/vgui/nb_select_campaign_panel.cpp" + $file "swarm/vgui/nb_select_campaign_panel.h" + $file "swarm/vgui/nb_header_footer.cpp" + $file "swarm/vgui/nb_header_footer.h" + $file "swarm/vgui/nb_spend_skill_points.cpp" + $file "swarm/vgui/nb_spend_skill_points.h" + $file "swarm/vgui/nb_mission_options.cpp" + $file "swarm/vgui/nb_mission_options.h" + $file "swarm/vgui/nb_mission_panel.cpp" + $file "swarm/vgui/nb_mission_panel.h" + $file "swarm/vgui/nb_mission_summary.cpp" + $file "swarm/vgui/nb_mission_summary.h" + $file "swarm/vgui/nb_lobby_row_small.cpp" + $file "swarm/vgui/nb_lobby_row_small.h" + $file "swarm/vgui/nb_select_weapon_entry.cpp" + $file "swarm/vgui/nb_select_weapon_entry.h" + $file "swarm/vgui/nb_weapon_detail.cpp" + $file "swarm/vgui/nb_weapon_detail.h" + $file "swarm/vgui/nb_select_weapon_panel.cpp" + $file "swarm/vgui/nb_select_weapon_panel.h" + $file "swarm/vgui/nb_select_marine_entry.cpp" + $file "swarm/vgui/nb_select_marine_entry.h" + $file "swarm/vgui/nb_horiz_list.cpp" + $file "swarm/vgui/nb_horiz_list.h" + $file "swarm/vgui/nb_skill_panel.cpp" + $file "swarm/vgui/nb_skill_panel.h" + $file "swarm/vgui/nb_select_marine_panel.cpp" + $file "swarm/vgui/nb_select_marine_panel.h" + $file "swarm/vgui/nb_lobby_tooltip.cpp" + $file "swarm/vgui/nb_lobby_tooltip.h" + $file "swarm/vgui/nb_lobby_row.cpp" + $file "swarm/vgui/nb_lobby_row.h" + $file "swarm/vgui/nb_main_panel.cpp" + $file "swarm/vgui/nb_main_panel.h" + } + } + + $Folder "Shared" + { + $File "$SRCDIR\game\shared\swarm\asw_achievements.cpp" + $File "$SRCDIR\game\shared\swarm\asw_achievements.h" + $File "$SRCDIR\game\shared\swarm\asw_health_bar_shared.cpp" + $File "$SRCDIR\game\shared\swarm\asw_prop_laserable_shared.cpp" + $File "$SRCDIR\game\shared\swarm\asw_prop_laserable_shared.h" + $File "$SRCDIR\game\shared\swarm\asw_target_dummy_shared.cpp" + $File "$SRCDIR\game\shared\swarm\asw_target_dummy_shared.h" + $File "$SRCDIR\game\shared\swarm\asw_weapon_blink.cpp" + $File "$SRCDIR\game\shared\swarm\asw_weapon_blink.h" + $File "$SRCDIR\game\shared\swarm\asw_weapon_fist.cpp" + $File "$SRCDIR\game\shared\swarm\asw_weapon_fist.h" + $File "$SRCDIR\game\shared\swarm\asw_weapon_jump_jet.cpp" + $File "$SRCDIR\game\shared\swarm\asw_weapon_jump_jet.h" + $File "$SRCDIR\game\shared\swarm\asw_weapon_smart_bomb.cpp" + $File "$SRCDIR\game\shared\swarm\asw_weapon_smart_bomb.h" + + $File "$SRCDIR\game\shared\swarm\asw_alien_goo_shared.cpp" + $File "$SRCDIR\game\shared\swarm\asw_alien_goo_shared.h" + $File "$SRCDIR\game\shared\swarm\asw_alien_shared.cpp" + $File "$SRCDIR\game\shared\swarm\asw_alien_shared.h" + $File "$SRCDIR\game\shared\swarm\asw_ammo_drop_shared.cpp" + $File "$SRCDIR\game\shared\swarm\asw_ammo_drop_shared.h" + $File "$SRCDIR\game\shared\swarm\asw_bouncing_pellet_shared.cpp" + $File "$SRCDIR\game\shared\swarm\asw_bouncing_pellet_shared.h" + $File "$SRCDIR\game\shared\swarm\asw_campaign_commands.cpp" + $File "$SRCDIR\game\shared\swarm\asw_campaign_info.cpp" + $File "$SRCDIR\game\shared\swarm\asw_campaign_info.h" + $File "$SRCDIR\game\shared\swarm\asw_campaign_save_shared.cpp" + $File "$SRCDIR\game\shared\swarm\asw_equipment_list.cpp" + $File "$SRCDIR\game\shared\swarm\asw_equipment_list.h" + $File "$SRCDIR\game\shared\swarm\asw_equip_req.cpp" + $File "$SRCDIR\game\shared\swarm\asw_equip_req.h" + $File "$SRCDIR\game\shared\swarm\asw_env_spark.cpp" + $File "$SRCDIR\game\shared\swarm\asw_fx_shared.cpp" + $File "$SRCDIR\game\shared\swarm\asw_fx_shared.h" + $File "$SRCDIR\game\shared\swarm\asw_game_resource_shared.cpp" + $File "$SRCDIR\game\shared\swarm\asw_gamemovement.cpp" + $File "$SRCDIR\game\shared\swarm\asw_gamerules.cpp" + $File "$SRCDIR\game\shared\swarm\asw_gamerules.h" + $File "$SRCDIR\game\shared\swarm\asw_gamestats_shared.cpp" + $File "$SRCDIR\game\shared\swarm\asw_gamestats_shared.h" + $File "$SRCDIR\game\shared\swarm\asw_hack_computer_shared.cpp" + $File "$SRCDIR\game\shared\swarm\asw_hack_wire_tile_shared.cpp" + $File "$SRCDIR\game\shared\swarm\asw_holdout_mode.cpp" + $File "$SRCDIR\game\shared\swarm\asw_holdout_mode.h" + $File "$SRCDIR\game\shared\swarm\asw_holdout_wave.cpp" + $File "$SRCDIR\game\shared\swarm\asw_holdout_wave.h" + $File "$SRCDIR\game\shared\swarm\asw_holo_sentry_shared.cpp" + $File "$SRCDIR\game\shared\swarm\asw_holo_sentry_shared.h" + $File "$SRCDIR\game\shared\swarm\asw_imarinegamemovement.h" + $File "$SRCDIR\game\shared\swarm\asw_info_message_shared.cpp" + $File "$SRCDIR\game\shared\swarm\asw_info_message_shared.h" + $File "$SRCDIR\game\shared\swarm\asw_laser_mine_shared.cpp" + $File "$SRCDIR\game\shared\swarm\asw_marine_profile.cpp" + $File "$SRCDIR\game\shared\swarm\asw_marine_profile.h" + $File "$SRCDIR\game\shared\swarm\asw_marine_command.cpp" + $File "$SRCDIR\game\shared\swarm\asw_marine_command.h" + $File "$SRCDIR\game\shared\swarm\asw_marine_gamemovement.cpp" + $File "$SRCDIR\game\shared\swarm\asw_marine_gamemovement.h" + $File "$SRCDIR\game\shared\swarm\asw_marine_shared.cpp" + $File "$SRCDIR\game\shared\swarm\asw_marine_shared.h" + $File "$SRCDIR\game\shared\swarm\asw_marine_skills.cpp" + $File "$SRCDIR\game\shared\swarm\asw_marine_skills.h" + $File "$SRCDIR\game\shared\swarm\asw_medals_shared.h" + $File "$SRCDIR\game\shared\swarm\asw_melee_system.cpp" + $File "$SRCDIR\game\shared\swarm\asw_melee_system.h" + $File "$SRCDIR\game\shared\swarm\asw_missile_round_shared.cpp" + $File "$SRCDIR\game\shared\swarm\asw_missile_round_shared.h" + $File "$SRCDIR\game\shared\swarm\asw_mortarbug_shell_shared.cpp" + $File "$SRCDIR\game\shared\swarm\asw_mortarbug_shell_shared.h" + $File "$SRCDIR\game\shared\swarm\asw_movedata.h" + $File "$SRCDIR\game\shared\swarm\asw_pickup_shared.cpp" + $File "$SRCDIR\game\shared\swarm\asw_playeranimstate.cpp" + $File "$SRCDIR\game\shared\swarm\asw_playeranimstate.h" + $File "$SRCDIR\game\shared\swarm\asw_player_experience.cpp" + $File "$SRCDIR\game\shared\swarm\asw_player_shared.cpp" + $File "$SRCDIR\game\shared\swarm\asw_player_shared.h" + $File "$SRCDIR\game\shared\swarm\asw_powerup_shared.cpp" + $File "$SRCDIR\game\shared\swarm\asw_powerup_shared.h" + $File "$SRCDIR\game\shared\swarm\asw_queen_divers_shared.cpp" + $File "$SRCDIR\game\shared\swarm\asw_queen_divers_shared.h" + $File "$SRCDIR\game\shared\swarm\asw_queen_grabber_shared.cpp" + $File "$SRCDIR\game\shared\swarm\asw_queen_grabber_shared.h" + $File "$SRCDIR\game\shared\swarm\asw_remote_turret_shared.cpp" + $File "$SRCDIR\game\shared\swarm\asw_remote_turret_shared.h" + $File "$SRCDIR\game\shared\swarm\asw_scanner_objects_enumerator.cpp" + $File "$SRCDIR\game\shared\swarm\asw_scanner_objects_enumerator.h" + $File "$SRCDIR\game\shared\swarm\asw_shareddefs.cpp" + $File "$SRCDIR\game\shared\swarm\asw_shareddefs.h" + $File "$SRCDIR\game\shared\swarm\asw_shieldbug_shared.cpp" + $File "$SRCDIR\game\shared\swarm\asw_shotgun_pellet_predicted_shared.cpp" + $File "$SRCDIR\game\shared\swarm\asw_shotgun_pellet_predicted_shared.h" + $File "$SRCDIR\game\shared\swarm\asw_trace_filter_melee.cpp" + $File "$SRCDIR\game\shared\swarm\asw_trace_filter_melee.h" + $File "$SRCDIR\game\shared\swarm\asw_trace_filter_shot.cpp" + $File "$SRCDIR\game\shared\swarm\asw_trace_filter_shot.h" + $File "$SRCDIR\game\shared\swarm\asw_usableobjectsenumerator.cpp" + $File "$SRCDIR\game\shared\swarm\asw_usableobjectsenumerator.h" + $File "$SRCDIR\game\shared\swarm\asw_usermessages.cpp" + $File "$SRCDIR\game\shared\swarm\asw_util_shared.cpp" + $File "$SRCDIR\game\shared\swarm\asw_util_shared.h" + $File "$SRCDIR\game\shared\swarm\asw_weapon_ammo_bag_shared.cpp" + $File "$SRCDIR\game\shared\swarm\asw_weapon_ammo_bag_shared.h" + $File "$SRCDIR\game\shared\swarm\asw_weapon_ammo_satchel_shared.cpp" + $File "$SRCDIR\game\shared\swarm\asw_weapon_ammo_satchel_shared.h" + $File "$SRCDIR\game\shared\swarm\asw_weapon_assault_shotgun_shared.cpp" + $File "$SRCDIR\game\shared\swarm\asw_weapon_assault_shotgun_shared.h" + $File "$SRCDIR\game\shared\swarm\asw_weapon_autogun_shared.cpp" + $File "$SRCDIR\game\shared\swarm\asw_weapon_autogun_shared.h" + $File "$SRCDIR\game\shared\swarm\asw_weapon_bait.cpp" + $File "$SRCDIR\game\shared\swarm\asw_weapon_bait.h" + $File "$SRCDIR\game\shared\swarm\asw_weapon_buff_grenade.cpp" + $File "$SRCDIR\game\shared\swarm\asw_weapon_buff_grenade.h" + $File "$SRCDIR\game\shared\swarm\asw_weapon_chainsaw_shared.cpp" + $File "$SRCDIR\game\shared\swarm\asw_weapon_chainsaw_shared.h" + $File "$SRCDIR\game\shared\swarm\asw_weapon_electrified_armor.cpp" + $File "$SRCDIR\game\shared\swarm\asw_weapon_electrified_armor.h" + $File "$SRCDIR\game\shared\swarm\asw_weapon_normal_armor.cpp" + $File "$SRCDIR\game\shared\swarm\asw_weapon_normal_armor.h" + $File "$SRCDIR\game\shared\swarm\asw_weapon_fire_extinguisher_shared.cpp" + $File "$SRCDIR\game\shared\swarm\asw_weapon_fire_extinguisher_shared.h" + $File "$SRCDIR\game\shared\swarm\asw_weapon_flamer_shared.cpp" + $File "$SRCDIR\game\shared\swarm\asw_weapon_flamer_shared.h" + $File "$SRCDIR\game\shared\swarm\asw_weapon_flares_shared.cpp" + $File "$SRCDIR\game\shared\swarm\asw_weapon_flares_shared.h" + $File "$SRCDIR\game\shared\swarm\asw_weapon_flashlight_shared.cpp" + $File "$SRCDIR\game\shared\swarm\asw_weapon_flashlight_shared.h" + $File "$SRCDIR\game\shared\swarm\asw_weapon_flechette_shared.cpp" + $File "$SRCDIR\game\shared\swarm\asw_weapon_flechette_shared.h" + $File "$SRCDIR\game\shared\swarm\asw_weapon_freeze_grenades.cpp" + $File "$SRCDIR\game\shared\swarm\asw_weapon_freeze_grenades.h" + $File "$SRCDIR\game\shared\swarm\asw_weapon_grenade_launcher.cpp" + $File "$SRCDIR\game\shared\swarm\asw_weapon_grenade_launcher.h" + $File "$SRCDIR\game\shared\swarm\asw_weapon_grenades.cpp" + $File "$SRCDIR\game\shared\swarm\asw_weapon_grenades.h" + $File "$SRCDIR\game\shared\swarm\asw_weapon_heal_gun_shared.cpp" + $File "$SRCDIR\game\shared\swarm\asw_weapon_heal_gun_shared.h" + $File "$SRCDIR\game\shared\swarm\asw_weapon_healgrenade_shared.cpp" + $File "$SRCDIR\game\shared\swarm\asw_weapon_healgrenade_shared.h" + $File "$SRCDIR\game\shared\swarm\asw_weapon_hornet_barrage.cpp" + $File "$SRCDIR\game\shared\swarm\asw_weapon_hornet_barrage.h" + $File "$SRCDIR\game\shared\swarm\asw_weapon_laser_mines.cpp" + $File "$SRCDIR\game\shared\swarm\asw_weapon_laser_mines.h" + $File "$SRCDIR\game\shared\swarm\asw_weapon_medical_satchel_shared.cpp" + $File "$SRCDIR\game\shared\swarm\asw_weapon_medical_satchel_shared.h" + $File "$SRCDIR\game\shared\swarm\asw_weapon_medkit_shared.cpp" + $File "$SRCDIR\game\shared\swarm\asw_weapon_medkit_shared.h" + $File "$SRCDIR\game\shared\swarm\asw_weapon_mines_shared.cpp" + $File "$SRCDIR\game\shared\swarm\asw_weapon_mines_shared.h" + $File "$SRCDIR\game\shared\swarm\asw_weapon_mining_laser_shared.cpp" + $File "$SRCDIR\game\shared\swarm\asw_weapon_mining_laser_shared.h" + $File "$SRCDIR\game\shared\swarm\asw_weapon_minigun.cpp" + $File "$SRCDIR\game\shared\swarm\asw_weapon_minigun.h" + $File "$SRCDIR\game\shared\swarm\asw_weapon_night_vision.cpp" + $File "$SRCDIR\game\shared\swarm\asw_weapon_night_vision.h" + $File "$SRCDIR\game\shared\swarm\asw_weapon_parse.cpp" + $File "$SRCDIR\game\shared\swarm\asw_weapon_parse.h" + $File "$SRCDIR\game\shared\swarm\asw_weapon_pdw_shared.cpp" + $File "$SRCDIR\game\shared\swarm\asw_weapon_pdw_shared.h" + $File "$SRCDIR\game\shared\swarm\asw_weapon_pistol_shared.cpp" + $File "$SRCDIR\game\shared\swarm\asw_weapon_pistol_shared.h" + $File "$SRCDIR\game\shared\swarm\asw_weapon_prifle_shared.cpp" + $File "$SRCDIR\game\shared\swarm\asw_weapon_prifle_shared.h" + $File "$SRCDIR\game\shared\swarm\asw_weapon_railgun_shared.cpp" + $File "$SRCDIR\game\shared\swarm\asw_weapon_railgun_shared.h" + $File "$SRCDIR\game\shared\swarm\asw_weapon_ricochet_shared.cpp" + $File "$SRCDIR\game\shared\swarm\asw_weapon_ricochet_shared.h" + $File "$SRCDIR\game\shared\swarm\asw_weapon_sentry_shared.cpp" + $File "$SRCDIR\game\shared\swarm\asw_weapon_sentry_shared.h" + $File "$SRCDIR\game\shared\swarm\asw_weapon_shared.cpp" + $File "$SRCDIR\game\shared\swarm\asw_weapon_shared.h" + $File "$SRCDIR\game\shared\swarm\asw_weapon_shotgun_shared.cpp" + $File "$SRCDIR\game\shared\swarm\asw_weapon_shotgun_shared.h" + $File "$SRCDIR\game\shared\swarm\asw_weapon_sniper_rifle.cpp" + $File "$SRCDIR\game\shared\swarm\asw_weapon_sniper_rifle.h" + $File "$SRCDIR\game\shared\swarm\asw_weapon_stim_shared.cpp" + $File "$SRCDIR\game\shared\swarm\asw_weapon_stim_shared.h" + $File "$SRCDIR\game\shared\swarm\asw_weapon_t75.cpp" + $File "$SRCDIR\game\shared\swarm\asw_weapon_t75.h" + $File "$SRCDIR\game\shared\swarm\asw_weapon_tesla_gun_shared.cpp" + $File "$SRCDIR\game\shared\swarm\asw_weapon_tesla_gun_shared.h" + $File "$SRCDIR\game\shared\swarm\asw_weapon_tesla_trap.cpp" + $File "$SRCDIR\game\shared\swarm\asw_weapon_tesla_trap.h" + $File "$SRCDIR\game\shared\swarm\asw_weapon_welder_shared.cpp" + $File "$SRCDIR\game\shared\swarm\asw_weapon_welder_shared.h" + } + } + } + + $Folder "Link Libraries" + { + $Lib "$LIBCOMMON\jpeglib" + $Lib "$LIBPUBLIC\vpklib" + } +} \ No newline at end of file diff --git a/game/client/client_thinklist.cpp b/game/client/client_thinklist.cpp index bbb70a7b1..28abd5ad4 100644 --- a/game/client/client_thinklist.cpp +++ b/game/client/client_thinklist.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // @@ -14,6 +14,9 @@ CClientThinkList g_ClientThinkList; +static ConVar report_clientthinklist( "report_clientthinklist", "0", FCVAR_CHEAT, "List all clientside entities thinking and time - will report and turn itself off." ); + + CClientThinkList::CClientThinkList() { } @@ -120,7 +123,7 @@ void CClientThinkList::SetNextClientThink( ClientEntityHandle_t hEnt, float flNe // Add it to the list if it's not already in there. if ( hThink == INVALID_THINK_HANDLE ) { - hThink = (ClientThinkHandle_t)(uintp)m_ThinkEntries.AddToTail(); + hThink = (ClientThinkHandle_t)m_ThinkEntries.AddToTail(); pThink->SetThinkHandle( hThink ); ThinkEntry_t *pEntry = GetThinkEntry( hThink ); @@ -158,7 +161,7 @@ void CClientThinkList::RemoveThinkable( ClientThinkHandle_t hThink ) { pThink->SetThinkHandle( INVALID_THINK_HANDLE ); } - m_ThinkEntries.Remove( (uintp)hThink ); + m_ThinkEntries.Remove( (unsigned long)hThink ); } @@ -287,24 +290,45 @@ void CClientThinkList::PerformThinkFunctions() // While we're in the loop, no changes to the think list are allowed m_bInThinkLoop = true; - // Perform thinks on all entities that need it - int i; - for ( i = 0; i < nThinkCount; ++i ) + if( !report_clientthinklist.GetBool() ) + { + // Perform thinks on all entities that need it + for ( int i = 0; i < nThinkCount; ++i ) + { + PerformThinkFunction( ppThinkEntryList[i], gpGlobals->curtime ); + } + } + else { - PerformThinkFunction( ppThinkEntryList[i], gpGlobals->curtime ); + CFastTimer fastTimer; + + for ( int i = 0; i < nThinkCount; ++i ) + { + fastTimer.Start(); + PerformThinkFunction( ppThinkEntryList[i], gpGlobals->curtime ); + fastTimer.End(); + + C_BaseEntity *pEntity = ClientEntityList().GetBaseEntityFromHandle( ppThinkEntryList[i]->m_hEnt ); + if ( pEntity ) + { + Msg( "Entity(%d): %s - %f\n", pEntity->entindex(), pEntity->GetDebugName(), fastTimer.GetDuration().GetMillisecondsF() ); + } + } + + report_clientthinklist.SetValue( 0 ); } m_bInThinkLoop = false; // Apply changes to the think list int nCount = m_aChangeList.Count(); - for ( i = 0; i < nCount; ++i ) + for ( int i = 0; i < nCount; ++i ) { ClientThinkHandle_t hThink = m_aChangeList[i].m_hThink; if ( hThink != INVALID_THINK_HANDLE ) { // This can happen if the same think handle was removed twice - if ( !m_ThinkEntries.IsInList( (uintp)hThink ) ) + if ( !m_ThinkEntries.IsInList( (unsigned long)hThink ) ) continue; // NOTE: This is necessary for the case where the client entity handle diff --git a/game/client/client_thinklist.h b/game/client/client_thinklist.h index 9d3b3b545..305dc20a3 100644 --- a/game/client/client_thinklist.h +++ b/game/client/client_thinklist.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // @@ -12,7 +12,7 @@ #endif -#include "igamesystem.h" +#include "IGameSystem.h" #include "utllinkedlist.h" #include "cliententitylist.h" #include "iclientthinkable.h" @@ -115,13 +115,13 @@ class CClientThinkList : public IGameSystemPerFrame inline ClientThinkHandle_t CClientThinkList::GetInvalidThinkHandle() { - return (ClientThinkHandle_t)(uintp)m_ThinkEntries.InvalidIndex(); + return (ClientThinkHandle_t)m_ThinkEntries.InvalidIndex(); } inline CClientThinkList::ThinkEntry_t* CClientThinkList::GetThinkEntry( ClientThinkHandle_t hThink ) { - return &m_ThinkEntries[ (uintp)hThink ]; + return &m_ThinkEntries[ (unsigned long)hThink ]; } diff --git a/game/client/client_virtualreality.cpp b/game/client/client_virtualreality.cpp deleted file mode 100644 index af52b56e0..000000000 --- a/game/client/client_virtualreality.cpp +++ /dev/null @@ -1,1514 +0,0 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -// $NoKeywords: $ -//===========================================================================// -#include "cbase.h" - -#include "client_virtualreality.h" - -#include "materialsystem/itexture.h" -#include "materialsystem/materialsystem_config.h" -#include "view_shared.h" -#include "view_scene.h" -#include "VGuiMatSurface/IMatSystemSurface.h" -#include "vgui_controls/Controls.h" -#include "sourcevr/isourcevirtualreality.h" -#include "ienginevgui.h" -#include "cdll_client_int.h" -#include "vgui/IVGui.h" -#include "vgui_controls/Controls.h" -#include "tier0/vprof_telemetry.h" -#include -#include "steam/steam_api.h" - -const char *COM_GetModDirectory(); // return the mod dir (rather than the complete -game param, which can be a path) - -CClientVirtualReality g_ClientVirtualReality; -EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CClientVirtualReality, IClientVirtualReality, - CLIENTVIRTUALREALITY_INTERFACE_VERSION, g_ClientVirtualReality ); - - -// -------------------------------------------------------------------- -// A huge pile of VR convars -// -------------------------------------------------------------------- -ConVar vr_activate_default( "vr_activate_default", "0", FCVAR_ARCHIVE, "If this is true the game will switch to VR mode once startup is complete." ); - - -ConVar vr_moveaim_mode ( "vr_moveaim_mode", "3", FCVAR_ARCHIVE, "0=move+shoot from face. 1=move with torso. 2,3,4=shoot with face+mouse cursor. 5+ are probably not that useful." ); -ConVar vr_moveaim_mode_zoom ( "vr_moveaim_mode_zoom", "3", FCVAR_ARCHIVE, "0=move+shoot from face. 1=move with torso. 2,3,4=shoot with face+mouse cursor. 5+ are probably not that useful." ); - -ConVar vr_moveaim_reticle_yaw_limit ( "vr_moveaim_reticle_yaw_limit", "10", FCVAR_ARCHIVE, "Beyond this number of degrees, the mouse drags the torso" ); -ConVar vr_moveaim_reticle_pitch_limit ( "vr_moveaim_reticle_pitch_limit", "30", FCVAR_ARCHIVE, "Beyond this number of degrees, the mouse clamps" ); -// Note these are scaled by the zoom factor. -ConVar vr_moveaim_reticle_yaw_limit_zoom ( "vr_moveaim_reticle_yaw_limit_zoom", "0", FCVAR_ARCHIVE, "Beyond this number of degrees, the mouse drags the torso" ); -ConVar vr_moveaim_reticle_pitch_limit_zoom ( "vr_moveaim_reticle_pitch_limit_zoom", "-1", FCVAR_ARCHIVE, "Beyond this number of degrees, the mouse clamps" ); - -// This are somewhat obsolete. -ConVar vr_aim_yaw_offset( "vr_aim_yaw_offset", "90", 0, "This value is added to Yaw when returning the vehicle aim angles to Source." ); - -ConVar vr_stereo_swap_eyes ( "vr_stereo_swap_eyes", "0", 0, "1=swap eyes." ); - -// Useful for debugging wacky-projection problems, separate from multi-rendering problems. -ConVar vr_stereo_mono_set_eye ( "vr_stereo_mono_set_eye", "0", 0, "0=off, Set all eyes to 1=left, 2=right, 3=middle eye" ); - -// Useful for examining anims, etc. -ConVar vr_debug_remote_cam( "vr_debug_remote_cam", "0" ); -ConVar vr_debug_remote_cam_pos_x( "vr_debug_remote_cam_pos_x", "150.0" ); -ConVar vr_debug_remote_cam_pos_y( "vr_debug_remote_cam_pos_y", "0.0" ); -ConVar vr_debug_remote_cam_pos_z( "vr_debug_remote_cam_pos_z", "0.0" ); -ConVar vr_debug_remote_cam_target_x( "vr_debug_remote_cam_target_x", "0.0" ); -ConVar vr_debug_remote_cam_target_y( "vr_debug_remote_cam_target_y", "0.0" ); -ConVar vr_debug_remote_cam_target_z( "vr_debug_remote_cam_target_z", "-50.0" ); - -ConVar vr_translation_limit( "vr_translation_limit", "10.0", 0, "How far the in-game head will translate before being clamped." ); - -// HUD config values -ConVar vr_render_hud_in_world( "vr_render_hud_in_world", "1" ); -ConVar vr_hud_max_fov( "vr_hud_max_fov", "60", FCVAR_ARCHIVE, "Max FOV of the HUD" ); -ConVar vr_hud_forward( "vr_hud_forward", "500", FCVAR_ARCHIVE, "Apparent distance of the HUD in inches" ); -ConVar vr_hud_display_ratio( "vr_hud_display_ratio", "0.95", FCVAR_ARCHIVE ); -ConVar vr_hud_never_overlay( "vr_hud_never_overlay", "0" ); - -ConVar vr_hud_axis_lock_to_world( "vr_hud_axis_lock_to_world", "0", FCVAR_ARCHIVE, "Bitfield - locks HUD axes to the world - 0=pitch, 1=yaw, 2=roll" ); - -// Default distance clips through rocketlauncher, heavy's body, etc. -ConVar vr_projection_znear_multiplier( "vr_projection_znear_multiplier", "0.3", 0, "Allows moving the ZNear plane to deal with body clipping" ); - -// Should the viewmodel (weapon) translate with the HMD, or remain fixed to the in-world body (but still rotate with the head)? Purely a graphics effect - no effect on actual bullet aiming. -// Has no effect in aim modes where aiming is not controlled by the head. -ConVar vr_viewmodel_translate_with_head ( "vr_viewmodel_translate_with_head", "0", 0, "1=translate the viewmodel with the head motion." ); - -ConVar vr_zoom_multiplier ( "vr_zoom_multiplier", "2.0", FCVAR_ARCHIVE, "When zoomed, how big is the scope on your HUD?" ); -ConVar vr_zoom_scope_scale ( "vr_zoom_scope_scale", "6.0", 0, "Something to do with the default scope HUD overlay size." ); // Horrible hack - should work out the math properly, but we need to ship. - - -ConVar vr_viewmodel_offset_forward( "vr_viewmodel_offset_forward", "-8", 0 ); -ConVar vr_viewmodel_offset_forward_large( "vr_viewmodel_offset_forward_large", "-15", 0 ); - -ConVar vr_force_windowed ( "vr_force_windowed", "0", FCVAR_ARCHIVE ); - -ConVar vr_first_person_uses_world_model ( "vr_first_person_uses_world_model", "1", 0, "Causes the third person model to be drawn instead of the view model" ); - -// -------------------------------------------------------------------- -// Purpose: Cycle through the aim & move modes. -// -------------------------------------------------------------------- -void CC_VR_Cycle_Aim_Move_Mode ( const CCommand& args ) -{ - int hmmCurrentMode = vr_moveaim_mode.GetInt(); - if ( g_ClientVirtualReality.CurrentlyZoomed() ) - { - hmmCurrentMode = vr_moveaim_mode_zoom.GetInt(); - } - - hmmCurrentMode++; - if ( hmmCurrentMode >= HMM_LAST ) - { - hmmCurrentMode = 0; - } - - if ( g_ClientVirtualReality.CurrentlyZoomed() ) - { - vr_moveaim_mode_zoom.SetValue ( hmmCurrentMode ); - Warning ( "Headtrack mode (zoomed) %d\n", hmmCurrentMode ); - } - else - { - vr_moveaim_mode.SetValue ( hmmCurrentMode ); - Warning ( "Headtrack mode %d\n", hmmCurrentMode ); - } -} -static ConCommand vr_cycle_aim_move_mode("vr_cycle_aim_move_mode", CC_VR_Cycle_Aim_Move_Mode, "Cycle through the aim & move modes." ); - - -// -------------------------------------------------------------------- -// Purpose: Switch to/from VR mode. -// -------------------------------------------------------------------- -CON_COMMAND( vr_activate, "Switch to VR mode" ) -{ - g_ClientVirtualReality.Activate(); -} -CON_COMMAND( vr_deactivate, "Switch from VR mode to normal mode" ) -{ - g_ClientVirtualReality.Deactivate(); -} -CON_COMMAND( vr_toggle, "Toggles VR mode" ) -{ - if( g_pSourceVR ) - { - if( g_pSourceVR->ShouldRunInVR() ) - g_ClientVirtualReality.Deactivate(); - else - g_ClientVirtualReality.Activate(); - } - else - { - Msg( "VR Mode is not enabled.\n" ); - } -} - - -// -------------------------------------------------------------------- -// Purpose: Returns true if the matrix is orthonormal -// -------------------------------------------------------------------- -bool IsOrthonormal ( VMatrix Mat, float fTolerance ) -{ - float LenFwd = Mat.GetForward().Length(); - float LenUp = Mat.GetUp().Length(); - float LenLeft = Mat.GetLeft().Length(); - float DotFwdUp = Mat.GetForward().Dot ( Mat.GetUp() ); - float DotUpLeft = Mat.GetUp().Dot ( Mat.GetLeft() ); - float DotLeftFwd = Mat.GetLeft().Dot ( Mat.GetForward() ); - if ( fabsf ( LenFwd - 1.0f ) > fTolerance ) - { - return false; - } - if ( fabsf ( LenUp - 1.0f ) > fTolerance ) - { - return false; - } - if ( fabsf ( LenLeft - 1.0f ) > fTolerance ) - { - return false; - } - if ( fabsf ( DotFwdUp ) > fTolerance ) - { - return false; - } - if ( fabsf ( DotUpLeft ) > fTolerance ) - { - return false; - } - if ( fabsf ( DotLeftFwd ) > fTolerance ) - { - return false; - } - return true; -} - - -// -------------------------------------------------------------------- -// Purpose: Computes the FOV from the projection matrix -// -------------------------------------------------------------------- -void CalcFovFromProjection ( float *pFov, const VMatrix &proj ) -{ - // The projection matrices should be of the form: - // p0 0 z1 p1 - // 0 p2 z2 p3 - // 0 0 z3 1 - // (p0 = X fov, p1 = X offset, p2 = Y fov, p3 = Y offset ) - // TODO: cope with more complex projection matrices? - float xscale = proj.m[0][0]; - Assert ( proj.m[0][1] == 0.0f ); - float xoffset = proj.m[0][2]; - Assert ( proj.m[0][3] == 0.0f ); - Assert ( proj.m[1][0] == 0.0f ); - float yscale = proj.m[1][1]; - float yoffset = proj.m[1][2]; - Assert ( proj.m[1][3] == 0.0f ); - // Row 2 determines Z-buffer values - don't care about those for now. - Assert ( proj.m[3][0] == 0.0f ); - Assert ( proj.m[3][1] == 0.0f ); - Assert ( proj.m[3][2] == -1.0f ); - Assert ( proj.m[3][3] == 0.0f ); - - // The math here: - // A view-space vector (x,y,z,1) is transformed by the projection matrix - // / xscale 0 xoffset 0 \ - // | 0 yscale yoffset 0 | - // | ? ? ? ? | - // \ 0 0 -1 0 / - // - // Then the result is normalized (i.e. divide by w) and the result clipped to the [-1,+1] unit cube. - // (ignore Z for now, and the clipping is slightly different). - // So, we want to know what vectors produce a clip value of -1 and +1 in each direction, e.g. in the X direction: - // +-1 = ( xscale*x + xoffset*z ) / (-1*z) - // = xscale*(x/z) + xoffset (I flipped the signs of both sides) - // => (+-1 - xoffset)/xscale = x/z - // ...and x/z is tan(theta), and theta is the half-FOV. - - float fov_px = 2.0f * RAD2DEG ( atanf ( fabsf ( ( 1.0f - xoffset ) / xscale ) ) ); - float fov_nx = 2.0f * RAD2DEG ( atanf ( fabsf ( ( -1.0f - xoffset ) / xscale ) ) ); - float fov_py = 2.0f * RAD2DEG ( atanf ( fabsf ( ( 1.0f - yoffset ) / yscale ) ) ); - float fov_ny = 2.0f * RAD2DEG ( atanf ( fabsf ( ( -1.0f - yoffset ) / yscale ) ) ); - - *pFov = Max ( Max ( fov_px, fov_nx ), Max ( fov_py, fov_ny ) ); - // FIXME: hey you know, I could do the Max() series before I call all those expensive atanf()s... -} - - -// -------------------------------------------------------------------- -// construction/destruction -// -------------------------------------------------------------------- -CClientVirtualReality::CClientVirtualReality() -{ - m_PlayerTorsoOrigin.Init(); - m_PlayerTorsoAngle.Init(); - m_WorldFromWeapon.Identity(); - m_WorldFromMidEye.Identity(); - - m_bOverrideTorsoAngle = false; - m_OverrideTorsoOffset.Init(); - - // Also reset our model of the player's torso orientation - m_PlayerTorsoAngle.Init ( 0.0f, 0.0f, 0.0f ); - - m_WorldZoomScale = 1.0f; - m_hmmMovementActual = HMM_SHOOTFACE_MOVEFACE; - m_iAlignTorsoAndViewToWeaponCountdown = 0; - - m_rtLastMotionSample = 0; - m_bMotionUpdated = false; - -#if defined( USE_SDL ) - m_nNonVRSDLDisplayIndex = 0; -#endif -} - -CClientVirtualReality::~CClientVirtualReality() -{ -} - - -// -------------------------------------------------------------------- -// Purpose: -// -------------------------------------------------------------------- -bool CClientVirtualReality::Connect( CreateInterfaceFn factory ) -{ - if ( !factory ) - return false; - - if ( !BaseClass::Connect( factory ) ) - return false; - - return true; -} - - -// -------------------------------------------------------------------- -// Purpose: -// -------------------------------------------------------------------- -void CClientVirtualReality::Disconnect() -{ - BaseClass::Disconnect(); -} - - -// -------------------------------------------------------------------- -// Purpose: -// -------------------------------------------------------------------- -void * CClientVirtualReality::QueryInterface( const char *pInterfaceName ) -{ - CreateInterfaceFn factory = Sys_GetFactoryThis(); // This silly construction is necessary - return factory( pInterfaceName, NULL ); // to prevent the LTCG compiler from crashing. -} - - -// -------------------------------------------------------------------- -// Purpose: -// -------------------------------------------------------------------- -InitReturnVal_t CClientVirtualReality::Init() -{ - InitReturnVal_t nRetVal = BaseClass::Init(); - if ( nRetVal != INIT_OK ) - return nRetVal; - - return INIT_OK; -} - - -// -------------------------------------------------------------------- -// Purpose: -// -------------------------------------------------------------------- -void CClientVirtualReality::Shutdown() -{ - BaseClass::Shutdown(); -} - - -// -------------------------------------------------------------------- -// Purpose: Draws the main menu in Stereo -// -------------------------------------------------------------------- -void CClientVirtualReality::DrawMainMenu() -{ - // have to draw the UI in stereo via the render texture or it won't fuse properly - - // Draw it into the render target first - ITexture *pTexture = materials->FindTexture( "_rt_gui", NULL, false ); - Assert( pTexture ); - if( !pTexture) - return; - - CMatRenderContextPtr pRenderContext( materials ); - int viewActualWidth = pTexture->GetActualWidth(); - int viewActualHeight = pTexture->GetActualHeight(); - - int viewWidth, viewHeight; - vgui::surface()->GetScreenSize( viewWidth, viewHeight ); - - // clear depth in the backbuffer before we push the render target - pRenderContext->ClearBuffers( false, true, true ); - - // constrain where VGUI can render to the view - pRenderContext->PushRenderTargetAndViewport( pTexture, NULL, 0, 0, viewActualWidth, viewActualHeight ); - pRenderContext->OverrideAlphaWriteEnable( true, true ); - - // clear the render target - pRenderContext->ClearColor4ub( 0, 0, 0, 0 ); - pRenderContext->ClearBuffers( true, false ); - - tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "VGui_DrawHud", __FUNCTION__ ); - - // Make sure the client .dll root panel is at the proper point before doing the "SolveTraverse" calls - vgui::VPANEL root = enginevgui->GetPanel( PANEL_CLIENTDLL ); - if ( root != 0 ) - { - vgui::ipanel()->SetSize( root, viewWidth, viewHeight ); - } - // Same for client .dll tools - root = enginevgui->GetPanel( PANEL_CLIENTDLL_TOOLS ); - if ( root != 0 ) - { - vgui::ipanel()->SetSize( root, viewWidth, viewHeight ); - } - - // paint the main menu and cursor - render->VGui_Paint( (PaintMode_t) ( PAINT_UIPANELS | PAINT_CURSOR ) ); - - pRenderContext->OverrideAlphaWriteEnable( false, true ); - pRenderContext->PopRenderTargetAndViewport(); - pRenderContext->Flush(); - - int leftX, leftY, leftW, leftH, rightX, rightY, rightW, rightH; - g_pSourceVR->GetViewportBounds( ISourceVirtualReality::VREye_Left, &leftX, &leftY, &leftW, &leftH ); - g_pSourceVR->GetViewportBounds( ISourceVirtualReality::VREye_Right, &rightX, &rightY, &rightW, &rightH ); - - - // render the main view - CViewSetup viewEye[STEREO_EYE_MAX]; - viewEye[ STEREO_EYE_MONO ].zNear = 0.1; - viewEye[ STEREO_EYE_MONO ].zFar = 10000.f; - viewEye[ STEREO_EYE_MONO ].angles.Init(); - viewEye[ STEREO_EYE_MONO ].origin.Zero(); - viewEye[ STEREO_EYE_MONO ].x = viewEye[ STEREO_EYE_MONO ].m_nUnscaledX = leftX; - viewEye[ STEREO_EYE_MONO ].y = viewEye[ STEREO_EYE_MONO ].m_nUnscaledY = leftY; - viewEye[ STEREO_EYE_MONO ].width = viewEye[ STEREO_EYE_MONO ].m_nUnscaledWidth = leftW; - viewEye[ STEREO_EYE_MONO ].height = viewEye[ STEREO_EYE_MONO ].m_nUnscaledHeight = leftH; - - viewEye[STEREO_EYE_LEFT] = viewEye[STEREO_EYE_RIGHT] = viewEye[ STEREO_EYE_MONO ] ; - viewEye[STEREO_EYE_LEFT].m_eStereoEye = STEREO_EYE_LEFT; - viewEye[STEREO_EYE_RIGHT].x = rightX; - viewEye[STEREO_EYE_RIGHT].y = rightY; - viewEye[STEREO_EYE_RIGHT].m_eStereoEye = STEREO_EYE_RIGHT; - - // let sourcevr.dll tell us where to put the cameras - ProcessCurrentTrackingState( 0 ); - Vector vViewModelOrigin; - QAngle qViewModelAngles; - OverrideView( &viewEye[ STEREO_EYE_MONO ] , &vViewModelOrigin, &qViewModelAngles, HMM_NOOVERRIDE ); - g_ClientVirtualReality.OverrideStereoView( &viewEye[ STEREO_EYE_MONO ] , &viewEye[STEREO_EYE_LEFT], &viewEye[STEREO_EYE_RIGHT] ); - - // render both eyes - for( int nView = STEREO_EYE_LEFT; nView <= STEREO_EYE_RIGHT; nView++ ) - { - CMatRenderContextPtr pRenderContext( materials ); - PIXEvent pixEvent( pRenderContext, nView == STEREO_EYE_LEFT ? "left eye" : "right eye" ); - - ITexture *pColor = g_pSourceVR->GetRenderTarget( (ISourceVirtualReality::VREye)(nView-1), ISourceVirtualReality::RT_Color ); - ITexture *pDepth = g_pSourceVR->GetRenderTarget( (ISourceVirtualReality::VREye)(nView-1), ISourceVirtualReality::RT_Depth ); - render->Push3DView( viewEye[nView], VIEW_CLEAR_DEPTH|VIEW_CLEAR_COLOR, pColor, NULL, pDepth ); - RenderHUDQuad( false, false ); - render->PopView( NULL ); - - PostProcessFrame( (StereoEye_t)nView ); - - OverlayHUDQuadWithUndistort( viewEye[nView], true, true, false ); - } -} - - -// -------------------------------------------------------------------- -// Purpose: -// Offset the incoming view appropriately. -// Set up the "middle eye" from that. -// -------------------------------------------------------------------- -bool CClientVirtualReality::OverrideView ( CViewSetup *pViewMiddle, Vector *pViewModelOrigin, QAngle *pViewModelAngles, HeadtrackMovementMode_t hmmMovementOverride ) -{ - if( !UseVR() ) - { - return false; - } - - if ( hmmMovementOverride == HMM_NOOVERRIDE ) - { - if ( CurrentlyZoomed() ) - { - m_hmmMovementActual = static_cast( vr_moveaim_mode_zoom.GetInt() ); - } - else - { - m_hmmMovementActual = static_cast( vr_moveaim_mode.GetInt() ); - } - } - else - { - m_hmmMovementActual = hmmMovementOverride; - } - - - // Incoming data may or may not be useful - it is the origin and aim of the "player", i.e. where bullets come from. - // In some modes it is an independent thing, guided by the mouse & keyboard = useful. - // In other modes it's just where the HMD was pointed last frame, modified slightly by kbd+mouse. - // In those cases, we should use our internal reference (which keeps track thanks to OverridePlayerMotion) - QAngle originalMiddleAngles = pViewMiddle->angles; - Vector originalMiddleOrigin = pViewMiddle->origin; - - // Figure out the in-game "torso" concept, which corresponds to the player's physical torso. - m_PlayerTorsoOrigin = pViewMiddle->origin; - - // Ignore what was passed in - it's just the direction the weapon is pointing, which was determined by last frame's HMD orientation! - // Instead use our cached value. - QAngle torsoAngles = m_PlayerTorsoAngle; - - VMatrix worldFromTorso; - worldFromTorso.SetupMatrixOrgAngles( m_PlayerTorsoOrigin, torsoAngles ); - - //// Scale translation e.g. to allow big in-game leans with only a small head movement. - //// Clamp HMD movement to a reasonable amount to avoid wallhacks, vis problems, etc. - float limit = vr_translation_limit.GetFloat(); - VMatrix matMideyeZeroFromMideyeCurrent = g_pSourceVR->GetMideyePose(); - Vector viewTranslation = matMideyeZeroFromMideyeCurrent.GetTranslation(); - if ( viewTranslation.IsLengthGreaterThan ( limit ) ) - { - viewTranslation.NormalizeInPlace(); - viewTranslation *= limit; - matMideyeZeroFromMideyeCurrent.SetTranslation( viewTranslation ); - } - - // Now figure out the three principal matrices: m_TorsoFromMideye, m_WorldFromMidEye, m_WorldFromWeapon - // m_TorsoFromMideye is done so that OverridePlayerMotion knows what to do with WASD. - - switch ( m_hmmMovementActual ) - { - case HMM_SHOOTFACE_MOVEFACE: - case HMM_SHOOTFACE_MOVETORSO: - // Aim point is down your nose, i.e. same as the view angles. - m_TorsoFromMideye = matMideyeZeroFromMideyeCurrent; - m_WorldFromMidEye = worldFromTorso * matMideyeZeroFromMideyeCurrent; - m_WorldFromWeapon = m_WorldFromMidEye; - break; - - case HMM_SHOOTBOUNDEDMOUSE_LOOKFACE_MOVEFACE: - case HMM_SHOOTBOUNDEDMOUSE_LOOKFACE_MOVEMOUSE: - case HMM_SHOOTMOUSE_MOVEFACE: - case HMM_SHOOTMOVEMOUSE_LOOKFACE: - // Aim point is independent of view - leave it as it was, just copy it into m_WorldFromWeapon for our use. - m_TorsoFromMideye = matMideyeZeroFromMideyeCurrent; - m_WorldFromMidEye = worldFromTorso * matMideyeZeroFromMideyeCurrent; - m_WorldFromWeapon.SetupMatrixOrgAngles( originalMiddleOrigin, originalMiddleAngles ); - break; - - case HMM_SHOOTMOVELOOKMOUSE: - // HMD is ignored completely, mouse does everything. - m_PlayerTorsoAngle = originalMiddleAngles; - - worldFromTorso.SetupMatrixOrgAngles( m_PlayerTorsoOrigin, originalMiddleAngles ); - - m_TorsoFromMideye.Identity(); - m_WorldFromMidEye = worldFromTorso; - m_WorldFromWeapon = worldFromTorso; - break; - - case HMM_SHOOTMOVELOOKMOUSEFACE: - // mouse does everything, and then we add head tracking on top of that - worldFromTorso = worldFromTorso * matMideyeZeroFromMideyeCurrent; - - m_TorsoFromMideye = matMideyeZeroFromMideyeCurrent; - m_WorldFromWeapon = worldFromTorso; - m_WorldFromMidEye = worldFromTorso; - break; - - default: Assert ( false ); break; - } - - // Finally convert back to origin+angles that the game understands. - pViewMiddle->origin = m_WorldFromMidEye.GetTranslation(); - VectorAngles ( m_WorldFromMidEye.GetForward(), m_WorldFromMidEye.GetUp(), pViewMiddle->angles ); - - *pViewModelAngles = pViewMiddle->angles; - if ( vr_viewmodel_translate_with_head.GetBool() ) - { - *pViewModelOrigin = pViewMiddle->origin; - } - else - { - *pViewModelOrigin = originalMiddleOrigin; - } - - m_WorldFromMidEyeNoDebugCam = m_WorldFromMidEye; - if ( vr_debug_remote_cam.GetBool() ) - { - Vector vOffset ( vr_debug_remote_cam_pos_x.GetFloat(), vr_debug_remote_cam_pos_y.GetFloat(), vr_debug_remote_cam_pos_z.GetFloat() ); - Vector vLookat ( vr_debug_remote_cam_target_x.GetFloat(), vr_debug_remote_cam_target_y.GetFloat(), vr_debug_remote_cam_target_z.GetFloat() ); - pViewMiddle->origin += vOffset; - Vector vView = vLookat - vOffset; - VectorAngles ( vView, m_WorldFromMidEye.GetUp(), pViewMiddle->angles ); - - m_WorldFromMidEye.SetupMatrixOrgAngles( pViewMiddle->origin, pViewMiddle->angles ); - - m_TorsoFromMideye.Identity(); - } - - // set the near clip plane so the local player clips less - pViewMiddle->zNear *= vr_projection_znear_multiplier.GetFloat(); - - return true; -} - - -// -------------------------------------------------------------------- -// Purpose: -// In some aim/move modes, the HUD aim reticle lags because it's -// using slightly stale data. This will feed it the newest data. -// -------------------------------------------------------------------- -bool CClientVirtualReality::OverrideWeaponHudAimVectors ( Vector *pAimOrigin, Vector *pAimDirection ) -{ - if( !UseVR() ) - { - return false; - } - - Assert ( pAimOrigin != NULL ); - Assert ( pAimDirection != NULL ); - - // So give it some nice high-fps numbers, not the low-fps ones we get from the game. - *pAimOrigin = m_WorldFromWeapon.GetTranslation(); - *pAimDirection = m_WorldFromWeapon.GetForward(); - - return true; -} - - -// -------------------------------------------------------------------- -// Purpose: -// Set up the left and right eyes from the middle eye if stereo is on. -// Advise calling soonish after OverrideView(). -// -------------------------------------------------------------------- -bool CClientVirtualReality::OverrideStereoView( CViewSetup *pViewMiddle, CViewSetup *pViewLeft, CViewSetup *pViewRight ) -{ - // Everything in here is in Source coordinate space. - if( !UseVR() ) - { - return false; - } - - VMatrix matOffsetLeft = g_pSourceVR->GetMidEyeFromEye( ISourceVirtualReality::VREye_Left ); - VMatrix matOffsetRight = g_pSourceVR->GetMidEyeFromEye( ISourceVirtualReality::VREye_Right ); - - // Move eyes to IPD positions. - VMatrix worldFromLeftEye = m_WorldFromMidEye * matOffsetLeft; - VMatrix worldFromRightEye = m_WorldFromMidEye * matOffsetRight; - - Assert ( IsOrthonormal ( worldFromLeftEye, 0.001f ) ); - Assert ( IsOrthonormal ( worldFromRightEye, 0.001f ) ); - - // Finally convert back to origin+angles. - MatrixAngles( worldFromLeftEye.As3x4(), pViewLeft->angles, pViewLeft->origin ); - MatrixAngles( worldFromRightEye.As3x4(), pViewRight->angles, pViewRight->origin ); - - // Find the projection matrices. - - // TODO: this isn't the fastest thing in the world. Cache them? - float headtrackFovScale = m_WorldZoomScale; - pViewLeft->m_bViewToProjectionOverride = true; - pViewRight->m_bViewToProjectionOverride = true; - g_pSourceVR->GetEyeProjectionMatrix ( &pViewLeft->m_ViewToProjection, ISourceVirtualReality::VREye_Left, pViewMiddle->zNear, pViewMiddle->zFar, 1.0f/headtrackFovScale ); - g_pSourceVR->GetEyeProjectionMatrix ( &pViewRight->m_ViewToProjection, ISourceVirtualReality::VREye_Right, pViewMiddle->zNear, pViewMiddle->zFar, 1.0f/headtrackFovScale ); - - // And bodge together some sort of average for our cyclops friends. - pViewMiddle->m_bViewToProjectionOverride = true; - for ( int i = 0; i < 4; i++ ) - { - for ( int j = 0; j < 4; j++ ) - { - pViewMiddle->m_ViewToProjection.m[i][j] = (pViewLeft->m_ViewToProjection.m[i][j] + pViewRight->m_ViewToProjection.m[i][j] ) * 0.5f; - } - } - - switch ( vr_stereo_mono_set_eye.GetInt() ) - { - case 0: - // ... nothing. - break; - case 1: - // Override all eyes with left - *pViewMiddle = *pViewLeft; - *pViewRight = *pViewLeft; - pViewRight->m_eStereoEye = STEREO_EYE_RIGHT; - break; - case 2: - // Override all eyes with right - *pViewMiddle = *pViewRight; - *pViewLeft = *pViewRight; - pViewLeft->m_eStereoEye = STEREO_EYE_LEFT; - break; - case 3: - // Override all eyes with middle - *pViewRight = *pViewMiddle; - *pViewLeft = *pViewMiddle; - pViewLeft->m_eStereoEye = STEREO_EYE_LEFT; - pViewRight->m_eStereoEye = STEREO_EYE_RIGHT; - break; - } - - // To make culling work correctly, calculate the widest FOV of each projection matrix. - CalcFovFromProjection ( &(pViewLeft ->fov), pViewLeft ->m_ViewToProjection ); - CalcFovFromProjection ( &(pViewRight ->fov), pViewRight ->m_ViewToProjection ); - CalcFovFromProjection ( &(pViewMiddle->fov), pViewMiddle->m_ViewToProjection ); - - // if we don't know the HUD FOV, figure that out now - if( m_fHudHorizontalFov == 0.f ) - { - // Figure out the current HUD FOV. - m_fHudHorizontalFov = pViewLeft->fov * vr_hud_display_ratio.GetFloat(); - if( m_fHudHorizontalFov > vr_hud_max_fov.GetFloat() ) - { - m_fHudHorizontalFov = vr_hud_max_fov.GetFloat(); - } - } - - // remember the view angles so we can limit the weapon to something near those - m_PlayerViewAngle = pViewMiddle->angles; - m_PlayerViewOrigin = pViewMiddle->origin; - - - - // Figure out the HUD vectors and frustum. - - // The aspect ratio of the HMD may be something bizarre (e.g. Rift is 640x800), and the pixels may not be square, so don't use that! - static const float fAspectRatio = 4.f/3.f; - float fHFOV = m_fHudHorizontalFov; - float fVFOV = m_fHudHorizontalFov / fAspectRatio; - - const float fHudForward = vr_hud_forward.GetFloat(); - m_fHudHalfWidth = tan( DEG2RAD( fHFOV * 0.5f ) ) * fHudForward * m_WorldZoomScale; - m_fHudHalfHeight = tan( DEG2RAD( fVFOV * 0.5f ) ) * fHudForward * m_WorldZoomScale; - - QAngle HudAngles; - switch ( m_hmmMovementActual ) - { - case HMM_SHOOTFACE_MOVETORSO: - // Put the HUD in front of the player's torso. - // This helps keep you oriented about where "forwards" is, which is otherwise surprisingly tricky! - // TODO: try preserving roll and/or pitch from the view? - HudAngles = m_PlayerTorsoAngle; - break; - case HMM_SHOOTFACE_MOVEFACE: - case HMM_SHOOTMOUSE_MOVEFACE: - case HMM_SHOOTMOVEMOUSE_LOOKFACE: - case HMM_SHOOTMOVELOOKMOUSE: - case HMM_SHOOTMOVELOOKMOUSEFACE: - case HMM_SHOOTBOUNDEDMOUSE_LOOKFACE_MOVEFACE: - case HMM_SHOOTBOUNDEDMOUSE_LOOKFACE_MOVEMOUSE: - // Put the HUD in front of wherever the player is looking. - HudAngles = m_PlayerViewAngle; - break; - default: Assert ( false ); break; - } - - // This is a bitfield. A set bit means lock to the world, a clear bit means don't. - int iVrHudAxisLockToWorld = vr_hud_axis_lock_to_world.GetInt(); - if ( ( iVrHudAxisLockToWorld & (1< 180.0f ) - { - fReticleYawLimit = 180.0f; - } - if ( fReticlePitchLimit > 180.0f ) - { - fReticlePitchLimit = 180.0f; - } - } - - if ( fReticlePitchLimit >= 0.0f ) - { - // Clamp pitch to within the limits. - (*pNewAngles)[PITCH] = Clamp ( curAngles[PITCH], m_PlayerViewAngle[PITCH] - fReticlePitchLimit, m_PlayerViewAngle[PITCH] + fReticlePitchLimit ); - } - - // For yaw the concept here is the torso stays within a set number of degrees of the weapon in yaw. - // However, with drifty tracking systems (e.g. IMUs) the concept of "torso" is hazy. - // Really it's just a mechanism to turn the view without moving the head - its absolute - // orientation is not that useful. - // So... if the mouse is to the right greater than the chosen angle from the view, and then - // moves more right, it will drag the torso (and thus the view) right, so it stays on the edge of the view. - // But if it moves left towards the view, it does no dragging. - // Note that if the mouse does not move, but the view moves, it will NOT drag at all. - // This allows people to mouse-aim within their view, but also to flick-turn with the mouse, - // and to flick-glance with the head. - if ( fReticleYawLimit >= 0.0f ) - { - float fViewToWeaponYaw = AngleDiff ( curAngles[YAW], m_PlayerViewAngle[YAW] ); - float fWeaponYawMovement = AngleDiff ( curAngles[YAW], oldAngles[YAW] ); - if ( fViewToWeaponYaw > fReticleYawLimit ) - { - if ( fWeaponYawMovement > 0.0f ) - { - m_PlayerTorsoAngle[YAW] += fWeaponYawMovement; - } - } - else if ( fViewToWeaponYaw < -fReticleYawLimit ) - { - if ( fWeaponYawMovement < 0.0f ) - { - m_PlayerTorsoAngle[YAW] += fWeaponYawMovement; - } - } - } - - // Let every other system know. - m_WorldFromWeapon.SetupMatrixOrgAngles( vWeaponOrigin, *pNewAngles ); - worldFromTorso.SetupMatrixAngles( m_PlayerTorsoAngle ); - } - break; - case HMM_SHOOTMOUSE_MOVEFACE: - { - (*pNewAngles)[PITCH] = clamp( (*pNewAngles)[PITCH], m_PlayerViewAngle[PITCH]-15.f, m_PlayerViewAngle[PITCH]+15.f ); - - float fDiff = AngleDiff( (*pNewAngles)[YAW], m_PlayerViewAngle[YAW] ); - - if( fDiff > 15.f ) - { - (*pNewAngles)[YAW] = AngleNormalize( m_PlayerViewAngle[YAW] + 15.f ); - if( !m_bOverrideTorsoAngle ) - m_PlayerTorsoAngle[ YAW ] += fDiff - 15.f; - } - else if( fDiff < -15.f ) - { - (*pNewAngles)[YAW] = AngleNormalize( m_PlayerViewAngle[YAW] - 15.f ); - if( !m_bOverrideTorsoAngle ) - m_PlayerTorsoAngle[ YAW ] += fDiff + 15.f; - } - else - { - m_PlayerTorsoAngle[ YAW ] += AngleDiff( curAngles[YAW], oldAngles[YAW] ) /2.f; - } - - m_WorldFromWeapon.SetupMatrixOrgAngles( vWeaponOrigin, *pNewAngles ); - worldFromTorso.SetupMatrixAngles( m_PlayerTorsoAngle ); - } - break; - default: Assert ( false ); break; - } - - // Figure out player motion. - switch ( m_hmmMovementActual ) - { - case HMM_SHOOTBOUNDEDMOUSE_LOOKFACE_MOVEFACE: - { - // The motion passed in is meant to be relative to the face, so jimmy it to be relative to the new weapon aim. - VMatrix mideyeFromWorld = m_WorldFromMidEye.InverseTR(); - VMatrix newMidEyeFromWeapon = mideyeFromWorld * m_WorldFromWeapon; - newMidEyeFromWeapon.SetTranslation ( Vector ( 0.0f, 0.0f, 0.0f ) ); - *pNewMotion = newMidEyeFromWeapon * curMotion; - } - break; - case HMM_SHOOTFACE_MOVETORSO: - { - // The motion passed in is meant to be relative to the torso, so jimmy it to be relative to the new weapon aim. - VMatrix torsoFromWorld = worldFromTorso.InverseTR(); - VMatrix newTorsoFromWeapon = torsoFromWorld * m_WorldFromWeapon; - newTorsoFromWeapon.SetTranslation ( Vector ( 0.0f, 0.0f, 0.0f ) ); - *pNewMotion = newTorsoFromWeapon * curMotion; - } - break; - case HMM_SHOOTBOUNDEDMOUSE_LOOKFACE_MOVEMOUSE: - case HMM_SHOOTMOVELOOKMOUSEFACE: - case HMM_SHOOTFACE_MOVEFACE: - case HMM_SHOOTMOUSE_MOVEFACE: - case HMM_SHOOTMOVEMOUSE_LOOKFACE: - case HMM_SHOOTMOVELOOKMOUSE: - // Motion is meant to be relative to the weapon, so we're fine. - *pNewMotion = curMotion; - break; - default: Assert ( false ); break; - } - - // If the game told us to, recenter the torso yaw to match the weapon - if ( m_iAlignTorsoAndViewToWeaponCountdown > 0 ) - { - m_iAlignTorsoAndViewToWeaponCountdown--; - - // figure out the angles from the torso to the head - QAngle torsoFromHeadAngles; - MatrixAngles( m_TorsoFromMideye.As3x4(), torsoFromHeadAngles ); - - QAngle weaponAngles; - MatrixAngles( m_WorldFromWeapon.As3x4(), weaponAngles ); - m_PlayerTorsoAngle[ YAW ] = weaponAngles[ YAW ] - torsoFromHeadAngles[ YAW ] ; - NormalizeAngles( m_PlayerTorsoAngle ); - } - - // remember the motion for stat tracking - m_PlayerLastMovement = *pNewMotion; - - - - return true; -} - -// -------------------------------------------------------------------- -// Purpose: Returns true if the world is zoomed -// -------------------------------------------------------------------- -bool CClientVirtualReality::CurrentlyZoomed() -{ - return ( m_WorldZoomScale != 1.0f ); -} - - -// -------------------------------------------------------------------- -// Purpose: Tells the headtracker to keep the torso angle of the player -// fixed at this point until the game tells us something -// different. -// -------------------------------------------------------------------- -void CClientVirtualReality::OverrideTorsoTransform( const Vector & position, const QAngle & angles ) -{ - if( m_iAlignTorsoAndViewToWeaponCountdown > 0 ) - { - m_iAlignTorsoAndViewToWeaponCountdown--; - - // figure out the angles from the torso to the head - QAngle torsoFromHeadAngles; - MatrixAngles( m_TorsoFromMideye.As3x4(), torsoFromHeadAngles ); - - // this is how far off the torso we actually set will need to be to keep the current "forward" - // vector while the torso angle is being overridden. - m_OverrideTorsoOffset[ YAW ] = -torsoFromHeadAngles[ YAW ]; - } - - m_bOverrideTorsoAngle = true; - m_OverrideTorsoAngle = angles + m_OverrideTorsoOffset; - - // overriding pitch and roll isn't allowed to avoid making people sick - m_OverrideTorsoAngle[ PITCH ] = 0; - m_OverrideTorsoAngle[ ROLL ] = 0; - - NormalizeAngles( m_OverrideTorsoAngle ); - - m_PlayerTorsoAngle = m_OverrideTorsoAngle; -} - - -// -------------------------------------------------------------------- -// Purpose: Tells the headtracker to resume using its own notion of -// where the torso is pointed. -// -------------------------------------------------------------------- -void CClientVirtualReality::CancelTorsoTransformOverride() -{ - m_bOverrideTorsoAngle = false; -} - - -bool CClientVirtualReality::CanOverlayHudQuad() -{ - bool bCanOverlay = true; - - bCanOverlay = bCanOverlay && vr_render_hud_in_world.GetBool(); - bCanOverlay = bCanOverlay && ( ! vr_hud_never_overlay.GetBool() ); - bCanOverlay = bCanOverlay && ( vr_hud_axis_lock_to_world.GetInt() == 0 ); - bCanOverlay = bCanOverlay && ( m_hmmMovementActual != HMM_SHOOTFACE_MOVETORSO ); - - return bCanOverlay; -} - - -// -------------------------------------------------------------------- -// Purpose: Returns the bounds in world space where the game should -// position the HUD. -// -------------------------------------------------------------------- -void CClientVirtualReality::GetHUDBounds( Vector *pViewer, Vector *pUL, Vector *pUR, Vector *pLL, Vector *pLR ) -{ - Vector vHalfWidth = m_WorldFromHud.GetLeft() * -m_fHudHalfWidth; - Vector vHalfHeight = m_WorldFromHud.GetUp() * m_fHudHalfHeight; - Vector vHUDOrigin = m_PlayerViewOrigin + m_WorldFromHud.GetForward() * vr_hud_forward.GetFloat(); - - *pViewer = m_PlayerViewOrigin; - *pUL = vHUDOrigin - vHalfWidth + vHalfHeight; - *pUR = vHUDOrigin + vHalfWidth + vHalfHeight; - *pLL = vHUDOrigin - vHalfWidth - vHalfHeight; - *pLR = vHUDOrigin + vHalfWidth - vHalfHeight; -} - - -// -------------------------------------------------------------------- -// Purpose: Renders the HUD in the world. -// -------------------------------------------------------------------- -void CClientVirtualReality::RenderHUDQuad( bool bBlackout, bool bTranslucent ) -{ - // If we can overlay the HUD directly onto the target later, we'll do that instead (higher image quality). - if ( CanOverlayHudQuad() ) - return; - - Vector vHead, vUL, vUR, vLL, vLR; - GetHUDBounds ( &vHead, &vUL, &vUR, &vLL, &vLR ); - - CMatRenderContextPtr pRenderContext( materials ); - - { - IMaterial *mymat = NULL; - if ( bTranslucent ) - { - mymat = materials->FindMaterial( "vgui/inworldui", TEXTURE_GROUP_VGUI ); - } - else - { - mymat = materials->FindMaterial( "vgui/inworldui_opaque", TEXTURE_GROUP_VGUI ); - } - Assert( !mymat->IsErrorMaterial() ); - - IMesh *pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, mymat ); - - CMeshBuilder meshBuilder; - meshBuilder.Begin( pMesh, MATERIAL_TRIANGLE_STRIP, 2 ); - - meshBuilder.Position3fv (vLR.Base() ); - meshBuilder.TexCoord2f( 0, 1, 1 ); - meshBuilder.AdvanceVertexF(); - - meshBuilder.Position3fv (vLL.Base()); - meshBuilder.TexCoord2f( 0, 0, 1 ); - meshBuilder.AdvanceVertexF(); - - meshBuilder.Position3fv (vUR.Base()); - meshBuilder.TexCoord2f( 0, 1, 0 ); - meshBuilder.AdvanceVertexF(); - - meshBuilder.Position3fv (vUL.Base()); - meshBuilder.TexCoord2f( 0, 0, 0 ); - meshBuilder.AdvanceVertexF(); - - meshBuilder.End(); - pMesh->Draw(); - } - - if( bBlackout ) - { - Vector vbUL, vbUR, vbLL, vbLR; - // "Reflect" the HUD bounds through the viewer to find the ones behind the head. - vbUL = 2 * vHead - vLR; - vbUR = 2 * vHead - vLL; - vbLL = 2 * vHead - vUR; - vbLR = 2 * vHead - vUL; - - IMaterial *mymat = materials->FindMaterial( "vgui/black", TEXTURE_GROUP_VGUI ); - IMesh *pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, mymat ); - - // Tube around the outside. - CMeshBuilder meshBuilder; - meshBuilder.Begin( pMesh, MATERIAL_TRIANGLE_STRIP, 8 ); - - meshBuilder.Position3fv (vLR.Base()); - meshBuilder.AdvanceVertexF(); - - meshBuilder.Position3fv (vbLR.Base() ); - meshBuilder.AdvanceVertexF(); - - meshBuilder.Position3fv (vLL.Base()); - meshBuilder.AdvanceVertexF(); - - meshBuilder.Position3fv (vbLL.Base()); - meshBuilder.AdvanceVertexF(); - - meshBuilder.Position3fv (vUL.Base()); - meshBuilder.AdvanceVertexF(); - - meshBuilder.Position3fv (vbUL.Base()); - meshBuilder.AdvanceVertexF(); - - meshBuilder.Position3fv (vUR.Base()); - meshBuilder.AdvanceVertexF(); - - meshBuilder.Position3fv (vbUR.Base()); - meshBuilder.AdvanceVertexF(); - - meshBuilder.Position3fv (vLR.Base()); - meshBuilder.AdvanceVertexF(); - - meshBuilder.Position3fv (vbLR.Base()); - meshBuilder.AdvanceVertexF(); - - meshBuilder.End(); - pMesh->Draw(); - - // Cap behind the viewer. - meshBuilder.Begin( pMesh, MATERIAL_TRIANGLE_STRIP, 2 ); - - meshBuilder.Position3fv (vbUR.Base() ); - meshBuilder.AdvanceVertexF(); - - meshBuilder.Position3fv (vbUL.Base()); - meshBuilder.AdvanceVertexF(); - - meshBuilder.Position3fv (vbLR.Base()); - meshBuilder.AdvanceVertexF(); - - meshBuilder.Position3fv (vbLL.Base()); - meshBuilder.AdvanceVertexF(); - - meshBuilder.End(); - pMesh->Draw(); - } -} - - -// -------------------------------------------------------------------- -// Purpose: Gets the amount of zoom to apply -// -------------------------------------------------------------------- -float CClientVirtualReality::GetZoomedModeMagnification() -{ - return m_WorldZoomScale * vr_zoom_scope_scale.GetFloat(); -} - - -// -------------------------------------------------------------------- -// Purpose: Does some client-side tracking work and then tells headtrack -// to do its own work. -// -------------------------------------------------------------------- -bool CClientVirtualReality::ProcessCurrentTrackingState( float fGameFOV ) -{ - m_WorldZoomScale = 1.0f; - if ( fGameFOV != 0.0f ) - { - // To compensate for the lack of pixels on most HUDs, let's grow this a bit. - // Remember that MORE zoom equals LESS fov! - fGameFOV *= ( 1.0f / vr_zoom_multiplier.GetFloat() ); - fGameFOV = Min ( fGameFOV, 170.0f ); - - // The game has overridden the FOV, e.g. because of a sniper scope. So we need to match this view with whatever actual FOV the HUD has. - float wantedGameTanfov = tanf ( DEG2RAD ( fGameFOV * 0.5f ) ); - // OK, so now in stereo mode, we're going to also draw an overlay, but that overlay usually covers more of the screen (because in a good HMD usually our actual FOV is much wider) - float overlayActualPhysicalTanfov = tanf ( DEG2RAD ( m_fHudHorizontalFov * 0.5f ) ); - // Therefore... (remembering that a zoom > 1.0 means you zoom *out*) - m_WorldZoomScale = wantedGameTanfov / overlayActualPhysicalTanfov; - } - - return g_pSourceVR->SampleTrackingState( fGameFOV, 0.f /* seconds to predict */ ); -} - - -// -------------------------------------------------------------------- -// Purpose: Returns the projection matrix to use for the HUD -// -------------------------------------------------------------------- -const VMatrix &CClientVirtualReality::GetHudProjectionFromWorld() -{ - // This matrix will transform a world-space position into a homogenous HUD-space vector. - // So if you divide x+y by w, you will get the position on the HUD in [-1,1] space. - return m_HudProjectionFromWorld; -} - - -// -------------------------------------------------------------------- -// Purpose: Returns the aim vector relative to the torso -// -------------------------------------------------------------------- -void CClientVirtualReality::GetTorsoRelativeAim( Vector *pPosition, QAngle *pAngles ) -{ - MatrixAngles( m_TorsoFromMideye.As3x4(), *pAngles, *pPosition ); - pAngles->y += vr_aim_yaw_offset.GetFloat(); -} - - -// -------------------------------------------------------------------- -// Purpose: Returns distance of the HUD in front of the eyes. -// -------------------------------------------------------------------- -float CClientVirtualReality::GetHUDDistance() -{ - return vr_hud_forward.GetFloat(); -} - - -// -------------------------------------------------------------------- -// Purpose: Returns true if the HUD should be rendered into a render -// target and then into the world on a quad. -// -------------------------------------------------------------------- -bool CClientVirtualReality::ShouldRenderHUDInWorld() -{ - return UseVR() && vr_render_hud_in_world.GetBool(); -} - - -// -------------------------------------------------------------------- -// Purpose: Lets headtrack tweak the view model origin and angles to match -// aim angles and handle strange viewmode FOV stuff -// -------------------------------------------------------------------- -void CClientVirtualReality::OverrideViewModelTransform( Vector & vmorigin, QAngle & vmangles, bool bUseLargeOverride ) -{ - Vector vForward, vRight, vUp; - AngleVectors( vmangles, &vForward, &vRight, &vUp ); - - float fForward = bUseLargeOverride ? vr_viewmodel_offset_forward_large.GetFloat() : vr_viewmodel_offset_forward.GetFloat(); - - vmorigin += vForward * fForward; - MatrixAngles( m_WorldFromWeapon.As3x4(), vmangles ); -} - - -// -------------------------------------------------------------------- -// Purpose: Tells the head tracker to reset the torso position in case -// we're on a drifty tracker. -// -------------------------------------------------------------------- -void CClientVirtualReality::AlignTorsoAndViewToWeapon() -{ - if( !UseVR() ) - return; - - if( g_pSourceVR->WillDriftInYaw() ) - { - m_iAlignTorsoAndViewToWeaponCountdown = 2; - } -} - - -// -------------------------------------------------------------------- -// Purpose: Lets VR do stuff at the very end of the rendering process -// -------------------------------------------------------------------- -void CClientVirtualReality::PostProcessFrame( StereoEye_t eEye ) -{ - if( !UseVR() ) - return; - - g_pSourceVR->DoDistortionProcessing( eEye == STEREO_EYE_LEFT ? ISourceVirtualReality::VREye_Left : ISourceVirtualReality::VREye_Right ); -} - - -// -------------------------------------------------------------------- -// Pastes the HUD directly onto the backbuffer / render target. -// (higher quality than the RenderHUDQuad() path but can't always be used) -// -------------------------------------------------------------------- -void CClientVirtualReality::OverlayHUDQuadWithUndistort( const CViewSetup &eyeView, bool bDoUndistort, bool bBlackout, bool bTranslucent ) -{ - if ( ! UseVR() ) - return; - - // If we can't overlay the HUD, it will be handled on another path (rendered into the scene with RenderHUDQuad()). - if ( ! CanOverlayHudQuad() ) - return; - - // Get the position of the HUD quad in world space as used by RenderHUDQuad(). Then convert to a rectangle in normalized - // device coordinates. - - Vector vHead, vUL, vUR, vLL, vLR; - GetHUDBounds ( &vHead, &vUL, &vUR, &vLL, &vLR ); - - VMatrix worldToView, viewToProjection, worldToProjection, worldToPixels; - render->GetMatricesForView( eyeView, &worldToView, &viewToProjection, &worldToProjection, &worldToPixels ); - - Vector pUL, pUR, pLL, pLR; - - worldToProjection.V3Mul( vUL, pUL ); - worldToProjection.V3Mul( vUR, pUR ); - worldToProjection.V3Mul( vLL, pLL ); - worldToProjection.V3Mul( vLR, pLR ); - - float ndcHudBounds[4]; - ndcHudBounds[0] = Min ( Min( pUL.x, pUR.x ), Min( pLL.x, pLR.x ) ); - ndcHudBounds[1] = Min ( Min( pUL.y, pUR.y ), Min( pLL.y, pLR.y ) ); - ndcHudBounds[2] = Max ( Max( pUL.x, pUR.x ), Max( pLL.x, pLR.x ) ); - ndcHudBounds[3] = Max ( Max( pUL.y, pUR.y ), Max( pLL.y, pLR.y ) ); - - ISourceVirtualReality::VREye sourceVrEye = ( eyeView.m_eStereoEye == STEREO_EYE_LEFT ) ? ISourceVirtualReality::VREye_Left : ISourceVirtualReality::VREye_Right; - - g_pSourceVR->CompositeHud ( sourceVrEye, ndcHudBounds, bDoUndistort, bBlackout, bTranslucent ); -} - - -// -------------------------------------------------------------------- -// Purpose: Switches to VR mode -// -------------------------------------------------------------------- -void CClientVirtualReality::Activate() -{ - // we can only do this if a headtrack DLL is loaded - if( !g_pSourceVR ) - return; - - // These checks don't apply if we're in VR mode because Steam said so. - if ( !ShouldForceVRActive() ) - { - // see if VR mode is even enabled - if ( materials->GetCurrentConfigForVideoCard().m_nVRModeAdapter == -1 ) - { - Warning( "Enable VR mode in the video options before trying to use it.\n" ); - return; - } - - // See if we have an actual adapter - int32 nVRModeAdapter = g_pSourceVR->GetVRModeAdapter(); - if ( nVRModeAdapter == -1 ) - { - Warning( "Unable to get VRMode adapter from OpenVR. VR mode cannot be enabled. Try restarting and then enabling VR again.\n" ); - return; - } - - // we can only activate if we've got a VR device - if ( materials->GetCurrentConfigForVideoCard().m_nVRModeAdapter != nVRModeAdapter ) - { - Warning( "VR Mode expects adapter %d which is different from %d which we are currently using. Try restarting and enabling VR mode again.\n", - nVRModeAdapter, materials->GetCurrentConfigForVideoCard().m_nVRModeAdapter ); - engine->ExecuteClientCmd( "mat_enable_vrmode 0\n" ); - return; - } - } - - - // can't activate twice - if( UseVR() ) - return; - - // remember where we were - m_bNonVRWindowed = g_pMaterialSystem->GetCurrentConfigForVideoCard().Windowed(); - vgui::surface()->GetScreenSize( m_nNonVRWidth, m_nNonVRHeight ); -#if defined( USE_SDL ) - static ConVarRef sdl_displayindex( "sdl_displayindex" ); - m_nNonVRSDLDisplayIndex = sdl_displayindex.GetInt(); -#endif - - if( !g_pSourceVR->Activate() ) - { - // we couldn't activate, so just punt on this whole thing - return; - } - - // general all-game stuff - engine->ExecuteClientCmd( "mat_reset_rendertargets\n" ); - - // game specific VR config - CUtlString sCmd; - sCmd.Format( "exec sourcevr_%s.cfg\n", COM_GetModDirectory() ); - engine->ExecuteClientCmd( sCmd.Get() ); - - vgui::surface()->SetSoftwareCursor( true ); - -#if defined(POSIX) - ConVarRef m_rawinput( "m_rawinput" ); - m_bNonVRRawInput = m_rawinput.GetBool(); - m_rawinput.SetValue( 1 ); - - ConVarRef mat_vsync( "mat_vsync" ); - mat_vsync.SetValue( 0 ); -#endif - - g_pMatSystemSurface->ForceScreenSizeOverride(true, 640, 480 ); - int nViewportWidth, nViewportHeight; - - g_pSourceVR->GetViewportBounds( ISourceVirtualReality::VREye_Left, NULL, NULL, &nViewportWidth, &nViewportHeight ); - g_pMatSystemSurface->SetFullscreenViewportAndRenderTarget( 0, 0, nViewportWidth, nViewportHeight, g_pSourceVR->GetRenderTarget( ISourceVirtualReality::VREye_Left, ISourceVirtualReality::RT_Color ) ); - - vgui::ivgui()->SetVRMode( true ); - - // we can skip this extra mode change if we've always been in VR mode - if ( !ShouldForceVRActive() ) - { - VRRect_t rect; - if ( g_pSourceVR->GetDisplayBounds( &rect ) ) - { - - // set mode - char szCmd[256]; - Q_snprintf( szCmd, sizeof(szCmd), "mat_setvideomode %i %i %i\n", rect.nWidth, rect.nHeight, vr_force_windowed.GetBool() ? 1 : 0 ); - engine->ClientCmd_Unrestricted( szCmd ); - } - } -} - - -void CClientVirtualReality::Deactivate() -{ - // can't deactivate when we aren't active - if( !UseVR() ) - return; - - g_pSourceVR->Deactivate(); - - g_pMatSystemSurface->ForceScreenSizeOverride(false, 0, 0 ); - g_pMaterialSystem->GetRenderContext()->Viewport( 0, 0, m_nNonVRWidth, m_nNonVRHeight ); - g_pMatSystemSurface->SetFullscreenViewportAndRenderTarget( 0, 0, m_nNonVRWidth, m_nNonVRHeight, NULL ); - - static ConVarRef cl_software_cursor( "cl_software_cursor" ); - vgui::surface()->SetSoftwareCursor( cl_software_cursor.GetBool() ); - -#if defined( USE_SDL ) - static ConVarRef sdl_displayindex( "sdl_displayindex" ); - sdl_displayindex.SetValue( m_nNonVRSDLDisplayIndex ); -#endif - -#if defined(POSIX) - ConVarRef m_rawinput( "m_rawinput" ); - m_rawinput.SetValue( m_bNonVRRawInput ); -#endif - - // Make sure the client .dll root panel is at the proper point before doing the "SolveTraverse" calls - vgui::VPANEL root = enginevgui->GetPanel( PANEL_CLIENTDLL ); - if ( root != 0 ) - { - vgui::ipanel()->SetSize( root, m_nNonVRWidth, m_nNonVRHeight ); - } - // Same for client .dll tools - root = enginevgui->GetPanel( PANEL_CLIENTDLL_TOOLS ); - if ( root != 0 ) - { - vgui::ipanel()->SetSize( root, m_nNonVRWidth, m_nNonVRHeight ); - } - - int viewWidth, viewHeight; - vgui::surface()->GetScreenSize( viewWidth, viewHeight ); - - engine->ExecuteClientCmd( "mat_reset_rendertargets\n" ); - - // set mode - char szCmd[ 256 ]; - Q_snprintf( szCmd, sizeof( szCmd ), "mat_setvideomode %i %i %i\n", m_nNonVRWidth, m_nNonVRHeight, m_bNonVRWindowed ? 1 : 0 ); - engine->ClientCmd_Unrestricted( szCmd ); - -} - - -// Called when startup is complete -void CClientVirtualReality::StartupComplete() -{ - if ( vr_activate_default.GetBool() || ShouldForceVRActive() ) - Activate(); -} - diff --git a/game/client/client_virtualreality.h b/game/client/client_virtualreality.h deleted file mode 100644 index 9aadfeb37..000000000 --- a/game/client/client_virtualreality.h +++ /dev/null @@ -1,165 +0,0 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// -// -// Purpose: The implementation of ISourceVirtualReality, which provides utility -// functions for VR including head tracking, window/viewport information, -// rendering information, and distortion -// -//============================================================================= - -#ifndef CLIENTVIRTUALREALITY_H -#define CLIENTVIRTUALREALITY_H -#if defined( _WIN32 ) -#pragma once -#endif - -#include "tier3/tier3.h" -#include "iclientvirtualreality.h" -#include "view_shared.h" - -enum HeadtrackMovementMode_t -{ - HMM_SHOOTFACE_MOVEFACE = 0, // Shoot from your face, move along your face. - HMM_SHOOTFACE_MOVETORSO, // Shoot from your face, move the direction your torso is facing. - HMM_SHOOTMOUSE_MOVEFACE, // Shoot from the mouse cursor which moves within the HUD, move along your face. - HMM_SHOOTBOUNDEDMOUSE_LOOKFACE_MOVEFACE, // Shoot from the mouse cursor which moves, bounded within the HUD, move along your face. - HMM_SHOOTBOUNDEDMOUSE_LOOKFACE_MOVEMOUSE, // Shoot from the mouse cursor which moves, bounded within the HUD, move along your weapon (the "mouse") - - // The following are not intended to be user-selectable modes, they are used by e.g. followcam stuff. - HMM_SHOOTMOVELOOKMOUSEFACE, // Shoot & move & look along the mouse cursor (i.e. original unchanged gameplay), face just looks on top of that. - HMM_SHOOTMOVEMOUSE_LOOKFACE, // Shoot & move along the mouse cursor (i.e. original unchanged gameplay), face just looks. - HMM_SHOOTMOVELOOKMOUSE, // Shoot, move and look along the mouse cursor - HMD orientation is completely ignored! - - HMM_LAST, - - HMM_NOOVERRIDE = HMM_LAST // Used as a retrun from ShouldOverrideHeadtrackControl(), not an actual mode. -}; - - -//----------------------------------------------------------------------------- -// The implementation -//----------------------------------------------------------------------------- - - -class CClientVirtualReality: public CTier3AppSystem< IClientVirtualReality > -{ - typedef CTier3AppSystem< IClientVirtualReality > BaseClass; - -public: - - CClientVirtualReality(); - ~CClientVirtualReality(); - - //--------------------------------------------------------- - // Initialization and shutdown - //--------------------------------------------------------- - - // - // IAppSystem - // - virtual bool Connect( CreateInterfaceFn factory ); - virtual void Disconnect(); - virtual void * QueryInterface( const char *pInterfaceName ); - - // these will come from the engine - virtual InitReturnVal_t Init(); - virtual void Shutdown(); - - // Called when startup is complete - void StartupComplete(); - - //--------------------------------------------------------- - // IClientVirtualReality implementation - //--------------------------------------------------------- - virtual void DrawMainMenu() OVERRIDE; - - - //--------------------------------------------------------- - // VR utilities for use in the client - //--------------------------------------------------------- - bool OverrideView ( CViewSetup *pViewMiddle, Vector *pViewModelOrigin, QAngle *pViewModelAngles, HeadtrackMovementMode_t hmmMovementOverride ); - bool OverrideStereoView( CViewSetup *pViewMiddle, CViewSetup *pViewLeft, CViewSetup *pViewRight ); - bool OverridePlayerMotion( float flInputSampleFrametime, const QAngle &oldAngles, const QAngle &curAngles, const Vector &curMotion, QAngle *pNewAngles, Vector *pNewMotion ); - bool OverrideWeaponHudAimVectors ( Vector *pAimOrigin, Vector *pAimDirection ); - bool CurrentlyZoomed(); - void OverrideTorsoTransform( const Vector & position, const QAngle & angles ) ; - void CancelTorsoTransformOverride( ) ; - bool CanOverlayHudQuad(); - void GetHUDBounds( Vector *pViewer, Vector *pUL, Vector *pUR, Vector *pLL, Vector *pLR ); - void RenderHUDQuad( bool bBlackout, bool bTranslucent ); - float GetZoomedModeMagnification(); - bool ProcessCurrentTrackingState( float fGameFOV ); - const VMatrix &GetHudProjectionFromWorld(); - void GetTorsoRelativeAim( Vector *pPosition, QAngle *pAngles ); - float GetHUDDistance(); - bool ShouldRenderHUDInWorld(); - const VMatrix & GetWorldFromMidEye() const { return m_WorldFromMidEyeNoDebugCam; } - void OverrideViewModelTransform( Vector & vmorigin, QAngle & vmangles, bool bUseLargeOverride ); - void AlignTorsoAndViewToWeapon(); - void PostProcessFrame( StereoEye_t eEye ); - void OverlayHUDQuadWithUndistort( const CViewSetup &view, bool bDoUndistort, bool bBlackout, bool bTranslucent ); - - //--------------------------------------------------------- - // Enter/leave VR mode - //--------------------------------------------------------- - void Activate(); - void Deactivate(); - -private: - HeadtrackMovementMode_t m_hmmMovementActual; - - // Where the current mideye is relative to the (game)world. - VMatrix m_WorldFromMidEye; - - // used for drawing the HUD - float m_fHudHorizontalFov; - VMatrix m_WorldFromHud; - VMatrix m_HudProjectionFromWorld; - float m_fHudHalfWidth; - float m_fHudHalfHeight; - - // Where the current mideye is relative to the zero (torso) (currently always the same as m_MideyeZeroFromMideyeCurrent!) - VMatrix m_TorsoFromMideye; - - // The debug cam will play with the above, but some things want the non-debug view. - VMatrix m_WorldFromMidEyeNoDebugCam; - - // Where the weapon is currently pointing (note the translation will be zero - this is just orientation) - VMatrix m_WorldFromWeapon; - - // The player's current torso angles/pos in the world. - QAngle m_PlayerTorsoAngle; - Vector m_PlayerTorsoOrigin; - Vector m_PlayerLastMovement; - - // The player's current view angles/pos in the world. - QAngle m_PlayerViewAngle; - Vector m_PlayerViewOrigin; - - // The amount of zoom to apply to the view of the world (but NOT to the HUD!). Used for sniper weapons, etc. - float m_WorldZoomScale; - - // for overriding torso position in vehicles - QAngle m_OverrideTorsoAngle; - QAngle m_OverrideTorsoOffset; - bool m_bOverrideTorsoAngle; - - // While this is >0, we keep forcing the torso (and maybe view) to the weapon. - int m_iAlignTorsoAndViewToWeaponCountdown; - - bool m_bMotionUpdated; - - RTime32 m_rtLastMotionSample; - - // video mode we had before we entered VR mode - bool m_bNonVRWindowed; - int m_nNonVRWidth; - int m_nNonVRHeight; -#if defined( USE_SDL ) - int m_nNonVRSDLDisplayIndex; -#endif - bool m_bNonVRRawInput; -}; - -extern CClientVirtualReality g_ClientVirtualReality; - -#endif // CLIENTVIRTUALREALITY_H diff --git a/game/client/clientalphaproperty.cpp b/game/client/clientalphaproperty.cpp new file mode 100644 index 000000000..6fcedab56 --- /dev/null +++ b/game/client/clientalphaproperty.cpp @@ -0,0 +1,249 @@ +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// + +#include "cbase.h" +#include "clientalphaproperty.h" +#include "const.h" +#include "iclientshadowmgr.h" +#include "iclientunknown.h" +#include "iclientrenderable.h" + +// NOTE: This has to be the last file included! +#include "tier0/memdbgon.h" + + +//----------------------------------------------------------------------------- +// Client alpha property starts here +//----------------------------------------------------------------------------- +CClientAlphaProperty::CClientAlphaProperty( ) +{ + m_nRenderFX = kRenderFxNone; + m_nRenderMode = kRenderNormal; + m_nDesyncOffset = 0; + m_hShadowHandle = CLIENTSHADOW_INVALID_HANDLE; + m_nAlpha = 255; + m_flFadeScale = 0.0f; // By default, things don't fade out automagically + m_nDistFadeStart = 0; + m_nDistFadeEnd = 0; + m_bAlphaOverride = false; + m_bShadowAlphaOverride = false; + m_nDistanceFadeMode = CLIENT_ALPHA_DISTANCE_FADE_USE_CENTER; +} + +void CClientAlphaProperty::Init( IClientUnknown *pUnk ) +{ + m_pOuter = pUnk; +} + +IClientUnknown* CClientAlphaProperty::GetIClientUnknown() +{ + return m_pOuter; +} + +void CClientAlphaProperty::SetShadowHandle( ClientShadowHandle_t hShadowHandle ) +{ + m_hShadowHandle = hShadowHandle; +} + +void CClientAlphaProperty::SetAlphaModulation( uint8 a ) +{ + m_nAlpha = a; +} + +void CClientAlphaProperty::EnableAlphaModulationOverride( bool bEnable ) +{ + m_bAlphaOverride = bEnable; +} + +void CClientAlphaProperty::EnableShadowAlphaModulationOverride( bool bEnable ) +{ + m_bShadowAlphaOverride = bEnable; +} + +// Sets an FX function +void CClientAlphaProperty::SetRenderFX( RenderFx_t nRenderFx, RenderMode_t nRenderMode, float flStartTime, float flDuration ) +{ + bool bStartTimeUnspecified = ( flStartTime == FLT_MAX ); + bool bRenderFxChanged = ( m_nRenderFX != nRenderFx ); + + switch( nRenderFx ) + { + case kRenderFxFadeIn: + case kRenderFxFadeOut: + Assert( !bStartTimeUnspecified || !bRenderFxChanged ); + if ( bStartTimeUnspecified ) + { + flStartTime = gpGlobals->curtime; + } + break; + + case kRenderFxFadeSlow: + case kRenderFxSolidSlow: + Assert( !bStartTimeUnspecified || !bRenderFxChanged ); + if ( bStartTimeUnspecified ) + { + flStartTime = gpGlobals->curtime; + } + flDuration = 4.0f; + break; + + case kRenderFxFadeFast: + case kRenderFxSolidFast: + Assert( !bStartTimeUnspecified || !bRenderFxChanged ); + if ( bStartTimeUnspecified ) + { + flStartTime = gpGlobals->curtime; + } + flDuration = 1.0f; + break; + } + + m_nRenderMode = nRenderMode; + m_nRenderFX = nRenderFx; + if ( bRenderFxChanged || !bStartTimeUnspecified ) + { + m_flRenderFxStartTime = flStartTime; + m_flRenderFxDuration = flDuration; + } +} + +void CClientAlphaProperty::SetDesyncOffset( int nOffset ) +{ + m_nDesyncOffset = nOffset; +} + +void CClientAlphaProperty::SetDistanceFadeMode( ClientAlphaDistanceFadeMode_t nFadeMode ) +{ + // Necessary since m_nDistanceFadeMode is stored in 1 bit + COMPILE_TIME_ASSERT( CLIENT_ALPHA_DISTANCE_FADE_MODE_COUNT <= ( 1 << CLIENT_ALPHA_DISTANCE_FADE_MODE_BIT_COUNT ) ); + m_nDistanceFadeMode = nFadeMode; +} + + +// Sets fade parameters +void CClientAlphaProperty::SetFade( float flGlobalFadeScale, float flDistFadeStart, float flDistFadeEnd ) +{ + if( flDistFadeStart > flDistFadeEnd ) + { + V_swap( flDistFadeStart, flDistFadeEnd ); + } + + // If a negative value is provided for the min fade distance, then base it off the max. + if( flDistFadeStart < 0 ) + { + flDistFadeStart = flDistFadeEnd + flDistFadeStart; + if( flDistFadeStart < 0 ) + { + flDistFadeStart = 0; + } + } + + Assert( flDistFadeStart >= 0 && flDistFadeStart <= 65535 ); + Assert( flDistFadeEnd >= 0 && flDistFadeEnd <= 65535 ); + + m_nDistFadeStart = (uint16)flDistFadeStart; + m_nDistFadeEnd = (uint16)flDistFadeEnd; + m_flFadeScale = flGlobalFadeScale; +} + + +//----------------------------------------------------------------------------- +// Computes alpha value based on render fx +//----------------------------------------------------------------------------- +uint8 CClientAlphaProperty::ComputeRenderAlpha( ) const +{ + if ( m_nRenderMode == kRenderNone || m_nRenderMode == kRenderEnvironmental ) + return 0; + + int blend = 0; + float flOffset = ((int)m_nDesyncOffset) * 363.0;// Use ent index to de-sync these fx + + switch( m_nRenderFX ) + { + case kRenderFxPulseSlowWide: + blend = m_nAlpha + 0x40 * sin( gpGlobals->curtime * 2 + flOffset ); + break; + + case kRenderFxPulseFastWide: + blend = m_nAlpha + 0x40 * sin( gpGlobals->curtime * 8 + flOffset ); + break; + + case kRenderFxPulseFastWider: + blend = ( 0xff * fabs(sin( gpGlobals->curtime * 12 + flOffset ) ) ); + break; + + case kRenderFxPulseSlow: + blend = m_nAlpha + 0x10 * sin( gpGlobals->curtime * 2 + flOffset ); + break; + + case kRenderFxPulseFast: + blend = m_nAlpha + 0x10 * sin( gpGlobals->curtime * 8 + flOffset ); + break; + + case kRenderFxFadeOut: + case kRenderFxFadeFast: + case kRenderFxFadeSlow: + { + float flElapsed = gpGlobals->curtime - m_flRenderFxStartTime; + float flVal = RemapValClamped( flElapsed, 0, m_flRenderFxDuration, m_nAlpha, 0 ); + flVal = clamp( flVal, 0, 255 ); + blend = (int)flVal; + } + break; + + case kRenderFxFadeIn: + case kRenderFxSolidFast: + case kRenderFxSolidSlow: + { + float flElapsed = gpGlobals->curtime - m_flRenderFxStartTime; + float flVal = RemapValClamped( flElapsed, 0, m_flRenderFxDuration, 0, m_nAlpha ); + flVal = clamp( flVal, 0, 255 ); + blend = (int)flVal; + } + break; + + case kRenderFxStrobeSlow: + blend = 20 * sin( gpGlobals->curtime * 4 + flOffset ); + blend = ( blend < 0 ) ? 0 : m_nAlpha; + break; + + case kRenderFxStrobeFast: + blend = 20 * sin( gpGlobals->curtime * 16 + flOffset ); + blend = ( blend < 0 ) ? 0 : m_nAlpha; + break; + + case kRenderFxStrobeFaster: + blend = 20 * sin( gpGlobals->curtime * 36 + flOffset ); + blend = ( blend < 0 ) ? 0 : m_nAlpha; + break; + + case kRenderFxFlickerSlow: + blend = 20 * (sin( gpGlobals->curtime * 2 ) + sin( gpGlobals->curtime * 17 + flOffset )); + blend = ( blend < 0 ) ? 0 : m_nAlpha; + break; + + case kRenderFxFlickerFast: + blend = 20 * (sin( gpGlobals->curtime * 16 ) + sin( gpGlobals->curtime * 23 + flOffset )); + blend = ( blend < 0 ) ? 0 : m_nAlpha; + break; + + case kRenderFxNone: + default: + blend = ( m_nRenderMode == kRenderNormal ) ? 255 : m_nAlpha; + break; + } + + blend = clamp( blend, 0, 255 ); + + if ( m_bAlphaOverride ) + { + blend = m_pOuter->GetClientRenderable()->OverrideAlphaModulation( m_nAlpha ); + blend = clamp( blend, 0, 255 ); + } + + return blend; +} diff --git a/game/client/clientalphaproperty.h b/game/client/clientalphaproperty.h new file mode 100644 index 000000000..e6aba5321 --- /dev/null +++ b/game/client/clientalphaproperty.h @@ -0,0 +1,113 @@ +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// + +#ifndef CLIENTALPHAPROPERTY_H +#define CLIENTALPHAPROPERTY_H +#ifdef _WIN32 +#pragma once +#endif + +#include "iclientalphaproperty.h" + + +#define CLIENT_ALPHA_DISTANCE_FADE_MODE_BIT_COUNT 1 + +//----------------------------------------------------------------------------- +// Implementation class +//----------------------------------------------------------------------------- +class CClientAlphaProperty : public IClientAlphaProperty +{ + // Inherited from IClientAlphaProperty +public: + virtual IClientUnknown* GetIClientUnknown(); + virtual void SetAlphaModulation( uint8 a ); + virtual void SetRenderFX( RenderFx_t nRenderFx, RenderMode_t nRenderMode, float flStartTime = FLT_MAX, float flDuration = 0.0f ); + virtual void SetFade( float flGlobalFadeScale, float flDistFadeMinDist, float flDistFadeMaxDist ); + virtual void SetDesyncOffset( int nOffset ); + virtual void EnableAlphaModulationOverride( bool bEnable ); + virtual void EnableShadowAlphaModulationOverride( bool bEnable ); + virtual void SetDistanceFadeMode( ClientAlphaDistanceFadeMode_t nFadeMode ); + + // Other public methods +public: + CClientAlphaProperty( ); + void Init( IClientUnknown *pUnk ); + + // NOTE: Only the client shadow manager should ever call this method! + void SetShadowHandle( ClientShadowHandle_t hShadowHandle ); + + // Returns the current alpha modulation (no fades or render FX taken into account) + uint8 GetAlphaModulation() const; + + // Compute the render alpha (after fades + render FX are applied) + uint8 ComputeRenderAlpha( ) const; + + // Returns alpha fade + float GetMinFadeDist() const; + float GetMaxFadeDist() const; + float GetGlobalFadeScale() const; + + // Should this ignore the Z buffer? + bool IgnoresZBuffer( void ) const; + +private: + // NOTE: Be careful if you add data to this class. + // It needs to be no more than 32 bytes, which it is right now + // (remember the vtable adds 4 bytes). Try to restrict usage + // to reserved areas or figure out a way of compressing existing fields + IClientUnknown *m_pOuter; + + ClientShadowHandle_t m_hShadowHandle; + uint16 m_nRenderFX : 5; + uint16 m_nRenderMode : 4; + uint16 m_bAlphaOverride : 1; + uint16 m_bShadowAlphaOverride : 1; + uint16 m_nDistanceFadeMode : CLIENT_ALPHA_DISTANCE_FADE_MODE_BIT_COUNT; + uint16 m_nReserved : 4; + + uint16 m_nDesyncOffset; + uint8 m_nAlpha; + uint8 m_nReserved2; + + uint16 m_nDistFadeStart; + uint16 m_nDistFadeEnd; + + float m_flFadeScale; + float m_flRenderFxStartTime; + float m_flRenderFxDuration; + + friend class CClientLeafSystem; +}; + +// Returns the current alpha modulation +inline uint8 CClientAlphaProperty::GetAlphaModulation() const +{ + return m_nAlpha; +} + +inline float CClientAlphaProperty::GetMinFadeDist() const +{ + return m_nDistFadeStart; +} + +inline float CClientAlphaProperty::GetMaxFadeDist() const +{ + return m_nDistFadeEnd; +} + +inline float CClientAlphaProperty::GetGlobalFadeScale() const +{ + return m_flFadeScale; +} + +inline bool CClientAlphaProperty::IgnoresZBuffer( void ) const +{ + return m_nRenderMode == kRenderGlow || m_nRenderMode == kRenderWorldGlow; +} + + +#endif // CLIENTALPHAPROPERTY_H diff --git a/game/client/clienteffectprecachesystem.cpp b/game/client/clienteffectprecachesystem.cpp deleted file mode 100644 index c5d4e07b4..000000000 --- a/game/client/clienteffectprecachesystem.cpp +++ /dev/null @@ -1,78 +0,0 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// -// -// Purpose: Deals with precaching requests from client effects -// -// $Revision: $ -// $NoKeywords: $ -//=============================================================================// -#include "cbase.h" -#include "fx.h" -#include "clienteffectprecachesystem.h" -#include "particles/particles.h" - -// memdbgon must be the last include file in a .cpp file!!! -#include "tier0/memdbgon.h" - -//Global singelton accessor -CClientEffectPrecacheSystem *ClientEffectPrecacheSystem( void ) -{ - static CClientEffectPrecacheSystem s_ClientEffectPrecacheSystem; - return &s_ClientEffectPrecacheSystem; -} - -//----------------------------------------------------------------------------- -// Purpose: Precache all the registered effects -//----------------------------------------------------------------------------- -void CClientEffectPrecacheSystem::LevelInitPreEntity( void ) -{ - //Precache all known effects - for ( int i = 0; i < m_Effects.Size(); i++ ) - { - m_Effects[i]->Cache(); - } - - //FIXME: Double check this - //Finally, force the cache of these materials - materials->CacheUsedMaterials(); - - // Now, cache off our material handles - FX_CacheMaterialHandles(); -} - -//----------------------------------------------------------------------------- -// Purpose: Nothing to do here -//----------------------------------------------------------------------------- -void CClientEffectPrecacheSystem::LevelShutdownPreEntity( void ) -{ -} - -//----------------------------------------------------------------------------- -// Purpose: Dereference all the registered effects -//----------------------------------------------------------------------------- -void CClientEffectPrecacheSystem::LevelShutdownPostEntity( void ) -{ - // mark all known effects as free - for ( int i = 0; i < m_Effects.Size(); i++ ) - { - m_Effects[i]->Cache( false ); - } -} - -//----------------------------------------------------------------------------- -// Purpose: Purges the effect list -//----------------------------------------------------------------------------- -void CClientEffectPrecacheSystem::Shutdown( void ) -{ - //Release all effects - m_Effects.Purge(); -} - -//----------------------------------------------------------------------------- -// Purpose: Adds the effect to the list to be precached -// Input : *effect - system to precache -//----------------------------------------------------------------------------- -void CClientEffectPrecacheSystem::Register( IClientEffect *effect ) -{ - //Hold onto this effect for precaching later - m_Effects.AddToTail( effect ); -} diff --git a/game/client/clienteffectprecachesystem.h b/game/client/clienteffectprecachesystem.h deleted file mode 100644 index e05a50019..000000000 --- a/game/client/clienteffectprecachesystem.h +++ /dev/null @@ -1,150 +0,0 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// -// -// Purpose: Deals with singleton -// -// $Revision: $ -// $NoKeywords: $ -//=============================================================================// - -#if !defined( CLIENTEFFECTPRECACHESYSTEM_H ) -#define CLIENTEFFECTPRECACHESYSTEM_H -#ifdef _WIN32 -#pragma once -#endif - -#include "igamesystem.h" -#include "commonmacros.h" -#include "utlvector.h" -#include "materialsystem/imaterialsystem.h" -#include "materialsystem/imaterial.h" - -//----------------------------------------------------------------------------- -// Interface to automated system for precaching materials -//----------------------------------------------------------------------------- -class IClientEffect -{ -public: - virtual void Cache( bool precache = true ) = 0; -}; - -//----------------------------------------------------------------------------- -// Responsible for managing precaching of particles -//----------------------------------------------------------------------------- - -class CClientEffectPrecacheSystem : public IGameSystem -{ -public: - virtual char const *Name() { return "CCLientEffectPrecacheSystem"; } - - virtual bool IsPerFrame() { return false; } - - // constructor, destructor - CClientEffectPrecacheSystem() {} - virtual ~CClientEffectPrecacheSystem() {} - - // Init, shutdown - virtual bool Init() { return true; } - virtual void PostInit() {} - virtual void Shutdown(); - - // Level init, shutdown - virtual void LevelInitPreEntity(); - virtual void LevelInitPostEntity() {} - virtual void LevelShutdownPreEntity(); - virtual void LevelShutdownPostEntity(); - - virtual void OnSave() {} - virtual void OnRestore() {} - virtual void SafeRemoveIfDesired() {} - - void Register( IClientEffect *effect ); - -protected: - - CUtlVector< IClientEffect * > m_Effects; -}; - -//Singleton accessor -extern CClientEffectPrecacheSystem *ClientEffectPrecacheSystem(); - -//----------------------------------------------------------------------------- -// Deals with automated registering and precaching of materials for effects -//----------------------------------------------------------------------------- - -class CClientEffect : public IClientEffect -{ -public: - - CClientEffect( void ) - { - //Register with the main effect system - ClientEffectPrecacheSystem()->Register( this ); - } - -//----------------------------------------------------------------------------- -// Purpose: Precache a material by artificially incrementing its reference counter -// Input : *materialName - name of the material -// : increment - whether to increment or decrement the reference counter -//----------------------------------------------------------------------------- - - inline void ReferenceMaterial( const char *materialName, bool increment = true ) - { - IMaterial *material = materials->FindMaterial( materialName, TEXTURE_GROUP_CLIENT_EFFECTS ); - if ( !IsErrorMaterial( material ) ) - { - if ( increment ) - { - material->IncrementReferenceCount(); - } - else - { - material->DecrementReferenceCount(); - } - } - } -}; - -//Automatic precache macros - -//Beginning -#define CLIENTEFFECT_REGISTER_BEGIN( className ) \ -namespace className { \ -class ClientEffectRegister : public CClientEffect \ -{ \ -private: \ - static const char *m_pszMaterials[]; \ -public: \ - void Cache( bool precache = true ); \ -}; \ -const char *ClientEffectRegister::m_pszMaterials[] = { - -//Material definitions -#define CLIENTEFFECT_MATERIAL( materialName ) materialName, - -//End -#define CLIENTEFFECT_REGISTER_END( ) }; \ -void ClientEffectRegister::Cache( bool precache ) \ -{ \ - for ( int i = 0; i < ARRAYSIZE( m_pszMaterials ); i++ ) \ - { \ - ReferenceMaterial( m_pszMaterials[i], precache ); \ - } \ -} \ -ClientEffectRegister register_ClientEffectRegister; \ -} - -#define CLIENTEFFECT_REGISTER_END_CONDITIONAL(condition ) }; \ -void ClientEffectRegister::Cache( bool precache ) \ -{ \ - if ( condition) \ - { \ - for ( int i = 0; i < ARRAYSIZE( m_pszMaterials ); i++ ) \ - { \ - ReferenceMaterial( m_pszMaterials[i], precache ); \ - } \ - } \ -} \ -ClientEffectRegister register_ClientEffectRegister; \ -} - -#endif //CLIENTEFFECTPRECACHESYSTEM_H diff --git a/game/client/cliententitylist.cpp b/game/client/cliententitylist.cpp index 294d4ff1c..badbe3b74 100644 --- a/game/client/cliententitylist.cpp +++ b/game/client/cliententitylist.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // @@ -100,6 +100,20 @@ IClientNetworkable* CClientEntityList::GetClientNetworkable( int entnum ) } +EntityCacheInfo_t *CClientEntityList::GetClientNetworkableArray() +{ + PREFETCH360(m_EntityCacheInfo, 0); + return m_EntityCacheInfo; +} + +void CClientEntityList::SetDormant( int entityIndex, bool bDormant ) +{ + Assert( entityIndex >= 0 ); + Assert( entityIndex < MAX_EDICTS ); + m_EntityCacheInfo[entityIndex].m_bDormant = bDormant; +} + + IClientEntity* CClientEntityList::GetClientEntity( int entnum ) { IClientUnknown *pEnt = GetListedEntity( entnum ); @@ -322,6 +336,7 @@ void CClientEntityList::OnAddEntity( IHandleEntity *pEnt, CBaseHandle handle ) Assert( dynamic_cast< IClientUnknown* >( pEnt ) ); Assert( ((IClientUnknown*)pEnt)->GetClientNetworkable() ); // Server entities should all be networkable. pCache->m_pNetworkable = ((IClientUnknown*)pEnt)->GetClientNetworkable(); + pCache->m_bDormant = true; } IClientUnknown *pUnknown = (IClientUnknown*)pEnt; diff --git a/game/client/cliententitylist.h b/game/client/cliententitylist.h index f09b89169..8aef4d3f9 100644 --- a/game/client/cliententitylist.h +++ b/game/client/cliententitylist.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // @@ -15,8 +15,8 @@ #include "tier0/dbg.h" #include "icliententitylist.h" #include "iclientunknown.h" -#include "utllinkedlist.h" -#include "utlvector.h" +#include "UtlLinkedList.h" +#include "UtlVector.h" #include "icliententityinternal.h" #include "ispatialpartition.h" #include "cdll_util.h" @@ -109,6 +109,7 @@ friend class C_AllBaseEntityIterator; public: virtual IClientNetworkable* GetClientNetworkable( int entnum ); + virtual EntityCacheInfo_t *GetClientNetworkableArray(); virtual IClientEntity* GetClientEntity( int entnum ); virtual int NumberOfEntities( bool bIncludeNonNetworkable = false ); @@ -182,17 +183,9 @@ friend class C_AllBaseEntityIterator; void NotifyCreateEntity( C_BaseEntity *pEnt ); void NotifyRemoveEntity( C_BaseEntity *pEnt ); - + void SetDormant( int entityIndex, bool bDormant ); private: - // Cached info for networked entities. - struct EntityCacheInfo_t - { - // Cached off because GetClientNetworkable is called a *lot* - IClientNetworkable *m_pNetworkable; - unsigned short m_BaseEntitiesIndex; // Index into m_BaseEntities (or m_BaseEntities.InvalidIndex() if none). - }; - // Current count int m_iNumServerEnts; // Max allowed diff --git a/game/client/clientleafsystem.cpp b/game/client/clientleafsystem.cpp index c00481fdc..cfbecf5ba 100644 --- a/game/client/clientleafsystem.cpp +++ b/game/client/clientleafsystem.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright 1996-2007, Valve Corporation, All rights reserved. ======// // // Purpose: // @@ -9,31 +9,42 @@ //===========================================================================// #include "cbase.h" -#include "clientleafsystem.h" -#include "utlbidirectionalset.h" +#include "ClientLeafSystem.h" +#include "UtlBidirectionalSet.h" #include "model_types.h" -#include "ivrenderview.h" +#include "IVRenderView.h" #include "tier0/vprof.h" -#include "bsptreedata.h" -#include "detailobjectsystem.h" +#include "BSPTreeData.h" +#include "DetailObjectSystem.h" #include "engine/IStaticPropMgr.h" -#include "engine/ivdebugoverlay.h" +#include "engine/IVDebugOverlay.h" #include "vstdlib/jobthread.h" #include "tier1/utllinkedlist.h" #include "datacache/imdlcache.h" #include "view.h" +#include "iviewrender.h" #include "viewrender.h" +#include "clientalphaproperty.h" +#include "con_nprint.h" +//#include "tier0/miniprofiler.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" class VMatrix; // forward decl +//extern LinkedMiniProfiler *g_pMiniProfilers; +//LinkedMiniProfiler g_mpRecomputeLeaves("CClientLeafSystem::RecomputeRenderableLeaves", &g_pMiniProfilers); +//LinkedMiniProfiler g_mpComputeBounds("CClientLeafSystem::ComputeBounds", &g_pMiniProfilers); + + static ConVar cl_drawleaf("cl_drawleaf", "-1", FCVAR_CHEAT ); static ConVar r_PortalTestEnts( "r_PortalTestEnts", "1", FCVAR_CHEAT, "Clip entities against portal frustums." ); static ConVar r_portalsopenall( "r_portalsopenall", "0", FCVAR_CHEAT, "Open all portals" ); -static ConVar cl_threaded_client_leaf_system("cl_threaded_client_leaf_system", "0" ); +static ConVar r_shadows_on_renderables_enable( "r_shadows_on_renderables_enable", "0", 0, "Support casting RTT shadows onto other renderables" ); + +static ConVar cl_leafsystemvis( "cl_leafsystemvis", "0", FCVAR_CHEAT ); DEFINE_FIXEDSIZE_ALLOCATOR( CClientRenderablesList, 1, CUtlMemoryPool::GROW_SLOW ); @@ -51,15 +62,11 @@ static void FrameUnlock() mdlcache->EndLock(); } -static void CallComputeFXBlend( IClientRenderable *&pRenderable ) -{ - pRenderable->ComputeFxBlend(); -} //----------------------------------------------------------------------------- // The client leaf system //----------------------------------------------------------------------------- -class CClientLeafSystem : public IClientLeafSystem, public ISpatialLeafEnumerator +class CClientLeafSystem : public IClientLeafSystem, public ISpatialLeafEnumerator, public IClientAlphaPropertyMgr { public: virtual char const *Name() { return "CClientLeafSystem"; } @@ -77,7 +84,7 @@ class CClientLeafSystem : public IClientLeafSystem, public ISpatialLeafEnumerato void PreRender(); void PostRender() { } - void Update( float frametime ) { } + void Update( float frametime ) { m_nDebugIndex = 0; } void LevelInitPreEntity(); void LevelInitPostEntity() {} @@ -88,15 +95,19 @@ class CClientLeafSystem : public IClientLeafSystem, public ISpatialLeafEnumerato virtual void OnRestore() {} virtual void SafeRemoveIfDesired() {} +// Methods of IClientAlphaPropertyMgr +public: + virtual IClientAlphaProperty *CreateClientAlphaProperty( IClientUnknown *pUnknown ); + virtual void DestroyClientAlphaProperty( IClientAlphaProperty *pAlphaProperty ); + // Methods of IClientLeafSystem public: - virtual void AddRenderable( IClientRenderable* pRenderable, RenderGroup_t group ); + virtual void AddRenderable( IClientRenderable* pRenderable, bool bRenderWithViewModels, RenderableTranslucencyType_t nType, RenderableModelType_t nModelType, uint32 nSplitscreenEnabledFlags ); virtual bool IsRenderableInPVS( IClientRenderable *pRenderable ); - virtual void CreateRenderableHandle( IClientRenderable* pRenderable, bool bIsStaticProp ); + virtual void CreateRenderableHandle( IClientRenderable* pRenderable, bool bRenderWithViewModels, RenderableTranslucencyType_t nType, RenderableModelType_t nModelType, uint32 nSplitscreenEnabled ); virtual void RemoveRenderable( ClientRenderHandle_t handle ); - virtual void SetSubSystemDataInLeaf( int leaf, int nSubSystemIdx, CClientLeafSubSystemData *pData ); virtual CClientLeafSubSystemData *GetSubSystemDataInLeaf( int leaf, int nSubSystemIdx ); @@ -107,17 +118,24 @@ class CClientLeafSystem : public IClientLeafSystem, public ISpatialLeafEnumerato virtual void DrawDetailObjectsInLeaf( int leaf, int frameNumber, int& nFirstDetailObject, int& nDetailObjectCount ); virtual bool ShouldDrawDetailObjectsInLeaf( int leaf, int frameNumber ); virtual void RenderableChanged( ClientRenderHandle_t handle ); - virtual void SetRenderGroup( ClientRenderHandle_t handle, RenderGroup_t group ); - virtual void ComputeTranslucentRenderLeaf( int count, const LeafIndex_t *pLeafList, const LeafFogVolume_t *pLeafFogVolumeList, int frameNumber, int viewID ); - virtual void CollateViewModelRenderables( CUtlVector< IClientRenderable * >& opaque, CUtlVector< IClientRenderable * >& translucent ); + virtual void CollateViewModelRenderables( CViewModelRenderablesList *pList ); virtual void BuildRenderablesList( const SetupRenderInfo_t &info ); - void CollateRenderablesInLeaf( int leaf, int worldListLeafIndex, const SetupRenderInfo_t &info ); virtual void DrawStaticProps( bool enable ); virtual void DrawSmallEntities( bool enable ); virtual void EnableAlternateSorting( ClientRenderHandle_t handle, bool bEnable ); + virtual void RenderWithViewModels( ClientRenderHandle_t handle, bool bEnable ); + virtual bool IsRenderingWithViewModels( ClientRenderHandle_t handle ) const; + virtual void SetTranslucencyType( ClientRenderHandle_t handle, RenderableTranslucencyType_t nType ); + virtual RenderableTranslucencyType_t GetTranslucencyType( ClientRenderHandle_t handle ) const; + virtual void SetModelType( ClientRenderHandle_t handle, RenderableModelType_t nType ); + virtual void EnableSplitscreenRendering( ClientRenderHandle_t handle, uint32 nFlags ); + virtual void EnableRendering( ClientRenderHandle_t handle, bool bEnable ); + virtual void EnableBloatedBounds( ClientRenderHandle_t handle, bool bEnable ); + virtual void DisableCachedRenderBounds( ClientRenderHandle_t handle, bool bDisable ); // Adds a renderable to a set of leaves virtual void AddRenderableToLeaves( ClientRenderHandle_t handle, int nLeafCount, unsigned short *pLeaves ); + void AddRenderableToLeaves( ClientRenderHandle_t handle, int nLeafCount, unsigned short *pLeaves, bool bReceiveShadows ); // The following methods are related to shadows... virtual ClientLeafShadowHandle_t AddShadow( ClientShadowHandle_t userId, unsigned short flags ); @@ -127,15 +145,20 @@ class CClientLeafSystem : public IClientLeafSystem, public ISpatialLeafEnumerato virtual void ProjectFlashlight( ClientLeafShadowHandle_t handle, int nLeafCount, const int *pLeafList ); // Find all shadow casters in a set of leaves - virtual void EnumerateShadowsInLeaves( int leafCount, LeafIndex_t* pLeaves, IClientLeafShadowEnum* pEnum ); + virtual void EnumerateShadowsInLeaves( int leafCount, WorldListLeafData_t* pLeaves, IClientLeafShadowEnum* pEnum ); + virtual void RecomputeRenderableLeaves(); + virtual void DisableLeafReinsertion( bool bDisable ); + + //Assuming the renderable would be in a properly built render list, generate a render list entry + virtual RenderGroup_t GenerateRenderListEntry( IClientRenderable *pRenderable, CClientRenderablesList::CEntry &entryOut ); // methods of ISpatialLeafEnumerator public: - bool EnumerateLeaf( int leaf, intp context ); + bool EnumerateLeaf( int leaf, int context ); // Adds a shadow to a leaf - void AddShadowToLeaf( int leaf, ClientLeafShadowHandle_t handle ); + void AddShadowToLeaf( int leaf, ClientLeafShadowHandle_t handle, bool bFlashlight ); // Fill in a list of the leaves this renderable is in. // Returns -1 if the handle is invalid. @@ -148,23 +171,101 @@ class CClientLeafSystem : public IClientLeafSystem, public ISpatialLeafEnumerato static CClientLeafSystem s_ClientLeafSystem; private: - // Creates a new renderable - void NewRenderable( IClientRenderable* pRenderable, RenderGroup_t type, int flags = 0 ); + enum + { + RENDER_FLAGS_DISABLE_RENDERING = 0x01, + RENDER_FLAGS_HASCHANGED = 0x02, + RENDER_FLAGS_ALTERNATE_SORTING = 0x04, + RENDER_FLAGS_RENDER_WITH_VIEWMODELS = 0x08, + RENDER_FLAGS_BLOAT_BOUNDS = 0x10, + RENDER_FLAGS_BOUNDS_VALID = 0x20, + RENDER_FLAGS_BOUNDS_ALWAYS_RECOMPUTE = 0x40, + }; + + // All the information associated with a particular handle + struct RenderableInfo_t + { + IClientRenderable* m_pRenderable; + CClientAlphaProperty *m_pAlphaProperty; + int m_EnumCount; // Have I been added to a particular shadow yet? + int m_nRenderFrame; + unsigned short m_FirstShadow; // The first shadow caster that cast on it + unsigned short m_LeafList; // What leafs is it in? + short m_Area; // -1 if the renderable spans multiple areas. + uint16 m_Flags : 10; // rendering flags + uint16 m_nSplitscreenEnabled : 2; // splitscreen rendering flags + uint16 m_nTranslucencyType : 2; // RenderableTranslucencyType_t + uint16 m_nModelType : 2; // RenderableModelType_t + Vector m_vecBloatedAbsMins; // Use this for tree insertion + Vector m_vecBloatedAbsMaxs; + Vector m_vecAbsMins; // NOTE: These members are not threadsafe!! + Vector m_vecAbsMaxs; // They can be updated from any viewpoint (based on RENDER_FLAGS_BOUNDS_VALID) + }; + + // The leaf contains an index into a list of renderables + struct ClientLeaf_t + { + unsigned short m_FirstElement; + unsigned short m_FirstShadow; + + unsigned short m_FirstDetailProp; + unsigned short m_DetailPropCount; + int m_DetailPropRenderFrame; + CClientLeafSubSystemData *m_pSubSystemData[N_CLSUBSYSTEMS]; + }; + + // Shadow information + struct ShadowInfo_t + { + unsigned short m_FirstLeaf; + unsigned short m_FirstRenderable; + int m_EnumCount; + ClientShadowHandle_t m_Shadow; + unsigned short m_Flags; + }; + + struct EnumResult_t + { + int leaf; + EnumResult_t *pNext; + }; + + struct EnumResultList_t + { + EnumResult_t *pHead; + ClientRenderHandle_t handle; + }; + + struct BuildRenderListInfo_t + { + Vector m_vecMins; + Vector m_vecMaxs; + short m_nArea; + uint8 m_nAlpha; + bool m_bPerformOcclusionTest : 1; + bool m_bIgnoreZBuffer : 1; + }; + + struct AlphaInfo_t + { + CClientAlphaProperty *m_pAlphaProperty; + Vector m_vecCenter; + float m_flRadius; + float m_flFadeFactor; + }; +private: // Adds a renderable to the list of renderables - void AddRenderableToLeaf( int leaf, ClientRenderHandle_t handle ); + void AddRenderableToLeaf( int leaf, ClientRenderHandle_t handle, bool bReceiveShadows ); - void SortEntities( const Vector &vecRenderOrigin, const Vector &vecRenderForward, CClientRenderablesList::CEntry *pEntities, int nEntities ); + void SortEntities( const Vector &vecRenderOrigin, const Vector &vecRenderForward, CClientRenderablesList::CEntry *pEntities, int nEntities ); // Returns -1 if the renderable spans more than one area. If it's totally in one area, then this returns the leaf. short GetRenderableArea( ClientRenderHandle_t handle ); // remove renderables from leaves - void InsertIntoTree( ClientRenderHandle_t &handle ); void RemoveFromTree( ClientRenderHandle_t handle ); - - // Returns if it's a view model render group - inline bool IsViewModelRenderGroup( RenderGroup_t group ) const; + void InsertIntoTree( ClientRenderHandle_t &handle, const Vector &absMins, const Vector &absMaxs ); // Adds, removes renderables from view model list void AddToViewModelList( ClientRenderHandle_t handle ); @@ -174,10 +275,6 @@ class CClientLeafSystem : public IClientLeafSystem, public ISpatialLeafEnumerato void InsertTranslucentRenderable( IClientRenderable* pRenderable, int& count, IClientRenderable** pList, float* pDist ); - // Used to change renderables from translucent to opaque - // Only really used by the static prop fading... - void ChangeRenderableRenderGroup( ClientRenderHandle_t handle, RenderGroup_t group ); - // Adds a shadow to a leaf/removes shadow from renderable void AddShadowToRenderable( ClientRenderHandle_t renderHandle, ClientLeafShadowHandle_t shadowHandle ); void RemoveShadowFromRenderables( ClientLeafShadowHandle_t handle ); @@ -188,6 +285,23 @@ class CClientLeafSystem : public IClientLeafSystem, public ISpatialLeafEnumerato // Adds a shadow to a leaf/removes shadow from leaf void RemoveShadowFromLeaves( ClientLeafShadowHandle_t handle ); + // Methods related to renderable list building + int ExtractStaticProps( int nCount, RenderableInfo_t **ppRenderables ); + int ExtractSplitscreenRenderables( int nCount, RenderableInfo_t **ppRenderables ); + int ExtractTranslucentRenderables( int nCount, RenderableInfo_t **ppRenderables ); + int ExtractDuplicates( int nFrameNumber, int nCount, RenderableInfo_t **ppRenderables ); + void ComputeBounds( int nCount, RenderableInfo_t **ppRenderables, BuildRenderListInfo_t *pRLInfo ); + int ExtractCulledRenderables( int nCount, RenderableInfo_t **ppRenderables, BuildRenderListInfo_t *pRLInfo ); + int ExtractOccludedRenderables( int nCount, RenderableInfo_t **ppRenderables, BuildRenderListInfo_t *pRLInfo ); + void AddRenderablesToRenderLists( const SetupRenderInfo_t &info, int nCount, RenderableInfo_t **ppRenderables, BuildRenderListInfo_t *pRLInfo, int nDetailCount, DetailRenderableInfo_t *pDetailInfo ); + void AddDependentRenderables( const SetupRenderInfo_t &info ); + + int ComputeTranslucency( int nFrameNumber, int nViewID, int nCount, RenderableInfo_t **ppRenderables, BuildRenderListInfo_t *pRLInfo ); + void ComputeDistanceFade( int nCount, AlphaInfo_t *pAlphaInfo, BuildRenderListInfo_t *pRLInfo ); + void ComputeScreenFade( const ScreenSizeComputeInfo_t &info, float flMinScreenWidth, float flMaxScreenWidth, int nCount, AlphaInfo_t *pAlphaInfo ); + + void CalcRenderableWorldSpaceAABB_Bloated( const RenderableInfo_t &info, Vector &absMin, Vector &absMax ); + // Methods associated with the various bi-directional sets static unsigned short& FirstRenderableInLeaf( int leaf ) { @@ -229,69 +343,6 @@ class CClientLeafSystem : public IClientLeafSystem, public ISpatialLeafEnumerato mdlcache->EndLock(); } -private: - enum - { - RENDER_FLAGS_TWOPASS = 0x01, - RENDER_FLAGS_STATIC_PROP = 0x02, - RENDER_FLAGS_BRUSH_MODEL = 0x04, - RENDER_FLAGS_STUDIO_MODEL = 0x08, - RENDER_FLAGS_HASCHANGED = 0x10, - RENDER_FLAGS_ALTERNATE_SORTING = 0x20, - }; - - // All the information associated with a particular handle - struct RenderableInfo_t - { - IClientRenderable* m_pRenderable; - int m_RenderFrame; // which frame did I render it in? - int m_RenderFrame2; - int m_EnumCount; // Have I been added to a particular shadow yet? - int m_TranslucencyCalculated; - unsigned short m_LeafList; // What leafs is it in? - unsigned short m_RenderLeaf; // What leaf do I render in? - unsigned char m_Flags; // rendering flags - unsigned char m_RenderGroup; // RenderGroup_t type - unsigned short m_FirstShadow; // The first shadow caster that cast on it - short m_Area; // -1 if the renderable spans multiple areas. - signed char m_TranslucencyCalculatedView; - }; - - // The leaf contains an index into a list of renderables - struct ClientLeaf_t - { - unsigned short m_FirstElement; - unsigned short m_FirstShadow; - - unsigned short m_FirstDetailProp; - unsigned short m_DetailPropCount; - int m_DetailPropRenderFrame; - CClientLeafSubSystemData *m_pSubSystemData[N_CLSUBSYSTEMS]; - - }; - - // Shadow information - struct ShadowInfo_t - { - unsigned short m_FirstLeaf; - unsigned short m_FirstRenderable; - int m_EnumCount; - ClientShadowHandle_t m_Shadow; - unsigned short m_Flags; - }; - - struct EnumResult_t - { - int leaf; - EnumResult_t *pNext; - }; - - struct EnumResultList_t - { - EnumResult_t *pHead; - ClientRenderHandle_t handle; - }; - // Stores data associated with each leaf. CUtlVector< ClientLeaf_t > m_Leaf; @@ -319,23 +370,62 @@ class CClientLeafSystem : public IClientLeafSystem, public ISpatialLeafEnumerato // Should I draw static props? bool m_DrawStaticProps; bool m_DrawSmallObjects; + bool m_bDisableLeafReinsertion; // A little enumerator to help us when adding shadows to renderables int m_ShadowEnum; - CTSList m_DeferredInserts; + // Does anything use alternate sorting? + int m_nAlternateSortCount; + + // Number of alpha properties out there + int m_nAlphaPropertyCount; + + CUtlMemoryPool m_AlphaPropertyPool; + + int m_nDebugIndex; }; +//----------------------------------------------------------------------------- +// Methods of IClientAlphaPropertyMgr +//----------------------------------------------------------------------------- +IClientAlphaProperty *CClientLeafSystem::CreateClientAlphaProperty( IClientUnknown *pUnk ) +{ + ++m_nAlphaPropertyCount; + CClientAlphaProperty *pProperty = (CClientAlphaProperty*)m_AlphaPropertyPool.Alloc( sizeof(CClientAlphaProperty) ); + Construct( pProperty ); + pProperty->Init( pUnk ); + return pProperty; +} + +void CClientLeafSystem::DestroyClientAlphaProperty( IClientAlphaProperty *pAlphaProperty ) +{ + if ( !pAlphaProperty ) + return; + + Destruct( static_cast( pAlphaProperty ) ); + m_AlphaPropertyPool.Free( pAlphaProperty ); + Assert( m_nAlphaPropertyCount > 0 ); + if ( --m_nAlphaPropertyCount == 0 ) + { + m_AlphaPropertyPool.Clear(); + } +} + + //----------------------------------------------------------------------------- // Expose IClientLeafSystem to the client dll. //----------------------------------------------------------------------------- CClientLeafSystem CClientLeafSystem::s_ClientLeafSystem; IClientLeafSystem *g_pClientLeafSystem = &CClientLeafSystem::s_ClientLeafSystem; +IClientAlphaPropertyMgr *g_pClientAlphaPropertyMgr = &CClientLeafSystem::s_ClientLeafSystem; EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CClientLeafSystem, IClientLeafSystem, CLIENTLEAFSYSTEM_INTERFACE_VERSION, CClientLeafSystem::s_ClientLeafSystem ); +EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CClientLeafSystem, IClientAlphaPropertyMgr, CLIENT_ALPHA_PROPERTY_MGR_INTERFACE_VERSION, CClientLeafSystem::s_ClientLeafSystem ); void CalcRenderableWorldSpaceAABB_Fast( IClientRenderable *pRenderable, Vector &absMin, Vector &absMax ); + //----------------------------------------------------------------------------- // Helper functions. //----------------------------------------------------------------------------- @@ -344,9 +434,9 @@ void DefaultRenderBoundsWorldspace( IClientRenderable *pRenderable, Vector &absM // Tracker 37433: This fixes a bug where if the stunstick is being wielded by a combine soldier, the fact that the stick was // attached to the soldier's hand would move it such that it would get frustum culled near the edge of the screen. C_BaseEntity *pEnt = pRenderable->GetIClientUnknown()->GetBaseEntity(); - if ( pEnt && pEnt->IsFollowingEntity() ) + if ( pEnt && ( pEnt->IsFollowingEntity() || ( pEnt->GetParentAttachment() > 0 ) ) ) { - C_BaseEntity *pParent = pEnt->GetFollowedEntity(); + C_BaseEntity *pParent = pEnt->GetMoveParent(); if ( pParent ) { // Get the parent's abs space world bounds. @@ -374,17 +464,15 @@ void DefaultRenderBoundsWorldspace( IClientRenderable *pRenderable, Vector &absM // Another option is to pass the OBB down the tree; makes for a better fit // Generate a world-aligned AABB const QAngle& angles = pRenderable->GetRenderAngles(); - const Vector& origin = pRenderable->GetRenderOrigin(); if (angles == vec3_angle) { + const Vector& origin = pRenderable->GetRenderOrigin(); VectorAdd( mins, origin, absMins ); VectorAdd( maxs, origin, absMaxs ); } else { - matrix3x4_t boxToWorld; - AngleMatrix( angles, origin, boxToWorld ); - TransformAABB( boxToWorld, mins, maxs, absMins, absMaxs ); + TransformAABB( pRenderable->RenderableToWorldTransform(), mins, maxs, absMins, absMaxs ); } Assert( absMins.IsValid() && absMaxs.IsValid() ); } @@ -404,7 +492,7 @@ inline void CalcRenderableWorldSpaceAABB( void CalcRenderableWorldSpaceAABB_Fast( IClientRenderable *pRenderable, Vector &absMin, Vector &absMax ) { C_BaseEntity *pEnt = pRenderable->GetIClientUnknown()->GetBaseEntity(); - if ( pEnt && pEnt->IsFollowingEntity() ) + if ( pEnt && ( pEnt->IsFollowingEntity() || ( pEnt->GetMoveParent() && ( pEnt->GetParentAttachment() > 0 ) ) ) ) { C_BaseEntity *pParent = pEnt->GetMoveParent(); Assert( pParent ); @@ -431,16 +519,18 @@ void CalcRenderableWorldSpaceAABB_Fast( IClientRenderable *pRenderable, Vector & } } - //----------------------------------------------------------------------------- // constructor, destructor //----------------------------------------------------------------------------- -CClientLeafSystem::CClientLeafSystem() : m_DrawStaticProps(true), m_DrawSmallObjects(true) +CClientLeafSystem::CClientLeafSystem() : m_DrawStaticProps(true), m_DrawSmallObjects(true), + m_AlphaPropertyPool( sizeof( CClientAlphaProperty ), 1024, CUtlMemoryPool::GROW_SLOW, "CClientAlphaProperty" ) { // Set up the bi-directional lists... m_RenderablesInLeaf.Init( FirstRenderableInLeaf, FirstLeafInRenderable ); m_ShadowsInLeaf.Init( FirstShadowInLeaf, FirstLeafInShadow ); m_ShadowsOnRenderable.Init( FirstShadowOnRenderable, FirstRenderableInShadow ); + m_nAlternateSortCount = 0; + m_bDisableLeafReinsertion = false; } CClientLeafSystem::~CClientLeafSystem() @@ -460,6 +550,11 @@ void CClientLeafSystem::DrawSmallEntities( bool enable ) m_DrawSmallObjects = enable; } +void CClientLeafSystem::DisableLeafReinsertion( bool bDisable ) +{ + m_bDisableLeafReinsertion = bDisable; +} + //----------------------------------------------------------------------------- // Level init, shutdown @@ -497,6 +592,7 @@ void CClientLeafSystem::LevelShutdownPreEntity() void CClientLeafSystem::LevelShutdownPostEntity() { + m_nAlternateSortCount = 0; m_ViewModels.Purge(); m_Renderables.Purge(); m_RenderablesInLeaf.Purge(); @@ -521,16 +617,69 @@ void CClientLeafSystem::LevelShutdownPostEntity() } +//----------------------------------------------------------------------------- +// Computes a bloated bounding box to reduce insertions into the tree +//----------------------------------------------------------------------------- +#define BBOX_GRANULARITY 32.0f +#define MIN_SHRINK_VOLUME ( 32.0f * 32.0f * 32.0f ) + +void CClientLeafSystem::CalcRenderableWorldSpaceAABB_Bloated( const RenderableInfo_t &info, Vector &absMin, Vector &absMax ) +{ + CalcRenderableWorldSpaceAABB_Fast( info.m_pRenderable, absMin, absMax ); + + // Bloat bounds to avoid reinsertion into tree + absMin.x = floor( absMin.x / BBOX_GRANULARITY ) * BBOX_GRANULARITY; + absMin.y = floor( absMin.y / BBOX_GRANULARITY ) * BBOX_GRANULARITY; + absMin.z = floor( absMin.z / BBOX_GRANULARITY ) * BBOX_GRANULARITY; + + absMax.x = ceil( absMax.x / BBOX_GRANULARITY ) * BBOX_GRANULARITY; + absMax.y = ceil( absMax.y / BBOX_GRANULARITY ) * BBOX_GRANULARITY; + absMax.z = ceil( absMax.z / BBOX_GRANULARITY ) * BBOX_GRANULARITY; + + // Optimization to make particle systems not re-insert themselves + if ( info.m_Flags & RENDER_FLAGS_BLOAT_BOUNDS ) + { + Vector vecTempMin, vecTempMax; + VectorMin( info.m_vecBloatedAbsMins, absMin, vecTempMin ); + VectorMax( info.m_vecBloatedAbsMaxs, absMax, vecTempMax ); + float flTempVolume = ComputeVolume( vecTempMin, vecTempMax ); + float flCurrVolume = ComputeVolume( absMin, absMax ); + + if ( ( flTempVolume <= MIN_SHRINK_VOLUME ) || ( flCurrVolume * 2.0f >= flTempVolume ) ) + { + absMin = vecTempMin; + absMax = vecTempMax; + } + } +} + + //----------------------------------------------------------------------------- // This is what happens before rendering a particular view //----------------------------------------------------------------------------- void CClientLeafSystem::PreRender() { - VPROF_BUDGET( "CClientLeafSystem::PreRender", "PreRender" ); +// Assert( m_DirtyRenderables.Count() == 0 ); + + // FIXME: This should never need to happen here! + // At the moment, it's necessary because of the horrid viewmodel/combatweapon + // confusion in the code where a combat weapon changes its rendering model + // per view. + RecomputeRenderableLeaves(); +} + +// Use this to make sure we're not adding the same renderables to the list while we're going through and re-inserting them into the clientleafsystem +static bool s_bIsInRecomputeRenderableLeaves = false; +void CClientLeafSystem::RecomputeRenderableLeaves() +{ +// MiniProfilerGuard mpGuard(&g_mpRecomputeLeaves); int i; int nIterations = 0; + bool bDebugLeafSystem = !IsX360() && cl_leafsystemvis.GetBool(); + + Vector absMins, absMaxs; while ( m_DirtyRenderables.Count() ) { if ( ++nIterations > 10 ) @@ -539,49 +688,42 @@ void CClientLeafSystem::PreRender() break; } + s_bIsInRecomputeRenderableLeaves = true; + int nDirty = m_DirtyRenderables.Count(); for ( i = nDirty; --i >= 0; ) { ClientRenderHandle_t handle = m_DirtyRenderables[i]; - Assert( m_Renderables[ handle ].m_Flags & RENDER_FLAGS_HASCHANGED ); + RenderableInfo_t &info = m_Renderables[ handle ]; - // Update position in leaf system - RemoveFromTree( handle ); - } + Assert( info.m_Flags & RENDER_FLAGS_HASCHANGED ); - bool bThreaded = false;//( nDirty > 5 && cl_threaded_client_leaf_system.GetBool() && g_pThreadPool->NumThreads() ); + // See note below + info.m_Flags &= ~RENDER_FLAGS_HASCHANGED; - if ( !bThreaded ) - { - for ( i = nDirty; --i >= 0; ) - { - InsertIntoTree( m_DirtyRenderables[i] ); - } - } - else - { - // InsertIntoTree can result in new renderables being added, so copy: - ClientRenderHandle_t *pDirtyRenderables = (ClientRenderHandle_t *)alloca( sizeof(ClientRenderHandle_t) * nDirty ); - memcpy( pDirtyRenderables, m_DirtyRenderables.Base(), sizeof(ClientRenderHandle_t) * nDirty ); - ParallelProcess( "CClientLeafSystem::PreRender", pDirtyRenderables, nDirty, this, &CClientLeafSystem::InsertIntoTree, &CClientLeafSystem::FrameLock, &CClientLeafSystem::FrameUnlock ); - } + if ( info.m_Flags & RENDER_FLAGS_RENDER_WITH_VIEWMODELS ) + continue; - if ( m_DeferredInserts.Count() ) - { - EnumResultList_t enumResultList; - while ( m_DeferredInserts.PopItem( &enumResultList ) ) + CalcRenderableWorldSpaceAABB_Bloated( info, absMins, absMaxs ); + if ( absMins != info.m_vecBloatedAbsMins || absMaxs != info.m_vecBloatedAbsMaxs ) { - m_ShadowEnum++; - while ( enumResultList.pHead ) + // Update position in leaf system + RemoveFromTree( handle ); + InsertIntoTree( m_DirtyRenderables[i], absMins, absMaxs ); + if ( bDebugLeafSystem ) { - EnumResult_t *p = enumResultList.pHead; - enumResultList.pHead = p->pNext; - AddRenderableToLeaf( p->leaf, enumResultList.handle ); - delete p; + debugoverlay->AddBoxOverlay( vec3_origin, absMins, absMaxs, QAngle( 0, 0, 0 ), 0, 255, 0, 0, 0 ); } } } + s_bIsInRecomputeRenderableLeaves = false; + + // NOTE: If we get the following error displayed in the console spew + // "Re-entrancy found in CClientLeafSystem::RenderableChanged\n" + // We'll have to reenable this code and remove the line that + // removes the RENDER_FLAGS_HASCHANGED in the loop above. + /* for ( i = nDirty; --i >= 0; ) { // Cache off the area it's sitting in. @@ -589,8 +731,8 @@ void CClientLeafSystem::PreRender() RenderableInfo_t& renderable = m_Renderables[ handle ]; renderable.m_Flags &= ~RENDER_FLAGS_HASCHANGED; - m_Renderables[handle].m_Area = GetRenderableArea( handle ); } + */ m_DirtyRenderables.RemoveMultiple( 0, nDirty ); } @@ -600,7 +742,7 @@ void CClientLeafSystem::PreRender() //----------------------------------------------------------------------------- // Creates a new renderable //----------------------------------------------------------------------------- -void CClientLeafSystem::NewRenderable( IClientRenderable* pRenderable, RenderGroup_t type, int flags ) +void CClientLeafSystem::CreateRenderableHandle( IClientRenderable* pRenderable, bool bRenderWithViewModels, RenderableTranslucencyType_t nType, RenderableModelType_t nModelType, uint32 nSplitscreenEnabled ) { Assert( pRenderable ); Assert( pRenderable->RenderHandle() == INVALID_CLIENT_RENDER_HANDLE ); @@ -608,79 +750,155 @@ void CClientLeafSystem::NewRenderable( IClientRenderable* pRenderable, RenderGro ClientRenderHandle_t handle = m_Renderables.AddToTail(); RenderableInfo_t &info = m_Renderables[handle]; - // We need to know if it's a brush model for shadows - int modelType = modelinfo->GetModelType( pRenderable->GetModel() ); - if (modelType == mod_brush) + if ( nModelType == RENDERABLE_MODEL_UNKNOWN_TYPE ) { - flags |= RENDER_FLAGS_BRUSH_MODEL; + int nType = modelinfo->GetModelType( pRenderable->GetModel() ); + switch( nType ) + { + default: nModelType = RENDERABLE_MODEL_ENTITY; break; + case mod_brush: nModelType = RENDERABLE_MODEL_BRUSH; break; + case mod_studio: nModelType = RENDERABLE_MODEL_STUDIOMDL; break; + } } - else if ( modelType == mod_studio ) + +#ifdef _DEBUG + // We need to know if it's a brush model for shadows + int modelType = modelinfo->GetModelType( pRenderable->GetModel() ); + switch ( modelType ) { - flags |= RENDER_FLAGS_STUDIO_MODEL; + case mod_brush: Assert( nModelType == RENDERABLE_MODEL_BRUSH ); break; + case mod_studio: Assert( nModelType == RENDERABLE_MODEL_STUDIOMDL || nModelType == RENDERABLE_MODEL_STATIC_PROP ); break; + case mod_sprite: default: Assert( nModelType == RENDERABLE_MODEL_ENTITY ); break; } +#endif info.m_pRenderable = pRenderable; - info.m_RenderFrame = -1; - info.m_RenderFrame2 = -1; - info.m_TranslucencyCalculated = -1; - info.m_TranslucencyCalculatedView = VIEW_ILLEGAL; + info.m_pAlphaProperty = static_cast< CClientAlphaProperty* >( pRenderable->GetIClientUnknown()->GetClientAlphaProperty() ); info.m_FirstShadow = m_ShadowsOnRenderable.InvalidIndex(); info.m_LeafList = m_RenderablesInLeaf.InvalidIndex(); - info.m_Flags = flags; - info.m_RenderGroup = (unsigned char)type; + info.m_Flags = 0; + info.m_nRenderFrame = -1; info.m_EnumCount = 0; - info.m_RenderLeaf = 0xFFFF; - if ( IsViewModelRenderGroup( (RenderGroup_t)info.m_RenderGroup ) ) - { - AddToViewModelList( handle ); - } + info.m_nSplitscreenEnabled = nSplitscreenEnabled & 0x3; + info.m_nTranslucencyType = nType; + info.m_nModelType = nModelType; + info.m_vecBloatedAbsMins.Init( FLT_MAX, FLT_MAX, FLT_MAX ); + info.m_vecBloatedAbsMaxs.Init( -FLT_MAX, -FLT_MAX, -FLT_MAX ); + info.m_vecAbsMins.Init(); + info.m_vecAbsMaxs.Init(); pRenderable->RenderHandle() = handle; + RenderWithViewModels( handle, bRenderWithViewModels ); +} + + +//----------------------------------------------------------------------------- +// Call this if the model changes +//----------------------------------------------------------------------------- +void CClientLeafSystem::SetTranslucencyType( ClientRenderHandle_t handle, RenderableTranslucencyType_t nType ) +{ + if ( handle == INVALID_CLIENT_RENDER_HANDLE ) + return; + + RenderableInfo_t &info = m_Renderables[handle]; + info.m_nTranslucencyType = nType; } -void CClientLeafSystem::CreateRenderableHandle( IClientRenderable* pRenderable, bool bIsStaticProp ) +RenderableTranslucencyType_t CClientLeafSystem::GetTranslucencyType( ClientRenderHandle_t handle ) const { - // FIXME: The argument is unnecessary if we could get this next line to work - // the reason why we can't is because currently there are IClientRenderables - // which don't correctly implement GetRefEHandle. + if ( handle == INVALID_CLIENT_RENDER_HANDLE ) + return RENDERABLE_IS_OPAQUE; - //bool bIsStaticProp = staticpropmgr->IsStaticProp( pRenderable->GetIClientUnknown() ); + const RenderableInfo_t &info = m_Renderables[handle]; + return (RenderableTranslucencyType_t)info.m_nTranslucencyType; +} - // Add the prop to all the leaves it lies in - RenderGroup_t group = pRenderable->IsTransparent() ? RENDER_GROUP_TRANSLUCENT_ENTITY : RENDER_GROUP_OPAQUE_ENTITY; - bool bTwoPass = false; - if ( group == RENDER_GROUP_TRANSLUCENT_ENTITY ) - { - bTwoPass = pRenderable->IsTwoPass( ); - } +void CClientLeafSystem::EnableSplitscreenRendering( ClientRenderHandle_t handle, uint32 nFlags ) +{ + if ( handle == INVALID_CLIENT_RENDER_HANDLE ) + return; + + RenderableInfo_t &info = m_Renderables[handle]; + info.m_nSplitscreenEnabled = nFlags & 0x3; +} + +void CClientLeafSystem::SetModelType( ClientRenderHandle_t handle, RenderableModelType_t nModelType ) +{ + if ( handle == INVALID_CLIENT_RENDER_HANDLE ) + return; - int flags = 0; - if ( bIsStaticProp ) + RenderableInfo_t &info = m_Renderables[handle]; + if ( nModelType == RENDERABLE_MODEL_UNKNOWN_TYPE ) { - flags = RENDER_FLAGS_STATIC_PROP; - if ( group == RENDER_GROUP_OPAQUE_ENTITY ) + int nType = modelinfo->GetModelType( info.m_pRenderable->GetModel() ); + switch( nType ) { - group = RENDER_GROUP_OPAQUE_STATIC; + default: nModelType = RENDERABLE_MODEL_ENTITY; break; + case mod_brush: nModelType = RENDERABLE_MODEL_BRUSH; break; + case mod_studio: nModelType = RENDERABLE_MODEL_STUDIOMDL; break; } } - if (bTwoPass) + if ( info.m_nModelType != nModelType ) { - flags |= RENDER_FLAGS_TWOPASS; + info.m_nModelType = nModelType; + RenderableChanged( handle ); } +} + +void CClientLeafSystem::EnableRendering( ClientRenderHandle_t handle, bool bEnable ) +{ + if ( handle == INVALID_CLIENT_RENDER_HANDLE ) + return; - NewRenderable( pRenderable, group, flags ); + RenderableInfo_t &info = m_Renderables[handle]; + if ( bEnable ) + { + info.m_Flags &= ~RENDER_FLAGS_DISABLE_RENDERING; + } + else + { + info.m_Flags |= RENDER_FLAGS_DISABLE_RENDERING; + } } +void CClientLeafSystem::EnableBloatedBounds( ClientRenderHandle_t handle, bool bEnable ) +{ + if ( handle == INVALID_CLIENT_RENDER_HANDLE ) + return; -//----------------------------------------------------------------------------- -// Used to change renderables from translucent to opaque -//----------------------------------------------------------------------------- -void CClientLeafSystem::ChangeRenderableRenderGroup( ClientRenderHandle_t handle, RenderGroup_t group ) + RenderableInfo_t &info = m_Renderables[handle]; + if ( bEnable ) + { + info.m_Flags |= RENDER_FLAGS_BLOAT_BOUNDS; + } + else + { + if ( info.m_Flags & RENDER_FLAGS_BLOAT_BOUNDS ) + { + info.m_Flags &= ~RENDER_FLAGS_BLOAT_BOUNDS; + + // Necessary to generate unbloated bounds later + RenderableChanged( handle ); + } + } +} + +void CClientLeafSystem::DisableCachedRenderBounds( ClientRenderHandle_t handle, bool bDisable ) { + if ( handle == INVALID_CLIENT_RENDER_HANDLE ) + return; + RenderableInfo_t &info = m_Renderables[handle]; - info.m_RenderGroup = (unsigned char)group; + if ( bDisable ) + { + info.m_Flags |= RENDER_FLAGS_BOUNDS_ALWAYS_RECOMPUTE; + } + else + { + info.m_Flags &= ~RENDER_FLAGS_BOUNDS_ALWAYS_RECOMPUTE; + } } @@ -692,37 +910,76 @@ void CClientLeafSystem::EnableAlternateSorting( ClientRenderHandle_t handle, boo RenderableInfo_t &info = m_Renderables[handle]; if ( bEnable ) { - info.m_Flags |= RENDER_FLAGS_ALTERNATE_SORTING; + if ( ( info.m_Flags & RENDER_FLAGS_ALTERNATE_SORTING ) == 0 ) + { + ++m_nAlternateSortCount; + info.m_Flags |= RENDER_FLAGS_ALTERNATE_SORTING; + } } else { - info.m_Flags &= ~RENDER_FLAGS_ALTERNATE_SORTING; + if ( ( info.m_Flags & RENDER_FLAGS_ALTERNATE_SORTING ) != 0 ) + { + --m_nAlternateSortCount; + info.m_Flags &= ~RENDER_FLAGS_ALTERNATE_SORTING; + } } } //----------------------------------------------------------------------------- -// Add/remove renderable +// Should this render with viewmodels? //----------------------------------------------------------------------------- -void CClientLeafSystem::AddRenderable( IClientRenderable* pRenderable, RenderGroup_t group ) +void CClientLeafSystem::RenderWithViewModels( ClientRenderHandle_t handle, bool bEnable ) { - // force a relink we we try to draw it for the first time - int flags = RENDER_FLAGS_HASCHANGED; + if ( handle == INVALID_CLIENT_RENDER_HANDLE ) + return; - if ( group == RENDER_GROUP_TWOPASS ) + RenderableInfo_t &info = m_Renderables[handle]; + if ( bEnable ) { - group = RENDER_GROUP_TRANSLUCENT_ENTITY; - flags |= RENDER_FLAGS_TWOPASS; + if ( ( info.m_Flags & RENDER_FLAGS_RENDER_WITH_VIEWMODELS ) == 0 ) + { + info.m_Flags |= RENDER_FLAGS_RENDER_WITH_VIEWMODELS; + AddToViewModelList( handle ); + RemoveFromTree( handle ); + } + } + else + { + if ( ( info.m_Flags & RENDER_FLAGS_RENDER_WITH_VIEWMODELS ) != 0 ) + { + info.m_Flags &= ~RENDER_FLAGS_RENDER_WITH_VIEWMODELS; + RemoveFromViewModelList( handle ); + RenderableChanged( handle ); + } } - - NewRenderable( pRenderable, group, flags ); - ClientRenderHandle_t handle = pRenderable->RenderHandle(); - m_DirtyRenderables.AddToTail( handle ); } -void CClientLeafSystem::RemoveRenderable( ClientRenderHandle_t handle ) + +bool CClientLeafSystem::IsRenderingWithViewModels( ClientRenderHandle_t handle ) const { - // This can happen upon level shutdown + if ( handle == INVALID_CLIENT_RENDER_HANDLE ) + return false; + return ( m_Renderables[handle].m_Flags & RENDER_FLAGS_RENDER_WITH_VIEWMODELS ) != 0; +} + + + +//----------------------------------------------------------------------------- +// Add/remove renderable +//----------------------------------------------------------------------------- +void CClientLeafSystem::AddRenderable( IClientRenderable* pRenderable, bool bRenderWithViewModels, RenderableTranslucencyType_t nType, RenderableModelType_t nModelType, uint32 nSplitscreenEnabled ) +{ + // force a relink we we try to draw it for the first time + CreateRenderableHandle( pRenderable, bRenderWithViewModels, nType, nModelType, nSplitscreenEnabled ); + ClientRenderHandle_t handle = pRenderable->RenderHandle(); + RenderableChanged( handle ); +} + +void CClientLeafSystem::RemoveRenderable( ClientRenderHandle_t handle ) +{ + // This can happen upon level shutdown if (!m_Renderables.IsValidIndex(handle)) return; @@ -731,8 +988,14 @@ void CClientLeafSystem::RemoveRenderable( ClientRenderHandle_t handle ) Assert( handle == pRenderable->RenderHandle() ); pRenderable->RenderHandle() = INVALID_CLIENT_RENDER_HANDLE; - // Reemove the renderable from the dirty list - if ( m_Renderables[handle].m_Flags & RENDER_FLAGS_HASCHANGED ) + int nFlags = m_Renderables[handle].m_Flags; + if ( nFlags & RENDER_FLAGS_ALTERNATE_SORTING ) + { + --m_nAlternateSortCount; + } + + // Remove the renderable from the dirty list + if ( nFlags & RENDER_FLAGS_HASCHANGED ) { // NOTE: This isn't particularly fast (linear search), // but I'm assuming it's an unusual case where we remove @@ -743,7 +1006,7 @@ void CClientLeafSystem::RemoveRenderable( ClientRenderHandle_t handle ) m_DirtyRenderables.FastRemove( i ); } - if ( IsViewModelRenderGroup( (RenderGroup_t)m_Renderables[handle].m_RenderGroup ) ) + if ( IsRenderingWithViewModels( handle ) ) { RemoveFromViewModelList( handle ); } @@ -851,18 +1114,6 @@ bool CClientLeafSystem::IsRenderableInPVS( IClientRenderable *pRenderable ) return render->AreAnyLeavesVisible( leaves, nLeaves ); } -short CClientLeafSystem::GetRenderableArea( ClientRenderHandle_t handle ) -{ - int leaves[128]; - int nLeaves = GetRenderableLeaves( handle, leaves ); - if ( nLeaves == -1 ) - return 0; - - // Now ask the - return engine->GetLeavesArea( leaves, nLeaves ); -} - - void CClientLeafSystem::SetSubSystemDataInLeaf( int leaf, int nSubSystemIdx, CClientLeafSubSystemData *pData ) { assert( nSubSystemIdx < N_CLSUBSYSTEMS ); @@ -885,6 +1136,8 @@ void CClientLeafSystem::SetDetailObjectsInLeaf( int leaf, int firstDetailObject, { m_Leaf[leaf].m_FirstDetailProp = firstDetailObject; m_Leaf[leaf].m_DetailPropCount = detailObjectCount; + if ( detailObjectCount ) + engine->SetLeafFlag( leaf, LEAF_FLAGS_CONTAINS_DETAILOBJECTS ); // for fast searches } //----------------------------------------------------------------------------- @@ -929,7 +1182,7 @@ void CClientLeafSystem::RemoveShadow( ClientLeafShadowHandle_t handle ) inline bool CClientLeafSystem::ShouldRenderableReceiveShadow( ClientRenderHandle_t renderHandle, int nShadowFlags ) { RenderableInfo_t &renderable = m_Renderables[renderHandle]; - if( !( renderable.m_Flags & ( RENDER_FLAGS_BRUSH_MODEL | RENDER_FLAGS_STATIC_PROP | RENDER_FLAGS_STUDIO_MODEL ) ) ) + if ( renderable.m_nModelType == RENDERABLE_MODEL_ENTITY ) return false; return renderable.m_pRenderable->ShouldReceiveProjectedTextures( nShadowFlags ); @@ -950,26 +1203,47 @@ void CClientLeafSystem::AddShadowToRenderable( ClientRenderHandle_t renderHandle m_ShadowsOnRenderable.AddElementToBucket( renderHandle, shadowHandle ); // Also, do some stuff specific to the particular types of renderables - +#if 0 // If the renderable is a brush model, then add this shadow to it - if (m_Renderables[renderHandle].m_Flags & RENDER_FLAGS_BRUSH_MODEL) + IClientRenderable* pRenderable = m_Renderables[renderHandle].m_pRenderable; + switch( m_Renderables[renderHandle].m_nModelType ) { - IClientRenderable* pRenderable = m_Renderables[renderHandle].m_pRenderable; + case RENDERABLE_MODEL_BRUSH: g_pClientShadowMgr->AddShadowToReceiver( m_Shadows[shadowHandle].m_Shadow, pRenderable, SHADOW_RECEIVER_BRUSH_MODEL ); - } - else if( m_Renderables[renderHandle].m_Flags & RENDER_FLAGS_STATIC_PROP ) - { - IClientRenderable* pRenderable = m_Renderables[renderHandle].m_pRenderable; + break; + + case RENDERABLE_MODEL_STATIC_PROP: g_pClientShadowMgr->AddShadowToReceiver( m_Shadows[shadowHandle].m_Shadow, pRenderable, SHADOW_RECEIVER_STATIC_PROP ); - } - else if( m_Renderables[renderHandle].m_Flags & RENDER_FLAGS_STUDIO_MODEL ) - { - IClientRenderable* pRenderable = m_Renderables[renderHandle].m_pRenderable; + break; + + case RENDERABLE_MODEL_STUDIOMDL: g_pClientShadowMgr->AddShadowToReceiver( m_Shadows[shadowHandle].m_Shadow, pRenderable, SHADOW_RECEIVER_STUDIO_MODEL ); + break; + } +#else + // Do AddShadowToReceiver to avoid branching + static const byte arrRecvType[0x4] = { + 0, + SHADOW_RECEIVER_STUDIO_MODEL, + SHADOW_RECEIVER_STATIC_PROP, + SHADOW_RECEIVER_BRUSH_MODEL + }; + COMPILE_TIME_ASSERT( RENDERABLE_MODEL_STUDIOMDL == 1 ); + COMPILE_TIME_ASSERT( RENDERABLE_MODEL_STATIC_PROP == 2 ); + COMPILE_TIME_ASSERT( RENDERABLE_MODEL_BRUSH == 3 ); + + RenderableInfo_t const &ri = m_Renderables[renderHandle]; + if ( ri.m_nModelType < ARRAYSIZE( arrRecvType ) ) + { + g_pClientShadowMgr->AddShadowToReceiver( + m_Shadows[shadowHandle].m_Shadow, + ri.m_pRenderable, + ( ShadowReceiver_t ) arrRecvType[ ri.m_nModelType ] ); } +#endif } void CClientLeafSystem::RemoveShadowFromRenderables( ClientLeafShadowHandle_t handle ) @@ -981,10 +1255,15 @@ void CClientLeafSystem::RemoveShadowFromRenderables( ClientLeafShadowHandle_t ha //----------------------------------------------------------------------------- // Adds a shadow to a leaf/removes shadow from leaf //----------------------------------------------------------------------------- -void CClientLeafSystem::AddShadowToLeaf( int leaf, ClientLeafShadowHandle_t shadow ) +void CClientLeafSystem::AddShadowToLeaf( int leaf, ClientLeafShadowHandle_t shadow, bool bFlashlight ) { m_ShadowsInLeaf.AddElementToBucket( leaf, shadow ); + if ( !( bFlashlight || r_shadows_on_renderables_enable.GetBool() ) ) + { + return; + } + // Add the shadow exactly once to all renderables in the leaf unsigned short i = m_RenderablesInLeaf.FirstElement( leaf ); while ( i != m_RenderablesInLeaf.InvalidIndex() ) @@ -999,8 +1278,6 @@ void CClientLeafSystem::AddShadowToLeaf( int leaf, ClientLeafShadowHandle_t shad info.m_EnumCount = m_ShadowEnum; } - Assert( m_ShadowsInLeaf.NumAllocated() < 2000 ); - i = m_RenderablesInLeaf.NextElement(i); } } @@ -1027,7 +1304,7 @@ void CClientLeafSystem::ProjectShadow( ClientLeafShadowHandle_t handle, int nLea for ( int i = 0; i < nLeafCount; ++i ) { - AddShadowToLeaf( pLeafList[i], handle ); + AddShadowToLeaf( pLeafList[i], handle, false ); } } @@ -1039,14 +1316,14 @@ void CClientLeafSystem::ProjectFlashlight( ClientLeafShadowHandle_t handle, int RemoveShadowFromLeaves( handle ); RemoveShadowFromRenderables( handle ); - Assert( ( m_Shadows[handle].m_Flags & SHADOW_FLAGS_PROJECTED_TEXTURE_TYPE_MASK ) == SHADOW_FLAGS_FLASHLIGHT ); + Assert( ( m_Shadows[handle].m_Flags & SHADOW_FLAGS_PROJECTED_TEXTURE_TYPE_MASK ) != 0 ); // This will help us to avoid adding the shadow multiple times to a renderable ++m_ShadowEnum; for ( int i = 0; i < nLeafCount; ++i ) { - AddShadowToLeaf( pLeafList[i], handle ); + AddShadowToLeaf( pLeafList[i], handle, true ); } } @@ -1054,7 +1331,7 @@ void CClientLeafSystem::ProjectFlashlight( ClientLeafShadowHandle_t handle, int //----------------------------------------------------------------------------- // Find all shadow casters in a set of leaves //----------------------------------------------------------------------------- -void CClientLeafSystem::EnumerateShadowsInLeaves( int leafCount, LeafIndex_t* pLeaves, IClientLeafShadowEnum* pEnum ) +void CClientLeafSystem::EnumerateShadowsInLeaves( int leafCount, WorldListLeafData_t* pLeaves, IClientLeafShadowEnum* pEnum ) { if (leafCount == 0) return; @@ -1064,7 +1341,7 @@ void CClientLeafSystem::EnumerateShadowsInLeaves( int leafCount, LeafIndex_t* pL for (int i = 0; i < leafCount; ++i) { - int leaf = pLeaves[i]; + int leaf = pLeaves[i].leafIndex; unsigned short j = m_ShadowsInLeaf.FirstElement( leaf ); while ( j != m_ShadowsInLeaf.InvalidIndex() ) @@ -1087,31 +1364,61 @@ void CClientLeafSystem::EnumerateShadowsInLeaves( int leafCount, LeafIndex_t* pL //----------------------------------------------------------------------------- // Adds a renderable to a leaf //----------------------------------------------------------------------------- -void CClientLeafSystem::AddRenderableToLeaf( int leaf, ClientRenderHandle_t renderable ) +void CClientLeafSystem::AddRenderableToLeaf( int leaf, ClientRenderHandle_t renderable, bool bReceiveShadows ) { #ifdef VALIDATE_CLIENT_LEAF_SYSTEM m_RenderablesInLeaf.ValidateAddElementToBucket( leaf, renderable ); #endif m_RenderablesInLeaf.AddElementToBucket( leaf, renderable ); - if ( !ShouldRenderableReceiveShadow( renderable, SHADOW_FLAGS_PROJECTED_TEXTURE_TYPE_MASK ) ) + bool bShadowsOnRenderables = r_shadows_on_renderables_enable.GetBool(); + + if ( !bReceiveShadows ) + { return; + } - // Add all shadows in the leaf to the renderable... - unsigned short i = m_ShadowsInLeaf.FirstElement( leaf ); - while (i != m_ShadowsInLeaf.InvalidIndex() ) + if ( bShadowsOnRenderables ) { - ClientLeafShadowHandle_t shadow = m_ShadowsInLeaf.Element(i); - ShadowInfo_t& info = m_Shadows[shadow]; + // skipping this code entirely is only safe with single-pass flashlight (i.e. on the 360) - // Add each shadow exactly once to each renderable - if (info.m_EnumCount != m_ShadowEnum) + // Add all shadows in the leaf to the renderable... + unsigned short i = m_ShadowsInLeaf.FirstElement( leaf ); + while ( i != m_ShadowsInLeaf.InvalidIndex() ) { - AddShadowToRenderable( renderable, shadow ); - info.m_EnumCount = m_ShadowEnum; + ClientLeafShadowHandle_t shadow = m_ShadowsInLeaf.Element(i); + ShadowInfo_t& info = m_Shadows[shadow]; + + // Add each shadow exactly once to each renderable + if ( info.m_EnumCount != m_ShadowEnum ) + { + AddShadowToRenderable( renderable, shadow ); + info.m_EnumCount = m_ShadowEnum; + } + + i = m_ShadowsInLeaf.NextElement(i); } + } + else if ( /*!bShadowsOnRenderables &&*/ IsPC() ) + { + // for non-singlepass flashlight (i.e. PC) we need to still add all flashlights to the renderable + + // Add all flashlights in the leaf to the renderable... + unsigned short i = m_ShadowsInLeaf.FirstElement( leaf ); + while ( i != m_ShadowsInLeaf.InvalidIndex() ) + { + ClientLeafShadowHandle_t shadow = m_ShadowsInLeaf.Element(i); + ShadowInfo_t& info = m_Shadows[shadow]; + + // Add each flashlight exactly once to each renderable + if ( ( info.m_Flags & ( SHADOW_FLAGS_FLASHLIGHT | SHADOW_FLAGS_SIMPLE_PROJECTION ) ) && ( info.m_EnumCount != m_ShadowEnum ) ) + { + AddShadowToRenderable( renderable, shadow ); + info.m_EnumCount = m_ShadowEnum; + } - i = m_ShadowsInLeaf.NextElement(i); + i = m_ShadowsInLeaf.NextElement(i); + } } } @@ -1119,25 +1426,33 @@ void CClientLeafSystem::AddRenderableToLeaf( int leaf, ClientRenderHandle_t rend //----------------------------------------------------------------------------- // Adds a renderable to a set of leaves //----------------------------------------------------------------------------- -void CClientLeafSystem::AddRenderableToLeaves( ClientRenderHandle_t handle, int nLeafCount, unsigned short *pLeaves ) +void CClientLeafSystem::AddRenderableToLeaves( ClientRenderHandle_t handle, int nLeafCount, unsigned short *pLeaves, bool bReceiveShadows ) { for (int j = 0; j < nLeafCount; ++j) { - AddRenderableToLeaf( pLeaves[j], handle ); + AddRenderableToLeaf( pLeaves[j], handle, bReceiveShadows ); } - m_Renderables[handle].m_Area = GetRenderableArea( handle ); + + m_Renderables[handle].m_Area = engine->GetLeavesArea( pLeaves, nLeafCount ); +} + +void CClientLeafSystem::AddRenderableToLeaves( ClientRenderHandle_t handle, int nLeafCount, unsigned short *pLeaves ) +{ + bool bReceiveShadows = ShouldRenderableReceiveShadow( handle, SHADOW_FLAGS_PROJECTED_TEXTURE_TYPE_MASK ); + AddRenderableToLeaves( handle, nLeafCount, pLeaves, bReceiveShadows ); } //----------------------------------------------------------------------------- // Inserts an element into the tree //----------------------------------------------------------------------------- -bool CClientLeafSystem::EnumerateLeaf( int leaf, intp context ) +bool CClientLeafSystem::EnumerateLeaf( int leaf, int context ) { EnumResultList_t *pList = (EnumResultList_t *)context; if ( ThreadInMainThread() ) { - AddRenderableToLeaf( leaf, pList->handle ); + bool bReceiveShadows = ShouldRenderableReceiveShadow( pList->handle, SHADOW_FLAGS_PROJECTED_TEXTURE_TYPE_MASK ); + AddRenderableToLeaf( leaf, pList->handle, bReceiveShadows ); } else { @@ -1149,31 +1464,61 @@ bool CClientLeafSystem::EnumerateLeaf( int leaf, intp context ) return true; } -void CClientLeafSystem::InsertIntoTree( ClientRenderHandle_t &handle ) +void CClientLeafSystem::InsertIntoTree( ClientRenderHandle_t &handle, const Vector &absMins, const Vector &absMaxs ) { - if ( ThreadInMainThread() ) - { - // When we insert into the tree, increase the shadow enumerator - // to make sure each shadow is added exactly once to each renderable - m_ShadowEnum++; - } - - EnumResultList_t list = { NULL, handle }; - // NOTE: The render bounds here are relative to the renderable's coordinate system - IClientRenderable* pRenderable = m_Renderables[handle].m_pRenderable; - Vector absMins, absMaxs; - - CalcRenderableWorldSpaceAABB_Fast( pRenderable, absMins, absMaxs ); + RenderableInfo_t &info = m_Renderables[handle]; Assert( absMins.IsValid() && absMaxs.IsValid() ); + Assert( ( info.m_Flags & RENDER_FLAGS_RENDER_WITH_VIEWMODELS ) == 0 ); + Assert( ThreadInMainThread() ); + + info.m_vecBloatedAbsMins = absMins; + info.m_vecBloatedAbsMaxs = absMaxs; + + // When we insert into the tree, increase the shadow enumerator + // to make sure each shadow is added exactly once to each renderable + m_ShadowEnum++; + unsigned short leafList[1024]; ISpatialQuery* pQuery = engine->GetBSPTreeQuery(); - pQuery->EnumerateLeavesInBox( absMins, absMaxs, this, (intp)&list ); + int leafCount = pQuery->ListLeavesInBox( absMins, absMaxs, leafList, ARRAYSIZE(leafList) ); + bool bReceiveShadows = ShouldRenderableReceiveShadow( handle, SHADOW_FLAGS_PROJECTED_TEXTURE_TYPE_MASK ); - if ( list.pHead ) + if ( !IsX360() && cl_leafsystemvis.GetBool() ) { - m_DeferredInserts.PushItem( list ); + char pTemp[256]; + const char *pClassName = ""; + C_BaseEntity *pEnt = info.m_pRenderable->GetIClientUnknown()->GetBaseEntity(); + if ( pEnt ) + { + pClassName = pEnt->GetClassname(); + } + else + { + CNewParticleEffect *pEffect = dynamic_cast< CNewParticleEffect*>( info.m_pRenderable ); + if ( pEffect ) + { + Q_snprintf( pTemp, sizeof(pTemp), "ps: %s", pEffect->GetName() ); + pClassName = pTemp; + } + else if ( dynamic_cast< CParticleEffectBinding* >( info.m_pRenderable ) ) + { + pClassName = ""; + } + } + + con_nprint_t np; + np.time_to_live = 0.1f; + np.fixed_width_font = true; + np.color[0] = 1.0; + np.color[1] = 0.8; + np.color[2] = 0.1; + np.index = m_nDebugIndex++; + + engine->Con_NXPrintf( &np, "%s", pClassName ); } + + AddRenderableToLeaves( handle, leafCount, leafList, bReceiveShadows ); } //----------------------------------------------------------------------------- @@ -1186,17 +1531,24 @@ void CClientLeafSystem::RemoveFromTree( ClientRenderHandle_t handle ) // Remove all shadows cast onto the object m_ShadowsOnRenderable.RemoveBucket( handle ); - // If the renderable is a brush model, then remove all shadows from it - if (m_Renderables[handle].m_Flags & RENDER_FLAGS_BRUSH_MODEL) + switch( m_Renderables[handle].m_nModelType ) { + case RENDERABLE_MODEL_BRUSH: g_pClientShadowMgr->RemoveAllShadowsFromReceiver( m_Renderables[handle].m_pRenderable, SHADOW_RECEIVER_BRUSH_MODEL ); - } - else if( m_Renderables[handle].m_Flags & RENDER_FLAGS_STUDIO_MODEL ) - { + break; + + case RENDERABLE_MODEL_STATIC_PROP: + g_pClientShadowMgr->RemoveAllShadowsFromReceiver( + m_Renderables[handle].m_pRenderable, SHADOW_RECEIVER_STATIC_PROP ); + break; + + case RENDERABLE_MODEL_STUDIOMDL: g_pClientShadowMgr->RemoveAllShadowsFromReceiver( m_Renderables[handle].m_pRenderable, SHADOW_RECEIVER_STUDIO_MODEL ); + break; } + } @@ -1205,32 +1557,41 @@ void CClientLeafSystem::RemoveFromTree( ClientRenderHandle_t handle ) //----------------------------------------------------------------------------- void CClientLeafSystem::RenderableChanged( ClientRenderHandle_t handle ) { + // This should not be called during view rendering +// Assert( !m_bDisableLeafReinsertion ); + Assert ( handle != INVALID_CLIENT_RENDER_HANDLE ); Assert( m_Renderables.IsValidIndex( handle ) ); if ( !m_Renderables.IsValidIndex( handle ) ) return; - if ( (m_Renderables[handle].m_Flags & RENDER_FLAGS_HASCHANGED ) == 0 ) + RenderableInfo_t &info = m_Renderables[handle]; + info.m_Flags &= ~RENDER_FLAGS_BOUNDS_VALID; + if ( ( info.m_Flags & RENDER_FLAGS_HASCHANGED ) == 0 ) { - m_Renderables[handle].m_Flags |= RENDER_FLAGS_HASCHANGED; + info.m_Flags |= RENDER_FLAGS_HASCHANGED; m_DirtyRenderables.AddToTail( handle ); } -#if _DEBUG +//#if _DEBUG else { + if ( s_bIsInRecomputeRenderableLeaves ) + { + Warning( "------------------------------------------------------------\n" ); + Warning( "------------------------------------------------------------\n" ); + Warning( "------------------------------------------------------------\n" ); + Warning( "------------------------------------------------------------\n" ); + Warning( "Re-entrancy found in CClientLeafSystem::RenderableChanged\n" ); + Warning( "Contact Shanon or Brian\n" ); + Warning( "------------------------------------------------------------\n" ); + Warning( "------------------------------------------------------------\n" ); + Warning( "------------------------------------------------------------\n" ); + Warning( "------------------------------------------------------------\n" ); + } // It had better be in the list Assert( m_DirtyRenderables.Find( handle ) != m_DirtyRenderables.InvalidIndex() ); } -#endif -} - - -//----------------------------------------------------------------------------- -// Returns if it's a view model render group -//----------------------------------------------------------------------------- -inline bool CClientLeafSystem::IsViewModelRenderGroup( RenderGroup_t group ) const -{ - return (group == RENDER_GROUP_VIEW_MODEL_TRANSLUCENT) || (group == RENDER_GROUP_VIEW_MODEL_OPAQUE); +//#endif } @@ -1252,48 +1613,6 @@ void CClientLeafSystem::RemoveFromViewModelList( ClientRenderHandle_t handle ) } -//----------------------------------------------------------------------------- -// Call this to change the render group -//----------------------------------------------------------------------------- -void CClientLeafSystem::SetRenderGroup( ClientRenderHandle_t handle, RenderGroup_t group ) -{ - RenderableInfo_t *pInfo = &m_Renderables[handle]; - - bool twoPass = false; - if ( group == RENDER_GROUP_TWOPASS ) - { - twoPass = true; - group = RENDER_GROUP_TRANSLUCENT_ENTITY; - } - - if ( twoPass ) - { - pInfo->m_Flags |= RENDER_FLAGS_TWOPASS; - } - else - { - pInfo->m_Flags &= ~RENDER_FLAGS_TWOPASS; - } - - bool bOldViewModelRenderGroup = IsViewModelRenderGroup( (RenderGroup_t)pInfo->m_RenderGroup ); - bool bNewViewModelRenderGroup = IsViewModelRenderGroup( group ); - if ( bOldViewModelRenderGroup != bNewViewModelRenderGroup ) - { - if ( bOldViewModelRenderGroup ) - { - RemoveFromViewModelList( handle ); - } - else - { - AddToViewModelList( handle ); - } - } - - pInfo->m_RenderGroup = group; - -} - - //----------------------------------------------------------------------------- // Detail system marks //----------------------------------------------------------------------------- @@ -1320,96 +1639,16 @@ bool CClientLeafSystem::ShouldDrawDetailObjectsInLeaf( int leaf, int frameNumber //----------------------------------------------------------------------------- // Compute which leaf the translucent renderables should render in //----------------------------------------------------------------------------- -void CClientLeafSystem::ComputeTranslucentRenderLeaf( int count, const LeafIndex_t *pLeafList, const LeafFogVolume_t *pLeafFogVolumeList, int frameNumber, int viewID ) -{ - ASSERT_NO_REENTRY(); - VPROF_BUDGET( "CClientLeafSystem::ComputeTranslucentRenderLeaf", "ComputeTranslucentRenderLeaf" ); - - #define LeafToMarker( leaf ) reinterpret_cast(( (leaf) << 1 ) | 1) - #define IsLeafMarker( p ) (bool)((reinterpret_cast(p)) & 1) - #define MarkerToLeaf( p ) (int)((reinterpret_cast(p)) >> 1) - - // For better sorting, we're gonna choose the leaf that is closest to the camera. - // The leaf list passed in here is sorted front to back - bool bThreaded = false;//( cl_threaded_client_leaf_system.GetBool() && g_pThreadPool->NumThreads() ); - int globalFrameCount = gpGlobals->framecount; - int i; - - static CUtlVector orderedList; // @MULTICORE (toml 8/30/2006): will need to make non-static if thread this function - static CUtlVector renderablesToUpdate; - intp leaf = 0; - for ( i = 0; i < count; ++i ) - { - leaf = pLeafList[i]; - orderedList.AddToTail( LeafToMarker( leaf ) ); - - // iterate over all elements in this leaf - unsigned short idx = m_RenderablesInLeaf.FirstElement(leaf); - while (idx != m_RenderablesInLeaf.InvalidIndex()) - { - RenderableInfo_t& info = m_Renderables[m_RenderablesInLeaf.Element(idx)]; - if ( info.m_TranslucencyCalculated != globalFrameCount || info.m_TranslucencyCalculatedView != viewID ) - { - // Compute translucency - if ( bThreaded ) - { - renderablesToUpdate.AddToTail( info.m_pRenderable ); - } - else - { - info.m_pRenderable->ComputeFxBlend(); - } - info.m_TranslucencyCalculated = globalFrameCount; - info.m_TranslucencyCalculatedView = viewID; - } - orderedList.AddToTail( &info ); - idx = m_RenderablesInLeaf.NextElement(idx); - } - } - - if ( bThreaded ) - { - ParallelProcess( "CClientLeafSystem::ComputeTranslucentRenderLeaf", renderablesToUpdate.Base(), renderablesToUpdate.Count(), &CallComputeFXBlend, &::FrameLock, &::FrameUnlock ); - renderablesToUpdate.RemoveAll(); - } - - for ( i = 0; i != orderedList.Count(); i++ ) - { - RenderableInfo_t *pInfo = orderedList[i]; - if ( !IsLeafMarker( pInfo ) ) - { - if( pInfo->m_RenderFrame != frameNumber ) - { - if( pInfo->m_RenderGroup == RENDER_GROUP_TRANSLUCENT_ENTITY ) - { - pInfo->m_RenderLeaf = leaf; - } - pInfo->m_RenderFrame = frameNumber; - } - else if ( pInfo->m_Flags & RENDER_FLAGS_ALTERNATE_SORTING ) - { - if( pInfo->m_RenderGroup == RENDER_GROUP_TRANSLUCENT_ENTITY ) - { - pInfo->m_RenderLeaf = leaf; - } - } - - } - else - { - leaf = MarkerToLeaf( pInfo ); - } - } - - orderedList.RemoveAll(); -} +#define LeafToMarker( leaf ) reinterpret_cast(( (leaf) << 1 ) | 1) +#define IsLeafMarker( p ) (bool)((reinterpret_cast(p)) & 1) +#define MarkerToLeaf( p ) (int)((reinterpret_cast(p)) >> 1) //----------------------------------------------------------------------------- // Adds a renderable to the list of renderables to render this frame //----------------------------------------------------------------------------- inline void AddRenderableToRenderList( CClientRenderablesList &renderList, IClientRenderable *pRenderable, - int iLeaf, RenderGroup_t group, ClientRenderHandle_t renderHandle, bool bTwoPass = false ) + int iLeaf, RenderGroup_t group, int nModelType, uint8 nAlphaModulation, bool bTwoPass = false ) { #ifdef _DEBUG if (cl_drawleaf.GetInt() >= 0) @@ -1429,8 +1668,9 @@ inline void AddRenderableToRenderList( CClientRenderablesList &renderList, IClie CClientRenderablesList::CEntry *pEntry = &renderList.m_RenderGroups[group][curCount]; pEntry->m_pRenderable = pRenderable; pEntry->m_iWorldListInfoLeaf = iLeaf; + pEntry->m_nModelType = nModelType; pEntry->m_TwoPass = bTwoPass; - pEntry->m_RenderHandle = renderHandle; + pEntry->m_InstanceData.m_nAlpha = nAlphaModulation; curCount++; } else @@ -1445,324 +1685,967 @@ inline void AddRenderableToRenderList( CClientRenderablesList &renderList, IClie // Input : renderList - // renderGroup - //----------------------------------------------------------------------------- -void CClientLeafSystem::CollateViewModelRenderables( CUtlVector< IClientRenderable * >& opaque, CUtlVector< IClientRenderable * >& translucent ) +void CClientLeafSystem::CollateViewModelRenderables( CViewModelRenderablesList *pList ) { + CViewModelRenderablesList::RenderGroups_t &opaqueList = pList->m_RenderGroups[ CViewModelRenderablesList::VM_GROUP_OPAQUE ]; + CViewModelRenderablesList::RenderGroups_t &translucentList = pList->m_RenderGroups[ CViewModelRenderablesList::VM_GROUP_TRANSLUCENT ]; + for ( int i = m_ViewModels.Count()-1; i >= 0; --i ) { ClientRenderHandle_t handle = m_ViewModels[i]; RenderableInfo_t& renderable = m_Renderables[handle]; - // NOTE: In some cases, this removes the entity from the view model list - renderable.m_pRenderable->ComputeFxBlend(); - + int nAlpha = renderable.m_pAlphaProperty ? renderable.m_pAlphaProperty->ComputeRenderAlpha( ) : 255; + bool bIsTransparent = ( nAlpha != 255 ) || ( renderable.m_nTranslucencyType != RENDERABLE_IS_OPAQUE ); + // That's why we need to test RENDER_GROUP_OPAQUE_ENTITY - it may have changed in ComputeFXBlend() - if ( renderable.m_RenderGroup == RENDER_GROUP_VIEW_MODEL_OPAQUE || renderable.m_RenderGroup == RENDER_GROUP_OPAQUE_ENTITY ) + if ( !bIsTransparent ) { - opaque.AddToTail( renderable.m_pRenderable ); + int i = opaqueList.AddToTail(); + CViewModelRenderablesList::CEntry *pEntry = &opaqueList[i]; + pEntry->m_pRenderable = renderable.m_pRenderable; + pEntry->m_InstanceData.m_nAlpha = 255; } else { - translucent.AddToTail( renderable.m_pRenderable ); + int i = translucentList.AddToTail(); + CViewModelRenderablesList::CEntry *pEntry = &translucentList[i]; + pEntry->m_pRenderable = renderable.m_pRenderable; + pEntry->m_InstanceData.m_nAlpha = nAlpha; + + if ( renderable.m_nTranslucencyType == RENDERABLE_IS_TWO_PASS ) + { + int i = opaqueList.AddToTail(); + CViewModelRenderablesList::CEntry *pEntry = &opaqueList[i]; + pEntry->m_pRenderable = renderable.m_pRenderable; + pEntry->m_InstanceData.m_nAlpha = 255; + } } } } -static RenderGroup_t DetectBucketedRenderGroup( RenderGroup_t group, float fDimension ) + +//----------------------------------------------------------------------------- +// Sort entities in a back-to-front ordering +//----------------------------------------------------------------------------- +void CClientLeafSystem::SortEntities( const Vector &vecRenderOrigin, const Vector &vecRenderForward, CClientRenderablesList::CEntry *pEntities, int nEntities ) { - float const arrThresholds[ 3 ] = { - 200.f, // tree size - 80.f, // player size - 30.f, // crate size - }; - Assert( ARRAYSIZE( arrThresholds ) + 1 >= RENDER_GROUP_CFG_NUM_OPAQUE_ENT_BUCKETS ); - Assert( group >= RENDER_GROUP_OPAQUE_STATIC && group <= RENDER_GROUP_OPAQUE_ENTITY ); + // Don't sort if we only have 1 entity + if ( nEntities <= 1 ) + return; + + float dists[CClientRenderablesList::MAX_GROUP_ENTITIES]; - int bucketedGroupIndex; - if ( RENDER_GROUP_CFG_NUM_OPAQUE_ENT_BUCKETS <= 2 || - fDimension >= arrThresholds[1] ) + // First get a distance for each entity. + int i; + for( i=0; i < nEntities; i++ ) { - if ( RENDER_GROUP_CFG_NUM_OPAQUE_ENT_BUCKETS <= 1 || - fDimension >= arrThresholds[0] ) - bucketedGroupIndex = 0; - else - bucketedGroupIndex = 1; + IClientRenderable *pRenderable = pEntities[i].m_pRenderable; + + // Compute the center of the object (needed for translucent brush models) + Vector boxcenter; + Vector mins,maxs; + pRenderable->GetRenderBounds( mins, maxs ); + VectorAdd( mins, maxs, boxcenter ); + VectorMA( pRenderable->GetRenderOrigin(), 0.5f, boxcenter, boxcenter ); + + // Compute distance... + Vector delta; + VectorSubtract( boxcenter, vecRenderOrigin, delta ); + dists[i] = DotProduct( delta, vecRenderForward ); } - else + + // H-sort. + int stepSize = 4; + while( stepSize ) { - if ( RENDER_GROUP_CFG_NUM_OPAQUE_ENT_BUCKETS <= 3 || - fDimension >= arrThresholds[2] ) - bucketedGroupIndex = 2; - else - bucketedGroupIndex = 3; - } + int end = nEntities - stepSize; + for( i=0; i < end; i += stepSize ) + { + if( dists[i] > dists[i+stepSize] ) + { + V_swap( pEntities[i], pEntities[i+stepSize] ); + V_swap( dists[i], dists[i+stepSize] ); - // Determine the new bucketed group - RenderGroup_t bucketedGroup = RenderGroup_t( group - ( ( RENDER_GROUP_CFG_NUM_OPAQUE_ENT_BUCKETS - 1 ) - bucketedGroupIndex ) * 2 ); - Assert( bucketedGroup >= RENDER_GROUP_OPAQUE_STATIC_HUGE && bucketedGroup <= RENDER_GROUP_OPAQUE_ENTITY ); - - return bucketedGroup; + if( i == 0 ) + { + i = -stepSize; + } + else + { + i -= stepSize << 1; + } + } + } + + stepSize >>= 1; + } } -void CClientLeafSystem::CollateRenderablesInLeaf( int leaf, int worldListLeafIndex, const SetupRenderInfo_t &info ) + +//----------------------------------------------------------------------------- +// Extracts static props from the list of renderables +//----------------------------------------------------------------------------- +int CClientLeafSystem::ExtractStaticProps( int nCount, RenderableInfo_t **ppRenderables ) { - bool portalTestEnts = r_PortalTestEnts.GetBool() && !r_portalsopenall.GetBool(); - - // Place a fake entity for static/opaque ents in this leaf - AddRenderableToRenderList( *info.m_pRenderList, NULL, worldListLeafIndex, RENDER_GROUP_OPAQUE_STATIC, NULL ); - AddRenderableToRenderList( *info.m_pRenderList, NULL, worldListLeafIndex, RENDER_GROUP_OPAQUE_ENTITY, NULL ); + if ( m_DrawStaticProps ) + return nCount; - // Collate everything. - unsigned short idx = m_RenderablesInLeaf.FirstElement(leaf); - for ( ;idx != m_RenderablesInLeaf.InvalidIndex(); idx = m_RenderablesInLeaf.NextElement(idx) ) + int nUniqueCount = 0; + for ( int i = 0; i < nCount; ++i ) { - ClientRenderHandle_t handle = m_RenderablesInLeaf.Element(idx); - RenderableInfo_t& renderable = m_Renderables[handle]; - - // Early out on static props if we don't want to render them - if ((!m_DrawStaticProps) && (renderable.m_Flags & RENDER_FLAGS_STATIC_PROP)) - continue; + RenderableInfo_t *pInfo = ppRenderables[i]; - // Early out if we're told to not draw small objects (top view only, - /* that's why we don't check the z component). - if (!m_DrawSmallObjects) + if ( !IsLeafMarker( pInfo ) ) { - CCachedRenderInfo& cachedInfo = m_CachedRenderInfos[renderable.m_CachedRenderInfo]; - float sizeX = cachedInfo.m_Maxs.x - cachedInfo.m_Mins.x; - float sizeY = cachedInfo.m_Maxs.y - cachedInfo.m_Mins.y; - if ((sizeX < 50.f) && (sizeY < 50.f)) + // Early out on static props if we don't want to render them + if ( pInfo->m_nModelType == RENDERABLE_MODEL_STATIC_PROP ) + { + // Necessary for dependent models to be grabbed + pInfo->m_nRenderFrame--; continue; - }*/ + } + } + ppRenderables[nUniqueCount++] = pInfo; + } + return nUniqueCount; +} - Assert( m_DrawSmallObjects ); // MOTODO - // Don't hit the same ent in multiple leaves twice. - if ( renderable.m_RenderGroup != RENDER_GROUP_TRANSLUCENT_ENTITY ) - { - if ( renderable.m_RenderFrame2 == info.m_nRenderFrame ) - continue; +//----------------------------------------------------------------------------- +// Extracts renderables that are excluded in splitscreen +//----------------------------------------------------------------------------- +int CClientLeafSystem::ExtractSplitscreenRenderables( int nCount, RenderableInfo_t **ppRenderables ) +{ + if ( !IsSplitScreenSupported() ) + return nCount; - renderable.m_RenderFrame2 = info.m_nRenderFrame; + if ( !engine->IsSplitScreenActive() ) + return nCount; + + ASSERT_LOCAL_PLAYER_RESOLVABLE(); + int nSlotMask = 1 << GET_ACTIVE_SPLITSCREEN_SLOT(); + + int nUniqueCount = 0; + for ( int i = 0; i < nCount; ++i ) + { + RenderableInfo_t *pInfo = ppRenderables[i]; + + if ( !IsLeafMarker( pInfo ) ) + { + // Early out on splitscreen renderables if we don't want to render them + if ( ( pInfo->m_nSplitscreenEnabled & nSlotMask ) == 0 ) + { + // Necessary for dependent models to be grabbed + pInfo->m_nRenderFrame--; + continue; + } } - else // translucent + ppRenderables[nUniqueCount++] = pInfo; + } + return nUniqueCount; +} + + +//----------------------------------------------------------------------------- +// Extracts duplicates +//----------------------------------------------------------------------------- +int CClientLeafSystem::ExtractDuplicates( int nFrameNumber, int nCount, RenderableInfo_t **ppRenderables ) +{ + // NOTE: We don't know whether these renderables are translucent or not + // but we do know if they participate in alternate sorting, which is all we need. + int nUniqueCount = 0; + int nLeaf = 0; + + // For better sorting, we're gonna choose the leaf that is closest to the camera. + // The leaf list passed in here is sorted front to back + + // FIXME: This algorithm won't work in a threaded context since it stores state in renderableinfo_t + if ( m_nAlternateSortCount == 0 ) + { + // I expect this is the typical case; nothing needs alternate sorting + for ( int i = 0; i < nCount; ++i ) { - // Shadow depth skips ComputeTranslucentRenderLeaf! + RenderableInfo_t *pInfo = ppRenderables[i]; + if ( !IsLeafMarker( pInfo ) ) + { + // Skip these bad boys altogether + if ( pInfo->m_Flags & ( RENDER_FLAGS_RENDER_WITH_VIEWMODELS | RENDER_FLAGS_DISABLE_RENDERING ) ) + continue; - // Translucent entities already have had ComputeTranslucentRenderLeaf called on them - // so m_RenderLeaf should be set to the nearest leaf, so that's what we want here. - if ( renderable.m_RenderLeaf != leaf ) - continue; + // If we've seen this already, then we don't need to add it + if ( pInfo->m_nRenderFrame == nFrameNumber ) + continue; + + pInfo->m_nRenderFrame = nFrameNumber; + } + ppRenderables[nUniqueCount++] = pInfo; } + return nUniqueCount; + } - unsigned char nAlpha = 255; - if ( info.m_bDrawTranslucentObjects ) + // Here, we have to worry about alternate sorting. I'm not sure if I + // can do better than 2n unless I cache off counts of each renderable + // in the first loop in BuildRenderablesListV2. I'm doing it this way + // because I don't believe we'll ever use this path. + int nAlternateSortCount = 0; + for ( int i = 0; i < nCount; ++i ) + { + RenderableInfo_t *pInfo = ppRenderables[i]; + if ( !IsLeafMarker( pInfo ) ) { - // Prevent culling if the renderable is invisible - // NOTE: OPAQUE objects can have alpha == 0. - // They are made to be opaque because they don't have to be sorted. - nAlpha = renderable.m_pRenderable->GetFxBlend(); - if ( nAlpha == 0 ) - continue; + // If we've seen this already, then we don't need to add it + if ( ( pInfo->m_Flags & RENDER_FLAGS_ALTERNATE_SORTING ) == 0 ) + { + if( pInfo->m_nRenderFrame == nFrameNumber ) + continue; + pInfo->m_nRenderFrame = nFrameNumber; + } + else + { + // A little convoluted, but I don't want to store any unnecessary state + // Basically, the render frame will == frame number + duplication count by the end + // NOTE: This will produce a problem for a few frames every 4 billion frames when wraparound happens + // tough noogies + ++nAlternateSortCount; + if( pInfo->m_nRenderFrame < nFrameNumber ) + pInfo->m_nRenderFrame = nFrameNumber + 1; + else + ++pInfo->m_nRenderFrame; + } } + ppRenderables[nUniqueCount++] = pInfo; + } - Vector absMins, absMaxs; - CalcRenderableWorldSpaceAABB( renderable.m_pRenderable, absMins, absMaxs ); - // If the renderable is inside an area, cull it using the frustum for that area. - if ( portalTestEnts && renderable.m_Area != -1 ) + if ( nAlternateSortCount ) + { + // Extract out the renderables which use alternate sorting + nCount = nUniqueCount; + nUniqueCount = 0; + nLeaf = 0; + for ( int i = 0; i < nCount; ++i ) { - VPROF( "r_PortalTestEnts" ); - if ( !engine->DoesBoxTouchAreaFrustum( absMins, absMaxs, renderable.m_Area ) ) - continue; + RenderableInfo_t *pInfo = ppRenderables[i]; + if ( !IsLeafMarker( pInfo ) ) + { + if ( pInfo->m_Flags & RENDER_FLAGS_ALTERNATE_SORTING ) + { + // Add in the last one we encountered + if( --pInfo->m_nRenderFrame != nFrameNumber ) + continue; + } + } + + ppRenderables[nUniqueCount++] = pInfo; } - else + } + + return nUniqueCount; +} + + +//----------------------------------------------------------------------------- +// Extracts static props from the list of renderables +//----------------------------------------------------------------------------- +int CClientLeafSystem::ExtractTranslucentRenderables( int nCount, RenderableInfo_t **ppRenderables ) +{ + int nUniqueCount = 0; + for ( int i = 0; i < nCount; ++i ) + { + RenderableInfo_t *pInfo = ppRenderables[i]; + + if ( !IsLeafMarker( pInfo ) ) { - // cull with main frustum - if ( engine->CullBox( absMins, absMaxs ) ) + if ( pInfo->m_nTranslucencyType == RENDERABLE_IS_TRANSLUCENT ) + { + // Necessary for dependent models to be grabbed + pInfo->m_nRenderFrame--; continue; + } } + ppRenderables[nUniqueCount++] = pInfo; + } + return nUniqueCount; +} - // UNDONE: Investigate speed tradeoffs of occlusion culling brush models too? - if ( renderable.m_Flags & RENDER_FLAGS_STUDIO_MODEL ) + +//----------------------------------------------------------------------------- +// Computes translucency for all renderables +//----------------------------------------------------------------------------- +void CClientLeafSystem::ComputeDistanceFade( int nCount, AlphaInfo_t *pAlphaInfo, BuildRenderListInfo_t *pRLInfo ) +{ + // Distance fade computations + float flDistFactorSq = 1.0f; + Vector vecViewOrigin = CurrentViewOrigin(); + C_BasePlayer *pLocal = C_BasePlayer::GetLocalPlayer(); + if ( pLocal ) + { + flDistFactorSq = pLocal->GetFOVDistanceAdjustFactor(); + flDistFactorSq *= flDistFactorSq; + } + + for ( int i = 0; i < nCount; ++i ) + { + CClientAlphaProperty *pAlphaProp = pAlphaInfo[i].m_pAlphaProperty; + if ( !pAlphaProp ) + continue; + + // Distance fade is inactive in this case + if ( pAlphaProp->m_nDistFadeEnd == 0 ) + continue; + + float flCurrentDistanceSq; + if ( pAlphaProp->m_nDistanceFadeMode == CLIENT_ALPHA_DISTANCE_FADE_USE_CENTER ) { - // test to see if this renderable is occluded by the engine's occlusion system - if ( engine->IsOccluded( absMins, absMaxs ) ) - continue; + flCurrentDistanceSq = flDistFactorSq * vecViewOrigin.DistToSqr( pAlphaInfo[i].m_vecCenter ); + } + else + { + flCurrentDistanceSq = flDistFactorSq * CalcSqrDistanceToAABB( pRLInfo[i].m_vecMins, pRLInfo[i].m_vecMaxs, vecViewOrigin ); } -#ifdef INVASION_CLIENT_DLL - if (info.m_flRenderDistSq != 0.0f) + float flDistFadeStartSq = pAlphaProp->m_nDistFadeStart; + flDistFadeStartSq *= flDistFadeStartSq; + if ( flCurrentDistanceSq <= flDistFadeStartSq ) + continue; + + float flDistFadeEndSq = pAlphaProp->m_nDistFadeEnd; + flDistFadeEndSq *= flDistFadeEndSq; + if ( flCurrentDistanceSq >= flDistFadeEndSq ) { - Vector mins, maxs; - renderable.m_pRenderable->GetRenderBounds( mins, maxs ); + pAlphaInfo[i].m_flFadeFactor = 0.0f; + continue; + } - if ((maxs.z - mins.z) < 100) - { - Vector vCenter; - VectorLerp( mins, maxs, 0.5f, vCenter ); - vCenter += renderable.m_pRenderable->GetRenderOrigin(); + // NOTE: Because of the if-checks above, flDistFadeEndSq != flDistFadeStartSq here + pAlphaInfo[i].m_flFadeFactor = ( flDistFadeEndSq - flCurrentDistanceSq ) / ( flDistFadeEndSq - flDistFadeStartSq ); + } +} - float flDistSq = info.m_vecRenderOrigin.DistToSqr( vCenter ); - if (info.m_flRenderDistSq <= flDistSq) - continue; +float ComputeScreenSize( const Vector &vecOrigin, float flRadius, const ScreenSizeComputeInfo_t& info ) +{ + // This is sort of faked, but it's faster that way + // FIXME: Also, there's a much faster way to do this with similar triangles + // but I want to make sure it exactly matches the current matrices, so + // for now, I do it this conservative way + /* + Vector4D testPoint1, testPoint2; + VectorMA( vecOrigin, flRadius, info.m_vecViewUp, testPoint1.AsVector3D() ); + VectorMA( vecOrigin, -flRadius, info.m_vecViewUp, testPoint2.AsVector3D() ); + testPoint1.w = testPoint2.w = 1.0f; + + Vector4D clipPos1, clipPos2; + Vector4DMultiply( info.m_matViewProj, testPoint1, clipPos1 ); + Vector4DMultiply( info.m_matViewProj, testPoint2, clipPos2 ); + if (clipPos1.w >= 0.001f) + { + clipPos1.y /= clipPos1.w; + } + else + { + clipPos1.y *= 1000; + } + if (clipPos2.w >= 0.001f) + { + clipPos2.y /= clipPos2.w; + } + else + { + clipPos2.y *= 1000; + } + + // The divide-by-two here is because y goes from -1 to 1 in projection space + return info.m_nViewportHeight * fabs( clipPos2.y - clipPos1.y ) * 0.5f; + */ + + // NOTE: Optimized version of the above algorithm, which only uses y and w components of clip + // Can also optimize based on clipPos = a +/- b * r + const float *pViewProjY = info.m_matViewProj[1]; + const float *pViewProjW = info.m_matViewProj[3]; + float flODotY = pViewProjY[0] * vecOrigin.x + pViewProjY[1] * vecOrigin.y + pViewProjY[2] * vecOrigin.z + pViewProjY[3]; + float flViewDotY = pViewProjY[0] * info.m_vecViewUp.x + pViewProjY[1] * info.m_vecViewUp.y + pViewProjY[2] * info.m_vecViewUp.z; + flViewDotY *= flRadius; + float flODotW = pViewProjW[0] * vecOrigin.x + pViewProjW[1] * vecOrigin.y + pViewProjW[2] * vecOrigin.z + pViewProjW[3]; + float flViewDotW = pViewProjW[0] * info.m_vecViewUp.x + pViewProjW[1] * info.m_vecViewUp.y + pViewProjW[2] * info.m_vecViewUp.z; + flViewDotW *= flRadius; + float y0 = flODotY + flViewDotY; + float w0 = flODotW + flViewDotW; + y0 *= ( w0 >= 0.001f ) ? ( 1.0f / w0 ) : 1000.0f; + float y1 = flODotY - flViewDotY; + float w1 = flODotW - flViewDotW; + y1 *= ( w1 >= 0.001f ) ? ( 1.0f / w1 ) : 1000.0f; + + // The divide-by-two here is because y goes from -1 to 1 in projection space + return info.m_nViewportHeight * fabs( y1 - y0 ) * 0.5f; +} + +void ComputeScreenSizeInfo( ScreenSizeComputeInfo_t *pInfo ) +{ + CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); + VMatrix viewMatrix, projectionMatrix; + pRenderContext->GetMatrix( MATERIAL_VIEW, &viewMatrix ); + pRenderContext->GetMatrix( MATERIAL_PROJECTION, &projectionMatrix ); + MatrixMultiply( projectionMatrix, viewMatrix, pInfo->m_matViewProj ); + + int x, y, w, h; + pRenderContext->GetViewport( x, y, w, h ); + pInfo->m_nViewportHeight = h; + + pRenderContext->GetWorldSpaceCameraVectors( NULL, NULL, &pInfo->m_vecViewUp ); +} + +void CClientLeafSystem::ComputeScreenFade( const ScreenSizeComputeInfo_t &info, float flMinScreenWidth, float flMaxScreenWidth, int nCount, AlphaInfo_t *pAlphaInfo ) +{ + if ( flMaxScreenWidth <= flMinScreenWidth ) + { + flMaxScreenWidth = flMinScreenWidth; + } + if ( flMinScreenWidth <= 0 ) + return; + + float flFalloffFactor; + if ( flMaxScreenWidth != flMinScreenWidth ) + { + flFalloffFactor = 1.0f / ( flMaxScreenWidth - flMinScreenWidth ); + } + else + { + flFalloffFactor = 1.0f; + } + + for ( int i = 0; i < nCount; ++i ) + { + CClientAlphaProperty *pAlphaProp = pAlphaInfo[i].m_pAlphaProperty; + if ( !pAlphaProp ) + continue; + + // Fade is inactive in this case + if ( pAlphaProp->m_flFadeScale <= 0.0f ) + continue; + + float flPixelWidth = ComputeScreenSize( pAlphaInfo[i].m_vecCenter, pAlphaInfo[i].m_flRadius, info ) / pAlphaProp->m_flFadeScale; + + // NOTE: This is to account for an error in the original screen computations years ago + flPixelWidth *= 2.0f; + + float flAlpha = 0.0f; + if ( flPixelWidth > flMinScreenWidth ) + { + if ( ( flMaxScreenWidth >= 0) && ( flPixelWidth < flMaxScreenWidth ) ) + { + flAlpha = flFalloffFactor * (flPixelWidth - flMinScreenWidth ); + } + else + { + flAlpha = 1.0f; } } + + pAlphaInfo[i].m_flFadeFactor = MIN( pAlphaInfo[i].m_flFadeFactor, flAlpha ); + } +} + +extern ConVar cl_leveloverview; +#ifdef _DEBUG +extern ConVar r_FadeProps; #endif - if( renderable.m_RenderGroup != RENDER_GROUP_TRANSLUCENT_ENTITY ) +int CClientLeafSystem::ComputeTranslucency( int nFrameNumber, int nViewID, int nCount, RenderableInfo_t **ppRenderables, BuildRenderListInfo_t *pRLInfo ) +{ + AlphaInfo_t *pAlphaInfo = (AlphaInfo_t*)stackalloc( nCount * sizeof(AlphaInfo_t) ); + for ( int i = 0; i < nCount; ++i ) + { + RenderableInfo_t *pInfo = ppRenderables[i]; + if ( IsLeafMarker( pInfo ) ) { - RenderGroup_t group = (RenderGroup_t)renderable.m_RenderGroup; - - // Determine object group offset - if ( RENDER_GROUP_CFG_NUM_OPAQUE_ENT_BUCKETS > 1 && - group >= RENDER_GROUP_OPAQUE_STATIC && - group <= RENDER_GROUP_OPAQUE_ENTITY ) - { - Vector dims; - VectorSubtract( absMaxs, absMins, dims ); + pAlphaInfo[i].m_pAlphaProperty = NULL; + continue; + } - float const fDimension = MAX( MAX( fabs(dims.x), fabs(dims.y) ), fabs(dims.z) ); - group = DetectBucketedRenderGroup( group, fDimension ); - - Assert( group >= RENDER_GROUP_OPAQUE_STATIC_HUGE && group <= RENDER_GROUP_OPAQUE_ENTITY ); - } + Vector vecCenter; + VectorAdd( pRLInfo[i].m_vecMaxs, pRLInfo[i].m_vecMins, vecCenter ); + vecCenter *= 0.5f; + pAlphaInfo[i].m_vecCenter = vecCenter; + pAlphaInfo[i].m_flRadius = vecCenter.DistTo( pRLInfo[i].m_vecMaxs ); + pAlphaInfo[i].m_pAlphaProperty = pInfo->m_pAlphaProperty; + pAlphaInfo[i].m_flFadeFactor = 1.0f; + } - AddRenderableToRenderList( *info.m_pRenderList, renderable.m_pRenderable, - worldListLeafIndex, group, handle); + for ( int i = 0; i < nCount; ++i ) + { + // FIXME: Computing the base alpha could potentially be sorted by renderfx type + CClientAlphaProperty *pAlphaProp = pAlphaInfo[i].m_pAlphaProperty; + if ( pAlphaProp ) + { + pRLInfo[i].m_nAlpha = pAlphaProp->ComputeRenderAlpha( ); + pRLInfo[i].m_bIgnoreZBuffer = pAlphaProp->IgnoresZBuffer(); } else { - bool bTwoPass = ((renderable.m_Flags & RENDER_FLAGS_TWOPASS) != 0) && ( nAlpha == 255 ); // Two pass? + pRLInfo[i].m_nAlpha = 255; + pRLInfo[i].m_bIgnoreZBuffer = false; + } + } - // Add to appropriate list if drawing translucent objects (shadow depth mapping will skip this) - if ( info.m_bDrawTranslucentObjects ) - { - AddRenderableToRenderList( *info.m_pRenderList, renderable.m_pRenderable, - worldListLeafIndex, (RenderGroup_t)renderable.m_RenderGroup, handle, bTwoPass ); - } - - if ( bTwoPass ) // Also add to opaque list if it's a two-pass model... - { - AddRenderableToRenderList( *info.m_pRenderList, renderable.m_pRenderable, - worldListLeafIndex, RENDER_GROUP_OPAQUE_ENTITY, handle, bTwoPass ); - } + // If we're taking devshots, don't fade props at all + bool bFadeProps = true; +#ifdef _DEBUG + bFadeProps = r_FadeProps.GetBool(); +#endif + + if ( nViewID == VIEW_3DSKY ) + { + bFadeProps = false; + } + + if ( !g_MakingDevShots && !cl_leveloverview.GetInt() && bFadeProps ) + { + ComputeDistanceFade( nCount, pAlphaInfo, pRLInfo ); + + ScreenSizeComputeInfo_t info; + + CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); + VMatrix viewMatrix, projectionMatrix; + pRenderContext->GetMatrix( MATERIAL_VIEW, &viewMatrix ); + pRenderContext->GetMatrix( MATERIAL_PROJECTION, &projectionMatrix ); + MatrixMultiply( projectionMatrix, viewMatrix, info.m_matViewProj ); + + int x, y, w, h; + pRenderContext->GetViewport( x, y, w, h ); + info.m_nViewportHeight = h; + + pRenderContext->GetWorldSpaceCameraVectors( NULL, NULL, &info.m_vecViewUp ); + + if ( GetViewRenderInstance()->AllowScreenspaceFade() ) + { + float flMinLevelFadeArea, flMaxLevelFadeArea; + modelinfo->GetLevelScreenFadeRange( &flMinLevelFadeArea, &flMaxLevelFadeArea ); + ComputeScreenFade( info, flMinLevelFadeArea, flMaxLevelFadeArea, nCount, pAlphaInfo ); + + float flMinViewFadeArea, flMaxViewFadeArea; + view->GetScreenFadeDistances( &flMinViewFadeArea, &flMaxViewFadeArea ); + ComputeScreenFade( info, flMinViewFadeArea, flMaxViewFadeArea, nCount, pAlphaInfo ); + } + + for ( int i = 0; i < nCount; ++i ) + { + if ( !pAlphaInfo[i].m_pAlphaProperty ) + continue; + + float flAlpha = pRLInfo[i].m_nAlpha * pAlphaInfo[i].m_flFadeFactor; + int nAlpha = (int)flAlpha; + pRLInfo[i].m_nAlpha = clamp( nAlpha, 0, 255 ); + } + } + + // Update shadows + for ( int i = 0; i < nCount; ++i ) + { + CClientAlphaProperty *pAlphaProp = pAlphaInfo[i].m_pAlphaProperty; + if ( !pAlphaProp || ( pAlphaInfo[i].m_pAlphaProperty->m_hShadowHandle == CLIENTSHADOW_INVALID_HANDLE ) ) + continue; + + int nAlpha = pRLInfo[i].m_nAlpha; + if ( pAlphaProp->m_bShadowAlphaOverride ) + { + nAlpha = pAlphaProp->m_pOuter->GetClientRenderable()->OverrideShadowAlphaModulation( nAlpha ); + nAlpha = clamp( nAlpha, 0, 255 ); } + g_pClientShadowMgr->SetFalloffBias( pAlphaInfo[i].m_pAlphaProperty->m_hShadowHandle, (255 - nAlpha) ); } - // Do detail objects. - // These don't have render handles! - if ( info.m_bDrawDetailObjects && ShouldDrawDetailObjectsInLeaf( leaf, info.m_nDetailBuildFrame ) ) + // Strip invisible ones out + int nUniqueCount = 0; + for ( int i = 0; i < nCount; ++i ) { - idx = m_Leaf[leaf].m_FirstDetailProp; - int count = m_Leaf[leaf].m_DetailPropCount; - while( --count >= 0 ) + if ( !IsLeafMarker( ppRenderables[i] ) && ( !pRLInfo[i].m_nAlpha ) ) { - IClientRenderable* pRenderable = DetailObjectSystem()->GetDetailModel(idx); + // Necessary for dependent models to be grabbed + ppRenderables[i]->m_nRenderFrame--; + continue; + } + + ppRenderables[nUniqueCount] = ppRenderables[i]; + pRLInfo[nUniqueCount] = pRLInfo[i]; + ++nUniqueCount; + } + return nUniqueCount; +} + + +//----------------------------------------------------------------------------- +// Computes bounds for all renderables +//----------------------------------------------------------------------------- +void CClientLeafSystem::ComputeBounds( int nCount, RenderableInfo_t **ppRenderables, BuildRenderListInfo_t *pRLInfo ) +{ +// MiniProfilerGuard mpGuard(&g_mpComputeBounds); - // FIXME: This if check here is necessary because the detail object system also maintains lists of sprites... - if (pRenderable) + for ( int i = 0; i < nCount; ++i ) + { + RenderableInfo_t *pInfo = ppRenderables[i]; + if ( IsLeafMarker( pInfo ) ) + continue; + + // UNDONE: Investigate speed tradeoffs of occlusion culling brush models too? + pRLInfo[i].m_bPerformOcclusionTest = ( pInfo->m_nModelType == RENDERABLE_MODEL_STATIC_PROP || pInfo->m_nModelType == RENDERABLE_MODEL_STUDIOMDL ); + pRLInfo[i].m_nArea = pInfo->m_Area; + pRLInfo[i].m_nAlpha = 255; // necessary to set for shadow depth rendering + + // NOTE: This is inherently not threadsafe!! + if ( ( pInfo->m_Flags & RENDER_FLAGS_BOUNDS_VALID ) == 0 ) + { + CalcRenderableWorldSpaceAABB( pInfo->m_pRenderable, pInfo->m_vecAbsMins, pInfo->m_vecAbsMaxs ); + if ( ( pInfo->m_Flags & RENDER_FLAGS_BOUNDS_ALWAYS_RECOMPUTE ) == 0 ) { - if( pRenderable->IsTransparent() ) + C_BaseEntity *pEnt = pInfo->m_pRenderable->GetIClientUnknown()->GetBaseEntity(); + if ( !pEnt || !pEnt->GetMoveParent() ) { - if ( info.m_bDrawTranslucentObjects ) // Don't draw translucent objects into shadow depth maps - { - // Lots of the detail entities are invisible so avoid sorting them and all that. - if( pRenderable->GetFxBlend() > 0 ) - { - AddRenderableToRenderList( *info.m_pRenderList, pRenderable, - worldListLeafIndex, RENDER_GROUP_TRANSLUCENT_ENTITY, DETAIL_PROP_RENDER_HANDLE ); - } - } - } - else - { - AddRenderableToRenderList( *info.m_pRenderList, pRenderable, - worldListLeafIndex, RENDER_GROUP_OPAQUE_ENTITY, DETAIL_PROP_RENDER_HANDLE ); + pInfo->m_Flags |= RENDER_FLAGS_BOUNDS_VALID; } } - ++idx; } +#ifdef _DEBUG + else + { + // If these assertions trigger, it means there's some state that GetRenderBounds + // depends on which, on change, doesn't call ClientLeafSystem::RenderableChanged(). + Vector vecTestMins, vecTestMaxs; + CalcRenderableWorldSpaceAABB( pInfo->m_pRenderable, vecTestMins, vecTestMaxs ); + Assert( VectorsAreEqual( vecTestMins, pInfo->m_vecAbsMins, 1e-3 ) ); + Assert( VectorsAreEqual( vecTestMaxs, pInfo->m_vecAbsMaxs, 1e-3 ) ); + } +#endif + + pRLInfo[i].m_vecMins = pInfo->m_vecAbsMins; + pRLInfo[i].m_vecMaxs = pInfo->m_vecAbsMaxs; } } //----------------------------------------------------------------------------- -// Sort entities in a back-to-front ordering +// Culls renderables based on view frustum + areaportals //----------------------------------------------------------------------------- -void CClientLeafSystem::SortEntities( const Vector &vecRenderOrigin, const Vector &vecRenderForward, CClientRenderablesList::CEntry *pEntities, int nEntities ) +int CClientLeafSystem::ExtractCulledRenderables( int nCount, RenderableInfo_t **ppRenderables, BuildRenderListInfo_t *pRLInfo ) { - // Don't sort if we only have 1 entity - if ( nEntities <= 1 ) - return; + bool bPortalTestEnts = r_PortalTestEnts.GetBool() && !r_portalsopenall.GetBool(); - float dists[CClientRenderablesList::MAX_GROUP_ENTITIES]; + // FIXME: sort by area and inline cull. Should make it a bunch faster + int nUniqueCount = 0; + if ( bPortalTestEnts ) + { + Frustum_t *list[MAX_MAP_AREAS]; + engine->GetFrustumList( list, ARRAYSIZE(list) ); + for ( int i = 0; i < nCount; ++i ) + { + RenderableInfo_t *pInfo = ppRenderables[i]; + BuildRenderListInfo_t &rlInfo = pRLInfo[i]; + if ( !IsLeafMarker( pInfo ) ) + { + int frustumIndex = rlInfo.m_nArea + 1; + if ( list[frustumIndex]->CullBox( rlInfo.m_vecMins, rlInfo.m_vecMaxs ) ) + { + // Necessary for dependent models to be grabbed + pInfo->m_nRenderFrame--; + continue; + } + } + pRLInfo[nUniqueCount] = rlInfo; + ppRenderables[nUniqueCount] = pInfo; + ++nUniqueCount; + } + return nUniqueCount; + } - // First get a distance for each entity. - int i; - for( i=0; i < nEntities; i++ ) + // Debug mode, doesn't need to be fast + for ( int i = 0; i < nCount; ++i ) { - IClientRenderable *pRenderable = pEntities[i].m_pRenderable; + RenderableInfo_t *pInfo = ppRenderables[i]; + BuildRenderListInfo_t &rlInfo = pRLInfo[i]; + if ( !IsLeafMarker( pInfo ) ) + { + // cull with main frustum + if ( engine->CullBox( rlInfo.m_vecMins, rlInfo.m_vecMaxs ) ) + { + // Necessary for dependent models to be grabbed + pInfo->m_nRenderFrame--; + continue; + } + } + pRLInfo[nUniqueCount] = rlInfo; + ppRenderables[nUniqueCount] = pInfo; + ++nUniqueCount; + } + return nUniqueCount; +} - // Compute the center of the object (needed for translucent brush models) - Vector boxcenter; - Vector mins,maxs; - pRenderable->GetRenderBounds( mins, maxs ); - VectorAdd( mins, maxs, boxcenter ); - VectorMA( pRenderable->GetRenderOrigin(), 0.5f, boxcenter, boxcenter ); +//----------------------------------------------------------------------------- +// Culls renderables based on occlusion +//----------------------------------------------------------------------------- +int CClientLeafSystem::ExtractOccludedRenderables( int nCount, RenderableInfo_t **ppRenderables, BuildRenderListInfo_t *pRLInfo ) +{ + static ConVarRef r_occlusion("r_occlusion"); - // Compute distance... - Vector delta; - VectorSubtract( boxcenter, vecRenderOrigin, delta ); - dists[i] = DotProduct( delta, vecRenderForward ); - } + // occlusion is off, just return + if ( !r_occlusion.GetBool() ) + return nCount; - // H-sort. - int stepSize = 4; - while( stepSize ) + int nUniqueCount = 0; + for ( int i = 0; i < nCount; ++i ) { - int end = nEntities - stepSize; - for( i=0; i < end; i += stepSize ) + RenderableInfo_t *pInfo = ppRenderables[i]; + BuildRenderListInfo_t &rlInfo = pRLInfo[i]; + if ( !IsLeafMarker( pInfo ) ) { - if( dists[i] > dists[i+stepSize] ) + if ( rlInfo.m_bPerformOcclusionTest ) { - ::V_swap( pEntities[i], pEntities[i+stepSize] ); - ::V_swap( dists[i], dists[i+stepSize] ); - - if( i == 0 ) + // test to see if this renderable is occluded by the engine's occlusion system + if ( engine->IsOccluded( rlInfo.m_vecMins, rlInfo.m_vecMaxs ) ) { - i = -stepSize; + // Necessary for dependent models to be grabbed + pInfo->m_nRenderFrame--; + continue; } - else + } + } + pRLInfo[nUniqueCount] = rlInfo; + ppRenderables[nUniqueCount] = pInfo; + ++nUniqueCount; + } + + return nUniqueCount; +} + + +//----------------------------------------------------------------------------- +// Adds renderables into their final lists +//----------------------------------------------------------------------------- +void CClientLeafSystem::AddDependentRenderables( const SetupRenderInfo_t &info ) +{ + // NOTE: This turns out to have non-zero cost. + // Remove early out if we actually end up needing to use this + return; + + CClientRenderablesList *pRenderList = info.m_pRenderList; + pRenderList->m_nBoneSetupDependencyCount = 0; + for ( int i = 0; i < RENDER_GROUP_COUNT; ++i ) + { + int nCount = pRenderList->m_RenderGroupCounts[i]; + for ( int j = 0; j < nCount; ++j ) + { + IClientRenderable *pRenderable = pRenderList->m_RenderGroups[i][j].m_pRenderable; + C_BaseEntity *pEnt = pRenderable->GetIClientUnknown()->GetBaseEntity(); + if ( !pEnt ) + continue; + + while ( pEnt->IsFollowingEntity() || ( pEnt->GetMoveParent() && pEnt->GetParentAttachment() > 0 ) ) + { + pEnt = pEnt->GetMoveParent(); + ClientRenderHandle_t hParent = pEnt->GetRenderHandle(); + Assert( hParent != INVALID_CLIENT_RENDER_HANDLE ); + if ( hParent == INVALID_CLIENT_RENDER_HANDLE ) + continue; + RenderableInfo_t &parentInfo = m_Renderables[hParent]; + if ( parentInfo.m_nRenderFrame != info.m_nRenderFrame ) { - i -= stepSize << 1; + parentInfo.m_nRenderFrame = info.m_nRenderFrame; + pRenderList->m_pBoneSetupDependency[ pRenderList->m_nBoneSetupDependencyCount++ ] = pEnt->GetClientRenderable(); } } } + } +} - stepSize >>= 1; + + +//----------------------------------------------------------------------------- +// Adds renderables into their final lists +//----------------------------------------------------------------------------- +void CClientLeafSystem::AddRenderablesToRenderLists( const SetupRenderInfo_t &info, int nCount, RenderableInfo_t **ppRenderables, BuildRenderListInfo_t *pRLInfo, int nDetailCount, DetailRenderableInfo_t *pDetailInfo ) +{ + CClientRenderablesList::CEntry *pTranslucentEntries = info.m_pRenderList->m_RenderGroups[RENDER_GROUP_TRANSLUCENT]; + int &nTranslucentEntries = info.m_pRenderList->m_RenderGroupCounts[RENDER_GROUP_TRANSLUCENT]; + int nTranslucent = 0; + int nCurDetail = 0; + int nWorldListLeafIndex = -1; + for ( int i = 0; i < nCount; ++i ) + { + RenderableInfo_t *pInfo = ppRenderables[i]; + if ( IsLeafMarker( pInfo ) ) + { + // Add detail props for this leaf + for( ; nCurDetail < nDetailCount; ++nCurDetail ) + { + DetailRenderableInfo_t &detailInfo = pDetailInfo[nCurDetail]; + if ( detailInfo.m_nLeafIndex > nWorldListLeafIndex ) + break; + Assert( detailInfo.m_nLeafIndex == nWorldListLeafIndex ); + AddRenderableToRenderList( *info.m_pRenderList, detailInfo.m_pRenderable, + nWorldListLeafIndex, detailInfo.m_nRenderGroup, RENDERABLE_MODEL_ENTITY, detailInfo.m_InstanceData.m_nAlpha ); + } + + int nNewTranslucent = nTranslucentEntries - nTranslucent; + if( ( nNewTranslucent != 0 ) && info.m_bDrawTranslucentObjects ) + { + // Sort the new translucent entities. + SortEntities( info.m_vecRenderOrigin, info.m_vecRenderForward, &pTranslucentEntries[nTranslucent], nNewTranslucent ); + } + nTranslucent = nTranslucentEntries; + nWorldListLeafIndex++; + continue; + } + + bool bIsTranslucent = ( pRLInfo[i].m_nAlpha != 255 ) || ( pInfo->m_nTranslucencyType != RENDERABLE_IS_OPAQUE ); + if ( !bIsTranslucent ) + { + AddRenderableToRenderList( *info.m_pRenderList, pInfo->m_pRenderable, + nWorldListLeafIndex, RENDER_GROUP_OPAQUE, pInfo->m_nModelType, pRLInfo[i].m_nAlpha ); + continue; + } + + // FIXME: Remove call to GetFXBlend + bool bIsTwoPass = ( pInfo->m_nTranslucencyType == RENDERABLE_IS_TWO_PASS ) && ( pRLInfo[i].m_nAlpha == 255 ); // Two pass? + + // Add to appropriate list if drawing translucent objects (shadow depth mapping will skip this) + if ( info.m_bDrawTranslucentObjects ) + { + RenderGroup_t group = pRLInfo[i].m_bIgnoreZBuffer ? RENDER_GROUP_TRANSLUCENT_IGNOREZ : RENDER_GROUP_TRANSLUCENT; + + AddRenderableToRenderList( *info.m_pRenderList, pInfo->m_pRenderable, + nWorldListLeafIndex, group, pInfo->m_nModelType, pRLInfo[i].m_nAlpha, bIsTwoPass ); + } + + if ( bIsTwoPass ) // Also add to opaque list if it's a two-pass model... + { + AddRenderableToRenderList( *info.m_pRenderList, pInfo->m_pRenderable, + nWorldListLeafIndex, RENDER_GROUP_OPAQUE, pInfo->m_nModelType, 255, bIsTwoPass ); + } } + + // Add detail props for this leaf + for( ; nCurDetail < nDetailCount; ++nCurDetail ) + { + DetailRenderableInfo_t &detailInfo = pDetailInfo[nCurDetail]; + if ( detailInfo.m_nLeafIndex > nWorldListLeafIndex ) + break; + Assert( detailInfo.m_nLeafIndex == nWorldListLeafIndex ); + AddRenderableToRenderList( *info.m_pRenderList, detailInfo.m_pRenderable, + nWorldListLeafIndex, detailInfo.m_nRenderGroup, RENDERABLE_MODEL_ENTITY, detailInfo.m_InstanceData.m_nAlpha ); + } + + int nNewTranslucent = nTranslucentEntries - nTranslucent; + if( ( nNewTranslucent != 0 ) && info.m_bDrawTranslucentObjects ) + { + // Sort the new translucent entities. + SortEntities( info.m_vecRenderOrigin, info.m_vecRenderForward, &pTranslucentEntries[nTranslucent], nNewTranslucent ); + } + + AddDependentRenderables( info ); } +static ConVar r_drawallrenderables( "r_drawallrenderables", "0", FCVAR_CHEAT, "Draw all renderables, even ones inside solid leaves." ); +//----------------------------------------------------------------------------- +// Main entry point to build renderable lists +//----------------------------------------------------------------------------- void CClientLeafSystem::BuildRenderablesList( const SetupRenderInfo_t &info ) { - VPROF_BUDGET( "BuildRenderablesList", "BuildRenderablesList" ); - int leafCount = info.m_pWorldListInfo->m_LeafCount; - const Vector &vecRenderOrigin = info.m_vecRenderOrigin; - const Vector &vecRenderForward = info.m_vecRenderForward; - CClientRenderablesList::CEntry *pTranslucentEntries = info.m_pRenderList->m_RenderGroups[RENDER_GROUP_TRANSLUCENT_ENTITY]; - int &nTranslucentEntries = info.m_pRenderList->m_RenderGroupCounts[RENDER_GROUP_TRANSLUCENT_ENTITY]; + ASSERT_NO_REENTRY(); - for( int i = 0; i < leafCount; i++ ) - { - int nTranslucent = nTranslucentEntries; + // Deal with detail objects + CUtlVectorFixedGrowable< DetailRenderableInfo_t, 2048 > detailRenderables( 2048 ); - // Add renderables from this leaf... - CollateRenderablesInLeaf( info.m_pWorldListInfo->m_pLeafList[i], i, info ); + // Get the fade information for detail objects + float flDetailDist = g_pDetailObjectSystem->ComputeDetailFadeInfo( &info.m_pRenderList->m_DetailFade ); + g_pDetailObjectSystem->BuildRenderingData( detailRenderables, info, flDetailDist, info.m_pRenderList->m_DetailFade ); - int nNewTranslucent = nTranslucentEntries - nTranslucent; - if( (nNewTranslucent != 0 ) && info.m_bDrawTranslucentObjects ) + // First build a non-unique list of renderables, separated by special leaf markers + CUtlVectorFixedGrowable< RenderableInfo_t *, 2048 > orderedList( 2048 ); + + if ( info.m_nViewID != VIEW_3DSKY && r_drawallrenderables.GetBool() ) + { + // HACK - treat all renderables as being in first visible leaf + int leaf = info.m_pWorldListInfo->m_pLeafDataList[ 0 ].leafIndex; + orderedList.AddToTail( LeafToMarker( leaf ) ); + + for ( int i = m_Renderables.Head(); i != m_Renderables.InvalidIndex(); i = m_Renderables.Next( i ) ) + { + orderedList.AddToTail( &m_Renderables[ i ] ); + } + } + else + { + int leaf = 0; + for ( int i = 0; i < info.m_pWorldListInfo->m_LeafCount; ++i ) { - // Sort the new translucent entities. - SortEntities( vecRenderOrigin, vecRenderForward, &pTranslucentEntries[nTranslucent], nNewTranslucent ); + leaf = info.m_pWorldListInfo->m_pLeafDataList[i].leafIndex; + orderedList.AddToTail( LeafToMarker( leaf ) ); + + // iterate over all elements in this leaf + unsigned short idx = m_RenderablesInLeaf.FirstElement(leaf); + for ( ; idx != m_RenderablesInLeaf.InvalidIndex(); idx = m_RenderablesInLeaf.NextElement( idx ) ) + { + orderedList.AddToTail( &m_Renderables[ m_RenderablesInLeaf.Element(idx) ] ); + } } } + + // Debugging + int nCount = orderedList.Count(); + RenderableInfo_t **ppRenderables = orderedList.Base(); + nCount = ExtractDuplicates( info.m_nRenderFrame, nCount, ppRenderables ); + nCount = ExtractStaticProps( nCount, ppRenderables ); + nCount = ExtractSplitscreenRenderables( nCount, ppRenderables ); + + if ( !info.m_bDrawTranslucentObjects ) + { + nCount = ExtractTranslucentRenderables( nCount, ppRenderables ); + } + + BuildRenderListInfo_t* pRLInfo = (BuildRenderListInfo_t*)stackalloc( nCount * sizeof(BuildRenderListInfo_t) ); + ComputeBounds( nCount, ppRenderables, pRLInfo ); + + nCount = ExtractCulledRenderables( nCount, ppRenderables, pRLInfo ); + + if ( info.m_bDrawTranslucentObjects ) + { + nCount = ComputeTranslucency( gpGlobals->framecount /*info.m_nRenderFrame*/, info.m_nViewID, nCount, ppRenderables, pRLInfo ); + } + + nCount = ExtractOccludedRenderables( nCount, ppRenderables, pRLInfo ); + + AddRenderablesToRenderLists( info, nCount, ppRenderables, pRLInfo, detailRenderables.Count(), detailRenderables.Base() ); + stackfree( pRLInfo ); +} + + +RenderGroup_t CClientLeafSystem::GenerateRenderListEntry( IClientRenderable *pRenderable, CClientRenderablesList::CEntry &entryOut ) +{ + ClientRenderHandle_t iter = m_Renderables.Head(); + while( m_Renderables.IsValidIndex( iter ) ) + { + RenderableInfo_t &info = m_Renderables.Element( iter ); + if( info.m_pRenderable == pRenderable ) + { + int nAlpha = info.m_pAlphaProperty ? info.m_pAlphaProperty->ComputeRenderAlpha( ) : 255; + bool bIsTranslucent = ( nAlpha != 255 ) || ( info.m_nTranslucencyType != RENDERABLE_IS_OPAQUE ); + + entryOut.m_pRenderable = pRenderable; + entryOut.m_iWorldListInfoLeaf = 0; //info.m_RenderLeaf; + entryOut.m_TwoPass = ( info.m_nTranslucencyType == RENDERABLE_IS_TWO_PASS ); + entryOut.m_nModelType = info.m_nModelType; + entryOut.m_InstanceData.m_nAlpha = nAlpha; + if ( !bIsTranslucent ) + return RENDER_GROUP_OPAQUE; + return info.m_pAlphaProperty->IgnoresZBuffer() ? RENDER_GROUP_TRANSLUCENT_IGNOREZ : RENDER_GROUP_TRANSLUCENT; + } + iter = m_Renderables.Next( iter ); + } + + entryOut.m_pRenderable = NULL; + entryOut.m_iWorldListInfoLeaf = 0; + entryOut.m_TwoPass = false; + entryOut.m_nModelType = RENDERABLE_MODEL_ENTITY; + entryOut.m_InstanceData.m_nAlpha = 255; + + return RENDER_GROUP_COUNT; } diff --git a/game/client/clientleafsystem.h b/game/client/clientleafsystem.h index dd48ec0bb..5761a306a 100644 --- a/game/client/clientleafsystem.h +++ b/game/client/clientleafsystem.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2007, Valve Corporation, All rights reserved. ======// // // Purpose: // @@ -15,10 +15,10 @@ #pragma once #endif -#include "igamesystem.h" +#include "IGameSystem.h" #include "engine/IClientLeafSystem.h" #include "cdll_int.h" -#include "ivrenderview.h" +#include "IVRenderView.h" #include "tier1/mempool.h" #include "tier1/refcount.h" @@ -36,6 +36,18 @@ class Vector2D; class CStaticProp; +//----------------------------------------------------------------------------- +// Render groups +//----------------------------------------------------------------------------- +enum RenderGroup_t +{ + RENDER_GROUP_OPAQUE = 0, + RENDER_GROUP_TRANSLUCENT, + RENDER_GROUP_TRANSLUCENT_IGNOREZ, + RENDER_GROUP_COUNT, // Indicates the groups above are real and used for bucketing a scene +}; + + //----------------------------------------------------------------------------- // Handle to an renderables in the client leaf system //----------------------------------------------------------------------------- @@ -45,6 +57,18 @@ enum }; +//----------------------------------------------------------------------------- +// Distance fade information +//----------------------------------------------------------------------------- +struct DistanceFadeInfo_t +{ + float m_flMaxDistSqr; // distance at which everything is faded out + float m_flMinDistSqr; // distance at which everything is unfaded + float m_flFalloffFactor; // 1.0f / ( maxDistSqr - MinDistSqr ) + // opacity = ( maxDist - distSqr ) * falloffFactor +}; + + class CClientRenderablesList : public CRefCounted<> { DECLARE_FIXEDSIZE_ALLOCATOR( CClientRenderablesList ); @@ -52,20 +76,51 @@ class CClientRenderablesList : public CRefCounted<> public: enum { - MAX_GROUP_ENTITIES = 4096 + MAX_GROUP_ENTITIES = 4096, + MAX_BONE_SETUP_DEPENDENCY = 64, }; struct CEntry { IClientRenderable *m_pRenderable; unsigned short m_iWorldListInfoLeaf; // NOTE: this indexes WorldListInfo_t's leaf list. - unsigned short m_TwoPass; - ClientRenderHandle_t m_RenderHandle; + RenderableInstance_t m_InstanceData; + uint8 m_nModelType : 7; // See RenderableModelType_t + uint8 m_TwoPass : 1; + }; + + // The leaves for the entries are in the order of the leaves you call CollateRenderablesInLeaf in. + DistanceFadeInfo_t m_DetailFade; + CEntry m_RenderGroups[RENDER_GROUP_COUNT][MAX_GROUP_ENTITIES]; + int m_RenderGroupCounts[RENDER_GROUP_COUNT]; + int m_nBoneSetupDependencyCount; + IClientRenderable *m_pBoneSetupDependency[MAX_BONE_SETUP_DEPENDENCY]; +}; + + +//----------------------------------------------------------------------------- +// Render list for viewmodels +//----------------------------------------------------------------------------- +class CViewModelRenderablesList +{ +public: + enum + { + VM_GROUP_OPAQUE = 0, + VM_GROUP_TRANSLUCENT, + VM_GROUP_COUNT, }; + struct CEntry + { + IClientRenderable *m_pRenderable; + RenderableInstance_t m_InstanceData; + }; + + typedef CUtlVectorFixedGrowable< CEntry, 32 > RenderGroups_t; + // The leaves for the entries are in the order of the leaves you call CollateRenderablesInLeaf in. - CEntry m_RenderGroups[RENDER_GROUP_COUNT][MAX_GROUP_ENTITIES]; - int m_RenderGroupCounts[RENDER_GROUP_COUNT]; + RenderGroups_t m_RenderGroups[VM_GROUP_COUNT]; }; @@ -81,6 +136,7 @@ struct SetupRenderInfo_t int m_nRenderFrame; int m_nDetailBuildFrame; // The "render frame" for detail objects float m_flRenderDistSq; + int m_nViewID; bool m_bDrawDetailObjects : 1; bool m_bDrawTranslucentObjects : 1; @@ -92,6 +148,20 @@ struct SetupRenderInfo_t }; +//----------------------------------------------------------------------------- +// Used to do batched screen size computations +//----------------------------------------------------------------------------- +struct ScreenSizeComputeInfo_t +{ + VMatrix m_matViewProj; + Vector m_vecViewUp; + int m_nViewportHeight; +}; + +void ComputeScreenSizeInfo( ScreenSizeComputeInfo_t *pInfo ); +float ComputeScreenSize( const Vector &vecOrigin, float flRadius, const ScreenSizeComputeInfo_t& info ); + + //----------------------------------------------------------------------------- // A handle associated with shadows managed by the client leaf system //----------------------------------------------------------------------------- @@ -136,7 +206,7 @@ abstract_class IClientLeafSystem : public IClientLeafSystemEngine, public IGameS { public: // Adds and removes renderables from the leaf lists - virtual void AddRenderable( IClientRenderable* pRenderable, RenderGroup_t group ) = 0; + virtual void AddRenderable( IClientRenderable* pRenderable, bool bRenderWithViewModels, RenderableTranslucencyType_t nType, RenderableModelType_t nModelType, uint32 nSplitscreenEnabled = 0xFFFFFFFF ) = 0; // This tells if the renderable is in the current PVS. It assumes you've updated the renderable // with RenderableChanged() calls @@ -145,7 +215,6 @@ abstract_class IClientLeafSystem : public IClientLeafSystemEngine, public IGameS virtual void SetSubSystemDataInLeaf( int leaf, int nSubSystemIdx, CClientLeafSubSystemData *pData ) =0; virtual CClientLeafSubSystemData *GetSubSystemDataInLeaf( int leaf, int nSubSystemIdx ) =0; - virtual void SetDetailObjectsInLeaf( int leaf, int firstDetailObject, int detailObjectCount ) = 0; virtual void GetDetailObjectsInLeaf( int leaf, int& firstDetailObject, int& detailObjectCount ) = 0; @@ -159,17 +228,11 @@ abstract_class IClientLeafSystem : public IClientLeafSystemEngine, public IGameS // Call this when a renderable origin/angles/bbox parameters has changed virtual void RenderableChanged( ClientRenderHandle_t handle ) = 0; - // Set a render group - virtual void SetRenderGroup( ClientRenderHandle_t handle, RenderGroup_t group ) = 0; - - // Computes which leaf translucent objects should be rendered in - virtual void ComputeTranslucentRenderLeaf( int count, const LeafIndex_t *pLeafList, const LeafFogVolume_t *pLeafFogVolumeList, int frameNumber, int viewID ) = 0; - // Put renderables into their appropriate lists. virtual void BuildRenderablesList( const SetupRenderInfo_t &info ) = 0; // Put renderables in the leaf into their appropriate lists. - virtual void CollateViewModelRenderables( CUtlVector< IClientRenderable * >& opaqueList, CUtlVector< IClientRenderable * >& translucentList ) = 0; + virtual void CollateViewModelRenderables( CViewModelRenderablesList *pList ) = 0; // Call this to deactivate static prop rendering.. virtual void DrawStaticProps( bool enable ) = 0; @@ -188,7 +251,7 @@ abstract_class IClientLeafSystem : public IClientLeafSystemEngine, public IGameS virtual void ProjectFlashlight( ClientLeafShadowHandle_t handle, int nLeafCount, const int *pLeafList ) = 0; // Find all shadow casters in a set of leaves - virtual void EnumerateShadowsInLeaves( int leafCount, LeafIndex_t* pLeaves, IClientLeafShadowEnum* pEnum ) = 0; + virtual void EnumerateShadowsInLeaves( int leafCount, WorldListLeafData_t* pLeaves, IClientLeafShadowEnum* pEnum ) = 0; // Fill in a list of the leaves this renderable is in. // Returns -1 if the handle is invalid. @@ -199,6 +262,36 @@ abstract_class IClientLeafSystem : public IClientLeafSystemEngine, public IGameS // Use alternate translucent sorting algorithm (draw translucent objects in the furthest leaf they lie in) virtual void EnableAlternateSorting( ClientRenderHandle_t handle, bool bEnable ) = 0; + + // Mark this as rendering with viewmodels + virtual void RenderWithViewModels( ClientRenderHandle_t handle, bool bEnable ) = 0; + virtual bool IsRenderingWithViewModels( ClientRenderHandle_t handle ) const = 0; + + // Call this if the model changes + virtual void SetTranslucencyType( ClientRenderHandle_t handle, RenderableTranslucencyType_t nType ) = 0; + virtual RenderableTranslucencyType_t GetTranslucencyType( ClientRenderHandle_t handle ) const = 0; + virtual void SetModelType( ClientRenderHandle_t handle, RenderableModelType_t nType = RENDERABLE_MODEL_UNKNOWN_TYPE ) = 0; + virtual void EnableSplitscreenRendering( ClientRenderHandle_t handle, uint32 nFlags ) = 0; + + // Suppress rendering of this renderable + virtual void EnableRendering( ClientRenderHandle_t handle, bool bEnable ) = 0; + + // Indicates this renderable should bloat its client leaf bounds over time + // used for renderables with oscillating bounds to reduce the cost of + // them reinserting themselves into the tree over and over. + virtual void EnableBloatedBounds( ClientRenderHandle_t handle, bool bEnable ) = 0; + + // Indicates this renderable should always recompute its bounds accurately + virtual void DisableCachedRenderBounds( ClientRenderHandle_t handle, bool bDisable ) = 0; + + // Recomputes which leaves renderables are in + virtual void RecomputeRenderableLeaves() = 0; + + // Warns about leaf reinsertion + virtual void DisableLeafReinsertion( bool bDisable ) = 0; + + //Assuming the renderable would be in a properly built render list, generate a render list entry + virtual RenderGroup_t GenerateRenderListEntry( IClientRenderable *pRenderable, CClientRenderablesList::CEntry &entryOut ) = 0; }; diff --git a/game/client/clientmode.h b/game/client/clientmode.h index b4d9350ac..a7e9d3ae6 100644 --- a/game/client/clientmode.h +++ b/game/client/clientmode.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // diff --git a/game/client/clientmode_normal.cpp b/game/client/clientmode_normal.cpp index 49fa61d16..439397ac3 100644 --- a/game/client/clientmode_normal.cpp +++ b/game/client/clientmode_normal.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // diff --git a/game/client/clientmode_normal.h b/game/client/clientmode_normal.h index 49fa61d16..439397ac3 100644 --- a/game/client/clientmode_normal.h +++ b/game/client/clientmode_normal.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // diff --git a/game/client/clientmode_shared.cpp b/game/client/clientmode_shared.cpp index 07f8cc045..ceefaf8e8 100644 --- a/game/client/clientmode_shared.cpp +++ b/game/client/clientmode_shared.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: Normal HUD mode // @@ -15,16 +15,18 @@ #include "iviewrender.h" #include "hud_basechat.h" #include "weapon_selection.h" -#include +#include #include #include -#include -#include "engine/IEngineSound.h" -#include +#include "engine/ienginesound.h" +#include #include #include "vgui_int.h" #include "hud_macros.h" #include "hltvcamera.h" +#if defined( REPLAY_ENABLED ) +#include "replaycamera.h" +#endif #include "particlemgr.h" #include "c_vguiscreen.h" #include "c_team.h" @@ -32,157 +34,76 @@ #include "fmtstr.h" #include "achievementmgr.h" #include "c_playerresource.h" -#include "cam_thirdperson.h" #include -#include "hud_vote.h" -#include "ienginevgui.h" -#include "sourcevr/isourcevirtualreality.h" #if defined( _X360 ) #include "xbox/xbox_console.h" #endif +#include "matchmaking/imatchframework.h" -#if defined( REPLAY_ENABLED ) -#include "replay/replaycamera.h" -#include "replay/ireplaysystem.h" -#include "replay/iclientreplaycontext.h" -#include "replay/ireplaymanager.h" -#include "replay/replay.h" -#include "replay/ienginereplay.h" -#include "replay/vgui/replayreminderpanel.h" -#include "replay/vgui/replaymessagepanel.h" -#include "econ/econ_controls.h" -#include "econ/confirm_dialog.h" - -extern IClientReplayContext *g_pClientReplayContext; -extern ConVar replay_rendersetting_renderglow; -#endif -#if defined USES_ECON_ITEMS -#include "econ_item_view.h" -#endif - -#if defined( TF_CLIENT_DLL ) -#include "c_tf_player.h" -#include "econ_item_description.h" -#endif // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" -#define ACHIEVEMENT_ANNOUNCEMENT_MIN_TIME 10 - class CHudWeaponSelection; class CHudChat; -class CHudVote; static vgui::HContext s_hVGuiContext = DEFAULT_VGUI_CONTEXT; ConVar cl_drawhud( "cl_drawhud", "1", FCVAR_CHEAT, "Enable the rendering of the hud" ); ConVar hud_takesshots( "hud_takesshots", "0", FCVAR_CLIENTDLL | FCVAR_ARCHIVE, "Auto-save a scoreboard screenshot at the end of a map." ); -ConVar hud_freezecamhide( "hud_freezecamhide", "0", FCVAR_CLIENTDLL | FCVAR_ARCHIVE, "Hide the HUD during freeze-cam" ); -ConVar cl_show_num_particle_systems( "cl_show_num_particle_systems", "0", FCVAR_CLIENTDLL, "Display the number of active particle systems." ); extern ConVar v_viewmodel_fov; -extern ConVar voice_modenable; extern bool IsInCommentaryMode( void ); -#ifdef VOICE_VOX_ENABLE -void VoxCallback( IConVar *var, const char *oldString, float oldFloat ) -{ - if ( engine && engine->IsConnected() ) - { - ConVarRef voice_vox( var->GetName() ); - if ( voice_vox.GetBool() && voice_modenable.GetBool() ) - { - engine->ClientCmd_Unrestricted( "voicerecord_toggle on\n" ); - } - else - { - engine->ClientCmd_Unrestricted( "voicerecord_toggle off\n" ); - } - } -} -ConVar voice_vox( "voice_vox", "0", FCVAR_ARCHIVE, "Voice chat uses a vox-style always on", true, 0, true, 1, VoxCallback ); - -// --------------------------------------------------------------------------------- // -// CVoxManager. -// --------------------------------------------------------------------------------- // -class CVoxManager : public CAutoGameSystem +CON_COMMAND( hud_reloadscheme, "Reloads hud layout and animation scripts." ) { -public: - CVoxManager() : CAutoGameSystem( "VoxManager" ) - { - } - - virtual void LevelInitPostEntity( void ) + for ( int hh = 0; hh < MAX_SPLITSCREEN_PLAYERS; ++hh ) { - if ( voice_vox.GetBool() && voice_modenable.GetBool() ) + ACTIVE_SPLITSCREEN_PLAYER_GUARD_VGUI( hh ); + ClientModeShared *mode = ( ClientModeShared * )GetClientModeNormal(); + if ( mode ) { - engine->ClientCmd_Unrestricted( "voicerecord_toggle on\n" ); + mode->ReloadScheme(); } } - - virtual void LevelShutdownPreEntity( void ) + ClientModeShared *mode = ( ClientModeShared * )GetFullscreenClientMode(); + if ( mode ) { - if ( voice_vox.GetBool() ) - { - engine->ClientCmd_Unrestricted( "voicerecord_toggle off\n" ); - } + mode->ReloadSchemeWithRoot( VGui_GetFullscreenRootVPANEL() ); } -}; - -static CVoxManager s_VoxManager; -// --------------------------------------------------------------------------------- // -#endif // VOICE_VOX_ENABLE - -CON_COMMAND( hud_reloadscheme, "Reloads hud layout and animation scripts." ) -{ - ClientModeShared *mode = ( ClientModeShared * )GetClientModeNormal(); - if ( !mode ) - return; - - mode->ReloadScheme(); } -CON_COMMAND( messagemode, "Opens chat dialog" ) -{ - ClientModeShared *mode = ( ClientModeShared * )GetClientModeNormal(); - mode->StartMessageMode( MM_SAY ); -} - -CON_COMMAND( messagemode2, "Opens chat dialog" ) -{ - ClientModeShared *mode = ( ClientModeShared * )GetClientModeNormal(); - mode->StartMessageMode( MM_SAY_TEAM ); -} - -#ifdef _DEBUG +#if 0 CON_COMMAND_F( crash, "Crash the client. Optional parameter -- type of crash:\n 0: read from NULL\n 1: write to NULL\n 2: DmCrashDump() (xbox360 only)", FCVAR_CHEAT ) { int crashtype = 0; int dummy; if ( args.ArgC() > 1 ) { - crashtype = Q_atoi( args[1] ); + crashtype = Q_atoi( args[1] ); } switch (crashtype) { - case 0: - dummy = *((int *) NULL); - Msg("Crashed! %d\n", dummy); // keeps dummy from optimizing out - break; - case 1: - *((int *)NULL) = 42; - break; + case 0: + dummy = *((int *) NULL); + Msg("Crashed! %d\n", dummy); // keeps dummy from optimizing out + break; + case 1: + *((int *)NULL) = 42; + break; #if defined( _X360 ) - case 2: - XBX_CrashDump(false); - break; + case 2: + XBX_CrashDump( false ); + break; + case 3: + XBX_CrashDumpFullHeap( true ); + break; #endif - default: - Msg("Unknown variety of crash. You have now failed to crash. I hope you're happy.\n"); - break; + default: + Msg("Unknown variety of crash. You have now failed to crash. I hope you're happy.\n"); + break; } } #endif // _DEBUG @@ -197,31 +118,28 @@ static void __MsgFunc_Rumble( bf_read &msg ) rumbleData = msg.ReadByte(); rumbleFlags = msg.ReadByte(); - RumbleEffect( waveformIndex, rumbleData, rumbleFlags ); + int userID = XBX_GetActiveUserId(); + + RumbleEffect( userID, waveformIndex, rumbleData, rumbleFlags ); } static void __MsgFunc_VGUIMenu( bf_read &msg ) { char panelname[2048]; - + msg.ReadString( panelname, sizeof(panelname) ); - bool bShow = msg.ReadByte()!=0; - - IViewPortPanel *viewport = gViewPortInterface->FindPanelByName( panelname ); + bool bShow = msg.ReadByte()!= 0; - if ( !viewport ) - { - // DevMsg("VGUIMenu: couldn't find panel '%s'.\n", panelname ); - return; - } + ASSERT_LOCAL_PLAYER_RESOLVABLE(); int count = msg.ReadByte(); + KeyValues *keys = NULL; + if ( count > 0 ) { - KeyValues *keys = new KeyValues("data"); - //Msg( "MsgFunc_VGUIMenu:\n" ); + keys = new KeyValues("data"); for ( int i=0; iSetString( name, data ); } + } - // !KLUDGE! Whitelist of URL protocols formats for MOTD - if ( - !V_stricmp( panelname, PANEL_INFO ) // MOTD - && keys->GetInt( "type", 0 ) == 2 // URL message type - ) { - const char *pszURL = keys->GetString( "msg", "" ); - if ( Q_strncmp( pszURL, "http://", 7 ) != 0 && Q_strncmp( pszURL, "https://", 8 ) != 0 && Q_stricmp( pszURL, "about:blank" ) != 0 ) - { - Warning( "Blocking MOTD URL '%s'; must begin with 'http://' or 'https://' or be about:blank\n", pszURL ); - keys->deleteThis(); - return; - } - } - - viewport->SetData( keys ); + GetViewPortInterface()->ShowPanel( panelname, bShow, keys, true ); - keys->deleteThis(); - } + // Don't do this since ShowPanel auto-deletes the keys + // keys->deleteThis(); // is the server telling us to show the scoreboard (at the end of a map)? if ( Q_stricmp( panelname, "scores" ) == 0 ) { if ( hud_takesshots.GetBool() == true ) { - gHUD.SetScreenShotTime( gpGlobals->curtime + 1.0 ); // take a screenshot in 1 second + GetHud().SetScreenShotTime( gpGlobals->curtime + 1.0 ); // take a screenshot in 1 second } } - - // is the server trying to show an MOTD panel? Check that it's allowed right now. - ClientModeShared *mode = ( ClientModeShared * )GetClientModeNormal(); - if ( Q_stricmp( panelname, PANEL_INFO ) == 0 && mode ) - { - if ( !mode->IsInfoPanelAllowed() ) - { - return; - } - else - { - mode->InfoPanelDisplayed(); - } - } - - gViewPortInterface->ShowPanel( viewport, bShow ); } + //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- @@ -289,12 +178,6 @@ ClientModeShared::ClientModeShared() m_pChatElement = NULL; m_pWeaponSelection = NULL; m_nRootSize[ 0 ] = m_nRootSize[ 1 ] = -1; - -#if defined( REPLAY_ENABLED ) - m_pReplayReminderPanel = NULL; - m_flReplayStartRecordTime = 0.0f; - m_flReplayStopRecordTime = 0.0f; -#endif } //----------------------------------------------------------------------------- @@ -302,72 +185,55 @@ ClientModeShared::ClientModeShared() //----------------------------------------------------------------------------- ClientModeShared::~ClientModeShared() { - delete m_pViewport; + // VGui_Shutdown() should have deleted/NULL'd + Assert( !m_pViewport ); } void ClientModeShared::ReloadScheme( void ) { - m_pViewport->ReloadScheme( "resource/ClientScheme.res" ); - ClearKeyValuesCache(); + ReloadSchemeWithRoot( VGui_GetClientDLLRootPanel() ); } - -//---------------------------------------------------------------------------- -// Purpose: Let the client mode set some vgui conditions -//----------------------------------------------------------------------------- -void ClientModeShared::ComputeVguiResConditions( KeyValues *pkvConditions ) +void ClientModeShared::ReloadSchemeWithRoot( vgui::VPANEL pRoot ) { - if ( UseVR() ) + if ( pRoot ) { - pkvConditions->FindKey( "if_vr", true ); + int wide, tall; + vgui::ipanel()->GetSize(pRoot, wide, tall); + m_nRootSize[ 0 ] = wide; + m_nRootSize[ 1 ] = tall; } -} - + m_pViewport->ReloadScheme( "resource/ClientScheme.res" ); + if ( GET_ACTIVE_SPLITSCREEN_SLOT() == 0 ) + { + ClearKeyValuesCache(); + } + // Msg( "Reload scheme [%d]\n", GET_ACTIVE_SPLITSCREEN_SLOT() ); +} //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void ClientModeShared::Init() { - m_pChatElement = ( CBaseHudChat * )GET_HUDELEMENT( CHudChat ); - Assert( m_pChatElement ); - - m_pWeaponSelection = ( CBaseHudWeaponSelection * )GET_HUDELEMENT( CHudWeaponSelection ); - Assert( m_pWeaponSelection ); + InitChatHudElement(); - KeyValuesAD pConditions( "conditions" ); - ComputeVguiResConditions( pConditions ); + InitWeaponSelectionHudElement(); // Derived ClientMode class must make sure m_Viewport is instantiated Assert( m_pViewport ); - m_pViewport->LoadControlSettings( "scripts/HudLayout.res", NULL, NULL, pConditions ); - -#if defined( REPLAY_ENABLED ) - m_pReplayReminderPanel = GET_HUDELEMENT( CReplayReminderPanel ); - Assert( m_pReplayReminderPanel ); -#endif + m_pViewport->LoadHudLayout(); ListenForGameEvent( "player_connect" ); ListenForGameEvent( "player_disconnect" ); ListenForGameEvent( "player_team" ); ListenForGameEvent( "server_cvar" ); ListenForGameEvent( "player_changename" ); + ListenForGameEvent( "player_fullyjoined" ); ListenForGameEvent( "teamplay_broadcast_audio" ); ListenForGameEvent( "achievement_earned" ); -#if defined( TF_CLIENT_DLL ) - ListenForGameEvent( "item_found" ); -#endif - -#if defined( REPLAY_ENABLED ) - ListenForGameEvent( "replay_startrecord" ); - ListenForGameEvent( "replay_endrecord" ); - ListenForGameEvent( "replay_replaysavailable" ); - ListenForGameEvent( "replay_servererror" ); - ListenForGameEvent( "game_newmap" ); -#endif - #ifndef _XBOX HLTVCamera()->Init(); #if defined( REPLAY_ENABLED ) @@ -381,6 +247,17 @@ void ClientModeShared::Init() HOOK_MESSAGE( Rumble ); } +void ClientModeShared::InitChatHudElement() +{ + m_pChatElement = CBaseHudChat::GetHudChat(); + Assert( m_pChatElement ); +} + +void ClientModeShared::InitWeaponSelectionHudElement() +{ + m_pWeaponSelection = ( CBaseHudWeaponSelection * )GET_HUDELEMENT( CHudWeaponSelection ); + Assert( m_pWeaponSelection ); +} void ClientModeShared::InitViewport() { @@ -434,29 +311,38 @@ void ClientModeShared::OverrideView( CViewSetup *pSetup ) if( ::input->CAM_IsThirdPerson() ) { - Vector cam_ofs = g_ThirdPersonManager.GetCameraOffsetAngles(); - Vector cam_ofs_distance = g_ThirdPersonManager.GetFinalCameraOffset(); + Vector cam_ofs; - cam_ofs_distance *= g_ThirdPersonManager.GetDistanceFraction(); + ::input->CAM_GetCameraOffset( cam_ofs ); camAngles[ PITCH ] = cam_ofs[ PITCH ]; camAngles[ YAW ] = cam_ofs[ YAW ]; camAngles[ ROLL ] = 0; Vector camForward, camRight, camUp; - + AngleVectors( camAngles, &camForward, &camRight, &camUp ); + + VectorMA( pSetup->origin, -cam_ofs[ ROLL ], camForward, pSetup->origin ); - if ( g_ThirdPersonManager.IsOverridingThirdPerson() == false ) + static ConVarRef c_thirdpersonshoulder( "c_thirdpersonshoulder" ); + if ( c_thirdpersonshoulder.GetBool() ) { - engine->GetViewAngles( camAngles ); + static ConVarRef c_thirdpersonshoulderoffset( "c_thirdpersonshoulderoffset" ); + static ConVarRef c_thirdpersonshoulderheight( "c_thirdpersonshoulderheight" ); + static ConVarRef c_thirdpersonshoulderaimdist( "c_thirdpersonshoulderaimdist" ); + + // add the shoulder offset to the origin in the cameras right vector + VectorMA( pSetup->origin, c_thirdpersonshoulderoffset.GetFloat(), camRight, pSetup->origin ); + + // add the shoulder height to the origin in the cameras up vector + VectorMA( pSetup->origin, c_thirdpersonshoulderheight.GetFloat(), camUp, pSetup->origin ); + + // adjust the yaw to the aim-point + camAngles[ YAW ] += RAD2DEG( atan(c_thirdpersonshoulderoffset.GetFloat() / (c_thirdpersonshoulderaimdist.GetFloat() + cam_ofs[ ROLL ])) ); + + // adjust the pitch to the aim-point + camAngles[ PITCH ] += RAD2DEG( atan(c_thirdpersonshoulderheight.GetFloat() / (c_thirdpersonshoulderaimdist.GetFloat() + cam_ofs[ ROLL ])) ); } - - // get the forward vector - AngleVectors( camAngles, &camForward, &camRight, &camUp ); - - VectorMA( pSetup->origin, -cam_ofs_distance[0], camForward, pSetup->origin ); - VectorMA( pSetup->origin, cam_ofs_distance[1], camRight, pSetup->origin ); - VectorMA( pSetup->origin, cam_ofs_distance[2], camUp, pSetup->origin ); // Override angles from third person camera VectorCopy( camAngles, pSetup->angles ); @@ -493,7 +379,8 @@ bool ClientModeShared::ShouldDrawParticles( ) //----------------------------------------------------------------------------- void ClientModeShared::OverrideMouseInput( float *x, float *y ) { - C_BaseCombatWeapon *pWeapon = GetActiveWeapon(); + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + C_BaseCombatWeapon *pWeapon = pPlayer ? pPlayer->GetActiveWeapon() : NULL;; if ( pWeapon ) { pWeapon->OverrideMouseInput( x, y ); @@ -513,26 +400,6 @@ bool ClientModeShared::ShouldDrawDetailObjects( ) return true; } - -//----------------------------------------------------------------------------- -// Purpose: Returns true if VR mode should black out everything outside the HUD. -// This is used for things like sniper scopes and full screen UI -//----------------------------------------------------------------------------- -bool ClientModeShared::ShouldBlackoutAroundHUD() -{ - return enginevgui->IsGameUIVisible(); -} - - -//----------------------------------------------------------------------------- -// Purpose: Allows the client mode to override mouse control stuff in sourcevr -//----------------------------------------------------------------------------- -HeadtrackMovementMode_t ClientModeShared::ShouldOverrideHeadtrackControl() -{ - return HMM_NOOVERRIDE; -} - - //----------------------------------------------------------------------------- // Purpose: // Output : Returns true on success, false on failure. @@ -543,11 +410,11 @@ bool ClientModeShared::ShouldDrawCrosshair( void ) } //----------------------------------------------------------------------------- -// Purpose: Don't draw the current view entity if we are using the fake viewmodel instead +// Purpose: Don't draw the current view entity if we are not in 3rd person //----------------------------------------------------------------------------- bool ClientModeShared::ShouldDrawLocalPlayer( C_BasePlayer *pPlayer ) { - if ( ( pPlayer->index == render->GetViewEntity() ) && !C_BasePlayer::ShouldDrawLocalPlayer() ) + if ( pPlayer->IsViewEntity() && !pPlayer->ShouldDrawLocalPlayer() ) return false; return true; @@ -594,38 +461,27 @@ void ClientModeShared::PostRenderVGui() //----------------------------------------------------------------------------- void ClientModeShared::Update() { -#if defined( REPLAY_ENABLED ) - UpdateReplayMessages(); -#endif - if ( m_pViewport->IsVisible() != cl_drawhud.GetBool() ) { m_pViewport->SetVisible( cl_drawhud.GetBool() ); } - UpdateRumbleEffects(); - - if ( cl_show_num_particle_systems.GetBool() ) - { - int nCount = 0; - - for ( int i = 0; i < g_pParticleSystemMgr->GetParticleSystemCount(); i++ ) - { - const char *pParticleSystemName = g_pParticleSystemMgr->GetParticleSystemNameFromIndex(i); - CParticleSystemDefinition *pParticleSystem = g_pParticleSystemMgr->FindParticleSystem( pParticleSystemName ); - if ( !pParticleSystem ) - continue; + UpdateRumbleEffects( XBX_GetActiveUserId() ); +} - for ( CParticleCollection *pCurCollection = pParticleSystem->FirstCollection(); - pCurCollection != NULL; - pCurCollection = pCurCollection->GetNextCollectionUsingSameDef() ) - { - ++nCount; - } - } +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void ClientModeShared::OnColorCorrectionWeightsReset( void ) +{ +} - engine->Con_NPrintf( 0, "# Active particle systems: %i", nCount ); - } +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +float ClientModeShared::GetColorCorrectionScale( void ) const +{ + return 0.0f; } //----------------------------------------------------------------------------- @@ -634,7 +490,7 @@ void ClientModeShared::Update() void ClientModeShared::ProcessInput(bool bActive) { - gHUD.ProcessInput( bActive ); + GetHud().ProcessInput( bActive ); } //----------------------------------------------------------------------------- @@ -644,21 +500,36 @@ int ClientModeShared::KeyInput( int down, ButtonCode_t keynum, const char *pszCu { if ( engine->Con_IsVisible() ) return 1; - - // If we're voting... -#ifdef VOTING_ENABLED - CHudVote *pHudVote = GET_HUDELEMENT( CHudVote ); - if ( pHudVote && pHudVote->IsVisible() ) + + // Should we start typing a message? + if ( pszCurrentBinding && + ( Q_strcmp( pszCurrentBinding, "messagemode" ) == 0 || + Q_strcmp( pszCurrentBinding, "say" ) == 0 ) ) { - if ( !pHudVote->KeyInput( down, keynum, pszCurrentBinding ) ) + if ( down ) { - return 0; + StartMessageMode( MM_SAY ); + } + return 0; + } + else if ( pszCurrentBinding && + ( Q_strcmp( pszCurrentBinding, "messagemode2" ) == 0 || + Q_strcmp( pszCurrentBinding, "say_team" ) == 0 ) ) + { + if ( down ) + { + StartMessageMode( MM_SAY_TEAM ); } + return 0; } -#endif C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + if ( IsJoystickCode( keynum ) ) + { + keynum = GetBaseButtonCode( keynum ); + } + // if ingame spectator mode, let spectator input intercept key event here if( pPlayer && ( pPlayer->GetObserverMode() > OBS_MODE_DEATHCAM ) && @@ -673,7 +544,7 @@ int ClientModeShared::KeyInput( int down, ButtonCode_t keynum, const char *pszCu return 0; } - C_BaseCombatWeapon *pWeapon = GetActiveWeapon(); + C_BaseCombatWeapon *pWeapon = pPlayer ? pPlayer->GetActiveWeapon() : NULL; if ( pWeapon ) { return pWeapon->KeyInput( down, keynum, pszCurrentBinding ); @@ -682,33 +553,63 @@ int ClientModeShared::KeyInput( int down, ButtonCode_t keynum, const char *pszCu return 1; } +//----------------------------------------------------------------------------- +// Purpose: Helper to find if a binding exists in a possible chain of bindings +//----------------------------------------------------------------------------- +static bool ContainsBinding( const char *pszBindingString, const char *pszBinding ) +{ + if ( !strchr( pszBindingString, ';' ) ) + { + return !Q_stricmp( pszBindingString, pszBinding ); + } + else + { + // Tokenize the binding name + char szBinding[ 256 ]; + Q_strncpy( szBinding, pszBindingString, sizeof( szBinding ) ); + + const char *pToken = strtok( szBinding, ";" ); + + while ( pToken ) + { + if ( !Q_stricmp( pszBinding, pToken ) ) + { + return true; + } + + pToken = strtok( NULL, ";" ); + } + return false; + } +} + //----------------------------------------------------------------------------- // Purpose: See if spectator input occurred. Return 0 if the key is swallowed. //----------------------------------------------------------------------------- int ClientModeShared::HandleSpectatorKeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding ) { // we are in spectator mode, open spectator menu - if ( down && pszCurrentBinding && Q_strcmp( pszCurrentBinding, "+duck" ) == 0 ) + if ( down && pszCurrentBinding && ContainsBinding( pszCurrentBinding, "+duck" ) ) { m_pViewport->ShowPanel( PANEL_SPECMENU, true ); return 0; // we handled it, don't handle twice or send to server } - else if ( down && pszCurrentBinding && Q_strcmp( pszCurrentBinding, "+attack" ) == 0 ) + else if ( down && pszCurrentBinding && ContainsBinding( pszCurrentBinding, "+attack" ) ) { engine->ClientCmd( "spec_next" ); return 0; } - else if ( down && pszCurrentBinding && Q_strcmp( pszCurrentBinding, "+attack2" ) == 0 ) + else if ( down && pszCurrentBinding && ContainsBinding( pszCurrentBinding, "+attack2" ) ) { engine->ClientCmd( "spec_prev" ); return 0; } - else if ( down && pszCurrentBinding && Q_strcmp( pszCurrentBinding, "+jump" ) == 0 ) + else if ( down && pszCurrentBinding && ContainsBinding( pszCurrentBinding, "+jump" ) ) { engine->ClientCmd( "spec_mode" ); return 0; } - else if ( down && pszCurrentBinding && Q_strcmp( pszCurrentBinding, "+strafe" ) == 0 ) + else if ( down && pszCurrentBinding && ContainsBinding( pszCurrentBinding, "+strafe" ) ) { HLTVCamera()->SetAutoDirector( true ); #if defined( REPLAY_ENABLED ) @@ -725,6 +626,10 @@ int ClientModeShared::HandleSpectatorKeyInput( int down, ButtonCode_t keynum, co //----------------------------------------------------------------------------- int ClientModeShared::HudElementKeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding ) { + if ( GetFullscreenClientMode() && GetFullscreenClientMode() != this && + !GetFullscreenClientMode()->HudElementKeyInput( down, keynum, pszCurrentBinding ) ) + return 0; + if ( m_pWeaponSelection ) { if ( !m_pWeaponSelection->KeyInput( down, keynum, pszCurrentBinding ) ) @@ -733,35 +638,9 @@ int ClientModeShared::HudElementKeyInput( int down, ButtonCode_t keynum, const c } } -#if defined( REPLAY_ENABLED ) - if ( m_pReplayReminderPanel ) - { - if ( m_pReplayReminderPanel->HudElementKeyInput( down, keynum, pszCurrentBinding ) ) - { - return 0; - } - } -#endif - return 1; } - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -bool ClientModeShared::DoPostScreenSpaceEffects( const CViewSetup *pSetup ) -{ -#if defined( REPLAY_ENABLED ) - if ( engine->IsPlayingDemo() ) - { - if ( !replay_rendersetting_renderglow.GetBool() ) - return false; - } -#endif - return true; -} - //----------------------------------------------------------------------------- // Purpose: // Output : vgui::Panel @@ -828,17 +707,14 @@ void ClientModeShared::LevelInit( const char *newmap ) //----------------------------------------------------------------------------- void ClientModeShared::LevelShutdown( void ) { - // Reset the third person camera so we don't crash - g_ThirdPersonManager.Init(); - if ( m_pChatElement ) { - m_pChatElement->LevelShutdown(); + m_pChatElement->LevelShutdown(); } if ( s_hVGuiContext != DEFAULT_VGUI_CONTEXT ) { vgui::ivgui()->DestroyContext( s_hVGuiContext ); - s_hVGuiContext = DEFAULT_VGUI_CONTEXT; + s_hVGuiContext = DEFAULT_VGUI_CONTEXT; } // Reset any player explosion/shock effects @@ -846,13 +722,16 @@ void ClientModeShared::LevelShutdown( void ) enginesound->SetPlayerDSP( filter, 0, true ); } - void ClientModeShared::Enable() { - vgui::VPANEL pRoot = VGui_GetClientDLLRootPanel();; + vgui::VPANEL pRoot = VGui_GetClientDLLRootPanel(); + EnableWithRootPanel( pRoot ); +} +void ClientModeShared::EnableWithRootPanel( vgui::VPANEL pRoot ) +{ // Add our viewport to the root panel. - if( pRoot != 0 ) + if( pRoot != NULL ) { m_pViewport->SetParent( pRoot ); } @@ -876,10 +755,10 @@ void ClientModeShared::Enable() void ClientModeShared::Disable() { - vgui::VPANEL pRoot = VGui_GetClientDLLRootPanel();; + vgui::VPANEL pRoot; // Remove our viewport from the root panel. - if( pRoot != 0 ) + if( ( pRoot = VGui_GetClientDLLRootPanel() ) != NULL ) { m_pViewport->SetParent( (vgui::VPANEL)NULL ); } @@ -888,24 +767,20 @@ void ClientModeShared::Disable() } -void ClientModeShared::Layout() +void ClientModeShared::Layout( bool bForce /*= false*/) { - vgui::VPANEL pRoot = VGui_GetClientDLLRootPanel(); + vgui::VPANEL pRoot; int wide, tall; // Make the viewport fill the root panel. - if( pRoot != 0 ) + if( ( pRoot = m_pViewport->GetVParent() ) != NULL ) { vgui::ipanel()->GetSize(pRoot, wide, tall); - bool changed = wide != m_nRootSize[ 0 ] || tall != m_nRootSize[ 1 ]; - m_nRootSize[ 0 ] = wide; - m_nRootSize[ 1 ] = tall; - m_pViewport->SetBounds(0, 0, wide, tall); - if ( changed ) + if ( changed || bForce ) { - ReloadScheme(); + ReloadSchemeWithRoot( pRoot ); } } } @@ -915,6 +790,117 @@ float ClientModeShared::GetViewModelFOV( void ) return v_viewmodel_fov.GetFloat(); } +vgui::Panel *ClientModeShared::GetPanelFromViewport( const char *pchNamePath ) +{ + char szTagetName[ 256 ]; + Q_strncpy( szTagetName, pchNamePath, sizeof(szTagetName) ); + + char *pchName = szTagetName; + + char *pchEndToken = strchr( pchName, ';' ); + if ( pchEndToken ) + { + *pchEndToken = '\0'; + } + + char *pchNextName = strchr( pchName, '/' ); + if ( pchNextName ) + { + *pchNextName = '\0'; + pchNextName++; + } + + // Comma means we want to count to a specific instance by name + int nInstance = 0; + + char *pchInstancePos = strchr( pchName, ',' ); + if ( pchInstancePos ) + { + *pchInstancePos = '\0'; + pchInstancePos++; + + nInstance = atoi( pchInstancePos ); + } + + // Find the child + int nCurrentInstance = 0; + vgui::Panel *pPanel = NULL; + + for ( int i = 0; i < GetViewport()->GetChildCount(); i++ ) + { + Panel *pChild = GetViewport()->GetChild( i ); + if ( !pChild ) + continue; + + if ( stricmp( pChild->GetName(), pchName ) == 0 ) + { + nCurrentInstance++; + + if ( nCurrentInstance > nInstance ) + { + pPanel = pChild; + break; + } + } + } + + pchName = pchNextName; + + while ( pPanel ) + { + if ( !pchName || pchName[ 0 ] == '\0' ) + { + break; + } + + pchNextName = strchr( pchName, '/' ); + if ( pchNextName ) + { + *pchNextName = '\0'; + pchNextName++; + } + + // Comma means we want to count to a specific instance by name + nInstance = 0; + + pchInstancePos = strchr( pchName, ',' ); + if ( pchInstancePos ) + { + *pchInstancePos = '\0'; + pchInstancePos++; + + nInstance = atoi( pchInstancePos ); + } + + // Find the child + nCurrentInstance = 0; + vgui::Panel *pNextPanel = NULL; + + for ( int i = 0; i < pPanel->GetChildCount(); i++ ) + { + Panel *pChild = pPanel->GetChild( i ); + if ( !pChild ) + continue; + + if ( stricmp( pChild->GetName(), pchName ) == 0 ) + { + nCurrentInstance++; + + if ( nCurrentInstance > nInstance ) + { + pNextPanel = pChild; + break; + } + } + } + + pPanel = pNextPanel; + pchName = pchNextName; + } + + return pPanel; +} + class CHudChat; bool PlayerNameNotSetYet( const char *pszName ) @@ -933,12 +919,16 @@ bool PlayerNameNotSetYet( const char *pszName ) void ClientModeShared::FireGameEvent( IGameEvent *event ) { - CBaseHudChat *hudChat = (CBaseHudChat *)GET_HUDELEMENT( CHudChat ); + ACTIVE_SPLITSCREEN_PLAYER_GUARD( GetSplitScreenPlayerSlot() ); + + CBaseHudChat *hudChat = CBaseHudChat::GetHudChat(); const char *eventname = event->GetName(); if ( Q_strcmp( "player_connect", eventname ) == 0 ) { + if ( this == GetFullscreenClientMode() ) + return; if ( !hudChat ) return; if ( PlayerNameNotSetYet(event->GetString("name")) ) @@ -949,7 +939,7 @@ void ClientModeShared::FireGameEvent( IGameEvent *event ) wchar_t wszLocalized[100]; wchar_t wszPlayerName[MAX_PLAYER_NAME_LENGTH]; g_pVGuiLocalize->ConvertANSIToUnicode( event->GetString("name"), wszPlayerName, sizeof(wszPlayerName) ); - g_pVGuiLocalize->ConstructString( wszLocalized, sizeof( wszLocalized ), g_pVGuiLocalize->Find( "#game_player_joined_game" ), 1, wszPlayerName ); + g_pVGuiLocalize->ConstructString( wszLocalized, sizeof( wszLocalized ), g_pVGuiLocalize->Find( "#game_player_connecting" ), 1, wszPlayerName ); char szLocalized[100]; g_pVGuiLocalize->ConvertUnicodeToANSI( wszLocalized, szLocalized, sizeof(szLocalized) ); @@ -959,6 +949,8 @@ void ClientModeShared::FireGameEvent( IGameEvent *event ) } else if ( Q_strcmp( "player_disconnect", eventname ) == 0 ) { + if ( this == GetFullscreenClientMode() ) + return; C_BasePlayer *pPlayer = USERID2PLAYER( event->GetInt("userid") ); if ( !hudChat || !pPlayer ) @@ -972,15 +964,7 @@ void ClientModeShared::FireGameEvent( IGameEvent *event ) g_pVGuiLocalize->ConvertANSIToUnicode( pPlayer->GetPlayerName(), wszPlayerName, sizeof(wszPlayerName) ); wchar_t wszReason[64]; - const char *pszReason = event->GetString( "reason" ); - if ( pszReason && ( pszReason[0] == '#' ) && g_pVGuiLocalize->Find( pszReason ) ) - { - V_wcsncpy( wszReason, g_pVGuiLocalize->Find( pszReason ), sizeof( wszReason ) ); - } - else - { - g_pVGuiLocalize->ConvertANSIToUnicode( pszReason, wszReason, sizeof(wszReason) ); - } + g_pVGuiLocalize->ConvertANSIToUnicode( event->GetString("reason"), wszReason, sizeof(wszReason) ); wchar_t wszLocalized[100]; if (IsPC()) @@ -998,11 +982,35 @@ void ClientModeShared::FireGameEvent( IGameEvent *event ) hudChat->Printf( CHAT_FILTER_JOINLEAVE, "%s", szLocalized ); } } + else if ( Q_strcmp( "player_fullyjoined", eventname ) == 0 ) + { + if ( this == GetFullscreenClientMode() ) + return; + if ( !hudChat ) + return; + if ( PlayerNameNotSetYet(event->GetString("name")) ) + return; + + wchar_t wszLocalized[100]; + wchar_t wszPlayerName[MAX_PLAYER_NAME_LENGTH]; + g_pVGuiLocalize->ConvertANSIToUnicode( event->GetString("name"), wszPlayerName, sizeof(wszPlayerName) ); + g_pVGuiLocalize->ConstructString( wszLocalized, sizeof( wszLocalized ), g_pVGuiLocalize->Find( "#game_player_joined_game" ), 1, wszPlayerName ); + + char szLocalized[100]; + g_pVGuiLocalize->ConvertUnicodeToANSI( wszLocalized, szLocalized, sizeof(szLocalized) ); + + hudChat->Printf( CHAT_FILTER_JOINLEAVE, "%s", szLocalized ); + } else if ( Q_strcmp( "player_team", eventname ) == 0 ) { + if ( this == GetFullscreenClientMode() ) + return; + C_BasePlayer *pPlayer = USERID2PLAYER( event->GetInt("userid") ); if ( !hudChat ) return; + if ( !pPlayer ) + return; bool bDisconnected = event->GetBool("disconnect"); @@ -1010,11 +1018,11 @@ void ClientModeShared::FireGameEvent( IGameEvent *event ) return; int team = event->GetInt( "team" ); - bool bAutoTeamed = event->GetInt( "autoteam", false ); - bool bSilent = event->GetInt( "silent", false ); + bool bAutoTeamed = event->GetBool( "autoteam", false ); + bool bSilent = event->GetBool( "silent", false ); - const char *pszName = event->GetString( "name" ); - if ( PlayerNameNotSetYet( pszName ) ) + const char *pszName = pPlayer->GetPlayerName(); + if ( PlayerNameNotSetYet(pszName) ) return; if ( !bSilent ) @@ -1052,14 +1060,19 @@ void ClientModeShared::FireGameEvent( IGameEvent *event ) } } - if ( pPlayer && pPlayer->IsLocalPlayer() ) + if ( C_BasePlayer::IsLocalPlayer( pPlayer ) ) { + ACTIVE_SPLITSCREEN_PLAYER_GUARD_ENT( pPlayer ); + // that's me pPlayer->TeamChange( team ); } } else if ( Q_strcmp( "player_changename", eventname ) == 0 ) { + if ( this == GetFullscreenClientMode() ) + return; + if ( !hudChat ) return; @@ -1081,8 +1094,11 @@ void ClientModeShared::FireGameEvent( IGameEvent *event ) hudChat->Printf( CHAT_FILTER_NAMECHANGE, "%s", szLocalized ); } - else if (Q_strcmp( "teamplay_broadcast_audio", eventname ) == 0 ) + else if ( Q_strcmp( "teamplay_broadcast_audio", eventname ) == 0 ) { + if ( this == GetFullscreenClientMode() ) + return; + int team = event->GetInt( "team" ); bool bValidTeam = false; @@ -1106,36 +1122,51 @@ void ClientModeShared::FireGameEvent( IGameEvent *event ) } } - if ( team == 0 && GetLocalTeam() ) + if ( team == 0 && GetLocalTeam() > 0 ) + { bValidTeam = false; - - if ( team == 255 ) - bValidTeam = true; + } if ( bValidTeam == true ) { - EmitSound_t et; - et.m_pSoundName = event->GetString("sound"); - et.m_nFlags = event->GetInt("additional_flags"); + CLocalPlayerFilter filter; + const char *pszSoundName = event->GetString("sound"); + C_BaseEntity::EmitSound( filter, SOUND_FROM_LOCAL_PLAYER, pszSoundName ); + } + } + else if ( Q_strcmp( "teamplay_broadcast_audio", eventname ) == 0 ) + { + if ( this == GetFullscreenClientMode() ) + return; + int team = event->GetInt( "team" ); + if ( !team || (GetLocalTeam() && GetLocalTeam()->GetTeamNumber() == team) ) + { CLocalPlayerFilter filter; - C_BaseEntity::EmitSound( filter, SOUND_FROM_LOCAL_PLAYER, et ); + const char *pszSoundName = event->GetString("sound"); + C_BaseEntity::EmitSound( filter, SOUND_FROM_LOCAL_PLAYER, pszSoundName ); } } else if ( Q_strcmp( "server_cvar", eventname ) == 0 ) { + if ( IsX360() && !developer.GetBool() ) + return; + + if ( this == GetFullscreenClientMode() ) + return; + if ( !IsInCommentaryMode() ) { wchar_t wszCvarName[64]; g_pVGuiLocalize->ConvertANSIToUnicode( event->GetString("cvarname"), wszCvarName, sizeof(wszCvarName) ); - wchar_t wszCvarValue[64]; + wchar_t wszCvarValue[16]; g_pVGuiLocalize->ConvertANSIToUnicode( event->GetString("cvarvalue"), wszCvarValue, sizeof(wszCvarValue) ); - wchar_t wszLocalized[256]; + wchar_t wszLocalized[100]; g_pVGuiLocalize->ConstructString( wszLocalized, sizeof( wszLocalized ), g_pVGuiLocalize->Find( "#game_server_cvar_changed" ), 2, wszCvarName, wszCvarValue ); - char szLocalized[256]; + char szLocalized[100]; g_pVGuiLocalize->ConvertUnicodeToANSI( wszLocalized, szLocalized, sizeof(szLocalized) ); hudChat->Printf( CHAT_FILTER_SERVERMSG, "%s", szLocalized ); @@ -1143,6 +1174,9 @@ void ClientModeShared::FireGameEvent( IGameEvent *event ) } else if ( Q_strcmp( "achievement_earned", eventname ) == 0 ) { + if ( this == GetFullscreenClientMode() ) + return; + int iPlayerIndex = event->GetInt( "player" ); C_BasePlayer *pPlayer = UTIL_PlayerByIndex( iPlayerIndex ); int iAchievement = event->GetInt( "achievement" ); @@ -1156,15 +1190,13 @@ void ClientModeShared::FireGameEvent( IGameEvent *event ) if ( !pAchievementMgr ) return; - IAchievement *pAchievement = pAchievementMgr->GetAchievementByID( iAchievement ); + IAchievement *pAchievement = pAchievementMgr->GetAchievementByID( iAchievement, GetSplitScreenPlayerSlot() ); if ( pAchievement ) { - if ( !pPlayer->IsDormant() && pPlayer->ShouldAnnounceAchievement() ) + if ( !pPlayer->IsDormant() ) { - pPlayer->SetNextAchievementAnnounceTime( gpGlobals->curtime + ACHIEVEMENT_ANNOUNCEMENT_MIN_TIME ); - // no particle effect if the local player is the one with the achievement or the player is dead - if ( !pPlayer->IsLocalPlayer() && pPlayer->IsAlive() ) + if ( !C_BasePlayer::IsLocalPlayer( pPlayer ) && pPlayer->IsAlive() ) { //tagES using the "head" attachment won't work for CS and DoD pPlayer->ParticleProp()->Create( "achieved", PATTACH_POINT_FOLLOW, "head" ); @@ -1193,192 +1225,14 @@ void ClientModeShared::FireGameEvent( IGameEvent *event ) } } } -#if defined( TF_CLIENT_DLL ) - else if ( Q_strcmp( "item_found", eventname ) == 0 ) - { - int iPlayerIndex = event->GetInt( "player" ); - entityquality_t iItemQuality = event->GetInt( "quality" ); - int iMethod = event->GetInt( "method" ); - int iItemDef = event->GetInt( "itemdef" ); - C_BasePlayer *pPlayer = UTIL_PlayerByIndex( iPlayerIndex ); - const GameItemDefinition_t *pItemDefinition = dynamic_cast( GetItemSchema()->GetItemDefinition( iItemDef ) ); - - if ( !pPlayer || !pItemDefinition ) - return; - - if ( g_PR ) - { - wchar_t wszPlayerName[MAX_PLAYER_NAME_LENGTH]; - g_pVGuiLocalize->ConvertANSIToUnicode( g_PR->GetPlayerName( iPlayerIndex ), wszPlayerName, sizeof( wszPlayerName ) ); - - if ( iMethod < 0 || iMethod >= ARRAYSIZE( g_pszItemFoundMethodStrings ) ) - { - iMethod = 0; - } - - const char *pszLocString = g_pszItemFoundMethodStrings[iMethod]; - if ( pszLocString ) - { - wchar_t wszItemFound[256]; - _snwprintf( wszItemFound, ARRAYSIZE( wszItemFound ), L"%ls", g_pVGuiLocalize->Find( pszLocString ) ); - - wchar_t *colorMarker = wcsstr( wszItemFound, L"::" ); - if ( colorMarker ) - { - const char *pszQualityColorString = EconQuality_GetColorString( (EEconItemQuality)iItemQuality ); - if ( pszQualityColorString ) - { - hudChat->SetCustomColor( pszQualityColorString ); - *(colorMarker+1) = COLOR_CUSTOM; - } - } - - // TODO: Update the localization strings to only have two format parameters since that's all we need. - wchar_t wszLocalizedString[256]; - g_pVGuiLocalize->ConstructString( wszLocalizedString, sizeof( wszLocalizedString ), wszItemFound, 3, wszPlayerName, CEconItemLocalizedFullNameGenerator( GLocalizationProvider(), pItemDefinition, iItemQuality ).GetFullName(), L"" ); - - char szLocalized[256]; - g_pVGuiLocalize->ConvertUnicodeToANSI( wszLocalizedString, szLocalized, sizeof( szLocalized ) ); - - hudChat->ChatPrintf( iPlayerIndex, CHAT_FILTER_SERVERMSG, "%s", szLocalized ); - } - } - } -#endif -#if defined( REPLAY_ENABLED ) - else if ( !V_strcmp( "replay_servererror", eventname ) ) - { - DisplayReplayMessage( event->GetString( "error", "#Replay_DefaultServerError" ), replay_msgduration_error.GetFloat(), true, NULL, false ); - } - else if ( !V_strcmp( "replay_startrecord", eventname ) ) - { - m_flReplayStartRecordTime = gpGlobals->curtime; - } - else if ( !V_strcmp( "replay_endrecord", eventname ) ) - { - m_flReplayStopRecordTime = gpGlobals->curtime; - } - else if ( !V_strcmp( "replay_replaysavailable", eventname ) ) - { - DisplayReplayMessage( "#Replay_ReplaysAvailable", replay_msgduration_replaysavailable.GetFloat(), false, NULL, false ); - } - - else if ( !V_strcmp( "game_newmap", eventname ) ) - { - // Make sure the instance count is reset to 0. Sometimes the count stay in sync and we get replay messages displaying lower than they should. - CReplayMessagePanel::RemoveAll(); - } -#endif - else { DevMsg( 2, "Unhandled GameEvent in ClientModeShared::FireGameEvent - %s\n", event->GetName() ); } } -void ClientModeShared::UpdateReplayMessages() -{ -#if defined( REPLAY_ENABLED ) - // Received a replay_startrecord event? - if ( m_flReplayStartRecordTime != 0.0f ) - { - DisplayReplayMessage( "#Replay_StartRecord", replay_msgduration_startrecord.GetFloat(), true, "replay\\startrecord.mp3", false ); - - m_flReplayStartRecordTime = 0.0f; - m_flReplayStopRecordTime = 0.0f; - } - - // Received a replay_endrecord event? - if ( m_flReplayStopRecordTime != 0.0f ) - { - DisplayReplayMessage( "#Replay_EndRecord", replay_msgduration_stoprecord.GetFloat(), true, "replay\\stoprecord.wav", false ); - - // Hide the replay reminder - if ( m_pReplayReminderPanel ) - { - m_pReplayReminderPanel->Hide(); - } - - m_flReplayStopRecordTime = 0.0f; - } - - if ( !engine->IsConnected() ) - { - ClearReplayMessageList(); - } -#endif -} - -void ClientModeShared::ClearReplayMessageList() -{ -#if defined( REPLAY_ENABLED ) - CReplayMessagePanel::RemoveAll(); -#endif -} -void ClientModeShared::DisplayReplayMessage( const char *pLocalizeName, float flDuration, bool bUrgent, - const char *pSound, bool bDlg ) -{ -#if defined( REPLAY_ENABLED ) - // Don't display during replay playback, and don't allow more than 4 at a time - const bool bInReplay = g_pEngineClientReplay->IsPlayingReplayDemo(); - if ( bInReplay || ( !bDlg && CReplayMessagePanel::InstanceCount() >= 4 ) ) - return; - // Use default duration? - if ( flDuration == -1.0f ) - { - flDuration = replay_msgduration_misc.GetFloat(); - } - - // Display a replay message - if ( bDlg ) - { - if ( engine->IsInGame() ) - { - Panel *pPanel = new CReplayMessageDlg( pLocalizeName ); - pPanel->SetVisible( true ); - pPanel->MakePopup(); - pPanel->MoveToFront(); - pPanel->SetKeyBoardInputEnabled( true ); - pPanel->SetMouseInputEnabled( true ); -#if defined( TF_CLIENT_DLL ) - TFModalStack()->PushModal( pPanel ); -#endif - } - else - { - ShowMessageBox( "#Replay_GenericMsgTitle", pLocalizeName, "#GameUI_OK" ); - } - } - else - { - CReplayMessagePanel *pMsgPanel = new CReplayMessagePanel( pLocalizeName, flDuration, bUrgent ); - pMsgPanel->Show(); - } - - // Play a sound if appropriate - if ( pSound ) - { - surface()->PlaySound( pSound ); - } -#endif -} - -void ClientModeShared::DisplayReplayReminder() -{ -#if defined( REPLAY_ENABLED ) - if ( m_pReplayReminderPanel && g_pReplay->IsRecording() ) - { - // Only display the panel if we haven't already requested a replay for the given life - CReplay *pCurLifeReplay = static_cast< CReplay * >( g_pClientReplayContext->GetReplayManager()->GetReplayForCurrentLife() ); - if ( pCurLifeReplay && !pCurLifeReplay->m_bRequestedByUser && !pCurLifeReplay->m_bSaved ) - { - m_pReplayReminderPanel->Show(); - } - } -#endif -} //----------------------------------------------------------------------------- @@ -1395,3 +1249,9 @@ void ClientModeShared::DeactivateInGameVGuiContext() vgui::ivgui()->ActivateContext( DEFAULT_VGUI_CONTEXT ); } +int ClientModeShared::GetSplitScreenPlayerSlot() const +{ + int nSplitScreenUserSlot = vgui::ipanel()->GetMessageContextId( m_pViewport->GetVPanel() ); + Assert( nSplitScreenUserSlot != -1 ); + return nSplitScreenUserSlot; +} diff --git a/game/client/clientmode_shared.h b/game/client/clientmode_shared.h index 27336964e..c05cfd5aa 100644 --- a/game/client/clientmode_shared.h +++ b/game/client/clientmode_shared.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // @@ -27,22 +27,10 @@ namespace vgui class Panel; } -//============================================================================= -// HPE_BEGIN: -// [tj] Moved this from the .cpp file so derived classes could access it -//============================================================================= - -#define ACHIEVEMENT_ANNOUNCEMENT_MIN_TIME 10 - -//============================================================================= -// HPE_END -//============================================================================= - -class CReplayReminderPanel; - #define USERID2PLAYER(i) ToBasePlayer( ClientEntityList().GetEnt( engine->GetPlayerForUserID( i ) ) ) extern IClientMode *GetClientModeNormal(); // must be implemented +extern IClientMode *GetFullscreenClientMode(); // This class implements client mode functionality common to HL2 and TF2. class ClientModeShared : public IClientMode, public CGameEventListener @@ -63,19 +51,20 @@ class ClientModeShared : public IClientMode, public CGameEventListener virtual void LevelShutdown( void ); virtual void Enable(); + virtual void EnableWithRootPanel( vgui::VPANEL pRoot ); virtual void Disable(); - virtual void Layout(); + virtual void Layout( bool bForce = false ); virtual void ReloadScheme( void ); + virtual void ReloadSchemeWithRoot( vgui::VPANEL pRoot ); virtual void OverrideView( CViewSetup *pSetup ); + virtual void OverrideAudioState( AudioState_t *pAudioState ) { return; } virtual bool ShouldDrawDetailObjects( ); virtual bool ShouldDrawEntity(C_BaseEntity *pEnt); virtual bool ShouldDrawLocalPlayer( C_BasePlayer *pPlayer ); virtual bool ShouldDrawViewModel(); virtual bool ShouldDrawParticles( ); virtual bool ShouldDrawCrosshair( void ); - virtual bool ShouldBlackoutAroundHUD() OVERRIDE; - virtual HeadtrackMovementMode_t ShouldOverrideHeadtrackControl() OVERRIDE; virtual void AdjustEngineViewport( int& x, int& y, int& width, int& height ); virtual void PreRender(CViewSetup *pSetup); virtual void PostRender(); @@ -83,6 +72,10 @@ class ClientModeShared : public IClientMode, public CGameEventListener virtual void ProcessInput(bool bActive); virtual bool CreateMove( float flInputSampleTime, CUserCmd *cmd ); virtual void Update(); + virtual void OnColorCorrectionWeightsReset( void ); + virtual float GetColorCorrectionScale( void ) const; + virtual void SetBlurFade( float scale ) {} + virtual float GetBlurFade( void ) { return 0.0f; } // Input virtual int KeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding ); @@ -99,6 +92,8 @@ class ClientModeShared : public IClientMode, public CGameEventListener virtual float GetViewModelFOV( void ); virtual vgui::Panel* GetViewport() { return m_pViewport; } + virtual vgui::Panel *GetPanelFromViewport( const char *pchNamePath ); + // Gets at the viewports vgui panel animation controller, if there is one... virtual vgui::AnimationController *GetViewportAnimationController() { return m_pViewport->GetAnimationController(); } @@ -109,46 +104,13 @@ class ClientModeShared : public IClientMode, public CGameEventListener virtual int HandleSpectatorKeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding ); - virtual void ComputeVguiResConditions( KeyValues *pkvConditions ) OVERRIDE; - - //============================================================================= - // HPE_BEGIN: - // [menglish] Save server information shown to the client in a persistent place - //============================================================================= - - virtual wchar_t* GetServerName() { return NULL; } - virtual void SetServerName(wchar_t* name) {}; - virtual wchar_t* GetMapName() { return NULL; } - virtual void SetMapName(wchar_t* name) {}; - - //============================================================================= - // HPE_END - //============================================================================= - - virtual bool DoPostScreenSpaceEffects( const CViewSetup *pSetup ); - - virtual void DisplayReplayMessage( const char *pLocalizeName, float flDuration, bool bUrgent, - const char *pSound, bool bDlg ); - - virtual bool IsInfoPanelAllowed() OVERRIDE { return true; } - virtual void InfoPanelDisplayed() OVERRIDE { } - virtual bool IsHTMLInfoPanelAllowed() OVERRIDE { return true; } + virtual void InitChatHudElement( void ); + virtual void InitWeaponSelectionHudElement( void ); protected: CBaseViewport *m_pViewport; - void DisplayReplayReminder(); - -private: - virtual void UpdateReplayMessages(); - - void ClearReplayMessageList(); - -#if defined( REPLAY_ENABLED ) - float m_flReplayStartRecordTime; - float m_flReplayStopRecordTime; - CReplayReminderPanel *m_pReplayReminderPanel; -#endif + int GetSplitScreenPlayerSlot() const; // Message mode handling // All modes share a common chat interface diff --git a/game/client/clientshadowmgr.cpp b/game/client/clientshadowmgr.cpp index 5b4dc6c8c..4cb2c8493 100644 --- a/game/client/clientshadowmgr.cpp +++ b/game/client/clientshadowmgr.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // @@ -52,62 +52,106 @@ // // In the case of studio models, we need a separate operation to remove // the shadow from all studio models +// +// DEFERRED SHADOW RENDERING +// +// When deferred shadow rendering (currently 360 only) is enabled. The +// ClientShadowMgr bypasses most calls to the engine shadow mgr to avoid the +// CPU overhead of clipping world geometry against shadow frustums. Instead, +// We render each shadow frustum and use the depth buffer to back-project each +// covered screen pixel into shadow space and apply the shadow. This causes +// everything that rendered into the depth buffer during the opaque renderables +// pass to be a shadow receiver (shadows on static props are free). Because this +// approach requires a lot of fill-rate, we impose the limitation that shadow +// casters can't receive shadows. Shadow casters are marked in the stencil buffer +// (using stencil mask 0x4) AND in the 360's heirarchical stencil buffer, which +// is most important for controlling fill rate. Initializing the stencil mask +// for shadow casters currently happens in several places: the staticpropmgr, +// c_baseanimating rendering code, and L4D-specific entity classes. +// //===========================================================================// #include "cbase.h" -#include "engine/ishadowmgr.h" +#include "engine/IShadowMgr.h" #include "model_types.h" #include "bitmap/imageformat.h" -#include "materialsystem/imaterialproxy.h" -#include "materialsystem/imaterialvar.h" -#include "materialsystem/imaterial.h" -#include "materialsystem/imesh.h" -#include "materialsystem/itexture.h" -#include "bsptreedata.h" +#include "materialsystem/IMaterialProxy.h" +#include "materialsystem/IMaterialVar.h" +#include "materialsystem/IMaterial.h" +#include "materialsystem/IMesh.h" +#include "materialsystem/ITexture.h" +#include "BSPTreeData.h" #include "utlmultilist.h" -#include "collisionutils.h" +#include "CollisionUtils.h" #include "iviewrender.h" -#include "ivrenderview.h" +#include "IVRenderView.h" #include "tier0/vprof.h" #include "engine/ivmodelinfo.h" #include "view_shared.h" -#include "engine/ivdebugoverlay.h" +#include "engine/IVDebugOverlay.h" #include "engine/IStaticPropMgr.h" #include "datacache/imdlcache.h" #include "viewrender.h" -#include "tier0/icommandline.h" +#include "tier0/ICommandLine.h" #include "vstdlib/jobthread.h" -#include "toolframework_client.h" #include "bonetoworldarray.h" -#include "cmodel.h" - - +#include "debugoverlay_shared.h" +#include "shaderapi/ishaderapi.h" +#include "renderparm.h" +#include "rendertexture.h" +#include "clientalphaproperty.h" +#include "flashlighteffect.h" +#include "c_env_projectedtexture.h" + +#include "imaterialproxydict.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" + static ConVar r_flashlightdrawfrustum( "r_flashlightdrawfrustum", "0" ); +static ConVar r_flashlightdrawfrustumbbox( "r_flashlightdrawfrustumbbox", "0" ); static ConVar r_flashlightmodels( "r_flashlightmodels", "1" ); static ConVar r_shadowrendertotexture( "r_shadowrendertotexture", "0" ); -static ConVar r_flashlight_version2( "r_flashlight_version2", "0", FCVAR_CHEAT | FCVAR_DEVELOPMENTONLY ); +static ConVar r_shadow_lightpos_lerptime( "r_shadow_lightpos_lerptime", "0.5" ); +static ConVar r_shadowfromworldlights_debug( "r_shadowfromworldlights_debug", "0", FCVAR_CHEAT ); +static ConVar r_shadowfromanyworldlight( "r_shadowfromanyworldlight", "0", FCVAR_CHEAT ); +static ConVar r_shadow_shortenfactor( "r_shadow_shortenfactor", "2" , 0, "Makes shadows cast from local lights shorter" ); + +static void HalfUpdateRateCallback( IConVar *var, const char *pOldValue, float flOldValue ); +static ConVar r_shadow_half_update_rate( "r_shadow_half_update_rate", IsX360() ? "1" : "0", 0, "Updates shadows at half the framerate", HalfUpdateRateCallback ); + +static void DeferredShadowToggleCallback( IConVar *var, const char *pOldValue, float flOldValue ); +static void DeferredShadowDownsampleToggleCallback( IConVar *var, const char *pOldValue, float flOldValue ); +ConVar r_shadow_deferred( "r_shadow_deferred", "0", FCVAR_CHEAT, "Toggle deferred shadow rendering", DeferredShadowToggleCallback ); +static ConVar r_shadow_deferred_downsample( "r_shadow_deferred_downsample", "0", 0, "Toggle low-res deferred shadow rendering", DeferredShadowDownsampleToggleCallback ); +static ConVar r_shadow_deferred_simd( "r_shadow_deferred_simd", "0" ); + +static ConVar r_shadow_debug_spew( "r_shadow_debug_spew", "0", FCVAR_CHEAT ); + ConVar r_flashlightdepthtexture( "r_flashlightdepthtexture", "1" ); +#if defined( _X360 ) +ConVar r_flashlightdepthreshigh( "r_flashlightdepthreshigh", "512" ); +#else +ConVar r_flashlightdepthreshigh( "r_flashlightdepthreshigh", "2048" ); +#endif + #if defined( _X360 ) ConVar r_flashlightdepthres( "r_flashlightdepthres", "512" ); #else ConVar r_flashlightdepthres( "r_flashlightdepthres", "1024" ); #endif -ConVar r_threaded_client_shadow_manager( "r_threaded_client_shadow_manager", "0" ); +#if defined( _X360 ) +#define RTT_TEXTURE_SIZE_640 +#endif #ifdef _WIN32 #pragma warning( disable: 4701 ) #endif -// forward declarations -void ToolFramework_RecordMaterialParams( IMaterial *pMaterial ); - //----------------------------------------------------------------------------- // A texture allocator used to batch textures together @@ -155,14 +199,21 @@ class CTextureAllocator void DebugPrintCache( void ); + void InitRenderTargets( void ); + private: typedef unsigned short FragmentHandle_t; enum { INVALID_FRAGMENT_HANDLE = (FragmentHandle_t)~0, +#ifdef RTT_TEXTURE_SIZE_640 + TEXTURE_PAGE_SIZE = 640, + MAX_TEXTURE_POWER = 7, +#else TEXTURE_PAGE_SIZE = 1024, MAX_TEXTURE_POWER = 8, +#endif #if !defined( _X360 ) MIN_TEXTURE_POWER = 4, #else @@ -241,6 +292,11 @@ void CTextureAllocator::Init() m_Cache[i].m_List = m_Fragments.InvalidIndex(); } + InitRenderTargets(); +} + +void CTextureAllocator::InitRenderTargets( void ) +{ #if !defined( _X360 ) // don't need depth buffer for shadows m_TexturePage.InitRenderTarget( TEXTURE_PAGE_SIZE, TEXTURE_PAGE_SIZE, RT_SIZE_NO_CHANGE, IMAGE_FORMAT_ARGB8888, MATERIAL_RT_DEPTH_NONE, false, "_rt_Shadows" ); @@ -250,15 +306,22 @@ void CTextureAllocator::Init() // because full-res 1024x1024 shadow buffer is too large for EDRAM m_TexturePage.InitRenderTargetTexture( TEXTURE_PAGE_SIZE, TEXTURE_PAGE_SIZE, RT_SIZE_NO_CHANGE, IMAGE_FORMAT_ARGB8888, MATERIAL_RT_DEPTH_NONE, false, "_rt_Shadows" ); +#ifdef RTT_TEXTURE_SIZE_640 + // use 4x multisampling for smoother shadows + m_TexturePage.InitRenderTargetSurface( MAX_TEXTURE_SIZE, MAX_TEXTURE_SIZE, IMAGE_FORMAT_ARGB8888, false, RT_MULTISAMPLE_4_SAMPLES ); +#else // edram footprint is only 256x256x4 = 256K m_TexturePage.InitRenderTargetSurface( MAX_TEXTURE_SIZE, MAX_TEXTURE_SIZE, IMAGE_FORMAT_ARGB8888, false ); +#endif // due to texture/surface size mismatch, ensure texture page is entirely cleared translucent // otherwise border artifacts at edge of shadows due to pixel shader averaging of unwanted bits m_TexturePage->ClearTexture( 0, 0, 0, 0 ); #endif + } + void CTextureAllocator::Shutdown() { m_TexturePage.Shutdown(); @@ -276,6 +339,35 @@ void CTextureAllocator::Reset() m_Fragments.EnsureCapacity(256); // Set up the block sizes.... +#ifdef RTT_TEXTURE_SIZE_640 + // Going to 640x640 gives us roughly the same number of texture slots than the 1024x1024 texture + // and thus won't change cache thrashing patterns + m_Blocks[0].m_FragmentPower = MAX_TEXTURE_POWER-2; + m_Blocks[1].m_FragmentPower = MAX_TEXTURE_POWER-2; + m_Blocks[2].m_FragmentPower = MAX_TEXTURE_POWER-2; + m_Blocks[3].m_FragmentPower = MAX_TEXTURE_POWER-2; + m_Blocks[4].m_FragmentPower = MAX_TEXTURE_POWER-2; + m_Blocks[5].m_FragmentPower = MAX_TEXTURE_POWER-2; + m_Blocks[6].m_FragmentPower = MAX_TEXTURE_POWER-2; + m_Blocks[7].m_FragmentPower = MAX_TEXTURE_POWER-2; + m_Blocks[8].m_FragmentPower = MAX_TEXTURE_POWER-2; + m_Blocks[9].m_FragmentPower = MAX_TEXTURE_POWER-2; // 10 * 16 = 160 + m_Blocks[10].m_FragmentPower = MAX_TEXTURE_POWER-1; + m_Blocks[11].m_FragmentPower = MAX_TEXTURE_POWER-1; + m_Blocks[12].m_FragmentPower = MAX_TEXTURE_POWER-1; + m_Blocks[13].m_FragmentPower = MAX_TEXTURE_POWER-1; + m_Blocks[14].m_FragmentPower = MAX_TEXTURE_POWER-1; + m_Blocks[15].m_FragmentPower = MAX_TEXTURE_POWER-1; + m_Blocks[16].m_FragmentPower = MAX_TEXTURE_POWER-1; + m_Blocks[17].m_FragmentPower = MAX_TEXTURE_POWER-1; // 8 * 4 = 32 + m_Blocks[18].m_FragmentPower = MAX_TEXTURE_POWER; // 7 + m_Blocks[19].m_FragmentPower = MAX_TEXTURE_POWER; + m_Blocks[20].m_FragmentPower = MAX_TEXTURE_POWER; + m_Blocks[21].m_FragmentPower = MAX_TEXTURE_POWER; + m_Blocks[22].m_FragmentPower = MAX_TEXTURE_POWER; + m_Blocks[23].m_FragmentPower = MAX_TEXTURE_POWER; + m_Blocks[24].m_FragmentPower = MAX_TEXTURE_POWER; // 199 slots total +#else // FIXME: Improve heuristic?!? #if !defined( _X360 ) m_Blocks[0].m_FragmentPower = MAX_TEXTURE_POWER-4; // 128 cells at ExE resolution @@ -296,7 +388,9 @@ void CTextureAllocator::Reset() m_Blocks[12].m_FragmentPower = MAX_TEXTURE_POWER; m_Blocks[13].m_FragmentPower = MAX_TEXTURE_POWER; m_Blocks[14].m_FragmentPower = MAX_TEXTURE_POWER; - m_Blocks[15].m_FragmentPower = MAX_TEXTURE_POWER; + m_Blocks[15].m_FragmentPower = MAX_TEXTURE_POWER; // 190 slots total on 360 +#endif + // Initialize the LRU int i; @@ -699,6 +793,8 @@ class CClientShadowMgr : public IClientShadowMgr // Inherited from IClientShadowMgr virtual bool Init(); + virtual void InitRenderTargets(); + virtual void PostInit() {} virtual void Shutdown(); virtual void LevelInitPreEntity(); @@ -708,7 +804,7 @@ class CClientShadowMgr : public IClientShadowMgr virtual bool IsPerFrame() { return true; } - virtual void PreRender(); + virtual void PreRender() {} virtual void Update( float frametime ) { } virtual void PostRender() {} @@ -716,7 +812,9 @@ class CClientShadowMgr : public IClientShadowMgr virtual void OnRestore() {} virtual void SafeRemoveIfDesired() {} - virtual ClientShadowHandle_t CreateShadow( ClientEntityHandle_t entity, int flags ); + virtual void ReprojectShadows(); + + virtual ClientShadowHandle_t CreateShadow( ClientEntityHandle_t entity, int nEntIndex, int flags, CBitVec< MAX_SPLITSCREEN_PLAYERS > *pSplitScreenBits = NULL ); virtual void DestroyShadow( ClientShadowHandle_t handle ); // Create flashlight (projected texture light source) @@ -724,6 +822,11 @@ class CClientShadowMgr : public IClientShadowMgr virtual void UpdateFlashlightState( ClientShadowHandle_t shadowHandle, const FlashlightState_t &lightState ); virtual void DestroyFlashlight( ClientShadowHandle_t shadowHandle ); + // Create simple projected texture. it is not a light or a shadow, but this system does most of the work already for it + virtual ClientShadowHandle_t CreateProjection( const FlashlightState_t &lightState ); + virtual void UpdateProjectionState( ClientShadowHandle_t shadowHandle, const FlashlightState_t &lightState ); + virtual void DestroyProjection( ClientShadowHandle_t shadowHandle ); + // Update a shadow virtual void UpdateProjectedTexture( ClientShadowHandle_t handle, bool force ); @@ -743,11 +846,16 @@ class CClientShadowMgr : public IClientShadowMgr void RemoveAllShadowsFromReceiver( IClientRenderable* pRenderable, ShadowReceiver_t type ); // Re-renders all shadow textures for shadow casters that lie in the leaf list - void ComputeShadowTextures( const CViewSetup &view, int leafCount, LeafIndex_t* pLeafList ); + void ComputeShadowTextures( const CViewSetup &view, int leafCount, WorldListLeafData_t* pLeafList ); // Kicks off rendering into shadow depth maps (if any) void ComputeShadowDepthTextures( const CViewSetup &view ); + // Kicks off rendering of volumetrics for the flashlights + void DrawVolumetrics( const CViewSetup &view ); + + void GetFrustumExtents( ClientShadowHandle_t handle, Vector &vecMin, Vector &vecMax ); + // Frees shadow depth textures for use in subsequent view/frame void FreeShadowDepthTextures(); @@ -782,7 +890,7 @@ class CClientShadowMgr : public IClientShadowMgr void RestoreRenderState(); // Computes a rough bounding box encompassing the volume of the shadow - void ComputeShadowBBox( IClientRenderable *pRenderable, const Vector &vecAbsCenter, float flRadius, Vector *pAbsMins, Vector *pAbsMaxs ); + void ComputeShadowBBox( IClientRenderable *pRenderable, ClientShadowHandle_t shadowHandle, const Vector &vecAbsCenter, float flRadius, Vector *pAbsMins, Vector *pAbsMaxs ); bool WillParentRenderBlobbyShadow( IClientRenderable *pRenderable ); @@ -794,6 +902,15 @@ class CClientShadowMgr : public IClientShadowMgr r_shadows_gamecontrol.SetValue( bDisabled != 1 ); } + // Toggle shadow casting from world light sources + virtual void SetShadowFromWorldLightsEnabled( bool bEnable ); + void SuppressShadowFromWorldLights( bool bSuppress ); + bool IsShadowingFromWorldLights() const { return m_bShadowFromWorldLights && !m_bSuppressShadowFromWorldLights; } + + virtual void DrawDeferredShadows( const CViewSetup &view, int leafCount, WorldListLeafData_t* pLeafList ); + + virtual void UpdateSplitscreenLocalPlayerShadowSkip(); + private: enum { @@ -811,20 +928,46 @@ class CClientShadowMgr : public IClientShadowMgr unsigned short m_Flags; VMatrix m_WorldToShadow; Vector2D m_WorldSize; + Vector m_ShadowDir; Vector m_LastOrigin; QAngle m_LastAngles; + Vector m_CurrentLightPos; // When shadowing from local lights, stores the position of the currently shadowing light + Vector m_TargetLightPos; // When shadowing from local lights, stores the position of the new shadowing light + float m_LightPosLerp; // Lerp progress when going from current to target light TextureHandle_t m_ShadowTexture; CTextureReference m_ShadowDepthTexture; int m_nRenderFrame; EHANDLE m_hTargetEntity; + + bool m_bUseSplitScreenBits; + CBitVec< MAX_SPLITSCREEN_PLAYERS > m_SplitScreenBits; + int m_nLastUpdateFrame; + + // Extra info for deferred shadows. + // FIXME: This data is also stored in CShadowMgr in the engine. + int m_FalloffBias; + float m_MaxDist; + float m_FalloffStart; + Vector2D m_TexCoordOffset; + Vector2D m_TexCoordScale; + VMatrix m_WorldToTexture; + + int m_nSplitscreenOwner; }; private: + friend void DeferredShadowToggleCallback( IConVar *var, const char *pOldValue, float flOldValue ); + friend void DeferredShadowDownsampleToggleCallback( IConVar *var, const char *pOldValue, float flOldValue ); + friend void HalfUpdateRateCallback( IConVar *var, const char *pOldValue, float flOldValue ); + // Shadow update functions void UpdateStudioShadow( IClientRenderable *pRenderable, ClientShadowHandle_t handle ); void UpdateBrushShadow( IClientRenderable *pRenderable, ClientShadowHandle_t handle ); void UpdateShadow( ClientShadowHandle_t handle, bool force ); + // Updates shadow cast direction when shadowing from world lights + void UpdateShadowDirectionFromLocalLightSource( ClientShadowHandle_t shadowHandle ); + // Gets the entity whose shadow this shadow will render into IClientRenderable *GetParentShadowEntity( ClientShadowHandle_t handle ); @@ -842,6 +985,8 @@ class CClientShadowMgr : public IClientShadowMgr void BuildPerspectiveWorldToFlashlightMatrix( VMatrix& matWorldToShadow, const FlashlightState_t &flashlightState ); + void BuildOrthoWorldToFlashlightMatrix( VMatrix& matWorldToShadow, const FlashlightState_t &flashlightState ); + // Update a shadow void UpdateProjectedTextureInternal( ClientShadowHandle_t handle, bool force ); @@ -887,9 +1032,11 @@ class CClientShadowMgr : public IClientShadowMgr // Causes all shadows to be re-updated void UpdateAllShadows(); + void RemoveAllShadowDecals(); + // One of these gets called with every shadow that potentially will need to re-render - bool DrawRenderToTextureShadow( unsigned short clientShadowHandle, float flArea ); - void DrawRenderToTextureShadowLOD( unsigned short clientShadowHandle ); + bool DrawRenderToTextureShadow( int nSlot, unsigned short clientShadowHandle, float flArea ); + void DrawRenderToTextureShadowLOD( int nSlot, unsigned short clientShadowHandle ); // Draws all children shadows into our own bool DrawShadowHierarchy( IClientRenderable *pRenderable, const ClientShadow_t &shadow, bool bChild = false ); @@ -900,6 +1047,7 @@ class CClientShadowMgr : public IClientShadowMgr // Computes + sets the render-to-texture texcoords void SetRenderToTextureShadowTexCoords( ShadowHandle_t handle, int x, int y, int w, int h ); + void SetRenderToTextureShadowTexCoords( ClientShadow_t& shadow, int x, int y, int w, int h ); // Visualization.... void DrawRenderToTextureDebugInfo( IClientRenderable* pRenderable, const Vector& mins, const Vector& maxs ); @@ -911,6 +1059,8 @@ class CClientShadowMgr : public IClientShadowMgr float GetShadowDistance( IClientRenderable *pRenderable ) const; const Vector &GetShadowDirection( IClientRenderable *pRenderable ) const; + const Vector &GetShadowDirection( ClientShadowHandle_t shadowHandle ) const; + // Initialize, shutdown render-to-texture shadows void InitDepthTextureShadows(); void ShutdownDepthTextureShadows(); @@ -919,15 +1069,20 @@ class CClientShadowMgr : public IClientShadowMgr void InitRenderToTextureShadows(); void ShutdownRenderToTextureShadows(); + // Initialize, shutdown deferred render-to-texture shadows + void InitDeferredShadows(); + void ShutdownDeferredShadows(); + + void ShutdownRenderTargets( void ); static bool ShadowHandleCompareFunc( const ClientShadowHandle_t& lhs, const ClientShadowHandle_t& rhs ) { return lhs < rhs; } - ClientShadowHandle_t CreateProjectedTexture( ClientEntityHandle_t entity, int flags ); + ClientShadowHandle_t CreateProjectedTexture( ClientEntityHandle_t entity, int nEntIndex, int flags, CBitVec< MAX_SPLITSCREEN_PLAYERS > *pSplitScreenBits ); // Lock down the usage of a shadow depth texture...must be unlocked use on subsequent views / frames - bool LockShadowDepthTexture( CTextureReference *shadowDepthTexture ); + bool LockShadowDepthTexture( CTextureReference *shadowDepthTexture, int nStartTexture ); void UnlockAllShadowDepthTextures(); // Set and clear flashlight target renderable @@ -939,17 +1094,44 @@ class CClientShadowMgr : public IClientShadowMgr bool IsFlashlightTarget( ClientShadowHandle_t shadowHandle, IClientRenderable *pRenderable ); // Builds a list of active shadows requiring shadow depth renders - int BuildActiveShadowDepthList( const CViewSetup &viewSetup, int nMaxDepthShadows, ClientShadowHandle_t *pActiveDepthShadows ); + int BuildActiveShadowDepthList( const CViewSetup &viewSetup, int nMaxDepthShadows, ClientShadowHandle_t *pActiveDepthShadows, int &nNumHighRes ); + + // Builds a list of active flashlights + int BuildActiveFlashlightList( const CViewSetup &viewSetup, int nMaxFlashlights, ClientShadowHandle_t *pActiveFlashlights ); // Sets the view's active flashlight render state void SetViewFlashlightState( int nActiveFlashlightCount, ClientShadowHandle_t* pActiveFlashlights ); + // Draw flashlight wireframe using debug overlay + void DrawFrustum( const Vector &vOrigin, const VMatrix &matWorldToFlashlight ); + + // Draw uberlight rig in wireframe using debug overlay + void DrawUberlightRig( const Vector &vOrigin, const VMatrix &matWorldToFlashlight, FlashlightState_t state ); + + // Called from PreRender to work through the dirty shadow set + void UpdateDirtyShadows(); + void UpdateDirtyShadowsHalfRate(); + void UpdateDirtyShadow( ClientShadowHandle_t handle ); + void FlushLeftOverDirtyShadows(); + + void QueueShadowForDestruction( ClientShadowHandle_t handle ); + void DestroyQueuedShadows(); + + // Deferred RTT shadow rendering support + static void BuildCubeWithDegenerateEdgeQuads( CMeshBuilder& meshBuilder, const matrix3x4_t& objToWorld, const VMatrix& projToShadow, const CClientShadowMgr::ClientShadow_t& shadow ); + bool SetupDeferredShadow( const ClientShadow_t& shadow, const Vector& camPos, matrix3x4_t* pObjToWorldMat ) const; + void DownsampleDepthBuffer( IMatRenderContext* pRenderContext, const VMatrix& invViewProjMat ); + void CompositeDeferredShadows( IMatRenderContext* pRenderContext ); + static void ComputeFalloffInfo( const ClientShadow_t& shadow, Vector* pShadowFalloffParams ); + private: Vector m_SimpleShadowDir; color32 m_AmbientLightColor; CMaterialReference m_SimpleShadow; CMaterialReference m_RenderShadow; CMaterialReference m_RenderModelShadow; + CMaterialReference m_RenderDeferredShadowMat; + CMaterialReference m_RenderDeferredSimpleShadowMat; CTextureReference m_DummyColorTexture; CUtlLinkedList< ClientShadow_t, ClientShadowHandle_t > m_Shadows; CTextureAllocator m_ShadowAllocator; @@ -957,23 +1139,40 @@ class CClientShadowMgr : public IClientShadowMgr bool m_RenderToTextureActive; bool m_bRenderTargetNeedsClear; bool m_bUpdatingDirtyShadows; - bool m_bThreaded; float m_flShadowCastDist; float m_flMinShadowArea; - CUtlRBTree< ClientShadowHandle_t, unsigned short > m_DirtyShadows; + + typedef CUtlRBTree< ClientShadowHandle_t, unsigned short > ClientShadowHandleSet; + ClientShadowHandleSet m_DirtyShadows; + ClientShadowHandleSet m_DirtyShadowsLeftOver; // shadows left over to update from previous frame + CUtlVector< ClientShadowHandle_t > m_TransparentShadows; + CUtlVector< ClientShadowHandle_t > m_shadowsToDestroy; + + int m_nPrevFrameCount; // These members maintain current state of depth texturing (size and global active state) // If either changes in a frame, PreRender() will catch it and do the appropriate allocation, deallocation or reallocation bool m_bDepthTextureActive; int m_nDepthTextureResolution; // Assume square (height == width) + int m_nDepthTextureResolutionHigh; // Assume square (height == width) + int m_nLowResStart; // Place in the shadow render target where the low res shadows start + bool m_bDepthTexturesAllocated; CUtlVector< CTextureReference > m_DepthTextureCache; CUtlVector< bool > m_DepthTextureCacheLocks; int m_nMaxDepthTextureShadows; + bool m_bShadowFromWorldLights; + bool m_bSuppressShadowFromWorldLights; + friend class CVisibleShadowList; friend class CVisibleShadowFrustumList; + + CTextureReference m_downSampledNormals; + CTextureReference m_downSampledDepth; + + void CalculateRenderTargetsAndSizes( void ); }; //----------------------------------------------------------------------------- @@ -998,10 +1197,12 @@ class CVisibleShadowList : public IClientLeafShadowEnum public: CVisibleShadowList(); - int FindShadows( const CViewSetup *pView, int nLeafCount, LeafIndex_t *pLeafList ); + int FindShadows( const CViewSetup *pView, int nLeafCount, WorldListLeafData_t *pLeafList ); int GetVisibleShadowCount() const; + int GetVisibleBlobbyShadowCount() const; const VisibleShadowInfo_t &GetVisibleShadow( int i ) const; + const VisibleShadowInfo_t &GetVisibleBlobbyShadow( int i ) const; private: void EnumShadow( unsigned short clientShadowHandle ); @@ -1009,6 +1210,7 @@ class CVisibleShadowList : public IClientLeafShadowEnum void PrioritySort(); CUtlVector m_ShadowsInView; + CUtlVector m_BlobbyShadowsInView; CUtlVector m_PriorityIndex; }; @@ -1041,6 +1243,15 @@ const VisibleShadowInfo_t &CVisibleShadowList::GetVisibleShadow( int i ) const return m_ShadowsInView[m_PriorityIndex[i]]; } +int CVisibleShadowList::GetVisibleBlobbyShadowCount() const +{ + return m_BlobbyShadowsInView.Count(); +} + +const VisibleShadowInfo_t &CVisibleShadowList::GetVisibleBlobbyShadow( int i ) const +{ + return m_BlobbyShadowsInView[i]; +} //----------------------------------------------------------------------------- // CVisibleShadowList - Computes approximate screen area of the shadow @@ -1064,13 +1275,17 @@ void CVisibleShadowList::EnumShadow( unsigned short clientShadowHandle ) if ( shadow.m_nRenderFrame == gpGlobals->framecount ) return; + // Don't bother with flashlights + if ( ( shadow.m_Flags & ( SHADOW_FLAGS_FLASHLIGHT | SHADOW_FLAGS_SIMPLE_PROJECTION )) != 0 ) + return; + // We don't need to bother with it if it's not render-to-texture - if ( s_ClientShadowMgr.GetActualShadowCastType( clientShadowHandle ) != SHADOWS_RENDER_TO_TEXTURE ) + ShadowType_t shadowType = s_ClientShadowMgr.GetActualShadowCastType( clientShadowHandle ); + if ( shadowType != SHADOWS_RENDER_TO_TEXTURE && shadowType != SHADOWS_SIMPLE ) return; // Don't bother with it if the shadow is totally transparent - const ShadowInfo_t &shadowInfo = shadowmgr->GetInfo( shadow.m_ShadowHandle ); - if ( shadowInfo.m_FalloffBias == 255 ) + if ( shadow.m_FalloffBias == 255 ) return; IClientRenderable *pRenderable = ClientEntityList().GetClientRenderableFromHandle( shadow.m_Entity ); @@ -1088,7 +1303,7 @@ void CVisibleShadowList::EnumShadow( unsigned short clientShadowHandle ) // Compute a box surrounding the shadow Vector vecAbsMins, vecAbsMaxs; - s_ClientShadowMgr.ComputeShadowBBox( pRenderable, vecAbsCenter, flRadius, &vecAbsMins, &vecAbsMaxs ); + s_ClientShadowMgr.ComputeShadowBBox( pRenderable, clientShadowHandle, vecAbsCenter, flRadius, &vecAbsMins, &vecAbsMaxs ); // FIXME: Add distance check here? @@ -1096,16 +1311,28 @@ void CVisibleShadowList::EnumShadow( unsigned short clientShadowHandle ) if (engine->CullBox( vecAbsMins, vecAbsMaxs )) return; - int i = m_ShadowsInView.AddToTail( ); - VisibleShadowInfo_t &info = m_ShadowsInView[i]; - info.m_hShadow = clientShadowHandle; - m_ShadowsInView[i].m_flArea = ComputeScreenArea( vecAbsCenter, flRadius ); + if ( shadowType == SHADOWS_RENDER_TO_TEXTURE ) + { + int i = m_ShadowsInView.AddToTail( ); + VisibleShadowInfo_t &info = m_ShadowsInView[i]; + + info.m_hShadow = clientShadowHandle; + info.m_flArea = ComputeScreenArea( vecAbsCenter, flRadius ); + + // Har, har. When water is rendering (or any multipass technique), + // we may well initially render from a viewpoint which doesn't include this shadow. + // That doesn't mean we shouldn't check it again though. Sucks that we need to compute + // the sphere + bbox multiply times though. + shadow.m_nRenderFrame = gpGlobals->framecount; + } + else + { + int i = m_BlobbyShadowsInView.AddToTail( ); + VisibleShadowInfo_t &info = m_BlobbyShadowsInView[i]; - // Har, har. When water is rendering (or any multipass technique), - // we may well initially render from a viewpoint which doesn't include this shadow. - // That doesn't mean we shouldn't check it again though. Sucks that we need to compute - // the sphere + bbox multiply times though. - shadow.m_nRenderFrame = gpGlobals->framecount; + info.m_hShadow = clientShadowHandle; + info.m_flArea = 0.0f; + } } @@ -1138,7 +1365,7 @@ void CVisibleShadowList::PrioritySort() flLargestArea = m_ShadowsInView[nIndex].m_flArea; } } - ::V_swap( m_PriorityIndex[i], m_PriorityIndex[nLargestInd] ); + V_swap( m_PriorityIndex[i], m_PriorityIndex[nLargestInd] ); } } @@ -1146,12 +1373,14 @@ void CVisibleShadowList::PrioritySort() //----------------------------------------------------------------------------- // CVisibleShadowList - Main entry point for finding shadows in the leaf list //----------------------------------------------------------------------------- -int CVisibleShadowList::FindShadows( const CViewSetup *pView, int nLeafCount, LeafIndex_t *pLeafList ) +int CVisibleShadowList::FindShadows( const CViewSetup *pView, int nLeafCount, WorldListLeafData_t *pLeafList ) { VPROF_BUDGET( "CVisibleShadowList::FindShadows", VPROF_BUDGETGROUP_SHADOW_RENDERING ); m_ShadowsInView.RemoveAll(); + m_BlobbyShadowsInView.RemoveAll(); ClientLeafSystem()->EnumerateShadowsInLeaves( nLeafCount, pLeafList, this ); + int nCount = m_ShadowsInView.Count(); if (nCount != 0) { @@ -1162,16 +1391,36 @@ int CVisibleShadowList::FindShadows( const CViewSetup *pView, int nLeafCount, Le } + +// sniff the command line parameters, etc. to determine how many shadow rt's and their dimensions +void CClientShadowMgr::CalculateRenderTargetsAndSizes( void ) +{ + bool bTools = CommandLine()->CheckParm( "-tools" ) != NULL; + + m_nDepthTextureResolution = r_flashlightdepthres.GetInt(); + m_nDepthTextureResolutionHigh = r_flashlightdepthreshigh.GetInt(); + if ( bTools ) // Higher resolution shadow maps in tools mode + { + char defaultRes[] = "2048"; + m_nDepthTextureResolution = atoi( CommandLine()->ParmValue( "-sfm_shadowmapres", defaultRes ) ); + } + m_nMaxDepthTextureShadows = bTools ? MAX_DEPTH_TEXTURE_SHADOWS_TOOLS : MAX_DEPTH_TEXTURE_SHADOWS; // Just one shadow depth texture in games, more in tools +} //----------------------------------------------------------------------------- // Constructor //----------------------------------------------------------------------------- CClientShadowMgr::CClientShadowMgr() : m_DirtyShadows( 0, 0, ShadowHandleCompareFunc ), + m_DirtyShadowsLeftOver( 0, 0, ShadowHandleCompareFunc ), + m_nPrevFrameCount( -1 ), m_RenderToTextureActive( false ), - m_bDepthTextureActive( false ) + m_bDepthTextureActive( false ), + m_bDepthTexturesAllocated( false ), + m_bShadowFromWorldLights( false ), + m_bSuppressShadowFromWorldLights( false ) { - m_nDepthTextureResolution = r_flashlightdepthres.GetInt(); - m_bThreaded = false; + + } @@ -1271,6 +1520,13 @@ CON_COMMAND_F( r_shadowblobbycutoff, "some shadow stuff", FCVAR_CHEAT ) } } +void OnShadowFromWorldLights( IConVar *var, const char *pOldValue, float flOldValue ); +static ConVar r_shadowfromworldlights( "r_shadowfromworldlights", "1", FCVAR_NONE, "Enable shadowing from world lights", OnShadowFromWorldLights ); +void OnShadowFromWorldLights( IConVar *var, const char *pOldValue, float flOldValue ) +{ + s_ClientShadowMgr.SuppressShadowFromWorldLights( !r_shadowfromworldlights.GetBool() ); +} + static void ShadowRestoreFunc( int nChangeFlags ) { s_ClientShadowMgr.RestoreRenderState(); @@ -1279,7 +1535,12 @@ static void ShadowRestoreFunc( int nChangeFlags ) //----------------------------------------------------------------------------- // Initialization, shutdown //----------------------------------------------------------------------------- -bool CClientShadowMgr::Init() +bool CClientShadowMgr::Init() +{ + return true; +} + +void CClientShadowMgr::InitRenderTargets() { m_bRenderTargetNeedsClear = false; m_SimpleShadow.Init( "decals/simpleshadow", TEXTURE_GROUP_DECAL ); @@ -1290,42 +1551,67 @@ bool CClientShadowMgr::Init() SetShadowBlobbyCutoffArea( 0.005 ); - bool bTools = CommandLine()->CheckParm( "-tools" ) != NULL; - m_nMaxDepthTextureShadows = bTools ? 4 : 1; // Just one shadow depth texture in games, more in tools - - bool bLowEnd = ( g_pMaterialSystemHardwareConfig->GetDXSupportLevel() < 80 ); - if ( !bLowEnd && r_shadowrendertotexture.GetBool() ) + if ( r_shadowrendertotexture.GetBool() ) { InitRenderToTextureShadows(); } // If someone turned shadow depth mapping on but we can't do it, force it off - if ( r_flashlightdepthtexture.GetBool() && !materials->SupportsShadowDepthTextures() ) + if ( r_flashlightdepthtexture.GetBool() && !g_pMaterialSystemHardwareConfig->SupportsShadowDepthTextures() ) { r_flashlightdepthtexture.SetValue( 0 ); ShutdownDepthTextureShadows(); } - if ( !bLowEnd && r_flashlightdepthtexture.GetBool() ) + InitDepthTextureShadows(); + + r_flashlightdepthres.SetValue( m_nDepthTextureResolution ); + r_flashlightdepthreshigh.SetValue( m_nDepthTextureResolutionHigh ); + + if ( m_DepthTextureCache.Count() ) { - InitDepthTextureShadows(); + bool bTools = CommandLine()->CheckParm( "-tools" ) != NULL; + int nNumShadows = bTools ? MAX_DEPTH_TEXTURE_SHADOWS_TOOLS : MAX_DEPTH_TEXTURE_SHADOWS; + m_nLowResStart = bTools ? MAX_DEPTH_TEXTURE_HIGHRES_SHADOWS_TOOLS : MAX_DEPTH_TEXTURE_HIGHRES_SHADOWS; + + if ( m_nLowResStart > nNumShadows ) + { + // All shadow slots filled with high res + m_nLowResStart = 0; + } + + // Shadow may be resized during allocation (due to resolution constraints etc) + m_nDepthTextureResolution = m_DepthTextureCache[ m_nLowResStart ]->GetActualWidth(); + r_flashlightdepthres.SetValue( m_nDepthTextureResolution ); + + m_nDepthTextureResolutionHigh = m_DepthTextureCache[ 0 ]->GetActualWidth(); + r_flashlightdepthreshigh.SetValue( m_nDepthTextureResolutionHigh ); } + InitDeferredShadows(); materials->AddRestoreFunc( ShadowRestoreFunc ); +} - return true; +void CClientShadowMgr::ShutdownRenderTargets( void ) +{ + if ( materials ) // ugh - this gets called during program shutdown, but with no mat system + { + materials->RemoveRestoreFunc( ShadowRestoreFunc ); + } } void CClientShadowMgr::Shutdown() { + ShutdownRenderTargets(); m_SimpleShadow.Shutdown(); m_Shadows.RemoveAll(); ShutdownRenderToTextureShadows(); ShutdownDepthTextureShadows(); - materials->RemoveRestoreFunc( ShadowRestoreFunc ); + ShutdownDeferredShadows(); + } @@ -1336,23 +1622,32 @@ void CClientShadowMgr::InitDepthTextureShadows() { VPROF_BUDGET( "CClientShadowMgr::InitDepthTextureShadows", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING ); - if( !m_bDepthTextureActive ) + if ( m_bDepthTextureActive ) + return; + + m_bDepthTextureActive = true; + + if ( !r_flashlightdepthtexture.GetBool() ) + return; + + if( !m_bDepthTexturesAllocated || m_nDepthTextureResolution != r_flashlightdepthres.GetInt() || m_nDepthTextureResolutionHigh != r_flashlightdepthreshigh.GetInt() ) { - m_bDepthTextureActive = true; + CalculateRenderTargetsAndSizes(); + m_bDepthTexturesAllocated = true; - ImageFormat dstFormat = materials->GetShadowDepthTextureFormat(); // Vendor-dependent depth texture format + ImageFormat dstFormat = g_pMaterialSystemHardwareConfig->GetShadowDepthTextureFormat(); // Vendor-dependent depth texture format #if !defined( _X360 ) - ImageFormat nullFormat = materials->GetNullTextureFormat(); // Vendor-dependent null texture format (takes as little memory as possible) + ImageFormat nullFormat = g_pMaterialSystemHardwareConfig->GetNullTextureFormat(); // Vendor-dependent null texture format (takes as little memory as possible) #endif materials->BeginRenderTargetAllocation(); #if defined( _X360 ) // For the 360, we'll be rendering depth directly into the dummy depth and Resolve()ing to the depth texture. // only need the dummy surface, don't care about color results - m_DummyColorTexture.InitRenderTargetTexture( r_flashlightdepthres.GetInt(), r_flashlightdepthres.GetInt(), RT_SIZE_OFFSCREEN, IMAGE_FORMAT_BGR565, MATERIAL_RT_DEPTH_SHARED, false, "_rt_ShadowDummy" ); - m_DummyColorTexture.InitRenderTargetSurface( r_flashlightdepthres.GetInt(), r_flashlightdepthres.GetInt(), IMAGE_FORMAT_BGR565, true ); + m_DummyColorTexture.InitRenderTargetTexture( 1, 1, RT_SIZE_OFFSCREEN, IMAGE_FORMAT_BGR565, MATERIAL_RT_DEPTH_SHARED, false, "_rt_ShadowDummy" ); + m_DummyColorTexture.InitRenderTargetSurface( m_nDepthTextureResolution, m_nDepthTextureResolution, IMAGE_FORMAT_BGR565, false ); #else - m_DummyColorTexture.InitRenderTarget( r_flashlightdepthres.GetInt(), r_flashlightdepthres.GetInt(), RT_SIZE_OFFSCREEN, nullFormat, MATERIAL_RT_DEPTH_NONE, false, "_rt_ShadowDummy" ); + m_DummyColorTexture.InitRenderTarget( m_nDepthTextureResolution, m_nDepthTextureResolution, RT_SIZE_OFFSCREEN, nullFormat, MATERIAL_RT_DEPTH_NONE, false, "_rt_ShadowDummy" ); #endif // Create some number of depth-stencil textures @@ -1364,24 +1659,19 @@ void CClientShadowMgr::InitDepthTextureShadows() bool bFalse = false; char strRTName[64]; - Q_snprintf( strRTName, ARRAYSIZE( strRTName ), "_rt_ShadowDepthTexture_%d", i ); + sprintf( strRTName, "_rt_ShadowDepthTexture_%d", i ); + + int nTextureResolution = ( i < MAX_DEPTH_TEXTURE_HIGHRES_SHADOWS ? m_nDepthTextureResolutionHigh : m_nDepthTextureResolution ); #if defined( _X360 ) // create a render target to use as a resolve target to get the shared depth buffer // surface is effectively never used - depthTex.InitRenderTargetTexture( m_nDepthTextureResolution, m_nDepthTextureResolution, RT_SIZE_OFFSCREEN, dstFormat, MATERIAL_RT_DEPTH_NONE, false, strRTName ); + depthTex.InitRenderTargetTexture( nTextureResolution, nTextureResolution, RT_SIZE_OFFSCREEN, dstFormat, MATERIAL_RT_DEPTH_NONE, false, strRTName ); depthTex.InitRenderTargetSurface( 1, 1, dstFormat, false ); #else - depthTex.InitRenderTarget( m_nDepthTextureResolution, m_nDepthTextureResolution, RT_SIZE_OFFSCREEN, dstFormat, MATERIAL_RT_DEPTH_NONE, false, strRTName ); + depthTex.InitRenderTarget( nTextureResolution, nTextureResolution, RT_SIZE_OFFSCREEN, dstFormat, MATERIAL_RT_DEPTH_NONE, false, strRTName ); #endif - if ( i == 0 ) - { - // Shadow may be resized during allocation (due to resolution constraints etc) - m_nDepthTextureResolution = depthTex->GetActualWidth(); - r_flashlightdepthres.SetValue( m_nDepthTextureResolution ); - } - m_DepthTextureCache.AddToTail( depthTex ); m_DepthTextureCacheLocks.AddToTail( bFalse ); } @@ -1392,7 +1682,7 @@ void CClientShadowMgr::InitDepthTextureShadows() void CClientShadowMgr::ShutdownDepthTextureShadows() { - if( m_bDepthTextureActive ) + if( m_bDepthTexturesAllocated ) { // Shut down the dummy texture m_DummyColorTexture.Shutdown(); @@ -1405,8 +1695,9 @@ void CClientShadowMgr::ShutdownDepthTextureShadows() m_DepthTextureCache.Remove( m_DepthTextureCache.Count()-1 ); } - m_bDepthTextureActive = false; + m_bDepthTexturesAllocated = false; } + m_bDepthTextureActive = false; } //----------------------------------------------------------------------------- @@ -1417,9 +1708,13 @@ void CClientShadowMgr::InitRenderToTextureShadows() if ( !m_RenderToTextureActive ) { m_RenderToTextureActive = true; + + g_pMaterialSystem->BeginRenderTargetAllocation(); + m_ShadowAllocator.Init(); + g_pMaterialSystem->EndRenderTargetAllocation(); + m_RenderShadow.Init( "decals/rendershadow", TEXTURE_GROUP_DECAL ); m_RenderModelShadow.Init( "decals/rendermodelshadow", TEXTURE_GROUP_DECAL ); - m_ShadowAllocator.Init(); m_ShadowAllocator.Reset(); m_bRenderTargetNeedsClear = true; @@ -1440,7 +1735,7 @@ void CClientShadowMgr::InitRenderToTextureShadows() MarkRenderToTextureShadowDirty( i ); // Switch the material to use render-to-texture shadows - shadowmgr->SetShadowMaterial( shadow.m_ShadowHandle, m_RenderShadow, m_RenderModelShadow, (void*)(uintp)i ); + shadowmgr->SetShadowMaterial( shadow.m_ShadowHandle, m_RenderShadow, m_RenderModelShadow, (void*)i ); } } } @@ -1457,6 +1752,7 @@ void CClientShadowMgr::ShutdownRenderToTextureShadows() // Switch the material to use blobby shadows ClientShadow_t& shadow = m_Shadows[i]; + shadowmgr->SetShadowMaterial( shadow.m_ShadowHandle, m_SimpleShadow, m_SimpleShadow, (void*)CLIENTSHADOW_INVALID_HANDLE ); shadowmgr->SetShadowTexCoord( shadow.m_ShadowHandle, 0, 0, 1, 1 ); ClearExtraClipPlanes( i ); @@ -1475,6 +1771,35 @@ void CClientShadowMgr::ShutdownRenderToTextureShadows() } } +#define DEFERRED_SHADOW_BUFFER_WIDTH 320 +#define DEFERRED_SHADOW_BUFFER_HEIGHT 180 + +void CClientShadowMgr::InitDeferredShadows() +{ + if ( IsX360() ) + { + m_RenderDeferredShadowMat.Init( "engine/renderdeferredshadow", TEXTURE_GROUP_OTHER ); + m_RenderDeferredSimpleShadowMat.Init( "engine/renderdeferredsimpleshadow", TEXTURE_GROUP_OTHER ); + } + + if ( r_shadow_deferred_downsample.GetBool() ) + { +#if defined( _X360 ) + m_downSampledNormals.InitRenderTargetTexture( DEFERRED_SHADOW_BUFFER_WIDTH, DEFERRED_SHADOW_BUFFER_HEIGHT, RT_SIZE_OFFSCREEN, IMAGE_FORMAT_ARGB8888, MATERIAL_RT_DEPTH_SEPARATE, false, "_rt_DownsampledNormals" ); + m_downSampledNormals.InitRenderTargetSurface( DEFERRED_SHADOW_BUFFER_WIDTH, DEFERRED_SHADOW_BUFFER_HEIGHT, IMAGE_FORMAT_ARGB8888, true ); + m_downSampledDepth.InitRenderTargetTexture( DEFERRED_SHADOW_BUFFER_WIDTH, DEFERRED_SHADOW_BUFFER_HEIGHT, RT_SIZE_OFFSCREEN, IMAGE_FORMAT_D24FS8, MATERIAL_RT_DEPTH_NONE, false, "_rt_DownsampledDepth" ); +#endif + } +} + +void CClientShadowMgr::ShutdownDeferredShadows() +{ + m_RenderDeferredShadowMat.Shutdown(); + m_RenderDeferredSimpleShadowMat.Shutdown(); + + m_downSampledNormals.Shutdown(); + m_downSampledDepth.Shutdown(); +} //----------------------------------------------------------------------------- // Sets the shadow color @@ -1490,8 +1815,20 @@ void CClientShadowMgr::SetShadowColor( unsigned char r, unsigned char g, unsigne if (m_RenderToTextureActive) { - m_RenderShadow->ColorModulate( fr, fg, fb ); - m_RenderModelShadow->ColorModulate( fr, fg, fb ); + if ( m_RenderShadow ) + { + m_RenderShadow->ColorModulate( fr, fg, fb ); + } + if ( m_RenderModelShadow ) + { + m_RenderModelShadow->ColorModulate( fr, fg, fb ); + } + + if ( IsX360() ) + { + m_RenderDeferredShadowMat->ColorModulate( fr, fg, fb ); + m_RenderDeferredSimpleShadowMat->ColorModulate( fr, fg, fb ); + } } m_AmbientLightColor.r = r; @@ -1514,6 +1851,9 @@ void CClientShadowMgr::LevelInitPreEntity() { m_bUpdatingDirtyShadows = false; + // Default setting for this, can be overridden by shadow control entities + SetShadowFromWorldLightsEnabled( true ); + Vector ambientColor; engine->GetAmbientLightColor( ambientColor ); ambientColor *= 3; @@ -1539,6 +1879,14 @@ void CClientShadowMgr::LevelInitPreEntity() //----------------------------------------------------------------------------- void CClientShadowMgr::LevelShutdownPostEntity() { + // Paranoid code to make sure all flashlights are deactivated. + // This should happen in the C_BasePlayer destructor, but I'm turning everything off to release the + // flashlight shadows just in case. + for ( int i = 0; i < MAX_SPLITSCREEN_PLAYERS; i++ ) + { + FlashlightEffectManager( i ).TurnOffFlashlight( true ); + } + // All shadows *should* have been cleaned up when the entities went away // but, just in case.... Assert( m_Shadows.Count() == 0 ); @@ -1636,7 +1984,7 @@ void CClientShadowMgr::UpdateAllShadows() ClientShadow_t& shadow = m_Shadows[i]; // Don't bother with flashlights - if ( ( shadow.m_Flags & SHADOW_FLAGS_FLASHLIGHT ) != 0 ) + if ( ( shadow.m_Flags & ( SHADOW_FLAGS_FLASHLIGHT | SHADOW_FLAGS_SIMPLE_PROJECTION ) ) != 0 ) continue; IClientRenderable *pRenderable = ClientEntityList().GetClientRenderableFromHandle( shadow.m_Entity ); @@ -1648,6 +1996,19 @@ void CClientShadowMgr::UpdateAllShadows() } } +void CClientShadowMgr::RemoveAllShadowDecals() +{ + for ( ClientShadowHandle_t i = m_Shadows.Head(); i != m_Shadows.InvalidIndex(); i = m_Shadows.Next(i) ) + { + ClientShadow_t& shadow = m_Shadows[i]; + + // Don't bother with flashlights + if ( ( shadow.m_Flags & ( SHADOW_FLAGS_FLASHLIGHT | SHADOW_FLAGS_SIMPLE_PROJECTION ) ) != 0 ) + continue; + + shadowmgr->RemoveAllDecalsFromShadow( shadow.m_ShadowHandle ); + } +} //----------------------------------------------------------------------------- // Sets the shadow direction @@ -1698,6 +2059,148 @@ const Vector &CClientShadowMgr::GetShadowDirection( IClientRenderable *pRenderab return vecResult; } +const Vector &CClientShadowMgr::GetShadowDirection( ClientShadowHandle_t shadowHandle ) const +{ + Assert( shadowHandle != CLIENTSHADOW_INVALID_HANDLE ); + + IClientRenderable* pRenderable = ClientEntityList().GetClientRenderableFromHandle( m_Shadows[shadowHandle].m_Entity ); + Assert( pRenderable ); + + if ( !IsShadowingFromWorldLights() ) + { + return GetShadowDirection( pRenderable ); + } + + Vector &vecResult = AllocTempVector(); + vecResult = m_Shadows[shadowHandle].m_ShadowDir; + + // Allow the renderable to override the default + pRenderable->GetShadowCastDirection( &vecResult, GetActualShadowCastType( pRenderable ) ); + + return vecResult; +} + +void CClientShadowMgr::UpdateShadowDirectionFromLocalLightSource( ClientShadowHandle_t shadowHandle ) +{ + Assert( shadowHandle != CLIENTSHADOW_INVALID_HANDLE ); + + ClientShadow_t& shadow = m_Shadows[shadowHandle]; + + IClientRenderable* pRenderable = ClientEntityList().GetClientRenderableFromHandle( shadow.m_Entity ); + + // TODO: Figure out why this still gets hit + Assert( pRenderable ); + if ( !pRenderable ) + { + DevWarning( "%s(): Skipping shadow with invalid client renderable (shadow handle %d)\n", __FUNCTION__, shadowHandle ); + return; + } + + Vector bbMin, bbMax; + pRenderable->GetRenderBoundsWorldspace( bbMin, bbMax ); + Vector origin( 0.5f * ( bbMin + bbMax ) ); + origin.z = bbMin.z; // Putting origin at the bottom of the bounding box makes the shadows a little shorter + + Vector lightPos; + Vector lightBrightness; + + if ( shadow.m_LightPosLerp >= 1.0f ) // skip finding new light source if we're in the middle of a lerp + { + if( modelrender->GetBrightestShadowingLightSource( pRenderable->GetRenderOrigin(), lightPos, lightBrightness, + r_shadowfromanyworldlight.GetBool() ) == false ) + { + // didn't find a light source at all, use default shadow direction + // TODO: Could switch to using blobby shadow in this case + lightPos.Init( FLT_MAX, FLT_MAX, FLT_MAX ); + } + } + + if ( shadow.m_LightPosLerp == FLT_MAX ) // first light pos ever, just init + { + shadow.m_CurrentLightPos = lightPos; + shadow.m_TargetLightPos = lightPos; + shadow.m_LightPosLerp = 1.0f; + } + else if ( shadow.m_LightPosLerp < 1.0f ) + { + // We're in the middle of a lerp from current to target light. Finish it. + shadow.m_LightPosLerp += gpGlobals->frametime * 1.0f/r_shadow_lightpos_lerptime.GetFloat(); + shadow.m_LightPosLerp = clamp( shadow.m_LightPosLerp, 0.0f, 1.0f ); + + Vector currLightPos( shadow.m_CurrentLightPos ); + Vector targetLightPos( shadow.m_TargetLightPos ); + if ( currLightPos.x == FLT_MAX ) + { + currLightPos = origin - 200.0f * GetShadowDirection(); + } + if ( targetLightPos.x == FLT_MAX ) + { + targetLightPos = origin - 200.0f * GetShadowDirection(); + } + + // lerp light pos + Vector v1 = origin - shadow.m_CurrentLightPos; + v1.NormalizeInPlace(); + + Vector v2 = origin - shadow.m_TargetLightPos; + v2.NormalizeInPlace(); + + if ( v1.Dot( v2 ) < 0.0f ) + { + // if change in shadow angle is more than 90 degrees, lerp over the renderable's top to avoid long sweeping shadows + Vector fakeOverheadLightPos( origin.x, origin.y, origin.z + 200.0f ); + if( shadow.m_LightPosLerp < 0.5f ) + { + lightPos = Lerp( 2.0f * shadow.m_LightPosLerp, currLightPos, fakeOverheadLightPos ); + } + else + { + lightPos = Lerp( 2.0f * shadow.m_LightPosLerp - 1.0f, fakeOverheadLightPos, targetLightPos ); + } + } + else + { + lightPos = Lerp( shadow.m_LightPosLerp, currLightPos, targetLightPos ); + } + + if ( shadow.m_LightPosLerp >= 1.0f ) + { + shadow.m_CurrentLightPos = shadow.m_TargetLightPos; + } + } + else if ( shadow.m_LightPosLerp >= 1.0f ) + { + // check if we have a new closest light position and start a new lerp + float flDistSq = ( lightPos - shadow.m_CurrentLightPos ).LengthSqr(); + + if ( flDistSq > 1.0f ) + { + // light position has changed, which means we got a new light source. Initiate a lerp + shadow.m_TargetLightPos = lightPos; + shadow.m_LightPosLerp = 0.0f; + } + + lightPos = shadow.m_CurrentLightPos; + } + + if ( lightPos.x == FLT_MAX ) + { + lightPos = origin - 200.0f * GetShadowDirection(); + } + + Vector vecResult( origin - lightPos ); + vecResult.NormalizeInPlace(); + + vecResult.z *= r_shadow_shortenfactor.GetFloat(); + vecResult.NormalizeInPlace(); + + shadow.m_ShadowDir = vecResult; + + if ( r_shadowfromworldlights_debug.GetBool() ) + { + NDebugOverlay::Line( lightPos, origin, 255, 255, 0, false, 0.0f ); + } +} //----------------------------------------------------------------------------- // Sets the shadow distance @@ -1733,6 +2236,7 @@ float CClientShadowMgr::GetBlobbyCutoffArea( ) const void CClientShadowMgr::SetFalloffBias( ClientShadowHandle_t handle, unsigned char ucBias ) { shadowmgr->SetFalloffBias( m_Shadows[handle].m_ShadowHandle, ucBias ); + m_Shadows[handle].m_FalloffBias = ucBias; } //----------------------------------------------------------------------------- @@ -1796,12 +2300,15 @@ void CClientShadowMgr::RenderShadowTexture( int w, int h ) //----------------------------------------------------------------------------- // Create/destroy a shadow //----------------------------------------------------------------------------- -ClientShadowHandle_t CClientShadowMgr::CreateProjectedTexture( ClientEntityHandle_t entity, int flags ) +ClientShadowHandle_t CClientShadowMgr::CreateProjectedTexture( ClientEntityHandle_t entity, int nEntIndex, int flags, CBitVec< MAX_SPLITSCREEN_PLAYERS > *pSplitScreenBits ) { // We need to know if it's a brush model for shadows - if( !( flags & SHADOW_FLAGS_FLASHLIGHT ) ) + if( ( flags & ( SHADOW_FLAGS_FLASHLIGHT | SHADOW_FLAGS_SIMPLE_PROJECTION ) ) == 0 ) { IClientRenderable *pRenderable = ClientEntityList().GetClientRenderableFromHandle( entity ); + if ( !pRenderable ) + return m_Shadows.InvalidIndex(); + int modelType = modelinfo->GetModelType( pRenderable->GetModel() ); if (modelType == mod_brush) { @@ -1815,11 +2322,29 @@ ClientShadowHandle_t CClientShadowMgr::CreateProjectedTexture( ClientEntityHandl shadow.m_ClientLeafShadowHandle = ClientLeafSystem()->AddShadow( h, flags ); shadow.m_Flags = flags; shadow.m_nRenderFrame = -1; + shadow.m_ShadowDir = GetShadowDirection(); shadow.m_LastOrigin.Init( FLT_MAX, FLT_MAX, FLT_MAX ); shadow.m_LastAngles.Init( FLT_MAX, FLT_MAX, FLT_MAX ); - Assert( ( ( shadow.m_Flags & SHADOW_FLAGS_FLASHLIGHT ) == 0 ) != + shadow.m_CurrentLightPos.Init( FLT_MAX, FLT_MAX, FLT_MAX ); + shadow.m_TargetLightPos.Init( FLT_MAX, FLT_MAX, FLT_MAX ); + shadow.m_LightPosLerp = FLT_MAX; + Assert( ( ( shadow.m_Flags & ( SHADOW_FLAGS_FLASHLIGHT | SHADOW_FLAGS_SIMPLE_PROJECTION ) ) == 0 ) != ( ( shadow.m_Flags & SHADOW_FLAGS_SHADOW ) == 0 ) ); + shadow.m_nLastUpdateFrame = 0; + + shadow.m_nSplitscreenOwner = -1; // No one owns this texture + if ( ( flags & ( SHADOW_FLAGS_FLASHLIGHT | SHADOW_FLAGS_SIMPLE_PROJECTION ) ) || ( flags & SHADOW_FLAGS_USE_DEPTH_TEXTURE ) ) + { + // The local player isn't always resolvable if this projected texture isn't the player's flashlight, so + // if the local player isn't resolvable, leave the splitscreen owner set to -1 so all splitscreen players render it + if ( engine->IsLocalPlayerResolvable() ) + { + // Set ownership to this player + shadow.m_nSplitscreenOwner = GET_ACTIVE_SPLITSCREEN_SLOT(); + } + } + // Set up the flags.... IMaterial* pShadowMaterial = m_SimpleShadow; IMaterial* pShadowModelMaterial = m_SimpleShadow; @@ -1831,18 +2356,22 @@ ClientShadowHandle_t CClientShadowMgr::CreateProjectedTexture( ClientEntityHandl pShadowMaterial = m_RenderShadow; pShadowModelMaterial = m_RenderModelShadow; - pShadowProxyData = (void*)(uintp)h; + pShadowProxyData = (void*)h; } - if( flags & SHADOW_FLAGS_USE_DEPTH_TEXTURE ) + if( ( flags & SHADOW_FLAGS_USE_DEPTH_TEXTURE ) || ( flags & ( SHADOW_FLAGS_FLASHLIGHT | SHADOW_FLAGS_SIMPLE_PROJECTION ) ) ) { - pShadowMaterial = m_RenderShadow; - pShadowModelMaterial = m_RenderModelShadow; - pShadowProxyData = (void*)(uintp)h; + pShadowMaterial = NULL; // these materials aren't used for shadow depth texture shadows. + pShadowModelMaterial = NULL; + pShadowProxyData = (void*)h; } int createShadowFlags; - if( flags & SHADOW_FLAGS_FLASHLIGHT ) + if( flags & SHADOW_FLAGS_SIMPLE_PROJECTION ) + { + createShadowFlags = SHADOW_SIMPLE_PROJECTION; + } + else if( flags & SHADOW_FLAGS_FLASHLIGHT ) { // don't use SHADOW_CACHE_VERTS with projective lightsources since we expect that they will change every frame. // FIXME: might want to make it cache optionally if it's an entity light that is static. @@ -1852,7 +2381,14 @@ ClientShadowHandle_t CClientShadowMgr::CreateProjectedTexture( ClientEntityHandl { createShadowFlags = SHADOW_CACHE_VERTS; } - shadow.m_ShadowHandle = shadowmgr->CreateShadowEx( pShadowMaterial, pShadowModelMaterial, pShadowProxyData, createShadowFlags ); + + shadow.m_ShadowHandle = shadowmgr->CreateShadowEx( pShadowMaterial, pShadowModelMaterial, pShadowProxyData, createShadowFlags, nEntIndex ); + + shadow.m_bUseSplitScreenBits = pSplitScreenBits ? true : false; + if ( pSplitScreenBits ) + { + shadow.m_SplitScreenBits.Copy( *pSplitScreenBits ); + } return h; } @@ -1867,25 +2403,31 @@ ClientShadowHandle_t CClientShadowMgr::CreateFlashlight( const FlashlightState_t shadowFlags |= SHADOW_FLAGS_USE_DEPTH_TEXTURE; } - ClientShadowHandle_t shadowHandle = CreateProjectedTexture( invalidHandle, shadowFlags ); + ClientShadowHandle_t shadowHandle = CreateProjectedTexture( invalidHandle, -1, shadowFlags, NULL ); UpdateFlashlightState( shadowHandle, lightState ); UpdateProjectedTexture( shadowHandle, true ); return shadowHandle; } - -ClientShadowHandle_t CClientShadowMgr::CreateShadow( ClientEntityHandle_t entity, int flags ) + +ClientShadowHandle_t CClientShadowMgr::CreateShadow( ClientEntityHandle_t entity, int nEntIndex, int flags, CBitVec< MAX_SPLITSCREEN_PLAYERS > *pSplitScreenBits /*= NULL*/ ) { // We don't really need a model entity handle for a projective light source, so use an invalid one. flags &= ~SHADOW_FLAGS_PROJECTED_TEXTURE_TYPE_MASK; flags |= SHADOW_FLAGS_SHADOW | SHADOW_FLAGS_TEXTURE_DIRTY; - ClientShadowHandle_t shadowHandle = CreateProjectedTexture( entity, flags ); + ClientShadowHandle_t shadowHandle = CreateProjectedTexture( entity, nEntIndex, flags, pSplitScreenBits ); IClientRenderable *pRenderable = ClientEntityList().GetClientRenderableFromHandle( entity ); if ( pRenderable ) { Assert( !pRenderable->IsShadowDirty( ) ); pRenderable->MarkShadowDirty( true ); + + CClientAlphaProperty *pAlphaProperty = static_cast( pRenderable->GetIClientUnknown()->GetClientAlphaProperty() ); + if ( pAlphaProperty ) + { + pAlphaProperty->SetShadowHandle( shadowHandle ); + } } // NOTE: We *have* to call the version that takes a shadow handle @@ -1902,16 +2444,79 @@ void CClientShadowMgr::UpdateFlashlightState( ClientShadowHandle_t shadowHandle, { VPROF_BUDGET( "CClientShadowMgr::UpdateFlashlightState", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING ); - BuildPerspectiveWorldToFlashlightMatrix( m_Shadows[shadowHandle].m_WorldToShadow, flashlightState ); - - shadowmgr->UpdateFlashlightState( m_Shadows[shadowHandle].m_ShadowHandle, flashlightState ); -} - + if( flashlightState.m_bEnableShadows && r_flashlightdepthtexture.GetBool() ) + { + m_Shadows[shadowHandle].m_Flags |= SHADOW_FLAGS_USE_DEPTH_TEXTURE; + } + else + { + m_Shadows[shadowHandle].m_Flags &= ~SHADOW_FLAGS_USE_DEPTH_TEXTURE; + } + + if ( flashlightState.m_bOrtho ) + { + BuildOrthoWorldToFlashlightMatrix( m_Shadows[shadowHandle].m_WorldToShadow, flashlightState ); + } + else + { + BuildPerspectiveWorldToFlashlightMatrix( m_Shadows[shadowHandle].m_WorldToShadow, flashlightState ); + } + + shadowmgr->UpdateFlashlightState( m_Shadows[shadowHandle].m_ShadowHandle, flashlightState ); +} + void CClientShadowMgr::DestroyFlashlight( ClientShadowHandle_t shadowHandle ) { DestroyShadow( shadowHandle ); } + +ClientShadowHandle_t CClientShadowMgr::CreateProjection( const FlashlightState_t &lightState ) +{ +// return CreateFlashlight(lightState); + + // We don't really need a model entity handle for a projective light source, so use an invalid one. + static ClientEntityHandle_t invalidHandle = INVALID_CLIENTENTITY_HANDLE; + + int shadowFlags = SHADOW_FLAGS_SIMPLE_PROJECTION; + + ClientShadowHandle_t shadowHandle = CreateProjectedTexture( invalidHandle, -1, shadowFlags, NULL ); + + UpdateFlashlightState( shadowHandle, lightState ); + UpdateProjectedTexture( shadowHandle, true ); + + return shadowHandle; +} + + +//----------------------------------------------------------------------------- +// Updates the flashlight direction and re-computes surfaces it should lie on +//----------------------------------------------------------------------------- +void CClientShadowMgr::UpdateProjectionState( ClientShadowHandle_t shadowHandle, const FlashlightState_t &flashlightState ) +{ +// UpdateFlashlightState(shadowHandle, flashlightState ); +// return; + + VPROF_BUDGET( "CClientShadowMgr::UpdateProjectionState", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING ); + + if ( flashlightState.m_bOrtho ) + { + BuildOrthoWorldToFlashlightMatrix( m_Shadows[shadowHandle].m_WorldToShadow, flashlightState ); + } + else + { + BuildPerspectiveWorldToFlashlightMatrix( m_Shadows[shadowHandle].m_WorldToShadow, flashlightState ); + } + + shadowmgr->UpdateFlashlightState( m_Shadows[shadowHandle].m_ShadowHandle, flashlightState ); +} + +void CClientShadowMgr::DestroyProjection( ClientShadowHandle_t shadowHandle ) +{ + DestroyShadow( shadowHandle ); +} + + //----------------------------------------------------------------------------- // Remove a shadow from the dirty list //----------------------------------------------------------------------------- @@ -1928,6 +2533,17 @@ void CClientShadowMgr::RemoveShadowFromDirtyList( ClientShadowHandle_t handle ) } m_DirtyShadows.RemoveAt( idx ); } + idx = m_DirtyShadowsLeftOver.Find( handle ); + if ( idx != m_DirtyShadowsLeftOver.InvalidIndex() ) + { + // Clean up the shadow update bit. + IClientRenderable *pRenderable = ClientEntityList().GetClientRenderableFromHandle( m_Shadows[handle].m_Entity ); + if ( pRenderable ) + { + pRenderable->MarkShadowDirty( false ); + } + m_DirtyShadowsLeftOver.RemoveAt( idx ); + } } @@ -1936,15 +2552,68 @@ void CClientShadowMgr::RemoveShadowFromDirtyList( ClientShadowHandle_t handle ) //----------------------------------------------------------------------------- void CClientShadowMgr::DestroyShadow( ClientShadowHandle_t handle ) { + if ( m_bUpdatingDirtyShadows ) + { + // While we're updating dirty shadows, destroying a shadow can cause an RB-Tree we're currently iterating to be changed. + // This can cause tree corruption resulting in infinite loops or crashes. Instead, we queue the shadow handle for deletion and + // service the queue after we're done updating. + QueueShadowForDestruction( handle ); + return; + } + Assert( m_Shadows.IsValidIndex(handle) ); RemoveShadowFromDirtyList( handle ); + IClientRenderable *pRenderable = ClientEntityList().GetClientRenderableFromHandle( m_Shadows[handle].m_Entity ); + if ( pRenderable ) + { + CClientAlphaProperty *pAlphaProperty = static_cast( pRenderable->GetIClientUnknown()->GetClientAlphaProperty() ); + if ( pAlphaProperty ) + { + pAlphaProperty->SetShadowHandle( CLIENTSHADOW_INVALID_HANDLE ); + } + } shadowmgr->DestroyShadow( m_Shadows[handle].m_ShadowHandle ); - ClientLeafSystem()->RemoveShadow( m_Shadows[handle].m_ClientLeafShadowHandle ); + if ( m_Shadows[handle].m_ClientLeafShadowHandle != CLIENT_LEAF_SHADOW_INVALID_HANDLE ) + { + ClientLeafSystem()->RemoveShadow( m_Shadows[handle].m_ClientLeafShadowHandle ); + } CleanUpRenderToTextureShadow( handle ); m_Shadows.Remove(handle); } +//----------------------------------------------------------------------------- +// Queues a shadow for removal +//----------------------------------------------------------------------------- +void CClientShadowMgr::QueueShadowForDestruction( ClientShadowHandle_t handle ) +{ + // this function should be called infrequently (it is a failsafe) + // so check to make sure it's not queued to delete twice + if ( m_shadowsToDestroy.IsValidIndex( m_shadowsToDestroy.Find(handle) ) ) + { + AssertMsg1( false, "Tried to queue shadow %d for deletion twice!\n", (int)(handle) ); + } + else + { + m_shadowsToDestroy.AddToTail( handle ); + } +} + + +//----------------------------------------------------------------------------- +// Removes queued shadows +//----------------------------------------------------------------------------- +void CClientShadowMgr::DestroyQueuedShadows() +{ + Assert( !m_bUpdatingDirtyShadows ); + + for ( int i = 0; i < m_shadowsToDestroy.Count(); i++ ) + { + DestroyShadow( m_shadowsToDestroy[i] ); + } + m_shadowsToDestroy.RemoveAll(); +} + //----------------------------------------------------------------------------- // Build the worldtotexture matrix //----------------------------------------------------------------------------- @@ -2013,6 +2682,38 @@ void CClientShadowMgr::BuildPerspectiveWorldToFlashlightMatrix( VMatrix& matWorl MatrixMultiply( matPerspective, matWorldToShadowView, matWorldToShadow ); } +void CClientShadowMgr::BuildOrthoWorldToFlashlightMatrix( VMatrix& matWorldToShadow, const FlashlightState_t &flashlightState ) +{ + VPROF_BUDGET( "CClientShadowMgr::BuildPerspectiveWorldToFlashlightMatrix", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING ); + + // Buildworld to shadow matrix, then perspective projection and concatenate + VMatrix matWorldToShadowView, matPerspective; + BuildWorldToShadowMatrix( matWorldToShadowView, flashlightState.m_vecLightOrigin, + flashlightState.m_quatOrientation ); + + MatrixBuildOrtho( matPerspective, + flashlightState.m_fOrthoLeft, flashlightState.m_fOrthoTop, flashlightState.m_fOrthoRight, flashlightState.m_fOrthoBottom, + flashlightState.m_NearZ, flashlightState.m_FarZ ); + + // Shift it z/y to 0 to -2 space + VMatrix addW; + addW.Identity(); + addW[0][3] = -1.0f; + addW[1][3] = -1.0f; + addW[2][3] = 0.0f; + MatrixMultiply( addW, matPerspective, matPerspective ); + + // Flip x/y to positive 0 to 1... flip z to negative + VMatrix scaleHalf; + scaleHalf.Identity(); + scaleHalf[0][0] = -0.5f; + scaleHalf[1][1] = -0.5f; + scaleHalf[2][2] = -1.0f; + MatrixMultiply( scaleHalf, matPerspective, matPerspective ); + + MatrixMultiply( matPerspective, matWorldToShadowView, matWorldToShadow ); +} + //----------------------------------------------------------------------------- // Compute the shadow origin and attenuation start distance //----------------------------------------------------------------------------- @@ -2153,12 +2854,14 @@ static void BuildOrthoWorldToShadowMatrix( VMatrix& worldToShadow, //----------------------------------------------------------------------------- void CClientShadowMgr::ClearExtraClipPlanes( ClientShadowHandle_t h ) { - shadowmgr->ClearExtraClipPlanes( m_Shadows[h].m_ShadowHandle ); + if ( !r_shadow_deferred.GetBool() ) + shadowmgr->ClearExtraClipPlanes( m_Shadows[h].m_ShadowHandle ); } void CClientShadowMgr::AddExtraClipPlane( ClientShadowHandle_t h, const Vector& normal, float dist ) { - shadowmgr->AddExtraClipPlane( m_Shadows[h].m_ShadowHandle, normal, dist ); + if ( !r_shadow_deferred.GetBool() ) + shadowmgr->AddExtraClipPlane( m_Shadows[h].m_ShadowHandle, normal, dist ); } @@ -2244,12 +2947,29 @@ inline ShadowType_t CClientShadowMgr::GetActualShadowCastType( IClientRenderable class CShadowLeafEnum : public ISpatialLeafEnumerator { public: - bool EnumerateLeaf( int leaf, intp context ) + bool EnumerateLeaf( int leaf, int context ) { m_LeafList.AddToTail( leaf ); return true; } + void ExtractUnconnectedLeaves( const Vector &vecOrigin ) + { + VPROF_BUDGET( "ExtractUnconnectedLeaves", "ExtractUnconnectedLeaves" ); + int nCount = m_LeafList.Count(); + bool *pIsConnected = (bool*)stackalloc( nCount * sizeof(bool) ); + engine->ComputeLeavesConnected( vecOrigin, nCount, m_LeafList.Base(), pIsConnected ); + int nCountRemoved = 0; + for ( int i = nCount; --i >= 0; ) + { + if ( !pIsConnected[i] ) + { + ++nCountRemoved; + m_LeafList.FastRemove( i ); + } + } + } + CUtlVectorFixedGrowable< int, 512 > m_LeafList; }; @@ -2286,7 +3006,7 @@ void CClientShadowMgr::BuildOrthoShadow( IClientRenderable* pRenderable, AngleVectors( pRenderable->GetRenderAngles(), &vec[0], &vec[1], &vec[2] ); vec[1] *= -1.0f; - Vector vecShadowDir = GetShadowDirection( pRenderable ); + Vector vecShadowDir = GetShadowDirection( handle ); // Project the shadow casting direction into the space of the object Vector localShadowDir; @@ -2350,10 +3070,13 @@ void CClientShadowMgr::BuildOrthoShadow( IClientRenderable* pRenderable, // NOTE: We gotta use the general matrix because xvec and yvec aren't perp VMatrix matWorldToShadow, matWorldToTexture; - BuildGeneralWorldToShadowMatrix( m_Shadows[handle].m_WorldToShadow, worldOrigin, vecShadowDir, xvec, yvec ); + // negate xvec so that the matrix will have the same handedness as for an RTT shadow + BuildGeneralWorldToShadowMatrix( m_Shadows[handle].m_WorldToShadow, worldOrigin, vecShadowDir, -xvec, yvec ); BuildWorldToTextureMatrix( m_Shadows[handle].m_WorldToShadow, size, matWorldToTexture ); Vector2DCopy( size, m_Shadows[handle].m_WorldSize ); - + + MatrixCopy( matWorldToTexture, m_Shadows[handle].m_WorldToTexture ); + // Compute the falloff attenuation // Area computation isn't exact since xvec is not perp to yvec, but close enough // float shadowArea = size.x * size.y; @@ -2367,8 +3090,15 @@ void CClientShadowMgr::BuildOrthoShadow( IClientRenderable* pRenderable, int nCount = leafList.m_LeafList.Count(); const int *pLeafList = leafList.m_LeafList.Base(); - shadowmgr->ProjectShadow( m_Shadows[handle].m_ShadowHandle, worldOrigin, - vecShadowDir, matWorldToTexture, size, nCount, pLeafList, maxHeight, falloffStart, MAX_FALLOFF_AMOUNT, pRenderable->GetRenderOrigin() ); + if ( !r_shadow_deferred.GetBool() ) + { + shadowmgr->ProjectShadow( m_Shadows[handle].m_ShadowHandle, worldOrigin, + vecShadowDir, matWorldToTexture, size, nCount, pLeafList, maxHeight, falloffStart, MAX_FALLOFF_AMOUNT, pRenderable->GetRenderOrigin() ); + } + + m_Shadows[handle].m_MaxDist = maxHeight; + m_Shadows[handle].m_FalloffStart = falloffStart; + // Compute extra clip planes to prevent poke-thru // FIXME!!!!!!!!!!!!!! Removing this for now since it seems to mess up the blobby shadows. @@ -2469,7 +3199,7 @@ void CClientShadowMgr::BuildRenderToTextureShadow( IClientRenderable* pRenderabl AngleVectors( pRenderable->GetRenderAngles(), &vec[0], &vec[1], &vec[2] ); vec[1] *= -1.0f; - Vector vecShadowDir = GetShadowDirection( pRenderable ); + Vector vecShadowDir = GetShadowDirection( handle ); // Debugging aid // const model_t *pModel = pRenderable->GetModel(); @@ -2533,6 +3263,8 @@ void CClientShadowMgr::BuildRenderToTextureShadow( IClientRenderable* pRenderabl BuildWorldToTextureMatrix( m_Shadows[handle].m_WorldToShadow, size, matWorldToTexture ); Vector2DCopy( size, m_Shadows[handle].m_WorldSize ); + MatrixCopy( matWorldToTexture, m_Shadows[handle].m_WorldToTexture ); + // Compute the falloff attenuation // Area computation isn't exact since xvec is not perp to yvec, but close enough // Extra factor of 4 in the maxHeight due to the size being half as big @@ -2547,183 +3279,792 @@ void CClientShadowMgr::BuildRenderToTextureShadow( IClientRenderable* pRenderabl int nCount = leafList.m_LeafList.Count(); const int *pLeafList = leafList.m_LeafList.Base(); - shadowmgr->ProjectShadow( m_Shadows[handle].m_ShadowHandle, worldOrigin, - vecShadowDir, matWorldToTexture, size, nCount, pLeafList, maxHeight, falloffStart, MAX_FALLOFF_AMOUNT, pRenderable->GetRenderOrigin() ); + if ( !r_shadow_deferred.GetBool() ) + { + shadowmgr->ProjectShadow( m_Shadows[handle].m_ShadowHandle, worldOrigin, + vecShadowDir, matWorldToTexture, size, nCount, pLeafList, maxHeight, falloffStart, MAX_FALLOFF_AMOUNT, pRenderable->GetRenderOrigin() ); - // Compute extra clip planes to prevent poke-thru - ComputeExtraClipPlanes( pRenderable, handle, vec, mins, maxs, localShadowDir ); + // Compute extra clip planes to prevent poke-thru + ComputeExtraClipPlanes( pRenderable, handle, vec, mins, maxs, localShadowDir ); + } + + m_Shadows[handle].m_MaxDist = maxHeight; + m_Shadows[handle].m_FalloffStart = falloffStart; // Add the shadow to the client leaf system so it correctly marks // leafs as being affected by a particular shadow ClientLeafSystem()->ProjectShadow( m_Shadows[handle].m_ClientLeafShadowHandle, nCount, pLeafList ); } -static void LineDrawHelper( const Vector &startShadowSpace, const Vector &endShadowSpace, - const VMatrix &shadowToWorld, unsigned char r = 255, unsigned char g = 255, - unsigned char b = 255 ) +static void LineDrawHelperProjective( const Vector &startShadowSpace, const Vector &endShadowSpace, + const VMatrix &shadowToWorld, unsigned char r = 255, unsigned char g = 255, unsigned char b = 255 ) { Vector startWorldSpace, endWorldSpace; Vector3DMultiplyPositionProjective( shadowToWorld, startShadowSpace, startWorldSpace ); Vector3DMultiplyPositionProjective( shadowToWorld, endShadowSpace, endWorldSpace ); - debugoverlay->AddLineOverlay( startWorldSpace + Vector( 0.0f, 0.0f, 1.0f ), - endWorldSpace + Vector( 0.0f, 0.0f, 1.0f ), r, g, b, false, -1 ); + debugoverlay->AddLineOverlay( startWorldSpace, endWorldSpace, r, g, b, false, -1 ); } -static void DebugDrawFrustum( const Vector &vOrigin, const VMatrix &matWorldToFlashlight ) + +static void LineDrawHelper( const Vector &start, const Vector &end, + const VMatrix &viewMatrixInverse, unsigned char r = 255, unsigned char g = 255, unsigned char b = 255 ) { - VMatrix flashlightToWorld; - MatrixInverseGeneral( matWorldToFlashlight, flashlightToWorld ); - - // Draw boundaries of frustum - LineDrawHelper( Vector( 0.0f, 0.0f, 0.0f ), Vector( 0.0f, 0.0f, 1.0f ), flashlightToWorld, 255, 255, 255 ); - LineDrawHelper( Vector( 0.0f, 0.0f, 1.0f ), Vector( 0.0f, 1.0f, 1.0f ), flashlightToWorld, 255, 255, 255 ); - LineDrawHelper( Vector( 0.0f, 1.0f, 1.0f ), Vector( 0.0f, 1.0f, 0.0f ), flashlightToWorld, 255, 255, 255 ); - LineDrawHelper( Vector( 0.0f, 1.0f, 0.0f ), Vector( 0.0f, 0.0f, 0.0f ), flashlightToWorld, 255, 255, 255 ); - LineDrawHelper( Vector( 1.0f, 0.0f, 0.0f ), Vector( 1.0f, 0.0f, 1.0f ), flashlightToWorld, 255, 255, 255 ); - LineDrawHelper( Vector( 1.0f, 0.0f, 1.0f ), Vector( 1.0f, 1.0f, 1.0f ), flashlightToWorld, 255, 255, 255 ); - LineDrawHelper( Vector( 1.0f, 1.0f, 1.0f ), Vector( 1.0f, 1.0f, 0.0f ), flashlightToWorld, 255, 255, 255 ); - LineDrawHelper( Vector( 1.0f, 1.0f, 0.0f ), Vector( 1.0f, 0.0f, 0.0f ), flashlightToWorld, 255, 255, 255 ); - LineDrawHelper( Vector( 0.0f, 0.0f, 0.0f ), Vector( 1.0f, 0.0f, 0.0f ), flashlightToWorld, 255, 255, 255 ); - LineDrawHelper( Vector( 0.0f, 0.0f, 1.0f ), Vector( 1.0f, 0.0f, 1.0f ), flashlightToWorld, 255, 255, 255 ); - LineDrawHelper( Vector( 0.0f, 1.0f, 1.0f ), Vector( 1.0f, 1.0f, 1.0f ), flashlightToWorld, 255, 255, 255 ); - LineDrawHelper( Vector( 0.0f, 1.0f, 0.0f ), Vector( 1.0f, 1.0f, 0.0f ), flashlightToWorld, 255, 255, 255 ); + Vector startWorldSpace, endWorldSpace; + Vector3DMultiplyPosition( viewMatrixInverse, start, startWorldSpace ); + Vector3DMultiplyPosition( viewMatrixInverse, end, endWorldSpace ); - // Draw RGB triad at front plane - LineDrawHelper( Vector( 0.5f, 0.5f, 0.0f ), Vector( 1.0f, 0.5f, 0.0f ), flashlightToWorld, 255, 0, 0 ); - LineDrawHelper( Vector( 0.5f, 0.5f, 0.0f ), Vector( 0.5f, 1.0f, 0.0f ), flashlightToWorld, 0, 255, 0 ); - LineDrawHelper( Vector( 0.5f, 0.5f, 0.0f ), Vector( 0.5f, 0.5f, 0.35f ), flashlightToWorld, 0, 0, 255 ); + debugoverlay->AddLineOverlay( startWorldSpace, endWorldSpace, r, g, b, false, -1 ); } -//----------------------------------------------------------------------------- -// Builds a list of leaves inside the flashlight volume -//----------------------------------------------------------------------------- -static void BuildFlashlightLeafList( CShadowLeafEnum *pEnum, const VMatrix &worldToShadow ) -{ - // Use an AABB around the frustum to enumerate leaves. - Vector mins, maxs; - CalculateAABBFromProjectionMatrix( worldToShadow, &mins, &maxs ); - ISpatialQuery* pQuery = engine->GetBSPTreeQuery(); - pQuery->EnumerateLeavesInBox( mins, maxs, pEnum, 0 ); -} +// We're going to sweep out an inner and outer superellipse. Each superellipse has the equation: +// +// 2 2 +// - - +// ( x )d ( y )d +// (---) + (---) = 1 +// ( a ) ( b ) +// +// where, +// d is what we're calling m_fRoundness +// +// The inner superellipse uses a = m_fWidth and b = m_fHeight +// The outer superellipse uses a = (m_fWidth + m_fWedge) and b = (m_fHeight + m_fHedge) +// + +// Controls density of wireframe uberlight +#define NUM_SUPER_ELLIPSE_POINTS 192 +#define CONNECTOR_FREQ 24 -void CClientShadowMgr::BuildFlashlight( ClientShadowHandle_t handle ) +void CClientShadowMgr::DrawUberlightRig( const Vector &vOrigin, const VMatrix &matWorldToFlashlight, FlashlightState_t state ) { - // For the 360, we just draw flashlights with the main geometry - // and bypass the entire shadow casting system. - ClientShadow_t &shadow = m_Shadows[handle]; - if ( IsX360() || r_flashlight_version2.GetInt() ) - { - // This will update the matrices, but not do work to add the flashlight to surfaces - shadowmgr->ProjectFlashlight( shadow.m_ShadowHandle, shadow.m_WorldToShadow, 0, NULL ); - return; - } + int i; + float fXNear, fXFar, fYNear, fYFar, fXNearEdge, fXFarEdge, fYNearEdge, fYFarEdge, m; + UberlightState_t uber = state.m_uberlightState; + VMatrix viewMatrixInverse, viewMatrix; - VPROF_BUDGET( "CClientShadowMgr::BuildFlashlight", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING ); + // A set of scratch points on the +x +y quadrants of the near and far ends of the swept superellipse wireframe + Vector vecNearInnerPoints[(NUM_SUPER_ELLIPSE_POINTS / 4) + 1]; // Inner points for four superellipses + Vector vecFarInnerPoints[(NUM_SUPER_ELLIPSE_POINTS / 4) + 1]; + Vector vecNearEdgeInnerPoints[(NUM_SUPER_ELLIPSE_POINTS / 4) + 1]; + Vector vecFarEdgeInnerPoints[(NUM_SUPER_ELLIPSE_POINTS / 4) + 1]; - bool bLightModels = r_flashlightmodels.GetBool(); - bool bLightSpecificEntity = shadow.m_hTargetEntity.Get() != NULL; - bool bLightWorld = ( shadow.m_Flags & SHADOW_FLAGS_LIGHT_WORLD ) != 0; - int nCount = 0; - const int *pLeafList = 0; + Vector vecNearOuterPoints[(NUM_SUPER_ELLIPSE_POINTS / 4) + 1]; // Outer points for four superellipses + Vector vecFarOuterPoints[(NUM_SUPER_ELLIPSE_POINTS / 4) + 1]; + Vector vecNearEdgeOuterPoints[(NUM_SUPER_ELLIPSE_POINTS / 4) + 1]; + Vector vecFarEdgeOuterPoints[(NUM_SUPER_ELLIPSE_POINTS / 4) + 1]; - CShadowLeafEnum leafList; - if ( bLightWorld || ( bLightModels && !bLightSpecificEntity ) ) - { - BuildFlashlightLeafList( &leafList, shadow.m_WorldToShadow ); - nCount = leafList.m_LeafList.Count(); - pLeafList = leafList.m_LeafList.Base(); - } + // Clock hand which sweeps out a full circle + float fTheta = 0; + float fThetaIncrement = (2.0f * 3.14159) / ((float)NUM_SUPER_ELLIPSE_POINTS); - if( bLightWorld ) - { - shadowmgr->ProjectFlashlight( shadow.m_ShadowHandle, shadow.m_WorldToShadow, nCount, pLeafList ); - } - else + // precompute the 2/d exponent + float r = 2.0f / uber.m_fRoundness; + + // Initialize arrays of points in light's local space defining +x +y quadrants of extruded superellipses (including x==0 and y==0 vertices) + for ( i = 0; i<(NUM_SUPER_ELLIPSE_POINTS / 4) + 1; i++ ) { - // This should clear all models and surfaces from this shadow - shadowmgr->EnableShadow( shadow.m_ShadowHandle, false ); - shadowmgr->EnableShadow( shadow.m_ShadowHandle, true ); - } + if ( i == 0 ) // If this is the 0th vertex + { + fXFar = uber.m_fWidth * uber.m_fCutOff; // compute near and far x's + fXNear = uber.m_fWidth * uber.m_fCutOn; + fXFarEdge = uber.m_fWidth * (uber.m_fCutOff + uber.m_fFarEdge); + fXNearEdge = uber.m_fWidth * (uber.m_fCutOn - uber.m_fNearEdge); - if ( !bLightModels ) - return; + fYFar = fYNear = fYFarEdge = fYNearEdge =0; // y's are zero + } + else if ( i == (NUM_SUPER_ELLIPSE_POINTS / 4) ) // If this is the vertex on the y axis, avoid numerical problems + { + fXFar = fXNear = fXFarEdge = fXNearEdge = 0; // x's are zero - if ( !bLightSpecificEntity ) - { - // Add the shadow to the client leaf system so it correctly marks - // leafs as being affected by a particular shadow - ClientLeafSystem()->ProjectFlashlight( shadow.m_ClientLeafShadowHandle, nCount, pLeafList ); - return; - } + fYFar = uber.m_fHeight * uber.m_fCutOff; // compute near and far y's + fYNear = uber.m_fHeight * uber.m_fCutOn; + fYFarEdge = uber.m_fHeight * (uber.m_fCutOff + uber.m_fFarEdge); + fYNearEdge = uber.m_fHeight * (uber.m_fCutOn - uber.m_fNearEdge); + } + else + { + m = sinf(fTheta) / cosf(fTheta); // compute slope of line from origin - // We know what we are focused on, so just add the shadow directly to that receiver - Assert( shadow.m_hTargetEntity->GetModel() ); + // Solve for inner x's (intersect line of slope m with inner superellipses) + fXFar = (powf(powf(1.0f/uber.m_fWidth,r) + powf(m/uber.m_fHeight,r), -1.0f/r) * uber.m_fCutOff); + fXNear = (powf(powf(1.0f/uber.m_fWidth,r) + powf(m/uber.m_fHeight,r), -1.0f/r) * uber.m_fCutOn); - C_BaseEntity *pChild = shadow.m_hTargetEntity->FirstMoveChild(); - while( pChild ) - { - int modelType = modelinfo->GetModelType( pChild->GetModel() ); - if (modelType == mod_brush) + fXFarEdge = (powf(powf(1.0f/uber.m_fWidth,r) + powf(m/uber.m_fHeight,r), -1.0f/r) * (uber.m_fCutOff + uber.m_fFarEdge)); + fXNearEdge = (powf(powf(1.0f/uber.m_fWidth,r) + powf(m/uber.m_fHeight,r), -1.0f/r) * (uber.m_fCutOn - uber.m_fNearEdge)); + + // Solve for inner y's using line equations + fYFar = m * fXFar; + fYNear = m * fXNear; + fYFarEdge = m * fXFarEdge; + fYNearEdge = m * fXNearEdge; + } + + // World to Light's View matrix + BuildWorldToShadowMatrix( viewMatrix, state.m_vecLightOrigin, state.m_quatOrientation ); + viewMatrixInverse = viewMatrix.InverseTR(); + + // Store world space positions in array + vecFarInnerPoints[i] = Vector( fXFar, fYFar, uber.m_fCutOff ); + vecNearInnerPoints[i] = Vector( fXNear, fYNear, uber.m_fCutOn ); + vecFarEdgeInnerPoints[i] = Vector( fXFarEdge, fYFarEdge, uber.m_fCutOff + uber.m_fFarEdge ); + vecNearEdgeInnerPoints[i] = Vector( fXNearEdge, fYNearEdge, uber.m_fCutOn - uber.m_fNearEdge ); + + if ( i == 0 ) // If this is the 0th vertex { - AddShadowToReceiver( handle, pChild, SHADOW_RECEIVER_BRUSH_MODEL ); + fXFar = (uber.m_fWidth + uber.m_fWedge) * uber.m_fCutOff; // compute near and far x's + fXNear = (uber.m_fWidth + uber.m_fWedge) * uber.m_fCutOn; + fXFarEdge = (uber.m_fWidth + uber.m_fWedge) * (uber.m_fCutOff + uber.m_fFarEdge); + fXNearEdge = (uber.m_fWidth + uber.m_fWedge) * (uber.m_fCutOn - uber.m_fNearEdge); + + fYFar = fYNear = fYFarEdge = fYNearEdge = 0; // y's are zero } - else if ( modelType == mod_studio ) + else if ( i == (NUM_SUPER_ELLIPSE_POINTS / 4) ) // If this is the vertex on the y axis, avoid numerical problems { - AddShadowToReceiver( handle, pChild, SHADOW_RECEIVER_STUDIO_MODEL ); + fXFar = fXNear = fXFarEdge = fXNearEdge = 0; // x's are zero + + fYFar = (uber.m_fHeight + uber.m_fHedge) * uber.m_fCutOff; // compute near and far y's + fYNear = (uber.m_fHeight + uber.m_fHedge) * uber.m_fCutOn; + fYFarEdge = (uber.m_fHeight + uber.m_fHedge) * (uber.m_fCutOff + uber.m_fFarEdge); + fYNearEdge = (uber.m_fHeight + uber.m_fHedge) * (uber.m_fCutOn - uber.m_fNearEdge); } + else + { + m = sinf(fTheta) / cosf(fTheta); // compute slope of line from origin - pChild = pChild->NextMovePeer(); - } + // Solve for inner x's (intersect line of slope m with inner superellipses) + fXFar = (powf(powf(1.0f/(uber.m_fWidth + uber.m_fWedge),r) + powf(m/(uber.m_fHeight + uber.m_fHedge),r), -1.0f/r) * uber.m_fCutOff); + fXNear = (powf(powf(1.0f/(uber.m_fWidth + uber.m_fWedge),r) + powf(m/(uber.m_fHeight + uber.m_fHedge),r), -1.0f/r) * uber.m_fCutOn); - int modelType = modelinfo->GetModelType( shadow.m_hTargetEntity->GetModel() ); - if (modelType == mod_brush) - { - AddShadowToReceiver( handle, shadow.m_hTargetEntity, SHADOW_RECEIVER_BRUSH_MODEL ); - } - else if ( modelType == mod_studio ) - { - AddShadowToReceiver( handle, shadow.m_hTargetEntity, SHADOW_RECEIVER_STUDIO_MODEL ); - } -} + fXFarEdge = (powf(powf(1.0f/(uber.m_fWidth + uber.m_fWedge),r) + powf(m/(uber.m_fHeight + uber.m_fHedge),r), -1.0f/r) * (uber.m_fCutOff+ uber.m_fFarEdge)); + fXNearEdge = (powf(powf(1.0f/(uber.m_fWidth + uber.m_fWedge),r) + powf(m/(uber.m_fHeight + uber.m_fHedge),r), -1.0f/r) * (uber.m_fCutOn - uber.m_fNearEdge)); + // Solve for inner y's using line equations + fYFar = m * fXFar; + fYNear = m * fXNear; + fYFarEdge = m * fXFarEdge; + fYNearEdge = m * fXNearEdge; + } -//----------------------------------------------------------------------------- -// Adds the child bounds to the bounding box -//----------------------------------------------------------------------------- -void CClientShadowMgr::AddChildBounds( matrix3x4_t &matWorldToBBox, IClientRenderable* pParent, Vector &vecMins, Vector &vecMaxs ) -{ - Vector vecChildMins, vecChildMaxs; - Vector vecNewChildMins, vecNewChildMaxs; - matrix3x4_t childToBBox; + // Store in array + vecFarOuterPoints[i] = Vector( fXFar, fYFar, uber.m_fCutOff ); + vecNearOuterPoints[i] = Vector( fXNear, fYNear, uber.m_fCutOn ); + vecFarEdgeOuterPoints[i] = Vector( fXFarEdge, fYFarEdge, uber.m_fCutOff + uber.m_fFarEdge ); + vecNearEdgeOuterPoints[i] = Vector( fXNearEdge, fYNearEdge, uber.m_fCutOn - uber.m_fNearEdge ); - IClientRenderable *pChild = pParent->FirstShadowChild(); - while( pChild ) + fTheta += fThetaIncrement; + } + + Vector preVector, curVector; + + // Near inner superellipse + for ( i=0; iGetShadowRenderBounds( vecChildMins, vecChildMaxs, SHADOWS_RENDER_TO_TEXTURE ); - ConcatTransforms( matWorldToBBox, pChild->RenderableToWorldTransform(), childToBBox ); - TransformAABB( childToBBox, vecChildMins, vecChildMaxs, vecNewChildMins, vecNewChildMaxs ); - VectorMin( vecMins, vecNewChildMins, vecMins ); - VectorMax( vecMaxs, vecNewChildMaxs, vecMaxs ); + curVector = vecNearInnerPoints[i]; + curVector.x += uber.m_fShearx * curVector.z; + curVector.y += uber.m_fSheary * curVector.z; + } + else if ( i <= (NUM_SUPER_ELLIPSE_POINTS / 2)) // -x +y quadrant, negate x when copying from scratch array + { + curVector = vecNearInnerPoints[(NUM_SUPER_ELLIPSE_POINTS / 2)-i]; + curVector.x *= -1; + curVector.x += uber.m_fShearx * curVector.z; + curVector.y += uber.m_fSheary * curVector.z; + } + else if ( i <= (3*NUM_SUPER_ELLIPSE_POINTS / 4)) // -x -y quadrant, negate when copying from scratch array + { + curVector = vecNearInnerPoints[i-(NUM_SUPER_ELLIPSE_POINTS / 2)]; + curVector.x *= -1; + curVector.y *= -1; + curVector.x += uber.m_fShearx * curVector.z; + curVector.y += uber.m_fSheary * curVector.z; + } + else // +x -y quadrant, negate y when copying from scratch array + { + curVector = vecNearInnerPoints[NUM_SUPER_ELLIPSE_POINTS-i]; + curVector.y *= -1; + curVector.x += uber.m_fShearx * curVector.z; + curVector.y += uber.m_fSheary * curVector.z; } - AddChildBounds( matWorldToBBox, pChild, vecMins, vecMaxs ); - pChild = pChild->NextShadowPeer(); + if ( i != 0 ) + { + LineDrawHelper( preVector, curVector, viewMatrixInverse, 255, 10, 10 ); + } + + preVector = curVector; } -} + LineDrawHelper( preVector, vecNearInnerPoints[0], viewMatrixInverse, 255, 10, 10 ); -//----------------------------------------------------------------------------- -// Compute a bounds for the entity + children -//----------------------------------------------------------------------------- -void CClientShadowMgr::ComputeHierarchicalBounds( IClientRenderable *pRenderable, Vector &vecMins, Vector &vecMaxs ) -{ + // Far inner superellipse + for (i=0; iGetBSPTreeQuery(); + pQuery->EnumerateLeavesInBox( mins, maxs, pEnum, 0 ); +// pEnum->ExtractUnconnectedLeaves( vecOrigin ); +} + + +void CClientShadowMgr::BuildFlashlight( ClientShadowHandle_t handle ) +{ + // For the 360, we just draw flashlights with the main geometry + // and bypass the entire shadow casting system. + ClientShadow_t &shadow = m_Shadows[handle]; + if ( shadowmgr->SinglePassFlashlightModeEnabled() ) + { + // This will update the matrices, but not do work to add the flashlight to surfaces + shadowmgr->ProjectFlashlight( shadow.m_ShadowHandle, shadow.m_WorldToShadow, 0, NULL ); + return; + } + + VPROF_BUDGET( "CClientShadowMgr::BuildFlashlight", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING ); + + bool bLightModels = r_flashlightmodels.GetBool(); + bool bLightSpecificEntity = shadow.m_hTargetEntity.Get() != NULL; + bool bLightWorld = ( shadow.m_Flags & SHADOW_FLAGS_LIGHT_WORLD ) != 0; + int nCount = 0; + const int *pLeafList = 0; + + CShadowLeafEnum leafList; + if ( bLightWorld || ( bLightModels && !bLightSpecificEntity ) ) + { + const FlashlightState_t& flashlightState = shadowmgr->GetFlashlightState( shadow.m_ShadowHandle ); + BuildFlashlightLeafList( &leafList, flashlightState.m_vecLightOrigin, shadow.m_WorldToShadow ); + nCount = leafList.m_LeafList.Count(); + pLeafList = leafList.m_LeafList.Base(); + } + + if( bLightWorld ) + { + shadowmgr->ProjectFlashlight( shadow.m_ShadowHandle, shadow.m_WorldToShadow, nCount, pLeafList ); + } + else + { + // This should clear all models and surfaces from this shadow + shadowmgr->EnableShadow( shadow.m_ShadowHandle, false ); + shadowmgr->EnableShadow( shadow.m_ShadowHandle, true ); + } + + if ( !bLightModels ) + return; + + if ( !bLightSpecificEntity ) + { + // Add the shadow to the client leaf system so it correctly marks + // leafs as being affected by a particular shadow + ClientLeafSystem()->ProjectFlashlight( shadow.m_ClientLeafShadowHandle, nCount, pLeafList ); + return; + } + + if( ( shadow.m_Flags & ( SHADOW_FLAGS_SIMPLE_PROJECTION ) ) != 0 ) + { + return; + } + + // We know what we are focused on, so just add the shadow directly to that receiver + Assert( shadow.m_hTargetEntity->GetModel() ); + + C_BaseEntity *pChild = shadow.m_hTargetEntity->FirstMoveChild(); + while( pChild ) + { + int modelType = modelinfo->GetModelType( pChild->GetModel() ); + if (modelType == mod_brush) + { + AddShadowToReceiver( handle, pChild, SHADOW_RECEIVER_BRUSH_MODEL ); + } + else if ( modelType == mod_studio ) + { + AddShadowToReceiver( handle, pChild, SHADOW_RECEIVER_STUDIO_MODEL ); + } + + pChild = pChild->NextMovePeer(); + } + + int modelType = modelinfo->GetModelType( shadow.m_hTargetEntity->GetModel() ); + if (modelType == mod_brush) + { + AddShadowToReceiver( handle, shadow.m_hTargetEntity, SHADOW_RECEIVER_BRUSH_MODEL ); + } + else if ( modelType == mod_studio ) + { + AddShadowToReceiver( handle, shadow.m_hTargetEntity, SHADOW_RECEIVER_STUDIO_MODEL ); + } +} + + +//----------------------------------------------------------------------------- +// Adds the child bounds to the bounding box +//----------------------------------------------------------------------------- +void CClientShadowMgr::AddChildBounds( matrix3x4_t &matWorldToBBox, IClientRenderable* pParent, Vector &vecMins, Vector &vecMaxs ) +{ + Vector vecChildMins, vecChildMaxs; + Vector vecNewChildMins, vecNewChildMaxs; + matrix3x4_t childToBBox; + + IClientRenderable *pChild = pParent->FirstShadowChild(); + while( pChild ) + { + // Transform the child bbox into the space of the main bbox + // FIXME: Optimize this? + if ( GetActualShadowCastType( pChild ) != SHADOWS_NONE) + { + pChild->GetShadowRenderBounds( vecChildMins, vecChildMaxs, SHADOWS_RENDER_TO_TEXTURE ); + ConcatTransforms( matWorldToBBox, pChild->RenderableToWorldTransform(), childToBBox ); + TransformAABB( childToBBox, vecChildMins, vecChildMaxs, vecNewChildMins, vecNewChildMaxs ); + VectorMin( vecMins, vecNewChildMins, vecMins ); + VectorMax( vecMaxs, vecNewChildMaxs, vecMaxs ); + } + + AddChildBounds( matWorldToBBox, pChild, vecMins, vecMaxs ); + pChild = pChild->NextShadowPeer(); + } +} + + +//----------------------------------------------------------------------------- +// Compute a bounds for the entity + children +//----------------------------------------------------------------------------- +void CClientShadowMgr::ComputeHierarchicalBounds( IClientRenderable *pRenderable, Vector &vecMins, Vector &vecMaxs ) +{ ShadowType_t shadowType = GetActualShadowCastType( pRenderable ); pRenderable->GetShadowRenderBounds( vecMins, vecMaxs, shadowType ); @@ -2750,7 +4091,7 @@ void CClientShadowMgr::ComputeHierarchicalBounds( IClientRenderable *pRenderable //----------------------------------------------------------------------------- void CClientShadowMgr::UpdateStudioShadow( IClientRenderable *pRenderable, ClientShadowHandle_t handle ) { - if( !( m_Shadows[handle].m_Flags & SHADOW_FLAGS_FLASHLIGHT ) ) + if( !( m_Shadows[handle].m_Flags & ( SHADOW_FLAGS_FLASHLIGHT | SHADOW_FLAGS_SIMPLE_PROJECTION ) ) ) { Vector mins, maxs; ComputeHierarchicalBounds( pRenderable, mins, maxs ); @@ -2773,7 +4114,7 @@ void CClientShadowMgr::UpdateStudioShadow( IClientRenderable *pRenderable, Clien void CClientShadowMgr::UpdateBrushShadow( IClientRenderable *pRenderable, ClientShadowHandle_t handle ) { - if( !( m_Shadows[handle].m_Flags & SHADOW_FLAGS_FLASHLIGHT ) ) + if( !( m_Shadows[handle].m_Flags & ( SHADOW_FLAGS_FLASHLIGHT | SHADOW_FLAGS_SIMPLE_PROJECTION ) ) ) { // Compute the bounding box in the space of the shadow... Vector mins, maxs; @@ -2855,13 +4196,16 @@ bool CClientShadowMgr::ShouldUseParentShadow( IClientRenderable *pRenderable ) return true; } - //----------------------------------------------------------------------------- // Before we render any view, make sure all shadows are re-projected vs world //----------------------------------------------------------------------------- -void CClientShadowMgr::PreRender() +void CClientShadowMgr::ReprojectShadows() { - VPROF_BUDGET( "CClientShadowMgr::PreRender", VPROF_BUDGETGROUP_SHADOW_RENDERING ); + // only update shadows once per frame + Assert( gpGlobals->framecount != m_nPrevFrameCount ); + m_nPrevFrameCount = gpGlobals->framecount; + + VPROF_BUDGET( "CClientShadowMgr::ReprojectShadows", VPROF_BUDGETGROUP_SHADOW_RENDERING ); MDLCACHE_CRITICAL_SECTION(); // @@ -2870,10 +4214,10 @@ void CClientShadowMgr::PreRender() { // VPROF scope - VPROF_BUDGET( "CClientShadowMgr::PreRender", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING ); + //VPROF_BUDGET( "CClientShadowMgr::PreRender", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING ); // If someone turned shadow depth mapping on but we can't do it, force it off - if ( r_flashlightdepthtexture.GetBool() && !materials->SupportsShadowDepthTextures() ) + if ( r_flashlightdepthtexture.GetBool() && !g_pMaterialSystemHardwareConfig->SupportsShadowDepthTextures() ) { r_flashlightdepthtexture.SetValue( 0 ); ShutdownDepthTextureShadows(); @@ -2881,27 +4225,24 @@ void CClientShadowMgr::PreRender() bool bDepthTextureActive = r_flashlightdepthtexture.GetBool(); int nDepthTextureResolution = r_flashlightdepthres.GetInt(); + int nDepthTextureResolutionHigh = r_flashlightdepthreshigh.GetInt(); - // If shadow depth texture size or enable/disable changed, do appropriate deallocation/(re)allocation - if ( ( bDepthTextureActive != m_bDepthTextureActive ) || ( nDepthTextureResolution != m_nDepthTextureResolution ) ) + if ( ( bDepthTextureActive == true ) && ( m_bDepthTextureActive == true ) && + ( nDepthTextureResolution != m_nDepthTextureResolution || nDepthTextureResolutionHigh != m_nDepthTextureResolutionHigh ) ) { // If shadow depth texturing remains on, but resolution changed, shut down and reinitialize depth textures - if ( ( bDepthTextureActive == true ) && ( m_bDepthTextureActive == true ) && - ( nDepthTextureResolution != m_nDepthTextureResolution ) ) + ShutdownDepthTextureShadows(); + InitDepthTextureShadows(); + } + else + { + if ( bDepthTextureActive && !m_bDepthTextureActive ) { - ShutdownDepthTextureShadows(); - InitDepthTextureShadows(); - } - else - { - if ( m_bDepthTextureActive && !bDepthTextureActive ) // Turning off shadow depth texturing - { - ShutdownDepthTextureShadows(); - } - else if ( bDepthTextureActive && !m_bDepthTextureActive) // Turning on shadow depth mapping - { - InitDepthTextureShadows(); - } + // If shadow depth texture is now needed but wasn't allocated, allocate it + // Turning on shadow depth mapping + materials->ReEnableRenderTargetAllocation_IRealizeIfICallThisAllTexturesWillBeUnloadedAndLoadTimeWillSufferHorribly(); + InitDepthTextureShadows(); // only allocates buffers if they don't already exist + materials->FinishRenderTargetAllocation(); } } } @@ -2910,33 +4251,131 @@ void CClientShadowMgr::PreRender() // -- Render to Texture Shadows ----------------------- // - bool bRenderToTextureActive = r_shadowrendertotexture.GetBool(); - if ( bRenderToTextureActive != m_RenderToTextureActive ) + if ( !r_shadows.GetBool() ) + { + return; + } + + bool bRenderToTextureActive = r_shadowrendertotexture.GetBool(); + if ( !m_RenderToTextureActive && bRenderToTextureActive ) + { + materials->ReEnableRenderTargetAllocation_IRealizeIfICallThisAllTexturesWillBeUnloadedAndLoadTimeWillSufferHorribly(); + InitRenderToTextureShadows(); + materials->FinishRenderTargetAllocation(); + UpdateAllShadows(); + return; + } + + if ( m_RenderToTextureActive && !bRenderToTextureActive ) + { + materials->ReEnableRenderTargetAllocation_IRealizeIfICallThisAllTexturesWillBeUnloadedAndLoadTimeWillSufferHorribly(); + ShutdownRenderToTextureShadows(); + materials->FinishRenderTargetAllocation(); + UpdateAllShadows(); + return; + } + + m_bUpdatingDirtyShadows = true; + + if ( r_shadow_half_update_rate.GetBool() ) + { + UpdateDirtyShadowsHalfRate(); + } + else + { + UpdateDirtyShadows(); + } + + m_bUpdatingDirtyShadows = false; + + DestroyQueuedShadows(); +} + +//----------------------------------------------------------------------------- +// Update all shadows in the dirty shadow set +//----------------------------------------------------------------------------- +void CClientShadowMgr::UpdateDirtyShadows() +{ + if ( r_shadow_debug_spew.GetBool() ) + { + DevMsg( "dirty shadows: %3d\n", m_DirtyShadows.Count() ); + } + + unsigned short i = m_DirtyShadows.FirstInorder(); + while ( i != m_DirtyShadows.InvalidIndex() ) + { + MDLCACHE_CRITICAL_SECTION(); + ClientShadowHandle_t& handle = m_DirtyShadows[ i ]; + UpdateDirtyShadow( handle ); + i = m_DirtyShadows.NextInorder(i); + } + m_DirtyShadows.RemoveAll(); + + // Transparent shadows must remain dirty, since they were not re-projected + int nCount = m_TransparentShadows.Count(); + for ( int i = 0; i < nCount; ++i ) + { + m_DirtyShadows.Insert( m_TransparentShadows[i] ); + } + m_TransparentShadows.RemoveAll(); +} + +//----------------------------------------------------------------------------- +// Update half the shadows in the dirty shadow set, leaving the rest for next frame +//----------------------------------------------------------------------------- +void CClientShadowMgr::UpdateDirtyShadowsHalfRate() +{ + unsigned short i = m_DirtyShadowsLeftOver.FirstInorder(); + while ( i != m_DirtyShadowsLeftOver.InvalidIndex() ) { - if ( m_RenderToTextureActive ) - { - ShutdownRenderToTextureShadows(); - } - else + MDLCACHE_CRITICAL_SECTION(); + ClientShadowHandle_t& handle = m_DirtyShadowsLeftOver[ i ]; + UpdateDirtyShadow( handle ); + + // remove from real dirty set, so that we don't touch shadows twice + unsigned short nIdx = m_DirtyShadows.Find( handle ); + if ( nIdx != m_DirtyShadows.InvalidIndex() ) { - InitRenderToTextureShadows(); + m_DirtyShadows.RemoveAt( nIdx ); } + i = m_DirtyShadowsLeftOver.NextInorder( i ); + } + int nNumShadowsProcessed = m_DirtyShadowsLeftOver.Count(); - UpdateAllShadows(); - return; + int nNumTotalDirtyShadows = nNumShadowsProcessed + m_DirtyShadows.Count(); + int nNumShadowsToProcess = nNumTotalDirtyShadows / 2 + 1; + if ( r_shadow_debug_spew.GetBool() ) + { + DevMsg( "dirty shadows: %3d\n", nNumShadowsToProcess ); } - m_bUpdatingDirtyShadows = true; + nNumShadowsToProcess -= nNumShadowsProcessed; + nNumShadowsToProcess = MAX( 0, nNumShadowsToProcess ); + nNumShadowsToProcess = MIN( m_DirtyShadows.Count(), nNumShadowsToProcess ); + //DevMsg( "dirty: %2d leftover: %2d total: %2d from main list: %2d processed: %d\n", m_DirtyShadows.Count(), m_DirtyShadowsLeftOver.Count(), nNumTotalDirtyShadows, nNumShadowsToProcess, nNumShadowsProcessed + nNumShadowsToProcess ); - unsigned short i = m_DirtyShadows.FirstInorder(); - while ( i != m_DirtyShadows.InvalidIndex() ) + m_DirtyShadowsLeftOver.RemoveAll(); + + // + // process any additional dirty shadows + // + + i = m_DirtyShadows.FirstInorder(); + for ( int j = 0; j < nNumShadowsToProcess; j++ ) { MDLCACHE_CRITICAL_SECTION(); ClientShadowHandle_t& handle = m_DirtyShadows[ i ]; - Assert( m_Shadows.IsValidIndex( handle ) ); - UpdateProjectedTextureInternal( handle, false ); - i = m_DirtyShadows.NextInorder(i); + UpdateDirtyShadow( handle ); + i = m_DirtyShadows.NextInorder( i ); + } + // put the leftover shadows into the leftover bucket + while ( i != m_DirtyShadows.InvalidIndex() ) + { + ClientShadowHandle_t& handle = m_DirtyShadows[ i ]; + i = m_DirtyShadows.NextInorder( i ); + m_DirtyShadowsLeftOver.Insert( handle ); } + m_DirtyShadows.RemoveAll(); // Transparent shadows must remain dirty, since they were not re-projected @@ -2946,10 +4385,42 @@ void CClientShadowMgr::PreRender() m_DirtyShadows.Insert( m_TransparentShadows[i] ); } m_TransparentShadows.RemoveAll(); +} - m_bUpdatingDirtyShadows = false; +//----------------------------------------------------------------------------- +// Updates a single dirty shadow +//----------------------------------------------------------------------------- +void CClientShadowMgr::UpdateDirtyShadow( ClientShadowHandle_t handle ) +{ + Assert( m_Shadows.IsValidIndex( handle ) ); + if ( IsShadowingFromWorldLights() ) + { + UpdateShadowDirectionFromLocalLightSource( handle ); + } + UpdateProjectedTextureInternal( handle, false ); +} + +//----------------------------------------------------------------------------- +// Convar callback +//----------------------------------------------------------------------------- +void HalfUpdateRateCallback( IConVar *var, const char *pOldValue, float flOldValue ) +{ + s_ClientShadowMgr.FlushLeftOverDirtyShadows(); } +//----------------------------------------------------------------------------- +// Flushes any leftover dirty shadows into the main dirty shadow set +//----------------------------------------------------------------------------- +void CClientShadowMgr::FlushLeftOverDirtyShadows() +{ + unsigned short i = m_DirtyShadowsLeftOver.FirstInorder(); + while ( i != m_DirtyShadowsLeftOver.InvalidIndex() ) + { + m_DirtyShadows.InsertIfNotFound( m_DirtyShadowsLeftOver[ i ] ); + i = m_DirtyShadowsLeftOver.NextInorder(i); + } + m_DirtyShadowsLeftOver.RemoveAll(); +} //----------------------------------------------------------------------------- // Gets the entity whose shadow this shadow will render into @@ -2978,6 +4449,7 @@ IClientRenderable *CClientShadowMgr::GetParentShadowEntity( ClientShadowHandle_t //----------------------------------------------------------------------------- // Marks a shadow as needing re-projection //----------------------------------------------------------------------------- +CThreadFastMutex g_DirtyListAddMutex; // This should be made lock free? [3/19/2008 tom] void CClientShadowMgr::AddToDirtyShadowList( ClientShadowHandle_t handle, bool bForce ) { // Don't add to the dirty shadow list while we're iterating over it @@ -2989,6 +4461,8 @@ void CClientShadowMgr::AddToDirtyShadowList( ClientShadowHandle_t handle, bool b if ( handle == CLIENTSHADOW_INVALID_HANDLE ) return; + AUTO_LOCK( g_DirtyListAddMutex ); + Assert( m_DirtyShadows.Find( handle ) == m_DirtyShadows.InvalidIndex() ); m_DirtyShadows.Insert( handle ); @@ -3018,6 +4492,8 @@ void CClientShadowMgr::AddToDirtyShadowList( IClientRenderable *pRenderable, boo if ( m_bUpdatingDirtyShadows ) return; + AUTO_LOCK( g_DirtyListAddMutex ); + // Are we already in the dirty list? if ( pRenderable->IsShadowDirty( ) ) return; @@ -3089,14 +4565,33 @@ void CClientShadowMgr::UpdateShadow( ClientShadowHandle_t handle, bool force ) return; } + // Mark shadow as dirty if no split screen user needs it + bool bShouldDraw = false; + FOR_EACH_VALID_SPLITSCREEN_PLAYER( i ) + { + if ( pRenderable->ShouldDrawForSplitScreenUser( i ) ) + { + bShouldDraw = true; + break; + } + } + if ( !bShouldDraw ) + { + pRenderable->MarkShadowDirty( false ); + return; + } + // FIXME: NOTE! Because this is called from PreRender, the falloff bias is // off by a frame. We could move the code in PreRender to occur after world // list building is done to fix this issue. // Don't bother with it if the shadow is totally transparent - const ShadowInfo_t &shadowInfo = shadowmgr->GetInfo( shadow.m_ShadowHandle ); - if ( shadowInfo.m_FalloffBias == 255 ) + if ( shadow.m_FalloffBias == 255 ) { - shadowmgr->EnableShadow( shadow.m_ShadowHandle, false ); + if ( !r_shadow_deferred.GetBool() ) + { + shadowmgr->EnableShadow( shadow.m_ShadowHandle, false ); + } + m_TransparentShadows.AddToTail( handle ); return; } @@ -3111,12 +4606,18 @@ void CClientShadowMgr::UpdateShadow( ClientShadowHandle_t handle, bool force ) // Check to see if it's a child of an entity with a render-to-texture shadow... if ( ShouldUseParentShadow( pRenderable ) || WillParentRenderBlobbyShadow( pRenderable ) ) { - shadowmgr->EnableShadow( shadow.m_ShadowHandle, false ); + if ( !r_shadow_deferred.GetBool() ) + { + shadowmgr->EnableShadow( shadow.m_ShadowHandle, false ); + } pRenderable->MarkShadowDirty( false ); return; } - shadowmgr->EnableShadow( shadow.m_ShadowHandle, true ); + if ( !r_shadow_deferred.GetBool() ) + { + shadowmgr->EnableShadow( shadow.m_ShadowHandle, true ); + } // Figure out if the shadow moved... // Even though we have dirty bits, some entities @@ -3166,7 +4667,7 @@ void CClientShadowMgr::UpdateProjectedTextureInternal( ClientShadowHandle_t hand { ClientShadow_t& shadow = m_Shadows[handle]; - if( shadow.m_Flags & SHADOW_FLAGS_FLASHLIGHT ) + if( ( shadow.m_Flags & ( SHADOW_FLAGS_FLASHLIGHT | SHADOW_FLAGS_SIMPLE_PROJECTION ) ) != 0 ) { VPROF_BUDGET( "CClientShadowMgr::UpdateProjectedTextureInternal", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING ); @@ -3200,7 +4701,7 @@ void CClientShadowMgr::UpdateProjectedTexture( ClientShadowHandle_t handle, bool // NOTE: This can only work for flashlights, since UpdateProjectedTextureInternal // depends on the falloff offset to cull shadows. ClientShadow_t &shadow = m_Shadows[ handle ]; - if( ( shadow.m_Flags & SHADOW_FLAGS_FLASHLIGHT ) == 0 ) + if( ( shadow.m_Flags & ( SHADOW_FLAGS_FLASHLIGHT | SHADOW_FLAGS_SIMPLE_PROJECTION ) ) == 0 ) { Warning( "CClientShadowMgr::UpdateProjectedTexture can only be used with flashlights!\n" ); return; @@ -3243,12 +4744,12 @@ void CClientShadowMgr::ComputeBoundingSphere( IClientRenderable* pRenderable, Ve //----------------------------------------------------------------------------- // Computes a rough AABB encompassing the volume of the shadow //----------------------------------------------------------------------------- -void CClientShadowMgr::ComputeShadowBBox( IClientRenderable *pRenderable, const Vector &vecAbsCenter, float flRadius, Vector *pAbsMins, Vector *pAbsMaxs ) +void CClientShadowMgr::ComputeShadowBBox( IClientRenderable *pRenderable, ClientShadowHandle_t shadowHandle, const Vector &vecAbsCenter, float flRadius, Vector *pAbsMins, Vector *pAbsMaxs ) { // This is *really* rough. Basically we simply determine the // maximum shadow casting length and extrude the box by that distance - Vector vecShadowDir = GetShadowDirection( pRenderable ); + Vector vecShadowDir = GetShadowDirection( shadowHandle ); for (int i = 0; i < 3; ++i) { float flShadowCastDistance = GetShadowDistance( pRenderable ); @@ -3290,7 +4791,7 @@ bool CClientShadowMgr::CullReceiver( ClientShadowHandle_t handle, IClientRendera IClientRenderable* pSourceRenderable ) { // check flags here instead and assert !pSourceRenderable - if( m_Shadows[handle].m_Flags & SHADOW_FLAGS_FLASHLIGHT ) + if( m_Shadows[handle].m_Flags & ( SHADOW_FLAGS_FLASHLIGHT | SHADOW_FLAGS_SIMPLE_PROJECTION ) ) { VPROF_BUDGET( "CClientShadowMgr::CullReceiver", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING ); @@ -3300,7 +4801,7 @@ bool CClientShadowMgr::CullReceiver( ClientShadowHandle_t handle, IClientRendera Vector mins, maxs; pRenderable->GetRenderBoundsWorldspace( mins, maxs ); - return R_CullBox( mins, maxs, frustum ); + return frustum.CullBox( mins, maxs ); } Assert( pSourceRenderable ); @@ -3312,13 +4813,13 @@ bool CClientShadowMgr::CullReceiver( ClientShadowHandle_t handle, IClientRendera // Transform the sphere center into the space of the shadow Vector localOrigin; const ClientShadow_t& shadow = m_Shadows[handle]; - const ShadowInfo_t& info = shadowmgr->GetInfo( shadow.m_ShadowHandle ); + Vector3DMultiplyPosition( shadow.m_WorldToShadow, origin, localOrigin ); // Compute a rough bounding box for the shadow (in shadow space) Vector shadowMin, shadowMax; shadowMin.Init( -shadow.m_WorldSize.x * 0.5f, -shadow.m_WorldSize.y * 0.5f, 0 ); - shadowMax.Init( shadow.m_WorldSize.x * 0.5f, shadow.m_WorldSize.y * 0.5f, info.m_MaxDist ); + shadowMax.Init( shadow.m_WorldSize.x * 0.5f, shadow.m_WorldSize.y * 0.5f, shadow.m_MaxDist ); // If the bounding sphere doesn't intersect with the shadow volume, cull if (!IsBoxIntersectingSphere( shadowMin, shadowMax, localOrigin, radius )) @@ -3346,7 +4847,7 @@ bool CClientShadowMgr::CullReceiver( ClientShadowHandle_t handle, IClientRendera if (foundSeparatingPlane) { // Compute which side of the plane the renderable is on.. - Vector vecShadowDir = GetShadowDirection( pSourceRenderable ); + Vector vecShadowDir = GetShadowDirection( handle ); float shadowDot = DotProduct( vecShadowDir, plane.normal ); float receiverDot = DotProduct( plane.normal, origin ); float sourceDot = DotProduct( plane.normal, originSource ); @@ -3453,7 +4954,7 @@ void CClientShadowMgr::AddShadowToReceiver( ClientShadowHandle_t handle, { case SHADOW_RECEIVER_BRUSH_MODEL: - if( shadow.m_Flags & SHADOW_FLAGS_FLASHLIGHT ) + if( shadow.m_Flags & ( SHADOW_FLAGS_FLASHLIGHT | SHADOW_FLAGS_SIMPLE_PROJECTION ) ) { VPROF_BUDGET( "CClientShadowMgr::AddShadowToReceiver", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING ); @@ -3462,15 +4963,17 @@ void CClientShadowMgr::AddShadowToReceiver( ClientShadowHandle_t handle, shadowmgr->AddShadowToBrushModel( shadow.m_ShadowHandle, const_cast(pRenderable->GetModel()), pRenderable->GetRenderOrigin(), pRenderable->GetRenderAngles() ); - - shadowmgr->AddFlashlightRenderable( shadow.m_ShadowHandle, pRenderable ); } } else { - shadowmgr->AddShadowToBrushModel( shadow.m_ShadowHandle, - const_cast(pRenderable->GetModel()), - pRenderable->GetRenderOrigin(), pRenderable->GetRenderAngles() ); + if ( !r_shadow_deferred.GetBool() ) + { + shadowmgr->AddShadowToBrushModel( shadow.m_ShadowHandle, + const_cast(pRenderable->GetModel()), + pRenderable->GetRenderOrigin(), pRenderable->GetRenderAngles() ); + + } } break; @@ -3478,29 +4981,30 @@ void CClientShadowMgr::AddShadowToReceiver( ClientShadowHandle_t handle, // Don't add shadows to props if we're not using render-to-texture if ( GetActualShadowCastType( handle ) == SHADOWS_RENDER_TO_TEXTURE ) { - // Also don't add them unless an NPC or player casts them.. - // They are wickedly expensive!!! - C_BaseEntity *pEnt = pSourceRenderable->GetIClientUnknown()->GetBaseEntity(); - if ( pEnt && ( pEnt->GetFlags() & (FL_NPC | FL_CLIENT)) ) + if ( !r_shadow_deferred.GetBool() ) { - staticpropmgr->AddShadowToStaticProp( shadow.m_ShadowHandle, pRenderable ); + // Also don't add them unless an NPC or player casts them.. + // They are wickedly expensive!!! + C_BaseEntity *pEnt = pSourceRenderable->GetIClientUnknown()->GetBaseEntity(); + if ( pEnt && ( pEnt->GetFlags() & (FL_NPC | FL_CLIENT)) ) + { + staticpropmgr->AddShadowToStaticProp( shadow.m_ShadowHandle, pRenderable ); + } } } - else if( shadow.m_Flags & SHADOW_FLAGS_FLASHLIGHT ) + else if( shadow.m_Flags & ( SHADOW_FLAGS_FLASHLIGHT | SHADOW_FLAGS_SIMPLE_PROJECTION ) ) { VPROF_BUDGET( "CClientShadowMgr::AddShadowToReceiver", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING ); if( (!shadow.m_hTargetEntity) || IsFlashlightTarget( handle, pRenderable ) ) { staticpropmgr->AddShadowToStaticProp( shadow.m_ShadowHandle, pRenderable ); - - shadowmgr->AddFlashlightRenderable( shadow.m_ShadowHandle, pRenderable ); } } break; case SHADOW_RECEIVER_STUDIO_MODEL: - if( shadow.m_Flags & SHADOW_FLAGS_FLASHLIGHT ) + if( shadow.m_Flags & ( SHADOW_FLAGS_FLASHLIGHT | SHADOW_FLAGS_SIMPLE_PROJECTION ) ) { VPROF_BUDGET( "CClientShadowMgr::AddShadowToReceiver", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING ); @@ -3508,7 +5012,6 @@ void CClientShadowMgr::AddShadowToReceiver( ClientShadowHandle_t handle, { pRenderable->CreateModelInstance(); shadowmgr->AddShadowToModel( shadow.m_ShadowHandle, pRenderable->GetModelInstance() ); - shadowmgr->AddFlashlightRenderable( shadow.m_ShadowHandle, pRenderable ); } } break; @@ -3544,6 +5047,7 @@ void CClientShadowMgr::RemoveAllShadowsFromReceiver( case SHADOW_RECEIVER_STUDIO_MODEL: if( pRenderable && pRenderable->GetModelInstance() != MODEL_INSTANCE_INVALID ) { + Assert(shadowmgr); shadowmgr->RemoveAllShadowsFromModel( pRenderable->GetModelInstance() ); } break; @@ -3578,6 +5082,25 @@ void CClientShadowMgr::SetRenderToTextureShadowTexCoords( ShadowHandle_t handle, } +void CClientShadowMgr::SetRenderToTextureShadowTexCoords( ClientShadow_t& shadow, int x, int y, int w, int h ) +{ + // Let the shadow mgr know about the texture coordinates... + // That way it'll be able to batch rendering better. + int textureW, textureH; + m_ShadowAllocator.GetTotalTextureSize( textureW, textureH ); + + // Go in a half-pixel to avoid blending with neighboring textures.. + float u, v, du, dv; + + u = ((float)x + 0.5f) / (float)textureW; + v = ((float)y + 0.5f) / (float)textureH; + du = ((float)w - 1) / (float)textureW; + dv = ((float)h - 1) / (float)textureH; + + shadow.m_TexCoordOffset.Init( u, v ); + shadow.m_TexCoordScale.Init( du, dv ); +} + //----------------------------------------------------------------------------- // Setup all children shadows //----------------------------------------------------------------------------- @@ -3663,11 +5186,20 @@ bool CClientShadowMgr::DrawShadowHierarchy( IClientRenderable *pRenderable, cons bDrawModelShadow = nModelType == mod_studio; bDrawBrushShadow = nModelType == mod_brush; } - - if ( bDrawModelShadow ) + + if ( pRenderable && ( shadow.m_Flags & SHADOW_FLAGS_CUSTOM_DRAW ) ) + { + RenderableInstance_t instance; + instance.m_nAlpha = 255; + pRenderable->DrawModel( STUDIO_SHADOWTEXTURE, instance ); + bDrewTexture = true; + } + else if ( bDrawModelShadow ) { + CMatRenderContextPtr pRenderContext( materials ); + CMatRenderDataReference lock( pRenderContext ); DrawModelInfo_t info; - matrix3x4_t *pBoneToWorld = modelrender->DrawModelShadowSetup( pRenderable, pRenderable->GetBody(), pRenderable->GetSkin(), &info ); + matrix3x4a_t *pBoneToWorld = modelrender->DrawModelShadowSetup( pRenderable, pRenderable->GetBody(), pRenderable->GetSkin(), &info ); if ( pBoneToWorld ) { modelrender->DrawModelShadow( pRenderable, info, pBoneToWorld ); @@ -3722,26 +5254,32 @@ bool CClientShadowMgr::BuildSetupListForRenderToTextureShadow( unsigned short cl //----------------------------------------------------------------------------- // This gets called with every shadow that potentially will need to re-render //----------------------------------------------------------------------------- -bool CClientShadowMgr::DrawRenderToTextureShadow( unsigned short clientShadowHandle, float flArea ) +bool CClientShadowMgr::DrawRenderToTextureShadow( int nSlot, unsigned short clientShadowHandle, float flArea ) { ClientShadow_t& shadow = m_Shadows[clientShadowHandle]; + if ( shadow.m_bUseSplitScreenBits && + !shadow.m_SplitScreenBits.IsBitSet( nSlot ) ) + { + return false; + } + // If we were previously using the LOD shadow, set the material bool bPreviouslyUsingLODShadow = ( shadow.m_Flags & SHADOW_FLAGS_USING_LOD_SHADOW ) != 0; shadow.m_Flags &= ~SHADOW_FLAGS_USING_LOD_SHADOW; if ( bPreviouslyUsingLODShadow ) { - shadowmgr->SetShadowMaterial( shadow.m_ShadowHandle, m_RenderShadow, m_RenderModelShadow, (void*)(uintp)clientShadowHandle ); + shadowmgr->SetShadowMaterial( shadow.m_ShadowHandle, m_RenderShadow, m_RenderModelShadow, (void*)clientShadowHandle ); } // Mark texture as being used... bool bDirtyTexture = (shadow.m_Flags & SHADOW_FLAGS_TEXTURE_DIRTY) != 0; bool bDrewTexture = false; - bool bNeedsRedraw = ( !m_bThreaded && m_ShadowAllocator.UseTexture( shadow.m_ShadowTexture, bDirtyTexture, flArea ) ); + bool bNeedsRedraw = m_ShadowAllocator.UseTexture( shadow.m_ShadowTexture, bDirtyTexture, flArea ); if ( !m_ShadowAllocator.HasValidTexture( shadow.m_ShadowTexture ) ) { - DrawRenderToTextureShadowLOD( clientShadowHandle ); + DrawRenderToTextureShadowLOD( nSlot, clientShadowHandle ); return false; } @@ -3761,8 +5299,8 @@ bool CClientShadowMgr::DrawRenderToTextureShadow( unsigned short clientShadowHan pRenderContext->ClearBuffers( true, false ); pRenderContext->MatrixMode( MATERIAL_VIEW ); - pRenderContext->LoadMatrix( shadowmgr->GetInfo( shadow.m_ShadowHandle ).m_WorldToShadow ); - + pRenderContext->LoadMatrix( shadow.m_WorldToTexture ); + if ( DrawShadowHierarchy( pRenderable, shadow ) ) { bDrewTexture = true; @@ -3788,6 +5326,7 @@ bool CClientShadowMgr::DrawRenderToTextureShadow( unsigned short clientShadowHan } SetRenderToTextureShadowTexCoords( shadow.m_ShadowHandle, x, y, w, h ); + SetRenderToTextureShadowTexCoords( shadow, x, y, w, h ); } else if ( bPreviouslyUsingLODShadow ) { @@ -3796,6 +5335,7 @@ bool CClientShadowMgr::DrawRenderToTextureShadow( unsigned short clientShadowHan int x, y, w, h; m_ShadowAllocator.GetTextureRect( shadow.m_ShadowTexture, x, y, w, h ); SetRenderToTextureShadowTexCoords( shadow.m_ShadowHandle, x, y, w, h ); + SetRenderToTextureShadowTexCoords( shadow, x, y, w, h ); } return bDrewTexture; @@ -3805,14 +5345,25 @@ bool CClientShadowMgr::DrawRenderToTextureShadow( unsigned short clientShadowHan //----------------------------------------------------------------------------- // "Draws" the shadow LOD, which really means just set up the blobby shadow //----------------------------------------------------------------------------- -void CClientShadowMgr::DrawRenderToTextureShadowLOD( unsigned short clientShadowHandle ) +void CClientShadowMgr::DrawRenderToTextureShadowLOD( int nSlot, unsigned short clientShadowHandle ) { + if ( r_shadow_deferred.GetBool() ) + { + return; + } + ClientShadow_t &shadow = m_Shadows[clientShadowHandle]; + if ( shadow.m_bUseSplitScreenBits && + !shadow.m_SplitScreenBits.IsBitSet( nSlot ) ) + { + return; + } + if ( (shadow.m_Flags & SHADOW_FLAGS_USING_LOD_SHADOW) == 0 ) { shadowmgr->SetShadowMaterial( shadow.m_ShadowHandle, m_SimpleShadow, m_SimpleShadow, (void*)CLIENTSHADOW_INVALID_HANDLE ); shadowmgr->SetShadowTexCoord( shadow.m_ShadowHandle, 0, 0, 1, 1 ); - ClearExtraClipPlanes( clientShadowHandle ); // this was ClearExtraClipPlanes( shadow.m_ShadowHandle ), fix is from Joe Demers + ClearExtraClipPlanes( shadow.m_ShadowHandle ); shadow.m_Flags |= SHADOW_FLAGS_USING_LOD_SHADOW; } } @@ -3831,17 +5382,39 @@ void CClientShadowMgr::AdvanceFrame() //----------------------------------------------------------------------------- // Re-render shadow depth textures that lie in the leaf list //----------------------------------------------------------------------------- -int CClientShadowMgr::BuildActiveShadowDepthList( const CViewSetup &viewSetup, int nMaxDepthShadows, ClientShadowHandle_t *pActiveDepthShadows ) +int CClientShadowMgr::BuildActiveShadowDepthList( const CViewSetup &viewSetup, int nMaxDepthShadows, ClientShadowHandle_t *pActiveDepthShadows, int &nNumHighRes ) { + float fDots[ 1024 ]; + + nNumHighRes = 0; + + Frustum_t viewFrustum; + GeneratePerspectiveFrustum( viewSetup.origin, viewSetup.angles, viewSetup.zNear, viewSetup.zFar, viewSetup.fov, viewSetup.m_flAspectRatio, viewFrustum ); + + // Get a general look position for + Vector vViewForward; + AngleVectors( viewSetup.angles, &vViewForward ); + int nActiveDepthShadowCount = 0; + for ( ClientShadowHandle_t i = m_Shadows.Head(); i != m_Shadows.InvalidIndex(); i = m_Shadows.Next(i) ) { + if ( nActiveDepthShadowCount >= nMaxDepthShadows && nNumHighRes == nActiveDepthShadowCount ) + { + // Easy out! There's nothing more we can do + break; + } + ClientShadow_t& shadow = m_Shadows[i]; // If this is not a flashlight which should use a shadow depth texture, skip! if ( ( shadow.m_Flags & SHADOW_FLAGS_USE_DEPTH_TEXTURE ) == 0 ) continue; + ASSERT_LOCAL_PLAYER_RESOLVABLE(); + if ( ( shadow.m_nSplitscreenOwner >= 0 ) && ( shadow.m_nSplitscreenOwner != GET_ACTIVE_SPLITSCREEN_SLOT() ) ) + continue; + const FlashlightState_t& flashlightState = shadowmgr->GetFlashlightState( shadow.m_ShadowHandle ); // Bail if this flashlight doesn't want shadows @@ -3852,36 +5425,130 @@ int CClientShadowMgr::BuildActiveShadowDepthList( const CViewSetup &viewSetup, i Vector vecAbsMins, vecAbsMaxs; CalculateAABBFromProjectionMatrix( shadow.m_WorldToShadow, &vecAbsMins, &vecAbsMaxs ); + // FIXME: Could do other sorts of culling here, such as frustum-frustum test, distance etc. + // If it's not in the view frustum, move on + if ( !flashlightState.m_bOrtho && viewFrustum.CullBox( vecAbsMins, vecAbsMaxs ) ) + { + shadowmgr->SetFlashlightDepthTexture( shadow.m_ShadowHandle, NULL, 0 ); + continue; + } + + if ( nActiveDepthShadowCount >= nMaxDepthShadows ) + { + if ( !flashlightState.m_bShadowHighRes ) + { + // All active shadows are high res + static bool s_bOverflowWarning = false; + if ( !s_bOverflowWarning ) + { + Warning( "Too many depth textures rendered in a single view!\n" ); + Assert( 0 ); + s_bOverflowWarning = true; + } + shadowmgr->SetFlashlightDepthTexture( shadow.m_ShadowHandle, NULL, 0 ); + continue; + } + else + { + // Lets take the place of other non high res active shadows + for ( int j = nActiveDepthShadowCount - 1; j >= 0; --j ) + { + // Find a low res one to replace + ClientShadow_t& prevShadow = m_Shadows[ pActiveDepthShadows[ j ] ]; + const FlashlightState_t& prevFlashlightState = shadowmgr->GetFlashlightState( prevShadow.m_ShadowHandle ); + + if ( !prevFlashlightState.m_bShadowHighRes ) + { + pActiveDepthShadows[ j ] = i; + ++nNumHighRes; + break; + } + } + + continue; + } + } + + if ( flashlightState.m_bShadowHighRes ) + { + ++nNumHighRes; + } + + // Calculate the approximate distance to the nearest side + Vector vLightDirection = flashlightState.m_vecLightOrigin - viewSetup.origin; + VectorNormalize( vLightDirection ); + fDots[ nActiveDepthShadowCount ] = vLightDirection.Dot( vViewForward ); + + pActiveDepthShadows[ nActiveDepthShadowCount++ ] = i; + } + + // sort them + for ( int i = 0; i < nActiveDepthShadowCount - 1; i++ ) + { + for ( int j = 0; j < nActiveDepthShadowCount - i - 1; j++ ) + { + if ( fDots[ j ] < fDots[ j + 1 ] ) + { + ClientShadowHandle_t nTemp = pActiveDepthShadows[ j ]; + pActiveDepthShadows[ j ] = pActiveDepthShadows[ j + 1 ]; + pActiveDepthShadows[ j + 1 ] = nTemp; + } + } + } + + return nActiveDepthShadowCount; +} + + +//----------------------------------------------------------------------------- +// Re-render shadow depth textures that lie in the leaf list +//----------------------------------------------------------------------------- +int CClientShadowMgr::BuildActiveFlashlightList( const CViewSetup &viewSetup, int nMaxFlashlights, ClientShadowHandle_t *pActiveFlashlights ) +{ + int nActiveFlashlightCount = 0; + for ( ClientShadowHandle_t i = m_Shadows.Head(); i != m_Shadows.InvalidIndex(); i = m_Shadows.Next(i) ) + { + ClientShadow_t& shadow = m_Shadows[i]; + + if ( ( shadow.m_Flags & ( SHADOW_FLAGS_FLASHLIGHT | SHADOW_FLAGS_SIMPLE_PROJECTION ) ) == 0 ) + continue; + + ASSERT_LOCAL_PLAYER_RESOLVABLE(); + if ( ( shadow.m_nSplitscreenOwner >= 0 ) && ( shadow.m_nSplitscreenOwner != GET_ACTIVE_SPLITSCREEN_SLOT() ) ) + continue; + + // Calculate an AABB around the shadow frustum + Vector vecAbsMins, vecAbsMaxs; + CalculateAABBFromProjectionMatrix( shadow.m_WorldToShadow, &vecAbsMins, &vecAbsMaxs ); + Frustum_t viewFrustum; GeneratePerspectiveFrustum( viewSetup.origin, viewSetup.angles, viewSetup.zNear, viewSetup.zFar, viewSetup.fov, viewSetup.m_flAspectRatio, viewFrustum ); // FIXME: Could do other sorts of culling here, such as frustum-frustum test, distance etc. // If it's not in the view frustum, move on - if ( R_CullBox( vecAbsMins, vecAbsMaxs, viewFrustum ) ) + if ( viewFrustum.CullBox( vecAbsMins, vecAbsMaxs ) ) { - shadowmgr->SetFlashlightDepthTexture( shadow.m_ShadowHandle, NULL, 0 ); continue; } - if ( nActiveDepthShadowCount >= nMaxDepthShadows ) + if ( nActiveFlashlightCount >= nMaxFlashlights ) { static bool s_bOverflowWarning = false; if ( !s_bOverflowWarning ) { - Warning( "Too many depth textures rendered in a single view!\n" ); + Warning( "Too many flashlights rendered in a single view!\n" ); Assert( 0 ); s_bOverflowWarning = true; } - shadowmgr->SetFlashlightDepthTexture( shadow.m_ShadowHandle, NULL, 0 ); + //shadowmgr->SetFlashlightDepthTexture( shadow.m_ShadowHandle, NULL, 0 ); continue; } - pActiveDepthShadows[nActiveDepthShadowCount++] = i; + pActiveFlashlights[nActiveFlashlightCount++] = i; } - return nActiveDepthShadowCount; + return nActiveFlashlightCount; } - //----------------------------------------------------------------------------- // Sets the view's active flashlight render state //----------------------------------------------------------------------------- @@ -3890,55 +5557,111 @@ void CClientShadowMgr::SetViewFlashlightState( int nActiveFlashlightCount, Clien // NOTE: On the 360, we render the entire scene with the flashlight state // set and don't render flashlights additively in the shadow mgr at a far later time // because the CPU costs are prohibitive - if ( !IsX360() && !r_flashlight_version2.GetInt() ) - return; - Assert( nActiveFlashlightCount<= 1 ); + shadowmgr->PushSinglePassFlashlightStateEnabled( IsX360() ); + + if ( m_nMaxDepthTextureShadows > 1 ) + { + AssertOnce( nActiveFlashlightCount <= m_nMaxDepthTextureShadows ); + } + if ( nActiveFlashlightCount > 0 ) { - Assert( ( m_Shadows[ pActiveFlashlights[0] ].m_Flags & SHADOW_FLAGS_FLASHLIGHT ) != 0 ); - shadowmgr->SetFlashlightRenderState( pActiveFlashlights[0] ); + Assert( ( m_Shadows[ pActiveFlashlights[0] ].m_Flags & ( SHADOW_FLAGS_FLASHLIGHT | SHADOW_FLAGS_SIMPLE_PROJECTION ) ) != 0 ); + shadowmgr->SetSinglePassFlashlightRenderState( m_Shadows[ pActiveFlashlights[0] ].m_ShadowHandle ); } else { - shadowmgr->SetFlashlightRenderState( SHADOW_HANDLE_INVALID ); - } + shadowmgr->SetSinglePassFlashlightRenderState( SHADOW_HANDLE_INVALID ); + } +} + + + +//----------------------------------------------------------------------------- +// Kicks off rendering of volumetrics for the flashlights +//----------------------------------------------------------------------------- +void CClientShadowMgr::DrawVolumetrics( const CViewSetup &viewSetup ) +{ + CMatRenderContextPtr pRenderContext( materials ); + PIXEVENT( pRenderContext, "Draw Flashlight Volumetrics" ); + + shadowmgr->DrawVolumetrics(); } +void AddPointToExtentsHelper( const VMatrix &flashlightToWorld, const Vector &vecPos, Vector &vecMin, Vector &vecMax ) +{ + Vector worldSpacePos; + + Vector3DMultiplyPositionProjective( flashlightToWorld, vecPos, worldSpacePos ); + VectorMin( vecMin, worldSpacePos, vecMin ); + VectorMax( vecMax, worldSpacePos, vecMax ); +} + + +void CClientShadowMgr::GetFrustumExtents( ClientShadowHandle_t handle, Vector &vecMin, Vector &vecMax ) +{ + Assert( m_Shadows.IsValidIndex( handle ) ); + + CClientShadowMgr::ClientShadow_t &shadow = m_Shadows[ handle ]; + + VMatrix flashlightToWorld; + MatrixInverseGeneral( shadow.m_WorldToShadow, flashlightToWorld ); + + vecMin = Vector( FLT_MAX, FLT_MAX, FLT_MAX ); + vecMax = Vector( -FLT_MAX, -FLT_MAX, -FLT_MAX ); + + AddPointToExtentsHelper( flashlightToWorld, Vector( 0.0f, 0.0f, 0.0f ), vecMin, vecMax ); + AddPointToExtentsHelper( flashlightToWorld, Vector( 0.0f, 0.0f, 1.0f ), vecMin, vecMax ); + AddPointToExtentsHelper( flashlightToWorld, Vector( 0.0f, 1.0f, 0.0f ), vecMin, vecMax ); + AddPointToExtentsHelper( flashlightToWorld, Vector( 1.0f, 0.0f, 0.0f ), vecMin, vecMax ); + AddPointToExtentsHelper( flashlightToWorld, Vector( 0.0f, 1.0f, 1.0f ), vecMin, vecMax ); + AddPointToExtentsHelper( flashlightToWorld, Vector( 1.0f, 0.0f, 1.0f ), vecMin, vecMax ); + AddPointToExtentsHelper( flashlightToWorld, Vector( 1.0f, 1.0f, 0.0f ), vecMin, vecMax ); + AddPointToExtentsHelper( flashlightToWorld, Vector( 1.0f, 1.0f, 1.0f ), vecMin, vecMax ); +} + //----------------------------------------------------------------------------- // Re-render shadow depth textures that lie in the leaf list //----------------------------------------------------------------------------- void CClientShadowMgr::ComputeShadowDepthTextures( const CViewSetup &viewSetup ) { + if ( !r_flashlightdepthtexture.GetBool() ) + { + // Build list of active flashlights + ClientShadowHandle_t pActiveFlashlights[16]; + int nActiveFlashlights = BuildActiveFlashlightList( viewSetup, ARRAYSIZE( pActiveFlashlights ), pActiveFlashlights ); + SetViewFlashlightState( nActiveFlashlights, pActiveFlashlights ); + return; + } + VPROF_BUDGET( "CClientShadowMgr::ComputeShadowDepthTextures", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING ); CMatRenderContextPtr pRenderContext( materials ); PIXEVENT( pRenderContext, "Shadow Depth Textures" ); - // Build list of active render-to-texture shadows + // Build list of active shadow depth textures / flashlights + int iNumHighRes = 0; ClientShadowHandle_t pActiveDepthShadows[1024]; - int nActiveDepthShadowCount = BuildActiveShadowDepthList( viewSetup, ARRAYSIZE( pActiveDepthShadows ), pActiveDepthShadows ); + int nActiveDepthShadowCount = BuildActiveShadowDepthList( viewSetup, ARRAYSIZE( pActiveDepthShadows ), pActiveDepthShadows, iNumHighRes ); + + int iLowResStart = ( iNumHighRes >= m_nMaxDepthTextureShadows ? 0 : iNumHighRes ); // Iterate over all existing textures and allocate shadow textures bool bDebugFrustum = r_flashlightdrawfrustum.GetBool(); + bool bDebugFrustumBBox = r_flashlightdrawfrustumbbox.GetBool(); for ( int j = 0; j < nActiveDepthShadowCount; ++j ) { ClientShadow_t& shadow = m_Shadows[ pActiveDepthShadows[j] ]; + FlashlightState_t& flashlightState = const_cast( shadowmgr->GetFlashlightState( shadow.m_ShadowHandle ) ); + CTextureReference shadowDepthTexture; - bool bGotShadowDepthTexture = LockShadowDepthTexture( &shadowDepthTexture ); + bool bGotShadowDepthTexture = LockShadowDepthTexture( &shadowDepthTexture, flashlightState.m_bShadowHighRes ? 0 : iLowResStart ); if ( !bGotShadowDepthTexture ) { - // If we don't get one, that means we have too many this frame so bind no depth texture - static int bitchCount = 0; - if( bitchCount < 10 ) - { - Warning( "Too many shadow maps this frame!\n" ); - bitchCount++; - } - - Assert(0); + // If we don't get one, that means all the shadow maps allowed for this fram have already been used, no depth texture shadowmgr->SetFlashlightDepthTexture( shadow.m_ShadowHandle, NULL, 0 ); continue; } @@ -3948,11 +5671,24 @@ void CClientShadowMgr::ComputeShadowDepthTextures( const CViewSetup &viewSetup ) shadowView.x = shadowView.y = 0; shadowView.width = shadowDepthTexture->GetActualWidth(); shadowView.height = shadowDepthTexture->GetActualHeight(); - shadowView.m_bOrtho = false; - shadowView.m_bDoBloomAndToneMapping = false; // Copy flashlight parameters - const FlashlightState_t& flashlightState = shadowmgr->GetFlashlightState( shadow.m_ShadowHandle ); + if ( !flashlightState.m_bOrtho ) + { + shadowView.m_bOrtho = false; + } + else + { + shadowView.m_bOrtho = true; + shadowView.m_OrthoLeft = flashlightState.m_fOrthoLeft; + shadowView.m_OrthoTop = flashlightState.m_fOrthoTop; + shadowView.m_OrthoRight = flashlightState.m_fOrthoRight; + shadowView.m_OrthoBottom = flashlightState.m_fOrthoBottom; + } + + shadowView.m_bDoBloomAndToneMapping = false; + shadowView.m_nMotionBlurMode = MOTION_BLUR_DISABLE; + shadowView.fov = shadowView.fovViewmodel = flashlightState.m_fHorizontalFOVDegrees; shadowView.origin = flashlightState.m_vecLightOrigin; QuaternionAngles( flashlightState.m_quatOrientation, shadowView.angles ); // Convert from Quaternion to QAngle @@ -3963,13 +5699,31 @@ void CClientShadowMgr::ComputeShadowDepthTextures( const CViewSetup &viewSetup ) // Can turn on all light frustum overlays or per light with flashlightState parameter... if ( bDebugFrustum || flashlightState.m_bDrawShadowFrustum ) { - DebugDrawFrustum( shadowView.origin, shadow.m_WorldToShadow ); + if ( flashlightState.m_bUberlight ) + { + DrawUberlightRig( shadowView.origin, shadow.m_WorldToShadow, flashlightState ); + } + + DrawFrustum( shadowView.origin, shadow.m_WorldToShadow ); + } + + if ( bDebugFrustumBBox ) + { + Vector vecExtentsMin, vecExtentsMax; + GetFrustumExtents( pActiveDepthShadows[j], vecExtentsMin, vecExtentsMax ); + + float flVisibleBBoxMinHeight = MIN( vecExtentsMax.z - 1.0f, C_EnvProjectedTexture::GetVisibleBBoxMinHeight() ); + vecExtentsMin.z = MAX( vecExtentsMin.z, flVisibleBBoxMinHeight ); + + NDebugOverlay::Box( Vector( 0.0f, 0.0f, 0.0f ), vecExtentsMin, vecExtentsMax, 0, 0, 255, 100, 0.0f ); } // Set depth bias factors specific to this flashlight CMatRenderContextPtr pRenderContext( materials ); pRenderContext->SetShadowDepthBiasFactors( flashlightState.m_flShadowSlopeScaleDepthBias, flashlightState.m_flShadowDepthBias ); + shadowView.m_bRenderFlashlightDepthTranslucents = flashlightState.m_bGlobalLight; + // Render to the shadow depth texture with appropriate view view->UpdateShadowDepthTexture( m_DummyColorTexture, shadowDepthTexture, shadowView ); @@ -3990,15 +5744,16 @@ static void SetupBonesOnBaseAnimating( C_BaseAnimating *&pBaseAnimating ) } -void CClientShadowMgr::ComputeShadowTextures( const CViewSetup &view, int leafCount, LeafIndex_t* pLeafList ) +void CClientShadowMgr::ComputeShadowTextures( const CViewSetup &view, int leafCount, WorldListLeafData_t* pLeafList ) { + ASSERT_LOCAL_PLAYER_RESOLVABLE(); + int nSlot = GET_ACTIVE_SPLITSCREEN_SLOT(); + VPROF_BUDGET( "CClientShadowMgr::ComputeShadowTextures", VPROF_BUDGETGROUP_SHADOW_RENDERING ); if ( !m_RenderToTextureActive || (r_shadows.GetInt() == 0) || r_shadows_gamecontrol.GetInt() == 0 ) return; - m_bThreaded = false;//( r_threaded_client_shadow_manager.GetBool() && g_pThreadPool->NumIdleThreads() ); - MDLCACHE_CRITICAL_SECTION(); // First grab all shadow textures we may want to render int nCount = s_VisibleShadowList.FindShadows( &view, leafCount, pLeafList ); @@ -4043,42 +5798,19 @@ void CClientShadowMgr::ComputeShadowTextures( const CViewSetup &view, int leafCo int nModelsRendered = 0; int i; - if ( m_bThreaded && g_pThreadPool->NumIdleThreads() ) - { - s_NPCShadowBoneSetups.RemoveAll(); - s_NonNPCShadowBoneSetups.RemoveAll(); - - for (i = 0; i < nCount; ++i) - { - const VisibleShadowInfo_t &info = s_VisibleShadowList.GetVisibleShadow(i); - if ( nModelsRendered < nMaxShadows ) - { - if ( BuildSetupListForRenderToTextureShadow( info.m_hShadow, info.m_flArea ) ) - { - ++nModelsRendered; - } - } - } - - ParallelProcess( "NPCShadowBoneSetups", s_NPCShadowBoneSetups.Base(), s_NPCShadowBoneSetups.Count(), &SetupBonesOnBaseAnimating ); - ParallelProcess( "NonNPCShadowBoneSetups", s_NonNPCShadowBoneSetups.Base(), s_NonNPCShadowBoneSetups.Count(), &SetupBonesOnBaseAnimating ); - - nModelsRendered = 0; - } - for (i = 0; i < nCount; ++i) { const VisibleShadowInfo_t &info = s_VisibleShadowList.GetVisibleShadow(i); if ( nModelsRendered < nMaxShadows ) { - if ( DrawRenderToTextureShadow( info.m_hShadow, info.m_flArea ) ) + if ( DrawRenderToTextureShadow( nSlot, info.m_hShadow, info.m_flArea ) ) { ++nModelsRendered; } } else { - DrawRenderToTextureShadowLOD( info.m_hShadow ); + DrawRenderToTextureShadowLOD( nSlot, info.m_hShadow ); } } @@ -4103,11 +5835,11 @@ void CClientShadowMgr::ComputeShadowTextures( const CViewSetup &view, int leafCo //------------------------------------------------------------------------------------------------------- // Lock down the usage of a shadow depth texture...must be unlocked for use on subsequent views / frames //------------------------------------------------------------------------------------------------------- -bool CClientShadowMgr::LockShadowDepthTexture( CTextureReference *shadowDepthTexture ) +bool CClientShadowMgr::LockShadowDepthTexture( CTextureReference *shadowDepthTexture, int nStartTexture ) { - for ( int i=0; i < m_DepthTextureCache.Count(); i++ ) // Search for cached shadow depth texture + for ( int i = nStartTexture; i < m_DepthTextureCache.Count(); i++ ) // Search for cached shadow depth texture { - if ( m_DepthTextureCacheLocks[i] == false ) // If a free one is found + if ( m_DepthTextureCacheLocks[i] == false && m_DepthTextureCache[i].IsValid() ) // If a free one is found { *shadowDepthTexture = m_DepthTextureCache[i]; m_DepthTextureCacheLocks[i] = true; @@ -4127,7 +5859,9 @@ void CClientShadowMgr::UnlockAllShadowDepthTextures() { m_DepthTextureCacheLocks[i] = false; } - SetViewFlashlightState( 0, NULL ); + + shadowmgr->SetSinglePassFlashlightRenderState( SHADOW_HANDLE_INVALID ); + shadowmgr->PopSinglePassFlashlightStateEnabled(); } void CClientShadowMgr::SetFlashlightTarget( ClientShadowHandle_t shadowHandle, EHANDLE targetEntity ) @@ -4135,7 +5869,7 @@ void CClientShadowMgr::SetFlashlightTarget( ClientShadowHandle_t shadowHandle, E Assert( m_Shadows.IsValidIndex( shadowHandle ) ); CClientShadowMgr::ClientShadow_t &shadow = m_Shadows[ shadowHandle ]; - if( ( shadow.m_Flags & SHADOW_FLAGS_FLASHLIGHT ) == 0 ) + if( ( shadow.m_Flags & ( SHADOW_FLAGS_FLASHLIGHT | SHADOW_FLAGS_SIMPLE_PROJECTION ) ) == 0 ) return; // shadow.m_pTargetRenderable = pRenderable; @@ -4148,7 +5882,7 @@ void CClientShadowMgr::SetFlashlightLightWorld( ClientShadowHandle_t shadowHandl Assert( m_Shadows.IsValidIndex( shadowHandle ) ); ClientShadow_t &shadow = m_Shadows[ shadowHandle ]; - if( ( shadow.m_Flags & SHADOW_FLAGS_FLASHLIGHT ) == 0 ) + if( ( shadow.m_Flags & ( SHADOW_FLAGS_FLASHLIGHT | SHADOW_FLAGS_SIMPLE_PROJECTION ) ) == 0 ) return; if ( bLightWorld ) @@ -4181,6 +5915,690 @@ bool CClientShadowMgr::IsFlashlightTarget( ClientShadowHandle_t shadowHandle, IC return false; } +void CClientShadowMgr::SetShadowFromWorldLightsEnabled( bool bEnable ) +{ + bool bIsShadowingFromWorldLights = IsShadowingFromWorldLights(); + m_bShadowFromWorldLights = bEnable; + if ( bIsShadowingFromWorldLights != IsShadowingFromWorldLights() ) + { + UpdateAllShadows(); + } +} + +void CClientShadowMgr::SuppressShadowFromWorldLights( bool bSuppress ) +{ + bool bIsShadowingFromWorldLights = IsShadowingFromWorldLights(); + m_bSuppressShadowFromWorldLights = bSuppress; + if ( bIsShadowingFromWorldLights != IsShadowingFromWorldLights() ) + { + UpdateAllShadows(); + } +} + +/////////////////////////////////////////////////////////////////////// +// Vertex and index data for cube with degenerate faces on each edge +/////////////////////////////////////////////////////////////////////// + +ALIGN16 static const float pShadowBoundVerts[] = +{ + // +X face + 1.0f, -1.0f, -1.0f, 1.0f, + 1.0f, 1.0f, -1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 1.0f, + 1.0f, -1.0f, 1.0f, 1.0f, + + // +Y face + -1.0f, 1.0f, -1.0f, 1.0f, + -1.0f, 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, -1.0f, 1.0f, + + // -X face + -1.0f, -1.0f, 1.0f, 1.0f, + -1.0f, 1.0f, 1.0f, 1.0f, + -1.0f, 1.0f, -1.0f, 1.0f, + -1.0f, -1.0f, -1.0f, 1.0f, + + // -Y face + -1.0f, -1.0f, -1.0f, 1.0f, + 1.0f, -1.0f, -1.0f, 1.0f, + 1.0f, -1.0f, 1.0f, 1.0f, + -1.0f, -1.0f, 1.0f, 1.0f, + + // +Z face + -1.0f, -1.0f, 1.0f, 1.0f, + 1.0f, -1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 1.0f, + -1.0f, 1.0f, 1.0f, 1.0f, + + // -Z face + 1.0f, -1.0f, -1.0f, 1.0f, + -1.0f, -1.0f, -1.0f, 1.0f, + -1.0f, 1.0f, -1.0f, 1.0f, + 1.0f, 1.0f, -1.0f, 1.0f +}; + +ALIGN16 static const float pShadowBoundNormals[] = +{ + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + -1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, -1.0f, 0.0f, 0.0f, + + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, -1.0f, 0.0f, + +}; + +ALIGN16 static const unsigned short pShadowBoundIndices[] = +{ + // box faces + 0, 2, 1, 0, 3, 2, + 4, 6, 5, 4, 7, 6, + 8, 10, 9, 8, 11, 10, + 12, 14, 13, 12, 15, 14, + 16, 18, 17, 16, 19, 18, + 20, 22, 21, 20, 23, 22, + + // degenerate faces on edges + 2, 7, 1, 2, 6, 7, + 5, 10, 4, 5, 9, 10, + 8, 12, 11, 8, 15, 12, + 14, 0, 13, 14, 3, 0, + + 17, 2, 3, 17, 18, 2, + 18, 5, 6, 18, 19, 5, + 8, 19, 16, 8, 9, 19, + 14, 16, 17, 14, 15, 16, + + 0, 23, 20, 0, 1, 23, + 7, 22, 23, 7, 4, 22, + 11, 21, 22, 11, 22, 10, + 13, 21, 12, 13, 20, 21 +}; + +// Adds a cube with degenerate edge quads to a mesh builder +void CClientShadowMgr::BuildCubeWithDegenerateEdgeQuads( CMeshBuilder& meshBuilder, const matrix3x4_t& objToWorld, const VMatrix& projToShadow, const CClientShadowMgr::ClientShadow_t& shadow ) +{ + static bool bSIMDDataInitialized = false; + static FourVectors srcPositions[6]; + static FourVectors srcNormals[2]; + + if ( !bSIMDDataInitialized ) + { + // convert vertex data into SIMD data + const float* RESTRICT pPos = pShadowBoundVerts; + const float* RESTRICT pNormal = pShadowBoundNormals; + for( int v = 0; v < 6; ++v ) + { + srcPositions[v].LoadAndSwizzleAligned( pPos, pPos+4, pPos+8, pPos+12); + pPos += 16; + } + + srcNormals[0].LoadAndSwizzleAligned( pNormal, pNormal+4, pNormal+8, pNormal+12); + pNormal += 16; + srcNormals[1].LoadAndSwizzleAligned( pNormal, pNormal+4, pNormal+4, pNormal+4); + + bSIMDDataInitialized = true; + } + + Vector fallOffParams; + ComputeFalloffInfo( shadow, &fallOffParams ); + + int nBaseVertIdx = meshBuilder.GetCurrentVertex(); + + float texCoord[4] = { shadow.m_TexCoordOffset.x, shadow.m_TexCoordOffset.y, shadow.m_TexCoordScale.x, shadow.m_TexCoordScale.y }; + Vector shadowDir = shadow.m_ShadowDir * shadow.m_MaxDist; + + if ( r_shadow_deferred_simd.GetBool() ) + { + // FIXME: Something in here is buggy + FourVectors positions[6]; + FourVectors normals[2]; + positions[0] = srcPositions[0]; + positions[1] = srcPositions[1]; + positions[2] = srcPositions[2]; + positions[3] = srcPositions[3]; + positions[4] = srcPositions[4]; + positions[5] = srcPositions[5]; + positions[0].TransformBy( objToWorld ); + positions[1].TransformBy( objToWorld ); + positions[2].TransformBy( objToWorld ); + positions[3].TransformBy( objToWorld ); + positions[4].TransformBy( objToWorld ); + positions[5].TransformBy( objToWorld ); + //FourVectors::TransformManyBy( srcPositions, 6, objToWorld, positions ); // this doesn't work but the above does. What gives??? + FourVectors::RotateManyBy( srcNormals, 2, objToWorld, normals ); + normals[0].VectorNormalizeFast(); // optional, will throw asserts in debug if we don't normalize + normals[1].VectorNormalizeFast(); + + for( int v = 0; v < ARRAYSIZE( pShadowBoundVerts ) / 4; ++v ) + { + meshBuilder.Position3fv( positions[v/4].Vec( v%4 ).Base() ); + meshBuilder.Normal3fv( normals[v/16].Vec( (v/4)%4 ).Base() ); + meshBuilder.TexCoord3fv( 0, shadowDir.Base() ); + meshBuilder.TexCoord4fv( 1, texCoord ); + meshBuilder.TexCoord4fv( 2, projToShadow[0] ); + meshBuilder.TexCoord4fv( 3, projToShadow[1] ); + meshBuilder.TexCoord4fv( 4, projToShadow[2] ); + meshBuilder.TexCoord4fv( 5, projToShadow[3] ); + meshBuilder.TexCoord3fv( 6, fallOffParams.Base() ); + meshBuilder.AdvanceVertex(); + } + } + else + { + const float* pPos = pShadowBoundVerts; + const float* pNormal = pShadowBoundNormals; + for( int v = 0; v < ARRAYSIZE( pShadowBoundVerts ) / 4; ++v ) + { + Vector pos; + Vector normal; + VectorTransform( pPos, objToWorld, (float*)&pos ); + VectorRotate( pNormal, objToWorld, (float*)&normal ); + + meshBuilder.Position3fv( pos.Base() ); + meshBuilder.Normal3fv( normal.Base() ); + meshBuilder.TexCoord3fv( 0, shadowDir.Base() ); + meshBuilder.TexCoord4fv( 1, texCoord ); + meshBuilder.TexCoord4fv( 2, projToShadow[0] ); + meshBuilder.TexCoord4fv( 3, projToShadow[1] ); + meshBuilder.TexCoord4fv( 4, projToShadow[2] ); + meshBuilder.TexCoord4fv( 5, projToShadow[3] ); + meshBuilder.TexCoord3fv( 6, fallOffParams.Base() ); + meshBuilder.AdvanceVertex(); + + pPos += 4; + if ( v % 4 == 3) + pNormal += 4; + } + } + + for( int i = 0; i < ARRAYSIZE( pShadowBoundIndices ) / 2; ++i ) + { + // this causes alignment exception on 360? + //meshBuilder.FastIndex2( nBaseVertIdx + pShadowBoundIndices[2*i], nBaseVertIdx + pShadowBoundIndices[2*i+1] ); + meshBuilder.FastIndex( nBaseVertIdx + pShadowBoundIndices[2*i] ); + meshBuilder.FastIndex( nBaseVertIdx + pShadowBoundIndices[2*i+1] ); + } +} + +struct IntersectingShadowInfo_t +{ + ClientShadowHandle_t h; + matrix3x4_t objToWorld; +}; + +// Sets up rendering info for deferred shadows +bool CClientShadowMgr::SetupDeferredShadow( const ClientShadow_t& shadow, const Vector& camPos, matrix3x4_t* pObjToWorldMat ) const +{ + IClientRenderable *pRenderable = ClientEntityList().GetClientRenderableFromHandle( shadow.m_Entity ); + + Vector mins; + Vector maxs; + pRenderable->GetShadowRenderBounds( mins, maxs, GetActualShadowCastType( pRenderable ) ); + Vector center = mins + maxs; + center *= 0.5f; + Vector dims = maxs - mins; + dims *= 0.5f; + + matrix3x4_t scaleAndOffset ( dims.x, 0.0f, 0.0f, center.x, + 0.0f, dims.y, 0.0f, center.y, + 0.0f, 0.0f, dims.z, center.z ); + + matrix3x4_t objToWorld; + AngleMatrix( pRenderable->GetRenderAngles(), pRenderable->GetRenderOrigin(), objToWorld ); + matrix3x4_t worldToObj; + MatrixInvert( objToWorld, worldToObj ); + MatrixMultiply( objToWorld, scaleAndOffset, objToWorld ); + + MatrixCopy( objToWorld, *pObjToWorldMat ); + + // test if camera is inside shadow volume + Vector shadowDirObjSpace; + Vector camPosObjSpace; + VectorRotate( shadow.m_ShadowDir, worldToObj, shadowDirObjSpace ); + VectorTransform( camPos, worldToObj, camPosObjSpace ); + BoxTraceInfo_t ti; + + if ( IntersectRayWithBox( camPosObjSpace, -shadow.m_MaxDist*shadowDirObjSpace, mins, maxs, 0.0f, &ti ) ) + { + return true; + } + + return false; +} + +void CClientShadowMgr::DownsampleDepthBuffer( IMatRenderContext* pRenderContext, const VMatrix& invViewProjMat ) +{ + int nScreenWidth, nScreenHeight, nDummy; + pRenderContext->GetViewport( nDummy, nDummy, nScreenWidth, nScreenHeight ); + + int nWidth = m_downSampledNormals->GetActualWidth(); + int nHeight = m_downSampledNormals->GetActualHeight(); + pRenderContext->PushRenderTargetAndViewport( m_downSampledNormals, 0, 0, nWidth, nHeight ); + + IMaterial* pMat = materials->FindMaterial( "dev/downsampledepth", TEXTURE_GROUP_OTHER ); + + // yes, this is stupid + IMaterialVar* pVar = pMat->FindVar( "$c0_x", NULL ); + pVar->SetFloatValue( invViewProjMat[0][0] ); + pVar = pMat->FindVar( "$c0_y", NULL ); + pVar->SetFloatValue( invViewProjMat[0][1] ); + pVar = pMat->FindVar( "$c0_z", NULL ); + pVar->SetFloatValue( invViewProjMat[0][2] ); + pVar = pMat->FindVar( "$c0_w", NULL ); + pVar->SetFloatValue( invViewProjMat[0][3] ); + pVar = pMat->FindVar( "$c1_x", NULL ); + pVar->SetFloatValue( invViewProjMat[1][0] ); + pVar = pMat->FindVar( "$c1_y", NULL ); + pVar->SetFloatValue( invViewProjMat[1][1] ); + pVar = pMat->FindVar( "$c1_z", NULL ); + pVar->SetFloatValue( invViewProjMat[1][2] ); + pVar = pMat->FindVar( "$c1_w", NULL ); + pVar->SetFloatValue( invViewProjMat[1][3] ); + pVar = pMat->FindVar( "$c2_x", NULL ); + pVar->SetFloatValue( invViewProjMat[2][0] ); + pVar = pMat->FindVar( "$c2_y", NULL ); + pVar->SetFloatValue( invViewProjMat[2][1] ); + pVar = pMat->FindVar( "$c2_z", NULL ); + pVar->SetFloatValue( invViewProjMat[2][2] ); + pVar = pMat->FindVar( "$c2_w", NULL ); + pVar->SetFloatValue( invViewProjMat[2][3] ); + pVar = pMat->FindVar( "$c3_x", NULL ); + pVar->SetFloatValue( invViewProjMat[3][0] ); + pVar = pMat->FindVar( "$c3_y", NULL ); + pVar->SetFloatValue( invViewProjMat[3][1] ); + pVar = pMat->FindVar( "$c3_z", NULL ); + pVar->SetFloatValue( invViewProjMat[3][2] ); + pVar = pMat->FindVar( "$c3_w", NULL ); + pVar->SetFloatValue( invViewProjMat[3][3] ); + + pVar = pMat->FindVar( "$c4_x", NULL ); + pVar->SetFloatValue( 1.0f / float( nScreenWidth ) ); + pVar = pMat->FindVar( "$c4_y", NULL ); + pVar->SetFloatValue( 1.0f / float( nScreenHeight ) ); + + pRenderContext->DrawScreenSpaceRectangle( pMat, 0, 0, nWidth, nHeight, + 0, 0, 2*nWidth-2, 2*nHeight-2, + 2*nWidth, 2*nHeight ); + + if ( IsX360() ) + { + pRenderContext->CopyRenderTargetToTextureEx( m_downSampledNormals, 0, NULL, NULL ); + pRenderContext->CopyRenderTargetToTextureEx( m_downSampledDepth, -1, NULL, NULL ); + } + + pRenderContext->PopRenderTargetAndViewport(); +} + +void CClientShadowMgr::CompositeDeferredShadows( IMatRenderContext* pRenderContext ) +{ + int nWidth, nHeight, nDummy; + pRenderContext->GetViewport( nDummy, nDummy, nWidth, nHeight ); + IMaterial* pMat = materials->FindMaterial( "dev/compositedeferredshadow", TEXTURE_GROUP_OTHER ); + + /* + IMaterialVar* pMatVar = pMat->FindVar( "$basetexture", NULL, false ); + if ( pMatVar ) + { + ITexture *pFullScreen = materials->FindTexture( "_rt_FullFrameFB1", TEXTURE_GROUP_RENDER_TARGET ); + pMatVar->SetTextureValue( pFullScreen ); + } + */ + + pRenderContext->DrawScreenSpaceRectangle( pMat, 0, 0, nWidth, nHeight, + 0, 0, 2*nWidth-2, 2*nHeight-2, + 2*nWidth, 2*nHeight ); +} + +void CClientShadowMgr::ComputeFalloffInfo( const ClientShadow_t& shadow, Vector* pShadowFalloffParams ) +{ + float flFalloffOffset = 0.7f * shadow.m_FalloffStart; // pull the offset in a little to hide the shadow darkness discontinuity + + float flFalloffDist = shadow.m_MaxDist - flFalloffOffset; + float flOOZFalloffDist = ( flFalloffDist > 0.0f ) ? 1.0f / flFalloffDist : 1.0f; + + // for use in the shader + pShadowFalloffParams->x = -flFalloffOffset * flOOZFalloffDist; + pShadowFalloffParams->y = flOOZFalloffDist; + pShadowFalloffParams->z = 1.0f/255.0f * shadow.m_FalloffBias; +} + +void CClientShadowMgr::DrawDeferredShadows( const CViewSetup &view, int leafCount, WorldListLeafData_t* pLeafList ) +{ + VPROF_BUDGET( __FUNCTION__, VPROF_BUDGETGROUP_SHADOW_RENDERING ); + + if ( !IsX360() ) + { + return; + } + + // We assume the visible shadow list was updated in ComputeShadowTextures. This is only correct if we're not rendering from multiple view points. + + int nNumShadows = s_VisibleShadowList.GetVisibleShadowCount(); + if ( nNumShadows == 0 ) + { + return; + } + + IntersectingShadowInfo_t* pInsideVolume = (IntersectingShadowInfo_t*)stackalloc( nNumShadows * sizeof(IntersectingShadowInfo_t) ); + int nNumInsideVolumes = 0; + + CMatRenderContextPtr pRenderContext( materials ); + + PIXEVENT( pRenderContext, "DEFERRED_SHADOWS" ); + + matrix3x4_t viewMatrix; + pRenderContext->GetMatrix( MATERIAL_VIEW, &viewMatrix ); + + VMatrix projMatrix; + pRenderContext->GetMatrix( MATERIAL_PROJECTION, &projMatrix ); + + VMatrix viewProjMatrix; + VMatrix invViewProjMatrix; + MatrixMultiply( projMatrix, VMatrix(viewMatrix), viewProjMatrix ); + MatrixInverseGeneral( viewProjMatrix, invViewProjMatrix ); + + ShaderStencilState_t state; + state.m_bEnable = true; + state.m_nWriteMask = 0xFF; + state.m_nTestMask = 0x1 << 2; + state.m_nReferenceValue = 0x0; + state.m_CompareFunc = SHADER_STENCILFUNC_EQUAL; + state.m_PassOp = SHADER_STENCILOP_KEEP; + state.m_FailOp = SHADER_STENCILOP_KEEP; + state.m_ZFailOp = SHADER_STENCILOP_KEEP; +#if defined( _X360 ) + state.m_bHiStencilEnable = true; + state.m_bHiStencilWriteEnable = false; + state.m_HiStencilCompareFunc = SHADER_HI_STENCILFUNC_EQUAL; + state.m_nHiStencilReferenceValue = 0; +#endif + +#ifdef _X360 + pRenderContext->PushVertexShaderGPRAllocation( 16 ); +#endif + + if ( r_shadow_deferred_downsample.GetBool() ) + { + DownsampleDepthBuffer( pRenderContext, invViewProjMatrix ); + + int nWidth = m_downSampledNormals->GetActualWidth(); + int nHeight = m_downSampledNormals->GetActualHeight(); + pRenderContext->PushRenderTargetAndViewport( m_downSampledNormals, 0, 0, nWidth, nHeight ); + } + else + { + pRenderContext->SetStencilState( state ); +#if defined( _X360 ) + pRenderContext->FlushHiStencil(); +#endif + } + + pRenderContext->MatrixMode( MATERIAL_MODEL ); + pRenderContext->PushMatrix(); + pRenderContext->LoadIdentity(); + + IMaterialVar* pTextureVar = m_RenderDeferredShadowMat->FindVar( "$basetexture", NULL, false ); + if( pTextureVar ) + { + pTextureVar->SetTextureValue( s_ClientShadowMgr.GetShadowTexture( CLIENTSHADOW_INVALID_HANDLE ) ); + } + pTextureVar = m_RenderDeferredShadowMat->FindVar( "$depthtexture", NULL, false ); + if( pTextureVar ) + { + //pTextureVar->SetTextureValue( s_ClientShadowMgr.GetShadowTexture( CLIENTSHADOW_INVALID_HANDLE ) ); + pTextureVar->SetTextureValue( GetFullFrameDepthTexture() ); + } + + IMaterialVar* pZFailVar = m_RenderDeferredShadowMat->FindVar( "$zfailenable", NULL, false ); + + if( pZFailVar ) + { + pZFailVar->SetIntValue( 0 ); + } + pRenderContext->Bind( m_RenderDeferredShadowMat ); + + Vector camPos; + pRenderContext->GetWorldSpaceCameraPosition( &camPos ); + + IMesh* pMesh = pRenderContext->GetDynamicMesh(); + CMeshBuilder meshBuilder; + + int nMaxVerts, nMaxIndices; + pRenderContext->GetMaxToRender( pMesh, false, &nMaxVerts, &nMaxIndices ); + int nMaxShadowsPerBatch = MIN( nMaxVerts / ( ARRAYSIZE( pShadowBoundVerts ) / 4 ), nMaxIndices / ARRAYSIZE( pShadowBoundIndices ) ); + + meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, nMaxShadowsPerBatch * ARRAYSIZE( pShadowBoundVerts ) / 4, nMaxShadowsPerBatch * ARRAYSIZE( pShadowBoundIndices ) ); + int nNumShadowsBatched = 0; + + // Z-Pass shadow volumes + for ( int i = 0; i < nNumShadows; ++i ) + { + const VisibleShadowInfo_t& vsi = s_VisibleShadowList.GetVisibleShadow( i ); + ClientShadow_t& shadow = m_Shadows[vsi.m_hShadow]; + + matrix3x4_t objToWorld; + if ( SetupDeferredShadow( shadow, camPos, &objToWorld ) ) + { + pInsideVolume[nNumInsideVolumes].h = vsi.m_hShadow; + MatrixCopy( objToWorld, pInsideVolume[nNumInsideVolumes].objToWorld ); + nNumInsideVolumes++; + continue; + } + + VMatrix projToTextureMatrix; + MatrixMultiply( shadow.m_WorldToTexture, invViewProjMatrix, projToTextureMatrix ); + + // create extruded bounding geometry + BuildCubeWithDegenerateEdgeQuads( meshBuilder, objToWorld, projToTextureMatrix, shadow ); + nNumShadowsBatched++; + if ( nNumShadowsBatched == nMaxShadowsPerBatch ) + { + // flush + meshBuilder.End(); + pMesh->Draw(); + meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, nMaxShadowsPerBatch * ARRAYSIZE( pShadowBoundVerts ) / 4, nMaxShadowsPerBatch * ARRAYSIZE( pShadowBoundIndices ) ); + nNumShadowsBatched = 0; + } + } + + // render + meshBuilder.End(); + if ( nNumShadowsBatched > 0 ) + { + pMesh->Draw(); + nNumShadowsBatched = 0; + } + else + { + pMesh->MarkAsDrawn(); + } + + // draw deferred blobby shadow volumes + if ( s_VisibleShadowList.GetVisibleBlobbyShadowCount() > 0 ) + { + pRenderContext->Bind( m_RenderDeferredSimpleShadowMat ); + pTextureVar = m_RenderDeferredSimpleShadowMat->FindVar( "$depthtexture", NULL, false ); + if( pTextureVar ) + { + pTextureVar->SetTextureValue( GetFullFrameDepthTexture() ); + } + + int nNumShadows = s_VisibleShadowList.GetVisibleBlobbyShadowCount(); + meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, nMaxShadowsPerBatch * ARRAYSIZE( pShadowBoundVerts ) / 4, nMaxShadowsPerBatch * ARRAYSIZE( pShadowBoundIndices ) ); + + for ( int i = 0; i < nNumShadows; ++i ) + { + const VisibleShadowInfo_t& vsi = s_VisibleShadowList.GetVisibleBlobbyShadow( i ); + ClientShadow_t& shadow = m_Shadows[vsi.m_hShadow]; + + matrix3x4_t objToWorld; + if ( SetupDeferredShadow( shadow, camPos, &objToWorld ) ) + { + //DevWarning( "Blobby shadow needs z-fail rendering. Skipped.\n" ); + continue; + } + + VMatrix projToTextureMatrix; + MatrixMultiply( shadow.m_WorldToTexture, invViewProjMatrix, projToTextureMatrix ); + + // create extruded bounding geometry + BuildCubeWithDegenerateEdgeQuads( meshBuilder, objToWorld, projToTextureMatrix, shadow ); + nNumShadowsBatched++; + if ( nNumShadowsBatched == nMaxShadowsPerBatch ) + { + // flush + meshBuilder.End(); + pMesh->Draw(); + meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, nMaxShadowsPerBatch * ARRAYSIZE( pShadowBoundVerts ) / 4, nMaxShadowsPerBatch * ARRAYSIZE( pShadowBoundIndices ) ); + nNumShadowsBatched = 0; + } + } + + // render + meshBuilder.End(); + if ( nNumShadowsBatched > 0 ) + { + pMesh->Draw(); + nNumShadowsBatched = 0; + } + else + { + pMesh->MarkAsDrawn(); + } + } + + // draw zfail volumes + if ( nNumInsideVolumes > 0 ) + { + pRenderContext->CullMode( MATERIAL_CULLMODE_CW ); + if( pZFailVar ) + { + pZFailVar->SetIntValue( 1 ); + } + pRenderContext->Bind( m_RenderDeferredShadowMat ); + + //IMesh* pMesh = pRenderContext->GetDynamicMesh(); + meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, nMaxShadowsPerBatch * ARRAYSIZE( pShadowBoundVerts ) / 4, nMaxShadowsPerBatch * ARRAYSIZE( pShadowBoundIndices ) ); + for ( int i = 0; i < nNumInsideVolumes; ++i ) + { + ClientShadow_t& shadow = m_Shadows[pInsideVolume[i].h]; + + VMatrix projToTextureMatrix; + MatrixMultiply( shadow.m_WorldToTexture, invViewProjMatrix, projToTextureMatrix ); + + // create extruded bounding geometry + BuildCubeWithDegenerateEdgeQuads( meshBuilder, pInsideVolume[i].objToWorld, projToTextureMatrix, shadow ); + nNumShadowsBatched++; + if ( nNumShadowsBatched == nMaxShadowsPerBatch ) + { + // flush + meshBuilder.End(); + pMesh->Draw(); + //pMesh = pRenderContext->GetDynamicMesh(); + meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, nMaxShadowsPerBatch * ARRAYSIZE( pShadowBoundVerts ) / 4, nMaxShadowsPerBatch * ARRAYSIZE( pShadowBoundIndices ) ); + nNumShadowsBatched = 0; + } + } + meshBuilder.End(); + if ( nNumShadowsBatched > 0 ) + { + pMesh->Draw(); + nNumShadowsBatched = 0; + } + else + { + pMesh->MarkAsDrawn(); + } + } + + pRenderContext->PopMatrix(); + // reset culling + pRenderContext->CullMode( MATERIAL_CULLMODE_CCW ); + + if ( r_shadow_deferred_downsample.GetBool() ) + { + pRenderContext->CopyRenderTargetToTextureEx( m_downSampledNormals, 0, NULL, NULL ); + pRenderContext->PopRenderTargetAndViewport(); + + pRenderContext->SetStencilState( state ); + + CompositeDeferredShadows( pRenderContext ); + } + + ShaderStencilState_t stateDisable; + stateDisable.m_bEnable = false; +#if defined( _X360 ) + stateDisable.m_bHiStencilEnable = false; + stateDisable.m_bHiStencilWriteEnable = false; +#endif + pRenderContext->SetStencilState( stateDisable ); + +#ifdef _X360 + pRenderContext->PopVertexShaderGPRAllocation(); +#endif + + // NOTE: We could use geometry instancing for drawing the extruded bounding boxes +} + +void DeferredShadowToggleCallback( IConVar*, const char *, float ) +{ + if ( !IsX360() ) + { + DevMsg( "Deferred shadow rendering only supported on the 360.\n" ); + return; + } + + s_ClientShadowMgr.UpdateAllShadows(); + s_ClientShadowMgr.RemoveAllShadowDecals(); +} + +void DeferredShadowDownsampleToggleCallback( IConVar *var, const char *pOldValue, float flOldValue ) +{ + s_ClientShadowMgr.ShutdownDeferredShadows(); + s_ClientShadowMgr.InitDeferredShadows(); +} + + +void CClientShadowMgr::UpdateSplitscreenLocalPlayerShadowSkip() +{ + // Don't draw the current splitscreen player's own shadow + if ( engine->IsSplitScreenActive() ) + { + ASSERT_LOCAL_PLAYER_RESOLVABLE(); + + C_BasePlayer* pPlayer = C_BasePlayer::GetLocalPlayer(); + C_BasePlayer* pFirstPersonEnt = pPlayer; + if ( pPlayer ) + { + if ( pPlayer->GetObserverMode() == OBS_MODE_IN_EYE ) + { + pFirstPersonEnt = ToBasePlayer( pPlayer->GetObserverTarget() ); + } + else if ( pPlayer->GetObserverMode() != OBS_MODE_NONE ) + { + pFirstPersonEnt = NULL; + } + } + + // pFirstPersonEnt NULL only if the player is spectating, but not first-person-spectating + if ( pFirstPersonEnt ) + { + shadowmgr->SkipShadowForEntity( pFirstPersonEnt->entindex() ); + } + else + { + shadowmgr->SkipShadowForEntity( INT_MIN ); // pick an entindex that is guaranteed not to be used by anything + } + } + else + { + shadowmgr->SkipShadowForEntity( INT_MIN ); // pick an entindex that is guaranteed not to be used by anything + } +} + //----------------------------------------------------------------------------- // A material proxy that resets the base texture to use the rendered shadow //----------------------------------------------------------------------------- @@ -4196,11 +6614,13 @@ class CShadowProxy : public IMaterialProxy private: IMaterialVar* m_BaseTextureVar; + IMaterialVar* m_MaxFalloffAmountVar; }; CShadowProxy::CShadowProxy() +: m_BaseTextureVar( NULL ), + m_MaxFalloffAmountVar( NULL ) { - m_BaseTextureVar = NULL; } CShadowProxy::~CShadowProxy() @@ -4212,18 +6632,18 @@ bool CShadowProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues ) { bool foundVar; m_BaseTextureVar = pMaterial->FindVar( "$basetexture", &foundVar, false ); + if ( !foundVar ) + return false; + m_MaxFalloffAmountVar = pMaterial->FindVar( "$maxfalloffamount", &foundVar, false ); return foundVar; } void CShadowProxy::OnBind( void *pProxyData ) { - unsigned short clientShadowHandle = ( unsigned short )(intp)pProxyData&0xffff; + unsigned short clientShadowHandle = ( unsigned short )(int)pProxyData&0xffff; ITexture* pTex = s_ClientShadowMgr.GetShadowTexture( clientShadowHandle ); m_BaseTextureVar->SetTextureValue( pTex ); - if ( ToolsEnabled() ) - { - ToolFramework_RecordMaterialParams( GetMaterial() ); - } + m_MaxFalloffAmountVar->SetFloatValue( MAX_FALLOFF_AMOUNT ); } IMaterial *CShadowProxy::GetMaterial() @@ -4231,7 +6651,7 @@ IMaterial *CShadowProxy::GetMaterial() return m_BaseTextureVar->GetOwningMaterial(); } -EXPOSE_INTERFACE( CShadowProxy, IMaterialProxy, "Shadow" IMATERIAL_PROXY_INTERFACE_VERSION ); +EXPOSE_MATERIAL_PROXY( CShadowProxy, Shadow ); @@ -4301,7 +6721,7 @@ bool CShadowModelProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues ) void CShadowModelProxy::OnBind( void *pProxyData ) { - unsigned short clientShadowHandle = ( unsigned short )((intp)pProxyData&0xffff); + unsigned short clientShadowHandle = ( unsigned short )((int)pProxyData&0xffff); ITexture* pTex = s_ClientShadowMgr.GetShadowTexture( clientShadowHandle ); m_BaseTextureVar->SetTextureValue( pTex ); @@ -4312,11 +6732,6 @@ void CShadowModelProxy::OnBind( void *pProxyData ) m_FalloffOffsetVar->SetFloatValue( info.m_FalloffOffset ); m_FalloffDistanceVar->SetFloatValue( info.m_MaxDist ); m_FalloffAmountVar->SetFloatValue( info.m_FalloffAmount ); - - if ( ToolsEnabled() ) - { - ToolFramework_RecordMaterialParams( GetMaterial() ); - } } IMaterial *CShadowModelProxy::GetMaterial() @@ -4324,4 +6739,4 @@ IMaterial *CShadowModelProxy::GetMaterial() return m_BaseTextureVar->GetOwningMaterial(); } -EXPOSE_INTERFACE( CShadowModelProxy, IMaterialProxy, "ShadowModel" IMATERIAL_PROXY_INTERFACE_VERSION ); +EXPOSE_MATERIAL_PROXY( CShadowModelProxy, ShadowModel ); diff --git a/game/client/clientsideeffects.cpp b/game/client/clientsideeffects.cpp index b9cb5f569..304a9f97f 100644 --- a/game/client/clientsideeffects.cpp +++ b/game/client/clientsideeffects.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // diff --git a/game/client/clientsideeffects.h b/game/client/clientsideeffects.h index c5aa4fd68..5a557d96c 100644 --- a/game/client/clientsideeffects.h +++ b/game/client/clientsideeffects.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // @@ -59,7 +59,6 @@ abstract_class IEffectsList extern IEffectsList *clienteffects; class IMaterialSystem; -extern IMaterialSystem *materials; //Actual function references void FX_AddCube( const Vector &mins, const Vector &maxs, const Vector &vColor, float life, const char *materialName ); diff --git a/game/client/clientsideeffects_test.cpp b/game/client/clientsideeffects_test.cpp index 8d1e3858d..d64805d2a 100644 --- a/game/client/clientsideeffects_test.cpp +++ b/game/client/clientsideeffects_test.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // @@ -16,19 +16,19 @@ #include "SoundEmitterSystem/isoundemittersystembase.h" #include "tier0/vprof.h" -#include "collisionutils.h" -#include "clienteffectprecachesystem.h" +#include "CollisionUtils.h" +#include "precache_register.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" //FIXME: All these functions will be moved out to FX_Main.CPP or a individual folder -CLIENTEFFECT_REGISTER_BEGIN( PrecacheEffectsTest ) -CLIENTEFFECT_MATERIAL( "effects/spark" ) -CLIENTEFFECT_MATERIAL( "effects/gunshiptracer" ) -CLIENTEFFECT_MATERIAL( "effects/bluespark" ) -CLIENTEFFECT_REGISTER_END() +PRECACHE_REGISTER_BEGIN( GLOBAL, PrecacheEffectsTest ) +PRECACHE( MATERIAL, "effects/spark" ) +PRECACHE( MATERIAL, "effects/gunshiptracer" ) +PRECACHE( MATERIAL, "effects/bluespark" ) +PRECACHE_REGISTER_END() //----------------------------------------------------------------------------- // Purpose: @@ -208,19 +208,22 @@ CBulletWhizTimer g_BulletWhiz( "CBulletWhizTimer" ); //----------------------------------------------------------------------------- #define LISTENER_HEIGHT 24 +ConVar cl_tracer_whiz_distance( "cl_tracer_whiz_distance", "72" ); // putting TRACER_MAX_HEAR_DIST on a cvar, so KellyT can find a good value + void FX_TracerSound( const Vector &start, const Vector &end, int iTracerType ) { const char *pszSoundName = NULL; float flWhizDist = TRACER_MAX_HEAR_DIST; float flMinWhizTime = TRACER_SOUND_TIME_MIN; float flMaxWhizTime = TRACER_SOUND_TIME_MAX; - Vector vecListenOrigin = MainViewOrigin(); + HACK_GETLOCALPLAYER_GUARD( "FX_TracerSound" ); + Vector vecListenOrigin = MainViewOrigin(GET_ACTIVE_SPLITSCREEN_SLOT()); switch( iTracerType ) { case TRACER_TYPE_DEFAULT: { pszSoundName = "Bullets.DefaultNearmiss"; - flWhizDist = 24; + flWhizDist = cl_tracer_whiz_distance.GetFloat(); // was 24 Ray_t bullet, listener; bullet.Init( start, end ); @@ -231,7 +234,7 @@ void FX_TracerSound( const Vector &start, const Vector &end, int iTracerType ) float s, t; IntersectRayWithRay( bullet, listener, s, t ); - t = clamp( t, 0.f, 1.f ); + t = clamp( t, 0, 1 ); vecListenOrigin.z -= t * LISTENER_HEIGHT; } break; @@ -278,7 +281,7 @@ void FX_TracerSound( const Vector &start, const Vector &end, int iTracerType ) CLocalPlayerFilter filter; enginesound->EmitSound( filter, SOUND_FROM_WORLD, CHAN_STATIC, params.soundname, - params.volume, SNDLVL_TO_ATTN(params.soundlevel), 0, params.pitch, 0, &start, &shotDir, NULL); + params.volume, SNDLVL_TO_ATTN(params.soundlevel), 0, params.pitch, &start, &shotDir, false); } // FIXME: This has a bad behavior when both bullet + strider shots are whizzing by at the same time @@ -298,15 +301,24 @@ void FX_Tracer( Vector& start, Vector& end, int velocity, bool makeWhiz ) VectorSubtract( end, start, dir ); dist = VectorNormalize( dir ); + int minDist; + float flMinWidth; + float flMaxWidth; + // Don't make short tracers. - if ( dist >= 256 ) + minDist = 256; + flMinWidth = 0.75; + flMaxWidth = 0.9; + + + if ( dist >= minDist ) { float length = random->RandomFloat( 64.0f, 128.0f ); float life = ( dist + length ) / velocity; //NOTENOTE: We want the tail to finish its run as well //Add it - FX_AddDiscreetLine( start, dir, velocity, length, dist, random->RandomFloat( 0.75f, 0.9f ), life, "effects/spark" ); + FX_AddDiscreetLine( start, dir, velocity, length, dist, random->RandomFloat( flMinWidth, flMaxWidth ), life, "effects/spark" ); } if( makeWhiz ) diff --git a/game/client/clientsteamcontext.cpp b/game/client/clientsteamcontext.cpp deleted file mode 100644 index df1f921d9..000000000 --- a/game/client/clientsteamcontext.cpp +++ /dev/null @@ -1,131 +0,0 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// -#include "cbase.h" -#include "clientsteamcontext.h" - -// memdbgon must be the last include file in a .cpp file!!! -#include "tier0/memdbgon.h" - -static CClientSteamContext g_ClientSteamContext; -CClientSteamContext &ClientSteamContext() -{ - return g_ClientSteamContext; -} - -CSteamAPIContext *steamapicontext = &g_ClientSteamContext; - -//----------------------------------------------------------------------------- -CClientSteamContext::CClientSteamContext() -#if !defined(NO_STEAM) -: - m_CallbackSteamServersDisconnected( this, &CClientSteamContext::OnSteamServersDisconnected ), - m_CallbackSteamServerConnectFailure( this, &CClientSteamContext::OnSteamServerConnectFailure ), - m_CallbackSteamServersConnected( this, &CClientSteamContext::OnSteamServersConnected ) -#endif -{ - m_bActive = false; - m_bLoggedOn = false; - m_nAppID = 0; -} - - -//----------------------------------------------------------------------------- -CClientSteamContext::~CClientSteamContext() -{ -} - - -//----------------------------------------------------------------------------- -// Purpose: Unload the steam3 engine -//----------------------------------------------------------------------------- -void CClientSteamContext::Shutdown() -{ - if ( !m_bActive ) - return; - - m_bActive = false; - m_bLoggedOn = false; -#if !defined( NO_STEAM ) - Clear(); // Steam API context shutdown -#endif -} - -//----------------------------------------------------------------------------- -// Purpose: Initialize the steam3 connection -//----------------------------------------------------------------------------- -void CClientSteamContext::Activate() -{ - if ( m_bActive ) - return; - - m_bActive = true; - -#if !defined( NO_STEAM ) - SteamAPI_InitSafe(); // ignore failure, that will fall out later when they don't get a valid logon cookie - SteamAPI_SetTryCatchCallbacks( false ); // We don't use exceptions, so tell steam not to use try/catch in callback handlers - Init(); // Steam API context init - - UpdateLoggedOnState(); - Msg( "CClientSteamContext logged on = %d\n", m_bLoggedOn ); -#endif -} - -void CClientSteamContext::UpdateLoggedOnState() -{ - bool bPreviousLoggedOn = m_bLoggedOn; - m_bLoggedOn = ( SteamUser() && SteamUtils() && SteamUser()->BLoggedOn() ); - - if ( !bPreviousLoggedOn && m_bLoggedOn ) - { - // update Steam info - m_SteamIDLocalPlayer = SteamUser()->GetSteamID(); - m_nUniverse = SteamUtils()->GetConnectedUniverse(); - m_nAppID = SteamUtils()->GetAppID(); - } - - if ( bPreviousLoggedOn != m_bLoggedOn ) - { - // Notify any listeners of the change in logged on state - SteamLoggedOnChange_t loggedOnChange; - loggedOnChange.bPreviousLoggedOn = bPreviousLoggedOn; - loggedOnChange.bLoggedOn = m_bLoggedOn; - InvokeCallbacks( loggedOnChange ); - } -} - -#if !defined(NO_STEAM) -void CClientSteamContext::OnSteamServersDisconnected( SteamServersDisconnected_t *pDisconnected ) -{ - UpdateLoggedOnState(); - Msg( "CClientSteamContext OnSteamServersDisconnected logged on = %d\n", m_bLoggedOn ); -} - -void CClientSteamContext::OnSteamServerConnectFailure( SteamServerConnectFailure_t *pConnectFailure ) -{ - UpdateLoggedOnState(); - Msg( "CClientSteamContext OnSteamServerConnectFailure logged on = %d\n", m_bLoggedOn ); -} - -void CClientSteamContext::OnSteamServersConnected( SteamServersConnected_t *pConnected ) -{ - UpdateLoggedOnState(); - Msg( "CClientSteamContext OnSteamServersConnected logged on = %d\n", m_bLoggedOn ); -} -#endif // !defined(NO_STEAM) - -void CClientSteamContext::InstallCallback( CUtlDelegate< void ( const SteamLoggedOnChange_t & ) > delegate ) -{ - m_LoggedOnCallbacks.AddToTail( delegate ); -} - -void CClientSteamContext::RemoveCallback( CUtlDelegate< void ( const SteamLoggedOnChange_t & ) > delegate ) -{ - m_LoggedOnCallbacks.FindAndRemove( delegate ); -} - -void CClientSteamContext::InvokeCallbacks( const SteamLoggedOnChange_t &loggedOnStatus ) -{ - for ( int i = 0; i < m_LoggedOnCallbacks.Count(); ++i ) - { - m_LoggedOnCallbacks[i]( loggedOnStatus ); - } -} \ No newline at end of file diff --git a/game/client/clientsteamcontext.h b/game/client/clientsteamcontext.h deleted file mode 100644 index 07a4bcd8f..000000000 --- a/game/client/clientsteamcontext.h +++ /dev/null @@ -1,56 +0,0 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// -#if !defined( CLIENTSTEAMCONTEXT_H ) -#define CLIENTSTEAMCONTEXT_H -#ifdef _WIN32 -#pragma once -#endif - -#include "steam/steam_api.h" -#include "utldelegate.h" - -struct SteamLoggedOnChange_t -{ - bool bPreviousLoggedOn; - bool bLoggedOn; -}; - -class CClientSteamContext : public CSteamAPIContext -{ -public: - CClientSteamContext(); - ~CClientSteamContext(); - - void Activate(); - void Shutdown(); - -#if !defined(NO_STEAM) - STEAM_CALLBACK( CClientSteamContext, OnSteamServersDisconnected, SteamServersDisconnected_t, m_CallbackSteamServersDisconnected ); - STEAM_CALLBACK( CClientSteamContext, OnSteamServerConnectFailure, SteamServerConnectFailure_t, m_CallbackSteamServerConnectFailure ); - STEAM_CALLBACK( CClientSteamContext, OnSteamServersConnected, SteamServersConnected_t, m_CallbackSteamServersConnected ); -#endif - - bool BLoggedOn() { return m_bLoggedOn; } - EUniverse GetConnectedUniverse() { return m_nUniverse; } - uint32 GetAppID() { return m_nAppID; } - const CSteamID & GetLocalPlayerSteamID() { return m_SteamIDLocalPlayer; } - - // Allow others to register for a callback when the Steam logged on status changes - void InstallCallback( CUtlDelegate< void ( const SteamLoggedOnChange_t & ) > delegate ); - void RemoveCallback( CUtlDelegate< void ( const SteamLoggedOnChange_t & ) > delegate ); - -private: - void UpdateLoggedOnState(); - void InvokeCallbacks( const SteamLoggedOnChange_t &loggedOnStatus ); - - bool m_bActive; - bool m_bLoggedOn; - CSteamID m_SteamIDLocalPlayer; - EUniverse m_nUniverse; - uint32 m_nAppID; - - CUtlVector< CUtlDelegate< void ( const SteamLoggedOnChange_t & ) > > m_LoggedOnCallbacks; -}; - -CClientSteamContext &ClientSteamContext(); // singleton accessor - -#endif // CLIENTSTEAMCONTEXT_H \ No newline at end of file diff --git a/game/client/colorcorrectionmgr.cpp b/game/client/colorcorrectionmgr.cpp index 770354b0f..67418456f 100644 --- a/game/client/colorcorrectionmgr.cpp +++ b/game/client/colorcorrectionmgr.cpp @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose : Singleton manager for color correction on the client // @@ -8,6 +8,10 @@ #include "cbase.h" #include "tier0/vprof.h" #include "colorcorrectionmgr.h" +#include "clientmode.h" + +// NOTE: This has to be the last file included! +#include "tier0/memdbgon.h" //------------------------------------------------------------------------------ @@ -16,6 +20,10 @@ static CColorCorrectionMgr s_ColorCorrectionMgr; CColorCorrectionMgr *g_pColorCorrectionMgr = &s_ColorCorrectionMgr; +static ConVar mat_colcorrection_editor( "mat_colcorrection_editor", "0" ); + +static CUtlVector g_ColorCorrectionList; +static CUtlVector g_ColorCorrectionVolumeList; //------------------------------------------------------------------------------ // Constructor @@ -62,16 +70,73 @@ void CColorCorrectionMgr::RemoveColorCorrection( ClientCCHandle_t h ) } } +ClientCCHandle_t CColorCorrectionMgr::AddColorCorrectionEntity( C_ColorCorrection *pEntity, const char *pName, const char *pFileName ) +{ + ClientCCHandle_t h = AddColorCorrection(pName, pFileName); + if ( h != INVALID_CLIENT_CCHANDLE ) + { + Assert(g_ColorCorrectionList.Find(pEntity) == -1); + g_ColorCorrectionList.AddToTail(pEntity); + } + return h; +} + +void CColorCorrectionMgr::RemoveColorCorrectionEntity( C_ColorCorrection *pEntity, ClientCCHandle_t h) +{ + RemoveColorCorrection(h); + g_ColorCorrectionList.FindAndFastRemove(pEntity); +} + +ClientCCHandle_t CColorCorrectionMgr::AddColorCorrectionVolume( C_ColorCorrectionVolume *pVolume, const char *pName, const char *pFileName ) +{ + ClientCCHandle_t h = AddColorCorrection(pName, pFileName); + if ( h != INVALID_CLIENT_CCHANDLE ) + { + Assert(g_ColorCorrectionVolumeList.Find(pVolume) == -1); + g_ColorCorrectionVolumeList.AddToTail(pVolume); + } + return h; +} + +void CColorCorrectionMgr::RemoveColorCorrectionVolume( C_ColorCorrectionVolume *pVolume, ClientCCHandle_t h) +{ + RemoveColorCorrection(h); + g_ColorCorrectionVolumeList.FindAndFastRemove(pVolume); +} //------------------------------------------------------------------------------ // Modify color correction weights //------------------------------------------------------------------------------ -void CColorCorrectionMgr::SetColorCorrectionWeight( ClientCCHandle_t h, float flWeight ) +void CColorCorrectionMgr::SetColorCorrectionWeight( ClientCCHandle_t h, float flWeight, bool bExclusive ) { if ( h != INVALID_CLIENT_CCHANDLE ) { - CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); - ColorCorrectionHandle_t ccHandle = (ColorCorrectionHandle_t)h; + SetWeightParams_t params = { h, flWeight, bExclusive }; + m_colorCorrectionWeights.AddToTail( params ); + if( bExclusive && m_bHaveExclusiveWeight && ( flWeight != 0.0f ) ) + { + DevWarning( "Found multiple active color_correction entities with exclusive setting enabled. This is invalid.\n" ); + } + if ( bExclusive ) + { + m_bHaveExclusiveWeight = true; + m_flExclusiveWeight = flWeight; + } + } +} + +void CColorCorrectionMgr::CommitColorCorrectionWeights() +{ + CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); + + for ( int i = 0; i < m_colorCorrectionWeights.Count(); i++ ) + { + ColorCorrectionHandle_t ccHandle = reinterpret_cast( m_colorCorrectionWeights[i].handle ); + float flWeight = m_colorCorrectionWeights[i].flWeight; + if ( !m_colorCorrectionWeights[i].bExclusive ) + { + flWeight = (1.0f - m_flExclusiveWeight ) * m_colorCorrectionWeights[i].flWeight; + } pRenderContext->SetLookupWeight( ccHandle, flWeight ); // FIXME: NOTE! This doesn't work if the same handle has @@ -82,6 +147,7 @@ void CColorCorrectionMgr::SetColorCorrectionWeight( ClientCCHandle_t h, float fl ++m_nActiveWeightCount; } } + m_colorCorrectionWeights.RemoveAll(); } void CColorCorrectionMgr::ResetColorCorrectionWeights() @@ -93,6 +159,9 @@ void CColorCorrectionMgr::ResetColorCorrectionWeights() CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); pRenderContext->ResetLookupWeights(); m_nActiveWeightCount = 0; + m_bHaveExclusiveWeight = false; + m_flExclusiveWeight = 0.0f; + m_colorCorrectionWeights.RemoveAll(); } void CColorCorrectionMgr::SetResetable( ClientCCHandle_t h, bool bResetable ) @@ -115,5 +184,25 @@ void CColorCorrectionMgr::SetResetable( ClientCCHandle_t h, bool bResetable ) //------------------------------------------------------------------------------ bool CColorCorrectionMgr::HasNonZeroColorCorrectionWeights() const { - return ( m_nActiveWeightCount != 0 ); + return ( m_nActiveWeightCount != 0 ) || mat_colcorrection_editor.GetBool(); +} + +void CColorCorrectionMgr::UpdateColorCorrection() +{ + ResetColorCorrectionWeights(); + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + IClientMode *pClientMode = GetClientMode(); + + Assert( pClientMode ); + if ( !pPlayer || !pClientMode ) + { + return; + } + + pClientMode->OnColorCorrectionWeightsReset(); + float ccScale = pClientMode->GetColorCorrectionScale(); + + UpdateColorCorrectionEntities( pPlayer, ccScale, g_ColorCorrectionList.Base(), g_ColorCorrectionList.Count() ); + UpdateColorCorrectionVolumes( pPlayer, ccScale, g_ColorCorrectionVolumeList.Base(), g_ColorCorrectionVolumeList.Count() ); + CommitColorCorrectionWeights(); } diff --git a/game/client/colorcorrectionmgr.h b/game/client/colorcorrectionmgr.h index 3d5271db6..8815682d6 100644 --- a/game/client/colorcorrectionmgr.h +++ b/game/client/colorcorrectionmgr.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose : Singleton manager for color correction on the client // @@ -14,6 +14,8 @@ #include "igamesystem.h" +class C_ColorCorrection; +class C_ColorCorrectionVolume; //------------------------------------------------------------------------------ // Purpose : Singleton manager for color correction on the client @@ -35,8 +37,15 @@ class CColorCorrectionMgr : public CBaseGameSystem ClientCCHandle_t AddColorCorrection( const char *pName, const char *pFileName = NULL ); void RemoveColorCorrection( ClientCCHandle_t ); + ClientCCHandle_t AddColorCorrectionEntity( C_ColorCorrection *pEntity, const char *pName, const char *pFileName = NULL ); + void RemoveColorCorrectionEntity( C_ColorCorrection *pEntity, ClientCCHandle_t ); + + ClientCCHandle_t AddColorCorrectionVolume( C_ColorCorrectionVolume *pVolume, const char *pName, const char *pFileName = NULL ); + void RemoveColorCorrectionVolume( C_ColorCorrectionVolume *pVolume, ClientCCHandle_t ); + // Modify color correction weights - void SetColorCorrectionWeight( ClientCCHandle_t h, float flWeight ); + void SetColorCorrectionWeight( ClientCCHandle_t h, float flWeight, bool bExclusive = false ); + void UpdateColorCorrection(); void ResetColorCorrectionWeights(); void SetResetable( ClientCCHandle_t h, bool bResetable ); @@ -45,8 +54,23 @@ class CColorCorrectionMgr : public CBaseGameSystem private: int m_nActiveWeightCount; + bool m_bHaveExclusiveWeight; + float m_flExclusiveWeight; + + struct SetWeightParams_t + { + ClientCCHandle_t handle; + float flWeight; + bool bExclusive; + }; + + CUtlVector< SetWeightParams_t > m_colorCorrectionWeights; + + void CommitColorCorrectionWeights(); }; +void UpdateColorCorrectionEntities( C_BasePlayer *pPlayer, float ccScale, C_ColorCorrection **pList, int listCount ); +void UpdateColorCorrectionVolumes( C_BasePlayer *pPlayer, float ccScale, C_ColorCorrectionVolume **pList, int listCount ); //------------------------------------------------------------------------------ // Singleton access diff --git a/game/client/commentary_modelviewer.cpp b/game/client/commentary_modelviewer.cpp index 8c81fbd3e..e479b4456 100644 --- a/game/client/commentary_modelviewer.cpp +++ b/game/client/commentary_modelviewer.cpp @@ -1,17 +1,24 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2006, Valve Corporation, All rights reserved. ============// // // Purpose: // //=============================================================================// - #include "cbase.h" #include "vgui/IInput.h" -#include +#include #include "commentary_modelviewer.h" #include "iclientmode.h" #include "baseviewport.h" +// NOTE: This has to be the last file included! +#include "tier0/memdbgon.h" + + +/* +// FIXME!!!!!! +// FIXME!!!!!! +// FIXME!!!!!! DECLARE_BUILD_FACTORY( CCommentaryModelPanel ); //----------------------------------------------------------------------------- @@ -20,6 +27,7 @@ DECLARE_BUILD_FACTORY( CCommentaryModelPanel ); CCommentaryModelPanel::CCommentaryModelPanel( vgui::Panel *parent, const char *name ) : CModelPanel( parent, name ) { } +*/ //----------------------------------------------------------------------------- // Purpose: @@ -27,7 +35,9 @@ CCommentaryModelPanel::CCommentaryModelPanel( vgui::Panel *parent, const char *n CCommentaryModelViewer::CCommentaryModelViewer(IViewPort *pViewPort) : Frame(NULL, PANEL_COMMENTARY_MODELVIEWER ) { m_pViewPort = pViewPort; - m_pModelPanel = NULL; + + // FIXME!!!!!! + //m_pModelPanel = NULL; } //----------------------------------------------------------------------------- @@ -46,7 +56,8 @@ void CCommentaryModelViewer::ApplySchemeSettings( vgui::IScheme *pScheme ) LoadControlSettings( "Resource/UI/CommentaryModelViewer.res" ); - m_pModelPanel = dynamic_cast( FindChildByName( "modelpanel" ) ); + // FIXME!!!!!! + //m_pModelPanel = dynamic_cast( FindChildByName( "modelpanel" ) ); } //----------------------------------------------------------------------------- @@ -58,10 +69,11 @@ void CCommentaryModelViewer::PerformLayout( void ) GetParent()->GetSize( w, h ); SetBounds(0,0,w,h); - if ( m_pModelPanel ) + // FIXME!!!!!! + /*if ( m_pModelPanel ) { m_pModelPanel->SetBounds(0,0,w,h); - } + }*/ BaseClass::PerformLayout(); } @@ -71,6 +83,8 @@ void CCommentaryModelViewer::PerformLayout( void ) //----------------------------------------------------------------------------- void CCommentaryModelViewer::SetModel( const char *pszName, const char *pszAttached ) { + // FIXME!!!!!! + /* if ( !m_pModelPanel ) return; @@ -82,6 +96,7 @@ void CCommentaryModelViewer::SetModel( const char *pszName, const char *pszAttac m_vecResetPos = m_pModelPanel->m_pModelInfo->m_vecOriginOffset; m_vecResetAngles = m_pModelPanel->m_pModelInfo->m_vecAbsAngles; + */ } //----------------------------------------------------------------------------- @@ -138,12 +153,15 @@ void CCommentaryModelViewer::OnKeyCodePressed( vgui::KeyCode code ) } else if ( code == KEY_R ) { + // FIXME!!!!!! + /* m_pModelPanel->m_pModelInfo->m_vecOriginOffset = m_vecResetPos; m_pModelPanel->m_pModelInfo->m_vecAbsAngles = m_vecResetAngles; m_flYawSpeed = 0; m_flZoomSpeed = 0; m_pModelPanel->ZoomToFrameDistance(); + */ } else { @@ -192,14 +210,17 @@ void CCommentaryModelViewer::HandleMovementInput( void ) } if ( m_flYawSpeed != 0 ) { + // FIXME!!!!!! + /* if ( m_bTranslating ) { - m_pModelPanel->m_pModelInfo->m_vecOriginOffset.y = clamp( m_pModelPanel->m_pModelInfo->m_vecOriginOffset.y + m_flYawSpeed, -100.f, 100.f ); + m_pModelPanel->m_pModelInfo->m_vecOriginOffset.y = clamp( m_pModelPanel->m_pModelInfo->m_vecOriginOffset.y + m_flYawSpeed, -100, 100 ); } else { m_pModelPanel->m_pModelInfo->m_vecAbsAngles.y = anglemod( m_pModelPanel->m_pModelInfo->m_vecAbsAngles.y + m_flYawSpeed ); } + */ if ( !bLeftDown && !bRightDown ) { @@ -226,9 +247,11 @@ void CCommentaryModelViewer::HandleMovementInput( void ) } if ( m_flZoomSpeed != 0 ) { + // FIXME!!!!!! + /* if ( m_bTranslating ) { - m_pModelPanel->m_pModelInfo->m_vecOriginOffset.z = clamp( m_pModelPanel->m_pModelInfo->m_vecOriginOffset.z + m_flZoomSpeed, -100.f, 300.f ); + m_pModelPanel->m_pModelInfo->m_vecOriginOffset.z = clamp( m_pModelPanel->m_pModelInfo->m_vecOriginOffset.z + m_flZoomSpeed, -100, 300 ); } else { @@ -236,6 +259,7 @@ void CCommentaryModelViewer::HandleMovementInput( void ) float flZoomMax = m_pModelPanel->m_flFrameDistance * 1.5; m_pModelPanel->m_pModelInfo->m_vecOriginOffset.x = clamp( m_pModelPanel->m_pModelInfo->m_vecOriginOffset.x + m_flZoomSpeed, flZoomMin, flZoomMax ); } + */ if ( !bForwardDown && !bBackDown ) { @@ -255,7 +279,7 @@ void CommentaryShowModelViewer( const CCommand &args ) return; } - CBaseViewport *pViewport = dynamic_cast( g_pClientMode->GetViewport() ); + CBaseViewport *pViewport = dynamic_cast( GetClientMode()->GetViewport() ); if ( pViewport ) { IViewPortPanel *pCommentaryPanel = pViewport->FindPanelByName( PANEL_COMMENTARY_MODELVIEWER ); diff --git a/game/client/commentary_modelviewer.h b/game/client/commentary_modelviewer.h index bd98c0542..c60040710 100644 --- a/game/client/commentary_modelviewer.h +++ b/game/client/commentary_modelviewer.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2006, Valve Corporation, All rights reserved. ============// // // Purpose: // @@ -13,11 +13,24 @@ #include #include -#include "basemodelpanel.h" + +// FIXME!!!!!! +//#include "basemodelpanel.h" //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- + +/* +// FIXME!!!!!! +// FIXME!!!!!! +// FIXME!!!!!! + +This should be using the NEW model panels... "CBaseModelPanel" in basemodel_panel.h/.cpp +Need to comment this out so we can remove the dependence on the old CModelPanel from all but TF. +This will make it so people don't accidently use it or get confused by its similar structure when +working with the new class. + class CCommentaryModelPanel : public CModelPanel { public: @@ -26,6 +39,8 @@ class CCommentaryModelPanel : public CModelPanel CCommentaryModelPanel( vgui::Panel *parent, const char *name ); }; +*/ + //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- @@ -60,12 +75,13 @@ class CCommentaryModelViewer : public vgui::Frame, public IViewPortPanel vgui::VPANEL GetVPanel( void ) { return BaseClass::GetVPanel(); } virtual bool IsVisible() { return BaseClass::IsVisible(); } virtual void SetParent( vgui::VPANEL parent ) { BaseClass::SetParent( parent ); } - - virtual GameActionSet_t GetPreferredActionSet() { return GAME_ACTION_SET_MENUCONTROLS; } + virtual bool WantsBackgroundBlurred( void ) { return false; } private: IViewPort *m_pViewPort; - CCommentaryModelPanel *m_pModelPanel; + + // FIXME!!!!!! + //CCommentaryModelPanel *m_pModelPanel; Vector m_vecResetPos; Vector m_vecResetAngles; diff --git a/game/client/convarproxy.cpp b/game/client/convarproxy.cpp new file mode 100644 index 000000000..3ffd646ec --- /dev/null +++ b/game/client/convarproxy.cpp @@ -0,0 +1,105 @@ +//========= Copyright © 1996-2008, Valve Corporation, All rights reserved. ============// +// +// Material proxy to stuff a convar into a material var. +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" +// identifier was truncated to '255' characters in the debug information +//#pragma warning(disable: 4786) + +#include "convar.h" +#include "MaterialSystem/imaterialproxy.h" +#include "materialsystem/IMaterialVar.h" +#include "imaterialproxydict.h" + +// NOTE: This has to be the last file included! +#include "tier0/memdbgon.h" + + +class CConVarMaterialProxy: public IMaterialProxy +{ +public: + CConVarMaterialProxy() + : m_pResult( NULL ), + m_conVarRef( "", true ) + { + } + + virtual ~CConVarMaterialProxy() + { + } + + virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues ) + { + const char *pResult = pKeyValues->GetString( "resultVar" ); + if ( !pResult ) + return false; + + bool found; + m_pResult = pMaterial->FindVar( pResult, &found ); + if ( !found ) + { + m_pResult = NULL; + return false; + } + + if ( !Q_stricmp( pResult, "$alpha" ) ) + { + pMaterial->SetMaterialVarFlag( MATERIAL_VAR_ALPHA_MODIFIED_BY_PROXY, true ); + } + + pResult = pKeyValues->GetString( "convar" ); + if( !pResult ) + { + return false; + } + + m_conVarRef.Init( pResult, false ); + if ( !m_conVarRef.IsValid() ) + { + return false; + } + + return true; + } + + virtual void OnBind( void* ) + { + switch( m_pResult->GetType() ) + { + case MATERIAL_VAR_TYPE_VECTOR: + { + float f = m_conVarRef.GetFloat(); + Vector4D vec( f, f, f, f ); + m_pResult->SetVecValue( vec.Base(), m_pResult->VectorSize() ); + } + break; + + case MATERIAL_VAR_TYPE_INT: + m_pResult->SetIntValue( m_conVarRef.GetInt() ); + break; + + case MATERIAL_VAR_TYPE_FLOAT: + default: + m_pResult->SetFloatValue( m_conVarRef.GetFloat() ); + break; + } + } + + virtual IMaterial *GetMaterial() + { + return m_pResult->GetOwningMaterial(); + } + + virtual void Release() + { + } + +protected: + IMaterialVar *m_pResult; + ConVarRef m_conVarRef; +}; + +EXPOSE_MATERIAL_PROXY( CConVarMaterialProxy, ConVar ); diff --git a/game/client/cstrike/VGUI/achievement_stats_summary.cpp b/game/client/cstrike/VGUI/achievement_stats_summary.cpp deleted file mode 100644 index 81ef29837..000000000 --- a/game/client/cstrike/VGUI/achievement_stats_summary.cpp +++ /dev/null @@ -1,120 +0,0 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -// $NoKeywords: $ -//=============================================================================// - -#include "cbase.h" -#include "achievement_stats_summary.h" -#include "achievements_page.h" -#include "lifetime_stats_page.h" -#include "match_stats_page.h" -#include "stats_summary.h" - -#include - -using namespace vgui; - -#include -#include "vgui/ISurface.h" - -#include "filesystem.h" -#include - -// memdbgon must be the last include file in a .cpp file!!! -#include - - -const int cDialogWidth = 900; - - -//----------------------------------------------------------------------------- -// Purpose: Constructor -//----------------------------------------------------------------------------- -CAchievementAndStatsSummary::CAchievementAndStatsSummary(vgui::Panel *parent) : BaseClass(parent, "AchievementAndStatsSummary") -{ - SetDeleteSelfOnClose(false); - //SetBounds(0, 0, 640, 384); - SetBounds(0, 0, 900, 780); - SetMinimumSize( 640, 780 ); - SetSizeable( false ); - - SetTitle("#GameUI_CreateAchievementsAndStats", true); - SetOKButtonText("#GameUI_Close"); - SetCancelButtonVisible(false); - - m_pStatsSummary = new CStatsSummary( this, "StatsSummary" ); - m_pAchievementsPage = new CAchievementsPage(this, "AchievementsPage"); - m_pLifetimeStatsPage = new CLifetimeStatsPage(this, "StatsPage"); - m_pMatchStatsPage = new CMatchStatsPage(this, "MatchStatsPage"); - - AddPage(m_pStatsSummary, "#GameUI_Stats_Summary"); - AddPage(m_pAchievementsPage, "#GameUI_Achievements_Tab"); - AddPage(m_pMatchStatsPage, "#GameUI_MatchStats"); - AddPage(m_pLifetimeStatsPage, "#GameUI_LifetimeStats"); -} - -//----------------------------------------------------------------------------- -// Purpose: Destructor -//----------------------------------------------------------------------------- -CAchievementAndStatsSummary::~CAchievementAndStatsSummary() -{ -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CAchievementAndStatsSummary::ApplySchemeSettings( vgui::IScheme *pScheme ) -{ - BaseClass::ApplySchemeSettings( pScheme ); - - int screenWide, screenTall; - surface()->GetScreenSize( screenWide, screenTall ); - - // [smessick] Close the achievements dialog for a low resolution screen. - if ( screenWide < cAchievementsDialogMinWidth ) - { - OnOK( true ); - Close(); - } -} - -//----------------------------------------------------------------------------- -// Purpose: runs the server when the OK button is pressed -//----------------------------------------------------------------------------- -bool CAchievementAndStatsSummary::OnOK(bool applyOnly) -{ - BaseClass::OnOK(applyOnly); - - return true; -} - -//---------------------------------------------------------- -// Purpose: Preserve our width to the one in the .res file -//---------------------------------------------------------- -void CAchievementAndStatsSummary::OnSizeChanged(int newWide, int newTall) -{ - // Lock the width, but allow height scaling - if ( newWide != cDialogWidth ) - { - SetSize( cDialogWidth, newTall ); - return; - } - - BaseClass::OnSizeChanged(newWide, newTall); -} - -//---------------------------------------------------------- -// Purpose: Processes when summary dialog is activated. -//---------------------------------------------------------- -void CAchievementAndStatsSummary::Activate() -{ - m_pStatsSummary->MakeReadyForUse(); - m_pStatsSummary->UpdateStatsData(); - m_pAchievementsPage->UpdateAchievementDialogInfo(); - m_pLifetimeStatsPage->UpdateStatsData(); - m_pMatchStatsPage->UpdateStatsData(); - - BaseClass::Activate(); -} diff --git a/game/client/cstrike/VGUI/achievement_stats_summary.h b/game/client/cstrike/VGUI/achievement_stats_summary.h deleted file mode 100644 index c73b4d73d..000000000 --- a/game/client/cstrike/VGUI/achievement_stats_summary.h +++ /dev/null @@ -1,62 +0,0 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -// $NoKeywords: $ -//=============================================================================// - -#ifndef ACHIEVEMENTANDSTATSSUMMARY_H -#define ACHIEVEMENTANDSTATSSUMMARY_H -#ifdef _WIN32 -#pragma once -#endif - -#include - -class CAchievementsPage; -class CLifetimeStatsPage; -class CMatchStatsPage; -class StatCard; -class CStatsSummary; - -const int cAchievementsDialogMinWidth = 1024; // don't show this screen for lower resolutions - -//----------------------------------------------------------------------------- -// Purpose: dialog for displaying the achievements/stats summary -//----------------------------------------------------------------------------- -class CAchievementAndStatsSummary : public vgui::PropertyDialog -{ - DECLARE_CLASS_SIMPLE( CAchievementAndStatsSummary, vgui::PropertyDialog ); - -public: - CAchievementAndStatsSummary(vgui::Panel *parent); - ~CAchievementAndStatsSummary(); - - virtual void Activate(); - - void OnKeyCodePressed( vgui::KeyCode code ) - { - if ( code == KEY_XBUTTON_B ) - { - Close(); - } - else - { - BaseClass::OnKeyCodePressed(code); - } - } - -protected: - virtual bool OnOK(bool applyOnly); - virtual void OnSizeChanged( int newWide, int newTall ); - virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); - -private: - CAchievementsPage* m_pAchievementsPage; - CLifetimeStatsPage* m_pLifetimeStatsPage; - CMatchStatsPage* m_pMatchStatsPage; - CStatsSummary* m_pStatsSummary; -}; - - -#endif // ACHIEVEMENTANDSTATSSUMMARY_H diff --git a/game/client/cstrike/VGUI/achievements_page.cpp b/game/client/cstrike/VGUI/achievements_page.cpp deleted file mode 100644 index bc6036e39..000000000 --- a/game/client/cstrike/VGUI/achievements_page.cpp +++ /dev/null @@ -1,1061 +0,0 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// -// -// Purpose: Display a list of achievements for the current game -// -//=============================================================================// - -#include "cbase.h" -#include "achievements_page.h" -#include "vgui_controls/Button.h" -#include "vgui/ILocalize.h" -#include "ixboxsystem.h" -#include "iachievementmgr.h" -#include "filesystem.h" -#include "vgui_controls/ImagePanel.h" -#include "vgui_controls/ComboBox.h" -#include "vgui_controls/CheckButton.h" -#include "fmtstr.h" -#include "c_cs_playerresource.h" -#include "stat_card.h" -#include - -#include "../../../public/steam/steam_api.h" -#include "achievementmgr.h" -#include "../../../../public/vgui/IScheme.h" -#include "../vgui_controls/ScrollBar.h" -#include "achievements_cs.h" - -extern CAchievementMgr g_AchievementMgrCS; - -using namespace vgui; - -// memdbgon must be the last include file in a .cpp file!!! -#include "tier0/memdbgon.h" - -KeyValues *g_pPreloadedCSAchievementPageItemLayout = NULL; -KeyValues *g_pPreloadedCSAchievementPageGroupLayout = NULL; - -// Shared helper functions so xbox and pc can share as much code as possible while coming from different bases. - -//----------------------------------------------------------------------------- -// Purpose: Sets the parameter pIconPanel to display the specified achievement's icon file. -//----------------------------------------------------------------------------- -bool CSLoadAchievementIconForPage( vgui::ImagePanel* pIconPanel, CCSBaseAchievement* pAchievement, const char *pszExt /*= NULL*/ ) -{ - char imagePath[_MAX_PATH]; - Q_strncpy( imagePath, "achievements\\", sizeof(imagePath) ); - Q_strncat( imagePath, pAchievement->GetName(), sizeof(imagePath), COPY_ALL_CHARACTERS ); - if ( pszExt ) - { - Q_strncat( imagePath, pszExt, sizeof(imagePath), COPY_ALL_CHARACTERS ); - } - Q_strncat( imagePath, ".vtf", sizeof(imagePath), COPY_ALL_CHARACTERS ); - - char checkFile[_MAX_PATH]; - Q_snprintf( checkFile, sizeof(checkFile), "materials\\vgui\\%s", imagePath ); - if ( !g_pFullFileSystem->FileExists( checkFile ) ) - { - Q_snprintf( imagePath, sizeof(imagePath), "hud\\icon_locked.vtf" ); - } - - pIconPanel->SetShouldScaleImage( true ); - pIconPanel->SetImage( imagePath ); - pIconPanel->SetVisible( true ); - - return pIconPanel->IsVisible(); -} - -//----------------------------------------------------------------------------- -// Purpose: Sets the parameter pIconPanel to display the specified achievement's icon file. -//----------------------------------------------------------------------------- -bool CSLoadIconForPage( vgui::ImagePanel* pIconPanel, const char* pFilename, const char *pszExt /*= NULL*/ ) -{ - char imagePath[_MAX_PATH]; - Q_strncpy( imagePath, "achievements\\", sizeof(imagePath) ); - Q_strncat( imagePath, pFilename, sizeof(imagePath), COPY_ALL_CHARACTERS ); - if ( pszExt ) - { - Q_strncat( imagePath, pszExt, sizeof(imagePath), COPY_ALL_CHARACTERS ); - } - Q_strncat( imagePath, ".vtf", sizeof(imagePath), COPY_ALL_CHARACTERS ); - - char checkFile[_MAX_PATH]; - Q_snprintf( checkFile, sizeof(checkFile), "materials\\vgui\\%s", imagePath ); - if ( !g_pFullFileSystem->FileExists( checkFile ) ) - { - Q_snprintf( imagePath, sizeof(imagePath), "hud\\icon_locked.vtf" ); - } - - pIconPanel->SetShouldScaleImage( true ); - pIconPanel->SetImage( imagePath ); - pIconPanel->SetVisible( true ); - - return pIconPanel->IsVisible(); -} - -//----------------------------------------------------------------------------- -// The bias is to ensure the percentage bar gets plenty orange before it reaches the text, -// as the white-on-grey is hard to read. -//----------------------------------------------------------------------------- -Color CSLerpColorsForPage ( Color cStart, Color cEnd, float flPercent ) -{ - float r = (float)((float)(cStart.r()) + (float)(cEnd.r() - cStart.r()) * Bias( flPercent, 0.75 ) ); - float g = (float)((float)(cStart.g()) + (float)(cEnd.g() - cStart.g()) * Bias( flPercent, 0.75 ) ); - float b = (float)((float)(cStart.b()) + (float)(cEnd.b() - cStart.b()) * Bias( flPercent, 0.75 ) ); - float a = (float)((float)(cStart.a()) + (float)(cEnd.a() - cStart.a()) * Bias( flPercent, 0.75 ) ); - return Color( r, g, b, a ); -} - -//----------------------------------------------------------------------------- -// Purpose: Shares common percentage bar calculations/color settings between xbox and pc. -// Not really intended for robustness or reuse across many panels. -// Input : pFrame - assumed to have certain child panels (see below) -// *pAchievement - source achievement to poll for progress. Non progress achievements will not show a percentage bar. -//----------------------------------------------------------------------------- -void CSUpdateProgressBarForPage( vgui::EditablePanel* pPanel, CCSBaseAchievement* pAchievement, Color clrProgressBar ) -{ - ///* - if ( pAchievement->GetGoal() > 1 ) - { - bool bShowProgress = true; - - // if this achievement gets saved with game and we're not in a level and have not achieved it, then we do not have any state - // for this achievement, don't show progress - if ( ( pAchievement->GetFlags() & ACH_SAVE_WITH_GAME ) && /*!GameUI().IsInLevel() &&*/ !pAchievement->IsAchieved() ) - { - bShowProgress = false; - } - - float flCompletion = 0.0f; - - // Once achieved, we can't rely on count. If they've completed the achievement just set to 100%. - int iCount = pAchievement->GetCount(); - if ( pAchievement->IsAchieved() ) - { - flCompletion = 1.0f; - iCount = pAchievement->GetGoal(); - } - else if ( bShowProgress ) - { - flCompletion = ( ((float)pAchievement->GetCount()) / ((float)pAchievement->GetGoal()) ); - // In rare cases count can exceed goal and not be achieved (switch local storage on X360, take saved game from different user on PC). - // These will self-correct with continued play, but if we're in that state don't show more than 100% achieved. - flCompletion = MIN( flCompletion, 1.0 ); - } - - char szPercentageText[ 256 ] = ""; - if ( bShowProgress ) - { - Q_snprintf( szPercentageText, 256, "%d/%d", iCount, pAchievement->GetGoal() ); - } - - pPanel->SetControlString( "PercentageText", szPercentageText ); - pPanel->SetControlVisible( "PercentageText", true ); - pPanel->SetControlVisible( "CompletionText", true ); - - vgui::ImagePanel *pPercentageBar = (vgui::ImagePanel*)pPanel->FindChildByName( "PercentageBar" ); - vgui::ImagePanel *pPercentageBarBkg = (vgui::ImagePanel*)pPanel->FindChildByName( "PercentageBarBackground" ); - - if ( pPercentageBar && pPercentageBarBkg ) - { - pPercentageBar->SetFillColor( clrProgressBar ); - pPercentageBar->SetWide( pPercentageBarBkg->GetWide() * flCompletion ); - - pPanel->SetControlVisible( "PercentageBarBackground", IsX360() ? bShowProgress : true ); - pPanel->SetControlVisible( "PercentageBar", true ); - } - } - //*/ -} - -// TODO: revisit this once other games are rebuilt using the updated IAchievement interface -bool CSGameSupportsAchievementTrackerForPage() -{ - const char *pGame = Q_UnqualifiedFileName( engine->GetGameDirectory() ); - return ( !Q_stricmp( pGame, "cstrike" ) ); -} - -////////////////////////////////////////////////////////////////////////// -// PC Implementation -////////////////////////////////////////////////////////////////////////// - - - -int AchivementSortPredicate( CCSBaseAchievement* const* pLeft, CCSBaseAchievement* const* pRight ) -{ - if ( (*pLeft)->IsAchieved() && !(*pRight)->IsAchieved() ) - return -1; - - if ( !(*pLeft)->IsAchieved() && (*pRight)->IsAchieved() ) - return 1; - - if ( (*pLeft)->GetAchievementID() < (*pRight)->GetAchievementID() ) - return -1; - - if ( (*pLeft)->GetAchievementID() > (*pRight)->GetAchievementID() ) - return 1; - - return 0; -} - - -//----------------------------------------------------------------------------- -// Purpose: creates child panels, passes down name to pick up any settings from res files. -//----------------------------------------------------------------------------- -CAchievementsPage::CAchievementsPage(vgui::Panel *parent, const char *name) : BaseClass(parent, "CSAchievementsDialog") -{ - m_iFixedWidth = 900; // Give this an initial value in order to set a proper size - SetBounds(0, 0, 900, 780); - SetMinimumSize( 256, 780 ); - - m_pStatCard = new StatCard(this, "ignored"); - - m_pAchievementsList = new vgui::PanelListPanel( this, "listpanel_achievements" ); - m_pAchievementsList->SetFirstColumnWidth( 0 ); - - m_pGroupsList = new vgui::PanelListPanel( this, "listpanel_groups" ); - m_pGroupsList->SetFirstColumnWidth( 0 ); - - m_pListBG = new vgui::ImagePanel( this, "listpanel_background" ); - - m_pPercentageBarBackground = SETUP_PANEL( new ImagePanel( this, "PercentageBarBackground" ) ); - m_pPercentageBar = SETUP_PANEL( new ImagePanel( this, "PercentageBar" ) ); - - ListenForGameEvent( "player_stats_updated" ); - ListenForGameEvent( "achievement_earned_local" ); - - // int that holds the highest number achievement id we've found - int iHighestAchievementIDSeen = -1; - int iNextGroupBoundary = 1000; - - Q_memset( m_AchievementGroups, 0, sizeof(m_AchievementGroups) ); - m_iNumAchievementGroups = 0; - - // Base groups - int iCount = g_AchievementMgrCS.GetAchievementCount(); - for ( int i = 0; i < iCount; ++i ) - { - CCSBaseAchievement* pAchievement = dynamic_cast(g_AchievementMgrCS.GetAchievementByIndex( i )); - - if ( !pAchievement ) - continue; - - int iAchievementID = pAchievement->GetAchievementID(); - - if ( iAchievementID > iHighestAchievementIDSeen ) - { - // if it's crossed the next group boundary, create a new group - if ( iAchievementID >= iNextGroupBoundary ) - { - int iNewGroupBoundary = iAchievementID; - CreateNewAchievementGroup( iNewGroupBoundary, iNewGroupBoundary+99 ); - - iNextGroupBoundary = iNewGroupBoundary + 100; - } - - iHighestAchievementIDSeen = iAchievementID; - } - } - - LoadControlSettings("resource/ui/CSAchievementsDialog.res"); - UpdateTotalProgressDisplay(); - CreateOrUpdateComboItems( true ); - - // Default display shows the first achievement group - UpdateAchievementList(1001, 1100); - - m_bStatsDirty = true; - m_bAchievementsDirty = true; -} - -CAchievementsPage::~CAchievementsPage() -{ - g_AchievementMgrCS.SaveGlobalStateIfDirty( false ); // check for saving here to store achievements we want pinned to HUD - - m_pAchievementsList->DeleteAllItems(); - delete m_pAchievementsList; - delete m_pPercentageBarBackground; - delete m_pPercentageBar; -} - -void CAchievementsPage::CreateNewAchievementGroup( int iMinRange, int iMaxRange ) -{ - m_AchievementGroups[m_iNumAchievementGroups].m_iMinRange = iMinRange; - m_AchievementGroups[m_iNumAchievementGroups].m_iMaxRange = iMaxRange; - m_iNumAchievementGroups++; -} - -//---------------------------------------------------------- -// Get the width we're going to lock at -//---------------------------------------------------------- -void CAchievementsPage::ApplySettings( KeyValues *pResourceData ) -{ - m_iFixedWidth = pResourceData->GetInt( "wide", 512 ); - - BaseClass::ApplySettings( pResourceData ); -} - -//---------------------------------------------------------- -// Preserve our width to the one in the .res file -//---------------------------------------------------------- -void CAchievementsPage::OnSizeChanged(int newWide, int newTall) -{ - // Lock the width, but allow height scaling - if ( newWide != m_iFixedWidth ) - { - SetSize( m_iFixedWidth, newTall ); - return; - } - - BaseClass::OnSizeChanged(newWide, newTall); -} - -//---------------------------------------------------------- -// Re-populate the achievement list with the selected group -//---------------------------------------------------------- -void CAchievementsPage::UpdateAchievementList(CAchievementsPageGroupPanel* groupPanel) -{ - if (!groupPanel) - return; - - UpdateAchievementList( groupPanel->GetFirstAchievementID(), groupPanel->GetLastAchievementID() ); - - vgui::IScheme *pGroupScheme = scheme()->GetIScheme( GetScheme() ); - - // Update active status for button display - for (int i = 0; i < m_pGroupsList->GetItemCount(); i++) - { - CAchievementsPageGroupPanel *pPanel = (CAchievementsPageGroupPanel*)m_pGroupsList->GetItemPanel(i); - if ( pPanel ) - { - if ( pPanel != groupPanel ) - { - pPanel->SetGroupActive( false ); - } - else - { - pPanel->SetGroupActive( true ); - } - - pPanel->UpdateAchievementInfo( pGroupScheme ); - } - } -} - -void CAchievementsPage::UpdateTotalProgressDisplay() -{ - // Set up total completion percentage bar - float flCompletion = 0.0f; - - int iCount = g_AchievementMgrCS.GetAchievementCount(); - int nUnlocked = 0; - - if ( iCount > 0 ) - { - for ( int i = 0; i < iCount; ++i ) - { - CCSBaseAchievement* pAchievement = dynamic_cast(g_AchievementMgrCS.GetAchievementByIndex( i )); - - if ( pAchievement && pAchievement->IsAchieved() ) - ++nUnlocked; - } - - flCompletion = (((float)nUnlocked) / ((float)g_AchievementMgrCS.GetAchievementCount())); - } - - char szPercentageText[64]; - V_sprintf_safe( szPercentageText, "%d / %d", - nUnlocked, g_AchievementMgrCS.GetAchievementCount() ); - - SetControlString( "PercentageText", szPercentageText ); - SetControlVisible( "PercentageText", true ); - SetControlVisible( "CompletionText", true ); - - vgui::IScheme *pScheme = scheme()->GetIScheme( GetScheme() ); - - Color clrHighlight = pScheme->GetColor( "NewGame.SelectionColor", Color(255, 255, 255, 255) ); - Color clrWhite(255, 255, 255, 255); - - Color cProgressBar = Color( static_cast( clrHighlight.r() ) * ( 1.0f - flCompletion ) + static_cast( clrWhite.r() ) * flCompletion, - static_cast( clrHighlight.g() ) * ( 1.0f - flCompletion ) + static_cast( clrWhite.g() ) * flCompletion, - static_cast( clrHighlight.b() ) * ( 1.0f - flCompletion ) + static_cast( clrWhite.b() ) * flCompletion, - static_cast( clrHighlight.a() ) * ( 1.0f - flCompletion ) + static_cast( clrWhite.a() ) * flCompletion ); - - m_pPercentageBar->SetFgColor( cProgressBar ); - m_pPercentageBar->SetWide( m_pPercentageBarBackground->GetWide() * flCompletion ); - - SetControlVisible( "PercentageBarBackground", true ); - SetControlVisible( "PercentageBar", true ); -} - -//---------------------------------------------------------- -// Re-populate the achievement list with the selected group -//---------------------------------------------------------- -void CAchievementsPage::UpdateAchievementList(int minID, int maxID) -{ - int iMinRange = minID; - int iMaxRange = maxID; - - int iCount = g_AchievementMgrCS.GetAchievementCount(); - - CUtlVector sortedAchivementList; - sortedAchivementList.EnsureCapacity(iCount); - - for ( int i = 0; i < iCount; ++i ) - { - CCSBaseAchievement* pAchievement = dynamic_cast(g_AchievementMgrCS.GetAchievementByIndex(i)); - - if ( !pAchievement ) - continue; - - int iAchievementID = pAchievement->GetAchievementID(); - - if ( iAchievementID < iMinRange || iAchievementID > iMaxRange ) - continue; - - // don't show hidden achievements if not achieved - if ( pAchievement->ShouldHideUntilAchieved() && !pAchievement->IsAchieved() ) - continue; - - sortedAchivementList.AddToTail(pAchievement); - } - - sortedAchivementList.Sort(AchivementSortPredicate); - - m_pAchievementsList->DeleteAllItems(); - - FOR_EACH_VEC(sortedAchivementList, i) - { - CCSBaseAchievement* pAchievement = sortedAchivementList[i]; - - CAchievementsPageItemPanel *pAchievementItemPanel = new CAchievementsPageItemPanel( m_pAchievementsList, "AchievementDialogItemPanel"); - pAchievementItemPanel->SetAchievementInfo(pAchievement); - - // force all our new panel to have the correct internal layout and size so that our parent container can layout properly - pAchievementItemPanel->InvalidateLayout(true, true); - - m_pAchievementsList->AddItem( NULL, pAchievementItemPanel ); - } - - m_pAchievementsList->MoveScrollBarToTop(); -} - -//----------------------------------------------------------------------------- -// Purpose: Loads settings from achievementsdialog.res in hl2/resource/ui/ -// Sets up progress bar displaying total achievement unlocking progress by the user. -//----------------------------------------------------------------------------- -void CAchievementsPage::ApplySchemeSettings( vgui::IScheme *pScheme ) -{ - BaseClass::ApplySchemeSettings( pScheme ); - - m_pGroupsList->SetBgColor(Color(86,86,86,255)); - - SetBgColor(Color(86,86,86,255)); - - // Set text color for percentage - Panel *pPanel; - pPanel = FindChildByName("PercentageText"); - if (pPanel) - { - pPanel->SetFgColor(Color(157, 194, 80, 255)); - } - - // Set text color for achievement earned label - pPanel = FindChildByName("AchievementsEarnedLabel"); - if (pPanel) - { - pPanel->SetFgColor(Color(157, 194, 80, 255)); - } -} - -//----------------------------------------------------------------------------- -// Purpose: Each sub-panel gets its data updated -//----------------------------------------------------------------------------- -void CAchievementsPage::UpdateAchievementDialogInfo( void ) -{ - // Hide the group list scrollbar - if (m_pGroupsList->GetScrollbar()) - { - m_pGroupsList->GetScrollbar()->SetWide(0); - } - - int iCount = m_pAchievementsList->GetItemCount(); - vgui::IScheme *pScheme = scheme()->GetIScheme( GetScheme() ); - - int i; - for ( i = 0; i < iCount; i++ ) - { - CAchievementsPageItemPanel *pPanel = (CAchievementsPageItemPanel*)m_pAchievementsList->GetItemPanel(i); - if ( pPanel ) - { - pPanel->UpdateAchievementInfo( pScheme ); - } - } - - // Update all group panels - int iGroupCount = m_pGroupsList->GetItemCount(); - for ( i = 0; i < iGroupCount; i++ ) - { - CAchievementsPageGroupPanel *pPanel = (CAchievementsPageGroupPanel*)m_pGroupsList->GetItemPanel(i); - if ( pPanel ) - { - pPanel->UpdateAchievementInfo( pScheme ); - - if ( pPanel->IsGroupActive() ) - { - UpdateAchievementList( pPanel ); - } - } - } - - // update the groups and overall progress bar - CreateOrUpdateComboItems( false ); // update them with new achieved counts - - UpdateTotalProgressDisplay(); - - m_pStatCard->UpdateInfo(); - - m_bAchievementsDirty = false; - m_bStatsDirty = false; -} - -void CAchievementsPage::CreateOrUpdateComboItems( bool bCreate ) -{ - // Build up achievement group names - for ( int i=0;iFind( buf ); - - if ( !wzGroupName ) - { - wzGroupName = L"Need Title ( %s1 of %s2 )"; - } - - wchar_t wzGroupTitle[128]; - - if ( wzGroupName ) - { - // Determine number of achievements in the group which have been awarded - int numAwarded = 0; - int numTested = 0; - for (int j = m_AchievementGroups[i].m_iMinRange; j < m_AchievementGroups[i].m_iMaxRange; j++) - { - IAchievement* pCur = g_AchievementMgrCS.GetAchievementByID( j ); - - if ( !pCur ) - continue; - - numTested++; - - if ( pCur->IsAchieved() ) - { - numAwarded++; - } - } - - wchar_t wzNumUnlocked[8]; - V_snwprintf( wzNumUnlocked, ARRAYSIZE( wzNumUnlocked ), L"%d", numAwarded ); - - wchar_t wzNumAchievements[8]; - V_snwprintf( wzNumAchievements, ARRAYSIZE( wzNumAchievements ), L"%d", numTested ); - - g_pVGuiLocalize->ConstructString( wzGroupTitle, sizeof( wzGroupTitle ), wzGroupName, 0 ); - } - - KeyValues *pKV = new KeyValues( "grp" ); - pKV->SetInt( "minrange", m_AchievementGroups[i].m_iMinRange ); - pKV->SetInt( "maxrange", m_AchievementGroups[i].m_iMaxRange ); - - if ( bCreate ) - { - // Create an achievement group instance - CAchievementsPageGroupPanel *achievementGroupPanel = new CAchievementsPageGroupPanel( m_pGroupsList, this, "AchievementDialogGroupPanel", i ); - achievementGroupPanel->SetGroupInfo( wzGroupTitle, m_AchievementGroups[i].m_iMinRange, m_AchievementGroups[i].m_iMaxRange ); - - if (i == 0) - { - achievementGroupPanel->SetGroupActive(true); - } - else - { - achievementGroupPanel->SetGroupActive(false); - } - - m_pGroupsList->AddItem( NULL, achievementGroupPanel ); - } - } - - m_pStatCard->UpdateInfo(); -} - -//----------------------------------------------------------------------------- -// Purpose: creates child panels, passes down name to pick up any settings from res files. -//----------------------------------------------------------------------------- -CAchievementsPageItemPanel::CAchievementsPageItemPanel( vgui::PanelListPanel *parent, const char* name) : BaseClass( parent, name ) -{ - m_pParent = parent; - m_pSchemeSettings = NULL; - - m_pAchievementIcon = SETUP_PANEL(new vgui::ImagePanel( this, "AchievementIcon" )); - m_pAchievementNameLabel = new vgui::Label( this, "AchievementName", "name" ); - m_pAchievementDescLabel = new vgui::Label( this, "AchievementDesc", "desc" ); - m_pPercentageBar = SETUP_PANEL( new ImagePanel( this, "PercentageBar" ) ); - m_pPercentageText = new vgui::Label( this, "PercentageText", "" ); - m_pAwardDate = new vgui::Label( this, "AwardDate", "date" ); - m_pShowOnHUDButton = new vgui::CheckButton( this, "ShowOnHudToggle", "" ); - m_pShowOnHUDButton->SetMouseInputEnabled( true ); - m_pShowOnHUDButton->SetEnabled( true ); - m_pShowOnHUDButton->SetCheckButtonCheckable( true ); - m_pShowOnHUDButton->AddActionSignalTarget( this ); - - m_pHiddenHUDToggleButton = new CHiddenHUDToggleButton( this, "HiddenHUDToggle", "" ); - m_pHiddenHUDToggleButton->SetPaintBorderEnabled( false ); - - - SetMouseInputEnabled( true ); - parent->SetMouseInputEnabled( true ); -} - -CAchievementsPageItemPanel::~CAchievementsPageItemPanel() -{ - delete m_pAchievementIcon; - delete m_pAchievementNameLabel; - delete m_pAchievementDescLabel; - delete m_pPercentageBar; - delete m_pPercentageText; - delete m_pAwardDate; - delete m_pShowOnHUDButton; - delete m_pHiddenHUDToggleButton; -} - -void CAchievementsPageItemPanel::ToggleShowOnHUDButton() -{ - if (m_pShowOnHUDButton) - { - m_pShowOnHUDButton->SetSelected( !m_pShowOnHUDButton->IsSelected() ); - } -} - -//----------------------------------------------------------------------------- -// Purpose: Updates displayed achievement data. In applyschemesettings, and when gameui activates. -//----------------------------------------------------------------------------- -void CAchievementsPageItemPanel::UpdateAchievementInfo( vgui::IScheme* pScheme ) -{ - if ( m_pSourceAchievement && m_pSchemeSettings ) - { - //============================================================================= - // HPE_BEGIN: - // [dwenger] Get achievement name and description text from the localized file - //============================================================================= - - // Set name, description and unlocked state text - m_pAchievementNameLabel->SetText( ACHIEVEMENT_LOCALIZED_NAME( m_pSourceAchievement ) ); - m_pAchievementDescLabel->SetText( ACHIEVEMENT_LOCALIZED_DESC( m_pSourceAchievement ) ); - - //============================================================================= - // HPE_END - //============================================================================= - - // Setup icon - // get the vtfFilename from the path. - - // Display percentage completion for progressive achievements - // Set up total completion percentage bar. Goal > 1 means its a progress achievement. - CSUpdateProgressBarForPage( this, m_pSourceAchievement, m_clrProgressBar ); - - if ( m_pSourceAchievement->IsAchieved() ) - { - CSLoadAchievementIconForPage( m_pAchievementIcon, m_pSourceAchievement ); - - SetBgColor( pScheme->GetColor( "AchievementsLightGrey", Color(255, 0, 0, 255) ) ); - - m_pAchievementNameLabel->SetFgColor( pScheme->GetColor( "SteamLightGreen", Color(255, 255, 255, 255) ) ); - - Color fgColor = pScheme->GetColor( "Label.TextBrightColor", Color(255, 255, 255, 255) ); - m_pAchievementDescLabel->SetFgColor( fgColor ); - m_pPercentageText->SetFgColor( fgColor ); - m_pShowOnHUDButton->SetVisible( false ); - m_pShowOnHUDButton->SetSelected( false ); - m_pHiddenHUDToggleButton->SetVisible( false ); - m_pAwardDate->SetVisible( true ); - m_pAwardDate->SetFgColor( pScheme->GetColor( "SteamLightGreen", Color(255, 255, 255, 255) ) ); - - // Assign the award date text - int year, month, day, hour, minute, second; - if ( m_pSourceAchievement->GetAwardTime(year, month, day, hour, minute, second) ) - { - char dateBuffer[32] = ""; - Q_snprintf( dateBuffer, 32, "%4d-%02d-%02d", year, month, day ); - m_pAwardDate->SetText( dateBuffer ); - } - else - m_pAwardDate->SetText( "" ); - } - else - { - CSLoadAchievementIconForPage( m_pAchievementIcon, m_pSourceAchievement, "_bw" ); - - SetBgColor( pScheme->GetColor( "AchievementsDarkGrey", Color(255, 0, 0, 255) ) ); - - Color fgColor = pScheme->GetColor( "AchievementsInactiveFG", Color(255, 255, 255, 255) ); - m_pAchievementNameLabel->SetFgColor( fgColor ); - m_pAchievementDescLabel->SetFgColor( fgColor ); - m_pPercentageText->SetFgColor( fgColor ); - - if ( CSGameSupportsAchievementTrackerForPage() ) - { - m_pShowOnHUDButton->SetVisible( !m_pSourceAchievement->ShouldHideUntilAchieved() ); - m_pShowOnHUDButton->SetSelected( m_pSourceAchievement->ShouldShowOnHUD() ); - - m_pHiddenHUDToggleButton->SetVisible( !m_pSourceAchievement->ShouldHideUntilAchieved() ); - } - else - { - m_pShowOnHUDButton->SetVisible( false ); - m_pHiddenHUDToggleButton->SetVisible( false ); - } - } - } -} - -//----------------------------------------------------------------------------- -// Purpose: Makes a local copy of a pointer to the achievement entity stored on the client. -//----------------------------------------------------------------------------- -void CAchievementsPageItemPanel::SetAchievementInfo( CCSBaseAchievement* pAchievement ) -{ - if ( !pAchievement ) - { - Assert( 0 ); - return; - } - - m_pSourceAchievement = pAchievement; - m_iSourceAchievementIndex = pAchievement->GetAchievementID(); -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CAchievementsPageItemPanel::PreloadResourceFile( void ) -{ - const char *controlResourceName = "resource/ui/AchievementItem.res"; - - g_pPreloadedCSAchievementPageItemLayout = new KeyValues(controlResourceName); - g_pPreloadedCSAchievementPageItemLayout->LoadFromFile(g_pFullFileSystem, controlResourceName); - -/* - // precache all achievement icons - int iCount = g_AchievementMgrCS.GetAchievementCount(); - for ( int i = 0; i < iCount; ++i ) - { - CCSBaseAchievement* pAchievement = dynamic_cast(g_AchievementMgrCS.GetAchievementByIndex( i )); - char imagePath[_MAX_PATH]; - - Q_strncpy( imagePath, "achievements\\", sizeof(imagePath) ); - Q_strncat( imagePath, pAchievement->GetName(), sizeof(imagePath), COPY_ALL_CHARACTERS ); - Q_strncat( imagePath, "_bw", sizeof(imagePath), COPY_ALL_CHARACTERS ); - Q_strncat( imagePath, ".vtf", sizeof(imagePath), COPY_ALL_CHARACTERS ); - - scheme()->GetImage(imagePath, true); - - Q_strncpy( imagePath, "achievements\\", sizeof(imagePath) ); - Q_strncat( imagePath, pAchievement->GetName(), sizeof(imagePath), COPY_ALL_CHARACTERS ); - Q_strncat( imagePath, ".vtf", sizeof(imagePath), COPY_ALL_CHARACTERS ); - - scheme()->GetImage(imagePath, true); - } -*/ -} - -//----------------------------------------------------------------------------- -// Purpose: Loads settings from hl2/resource/ui/achievementitem.res -// Sets display info for this achievement item. -//----------------------------------------------------------------------------- -void CAchievementsPageItemPanel::ApplySchemeSettings( vgui::IScheme* pScheme ) -{ - if ( !g_pPreloadedCSAchievementPageItemLayout ) - { - PreloadResourceFile(); - } - - LoadControlSettings( "", NULL, g_pPreloadedCSAchievementPageItemLayout ); - - m_pSchemeSettings = pScheme; - - if ( !m_pSourceAchievement ) - { - return; - } - - BaseClass::ApplySchemeSettings( pScheme ); - - // m_pSchemeSettings must be set for this. - UpdateAchievementInfo( pScheme ); -} - -void CAchievementsPageItemPanel::OnCheckButtonChecked(Panel *panel) -{ - if ( CSGameSupportsAchievementTrackerForPage() && panel == m_pShowOnHUDButton && m_pSourceAchievement ) - { - m_pSourceAchievement->SetShowOnHUD( m_pShowOnHUDButton->IsSelected() ); - } -} - - -//----------------------------------------------------------------------------- -// Purpose: creates child panels, passes down name to pick up any settings from res files. -//----------------------------------------------------------------------------- -CAchievementsPageGroupPanel::CAchievementsPageGroupPanel( vgui::PanelListPanel *parent, CAchievementsPage *owner, const char* name, int iListItemID ) : BaseClass( parent, name ) -{ - m_pParent = parent; - m_pOwner = owner; - m_pSchemeSettings = NULL; - - m_pGroupIcon = SETUP_PANEL(new vgui::ImagePanel( this, "GroupIcon" )); - m_pAchievementGroupLabel = new vgui::Label( this, "GroupName", "name" ); - m_pPercentageText = new vgui::Label( this, "GroupPercentageText", "1/1" ); - m_pPercentageBar = SETUP_PANEL( new ImagePanel( this, "GroupPercentageBar" ) ); - m_pGroupButton = new CGroupButton( this, "GroupButton", "" ); - m_pGroupButton->SetPos( 0, 0 ); - m_pGroupButton->SetZPos( 20 ); - m_pGroupButton->SetWide( 256 ); - m_pGroupButton->SetTall( 64 ); - SetMouseInputEnabled( true ); - parent->SetMouseInputEnabled( true ); - - m_bActiveButton = false; -} - -CAchievementsPageGroupPanel::~CAchievementsPageGroupPanel() -{ - delete m_pAchievementGroupLabel; - delete m_pPercentageBar; - delete m_pPercentageText; - delete m_pGroupIcon; -} - -//----------------------------------------------------------------------------- -// Purpose: Loads settings from hl2/resource/ui/achievementitem.res -// Sets display info for this achievement item. -//----------------------------------------------------------------------------- -void CAchievementsPageGroupPanel::ApplySchemeSettings( vgui::IScheme* pScheme ) -{ - if ( !g_pPreloadedCSAchievementPageGroupLayout ) - { - PreloadResourceFile(); - } - - LoadControlSettings( "", NULL, g_pPreloadedCSAchievementPageGroupLayout ); - - m_pSchemeSettings = pScheme; - - BaseClass::ApplySchemeSettings( pScheme ); - - // m_pSchemeSettings must be set for this. - UpdateAchievementInfo( pScheme ); -} - -//----------------------------------------------------------------------------- -// Purpose: Updates displayed achievement data. In ApplySchemeSettings(), and -// when gameui activates. -//----------------------------------------------------------------------------- -void CAchievementsPageGroupPanel::UpdateAchievementInfo( vgui::IScheme* pScheme ) -{ - if ( m_pSchemeSettings ) - { - int numAwarded = 0; - int numTested = 0; - - char buf[128]; - int achievementRangeStart = (m_iFirstAchievementID / 1000) * 1000; - Q_snprintf( buf, sizeof(buf), "#Achievement_Group_%d", achievementRangeStart ); - - wchar_t *wzGroupName = g_pVGuiLocalize->Find( buf ); - - if ( !wzGroupName ) - { - wzGroupName = L"Need Title ( %s1 of %s2 )"; - } - - wchar_t wzGroupTitle[128]; - - if ( wzGroupName ) - { - // Determine number of achievements in the group which have been awarded - for (int i = m_iFirstAchievementID; i < m_iLastAchievementID; i++) - { - IAchievement* pCur = g_AchievementMgrCS.GetAchievementByID( i ); - - if ( !pCur ) - continue; - - numTested++; - - if ( pCur->IsAchieved() ) - { - numAwarded++; - } - } - - wchar_t wzNumUnlocked[8]; - V_snwprintf( wzNumUnlocked, ARRAYSIZE( wzNumUnlocked ), L"%d", numAwarded ); - - wchar_t wzNumAchievements[8]; - V_snwprintf( wzNumAchievements,ARRAYSIZE( wzNumAchievements ), L"%d", numTested ); - - g_pVGuiLocalize->ConstructString( wzGroupTitle, sizeof( wzGroupTitle ), wzGroupName, 2, wzNumUnlocked, wzNumAchievements ); - } - - // Set group name text - m_pAchievementGroupLabel->SetText( wzGroupTitle );//m_pGroupName ); - m_pAchievementGroupLabel->SetFgColor(Color(157, 194, 80, 255)); - - char* buff[32]; - Q_snprintf( (char*)buff, 32, "%d / %d", numAwarded, numTested ); - m_pPercentageText->SetText( (const char*)buff ); - m_pPercentageText->SetFgColor(Color(157, 194, 80, 255)); - - if ( !m_bActiveButton ) - { - CSLoadIconForPage( m_pGroupIcon, "achievement-btn-up" ); - } - else - { - CSLoadIconForPage( m_pGroupIcon, "achievement-btn-select" ); - } - - // Update the percentage complete bar - vgui::ImagePanel *pPercentageBar = (vgui::ImagePanel*)FindChildByName( "GroupPercentageBar" ); - vgui::ImagePanel *pPercentageBarBkg = (vgui::ImagePanel*)FindChildByName( "GroupPercentageBarBackground" ); - - if ( pPercentageBar && pPercentageBarBkg ) - { - float flCompletion = (float)numAwarded / (float)numTested; - pPercentageBar->SetFillColor( Color(157, 194, 80, 255) ); - pPercentageBar->SetWide( pPercentageBarBkg->GetWide() * flCompletion ); - - SetControlVisible( "GroupPercentageBarBackground", true ); - SetControlVisible( "GroupPercentageBar", true ); - } - } -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CAchievementsPageGroupPanel::PreloadResourceFile( void ) -{ - const char *controlResourceName = "resource/ui/AchievementGroup.res"; - - g_pPreloadedCSAchievementPageGroupLayout = new KeyValues(controlResourceName); - g_pPreloadedCSAchievementPageGroupLayout->LoadFromFile(g_pFullFileSystem, controlResourceName); - - -} - -//----------------------------------------------------------------------------- -// Purpose: Assigns a name and achievement id bounds for an achievement group. -//----------------------------------------------------------------------------- -void CAchievementsPageGroupPanel::SetGroupInfo( const wchar_t* name, int firstAchievementID, int lastAchievementID ) -{ - // Store away the group name - short _textLen = (short)wcslen(name) + 1; - m_pGroupName = new wchar_t[_textLen]; - Q_memcpy( m_pGroupName, name, _textLen * sizeof(wchar_t) ); - - // Store off the start & end achievement IDs - m_iFirstAchievementID = firstAchievementID; - m_iLastAchievementID = lastAchievementID; -} - -CGroupButton::CGroupButton( vgui::Panel *pParent, const char *pName, const char *pText ) : -BaseClass( pParent, pName, pText ) -{ -} - -//----------------------------------------------------------------------------- -// Purpose: Handle the case where the user presses an achievement group button. -//----------------------------------------------------------------------------- -void CGroupButton::DoClick( void ) -{ - // Process when a group button is hit - CAchievementsPageGroupPanel* pParent = static_cast(GetParent()); - - if (pParent) - { - CAchievementsPage* pAchievementsPage = static_cast(pParent->GetOwner()); - - if (pAchievementsPage) - { - // Update the list of group achievements - pAchievementsPage->UpdateAchievementList( pParent ); - } - } -} - -void CAchievementsPage::OnPageShow() -{ - m_pGroupsList->GetScrollbar()->SetWide(0); -} - -void CAchievementsPage::FireGameEvent( IGameEvent *event ) -{ - const char *type = event->GetName(); - - if ( 0 == Q_strcmp( type, "achievement_earned_local" ) ) - m_bAchievementsDirty = true; - - if ( 0 == Q_strcmp( type, "player_stats_updated" ) ) - m_bStatsDirty = true; -} - -void CAchievementsPage::OnThink() -{ - vgui::IScheme *pScheme = scheme()->GetIScheme( GetScheme() ); - - if ( m_bAchievementsDirty ) - { - UpdateAchievementDialogInfo(); - } - else if ( m_bStatsDirty ) - { - // Update progress for currently displayed achievements - int itemId = m_pAchievementsList->FirstItem(); - - while (itemId != m_pAchievementsList->InvalidItemID() ) - { - CAchievementsPageItemPanel *pAchievementItem = dynamic_cast(m_pAchievementsList->GetItemPanel(itemId)); - pAchievementItem->UpdateAchievementInfo(pScheme); - - itemId = m_pAchievementsList->NextItem(itemId); - } - m_bStatsDirty = false; - } -} - -CHiddenHUDToggleButton::CHiddenHUDToggleButton( vgui::Panel *pParent, const char *pName, const char *pText ) : -BaseClass( pParent, pName, pText ) -{ -} - -//----------------------------------------------------------------------------- -// Purpose: Handle the case where the user shift-clicks on an un-awarded achievement. -//----------------------------------------------------------------------------- -void CHiddenHUDToggleButton::DoClick( void ) -{ - if ( input()->IsKeyDown(KEY_LSHIFT) || input()->IsKeyDown(KEY_RSHIFT) ) - { - // Process when a group button is hit - CAchievementsPageItemPanel* pParent = static_cast(GetParent()); - - if (pParent) - { - pParent->ToggleShowOnHUDButton(); - } - } -} diff --git a/game/client/cstrike/VGUI/achievements_page.h b/game/client/cstrike/VGUI/achievements_page.h deleted file mode 100644 index 2066b1dbb..000000000 --- a/game/client/cstrike/VGUI/achievements_page.h +++ /dev/null @@ -1,218 +0,0 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -// $NoKeywords: $ -//=============================================================================// - -#ifndef CSACHIEVEMENTSPAGE_H -#define CSACHIEVEMENTSPAGE_H -#ifdef _WIN32 -#pragma once -#endif - -#include "vgui_controls/PanelListPanel.h" -#include "vgui_controls/Label.h" -#include "tier1/KeyValues.h" -#include "vgui_controls/PropertyPage.h" -#include "vgui_controls/Button.h" -#include "c_cs_player.h" -#include "vgui_avatarimage.h" -#include "GameEventListener.h" - -class CCSBaseAchievement; -class IScheme; -class CAchievementsPageGroupPanel; -class StatCard; - -#define ACHIEVED_ICON_PATH "hud/icon_check.vtf" -#define LOCK_ICON_PATH "hud/icon_locked.vtf" - -// Loads an achievement's icon into a specified image panel, or turns the panel off if no achievement icon was found. -bool CSLoadAchievementIconForPage( vgui::ImagePanel* pIconPanel, CCSBaseAchievement *pAchievement, const char *pszExt = NULL ); - -// Loads an achievement's icon into a specified image panel, or turns the panel off if no achievement icon was found. -bool CSLoadIconForPage( vgui::ImagePanel* pIconPanel, const char* pFilename, const char *pszExt = NULL ); - -// Updates a listed achievement item's progress bar. -void CSUpdateProgressBarForPage( vgui::EditablePanel* pPanel, CCSBaseAchievement *pAchievement, Color clrProgressBar ); - -//////////////////////////////////////////////////////////////////////////// -// PC version -////////////////////////////////////////////////////////////////////////// -class CAchievementsPage : public vgui::PropertyPage, public CGameEventListener -{ - DECLARE_CLASS_SIMPLE ( CAchievementsPage, vgui::PropertyPage ); - -public: - CAchievementsPage( vgui::Panel *parent, const char *name ); - ~CAchievementsPage(); - - virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); - - void UpdateTotalProgressDisplay(); - virtual void UpdateAchievementDialogInfo( void ); - - virtual void OnPageShow(); - virtual void OnThink(); - - virtual void ApplySettings( KeyValues *pResourceData ); - virtual void OnSizeChanged( int newWide, int newTall ); - - virtual void FireGameEvent( IGameEvent *event ); - - void CreateNewAchievementGroup( int iMinRange, int iMaxRange ); - void CreateOrUpdateComboItems( bool bCreate ); - void UpdateAchievementList(CAchievementsPageGroupPanel* groupPanel); - void UpdateAchievementList(int minID, int maxID); - - vgui::PanelListPanel *m_pAchievementsList; - vgui::ImagePanel *m_pListBG; - - vgui::PanelListPanel *m_pGroupsList; - vgui::ImagePanel *m_pGroupListBG; - - vgui::ImagePanel *m_pPercentageBarBackground; - vgui::ImagePanel *m_pPercentageBar; - - StatCard* m_pStatCard; - - int m_iFixedWidth; - - bool m_bStatsDirty; - bool m_bAchievementsDirty; - - typedef struct - { - int m_iMinRange; - int m_iMaxRange; - } achievement_group_t; - - int m_iNumAchievementGroups; - - achievement_group_t m_AchievementGroups[15]; -}; - -class CHiddenHUDToggleButton : public vgui::Button -{ - DECLARE_CLASS_SIMPLE( CHiddenHUDToggleButton, vgui::Button ); - -public: - - CHiddenHUDToggleButton( vgui::Panel *pParent, const char *pName, const char *pText ); - - virtual void DoClick( void ); -}; - -////////////////////////////////////////////////////////////////////////// -// Individual item panel, displaying stats for one achievement -class CAchievementsPageItemPanel : public vgui::EditablePanel -{ - DECLARE_CLASS_SIMPLE( CAchievementsPageItemPanel, vgui::EditablePanel ); - -public: - CAchievementsPageItemPanel( vgui::PanelListPanel *parent, const char* name); - ~CAchievementsPageItemPanel(); - - void SetAchievementInfo ( CCSBaseAchievement* pAchievement ); - CCSBaseAchievement* GetAchievementInfo( void ) { return m_pSourceAchievement; } - void UpdateAchievementInfo( vgui::IScheme *pScheme ); - virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); - - void ToggleShowOnHUDButton(); - - MESSAGE_FUNC_PTR( OnCheckButtonChecked, "CheckButtonChecked", panel ); - -private: - static void PreloadResourceFile(); - - CCSBaseAchievement* m_pSourceAchievement; - int m_iSourceAchievementIndex; - - vgui::PanelListPanel *m_pParent; - - vgui::Label *m_pAchievementNameLabel; - vgui::Label *m_pAchievementDescLabel; - vgui::Label *m_pPercentageText; - vgui::Label *m_pAwardDate; - - vgui::ImagePanel *m_pLockedIcon; - vgui::ImagePanel *m_pAchievementIcon; - - vgui::ImagePanel *m_pPercentageBarBackground; - vgui::ImagePanel *m_pPercentageBar; - - vgui::CheckButton *m_pShowOnHUDButton; - - vgui::IScheme *m_pSchemeSettings; - - CHiddenHUDToggleButton *m_pHiddenHUDToggleButton; - - CPanelAnimationVar( Color, m_clrProgressBar, "ProgressBarColor", "140 140 140 255" ); -}; - -class CGroupButton : public vgui::Button -{ - DECLARE_CLASS_SIMPLE( CGroupButton, vgui::Button ); - -public: - - CGroupButton( vgui::Panel *pParent, const char *pName, const char *pText ); - - virtual void DoClick( void ); -}; - -////////////////////////////////////////////////////////////////////////// -// Individual achievement group panel, displaying info for one achievement group -class CAchievementsPageGroupPanel : public vgui::EditablePanel -{ - DECLARE_CLASS_SIMPLE( CAchievementsPageGroupPanel, vgui::EditablePanel ); - -public: - CAchievementsPageGroupPanel( vgui::PanelListPanel *parent, CAchievementsPage *owner, const char* name, int iListItemID ); - ~CAchievementsPageGroupPanel(); - - void SetGroupInfo ( const wchar_t* name, int firstAchievementID, int lastAchievementID ); - void UpdateAchievementInfo( vgui::IScheme *pScheme ); - virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); - - int GetFirstAchievementID() { return m_iFirstAchievementID; } - int GetLastAchievementID() { return m_iLastAchievementID; } - - vgui::PanelListPanel* GetParent() { return m_pParent; } - CAchievementsPage* GetOwner() { return m_pOwner; } - - void SetGroupActive(bool active) { m_bActiveButton = active; } - bool IsGroupActive() { return m_bActiveButton; } - -private: - void PreloadResourceFile( void ); - - vgui::PanelListPanel *m_pParent; - CAchievementsPage *m_pOwner; - - vgui::Label *m_pAchievementGroupLabel; - vgui::Label *m_pPercentageText; - - CGroupButton *m_pGroupButton; - - vgui::ImagePanel *m_pGroupIcon; - - vgui::ImagePanel *m_pPercentageBarBackground; - vgui::ImagePanel *m_pPercentageBar; - - vgui::IScheme *m_pSchemeSettings; - - bool m_bActiveButton; - - CPanelAnimationVar( Color, m_clrProgressBar, "ProgressBarColor", "140 140 140 255" ); - - int m_iFirstAchievementID; - int m_iLastAchievementID; - - wchar_t *m_pGroupName; -}; - - - -#endif // CSACHIEVEMENTSPAGE_H diff --git a/game/client/cstrike/VGUI/backgroundpanel.cpp b/game/client/cstrike/VGUI/backgroundpanel.cpp deleted file mode 100644 index c875217e0..000000000 --- a/game/client/cstrike/VGUI/backgroundpanel.cpp +++ /dev/null @@ -1,676 +0,0 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -// $NoKeywords: $ -//=============================================================================// - -#include "cbase.h" -#include "backgroundpanel.h" - -#include -#include -#include -#include -#include -#include "vgui_controls/BuildGroup.h" -#include "vgui_controls/BitmapImagePanel.h" - -using namespace vgui; - -#define DEBUG_WINDOW_RESIZING 0 -#define DEBUG_WINDOW_REPOSITIONING 0 - -//----------------------------------------------------------------------------- -const int NumSegments = 7; -static int coord[NumSegments+1] = { - 0, - 1, - 2, - 3, - 4, - 6, - 9, - 10 -}; - -//----------------------------------------------------------------------------- -void DrawRoundedBackground( Color bgColor, int wide, int tall ) -{ - int x1, x2, y1, y2; - surface()->DrawSetColor(bgColor); - surface()->DrawSetTextColor(bgColor); - - int i; - - // top-left corner -------------------------------------------------------- - int xDir = 1; - int yDir = -1; - int xIndex = 0; - int yIndex = NumSegments - 1; - int xMult = 1; - int yMult = 1; - int x = 0; - int y = 0; - for ( i=0; iDrawFilledRect( x1, y1, x2, y2 ); - - xIndex += xDir; - yIndex += yDir; - } - - // top-right corner ------------------------------------------------------- - xDir = 1; - yDir = -1; - xIndex = 0; - yIndex = NumSegments - 1; - x = wide; - y = 0; - xMult = -1; - yMult = 1; - for ( i=0; iDrawFilledRect( x1, y1, x2, y2 ); - xIndex += xDir; - yIndex += yDir; - } - - // bottom-right corner ---------------------------------------------------- - xDir = 1; - yDir = -1; - xIndex = 0; - yIndex = NumSegments - 1; - x = wide; - y = tall; - xMult = -1; - yMult = -1; - for ( i=0; iDrawFilledRect( x1, y1, x2, y2 ); - xIndex += xDir; - yIndex += yDir; - } - - // bottom-left corner ----------------------------------------------------- - xDir = 1; - yDir = -1; - xIndex = 0; - yIndex = NumSegments - 1; - x = 0; - y = tall; - xMult = 1; - yMult = -1; - for ( i=0; iDrawFilledRect( x1, y1, x2, y2 ); - xIndex += xDir; - yIndex += yDir; - } - - // paint between top left and bottom left --------------------------------- - x1 = 0; - x2 = coord[NumSegments]; - y1 = coord[NumSegments]; - y2 = tall - coord[NumSegments]; - surface()->DrawFilledRect( x1, y1, x2, y2 ); - - // paint between left and right ------------------------------------------- - x1 = coord[NumSegments]; - x2 = wide - coord[NumSegments]; - y1 = 0; - y2 = tall; - surface()->DrawFilledRect( x1, y1, x2, y2 ); - - // paint between top right and bottom right ------------------------------- - x1 = wide - coord[NumSegments]; - x2 = wide; - y1 = coord[NumSegments]; - y2 = tall - coord[NumSegments]; - surface()->DrawFilledRect( x1, y1, x2, y2 ); -} - -//----------------------------------------------------------------------------- -void DrawRoundedBorder( Color borderColor, int wide, int tall ) -{ - int x1, x2, y1, y2; - surface()->DrawSetColor(borderColor); - surface()->DrawSetTextColor(borderColor); - - int i; - - // top-left corner -------------------------------------------------------- - int xDir = 1; - int yDir = -1; - int xIndex = 0; - int yIndex = NumSegments - 1; - int xMult = 1; - int yMult = 1; - int x = 0; - int y = 0; - for ( i=0; iDrawFilledRect( x1, y1, x2, y2 ); - - xIndex += xDir; - yIndex += yDir; - } - - // top-right corner ------------------------------------------------------- - xDir = 1; - yDir = -1; - xIndex = 0; - yIndex = NumSegments - 1; - x = wide; - y = 0; - xMult = -1; - yMult = 1; - for ( i=0; iDrawFilledRect( x1, y1, x2, y2 ); - xIndex += xDir; - yIndex += yDir; - } - - // bottom-right corner ---------------------------------------------------- - xDir = 1; - yDir = -1; - xIndex = 0; - yIndex = NumSegments - 1; - x = wide; - y = tall; - xMult = -1; - yMult = -1; - for ( i=0; iDrawFilledRect( x1, y1, x2, y2 ); - xIndex += xDir; - yIndex += yDir; - } - - // bottom-left corner ----------------------------------------------------- - xDir = 1; - yDir = -1; - xIndex = 0; - yIndex = NumSegments - 1; - x = 0; - y = tall; - xMult = 1; - yMult = -1; - for ( i=0; iDrawFilledRect( x1, y1, x2, y2 ); - xIndex += xDir; - yIndex += yDir; - } - - // top -------------------------------------------------------------------- - x1 = coord[NumSegments]; - x2 = wide - coord[NumSegments]; - y1 = 0; - y2 = 1; - surface()->DrawFilledRect( x1, y1, x2, y2 ); - - // bottom ----------------------------------------------------------------- - x1 = coord[NumSegments]; - x2 = wide - coord[NumSegments]; - y1 = tall - 1; - y2 = tall; - surface()->DrawFilledRect( x1, y1, x2, y2 ); - - // left ------------------------------------------------------------------- - x1 = 0; - x2 = 1; - y1 = coord[NumSegments]; - y2 = tall - coord[NumSegments]; - surface()->DrawFilledRect( x1, y1, x2, y2 ); - - // right ------------------------------------------------------------------ - x1 = wide - 1; - x2 = wide; - y1 = coord[NumSegments]; - y2 = tall - coord[NumSegments]; - surface()->DrawFilledRect( x1, y1, x2, y2 ); -} - -//----------------------------------------------------------------------------- -class CaptionLabel : public Label -{ -public: - CaptionLabel(Panel *parent, const char *panelName, const char *text) : Label(parent, panelName, text) - { - } - - virtual void ApplySchemeSettings( vgui::IScheme *pScheme ) - { - Label::ApplySchemeSettings( pScheme ); - SetFont( pScheme->GetFont( "MenuTitle", IsProportional() ) ); - } -}; - -//----------------------------------------------------------------------------- -// Purpose: transform a normalized value into one that is scaled based the minimum -// of the horizontal and vertical ratios -//----------------------------------------------------------------------------- -static int GetAlternateProportionalValueFromNormal(int normalizedValue) -{ - int wide, tall; - GetHudSize( wide, tall ); - int proH, proW; - surface()->GetProportionalBase( proW, proH ); - double scaleH = (double)tall / (double)proH; - double scaleW = (double)wide / (double)proW; - double scale = (scaleW < scaleH) ? scaleW : scaleH; - - return (int)( normalizedValue * scale ); -} - -//----------------------------------------------------------------------------- -// Purpose: transform a standard scaled value into one that is scaled based the minimum -// of the horizontal and vertical ratios -//----------------------------------------------------------------------------- -int GetAlternateProportionalValueFromScaled( HScheme hScheme, int scaledValue) -{ - return GetAlternateProportionalValueFromNormal( scheme()->GetProportionalNormalizedValueEx( hScheme, scaledValue ) ); -} - -//----------------------------------------------------------------------------- -// Purpose: moves and resizes a single control -//----------------------------------------------------------------------------- -static void RepositionControl( Panel *pPanel ) -{ - int x, y, w, h; - pPanel->GetBounds(x, y, w, h); - -#if DEBUG_WINDOW_RESIZING - int x1, y1, w1, h1; - pPanel->GetBounds(x1, y1, w1, h1); - int x2, y2, w2, h2; - x2 = scheme()->GetProportionalNormalizedValueEx( pPanel->GetScheme(), x1 ); - y2 = scheme()->GetProportionalNormalizedValueEx( pPanel->GetScheme(), y1 ); - w2 = scheme()->GetProportionalNormalizedValueEx( pPanel->GetScheme(), w1 ); - h2 = scheme()->GetProportionalNormalizedValueEx( pPanel->GetScheme(), h1 ); -#endif - - x = GetAlternateProportionalValueFromScaled( pPanel->GetScheme(), x ); - y = GetAlternateProportionalValueFromScaled( pPanel->GetScheme(), y ); - w = GetAlternateProportionalValueFromScaled( pPanel->GetScheme(), w ); - h = GetAlternateProportionalValueFromScaled( pPanel->GetScheme(), h ); - - pPanel->SetBounds(x, y, w, h); - -#if DEBUG_WINDOW_RESIZING - DevMsg( "Resizing '%s' from (%d,%d) %dx%d to (%d,%d) %dx%d -- initially was (%d,%d) %dx%d\n", - pPanel->GetName(), x1, y1, w1, h1, x, y, w, h, x2, y2, w2, h2 ); -#endif -} - -//----------------------------------------------------------------------------- -// Purpose: Sets colors etc for background image panels -//----------------------------------------------------------------------------- -void ApplyBackgroundSchemeSettings( EditablePanel *pWindow, vgui::IScheme *pScheme ) -{ - Color bgColor = Color( 255, 255, 255, pScheme->GetColor( "BgColor", Color( 0, 0, 0, 0 ) )[3] ); - Color fgColor = pScheme->GetColor( "FgColor", Color( 0, 0, 0, 0 ) ); - - if ( !pWindow ) - return; - - CBitmapImagePanel *pBitmapPanel; - - // corners -------------------------------------------- - pBitmapPanel = dynamic_cast< CBitmapImagePanel * >(pWindow->FindChildByName( "TopLeftPanel" )); - if ( pBitmapPanel ) - { - pBitmapPanel->setImageColor( bgColor ); - } - pBitmapPanel = dynamic_cast< CBitmapImagePanel * >(pWindow->FindChildByName( "TopRightPanel" )); - if ( pBitmapPanel ) - { - pBitmapPanel->setImageColor( bgColor ); - } - pBitmapPanel = dynamic_cast< CBitmapImagePanel * >(pWindow->FindChildByName( "BottomLeftPanel" )); - if ( pBitmapPanel ) - { - pBitmapPanel->setImageColor( bgColor ); - } - pBitmapPanel = dynamic_cast< CBitmapImagePanel * >(pWindow->FindChildByName( "BottomRightPanel" )); - if ( pBitmapPanel ) - { - pBitmapPanel->setImageColor( bgColor ); - } - - // background ----------------------------------------- - pBitmapPanel = dynamic_cast< CBitmapImagePanel * >(pWindow->FindChildByName( "TopSolid" )); - if ( pBitmapPanel ) - { - pBitmapPanel->setImageColor( bgColor ); - } - pBitmapPanel = dynamic_cast< CBitmapImagePanel * >(pWindow->FindChildByName( "UpperMiddleSolid" )); - if ( pBitmapPanel ) - { - pBitmapPanel->setImageColor( bgColor ); - } - pBitmapPanel = dynamic_cast< CBitmapImagePanel * >(pWindow->FindChildByName( "LowerMiddleSolid" )); - if ( pBitmapPanel ) - { - pBitmapPanel->setImageColor( bgColor ); - } - pBitmapPanel = dynamic_cast< CBitmapImagePanel * >(pWindow->FindChildByName( "BottomSolid" )); - if ( pBitmapPanel ) - { - pBitmapPanel->setImageColor( bgColor ); - } - - // Logo ----------------------------------------------- - pBitmapPanel = dynamic_cast< CBitmapImagePanel * >(pWindow->FindChildByName( "ExclamationPanel" )); - if ( pBitmapPanel ) - { - pBitmapPanel->setImageColor( fgColor ); - } -} - -//----------------------------------------------------------------------------- -// Purpose: Re-aligns background image panels so they are touching. -//----------------------------------------------------------------------------- -static void FixupBackgroundPanels( EditablePanel *pWindow, int offsetX, int offsetY ) -{ - if ( !pWindow ) - return; - - int screenWide, screenTall; - pWindow->GetSize( screenWide, screenTall ); - - int inset = GetAlternateProportionalValueFromNormal( 20 ); - int cornerSize = GetAlternateProportionalValueFromNormal( 10 ); - - int titleHeight = GetAlternateProportionalValueFromNormal( 42 ); - int mainHeight = GetAlternateProportionalValueFromNormal( 376 ); - - int logoSize = titleHeight; - - int captionInset = GetAlternateProportionalValueFromNormal( 76 ); - - Panel *pPanel; - - // corners -------------------------------------------- - pPanel = pWindow->FindChildByName( "TopLeftPanel" ); - if ( pPanel ) - { - pPanel->SetZPos( -20 ); - pPanel->SetBounds( offsetX + inset, offsetY + inset, cornerSize, cornerSize ); - } - - pPanel = pWindow->FindChildByName( "TopRightPanel" ); - if ( pPanel ) - { - pPanel->SetZPos( -20 ); - pPanel->SetBounds( screenWide - offsetX - inset - cornerSize, offsetY + inset, cornerSize, cornerSize ); - } - - pPanel = pWindow->FindChildByName( "BottomLeftPanel" ); - if ( pPanel ) - { - pPanel->SetZPos( -20 ); - pPanel->SetBounds( offsetX + inset, screenTall - offsetY - inset - cornerSize, cornerSize, cornerSize ); - } - - pPanel = pWindow->FindChildByName( "BottomRightPanel" ); - if ( pPanel ) - { - pPanel->SetZPos( -20 ); - pPanel->SetBounds( screenWide - offsetX - inset - cornerSize, screenTall - offsetY - inset - cornerSize, cornerSize, cornerSize ); - } - - // background ----------------------------------------- - pPanel = pWindow->FindChildByName( "TopSolid" ); - if ( pPanel ) - { - pPanel->SetZPos( -20 ); - pPanel->SetBounds( offsetX + inset + cornerSize, offsetY + inset, screenWide - 2*offsetX - 2*inset - 2*cornerSize, cornerSize ); - } - - pPanel = pWindow->FindChildByName( "UpperMiddleSolid" ); - if ( pPanel ) - { - pPanel->SetZPos( -20 ); - pPanel->SetBounds( offsetX + inset, offsetY + inset + cornerSize, screenWide - 2*offsetX - 2*inset, titleHeight ); - } - - pPanel = pWindow->FindChildByName( "LowerMiddleSolid" ); - if ( pPanel ) - { - pPanel->SetZPos( -20 ); - pPanel->SetBounds( offsetX + inset + cornerSize, screenTall - offsetY - inset - cornerSize, screenWide - 2*offsetX - 2*inset - 2*cornerSize, cornerSize ); - } - - pPanel = pWindow->FindChildByName( "BottomSolid" ); - if ( pPanel ) - { - pPanel->SetZPos( -20 ); - pPanel->SetBounds( offsetX + inset, screenTall - offsetY - inset - cornerSize - mainHeight, screenWide - 2*offsetX - 2*inset, mainHeight ); - } - - // transparent border --------------------------------- - pPanel = pWindow->FindChildByName( "TopClear" ); - if ( pPanel ) - { - pPanel->SetZPos( -20 ); - pPanel->SetBounds( 0, 0, screenWide, offsetY + inset ); - } - - pPanel = pWindow->FindChildByName( "BottomClear" ); - if ( pPanel ) - { - pPanel->SetZPos( -20 ); - pPanel->SetBounds( 0, screenTall - offsetY - inset, screenWide, offsetY + inset ); - } - - pPanel = pWindow->FindChildByName( "LeftClear" ); - if ( pPanel ) - { - pPanel->SetZPos( -20 ); - pPanel->SetBounds( 0, offsetY + inset, offsetX + inset, screenTall - 2*offsetY - 2*inset ); - } - - pPanel = pWindow->FindChildByName( "RightClear" ); - if ( pPanel ) - { - pPanel->SetZPos( -20 ); - pPanel->SetBounds( screenWide - offsetX - inset, offsetY + inset, offsetX + inset, screenTall - 2*offsetY - 2*inset ); - } - - // Logo ----------------------------------------------- - int logoInset = (cornerSize + titleHeight - logoSize)/2; - pPanel = pWindow->FindChildByName( "ExclamationPanel" ); - if ( pPanel ) - { - pPanel->SetZPos( -19 ); // higher than the background - pPanel->SetBounds( offsetX + inset + logoInset, offsetY + inset + logoInset, logoSize, logoSize ); - } - - // Title caption -------------------------------------- - pPanel = dynamic_cast< Label * >(pWindow->FindChildByName( "CaptionLabel" )); - if ( pPanel ) - { - pPanel->SetZPos( -19 ); // higher than the background - pPanel->SetBounds( offsetX + captionInset/*inset + 2*logoInset + logoSize*/, offsetY + inset + logoInset, screenWide, logoSize ); - } -} - -//----------------------------------------------------------------------------- -// Purpose: Creates background image panels -//----------------------------------------------------------------------------- -void CreateBackground( EditablePanel *pWindow ) -{ - // corners -------------------------------------------- - new CBitmapImagePanel( pWindow, "TopLeftPanel", "gfx/vgui/round_corner_nw" ); - new CBitmapImagePanel( pWindow, "TopRightPanel", "gfx/vgui/round_corner_ne" ); - new CBitmapImagePanel( pWindow, "BottomLeftPanel", "gfx/vgui/round_corner_sw" ); - new CBitmapImagePanel( pWindow, "BottomRightPanel", "gfx/vgui/round_corner_se" ); - - // background ----------------------------------------- - new CBitmapImagePanel( pWindow, "TopSolid", "gfx/vgui/solid_background" ); - new CBitmapImagePanel( pWindow, "UpperMiddleSolid", "gfx/vgui/solid_background" ); - new CBitmapImagePanel( pWindow, "LowerMiddleSolid", "gfx/vgui/solid_background" ); - new CBitmapImagePanel( pWindow, "BottomSolid", "gfx/vgui/solid_background" ); - - // transparent border --------------------------------- - new CBitmapImagePanel( pWindow, "TopClear", "gfx/vgui/trans_background" ); - new CBitmapImagePanel( pWindow, "BottomClear", "gfx/vgui/trans_background" ); - new CBitmapImagePanel( pWindow, "LeftClear", "gfx/vgui/trans_background" ); - new CBitmapImagePanel( pWindow, "RightClear", "gfx/vgui/trans_background" ); - - // Logo ----------------------------------------------- - new CBitmapImagePanel( pWindow, "ExclamationPanel", "gfx/vgui/CS_logo" ); - - // Title caption -------------------------------------- - Panel *pPanel = dynamic_cast< Label * >(pWindow->FindChildByName( "CaptionLabel" )); - if ( !pPanel ) - new CaptionLabel( pWindow, "CaptionLabel", "" ); -} - -void ResizeWindowControls( EditablePanel *pWindow, int tall, int wide, int offsetX, int offsetY ) -{ - if (!pWindow || !pWindow->GetBuildGroup() || !pWindow->GetBuildGroup()->GetPanelList()) - return; - - CUtlVector *panelList = pWindow->GetBuildGroup()->GetPanelList(); - CUtlVector resizedPanels; - CUtlVector movedPanels; - - // Resize to account for 1.25 aspect ratio (1280x1024) screens - { - for ( int i = 0; i < panelList->Size(); ++i ) - { - PHandle handle = (*panelList)[i]; - - Panel *panel = handle.Get(); - - bool found = false; - for ( int j = 0; j < resizedPanels.Size(); ++j ) - { - if (panel == resizedPanels[j]) - found = true; - } - - if (!panel || found) - { - continue; - } - - resizedPanels.AddToTail( panel ); // don't move a panel more than once - - if ( panel != pWindow ) - { - RepositionControl( panel ); - } - } - } - - // and now re-center them. Woohoo! - for ( int i = 0; i < panelList->Size(); ++i ) - { - PHandle handle = (*panelList)[i]; - - Panel *panel = handle.Get(); - - bool found = false; - for ( int j = 0; j < movedPanels.Size(); ++j ) - { - if (panel == movedPanels[j]) - found = true; - } - - if (!panel || found) - { - continue; - } - - movedPanels.AddToTail( panel ); // don't move a panel more than once - - if ( panel != pWindow ) - { - int x, y; - - panel->GetPos( x, y ); - panel->SetPos( x + offsetX, y + offsetY ); - -#if DEBUG_WINDOW_REPOSITIONING - DevMsg( "Repositioning '%s' from (%d,%d) to (%d,%d) -- a distance of (%d,%d)\n", - panel->GetName(), x, y, x + offsetX, y + offsetY, offsetX, offsetY ); -#endif - } - } -} - -//----------------------------------------------------------------------------- -// Purpose: Resizes windows to fit completely on-screen (for 1280x1024), and -// centers them on the screen. Sub-controls are also resized and moved. -//----------------------------------------------------------------------------- -void LayoutBackgroundPanel( EditablePanel *pWindow ) -{ - if ( !pWindow ) - return; - - int screenW, screenH; - GetHudSize( screenW, screenH ); - - int wide, tall; - pWindow->GetSize( wide, tall ); - - int offsetX = 0; - int offsetY = 0; - - // Slide everything over to the center - pWindow->SetBounds( 0, 0, screenW, screenH ); - - if ( wide != screenW || tall != screenH ) - { - wide = GetAlternateProportionalValueFromScaled( pWindow->GetScheme(), wide); - tall = GetAlternateProportionalValueFromScaled( pWindow->GetScheme(), tall); - - offsetX = (screenW - wide)/2; - offsetY = (screenH - tall)/2; - - ResizeWindowControls( pWindow, tall, wide, offsetX, offsetY ); - } - - // now that the panels are moved/resized, look for some bg panels, and re-align them - FixupBackgroundPanels( pWindow, offsetX, offsetY ); -} - -//----------------------------------------------------------------------------- - diff --git a/game/client/cstrike/VGUI/backgroundpanel.h b/game/client/cstrike/VGUI/backgroundpanel.h deleted file mode 100644 index 5edf22e88..000000000 --- a/game/client/cstrike/VGUI/backgroundpanel.h +++ /dev/null @@ -1,53 +0,0 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -// $NoKeywords: $ -//=============================================================================// - -#ifndef CSBACKGROUND_H -#define CSBACKGROUND_H - -#include -#include - -//----------------------------------------------------------------------------- -// Purpose: Creates background image panels -//----------------------------------------------------------------------------- -void CreateBackground( vgui::EditablePanel *pWindow ); - -//----------------------------------------------------------------------------- -// Purpose: Resizes windows to fit completely on-screen (for 1280x1024), and -// centers them on the screen. Sub-controls are also resized and moved. -//----------------------------------------------------------------------------- -void LayoutBackgroundPanel( vgui::EditablePanel *pWindow ); - -//----------------------------------------------------------------------------- -// Purpose: Sets colors etc for background image panels -//----------------------------------------------------------------------------- -void ApplyBackgroundSchemeSettings( vgui::EditablePanel *pWindow, vgui::IScheme *pScheme ); - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void ResizeWindowControls( vgui::EditablePanel *pWindow, int tall, int wide, int offsetX, int offsetY ); - -//----------------------------------------------------------------------------- -// Purpose: transform a standard scaled value into one that is scaled based the minimum -// of the horizontal and vertical ratios -//----------------------------------------------------------------------------- -int GetAlternateProportionalValueFromScaled( vgui::HScheme scheme, int scaledValue ); - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void DrawRoundedBackground( Color bgColor, int wide, int tall ); - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void DrawRoundedBorder( Color borderColor, int wide, int tall ); - -//----------------------------------------------------------------------------- - -#endif // CSBACKGROUND_H diff --git a/game/client/cstrike/VGUI/base_stats_page.cpp b/game/client/cstrike/VGUI/base_stats_page.cpp deleted file mode 100644 index ab27865b6..000000000 --- a/game/client/cstrike/VGUI/base_stats_page.cpp +++ /dev/null @@ -1,359 +0,0 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// -// -// -//=============================================================================// - -#include "cbase.h" -#include "tier3/tier3.h" -#include "vgui/ILocalize.h" -#include "lifetime_stats_page.h" -#include -#include "cs_client_gamestats.h" -#include "filesystem.h" -#include "cs_weapon_parse.h" -#include "buy_presets/buy_presets.h" -#include "../vgui_controls/ScrollBar.h" -#include "stat_card.h" - -using namespace vgui; - -// memdbgon must be the last include file in a .cpp file!!! -#include "tier0/memdbgon.h" - - -KeyValues *g_pPreloadedCSBaseStatGroupLayout = NULL; - -//----------------------------------------------------------------------------- -// Purpose: creates child panels, passes down name to pick up any settings from res files. -//----------------------------------------------------------------------------- -CBaseStatsPage::CBaseStatsPage(vgui::Panel *parent, const char *name) : BaseClass(parent, "CSBaseStatsDialog") -{ - vgui::IScheme *pScheme = scheme()->GetIScheme( GetScheme() ); - - m_listItemFont = pScheme->GetFont( "StatsPageText", IsProportional() ); - - m_statsList = new SectionedListPanel( this, "StatsList" ); - m_statsList->SetClickable(false); - m_statsList->SetDrawHeaders(false); - - m_bottomBar = new ImagePanel(this, "BottomBar"); - - m_pGroupsList = new vgui::PanelListPanel( this, "listpanel_groups" ); - m_pGroupsList->SetFirstColumnWidth( 0 ); - - SetBounds(0, 0, 900, 780); - SetMinimumSize( 256, 780 ); - - SetBgColor(GetSchemeColor("ListPanel.BgColor", GetBgColor(), pScheme)); - - m_pStatCard = new StatCard(this, "ignored"); - - ListenForGameEvent( "player_stats_updated" ); - - m_bStatsDirty = true; -} - -CBaseStatsPage::~CBaseStatsPage() -{ - delete m_statsList; -} - - -void CBaseStatsPage::MoveToFront() -{ - UpdateStatsData(); - m_pStatCard->UpdateInfo(); -} - -void CBaseStatsPage::UpdateStatsData() -{ - // Hide the group list scrollbar - if (m_pGroupsList->GetScrollbar()) - { - m_pGroupsList->GetScrollbar()->SetWide(0); - } - - UpdateGroupPanels(); - RepopulateStats(); - - m_bStatsDirty = false; -} - -//----------------------------------------------------------------------------- -// Purpose: Loads settings from statsdialog.res in hl2/resource/ui/ -//----------------------------------------------------------------------------- -void CBaseStatsPage::ApplySchemeSettings( vgui::IScheme *pScheme ) -{ - BaseClass::ApplySchemeSettings( pScheme ); - LoadControlSettings("resource/ui/CSBaseStatsDialog.res"); - - m_statsList->SetClickable(false); - m_statsList->SetDrawHeaders(false); - - m_statsList->SetVerticalScrollbar(true); - - SetBgColor(Color(86,86,86,255)); - - //Remove any pre-existing sections and add then fresh (this can happen on a resolution change) - m_statsList->RemoveAllSections(); - - m_statsList->AddSection( 0, "Players"); - - m_statsList->SetFontSection(0, m_listItemFont); - - m_pGroupsList->SetBgColor(Color(86,86,86,255)); - m_statsList->SetBgColor(Color(52,52,52,255)); -} - -void CBaseStatsPage::SetActiveStatGroup (CBaseStatGroupPanel* groupPanel) -{ - for (int i = 0; i < m_pGroupsList->GetItemCount(); i++) - { - CBaseStatGroupPanel *pPanel = (CBaseStatGroupPanel*)m_pGroupsList->GetItemPanel(i); - if ( pPanel ) - { - if ( pPanel != groupPanel ) - { - pPanel->SetGroupActive( false ); - } - else - { - pPanel->SetGroupActive( true ); - } - } - } -} - -void CBaseStatsPage::UpdateGroupPanels() -{ - int iGroupCount = m_pGroupsList->GetItemCount(); - vgui::IScheme *pGroupScheme = scheme()->GetIScheme( GetScheme() ); - - for ( int i = 0; i < iGroupCount; i++ ) - { - CBaseStatGroupPanel *pPanel = (CBaseStatGroupPanel*)m_pGroupsList->GetItemPanel(i); - if ( pPanel ) - { - pPanel->Update( pGroupScheme ); - } - } -} - - - -void CBaseStatsPage::OnSizeChanged(int newWide, int newTall) -{ - BaseClass::OnSizeChanged(newWide, newTall); - - if (m_statsList) - { - int labelX, labelY, listX, listY, listWide, listTall; - m_statsList->GetBounds(listX, listY, listWide, listTall); - - if (m_bottomBar) - { - m_bottomBar->GetPos(labelX, labelY); - m_bottomBar->SetPos(labelX, listY + listTall); - } - } -} - -const wchar_t* CBaseStatsPage::TranslateWeaponKillIDToAlias( int statKillID ) -{ - CSWeaponID weaponIDIndex = WEAPON_MAX; - for ( int i = 0; WeaponName_StatId_Table[i].killStatId != CSSTAT_UNDEFINED; ++i ) - { - if( WeaponName_StatId_Table[i].killStatId == statKillID ) - { - weaponIDIndex = WeaponName_StatId_Table[i].weaponId; - break; - } - } - - if (weaponIDIndex == WEAPON_MAX) - { - return NULL; - } - else - { - return WeaponIDToDisplayName(weaponIDIndex); - } -} - -const wchar_t* CBaseStatsPage::LocalizeTagOrUseDefault( const char* tag, const wchar_t* def ) -{ - const wchar_t* result = g_pVGuiLocalize->Find( tag ); - - if ( !result ) - result = def ? def : L"\0"; - - return result; -} - -CBaseStatGroupPanel* CBaseStatsPage::AddGroup( const wchar_t* name, const char* title_tag, const wchar_t* def ) -{ - CBaseStatGroupPanel* newGroup = new CBaseStatGroupPanel( m_pGroupsList, this, "StatGroupPanel", 0 ); - newGroup->SetGroupInfo( name, LocalizeTagOrUseDefault( title_tag, def ) ); - newGroup->SetGroupActive( false ); - - m_pGroupsList->AddItem( NULL, newGroup ); - - return newGroup; -} - -void CBaseStatsPage::FireGameEvent( IGameEvent * event ) -{ - const char *type = event->GetName(); - - if ( 0 == Q_strcmp( type, "player_stats_updated" ) ) - m_bStatsDirty = true; -} - -void CBaseStatsPage::OnThink() -{ - if ( m_bStatsDirty ) - UpdateStatsData(); -} - -CBaseStatGroupPanel::CBaseStatGroupPanel( vgui::PanelListPanel *parent, CBaseStatsPage *owner, const char* name, int iListItemID ) : BaseClass( parent, name ) -{ - m_pParent = parent; - m_pOwner = owner; - m_pSchemeSettings = NULL; - - m_pGroupIcon = SETUP_PANEL(new vgui::ImagePanel( this, "GroupIcon" )); - m_pBaseStatGroupLabel = new vgui::Label( this, "GroupName", "name" ); - m_pGroupButton = new CBaseStatGroupButton(this, "GroupButton", "" ); - m_pGroupButton->SetPos( 0, 0 ); - m_pGroupButton->SetZPos( 20 ); - m_pGroupButton->SetWide( 256 ); - m_pGroupButton->SetTall( 64 ); - SetMouseInputEnabled( true ); - parent->SetMouseInputEnabled( true ); - - m_bActiveButton = false; -} - -CBaseStatGroupPanel::~CBaseStatGroupPanel() -{ - delete m_pBaseStatGroupLabel; - delete m_pGroupIcon; -} - - -//----------------------------------------------------------------------------- -// Purpose: Sets the parameter pIconPanel to display the specified achievement's icon file. -//----------------------------------------------------------------------------- -bool CBaseStatGroupPanel::LoadIcon( const char* pFilename) -{ - char imagePath[_MAX_PATH]; - Q_strncpy( imagePath, "achievements\\", sizeof(imagePath) ); - Q_strncat( imagePath, pFilename, sizeof(imagePath), COPY_ALL_CHARACTERS ); - Q_strncat( imagePath, ".vtf", sizeof(imagePath), COPY_ALL_CHARACTERS ); - - char checkFile[_MAX_PATH]; - Q_snprintf( checkFile, sizeof(checkFile), "materials\\vgui\\%s", imagePath ); - if ( !g_pFullFileSystem->FileExists( checkFile ) ) - { - Q_snprintf( imagePath, sizeof(imagePath), "hud\\icon_locked.vtf" ); - } - - m_pGroupIcon->SetShouldScaleImage( true ); - m_pGroupIcon->SetImage( imagePath ); - m_pGroupIcon->SetVisible( true ); - - return m_pGroupIcon->IsVisible(); -} - - -//----------------------------------------------------------------------------- -// Purpose: Loads settings from hl2/resource/ui/achievementitem.res -// Sets display info for this achievement item. -//----------------------------------------------------------------------------- -void CBaseStatGroupPanel::ApplySchemeSettings( vgui::IScheme* pScheme ) -{ - if ( !g_pPreloadedCSBaseStatGroupLayout ) - { - PreloadResourceFile(); - } - - LoadControlSettings( "", NULL, g_pPreloadedCSBaseStatGroupLayout ); - - m_pSchemeSettings = pScheme; - - BaseClass::ApplySchemeSettings( pScheme ); -} - -void CBaseStatGroupPanel::Update( vgui::IScheme* pScheme ) -{ - if ( m_pSchemeSettings ) - { - - // Set group name text - m_pBaseStatGroupLabel->SetText( m_pGroupTitle ); - m_pBaseStatGroupLabel->SetFgColor(Color(157, 194, 80, 255)); - - if ( !m_bActiveButton ) - { - LoadIcon( "achievement-btn-up" ); - } - else - { - LoadIcon( "achievement-btn-select" ); - } - } -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CBaseStatGroupPanel::PreloadResourceFile( void ) -{ - const char *controlResourceName = "resource/ui/StatGroup.res"; - - g_pPreloadedCSBaseStatGroupLayout = new KeyValues(controlResourceName); - g_pPreloadedCSBaseStatGroupLayout->LoadFromFile(g_pFullFileSystem, controlResourceName); -} - - - -//----------------------------------------------------------------------------- -// Purpose: Assigns a name and achievement id bounds for an achievement group. -//----------------------------------------------------------------------------- -void CBaseStatGroupPanel::SetGroupInfo ( const wchar_t* name, const wchar_t* title) -{ - // Store away the group name - short _textLen = (short)wcslen(name) + 1; - m_pGroupName = new wchar_t[_textLen]; - Q_memcpy( m_pGroupName, name, _textLen * sizeof(wchar_t) ); - - _textLen = (short)wcslen(title) + 1; - m_pGroupTitle = new wchar_t[_textLen]; - Q_memcpy( m_pGroupTitle, title, _textLen * sizeof(wchar_t) ); -} - - -CBaseStatGroupButton::CBaseStatGroupButton( vgui::Panel *pParent, const char *pName, const char *pText ) : -BaseClass( pParent, pName, pText ) -{ -} - -//----------------------------------------------------------------------------- -// Purpose: Handle the case where the user presses an achievement group button. -//----------------------------------------------------------------------------- -void CBaseStatGroupButton::DoClick( void ) -{ - // Process when a group button is hit - CBaseStatGroupPanel* pParent = static_cast(GetParent()); - - if (pParent) - { - CBaseStatsPage* pBaseStatsPage = static_cast(pParent->GetOwner()); - - if (pBaseStatsPage) - { - pBaseStatsPage->SetActiveStatGroup( pParent ); - pBaseStatsPage->UpdateStatsData(); - } - } -} diff --git a/game/client/cstrike/VGUI/base_stats_page.h b/game/client/cstrike/VGUI/base_stats_page.h deleted file mode 100644 index e22ec3230..000000000 --- a/game/client/cstrike/VGUI/base_stats_page.h +++ /dev/null @@ -1,135 +0,0 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -// $NoKeywords: $ -//=============================================================================// - -#ifndef CSBASESTATSPAGE_H -#define CSBASESTATSPAGE_H -#ifdef _WIN32 -#pragma once -#endif - -#include "vgui_controls/PanelListPanel.h" -#include "vgui_controls/Label.h" -#include "tier1/KeyValues.h" -#include "vgui_controls/PropertyPage.h" -#include "vgui_controls/Button.h" -#include "vgui_controls/ImagePanel.h" -#include "GameEventListener.h" - -struct PlayerStatData_t; -class IScheme; -class CBaseStatGroupPanel; -class StatCard; -struct StatsCollection_t; -struct RoundStatsDirectAverage_t; - -class CBaseStatsPage : public vgui::PropertyPage, public CGameEventListener -{ - DECLARE_CLASS_SIMPLE ( CBaseStatsPage, vgui::PropertyPage ); - -public: - CBaseStatsPage( vgui::Panel *parent, const char *name ); - - ~CBaseStatsPage(); - - virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); - virtual void MoveToFront(); - virtual void OnSizeChanged(int wide, int tall); - virtual void OnThink(); - - void UpdateStatsData(); - void SetActiveStatGroup (CBaseStatGroupPanel* groupPanel); - - virtual void FireGameEvent( IGameEvent * event ); - -protected: - - void UpdateGroupPanels(); - CBaseStatGroupPanel* AddGroup( const wchar_t* name, const char* title_tag, const wchar_t* def = NULL ); - const wchar_t* TranslateWeaponKillIDToAlias( int statKillID ); - const wchar_t* LocalizeTagOrUseDefault( const char* tag, const wchar_t* def = NULL ); - - virtual void RepopulateStats() = 0; - - vgui::SectionedListPanel *m_statsList; - vgui::HFont m_listItemFont; - -private: - - vgui::PanelListPanel *m_pGroupsList; - vgui::ImagePanel* m_bottomBar; - StatCard* m_pStatCard; - bool m_bStatsDirty; -}; - - - - -class CBaseStatGroupButton : public vgui::Button -{ - DECLARE_CLASS_SIMPLE( CBaseStatGroupButton, vgui::Button ); - -public: - - CBaseStatGroupButton( vgui::Panel *pParent, const char *pName, const char *pText ); - - virtual void DoClick( void ); -}; - - - - - -class CBaseStatGroupPanel : public vgui::EditablePanel -{ - DECLARE_CLASS_SIMPLE( CBaseStatGroupPanel, vgui::EditablePanel ); - -public: - CBaseStatGroupPanel( vgui::PanelListPanel *parent, CBaseStatsPage *owner, const char* name, int iListItemID ); - ~CBaseStatGroupPanel(); - - void SetGroupInfo ( const wchar_t* name, const wchar_t* title); - - virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); - - void Update( vgui::IScheme* pScheme ); - - vgui::PanelListPanel* GetParent() { return m_pParent; } - CBaseStatsPage* GetOwner() { return m_pOwner; } - - void SetGroupActive(bool active) { m_bActiveButton = active; } - bool IsGroupActive() { return m_bActiveButton; } - -protected: - - // Loads an icon into a specified image panel, or turns the panel off if no icon was found. - bool LoadIcon( const char* pFilename); - -private: - void PreloadResourceFile( void ); - - vgui::PanelListPanel *m_pParent; - CBaseStatsPage *m_pOwner; - - vgui::Label *m_pBaseStatGroupLabel; - - CBaseStatGroupButton *m_pGroupButton; - - vgui::ImagePanel *m_pGroupIcon; - - vgui::IScheme *m_pSchemeSettings; - - bool m_bActiveButton; - - wchar_t *m_pGroupName; - wchar_t *m_pGroupTitle; -}; - - - - - -#endif // CSBASESTATSPAGE_H diff --git a/game/client/cstrike/VGUI/bordered_panel.cpp b/game/client/cstrike/VGUI/bordered_panel.cpp deleted file mode 100644 index cec1d702c..000000000 --- a/game/client/cstrike/VGUI/bordered_panel.cpp +++ /dev/null @@ -1,27 +0,0 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// -//------------------------------------------------------------- -// File: BorderedPanel.cpp -// Desc: -// Author: Peter Freese -// Date: 2009/05/20 -// Copyright: © 2009 Hidden Path Entertainment -//------------------------------------------------------------- - -#include "cbase.h" -#include "bordered_panel.h" -#include "backgroundpanel.h" // rounded border support - -// memdbgon must be the last include file in a .cpp file!!! -#include "tier0/memdbgon.h" - -void BorderedPanel::PaintBackground() -{ - int wide, tall; - GetSize( wide, tall ); - - DrawRoundedBackground( GetBgColor(), wide, tall ); - DrawRoundedBorder( GetFgColor(), wide, tall ); -} - -DECLARE_BUILD_FACTORY( BorderedPanel ); - diff --git a/game/client/cstrike/VGUI/bordered_panel.h b/game/client/cstrike/VGUI/bordered_panel.h deleted file mode 100644 index 7279f10be..000000000 --- a/game/client/cstrike/VGUI/bordered_panel.h +++ /dev/null @@ -1,35 +0,0 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// -//------------------------------------------------------------- -// File: bordered_panel.h -// Desc: -// Author: Peter Freese -// Date: 2009/05/20 -// Copyright: © 2009 Hidden Path Entertainment -//------------------------------------------------------------- - -#ifndef INCLUDED_BorderedPanel -#define INCLUDED_BorderedPanel -#pragma once - -#include - -using namespace vgui; - -//----------------------------------------------------------------------------- -// Purpose: Editable panel with a forced rounded/outlined border -//----------------------------------------------------------------------------- -class BorderedPanel : public EditablePanel -{ -public: - DECLARE_CLASS_SIMPLE( BorderedPanel, EditablePanel ); - - BorderedPanel( Panel *parent, const char *name ) : - EditablePanel( parent, name ) - { - } - - void PaintBackground(); -}; - - -#endif // INCLUDED_BorderedPanel diff --git a/game/client/cstrike/VGUI/buymouseoverpanelbutton.h b/game/client/cstrike/VGUI/buymouseoverpanelbutton.h deleted file mode 100644 index 9e5abbf6d..000000000 --- a/game/client/cstrike/VGUI/buymouseoverpanelbutton.h +++ /dev/null @@ -1,397 +0,0 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -// $NoKeywords: $ -//=============================================================================// - -#ifndef BUYMOUSEOVERPANELBUTTON_H -#define BUYMOUSEOVERPANELBUTTON_H -#ifdef _WIN32 -#pragma once -#endif - -#include -#include -#include "mouseoverpanelbutton.h" -#include "hud.h" -#include "c_cs_player.h" -#include "cs_gamerules.h" -#include "cstrike/bot/shared_util.h" -#include -#include -#include - -using namespace vgui; - -//----------------------------------------------------------------------------- -// Purpose: Triggers a new panel when the mouse goes over the button -//----------------------------------------------------------------------------- -class BuyMouseOverPanelButton : public MouseOverPanelButton -{ -private: - typedef MouseOverPanelButton BaseClass; -public: - BuyMouseOverPanelButton(vgui::Panel *parent, const char *panelName, vgui::EditablePanel *panel) : - MouseOverPanelButton( parent, panelName, panel) - { - m_iPrice = 0; - m_iPreviousPrice = 0; - m_iASRestrict = 0; - m_iDEUseOnly = 0; - m_command = NULL; - m_bIsBargain = false; - - m_pBlackMarketPrice = NULL;//new EditablePanel( parent, "BlackMarket_Labels" ); - if ( m_pBlackMarketPrice ) - { - m_pBlackMarketPrice->LoadControlSettings( "Resource/UI/BlackMarket_Labels.res" ); - - int x,y,wide,tall; - GetClassPanel()->GetBounds( x, y, wide, tall ); - m_pBlackMarketPrice->SetBounds( x, y, wide, tall ); - int px, py; - GetClassPanel()->GetPinOffset( px, py ); - int rx, ry; - GetClassPanel()->GetResizeOffset( rx, ry ); - // Apply pin settings from template, too - m_pBlackMarketPrice->SetAutoResize( GetClassPanel()->GetPinCorner(), GetClassPanel()->GetAutoResize(), px, py, rx, ry ); - } - } - - virtual void ApplySettings( KeyValues *resourceData ) - { - BaseClass::ApplySettings( resourceData ); - - KeyValues *kv = resourceData->FindKey( "cost", false ); - if( kv ) // if this button has a cost defined for it - { - m_iPrice = kv->GetInt(); // save the price away - } - - kv = resourceData->FindKey( "as_restrict", false ); - if( kv ) // if this button has a map limitation for it - { - m_iASRestrict = kv->GetInt(); // save the as_restrict away - } - - kv = resourceData->FindKey( "de_useonly", false ); - if( kv ) // if this button has a map limitation for it - { - m_iDEUseOnly = kv->GetInt(); // save the de_useonly away - } - - if ( m_command ) - { - delete[] m_command; - m_command = NULL; - } - kv = resourceData->FindKey( "command", false ); - if ( kv ) - { - m_command = CloneString( kv->GetString() ); - } - - SetPriceState(); - SetMapTypeState(); - } - - int GetASRestrict() { return m_iASRestrict; } - - int GetDEUseOnly() { return m_iDEUseOnly; } - - virtual void PerformLayout() - { - BaseClass::PerformLayout(); - SetPriceState(); - SetMapTypeState(); - -#ifndef CS_SHIELD_ENABLED - if ( !Q_stricmp( GetName(), "shield" ) ) - { - SetVisible( false ); - SetEnabled( false ); - } -#endif - } - - virtual void ApplySchemeSettings( vgui::IScheme *pScheme ) - { - BaseClass::ApplySchemeSettings( pScheme ); - - m_avaliableColor = pScheme->GetColor( "Label.TextColor", Color( 0, 0, 0, 0 ) ); - m_unavailableColor = pScheme->GetColor( "Label.DisabledFgColor2", Color( 0, 0, 0, 0 ) ); - m_bargainColor = Color( 0, 255, 0, 192 ); - - SetPriceState(); - SetMapTypeState(); - } - - void SetPriceState() - { - if ( CSGameRules() && CSGameRules()->IsBlackMarket() ) - { - SetMarketState(); - } - else - { - if ( GetParent() ) - { - Panel *pPanel = dynamic_cast< Panel * >(GetParent()->FindChildByName( "MarketSticker" ) ); - - if ( pPanel ) - { - pPanel->SetVisible( false ); - } - } - - m_bIsBargain = false; - } - - C_CSPlayer *pPlayer = C_CSPlayer::GetLocalCSPlayer(); - - if ( m_iPrice && ( pPlayer && m_iPrice > pPlayer->GetAccount() ) ) - { - SetFgColor( m_unavailableColor ); - SetCommand( "buy_unavailable" ); - } - else - { - if ( m_bIsBargain == false ) - { - SetFgColor( m_avaliableColor ); - } - else - { - SetFgColor( m_bargainColor ); - } - - SetCommand( m_command ); - } - } - - void SetMarketState( void ) - { - Panel *pClassPanel = GetClassPanel(); - if ( pClassPanel ) - { - pClassPanel->SetVisible( false ); - } - - if ( m_pBlackMarketPrice ) - { - Label *pLabel = dynamic_cast< Label * >(m_pBlackMarketPrice->FindChildByName( "pricelabel" ) ); - - if ( pLabel ) - { - const int BufLen = 2048; - wchar_t wbuf[BufLen] = L""; - const wchar_t *formatStr = g_pVGuiLocalize->Find("#Cstrike_MarketPreviousPrice"); - - if ( !formatStr ) - formatStr = L"%s1"; - - char strPrice[16]; - wchar_t szPrice[64]; - Q_snprintf( strPrice, sizeof( strPrice ), "%d", m_iPreviousPrice ); - - g_pVGuiLocalize->ConvertANSIToUnicode( strPrice, szPrice, sizeof(szPrice)); - - g_pVGuiLocalize->ConstructString( wbuf, sizeof(wbuf), formatStr, 1, szPrice ); - pLabel->SetText( wbuf ); - pLabel->SetVisible( true ); - } - - pLabel = dynamic_cast< Label * >(m_pBlackMarketPrice->FindChildByName( "price" ) ); - - if ( pLabel ) - { - const int BufLen = 2048; - wchar_t wbuf[BufLen] = L""; - const wchar_t *formatStr = g_pVGuiLocalize->Find("#Cstrike_MarketCurrentPrice"); - - if ( !formatStr ) - formatStr = L"%s1"; - - char strPrice[16]; - wchar_t szPrice[64]; - Q_snprintf( strPrice, sizeof( strPrice ), "%d", m_iPrice ); - - g_pVGuiLocalize->ConvertANSIToUnicode( strPrice, szPrice, sizeof(szPrice)); - - g_pVGuiLocalize->ConstructString( wbuf, sizeof(wbuf), formatStr, 1, szPrice ); - pLabel->SetText( wbuf ); - pLabel->SetVisible( true ); - } - - pLabel = dynamic_cast< Label * >(m_pBlackMarketPrice->FindChildByName( "difference" ) ); - - if ( pLabel ) - { - const int BufLen = 2048; - wchar_t wbuf[BufLen] = L""; - const wchar_t *formatStr = g_pVGuiLocalize->Find("#Cstrike_MarketDeltaPrice"); - - if ( !formatStr ) - formatStr = L"%s1"; - - char strPrice[16]; - wchar_t szPrice[64]; - - int iDifference = m_iPreviousPrice - m_iPrice; - - if ( iDifference >= 0 ) - { - pLabel->SetFgColor( m_bargainColor ); - } - else - { - pLabel->SetFgColor( Color( 192, 28, 0, 255 ) ); - } - - Q_snprintf( strPrice, sizeof( strPrice ), "%d", abs( iDifference ) ); - - g_pVGuiLocalize->ConvertANSIToUnicode( strPrice, szPrice, sizeof(szPrice)); - - g_pVGuiLocalize->ConstructString( wbuf, sizeof(wbuf), formatStr, 1, szPrice ); - pLabel->SetText( wbuf ); - pLabel->SetVisible( true ); - } - - ImagePanel *pImage = dynamic_cast< ImagePanel * >(m_pBlackMarketPrice->FindChildByName( "classimage" ) ); - - if ( pImage ) - { - ImagePanel *pClassImage = dynamic_cast< ImagePanel * >(GetClassPanel()->FindChildByName( "classimage" ) ); - - if ( pClassImage ) - { - pImage->SetSize( pClassImage->GetWide(), pClassImage->GetTall() ); - pImage->SetImage( pClassImage->GetImage() ); - } - } - - if ( GetParent() ) - { - Panel *pPanel = dynamic_cast< Panel * >(GetParent()->FindChildByName( "MarketSticker" ) ); - - if ( pPanel ) - { - if ( m_bIsBargain ) - { - pPanel->SetVisible( true ); - } - else - { - pPanel->SetVisible( false ); - } - } - } - } - } - - void SetMapTypeState() - { - CCSGameRules *pRules = CSGameRules(); - - if ( pRules ) - { - if( pRules->IsVIPMap() ) - { - if ( m_iASRestrict ) - { - SetFgColor( m_unavailableColor ); - SetCommand( "buy_unavailable" ); - } - } - - if ( !pRules->IsBombDefuseMap() ) - { - if ( m_iDEUseOnly ) - { - SetFgColor( m_unavailableColor ); - SetCommand( "buy_unavailable" ); - } - } - } - } - - void SetBargainButton( bool state ) - { - m_bIsBargain = state; - } - - void SetCurrentPrice( int iPrice ) - { - m_iPrice = iPrice; - } - - void SetPreviousPrice( int iPrice ) - { - m_iPreviousPrice = iPrice; - } - - const char *GetBuyCommand( void ) - { - return m_command; - } - - virtual void ShowPage() - { - if ( g_lastPanel ) - { - for( int i = 0; i< g_lastPanel->GetParent()->GetChildCount(); i++ ) - { - MouseOverPanelButton *buyButton = dynamic_cast(g_lastPanel->GetParent()->GetChild(i)); - - if ( buyButton ) - { - buyButton->HidePage(); - } - } - } - - BaseClass::ShowPage(); - - if ( !Q_stricmp( m_command, "vguicancel" ) ) - return; - - if ( CSGameRules() && CSGameRules()->IsBlackMarket() ) - { - if ( m_pBlackMarketPrice && !m_pBlackMarketPrice->IsVisible() ) - { - m_pBlackMarketPrice->SetVisible( true ); - } - } - } - - virtual void HidePage() - { - BaseClass::HidePage(); - - if ( m_pBlackMarketPrice && m_pBlackMarketPrice->IsVisible() ) - { - m_pBlackMarketPrice->SetVisible( false ); - } - } - -private: - - int m_iPrice; - int m_iPreviousPrice; - int m_iASRestrict; - int m_iDEUseOnly; - bool m_bIsBargain; - - Color m_avaliableColor; - Color m_unavailableColor; - Color m_bargainColor; - - char *m_command; - -public: - vgui::EditablePanel *m_pBlackMarketPrice; -}; - - -#endif // BUYMOUSEOVERPANELBUTTON_H diff --git a/game/client/cstrike/VGUI/buypreset_imageinfo.cpp b/game/client/cstrike/VGUI/buypreset_imageinfo.cpp deleted file mode 100644 index 69f93cce7..000000000 --- a/game/client/cstrike/VGUI/buypreset_imageinfo.cpp +++ /dev/null @@ -1,577 +0,0 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -//============================================================================= - -#include "cbase.h" - -#include "weapon_csbase.h" -#include "cs_ammodef.h" - -#include -#include -#include -#include -#include -#include "vgui_controls/BuildGroup.h" -#include "vgui_controls/BitmapImagePanel.h" -#include "vgui_controls/TextEntry.h" -#include "vgui_controls/TextImage.h" -#include "vgui_controls/RichText.h" -#include "vgui_controls/QueryBox.h" -#include "career_box.h" -#include "buypreset_listbox.h" -#include "buypreset_weaponsetlabel.h" - -#include "cstrike/bot/shared_util.h" - -// memdbgon must be the last include file in a .cpp file!!! -#include "tier0/memdbgon.h" - -using namespace vgui; - -//-------------------------------------------------------------------------------------------------------------- -//-------------------------------------------------------------------------------------------------------------- -WeaponImageInfo::WeaponImageInfo() -{ - m_needLayout = m_isCentered = false; - m_left = m_top = m_wide = m_tall = 0; - m_isPrimary = false; - memset( &m_weapon, 0, sizeof(ImageInfo) ); - memset( &m_ammo, 0, sizeof(ImageInfo) ); - m_weaponScale = m_ammoScale = 0; - m_pAmmoText = new TextImage( "" ); -} - -//-------------------------------------------------------------------------------------------------------------- -WeaponImageInfo::~WeaponImageInfo() -{ - delete m_pAmmoText; -} - -//-------------------------------------------------------------------------------------------------------------- -void WeaponImageInfo::ApplyTextSettings( vgui::IScheme *pScheme, bool isProportional ) -{ - Color color = pScheme->GetColor( "FgColor", Color( 0, 0, 0, 0 ) ); - - m_pAmmoText->SetColor( color ); - m_pAmmoText->SetFont( pScheme->GetFont( "Default", isProportional ) ); - m_pAmmoText->SetWrap( false ); -} - -//-------------------------------------------------------------------------------------------------------------- -void WeaponImageInfo::SetBounds( int left, int top, int wide, int tall ) -{ - m_left = left; - m_top = top; - m_wide = wide; - m_tall = tall; - m_needLayout = true; -} - -//-------------------------------------------------------------------------------------------------------------- -void WeaponImageInfo::SetCentered( bool isCentered ) -{ - m_isCentered = isCentered; - m_needLayout = true; -} - -//-------------------------------------------------------------------------------------------------------------- -void WeaponImageInfo::SetScaleAt1024( int weaponScale, int ammoScale ) -{ - m_weaponScale = weaponScale; - m_ammoScale = ammoScale; - m_needLayout = true; -} - -//-------------------------------------------------------------------------------------------------------------- -void WeaponImageInfo::SetWeapon( const BuyPresetWeapon *pWeapon, bool isPrimary, bool useCurrentAmmoType ) -{ - m_pAmmoText->SetText( L"" ); - m_weapon.image = NULL; - m_ammo.image = NULL; - m_isPrimary = isPrimary; - - if ( !pWeapon ) - return; - - wchar_t *multiplierString = g_pVGuiLocalize->Find("#Cstrike_BuyMenuPresetMultiplier"); - if ( !multiplierString ) - multiplierString = L""; - const int BufLen = 32; - wchar_t buf[BufLen]; - - if ( pWeapon->GetAmmoType() == AMMO_CLIPS ) - { - CSWeaponID weaponID = pWeapon->GetWeaponID(); - const CCSWeaponInfo *info = GetWeaponInfo( weaponID ); - int numClips = pWeapon->GetAmmoAmount(); - if ( info ) - { - int maxRounds = GetCSAmmoDef()->MaxCarry( info->iAmmoType ); - int buyClipSize = GetCSAmmoDef()->GetBuySize( info->iAmmoType ); - - int maxClips = (buyClipSize > 0) ? ceil(maxRounds/(float)buyClipSize) : 0; - numClips = MIN( numClips, maxClips ); - m_weapon.image = scheme()->GetImage( ImageFnameFromWeaponID( weaponID, m_isPrimary ), true ); - if ( numClips == 0 ) - { - m_ammo.image = NULL; - } - else if ( info->m_WeaponType == WEAPONTYPE_SHOTGUN ) - { - m_ammo.image = scheme()->GetImage( "gfx/vgui/shell", true ); - } - else if ( isPrimary ) - { - m_ammo.image = scheme()->GetImage( "gfx/vgui/bullet", true ); - } - else - { - m_ammo.image = scheme()->GetImage( "gfx/vgui/cartridge", true ); - } - - if ( numClips > 1 ) - { - g_pVGuiLocalize->ConstructString( buf, sizeof(buf), multiplierString, 1, NumAsWString( numClips ) ); - m_pAmmoText->SetText( buf ); - } - else - { - m_pAmmoText->SetText( L"" ); - } - } - else if ( numClips > 0 || !useCurrentAmmoType ) - { - if ( useCurrentAmmoType ) - { - CSWeaponID currentID = GetClientWeaponID( isPrimary ); - m_weapon.image = scheme()->GetImage( ImageFnameFromWeaponID( currentID, m_isPrimary ), true ); - info = GetWeaponInfo( currentID ); - if ( !info ) - { - m_weapon.image = NULL; - numClips = 0; - } - else if ( info->m_WeaponType == WEAPONTYPE_SHOTGUN ) - { - m_ammo.image = scheme()->GetImage( "gfx/vgui/shell", true ); - } - else if ( isPrimary ) - { - m_ammo.image = scheme()->GetImage( "gfx/vgui/bullet", true ); - } - else - { - m_ammo.image = scheme()->GetImage( "gfx/vgui/cartridge", true ); - } - } - else - { - m_weapon.image = scheme()->GetImage( ImageFnameFromWeaponID( weaponID, m_isPrimary ), true ); - if ( numClips == 0 ) - { - m_ammo.image = NULL; - } - else if ( isPrimary ) - { - m_ammo.image = scheme()->GetImage( "gfx/vgui/bullet", true ); - } - else - { - m_ammo.image = scheme()->GetImage( "gfx/vgui/cartridge", true ); - } - } - if ( numClips > 1 ) - { - g_pVGuiLocalize->ConstructString( buf, sizeof(buf), multiplierString, 1, NumAsWString( numClips ) ); - m_pAmmoText->SetText( buf ); - } - else - { - m_pAmmoText->SetText( L"" ); - } - } - } - m_needLayout = true; -} - -//-------------------------------------------------------------------------------------------------------------- -void WeaponImageInfo::Paint() -{ - if ( m_needLayout ) - PerformLayout(); - - m_weapon.Paint(); - m_ammo.Paint(); -} - -//-------------------------------------------------------------------------------------------------------------- -void WeaponImageInfo::PaintText() -{ - if ( m_needLayout ) - PerformLayout(); - - m_pAmmoText->Paint(); -} - -//-------------------------------------------------------------------------------------------------------------- -void WeaponImageInfo::PerformLayout() -{ - m_needLayout = false; - - m_weapon.FitInBounds( m_left, m_top, m_wide*0.8, m_tall, m_isCentered, m_weaponScale ); - int ammoX = MIN( m_wide*5/6, m_weapon.w ); - int ammoSize = m_tall * 9 / 16; - if ( !m_isPrimary ) - { - ammoSize = ammoSize * 25 / 40; - ammoX = MIN( m_wide*5/6, m_weapon.w*3/4 ); - } - if ( ammoX + ammoSize > m_wide ) - { - ammoX = m_wide - ammoSize; - } - m_ammo.FitInBounds( m_left + ammoX, m_top + m_tall - ammoSize, ammoSize, ammoSize, false, m_ammoScale ); - - int w, h; - m_pAmmoText->ResizeImageToContent(); - m_pAmmoText->GetSize( w, h ); - if ( m_isPrimary ) - { - if ( m_ammoScale < 75 ) - { - m_pAmmoText->SetPos( m_left + ammoX + ammoSize*1.25f - w, m_top + m_tall - h ); - } - else - { - m_pAmmoText->SetPos( m_left + ammoX + ammoSize - w, m_top + m_tall - h ); - } - } - else - { - m_pAmmoText->SetPos( m_left + ammoX + ammoSize, m_top + m_tall - h ); - } -} - -//-------------------------------------------------------------------------------------------------------------- -//-------------------------------------------------------------------------------------------------------------- -WeaponLabel::WeaponLabel(Panel *parent, const char *panelName) : BaseClass( parent, panelName ) -{ - SetSize( 10, 10 ); - SetMouseInputEnabled( false ); -} - -//-------------------------------------------------------------------------------------------------------------- -WeaponLabel::~WeaponLabel() -{ -} - -//-------------------------------------------------------------------------------------------------------------- -void WeaponLabel::SetWeapon( const BuyPresetWeapon *pWeapon, bool isPrimary, bool showAmmo ) -{ - BuyPresetWeapon weapon(WEAPON_NONE); - if ( pWeapon ) - weapon = *pWeapon; - if ( !showAmmo ) - weapon.SetAmmoAmount( 0 ); - m_weapon.SetWeapon( &weapon, isPrimary, false ); -} - -//-------------------------------------------------------------------------------------------------------------- -void WeaponLabel::ApplySchemeSettings(IScheme *pScheme) -{ - BaseClass::ApplySchemeSettings( pScheme ); - - m_weapon.ApplyTextSettings( pScheme, IsProportional() ); -} - -//-------------------------------------------------------------------------------------------------------------- -void WeaponLabel::PerformLayout() -{ - BaseClass::PerformLayout(); - - int wide, tall; - GetSize( wide, tall ); - m_weapon.SetBounds( 0, 0, wide, tall ); -} - -//-------------------------------------------------------------------------------------------------------------- -void WeaponLabel::Paint() -{ - BaseClass::Paint(); - - m_weapon.Paint(); - m_weapon.PaintText(); -} - -//-------------------------------------------------------------------------------------------------------------- -//-------------------------------------------------------------------------------------------------------------- -ItemImageInfo::ItemImageInfo() -{ - m_needLayout = false; - m_left = m_top = m_wide = m_tall = 0; - m_count = 0; - memset( &m_image, 0, sizeof(ImageInfo) ); - m_pText = new TextImage( "" ); - - SetBounds( 0, 0, 100, 100 ); -} - -//-------------------------------------------------------------------------------------------------------------- -ItemImageInfo::~ItemImageInfo() -{ - delete m_pText; -} - -//-------------------------------------------------------------------------------------------------------------- -void ItemImageInfo::ApplyTextSettings( vgui::IScheme *pScheme, bool isProportional ) -{ - Color color = pScheme->GetColor( "Label.TextColor", Color( 0, 0, 0, 0 ) ); - - m_pText->SetColor( color ); - m_pText->SetFont( pScheme->GetFont( "Default", isProportional ) ); - m_pText->SetWrap( false ); -} - -//-------------------------------------------------------------------------------------------------------------- -void ItemImageInfo::SetBounds( int left, int top, int wide, int tall ) -{ - m_left = left; - m_top = top; - m_wide = wide; - m_tall = tall; - m_needLayout = true; -} - -//-------------------------------------------------------------------------------------------------------------- -void ItemImageInfo::SetItem( const char *imageFname, int count ) -{ - m_pText->SetText( L"" ); - m_count = count; - - if ( imageFname ) - m_image.image = scheme()->GetImage( imageFname, true ); - else - m_image.image = NULL; - - if ( count > 1 ) - { - wchar_t *multiplierString = g_pVGuiLocalize->Find("#Cstrike_BuyMenuPresetMultiplier"); - if ( !multiplierString ) - multiplierString = L""; - const int BufLen = 32; - wchar_t buf[BufLen]; - - g_pVGuiLocalize->ConstructString( buf, sizeof(buf), multiplierString, 1, NumAsWString( count ) ); - m_pText->SetText( buf ); - } - m_needLayout = true; -} - -//-------------------------------------------------------------------------------------------------------------- -void ItemImageInfo::Paint() -{ - if ( m_needLayout ) - PerformLayout(); - - if ( m_count ) - m_image.Paint(); -} - -//-------------------------------------------------------------------------------------------------------------- -void ItemImageInfo::PaintText() -{ - if ( m_needLayout ) - PerformLayout(); - - m_pText->Paint(); -} - -//-------------------------------------------------------------------------------------------------------------- -void ItemImageInfo::PerformLayout() -{ - m_needLayout = false; - - m_image.FitInBounds( m_left, m_top, m_wide, m_tall, false, 0 ); - - int w, h; - m_pText->ResizeImageToContent(); - m_pText->GetSize( w, h ); - m_pText->SetPos( m_left + m_image.w - w, m_top + m_tall - h ); -} - -//-------------------------------------------------------------------------------------------------------------- -//-------------------------------------------------------------------------------------------------------------- -EquipmentLabel::EquipmentLabel(Panel *parent, const char *panelName, const char *imageFname) : BaseClass( parent, panelName ) -{ - SetSize( 10, 10 ); - m_item.SetItem( imageFname, 0 ); - SetMouseInputEnabled( false ); -} - -//-------------------------------------------------------------------------------------------------------------- -EquipmentLabel::~EquipmentLabel() -{ -} - -//-------------------------------------------------------------------------------------------------------------- -void EquipmentLabel::SetItem( const char *imageFname, int count ) -{ - m_item.SetItem( imageFname, count ); -} - -//-------------------------------------------------------------------------------------------------------------- -void EquipmentLabel::ApplySchemeSettings(IScheme *pScheme) -{ - BaseClass::ApplySchemeSettings( pScheme ); - - m_item.ApplyTextSettings( pScheme, IsProportional() ); -} - -//-------------------------------------------------------------------------------------------------------------- -void EquipmentLabel::PerformLayout() -{ - BaseClass::PerformLayout(); - - int wide, tall; - GetSize( wide, tall ); - m_item.SetBounds( 0, 0, wide, tall ); -} - -//-------------------------------------------------------------------------------------------------------------- -void EquipmentLabel::Paint() -{ - BaseClass::Paint(); - - m_item.Paint(); - m_item.PaintText(); -} - - -//-------------------------------------------------------------------------------------------------------------- -//-------------------------------------------------------------------------------------------------------------- -/// Helper function: draws a simple dashed line -void DrawDashedLine(int x0, int y0, int x1, int y1, int dashLen, int gapLen) -{ - // work out which way the line goes - if ((x1 - x0) > (y1 - y0)) - { - // x direction line - while (1) - { - if (x0 + dashLen > x1) - { - // draw partial - surface()->DrawFilledRect(x0, y0, x1, y1+1); - } - else - { - surface()->DrawFilledRect(x0, y0, x0 + dashLen, y1+1); - } - - x0 += dashLen; - - if (x0 + gapLen > x1) - break; - - x0 += gapLen; - } - } - else - { - // y direction - while (1) - { - if (y0 + dashLen > y1) - { - // draw partial - surface()->DrawFilledRect(x0, y0, x1+1, y1); - } - else - { - surface()->DrawFilledRect(x0, y0, x1+1, y0 + dashLen); - } - - y0 += dashLen; - - if (y0 + gapLen > y1) - break; - - y0 += gapLen; - } - } -} - -//-------------------------------------------------------------------------------------------------------------- -//-------------------------------------------------------------------------------------------------------------- -void ImageInfo::Paint() -{ - if ( !image ) - return; - - image->SetSize( w, h ); - image->SetPos( x, y ); - image->Paint(); - image->SetSize( 0, 0 ); // restore image size to content size to not mess up other places that use the same image -} - -//-------------------------------------------------------------------------------------------------------------- -void ImageInfo::FitInBounds( int baseX, int baseY, int width, int height, bool center, int scaleAt1024, bool halfHeight ) -{ - if ( !image ) - { - x = y = w = h = 0; - return; - } - - image->GetContentSize(fullW, fullH); - - if ( scaleAt1024 ) - { - int screenW, screenH; - GetHudSize( screenW, screenH ); - - w = fullW * screenW / 1024 * scaleAt1024 / 100; - h = fullH * screenW / 1024 * scaleAt1024 / 100; - - if ( fullH > 64 && scaleAt1024 == 100 ) - { - w = w * 64 / fullH; - h = h * 64 / fullH; - } - - if ( h > height * 1.2 ) - scaleAt1024 = 0; - } - if ( !scaleAt1024 ) - { - w = fullW; - h = fullH; - - if ( h != height ) - { - w = (int) w * 1.0f * height / h; - h = height; - } - - if ( w > width ) - { - h = (int) h * 1.0f * width / w; - w = width; - } - } - - if ( center ) - { - x = baseX + (width - w)/2; - } - else - { - x = baseX; - } - y = baseY + (height - h)/2; -} - -//-------------------------------------------------------------------------------------------------------------- diff --git a/game/client/cstrike/VGUI/buypreset_listbox.cpp b/game/client/cstrike/VGUI/buypreset_listbox.cpp deleted file mode 100644 index 70dc046a9..000000000 --- a/game/client/cstrike/VGUI/buypreset_listbox.cpp +++ /dev/null @@ -1,406 +0,0 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -//============================================================================= - -#include "cbase.h" - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include "buypreset_listbox.h" - -// memdbgon must be the last include file in a .cpp file!!! -#include - -using namespace vgui; - -#ifndef max -#define max(a,b) (((a) > (b)) ? (a) : (b)) -#endif - - -//-------------------------------------------------------------------------------------------------------------- -//-------------------------------------------------------------------------------------------------------------- -BuyPresetListBox::BuyPresetListBox( vgui::Panel *parent, char const *panelName ) : Panel( parent, panelName ) -{ - m_visibleIndex = 0; - m_lastSize = 0; - - SetBounds( 0, 0, 100, 100 ); - - m_vbar = new ScrollBar(this, "PanelListPanelVScroll", true); - m_vbar->SetBounds( 0, 0, 20, 20 ); - m_vbar->SetVisible(true); - m_vbar->AddActionSignalTarget( this ); - - m_pPanelEmbedded = new EditablePanel(this, "PanelListEmbedded"); - m_pPanelEmbedded->SetBounds(0, 0, 20, 20); - m_pPanelEmbedded->SetPaintBackgroundEnabled( false ); - m_pPanelEmbedded->SetPaintBorderEnabled(false); - - if( IsProportional() ) - { - int width, height; - int sw,sh; - surface()->GetProportionalBase( width, height ); - GetHudSize(sw, sh); - - // resize scrollbar, etc - m_iScrollbarSize = static_cast( static_cast( SCROLLBAR_SIZE )*( static_cast( sw )/ static_cast( width ))); - m_iDefaultHeight = static_cast( static_cast( DEFAULT_HEIGHT )*( static_cast( sw )/ static_cast( width ))); - m_iPanelBuffer = static_cast( static_cast( PANELBUFFER )*( static_cast( sw )/ static_cast( width ))); - } - else - { - m_iScrollbarSize = SCROLLBAR_SIZE; - m_iDefaultHeight = DEFAULT_HEIGHT; - m_iPanelBuffer = PANELBUFFER; - } -} - -//-------------------------------------------------------------------------------------------------------------- -BuyPresetListBox::~BuyPresetListBox() -{ - // free data from table - DeleteAllItems(); -} - -//-------------------------------------------------------------------------------------------------------------- -/** - * Passes commands up to the parent - */ -void BuyPresetListBox::OnCommand( const char *command ) -{ - GetParent()->OnCommand( command ); -} - -//-------------------------------------------------------------------------------------------------------------- -/** - * Scrolls the list according to the mouse wheel movement - */ -void BuyPresetListBox::OnMouseWheeled(int delta) -{ - int scale = 3; - if ( m_items.Count() ) - { - Panel *panel = m_items[0].panel; - if ( panel ) - { - scale = panel->GetTall() + m_iPanelBuffer; - } - } - int val = m_vbar->GetValue(); - val -= (delta * scale); - m_vbar->SetValue(val); -} - -//-------------------------------------------------------------------------------------------------------------- -/** - * Computes vertical pixels needed by listbox contents - */ -int BuyPresetListBox::computeVPixelsNeeded( void ) -{ - int pixels = 0; - - int i; - for ( i = 0; i < m_items.Count(); i++ ) - { - Panel *panel = m_items[i].panel; - if ( !panel ) - continue; - - int w, h; - panel->GetSize( w, h ); - - pixels += m_iPanelBuffer; // add in buffer. between items. - pixels += h; - } - - pixels += m_iPanelBuffer; // add in buffer below last item - - return pixels; -} - -//-------------------------------------------------------------------------------------------------------------- -/** - * Adds an item to the end of the listbox. UserData is assumed to be a pointer that can be freed by the listbox if non-NULL. - */ -int BuyPresetListBox::AddItem( vgui::Panel *panel, IBuyPresetListBoxUserData * userData ) -{ - assert(panel); - - DataItem item = { panel, userData }; - - panel->SetParent( m_pPanelEmbedded ); - - m_items.AddToTail( item ); - - InvalidateLayout(); - return m_items.Count(); -} - -//-------------------------------------------------------------------------------------------------------------- -/** - * Exchanges two items in the listbox - */ -void BuyPresetListBox::SwapItems( int index1, int index2 ) -{ - if ( index1 < 0 || index2 < 0 || index1 >= m_items.Count() || index2 >= m_items.Count() ) - { - return; - } - - DataItem temp = m_items[index1]; - m_items[index1] = m_items[index2]; - m_items[index2] = temp; - - InvalidateLayout(); -} - -//-------------------------------------------------------------------------------------------------------------- -/** - * Returns the number of items in the listbox - */ -int BuyPresetListBox::GetItemCount( void ) const -{ - return m_items.Count(); -} - -//-------------------------------------------------------------------------------------------------------------- -/** - * Returns the panel in the given index, or NULL - */ -Panel * BuyPresetListBox::GetItemPanel(int index) const -{ - if ( index < 0 || index >= m_items.Count() ) - return NULL; - - return m_items[index].panel; -} - -//-------------------------------------------------------------------------------------------------------------- -/** - * Returns the userData in the given index, or NULL - */ -auto BuyPresetListBox::GetItemUserData(int index) -> IBuyPresetListBoxUserData * -{ - if ( index < 0 || index >= m_items.Count() ) - { - return NULL; - } - - return m_items[index].userData; -} - -//-------------------------------------------------------------------------------------------------------------- -/** - * Sets the userData in the given index - */ -void BuyPresetListBox::SetItemUserData( int index, IBuyPresetListBoxUserData * userData ) -{ - if ( index < 0 || index >= m_items.Count() ) - return; - - m_items[index].userData = userData; -} - -//-------------------------------------------------------------------------------------------------------------- -/** - * Removes an item from the table (changing the indices of all following items), deleting the panel and userData - */ -void BuyPresetListBox::RemoveItem(int index) -{ - if ( index < 0 || index >= m_items.Count() ) - return; - - DataItem item = m_items[index]; - if ( item.panel ) - { - item.panel->MarkForDeletion(); - } - if ( item.userData ) - { - delete item.userData; - } - - m_items.Remove( index ); - - InvalidateLayout(); -} - -//-------------------------------------------------------------------------------------------------------------- -/** - * clears the listbox, deleting all panels and userData - */ -void BuyPresetListBox::DeleteAllItems() -{ - while ( m_items.Count() ) - { - RemoveItem( 0 ); - } - - // move the scrollbar to the top of the list - m_vbar->SetValue(0); - InvalidateLayout(); -} - -//-------------------------------------------------------------------------------------------------------------- -/** - * Handles Count changes - */ -void BuyPresetListBox::OnSizeChanged(int wide, int tall) -{ - BaseClass::OnSizeChanged(wide, tall); - InvalidateLayout(); -} - -//-------------------------------------------------------------------------------------------------------------- -/** - * Positions listbox items, etc after internal changes - */ -void BuyPresetListBox::PerformLayout() -{ - int wide, tall; - GetSize( wide, tall ); - - int vpixels = computeVPixelsNeeded(); - - int visibleIndex = m_visibleIndex; - - //!! need to make it recalculate scroll positions - m_vbar->SetVisible(true); - m_vbar->SetEnabled(false); - m_vbar->SetRange( 0, (MAX( 0, vpixels - tall + m_iDefaultHeight )) ); - m_vbar->SetRangeWindow( m_iDefaultHeight ); - m_vbar->SetButtonPressedScrollValue( m_iDefaultHeight ); // standard height of labels/buttons etc. - m_vbar->SetPos(wide - m_iScrollbarSize, 1); - m_vbar->SetSize(m_iScrollbarSize, tall - 2); - - m_visibleIndex = visibleIndex; - - int top = MAX( 0, m_vbar->GetValue() ); - - m_pPanelEmbedded->SetPos( 1, -top ); - m_pPanelEmbedded->SetSize( wide-m_iScrollbarSize -2, vpixels ); - - // Now lay out the controls on the embedded panel - int y = 0; - int h = 0; - int totalh = 0; - - int i; - for ( i = 0; i < m_items.Count(); i++, y += h ) - { - // add in a little buffer between panels - y += m_iPanelBuffer; - DataItem item = m_items[i]; - - h = item.panel->GetTall(); - - totalh += h; - item.panel->SetBounds( 8, y, wide - m_iScrollbarSize - 8 - 8, h ); - item.panel->InvalidateLayout(); - } - - if ( m_visibleIndex >= 0 && m_visibleIndex < m_items.Count() ) - { - - int vpos = 0; - - int tempWide, tempTall; - GetSize( tempWide, tempTall ); - - int vtop, vbottom; - m_vbar->GetRange( vtop, vbottom ); - - int tempTop = MAX( 0, m_vbar->GetValue() ); // top pixel in the embedded panel - int bottom = tempTop + tempTall - 2; - - int itemTop, itemLeft, itemBottom, itemRight; - m_items[m_visibleIndex].panel->GetBounds( itemLeft, itemTop, itemRight, itemBottom ); - itemBottom += itemTop; - itemRight += itemLeft; - - if ( itemTop < tempTop ) - { - // item's top is too high - vpos -= ( tempTop - itemTop ); - - m_vbar->SetValue(vpos); - OnSliderMoved(vpos); - } - else if ( itemBottom > bottom ) - { - // item's bottom is too low - vpos += ( itemBottom - bottom ); - - m_vbar->SetValue(vpos); - OnSliderMoved(vpos); - } - } - - if ( m_lastSize == vpixels ) - { - m_visibleIndex = -1; - } - m_lastSize = vpixels; -} - -//-------------------------------------------------------------------------------------------------------------- -/** - * Try to ensure that the given index is visible - */ -void BuyPresetListBox::MakeItemVisible( int index ) -{ - m_visibleIndex = index; - m_lastSize = 0; -} - -//-------------------------------------------------------------------------------------------------------------- -/** - * Loads colors, fonts, etc - */ -void BuyPresetListBox::ApplySchemeSettings(IScheme *pScheme) -{ - BaseClass::ApplySchemeSettings(pScheme); - - SetBgColor(GetSchemeColor("BuyPresetListBox.BgColor", GetBgColor(), pScheme)); - - SetBorder(pScheme->GetBorder("BrowserBorder")); - m_vbar->SetBorder(pScheme->GetBorder("BrowserBorder")); - - PerformLayout(); -} - - -//-------------------------------------------------------------------------------------------------------------- -/** - * Handles slider being dragged - */ -void BuyPresetListBox::OnSliderMoved( int position ) -{ - InvalidateLayout(); - Repaint(); -} - - -//-------------------------------------------------------------------------------------------------------------- -/** - * Moves slider to the top - */ -void BuyPresetListBox::MoveScrollBarToTop() -{ - m_vbar->SetValue(0); - OnSliderMoved(0); -} - diff --git a/game/client/cstrike/VGUI/buypreset_listbox.h b/game/client/cstrike/VGUI/buypreset_listbox.h deleted file mode 100644 index a09abf0eb..000000000 --- a/game/client/cstrike/VGUI/buypreset_listbox.h +++ /dev/null @@ -1,85 +0,0 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -//============================================================================= - -#ifndef BUYPRESET_LISTBOX_H -#define BUYPRESET_LISTBOX_H -#ifdef _WIN32 -#pragma once -#endif - -#include -#include - -#include - -//-------------------------------------------------------------------------------------------------------------- -/** - * ListBox-style control with behavior needed by weapon lists for BuyPreset editing - */ -class BuyPresetListBox : public vgui::Panel -{ - DECLARE_CLASS_SIMPLE( BuyPresetListBox, vgui::Panel ); - -public: - BuyPresetListBox( vgui::Panel *parent, char const *panelName ); - ~BuyPresetListBox(); - - class IBuyPresetListBoxUserData - { - protected: - friend BuyPresetListBox; - virtual ~IBuyPresetListBoxUserData() {}; - }; - - virtual int AddItem( vgui::Panel *panel, IBuyPresetListBoxUserData *userData ); ///< Adds an item to the end of the listbox. UserData is assumed to be a pointer that will be deleted by the listbox if non-NULL. - virtual int GetItemCount( void ) const; ///< Returns the number of items in the listbox - void SwapItems( int index1, int index2 ); ///< Exchanges two items in the listbox - void MakeItemVisible( int index ); ///< Try to ensure that the given index is visible - - vgui::Panel * GetItemPanel( int index ) const; ///< Returns the panel in the given index, or NULL - IBuyPresetListBoxUserData * GetItemUserData( int index ); ///< Returns the userData in the given index, or NULL - void SetItemUserData( int index, IBuyPresetListBoxUserData * userData ); ///< Sets the userData in the given index - - virtual void RemoveItem( int index ); ///< Removes an item from the table (changing the indices of all following items), deleting the panel and userData - virtual void DeleteAllItems(); ///< clears the listbox, deleting all panels and userData - - // overrides - virtual void OnSizeChanged(int wide, int tall); ////< Handles size changes - MESSAGE_FUNC_INT( OnSliderMoved, "ScrollBarSliderMoved", position ); ///< Handles slider being dragged - virtual void OnMouseWheeled(int delta); ///< Scrolls the list according to the mouse wheel movement - virtual void MoveScrollBarToTop(); ///< Moves slider to the top - -protected: - - virtual int computeVPixelsNeeded( void ); ///< Computes vertical pixels needed by listbox contents - - virtual void PerformLayout(); ///< Positions listbox items, etc after internal changes - virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); ///< Loads colors, fonts, etc - - virtual void OnCommand( const char *command ); ///< Passes commands up to the parent - -private: - enum { SCROLLBAR_SIZE = 18, DEFAULT_HEIGHT = 24, PANELBUFFER = 5 }; - - typedef struct dataitem_s - { - vgui::Panel *panel; - IBuyPresetListBoxUserData * userData; - } DataItem; - CUtlVector< DataItem > m_items; - - vgui::ScrollBar *m_vbar; - vgui::Panel *m_pPanelEmbedded; - - int m_iScrollbarSize; - int m_iDefaultHeight; - int m_iPanelBuffer; - - int m_visibleIndex; - int m_lastSize; -}; - -#endif // BUYPRESET_LISTBOX_H diff --git a/game/client/cstrike/VGUI/buypreset_panel.cpp b/game/client/cstrike/VGUI/buypreset_panel.cpp deleted file mode 100644 index b6937036c..000000000 --- a/game/client/cstrike/VGUI/buypreset_panel.cpp +++ /dev/null @@ -1,447 +0,0 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -//============================================================================= - -#include "cbase.h" - -#include "weapon_csbase.h" -#include "cs_ammodef.h" - -#include -#include -#include -#include -#include -#include "vgui_controls/BuildGroup.h" -#include "vgui_controls/BitmapImagePanel.h" -#include "vgui_controls/TextEntry.h" -#include "vgui_controls/TextImage.h" -#include "vgui_controls/RichText.h" -#include "vgui_controls/QueryBox.h" -#include "career_box.h" -#include "buypreset_listbox.h" -#include "buypreset_weaponsetlabel.h" -#include "backgroundpanel.h" - -#include "cstrike/bot/shared_util.h" - -using namespace vgui; - -const float horizTitleRatio = 18.0f/68.0f; - -//-------------------------------------------------------------------------------------------------------------- -//-------------------------------------------------------------------------------------------------------------- -/* -class PresetNameTextEntry : public TextEntry -{ -public: - PresetNameTextEntry(Panel *parent, CBuyPresetEditMainMenu *menu, const char *name ) : TextEntry( parent, name ) - { - m_pMenu = menu; - } - - virtual void FireActionSignal() - { - TextEntry::FireActionSignal(); - if ( m_pMenu ) - { - m_pMenu->SetDirty(); - } - } - -private: - CBuyPresetEditMainMenu *m_pMenu; -}; -*/ - -//-------------------------------------------------------------------------------------------------------------- -//-------------------------------------------------------------------------------------------------------------- -int GetScaledValue( HScheme hScheme, int unscaled ) -{ - int val = scheme()->GetProportionalScaledValueEx( hScheme, unscaled ); - return GetAlternateProportionalValueFromScaled( hScheme, val ); -} - -//-------------------------------------------------------------------------------------------------------------- -//-------------------------------------------------------------------------------------------------------------- -class PresetBackgroundPanel : public vgui::Panel -{ - typedef vgui::Panel BaseClass; - -public: - PresetBackgroundPanel( vgui::Panel *parent, const char *panelName ) : BaseClass( parent, panelName ) - { - }; - - virtual void ApplySchemeSettings( vgui::IScheme *pScheme ) - { - BaseClass::ApplySchemeSettings( pScheme ); - SetBorder( pScheme->GetBorder("ButtonBorder") ); - m_lineColor = pScheme->GetColor( "Border.Bright", Color( 0, 0, 0, 0 ) ); - } - - virtual void ApplySettings( KeyValues *inResourceData ) - { - BaseClass::ApplySettings( inResourceData ); - - m_lines.RemoveAll(); - KeyValues *lines = inResourceData->FindKey( "lines", false ); - if ( lines ) - { - KeyValues *line = lines->GetFirstValue(); - while ( line ) - { - const char *str = line->GetString( nullptr, "" ); - Vector4D p; - int numPoints = sscanf( str, "%f %f %f %f", &p[0], &p[1], &p[2], &p[3] ); - if ( numPoints == 4 ) - { - m_lines.AddToTail( p ); - } - line = line->GetNextValue(); - } - } - } - - virtual void PaintBackground( void ) - { - BaseClass::PaintBackground(); - - vgui::surface()->DrawSetColor( m_lineColor ); - vgui::surface()->DrawSetTextColor( m_lineColor ); - for ( int i=0; iDrawFilledRect( x1, y1, x2, y2 ); - } - } - - virtual void PerformLayout( void ) - { - m_scaledLines.RemoveAll(); - for ( int i=0; i m_lines; - CUtlVector< Vector4D > m_scaledLines; -}; - -//-------------------------------------------------------------------------------------------------------------- -//-------------------------------------------------------------------------------------------------------------- -BuyPresetEditPanel::BuyPresetEditPanel( Panel *parent, const char *panelName, const char *resourceFilename, int fallbackIndex, bool editableName ) : BaseClass( parent, panelName ) -{ - SetProportional( parent->IsProportional() ); - if ( IsProportional() ) - { - m_baseWide = m_baseTall = scheme()->GetProportionalScaledValueEx( GetScheme(), 100 ); - } - else - { - m_baseWide = m_baseTall = 100; - } - SetSize( m_baseWide, m_baseTall ); - - m_fallbackIndex = fallbackIndex; - - m_pBgPanel = new PresetBackgroundPanel( this, "mainBackground" ); - - m_pTitleEntry = NULL; - m_pTitleLabel = NULL; - m_pCostLabel = NULL; - /* - m_pTitleEntry = new PresetNameTextEntry( this, dynamic_cast(parent), "titleEntry" ); - m_pTitleLabel = new Label( this, "title", "" ); - m_pCostLabel = new Label( this, "cost", "" ); - */ - - m_pPrimaryWeapon = new WeaponLabel( this, "primary" ); - m_pSecondaryWeapon = new WeaponLabel( this, "secondary" ); - - m_pHEGrenade = new EquipmentLabel( this, "hegrenade" ); - m_pSmokeGrenade = new EquipmentLabel( this, "smokegrenade" ); - m_pFlashbangs = new EquipmentLabel( this, "flashbang" ); - - m_pDefuser = new EquipmentLabel( this, "defuser" ); - m_pNightvision = new EquipmentLabel( this, "nightvision" ); - - m_pArmor = new EquipmentLabel( this, "armor" ); - - if ( resourceFilename ) - { - LoadControlSettings( resourceFilename ); - } - - int x, y, w, h; - m_pBgPanel->GetBounds( x, y, w, h ); - - m_baseWide = x + w; - m_baseTall = y + h; - SetSize( m_baseWide, m_baseTall ); -} - -//-------------------------------------------------------------------------------------------------------------- -BuyPresetEditPanel::~BuyPresetEditPanel() -{ -} - -//-------------------------------------------------------------------------------------------------------------- -void BuyPresetEditPanel::SetWeaponSet( const WeaponSet *pWeaponSet, bool current ) -{ - // set to empty state - Reset(); - - // now fill in items - if ( pWeaponSet ) - { - if ( m_pTitleLabel ) - { - m_pTitleLabel->SetText( SharedVarArgs( "#Cstrike_BuyPresetChoice%d", m_fallbackIndex ) ); - } - if ( m_pTitleEntry ) - { - m_pTitleEntry->SetText( SharedVarArgs( "#Cstrike_BuyPresetChoice%d", m_fallbackIndex ) ); - } - - if ( m_pCostLabel ) - { - const int BufLen = 256; - wchar_t wbuf[BufLen]; - g_pVGuiLocalize->ConstructString( wbuf, sizeof( wbuf ), - g_pVGuiLocalize->Find( "#Cstrike_BuyPresetPlainCost" ), - 1, NumAsWString( pWeaponSet->FullCost() ) ); - m_pCostLabel->SetText( wbuf ); - } - - m_pPrimaryWeapon->SetWeapon( &pWeaponSet->m_primaryWeapon, true, true ); - m_pSecondaryWeapon->SetWeapon( &pWeaponSet->m_secondaryWeapon, false, true ); - - if ( pWeaponSet->m_HEGrenade ) - m_pHEGrenade->SetItem( "gfx/vgui/hegrenade_square", 1 ); - if ( pWeaponSet->m_smokeGrenade ) - m_pSmokeGrenade->SetItem( "gfx/vgui/smokegrenade_square", 1 ); - if ( pWeaponSet->m_flashbangs ) - m_pFlashbangs->SetItem( "gfx/vgui/flashbang_square", pWeaponSet->m_flashbangs ); - - if ( pWeaponSet->m_defuser ) - m_pDefuser->SetItem( "gfx/vgui/defuser", 1 ); - if ( pWeaponSet->m_nightvision ) - m_pNightvision->SetItem( "gfx/vgui/nightvision", 1 ); - - if ( pWeaponSet->m_armor ) - { - if ( pWeaponSet->m_helmet ) - m_pArmor->SetItem( "gfx/vgui/kevlar_helmet", 1 ); - else - m_pArmor->SetItem( "gfx/vgui/kevlar", 1 ); - } - } -} - -//-------------------------------------------------------------------------------------------------------------- -void BuyPresetEditPanel::SetText( const wchar_t *text ) -{ - if ( !text ) - text = L""; - if ( m_pTitleLabel ) - { - m_pTitleLabel->SetText( text ); - } - if ( m_pTitleEntry ) - { - m_pTitleEntry->SetText( text ); - } - InvalidateLayout(); -} - -//-------------------------------------------------------------------------------------------------------------- -/** - * Handle command callbacks - */ -void BuyPresetEditPanel::OnCommand( const char *command ) -{ - if (stricmp(command, "close")) - { - PostActionSignal( new KeyValues("Command", "command", SharedVarArgs( "%s %d", command, m_fallbackIndex )) ); - } - - BaseClass::OnCommand(command); -} - -//-------------------------------------------------------------------------------------------------------------- -void BuyPresetEditPanel::ApplySchemeSettings(IScheme *pScheme) -{ - BaseClass::ApplySchemeSettings(pScheme); - SetBgColor( Color( 0, 0, 0, 0 ) ); - - IBorder *pBorder = NULL; - - int i; - - for (i = 0; i < GetChildCount(); i++) - { - // perform auto-layout on the child panel - Panel *child = GetChild(i); - if (!child) - continue; - - if ( !stricmp( "button", child->GetClassName() ) ) - { - Button *pButton = dynamic_cast