//===== Copyright © 2005-2005, Valve Corporation, All rights reserved. ======// // // Purpose: A higher level link library for general use in the game and tools. // //===========================================================================// #include "tier0/platform.h" #include "tier0/dbg.h" #include "interfaces/interfaces.h" //----------------------------------------------------------------------------- // Tier 1 libraries //----------------------------------------------------------------------------- ICvar *cvar = 0; ICvar *g_pCVar = 0; IProcessUtils *g_pProcessUtils = 0; static bool s_bConnected = false; IPhysics2 *g_pPhysics2 = 0; IPhysics2ActorManager *g_pPhysics2ActorManager = 0; IPhysics2ResourceManager *g_pPhysics2ResourceManager = 0; IEventSystem *g_pEventSystem = 0; ILocalize *g_pLocalize = 0; // for utlsortvector.h #ifndef _WIN32 void *g_pUtlSortVectorQSortContext = NULL; #endif //----------------------------------------------------------------------------- // Tier 2 libraries //----------------------------------------------------------------------------- IResourceSystem *g_pResourceSystem = 0; IRenderDeviceMgr *g_pRenderDeviceMgr = 0; IFileSystem *g_pFullFileSystem = 0; IAsyncFileSystem *g_pAsyncFileSystem = 0; IMaterialSystem *materials = 0; IMaterialSystem *g_pMaterialSystem = 0; IMaterialSystem2 *g_pMaterialSystem2 = 0; IInputSystem *g_pInputSystem = 0; IInputStackSystem *g_pInputStackSystem = 0; INetworkSystem *g_pNetworkSystem = 0; ISoundSystem *g_pSoundSystem = 0; IMaterialSystemHardwareConfig *g_pMaterialSystemHardwareConfig = 0; IDebugTextureInfo *g_pMaterialSystemDebugTextureInfo = 0; IVBAllocTracker *g_VBAllocTracker = 0; IColorCorrectionSystem *colorcorrection = 0; IP4 *p4 = 0; IMdlLib *mdllib = 0; IQueuedLoader *g_pQueuedLoader = 0; IResourceAccessControl *g_pResourceAccessControl = 0; IPrecacheSystem *g_pPrecacheSystem = 0; ISceneSystem *g_pSceneSystem = 0; #if defined( PLATFORM_X360 ) IXboxInstaller *g_pXboxInstaller = 0; #endif IMatchFramework *g_pMatchFramework = 0; IGameUISystemMgr *g_pGameUISystemMgr = 0; #if defined( INCLUDE_SCALEFORM ) IScaleformUI *g_pScaleformUI = 0; #endif //----------------------------------------------------------------------------- // Not exactly a global, but we're going to keep track of these here anyways //----------------------------------------------------------------------------- IRenderDevice *g_pRenderDevice = 0; IRenderHardwareConfig *g_pRenderHardwareConfig = 0; //----------------------------------------------------------------------------- // Tier3 libraries //----------------------------------------------------------------------------- IMeshSystem *g_pMeshSystem = 0; IStudioRender *g_pStudioRender = 0; IStudioRender *studiorender = 0; IMatSystemSurface *g_pMatSystemSurface = 0; vgui::IInput *g_pVGuiInput = 0; vgui::ISurface *g_pVGuiSurface = 0; vgui::IPanel *g_pVGuiPanel = 0; vgui::IVGui *g_pVGui = 0; vgui::ILocalize *g_pVGuiLocalize = 0; vgui::ISchemeManager *g_pVGuiSchemeManager = 0; vgui::ISystem *g_pVGuiSystem = 0; IDataCache *g_pDataCache = 0; IMDLCache *g_pMDLCache = 0; IMDLCache *mdlcache = 0; IAvi *g_pAVI = 0; IBik *g_pBIK = 0; IDmeMakefileUtils *g_pDmeMakefileUtils = 0; IPhysicsCollision *g_pPhysicsCollision = 0; ISoundEmitterSystemBase *g_pSoundEmitterSystem = 0; IWorldRendererMgr *g_pWorldRendererMgr = 0; IVGuiRenderSurface *g_pVGuiRenderSurface = 0; //----------------------------------------------------------------------------- // Mapping of interface string to globals //----------------------------------------------------------------------------- struct InterfaceGlobals_t { const char *m_pInterfaceName; void *m_ppGlobal; }; static InterfaceGlobals_t g_pInterfaceGlobals[] = { { CVAR_INTERFACE_VERSION, &cvar }, { CVAR_INTERFACE_VERSION, &g_pCVar }, { EVENTSYSTEM_INTERFACE_VERSION, &g_pEventSystem }, { PROCESS_UTILS_INTERFACE_VERSION, &g_pProcessUtils }, { VPHYSICS2_INTERFACE_VERSION, &g_pPhysics2 }, { VPHYSICS2_ACTOR_MGR_INTERFACE_VERSION, &g_pPhysics2ActorManager }, { VPHYSICS2_RESOURCE_MGR_INTERFACE_VERSION, &g_pPhysics2ResourceManager }, { FILESYSTEM_INTERFACE_VERSION, &g_pFullFileSystem }, { ASYNCFILESYSTEM_INTERFACE_VERSION, &g_pAsyncFileSystem }, { RESOURCESYSTEM_INTERFACE_VERSION, &g_pResourceSystem }, { MATERIAL_SYSTEM_INTERFACE_VERSION, &g_pMaterialSystem }, { MATERIAL_SYSTEM_INTERFACE_VERSION, &materials }, { MATERIAL_SYSTEM2_INTERFACE_VERSION, &g_pMaterialSystem2 }, { INPUTSYSTEM_INTERFACE_VERSION, &g_pInputSystem }, { INPUTSTACKSYSTEM_INTERFACE_VERSION, &g_pInputStackSystem }, { NETWORKSYSTEM_INTERFACE_VERSION, &g_pNetworkSystem }, { RENDER_DEVICE_MGR_INTERFACE_VERSION, &g_pRenderDeviceMgr }, { MATERIALSYSTEM_HARDWARECONFIG_INTERFACE_VERSION, &g_pMaterialSystemHardwareConfig }, { SOUNDSYSTEM_INTERFACE_VERSION, &g_pSoundSystem }, { DEBUG_TEXTURE_INFO_VERSION, &g_pMaterialSystemDebugTextureInfo }, { VB_ALLOC_TRACKER_INTERFACE_VERSION, &g_VBAllocTracker }, { COLORCORRECTION_INTERFACE_VERSION, &colorcorrection }, { P4_INTERFACE_VERSION, &p4 }, { MDLLIB_INTERFACE_VERSION, &mdllib }, { QUEUEDLOADER_INTERFACE_VERSION, &g_pQueuedLoader }, { RESOURCE_ACCESS_CONTROL_INTERFACE_VERSION, &g_pResourceAccessControl }, { PRECACHE_SYSTEM_INTERFACE_VERSION, &g_pPrecacheSystem }, { STUDIO_RENDER_INTERFACE_VERSION, &g_pStudioRender }, { STUDIO_RENDER_INTERFACE_VERSION, &studiorender }, { VGUI_IVGUI_INTERFACE_VERSION, &g_pVGui }, { VGUI_INPUT_INTERFACE_VERSION, &g_pVGuiInput }, { VGUI_PANEL_INTERFACE_VERSION, &g_pVGuiPanel }, { VGUI_SURFACE_INTERFACE_VERSION, &g_pVGuiSurface }, { VGUI_SCHEME_INTERFACE_VERSION, &g_pVGuiSchemeManager }, { VGUI_SYSTEM_INTERFACE_VERSION, &g_pVGuiSystem }, { LOCALIZE_INTERFACE_VERSION, &g_pLocalize }, { LOCALIZE_INTERFACE_VERSION, &g_pVGuiLocalize }, { MAT_SYSTEM_SURFACE_INTERFACE_VERSION, &g_pMatSystemSurface }, { DATACACHE_INTERFACE_VERSION, &g_pDataCache }, { MDLCACHE_INTERFACE_VERSION, &g_pMDLCache }, { MDLCACHE_INTERFACE_VERSION, &mdlcache }, { AVI_INTERFACE_VERSION, &g_pAVI }, { BIK_INTERFACE_VERSION, &g_pBIK }, { DMEMAKEFILE_UTILS_INTERFACE_VERSION, &g_pDmeMakefileUtils }, { VPHYSICS_COLLISION_INTERFACE_VERSION, &g_pPhysicsCollision }, { SOUNDEMITTERSYSTEM_INTERFACE_VERSION, &g_pSoundEmitterSystem }, { MESHSYSTEM_INTERFACE_VERSION, &g_pMeshSystem }, { RENDER_DEVICE_INTERFACE_VERSION, &g_pRenderDevice }, { RENDER_HARDWARECONFIG_INTERFACE_VERSION, &g_pRenderHardwareConfig }, { SCENESYSTEM_INTERFACE_VERSION, &g_pSceneSystem }, { WORLD_RENDERER_MGR_INTERFACE_VERSION, &g_pWorldRendererMgr }, { RENDER_SYSTEM_SURFACE_INTERFACE_VERSION, &g_pVGuiRenderSurface }, #if defined( _X360 ) { XBOXINSTALLER_INTERFACE_VERSION, &g_pXboxInstaller }, #endif { MATCHFRAMEWORK_INTERFACE_VERSION, &g_pMatchFramework }, { GAMEUISYSTEMMGR_INTERFACE_VERSION, &g_pGameUISystemMgr }, #if defined( INCLUDE_SCALEFORM ) { SCALEFORMUI_INTERFACE_VERSION, &g_pScaleformUI }, #endif }; //----------------------------------------------------------------------------- // The # of times this DLL has been connected //----------------------------------------------------------------------------- static int s_nConnectionCount = 0; //----------------------------------------------------------------------------- // At each level of connection, we're going to keep track of which interfaces // we filled in. When we disconnect, we'll clear those interface pointers out. //----------------------------------------------------------------------------- struct ConnectionRegistration_t { void *m_ppGlobalStorage; int m_nConnectionPhase; }; static int s_nRegistrationCount = 0; static ConnectionRegistration_t s_pConnectionRegistration[ ARRAYSIZE(g_pInterfaceGlobals) + 1 ]; void RegisterInterface( CreateInterfaceFn factory, const char *pInterfaceName, void **ppGlobal ) { if ( !(*ppGlobal) ) { *ppGlobal = factory( pInterfaceName, NULL ); if ( *ppGlobal ) { Assert( s_nRegistrationCount < ARRAYSIZE(s_pConnectionRegistration) ); ConnectionRegistration_t ® = s_pConnectionRegistration[s_nRegistrationCount++]; reg.m_ppGlobalStorage = ppGlobal; reg.m_nConnectionPhase = s_nConnectionCount; } } } void ReconnectInterface( CreateInterfaceFn factory, const char *pInterfaceName, void **ppGlobal ) { *ppGlobal = factory( pInterfaceName, NULL ); bool bFound = false; Assert( s_nRegistrationCount < ARRAYSIZE(s_pConnectionRegistration) ); for ( int i = 0; i < s_nRegistrationCount; ++i ) { ConnectionRegistration_t ® = s_pConnectionRegistration[i]; if ( reg.m_ppGlobalStorage != ppGlobal ) continue; reg.m_ppGlobalStorage = ppGlobal; bFound = true; } if ( !bFound && *ppGlobal ) { Assert( s_nRegistrationCount < ARRAYSIZE(s_pConnectionRegistration) ); ConnectionRegistration_t ® = s_pConnectionRegistration[s_nRegistrationCount++]; reg.m_ppGlobalStorage = ppGlobal; reg.m_nConnectionPhase = s_nConnectionCount; } } //----------------------------------------------------------------------------- // Call this to connect to all tier 1 libraries. // It's up to the caller to check the globals it cares about to see if ones are missing //----------------------------------------------------------------------------- void ConnectInterfaces( CreateInterfaceFn *pFactoryList, int nFactoryCount ) { if ( s_nRegistrationCount < 0 ) { Error( "APPSYSTEM: In ConnectInterfaces(), s_nRegistrationCount is %d!\n", s_nRegistrationCount ); } else if ( s_nRegistrationCount == 0 ) { for ( int i = 0; i < nFactoryCount; ++i ) { for ( int j = 0; j < ARRAYSIZE( g_pInterfaceGlobals ); ++j ) { RegisterInterface( pFactoryList[i], g_pInterfaceGlobals[j].m_pInterfaceName, (void**)g_pInterfaceGlobals[j].m_ppGlobal ); } } } else { // This is no longer questionable: ConnectInterfaces() is expected to be called multiple times for a file that exports multiple interfaces. // Warning("APPSYSTEM: ConnectInterfaces() was called twice for the same DLL.\nThis is expected behavior in building reslists, but questionable otherwise.\n"); for ( int i = 0; i < nFactoryCount; ++i ) { for ( int j = 0; j < ARRAYSIZE( g_pInterfaceGlobals ); ++j ) { ReconnectInterface( pFactoryList[i], g_pInterfaceGlobals[j].m_pInterfaceName, (void**)g_pInterfaceGlobals[j].m_ppGlobal ); } } } ++s_nConnectionCount; } void DisconnectInterfaces() { Assert( s_nConnectionCount > 0 ); if ( --s_nConnectionCount < 0 ) return; for ( int i = 0; i < s_nRegistrationCount; ++i ) { if ( s_pConnectionRegistration[i].m_nConnectionPhase != s_nConnectionCount ) continue; // Disconnect! *(void**)(s_pConnectionRegistration[i].m_ppGlobalStorage) = 0; } } //----------------------------------------------------------------------------- // Reloads an interface //----------------------------------------------------------------------------- void ReconnectInterface( CreateInterfaceFn factory, const char *pInterfaceName ) { for ( int i = 0; i < ARRAYSIZE( g_pInterfaceGlobals ); ++i ) { if ( strcmp( g_pInterfaceGlobals[i].m_pInterfaceName, pInterfaceName ) ) continue; ReconnectInterface( factory, g_pInterfaceGlobals[i].m_pInterfaceName, (void**)g_pInterfaceGlobals[i].m_ppGlobal ); } }