Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1308 lines
41 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $Workfile: $
  6. // $NoKeywords: $
  7. //===========================================================================//
  8. #include "engine/ivmodelinfo.h"
  9. #include "filesystem.h"
  10. #include "gl_model_private.h"
  11. #include "modelloader.h"
  12. #include "l_studio.h"
  13. #include "cmodel_engine.h"
  14. #include "server.h"
  15. #include "r_local.h"
  16. #include "materialsystem/imaterialsystem.h"
  17. #include "materialsystem/imaterial.h"
  18. #include "lightcache.h"
  19. #include "istudiorender.h"
  20. #include "utldict.h"
  21. #include "filesystem_engine.h"
  22. #include "client.h"
  23. #include "sys_dll.h"
  24. #include "gl_rsurf.h"
  25. #include "utlvector.h"
  26. #include "utlhashtable.h"
  27. #include "utlsymbol.h"
  28. #include "ModelInfo.h"
  29. #include "networkstringtable.h" // for Lock()
  30. #ifndef SWDS
  31. #include "demo.h"
  32. #endif
  33. // memdbgon must be the last include file in a .cpp file!!!
  34. #include "tier0/memdbgon.h"
  35. //-----------------------------------------------------------------------------
  36. // Gets the lighting center
  37. //-----------------------------------------------------------------------------
  38. static void R_StudioGetLightingCenter( IClientRenderable *pRenderable, studiohdr_t* pStudioHdr, const Vector& origin,
  39. const QAngle &angles, Vector* pLightingOrigin )
  40. {
  41. Assert( pLightingOrigin );
  42. matrix3x4_t matrix;
  43. AngleMatrix( angles, origin, matrix );
  44. R_ComputeLightingOrigin( pRenderable, pStudioHdr, matrix, *pLightingOrigin );
  45. }
  46. static int R_StudioBodyVariations( studiohdr_t *pstudiohdr )
  47. {
  48. mstudiobodyparts_t *pbodypart;
  49. int i, count;
  50. if ( !pstudiohdr )
  51. return 0;
  52. count = 1;
  53. pbodypart = pstudiohdr->pBodypart( 0 );
  54. // Each body part has nummodels variations so there are as many total variations as there
  55. // are in a matrix of each part by each other part
  56. for ( i = 0; i < pstudiohdr->numbodyparts; i++ )
  57. {
  58. count = count * pbodypart[i].nummodels;
  59. }
  60. return count;
  61. }
  62. static int ModelFrameCount( model_t *model )
  63. {
  64. int count = 1;
  65. if ( !model )
  66. return count;
  67. if ( model->type == mod_sprite )
  68. {
  69. return model->sprite.numframes;
  70. }
  71. else if ( model->type == mod_studio )
  72. {
  73. count = R_StudioBodyVariations( ( studiohdr_t * )modelloader->GetExtraData( model ) );
  74. }
  75. if ( count < 1 )
  76. count = 1;
  77. return count;
  78. }
  79. //-----------------------------------------------------------------------------
  80. // private extension of CNetworkStringTable to correct lack of Lock retval
  81. //-----------------------------------------------------------------------------
  82. class CNetworkStringTable_LockOverride : public CNetworkStringTable
  83. {
  84. private:
  85. CNetworkStringTable_LockOverride(); // no impl
  86. ~CNetworkStringTable_LockOverride(); // no impl
  87. CNetworkStringTable_LockOverride(const CNetworkStringTable_LockOverride &); // no impl
  88. CNetworkStringTable_LockOverride& operator=(const CNetworkStringTable_LockOverride &); // no impl
  89. public:
  90. bool LockWithRetVal( bool bLock ) { bool bWasLocked = m_bLocked; Lock(bLock); return bWasLocked; }
  91. };
  92. //-----------------------------------------------------------------------------
  93. // shared implementation of IVModelInfo
  94. //-----------------------------------------------------------------------------
  95. abstract_class CModelInfo : public IVModelInfoClient
  96. {
  97. public:
  98. // GetModel, RegisterDynamicModel(name) are in CModelInfoClient/CModelInfoServer
  99. virtual int GetModelIndex( const char *name ) const;
  100. virtual int GetModelClientSideIndex( const char *name ) const;
  101. virtual bool RegisterModelLoadCallback( int modelindex, IModelLoadCallback* pCallback, bool bCallImmediatelyIfLoaded );
  102. virtual void UnregisterModelLoadCallback( int modelindex, IModelLoadCallback* pCallback );
  103. virtual bool IsDynamicModelLoading( int modelIndex );
  104. virtual void AddRefDynamicModel( int modelIndex );
  105. virtual void ReleaseDynamicModel( int modelIndex );
  106. virtual void OnLevelChange();
  107. virtual const char *GetModelName( const model_t *model ) const;
  108. virtual void GetModelBounds( const model_t *model, Vector& mins, Vector& maxs ) const;
  109. virtual void GetModelRenderBounds( const model_t *model, Vector& mins, Vector& maxs ) const;
  110. virtual int GetModelFrameCount( const model_t *model ) const;
  111. virtual int GetModelType( const model_t *model ) const;
  112. virtual void *GetModelExtraData( const model_t *model );
  113. virtual bool ModelHasMaterialProxy( const model_t *model ) const;
  114. virtual bool IsTranslucent( const model_t *model ) const;
  115. virtual bool IsModelVertexLit( const model_t *model ) const;
  116. virtual bool IsTranslucentTwoPass( const model_t *model ) const;
  117. virtual void RecomputeTranslucency( const model_t *model, int nSkin, int nBody, void /*IClientRenderable*/ *pClientRenderable, float fInstanceAlphaModulate);
  118. virtual int GetModelMaterialCount( const model_t *model ) const;
  119. virtual void GetModelMaterials( const model_t *model, int count, IMaterial** ppMaterials );
  120. virtual void GetIlluminationPoint( const model_t *model, IClientRenderable *pRenderable, const Vector& origin,
  121. const QAngle& angles, Vector* pLightingOrigin );
  122. virtual int GetModelContents( int modelIndex );
  123. vcollide_t *GetVCollide( const model_t *model );
  124. vcollide_t *GetVCollide( int modelIndex );
  125. virtual const char *GetModelKeyValueText( const model_t *model );
  126. virtual bool GetModelKeyValue( const model_t *model, CUtlBuffer &buf );
  127. virtual float GetModelRadius( const model_t *model );
  128. virtual studiohdr_t *GetStudiomodel( const model_t *mod );
  129. virtual int GetModelSpriteWidth( const model_t *model ) const;
  130. virtual int GetModelSpriteHeight( const model_t *model ) const;
  131. virtual const studiohdr_t *FindModel( const studiohdr_t *pStudioHdr, void **cache, char const *modelname ) const;
  132. virtual const studiohdr_t *FindModel( void *cache ) const;
  133. virtual virtualmodel_t *GetVirtualModel( const studiohdr_t *pStudioHdr ) const;
  134. virtual byte *GetAnimBlock( const studiohdr_t *pStudioHdr, int iBlock ) const;
  135. byte *LoadAnimBlock( model_t *model, const studiohdr_t *pStudioHdr, int iBlock, cache_user_t *cache ) const;
  136. // NOTE: These aren't in the server version, but putting them here makes this code easier to write
  137. // Sets/gets a map-specified fade range
  138. virtual void SetLevelScreenFadeRange( float flMinSize, float flMaxSize ) {}
  139. virtual void GetLevelScreenFadeRange( float *pMinArea, float *pMaxArea ) const { *pMinArea = 0; *pMaxArea = 0; }
  140. // Sets/gets a map-specified per-view fade range
  141. virtual void SetViewScreenFadeRange( float flMinSize, float flMaxSize ) {}
  142. // Computes fade alpha based on distance fade + screen fade
  143. virtual unsigned char ComputeLevelScreenFade( const Vector &vecAbsOrigin, float flRadius, float flFadeScale ) const { return 0; }
  144. virtual unsigned char ComputeViewScreenFade( const Vector &vecAbsOrigin, float flRadius, float flFadeScale ) const { return 0; }
  145. int GetAutoplayList( const studiohdr_t *pStudioHdr, unsigned short **pAutoplayList ) const;
  146. CPhysCollide *GetCollideForVirtualTerrain( int index );
  147. virtual int GetSurfacepropsForVirtualTerrain( int index ) { return CM_SurfacepropsForDisp(index); }
  148. virtual bool IsUsingFBTexture( const model_t *model, int nSkin, int nBody, void /*IClientRenderable*/ *pClientRenderable ) const;
  149. virtual MDLHandle_t GetCacheHandle( const model_t *model ) const { return ( model->type == mod_studio ) ? model->studio : MDLHANDLE_INVALID; }
  150. // Returns planes of non-nodraw brush model surfaces
  151. virtual int GetBrushModelPlaneCount( const model_t *model ) const;
  152. virtual void GetBrushModelPlane( const model_t *model, int nIndex, cplane_t &plane, Vector *pOrigin ) const;
  153. protected:
  154. static int CLIENTSIDE_TO_MODEL( int i ) { return i >= 0 ? (-2 - (i*2 + 1)) : -1; }
  155. static int NETDYNAMIC_TO_MODEL( int i ) { return i >= 0 ? (-2 - (i*2)) : -1; }
  156. static int MODEL_TO_CLIENTSIDE( int i ) { return ( i <= -2 && (i & 1) ) ? (-2 - i) >> 1 : -1; }
  157. static int MODEL_TO_NETDYNAMIC( int i ) { return ( i <= -2 && !(i & 1) ) ? (-2 - i) >> 1 : -1; }
  158. model_t *LookupDynamicModel( int i );
  159. virtual INetworkStringTable *GetDynamicModelStringTable() const = 0;
  160. virtual int LookupPrecachedModelIndex( const char *name ) const = 0;
  161. void GrowNetworkedDynamicModels( int netidx )
  162. {
  163. if ( m_NetworkedDynamicModels.Count() <= netidx )
  164. {
  165. int origCount = m_NetworkedDynamicModels.Count();
  166. m_NetworkedDynamicModels.SetCountNonDestructively( netidx + 1 );
  167. for ( int i = origCount; i <= netidx; ++i )
  168. {
  169. m_NetworkedDynamicModels[i] = NULL;
  170. }
  171. }
  172. }
  173. // Networked dynamic model indices are lookup indices for this vector
  174. CUtlVector< model_t* > m_NetworkedDynamicModels;
  175. public:
  176. struct ModelFileHandleHash
  177. {
  178. uint operator()( model_t *p ) const { return Mix32HashFunctor()( (uint32)( p->fnHandle ) ); }
  179. uint operator()( FileNameHandle_t fn ) const { return Mix32HashFunctor()( (uint32) fn ); }
  180. };
  181. struct ModelFileHandleEq
  182. {
  183. bool operator()( model_t *a, model_t *b ) const { return a == b; }
  184. bool operator()( model_t *a, FileNameHandle_t b ) const { return a->fnHandle == b; }
  185. };
  186. protected:
  187. // Client-only dynamic model indices are iterators into this struct (only populated by CModelInfoClient subclass)
  188. CUtlStableHashtable< model_t*, empty_t, ModelFileHandleHash, ModelFileHandleEq, int16, FileNameHandle_t > m_ClientDynamicModels;
  189. };
  190. int CModelInfo::GetModelIndex( const char *name ) const
  191. {
  192. if ( !name )
  193. return -1;
  194. // Order of preference: precached, networked, client-only.
  195. int nIndex = LookupPrecachedModelIndex( name );
  196. if ( nIndex != -1 )
  197. return nIndex;
  198. INetworkStringTable* pTable = GetDynamicModelStringTable();
  199. if ( pTable )
  200. {
  201. int netdyn = pTable->FindStringIndex( name );
  202. if ( netdyn != INVALID_STRING_INDEX )
  203. {
  204. Assert( !m_NetworkedDynamicModels.IsValidIndex( netdyn ) || V_strcmp( m_NetworkedDynamicModels[netdyn]->strName, name ) == 0 );
  205. return NETDYNAMIC_TO_MODEL( netdyn );
  206. }
  207. #if defined( DEMO_BACKWARDCOMPATABILITY ) && !defined( SWDS )
  208. // dynamic model tables in old system did not have a full path with "models/" prefix
  209. if ( V_strnicmp( name, "models/", 7 ) == 0 && demoplayer && demoplayer->IsPlayingBack() && demoplayer->GetProtocolVersion() < PROTOCOL_VERSION_20 )
  210. {
  211. netdyn = pTable->FindStringIndex( name + 7 );
  212. if ( netdyn != INVALID_STRING_INDEX )
  213. {
  214. Assert( !m_NetworkedDynamicModels.IsValidIndex( netdyn ) || V_strcmp( m_NetworkedDynamicModels[netdyn]->strName, name ) == 0 );
  215. return NETDYNAMIC_TO_MODEL( netdyn );
  216. }
  217. }
  218. #endif
  219. }
  220. return GetModelClientSideIndex( name );
  221. }
  222. int CModelInfo::GetModelClientSideIndex( const char *name ) const
  223. {
  224. if ( m_ClientDynamicModels.Count() != 0 )
  225. {
  226. FileNameHandle_t file = g_pFullFileSystem->FindFileName( name );
  227. if ( file != FILENAMEHANDLE_INVALID )
  228. {
  229. UtlHashHandle_t h = m_ClientDynamicModels.Find( file );
  230. if ( h != m_ClientDynamicModels.InvalidHandle() )
  231. {
  232. Assert( V_strcmp( m_ClientDynamicModels[h]->strName, name ) == 0 );
  233. return CLIENTSIDE_TO_MODEL( h );
  234. }
  235. }
  236. }
  237. return -1;
  238. }
  239. model_t *CModelInfo::LookupDynamicModel( int i )
  240. {
  241. Assert( IsDynamicModelIndex( i ) );
  242. if ( IsClientOnlyModelIndex( i ) )
  243. {
  244. UtlHashHandle_t h = (UtlHashHandle_t) MODEL_TO_CLIENTSIDE( i );
  245. return m_ClientDynamicModels.IsValidHandle( h ) ? m_ClientDynamicModels[ h ] : NULL;
  246. }
  247. else
  248. {
  249. int netidx = MODEL_TO_NETDYNAMIC( i );
  250. if ( m_NetworkedDynamicModels.IsValidIndex( netidx ) && m_NetworkedDynamicModels[ netidx ] )
  251. return m_NetworkedDynamicModels[ netidx ];
  252. INetworkStringTable *pTable = GetDynamicModelStringTable();
  253. if ( pTable && (uint) netidx < (uint) pTable->GetNumStrings() )
  254. {
  255. GrowNetworkedDynamicModels( netidx );
  256. const char *name = pTable->GetString( netidx );
  257. #if defined( DEMO_BACKWARDCOMPATABILITY ) && !defined( SWDS )
  258. // dynamic model tables in old system did not have a full path with "models/" prefix
  259. char fixupBuf[MAX_PATH];
  260. if ( V_strnicmp( name, "models/", 7 ) != 0 && demoplayer && demoplayer->IsPlayingBack() && demoplayer->GetProtocolVersion() < PROTOCOL_VERSION_20 )
  261. {
  262. V_snprintf( fixupBuf, MAX_PATH, "models/%s", name );
  263. name = fixupBuf;
  264. }
  265. #endif
  266. model_t *pModel = modelloader->GetDynamicModel( name, false );
  267. m_NetworkedDynamicModels[ netidx ] = pModel;
  268. return pModel;
  269. }
  270. return NULL;
  271. }
  272. }
  273. bool CModelInfo::RegisterModelLoadCallback( int modelIndex, IModelLoadCallback* pCallback, bool bCallImmediatelyIfLoaded )
  274. {
  275. const model_t *pModel = GetModel( modelIndex );
  276. Assert( pModel );
  277. if ( pModel && IsDynamicModelIndex( modelIndex ) )
  278. {
  279. return modelloader->RegisterModelLoadCallback( const_cast< model_t *>( pModel ), IsClientOnlyModelIndex( modelIndex ), pCallback, bCallImmediatelyIfLoaded );
  280. }
  281. else if ( pModel && bCallImmediatelyIfLoaded )
  282. {
  283. pCallback->OnModelLoadComplete( pModel );
  284. return true;
  285. }
  286. return false;
  287. }
  288. void CModelInfo::UnregisterModelLoadCallback( int modelIndex, IModelLoadCallback* pCallback )
  289. {
  290. if ( modelIndex == -1 )
  291. {
  292. modelloader->UnregisterModelLoadCallback( NULL, false, pCallback );
  293. modelloader->UnregisterModelLoadCallback( NULL, true, pCallback );
  294. }
  295. else if ( IsDynamicModelIndex( modelIndex ) )
  296. {
  297. const model_t *pModel = LookupDynamicModel( modelIndex );
  298. Assert( pModel );
  299. if ( pModel )
  300. {
  301. modelloader->UnregisterModelLoadCallback( const_cast< model_t *>( pModel ), IsClientOnlyModelIndex( modelIndex ), pCallback );
  302. }
  303. }
  304. }
  305. bool CModelInfo::IsDynamicModelLoading( int modelIndex )
  306. {
  307. model_t *pModel = LookupDynamicModel( modelIndex );
  308. return pModel && modelloader->IsDynamicModelLoading( pModel, IsClientOnlyModelIndex( modelIndex ) );
  309. }
  310. void CModelInfo::AddRefDynamicModel( int modelIndex )
  311. {
  312. if ( IsDynamicModelIndex( modelIndex ) )
  313. {
  314. model_t *pModel = LookupDynamicModel( modelIndex );
  315. Assert( pModel );
  316. if ( pModel )
  317. {
  318. modelloader->AddRefDynamicModel( pModel, IsClientOnlyModelIndex( modelIndex ) );
  319. }
  320. }
  321. }
  322. void CModelInfo::ReleaseDynamicModel( int modelIndex )
  323. {
  324. if ( IsDynamicModelIndex( modelIndex ) )
  325. {
  326. model_t *pModel = LookupDynamicModel( modelIndex );
  327. Assert( pModel );
  328. if ( pModel )
  329. {
  330. modelloader->ReleaseDynamicModel( pModel, IsClientOnlyModelIndex( modelIndex ) );
  331. }
  332. }
  333. }
  334. void CModelInfo::OnLevelChange()
  335. {
  336. // Network string table has reset
  337. m_NetworkedDynamicModels.Purge();
  338. // Force-unload any server-side models
  339. modelloader->ForceUnloadNonClientDynamicModels();
  340. }
  341. const char *CModelInfo::GetModelName( const model_t *pModel ) const
  342. {
  343. if ( !pModel )
  344. {
  345. return "?";
  346. }
  347. return modelloader->GetName( pModel );
  348. }
  349. void CModelInfo::GetModelBounds( const model_t *model, Vector& mins, Vector& maxs ) const
  350. {
  351. VectorCopy( model->mins, mins );
  352. VectorCopy( model->maxs, maxs );
  353. }
  354. void CModelInfo::GetModelRenderBounds( const model_t *model, Vector& mins, Vector& maxs ) const
  355. {
  356. if (!model)
  357. {
  358. mins.Init(0,0,0);
  359. maxs.Init(0,0,0);
  360. return;
  361. }
  362. switch( model->type )
  363. {
  364. case mod_studio:
  365. {
  366. studiohdr_t *pStudioHdr = ( studiohdr_t * )modelloader->GetExtraData( (model_t*)model );
  367. Assert( pStudioHdr );
  368. // NOTE: We're not looking at the sequence box here, although we could
  369. if (!VectorCompare( vec3_origin, pStudioHdr->view_bbmin ) || !VectorCompare( vec3_origin, pStudioHdr->view_bbmax ))
  370. {
  371. // clipping bounding box
  372. VectorCopy ( pStudioHdr->view_bbmin, mins);
  373. VectorCopy ( pStudioHdr->view_bbmax, maxs);
  374. }
  375. else
  376. {
  377. // movement bounding box
  378. VectorCopy ( pStudioHdr->hull_min, mins);
  379. VectorCopy ( pStudioHdr->hull_max, maxs);
  380. }
  381. }
  382. break;
  383. case mod_brush:
  384. VectorCopy( model->mins, mins );
  385. VectorCopy( model->maxs, maxs );
  386. break;
  387. default:
  388. mins.Init( 0, 0, 0 );
  389. maxs.Init( 0, 0, 0 );
  390. break;
  391. }
  392. }
  393. int CModelInfo::GetModelSpriteWidth( const model_t *model ) const
  394. {
  395. // We must be a sprite to make this query
  396. if ( model->type != mod_sprite )
  397. return 0;
  398. return model->sprite.width;
  399. }
  400. int CModelInfo::GetModelSpriteHeight( const model_t *model ) const
  401. {
  402. // We must be a sprite to make this query
  403. if ( model->type != mod_sprite )
  404. return 0;
  405. return model->sprite.height;
  406. }
  407. int CModelInfo::GetModelFrameCount( const model_t *model ) const
  408. {
  409. return ModelFrameCount( ( model_t *)model );
  410. }
  411. int CModelInfo::GetModelType( const model_t *model ) const
  412. {
  413. if ( !model )
  414. return -1;
  415. if ( model->type == mod_bad )
  416. {
  417. if ( m_ClientDynamicModels.Find( (model_t*) model ) != m_ClientDynamicModels.InvalidHandle() )
  418. return mod_studio;
  419. INetworkStringTable* pTable = GetDynamicModelStringTable();
  420. if ( pTable && pTable->FindStringIndex( model->strName ) != INVALID_STRING_INDEX )
  421. return mod_studio;
  422. #if defined( DEMO_BACKWARDCOMPATABILITY ) && !defined( SWDS )
  423. // dynamic model tables in old system did not have a full path with "models/" prefix
  424. if ( pTable && demoplayer && demoplayer->IsPlayingBack() && demoplayer->GetProtocolVersion() < PROTOCOL_VERSION_20 &&
  425. V_strnicmp( model->strName, "models/", 7 ) == 0 && pTable->FindStringIndex( model->strName + 7 ) != INVALID_STRING_INDEX )
  426. {
  427. return mod_studio;
  428. }
  429. #endif
  430. }
  431. return model->type;
  432. }
  433. void *CModelInfo::GetModelExtraData( const model_t *model )
  434. {
  435. return modelloader->GetExtraData( (model_t *)model );
  436. }
  437. //-----------------------------------------------------------------------------
  438. // Purpose: Translate "cache" pointer into model_t, or lookup model by name
  439. //-----------------------------------------------------------------------------
  440. const studiohdr_t *CModelInfo::FindModel( const studiohdr_t *pStudioHdr, void **cache, char const *modelname ) const
  441. {
  442. const model_t *model = (model_t *)*cache;
  443. if (!model)
  444. {
  445. // FIXME: what do I pass in here?
  446. model = modelloader->GetModelForName( modelname, IModelLoader::FMODELLOADER_SERVER );
  447. *cache = (void *)model;
  448. }
  449. return (const studiohdr_t *)modelloader->GetExtraData( (model_t *)model );
  450. }
  451. //-----------------------------------------------------------------------------
  452. // Purpose: Translate "cache" pointer into model_t
  453. //-----------------------------------------------------------------------------
  454. const studiohdr_t *CModelInfo::FindModel( void *cache ) const
  455. {
  456. return g_pMDLCache->GetStudioHdr( (MDLHandle_t)(int)cache&0xffff );
  457. }
  458. //-----------------------------------------------------------------------------
  459. // Purpose: Return virtualmodel_t block associated with model_t
  460. //-----------------------------------------------------------------------------
  461. virtualmodel_t *CModelInfo::GetVirtualModel( const studiohdr_t *pStudioHdr ) const
  462. {
  463. MDLHandle_t handle = (MDLHandle_t)(int)pStudioHdr->virtualModel&0xffff;
  464. return g_pMDLCache->GetVirtualModelFast( pStudioHdr, handle );
  465. }
  466. //-----------------------------------------------------------------------------
  467. // Purpose:
  468. //-----------------------------------------------------------------------------
  469. byte *CModelInfo::GetAnimBlock( const studiohdr_t *pStudioHdr, int nBlock ) const
  470. {
  471. MDLHandle_t handle = (MDLHandle_t)(int)pStudioHdr->virtualModel&0xffff;
  472. return g_pMDLCache->GetAnimBlock( handle, nBlock );
  473. }
  474. int CModelInfo::GetAutoplayList( const studiohdr_t *pStudioHdr, unsigned short **pAutoplayList ) const
  475. {
  476. MDLHandle_t handle = (MDLHandle_t)(int)pStudioHdr->virtualModel&0xffff;
  477. return g_pMDLCache->GetAutoplayList( handle, pAutoplayList );
  478. }
  479. //-----------------------------------------------------------------------------
  480. // Purpose: bind studiohdr_t support functions to engine
  481. // FIXME: This should be moved into studio.cpp?
  482. //-----------------------------------------------------------------------------
  483. const studiohdr_t *studiohdr_t::FindModel( void **cache, char const *pModelName ) const
  484. {
  485. MDLHandle_t handle = g_pMDLCache->FindMDL( pModelName );
  486. *cache = (void*)(uintp)handle;
  487. return g_pMDLCache->GetStudioHdr( handle );
  488. }
  489. virtualmodel_t *studiohdr_t::GetVirtualModel( void ) const
  490. {
  491. if ( numincludemodels == 0 )
  492. return NULL;
  493. return g_pMDLCache->GetVirtualModelFast( this, (MDLHandle_t)(int)virtualModel&0xffff );
  494. }
  495. byte *studiohdr_t::GetAnimBlock( int i ) const
  496. {
  497. return g_pMDLCache->GetAnimBlock( (MDLHandle_t)(int)virtualModel&0xffff, i );
  498. }
  499. int studiohdr_t::GetAutoplayList( unsigned short **pOut ) const
  500. {
  501. return g_pMDLCache->GetAutoplayList( (MDLHandle_t)(int)virtualModel&0xffff, pOut );
  502. }
  503. const studiohdr_t *virtualgroup_t::GetStudioHdr( void ) const
  504. {
  505. return g_pMDLCache->GetStudioHdr( (MDLHandle_t)(int)cache&0xffff );
  506. }
  507. //-----------------------------------------------------------------------------
  508. // Purpose:
  509. //-----------------------------------------------------------------------------
  510. bool CModelInfo::ModelHasMaterialProxy( const model_t *model ) const
  511. {
  512. // Should we add skin & model to this function like IsUsingFBTexture()?
  513. return (model && (model->flags & MODELFLAG_MATERIALPROXY));
  514. }
  515. bool CModelInfo::IsTranslucent( const model_t *model ) const
  516. {
  517. return (model && (model->flags & MODELFLAG_TRANSLUCENT));
  518. }
  519. bool CModelInfo::IsModelVertexLit( const model_t *model ) const
  520. {
  521. // Should we add skin & model to this function like IsUsingFBTexture()?
  522. return (model && (model->flags & MODELFLAG_VERTEXLIT));
  523. }
  524. bool CModelInfo::IsTranslucentTwoPass( const model_t *model ) const
  525. {
  526. return (model && (model->flags & MODELFLAG_TRANSLUCENT_TWOPASS));
  527. }
  528. bool CModelInfo::IsUsingFBTexture( const model_t *model, int nSkin, int nBody, void /*IClientRenderable*/ *pClientRenderable ) const
  529. {
  530. bool bMightUseFbTextureThisFrame = (model && (model->flags & MODELFLAG_STUDIOHDR_USES_FB_TEXTURE));
  531. if ( bMightUseFbTextureThisFrame )
  532. {
  533. // Check each material's NeedsPowerOfTwoFrameBufferTexture() virtual func
  534. switch( model->type )
  535. {
  536. case mod_brush:
  537. {
  538. for (int i = 0; i < model->brush.nummodelsurfaces; ++i)
  539. {
  540. SurfaceHandle_t surfID = SurfaceHandleFromIndex( model->brush.firstmodelsurface+i, model->brush.pShared );
  541. IMaterial* material = MSurf_TexInfo( surfID, model->brush.pShared )->material;
  542. if ( material != NULL )
  543. {
  544. if ( material->NeedsPowerOfTwoFrameBufferTexture() )
  545. {
  546. return true;
  547. }
  548. }
  549. }
  550. }
  551. break;
  552. case mod_studio:
  553. {
  554. IMaterial *pMaterials[ 128 ];
  555. int materialCount = g_pStudioRender->GetMaterialListFromBodyAndSkin( model->studio, nSkin, nBody, ARRAYSIZE( pMaterials ), pMaterials );
  556. for ( int i = 0; i < materialCount; i++ )
  557. {
  558. if ( pMaterials[i] != NULL )
  559. {
  560. // Bind material first so all material proxies execute
  561. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  562. pRenderContext->Bind( pMaterials[i], pClientRenderable );
  563. if ( pMaterials[i]->NeedsPowerOfTwoFrameBufferTexture() )
  564. {
  565. return true;
  566. }
  567. }
  568. }
  569. }
  570. break;
  571. }
  572. }
  573. return false;
  574. }
  575. void CModelInfo::RecomputeTranslucency( const model_t *model, int nSkin, int nBody, void /*IClientRenderable*/ *pClientRenderable, float fInstanceAlphaModulate )
  576. {
  577. if ( model != NULL )
  578. {
  579. Mod_RecomputeTranslucency( (model_t *)model, nSkin, nBody, pClientRenderable, fInstanceAlphaModulate );
  580. }
  581. }
  582. int CModelInfo::GetModelMaterialCount( const model_t *model ) const
  583. {
  584. if (!model)
  585. return 0;
  586. return Mod_GetMaterialCount( (model_t *)model );
  587. }
  588. void CModelInfo::GetModelMaterials( const model_t *model, int count, IMaterial** ppMaterials )
  589. {
  590. if (model)
  591. Mod_GetModelMaterials( (model_t *)model, count, ppMaterials );
  592. }
  593. void CModelInfo::GetIlluminationPoint( const model_t *model, IClientRenderable *pRenderable, const Vector& origin,
  594. const QAngle& angles, Vector* pLightingOrigin )
  595. {
  596. Assert( model->type == mod_studio );
  597. studiohdr_t* pStudioHdr = (studiohdr_t*)GetModelExtraData(model);
  598. if (pStudioHdr)
  599. {
  600. R_StudioGetLightingCenter( pRenderable, pStudioHdr, origin, angles, pLightingOrigin );
  601. }
  602. else
  603. {
  604. *pLightingOrigin = origin;
  605. }
  606. }
  607. int CModelInfo::GetModelContents( int modelIndex )
  608. {
  609. const model_t *pModel = GetModel( modelIndex );
  610. if ( pModel )
  611. {
  612. switch( pModel->type )
  613. {
  614. case mod_brush:
  615. return CM_InlineModelContents( modelIndex-1 );
  616. // BUGBUG: Studio contents?
  617. case mod_studio:
  618. return CONTENTS_SOLID;
  619. }
  620. }
  621. return 0;
  622. }
  623. #if !defined( _RETAIL )
  624. extern double g_flAccumulatedModelLoadTimeVCollideSync;
  625. #endif
  626. vcollide_t *CModelInfo::GetVCollide( const model_t *pModel )
  627. {
  628. if ( !pModel )
  629. return NULL;
  630. if ( pModel->type == mod_studio )
  631. {
  632. #if !defined( _RETAIL )
  633. double t1 = Plat_FloatTime();
  634. #endif
  635. vcollide_t *col = g_pMDLCache->GetVCollide( pModel->studio );
  636. #if !defined( _RETAIL )
  637. double t2 = Plat_FloatTime();
  638. g_flAccumulatedModelLoadTimeVCollideSync += ( t2 - t1 );
  639. #endif
  640. return col;
  641. }
  642. int i = GetModelIndex( GetModelName( pModel ) );
  643. if ( i >= 0 )
  644. {
  645. return GetVCollide( i );
  646. }
  647. return NULL;
  648. }
  649. vcollide_t *CModelInfo::GetVCollide( int modelIndex )
  650. {
  651. // First model (index 0 )is is empty
  652. // Second model( index 1 ) is the world, then brushes/submodels, then players, etc.
  653. // So, we must subtract 1 from the model index to map modelindex to CM_ index
  654. // in cmodels, 0 is the world, then brushes, etc.
  655. if ( modelIndex < MAX_MODELS )
  656. {
  657. const model_t *pModel = GetModel( modelIndex );
  658. if ( pModel )
  659. {
  660. switch( pModel->type )
  661. {
  662. case mod_brush:
  663. return CM_GetVCollide( modelIndex-1 );
  664. case mod_studio:
  665. {
  666. #if !defined( _RETAIL )
  667. double t1 = Plat_FloatTime();
  668. #endif
  669. vcollide_t *col = g_pMDLCache->GetVCollide( pModel->studio );
  670. #if !defined( _RETAIL )
  671. double t2 = Plat_FloatTime();
  672. g_flAccumulatedModelLoadTimeVCollideSync += ( t2 - t1 );
  673. #endif
  674. return col;
  675. }
  676. }
  677. }
  678. else
  679. {
  680. // we may have the cmodels loaded and not know the model/mod->type yet
  681. return CM_GetVCollide( modelIndex-1 );
  682. }
  683. }
  684. return NULL;
  685. }
  686. // Client must instantiate a KeyValues, which will be filled by this method
  687. const char *CModelInfo::GetModelKeyValueText( const model_t *model )
  688. {
  689. if (!model || model->type != mod_studio)
  690. return NULL;
  691. studiohdr_t* pStudioHdr = g_pMDLCache->GetStudioHdr( model->studio );
  692. if (!pStudioHdr)
  693. return NULL;
  694. return pStudioHdr->KeyValueText();
  695. }
  696. bool CModelInfo::GetModelKeyValue( const model_t *model, CUtlBuffer &buf )
  697. {
  698. if (!model || model->type != mod_studio)
  699. return false;
  700. studiohdr_t* pStudioHdr = g_pMDLCache->GetStudioHdr( model->studio );
  701. if (!pStudioHdr)
  702. return false;
  703. if ( pStudioHdr->numincludemodels == 0)
  704. {
  705. buf.PutString( pStudioHdr->KeyValueText() );
  706. return true;
  707. }
  708. virtualmodel_t *pVM = GetVirtualModel( pStudioHdr );
  709. if (pVM)
  710. {
  711. for (int i = 0; i < pVM->m_group.Count(); i++)
  712. {
  713. const studiohdr_t* pSubStudioHdr = pVM->m_group[i].GetStudioHdr();
  714. if (pSubStudioHdr && pSubStudioHdr->KeyValueText())
  715. {
  716. buf.PutString( pSubStudioHdr->KeyValueText() );
  717. }
  718. }
  719. }
  720. return true;
  721. }
  722. //-----------------------------------------------------------------------------
  723. // Purpose:
  724. // Input : *model -
  725. // Output : float
  726. //-----------------------------------------------------------------------------
  727. float CModelInfo::GetModelRadius( const model_t *model )
  728. {
  729. if ( !model )
  730. return 0.0f;
  731. return model->radius;
  732. }
  733. //-----------------------------------------------------------------------------
  734. // Lovely studiohdrs
  735. //-----------------------------------------------------------------------------
  736. studiohdr_t *CModelInfo::GetStudiomodel( const model_t *model )
  737. {
  738. if ( model->type == mod_studio )
  739. return g_pMDLCache->GetStudioHdr( model->studio );
  740. return NULL;
  741. }
  742. CPhysCollide *CModelInfo::GetCollideForVirtualTerrain( int index )
  743. {
  744. return CM_PhysCollideForDisp( index );
  745. }
  746. // Returns planes of non-nodraw brush model surfaces
  747. int CModelInfo::GetBrushModelPlaneCount( const model_t *model ) const
  748. {
  749. if ( !model || model->type != mod_brush )
  750. return 0;
  751. return R_GetBrushModelPlaneCount( model );
  752. }
  753. void CModelInfo::GetBrushModelPlane( const model_t *model, int nIndex, cplane_t &plane, Vector *pOrigin ) const
  754. {
  755. if ( !model || model->type != mod_brush )
  756. return;
  757. plane = R_GetBrushModelPlane( model, nIndex, pOrigin );
  758. }
  759. //-----------------------------------------------------------------------------
  760. // implementation of IVModelInfo for server
  761. //-----------------------------------------------------------------------------
  762. class CModelInfoServer : public CModelInfo
  763. {
  764. public:
  765. virtual int RegisterDynamicModel( const char *name, bool bClientSideOnly );
  766. virtual const model_t *GetModel( int modelindex );
  767. virtual const model_t *FindOrLoadModel( const char *name );
  768. virtual void OnDynamicModelsStringTableChange( int nStringIndex, const char *pString, const void *pData );
  769. virtual void GetModelMaterialColorAndLighting( const model_t *model, const Vector& origin,
  770. const QAngle& angles, trace_t* pTrace, Vector& lighting, Vector& matColor );
  771. protected:
  772. virtual INetworkStringTable *GetDynamicModelStringTable() const;
  773. virtual int LookupPrecachedModelIndex( const char *name ) const;
  774. };
  775. INetworkStringTable *CModelInfoServer::GetDynamicModelStringTable() const
  776. {
  777. return sv.GetDynamicModelsTable();
  778. }
  779. int CModelInfoServer::LookupPrecachedModelIndex( const char *name ) const
  780. {
  781. return sv.LookupModelIndex( name );
  782. }
  783. int CModelInfoServer::RegisterDynamicModel( const char *name, bool bClientSide )
  784. {
  785. // Server should not know about client-side dynamic models!
  786. Assert( !bClientSide );
  787. if ( bClientSide )
  788. return -1;
  789. char buf[256];
  790. V_strncpy( buf, name, ARRAYSIZE(buf) );
  791. V_RemoveDotSlashes( buf, '/', true );
  792. name = buf;
  793. Assert( V_strnicmp( name, "models/", 7 ) == 0 && V_strstr( name, ".mdl" ) != NULL );
  794. // Already known? bClientSide should always be false and is asserted above.
  795. int index = GetModelIndex( name );
  796. if ( index != -1 )
  797. return index;
  798. INetworkStringTable *pTable = GetDynamicModelStringTable();
  799. Assert( pTable );
  800. if ( !pTable )
  801. return -1;
  802. // Register this model with the dynamic model string table
  803. Assert( pTable->FindStringIndex( name ) == INVALID_STRING_INDEX );
  804. bool bWasLocked = static_cast<CNetworkStringTable_LockOverride*>( pTable )->LockWithRetVal( false );
  805. char nIsLoaded = 0;
  806. int netidx = pTable->AddString( true, name, 1, &nIsLoaded );
  807. static_cast<CNetworkStringTable*>( pTable )->Lock( bWasLocked );
  808. // And also cache the model_t* pointer at this time
  809. GrowNetworkedDynamicModels( netidx );
  810. m_NetworkedDynamicModels[ netidx ] = modelloader->GetDynamicModel( name, bClientSide );
  811. Assert( MODEL_TO_NETDYNAMIC( ( short ) NETDYNAMIC_TO_MODEL( netidx ) ) == netidx );
  812. return NETDYNAMIC_TO_MODEL( netidx );
  813. }
  814. const model_t *CModelInfoServer::GetModel( int modelindex )
  815. {
  816. if ( IsDynamicModelIndex( modelindex ) )
  817. return LookupDynamicModel( modelindex );
  818. return sv.GetModel( modelindex );
  819. }
  820. void CModelInfoServer::OnDynamicModelsStringTableChange( int nStringIndex, const char *pString, const void *pData )
  821. {
  822. AssertMsg( false, "CModelInfoServer::OnDynamicModelsStringTableChange should never be called" );
  823. }
  824. void CModelInfoServer::GetModelMaterialColorAndLighting( const model_t *model, const Vector& origin,
  825. const QAngle& angles, trace_t* pTrace, Vector& lighting, Vector& matColor )
  826. {
  827. Msg( "GetModelMaterialColorAndLighting: Available on client only!\n" );
  828. }
  829. const model_t *CModelInfoServer::FindOrLoadModel( const char *name )
  830. {
  831. AssertMsg( false, "CModelInfoServer::FindOrLoadModel should never be called" );
  832. return NULL;
  833. }
  834. static CModelInfoServer g_ModelInfoServer;
  835. EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CModelInfoServer, IVModelInfo003, VMODELINFO_SERVER_INTERFACE_VERSION_3, g_ModelInfoServer );
  836. EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CModelInfoServer, IVModelInfo, VMODELINFO_SERVER_INTERFACE_VERSION, g_ModelInfoServer );
  837. // Expose IVModelInfo to the engine
  838. IVModelInfo *modelinfo = &g_ModelInfoServer;
  839. #ifndef SWDS
  840. //-----------------------------------------------------------------------------
  841. // implementation of IVModelInfo for client
  842. //-----------------------------------------------------------------------------
  843. class CModelInfoClient : public CModelInfo
  844. {
  845. public:
  846. virtual int RegisterDynamicModel( const char *name, bool bClientSideOnly );
  847. virtual const model_t *GetModel( int modelindex );
  848. virtual const model_t *FindOrLoadModel( const char *name );
  849. virtual void OnDynamicModelsStringTableChange( int nStringIndex, const char *pString, const void *pData );
  850. // Sets/gets a map-specified fade range
  851. virtual void SetLevelScreenFadeRange( float flMinSize, float flMaxSize );
  852. virtual void GetLevelScreenFadeRange( float *pMinArea, float *pMaxArea ) const;
  853. // Sets/gets a map-specified per-view fade range
  854. virtual void SetViewScreenFadeRange( float flMinSize, float flMaxSize );
  855. // Computes fade alpha based on distance fade + screen fade
  856. virtual unsigned char ComputeLevelScreenFade( const Vector &vecAbsOrigin, float flRadius, float flFadeScale ) const;
  857. virtual unsigned char ComputeViewScreenFade( const Vector &vecAbsOrigin, float flRadius, float flFadeScale ) const;
  858. virtual void GetModelMaterialColorAndLighting( const model_t *model, const Vector& origin,
  859. const QAngle& angles, trace_t* pTrace, Vector& lighting, Vector& matColor );
  860. protected:
  861. virtual INetworkStringTable *GetDynamicModelStringTable() const;
  862. virtual int LookupPrecachedModelIndex( const char *name ) const;
  863. private:
  864. struct ScreenFadeInfo_t
  865. {
  866. float m_flMinScreenWidth;
  867. float m_flMaxScreenWidth;
  868. float m_flFalloffFactor;
  869. };
  870. // Sets/gets a map-specified fade range
  871. void SetScreenFadeRange( float flMinSize, float flMaxSize, ScreenFadeInfo_t *pFade );
  872. unsigned char ComputeScreenFade( const Vector &vecAbsOrigin, float flRadius, float flFadeScale, const ScreenFadeInfo_t &fade ) const;
  873. ScreenFadeInfo_t m_LevelFade;
  874. ScreenFadeInfo_t m_ViewFade;
  875. };
  876. INetworkStringTable *CModelInfoClient::GetDynamicModelStringTable() const
  877. {
  878. return cl.m_pDynamicModelsTable;
  879. }
  880. int CModelInfoClient::LookupPrecachedModelIndex( const char *name ) const
  881. {
  882. return cl.LookupModelIndex( name );
  883. }
  884. int CModelInfoClient::RegisterDynamicModel( const char *name, bool bClientSide )
  885. {
  886. // Clients cannot register non-client-side dynamic models!
  887. Assert( bClientSide );
  888. if ( !bClientSide )
  889. return -1;
  890. char buf[256];
  891. V_strncpy( buf, name, ARRAYSIZE(buf) );
  892. V_RemoveDotSlashes( buf, '/', true );
  893. name = buf;
  894. Assert( V_strstr( name, ".mdl" ) != NULL );
  895. // Already known? bClientSide should always be true and is asserted above.
  896. int index = GetModelClientSideIndex( name );
  897. if ( index != -1 )
  898. return index;
  899. // Lookup (or create) model_t* and register it to get a stable iterator index
  900. model_t* pModel = modelloader->GetDynamicModel( name, true );
  901. Assert( pModel );
  902. UtlHashHandle_t localidx = m_ClientDynamicModels.Insert( pModel );
  903. Assert( m_ClientDynamicModels.Count() < ((32767 >> 1) - 2) );
  904. Assert( MODEL_TO_CLIENTSIDE( (short) CLIENTSIDE_TO_MODEL( localidx ) ) == (int) localidx );
  905. return CLIENTSIDE_TO_MODEL( localidx );
  906. }
  907. const model_t *CModelInfoClient::GetModel( int modelindex )
  908. {
  909. if ( IsDynamicModelIndex( modelindex ) )
  910. return LookupDynamicModel( modelindex );
  911. return cl.GetModel( modelindex );
  912. }
  913. void CModelInfoClient::OnDynamicModelsStringTableChange( int nStringIndex, const char *pString, const void *pData )
  914. {
  915. // Do a lookup to force an immediate insertion into our local lookup tables
  916. model_t* pModel = LookupDynamicModel( NETDYNAMIC_TO_MODEL( nStringIndex ) );
  917. // Notify model loader that the server-side state may have changed
  918. bool bServerLoaded = pData ? ( *(char*)pData != 0 ) : ( g_ClientGlobalVariables.network_protocol <= PROTOCOL_VERSION_20 );
  919. modelloader->Client_OnServerModelStateChanged( pModel, bServerLoaded );
  920. }
  921. const model_t *CModelInfoClient::FindOrLoadModel( const char *name )
  922. {
  923. // find the cached model from the server or client
  924. const model_t *pModel = GetModel( GetModelIndex( name ) );
  925. if ( pModel )
  926. return pModel;
  927. // load the model
  928. return modelloader->GetModelForName( name, IModelLoader::FMODELLOADER_CLIENTDLL );
  929. }
  930. //-----------------------------------------------------------------------------
  931. // Sets/gets a map-specified fade range
  932. //-----------------------------------------------------------------------------
  933. void CModelInfoClient::SetScreenFadeRange( float flMinSize, float flMaxSize, ScreenFadeInfo_t *pFade )
  934. {
  935. pFade->m_flMinScreenWidth = flMinSize;
  936. pFade->m_flMaxScreenWidth = flMaxSize;
  937. if ( pFade->m_flMaxScreenWidth <= pFade->m_flMinScreenWidth )
  938. {
  939. pFade->m_flMaxScreenWidth = pFade->m_flMinScreenWidth;
  940. }
  941. if (pFade->m_flMaxScreenWidth != pFade->m_flMinScreenWidth)
  942. {
  943. pFade->m_flFalloffFactor = 255.0f / (pFade->m_flMaxScreenWidth - pFade->m_flMinScreenWidth);
  944. }
  945. else
  946. {
  947. pFade->m_flFalloffFactor = 255.0f;
  948. }
  949. }
  950. void CModelInfoClient::SetLevelScreenFadeRange( float flMinSize, float flMaxSize )
  951. {
  952. SetScreenFadeRange( flMinSize, flMaxSize, &m_LevelFade );
  953. }
  954. void CModelInfoClient::GetLevelScreenFadeRange( float *pMinArea, float *pMaxArea ) const
  955. {
  956. *pMinArea = m_LevelFade.m_flMinScreenWidth;
  957. *pMaxArea = m_LevelFade.m_flMaxScreenWidth;
  958. }
  959. //-----------------------------------------------------------------------------
  960. // Sets/gets a map-specified per-view fade range
  961. //-----------------------------------------------------------------------------
  962. void CModelInfoClient::SetViewScreenFadeRange( float flMinSize, float flMaxSize )
  963. {
  964. SetScreenFadeRange( flMinSize, flMaxSize, &m_ViewFade );
  965. }
  966. //-----------------------------------------------------------------------------
  967. // Computes fade alpha based on distance fade + screen fade
  968. //-----------------------------------------------------------------------------
  969. inline unsigned char CModelInfoClient::ComputeScreenFade( const Vector &vecAbsOrigin,
  970. float flRadius, float flFadeScale, const ScreenFadeInfo_t &fade ) const
  971. {
  972. if ( ( fade.m_flMinScreenWidth <= 0 ) || (flFadeScale <= 0.0f) )
  973. return 255;
  974. CMatRenderContextPtr pRenderContext( materials );
  975. float flPixelWidth = pRenderContext->ComputePixelWidthOfSphere( vecAbsOrigin, flRadius ) / flFadeScale;
  976. unsigned char alpha = 0;
  977. if ( flPixelWidth > fade.m_flMinScreenWidth )
  978. {
  979. if ( (fade.m_flMaxScreenWidth >= 0) && (flPixelWidth < fade.m_flMaxScreenWidth) )
  980. {
  981. int nAlpha = fade.m_flFalloffFactor * (flPixelWidth - fade.m_flMinScreenWidth);
  982. alpha = clamp( nAlpha, 0, 255 );
  983. }
  984. else
  985. {
  986. alpha = 255;
  987. }
  988. }
  989. return alpha;
  990. }
  991. unsigned char CModelInfoClient::ComputeLevelScreenFade( const Vector &vecAbsOrigin, float flRadius, float flFadeScale ) const
  992. {
  993. if ( IsXbox() )
  994. {
  995. return 255;
  996. }
  997. else
  998. {
  999. return ComputeScreenFade( vecAbsOrigin, flRadius, flFadeScale, m_LevelFade );
  1000. }
  1001. }
  1002. unsigned char CModelInfoClient::ComputeViewScreenFade( const Vector &vecAbsOrigin, float flRadius, float flFadeScale ) const
  1003. {
  1004. return ComputeScreenFade( vecAbsOrigin, flRadius, flFadeScale, m_ViewFade );
  1005. }
  1006. //-----------------------------------------------------------------------------
  1007. // A method to get the material color + texture coordinate
  1008. //-----------------------------------------------------------------------------
  1009. IMaterial* BrushModel_GetLightingAndMaterial( const Vector &start,
  1010. const Vector &end, Vector &diffuseLightColor, Vector &baseColor)
  1011. {
  1012. float textureS, textureT;
  1013. IMaterial *material;
  1014. // TEMP initialize these values until we can find why R_LightVec is not assigning values to them
  1015. textureS = 0;
  1016. textureT = 0;
  1017. SurfaceHandle_t surfID = R_LightVec( start, end, true, diffuseLightColor, &textureS, &textureT );
  1018. if( !IS_SURF_VALID( surfID ) || !MSurf_TexInfo( surfID ) )
  1019. {
  1020. // ConMsg( "didn't hit anything\n" );
  1021. return 0;
  1022. }
  1023. else
  1024. {
  1025. material = MSurf_TexInfo( surfID )->material;
  1026. if ( material )
  1027. {
  1028. material->GetLowResColorSample( textureS, textureT, baseColor.Base() );
  1029. // ConMsg( "%s: diff: %f %f %f base: %f %f %f\n", material->GetName(), diffuseLightColor[0], diffuseLightColor[1], diffuseLightColor[2], baseColor[0], baseColor[1], baseColor[2] );
  1030. }
  1031. else
  1032. {
  1033. baseColor.Init();
  1034. }
  1035. return material;
  1036. }
  1037. }
  1038. void CModelInfoClient::GetModelMaterialColorAndLighting( const model_t *model, const Vector & origin,
  1039. const QAngle & angles, trace_t* pTrace, Vector& lighting, Vector& matColor )
  1040. {
  1041. switch( model->type )
  1042. {
  1043. case mod_brush:
  1044. {
  1045. Vector origin_l, delta, delta_l;
  1046. VectorSubtract( pTrace->endpos, pTrace->startpos, delta );
  1047. // subtract origin offset
  1048. VectorSubtract (pTrace->startpos, origin, origin_l);
  1049. // rotate start and end into the models frame of reference
  1050. if (angles[0] || angles[1] || angles[2])
  1051. {
  1052. Vector forward, right, up;
  1053. AngleVectors (angles, &forward, &right, &up);
  1054. // transform the direction into the local space of this entity
  1055. delta_l[0] = DotProduct (delta, forward);
  1056. delta_l[1] = -DotProduct (delta, right);
  1057. delta_l[2] = DotProduct (delta, up);
  1058. }
  1059. else
  1060. {
  1061. VectorCopy( delta, delta_l );
  1062. }
  1063. Vector end_l;
  1064. VectorMA( origin_l, 1.1f, delta_l, end_l );
  1065. R_LightVecUseModel( ( model_t * )model );
  1066. BrushModel_GetLightingAndMaterial( origin_l, end_l, lighting, matColor );
  1067. R_LightVecUseModel();
  1068. return;
  1069. }
  1070. case mod_studio:
  1071. {
  1072. // FIXME: Need some way of getting the material!
  1073. matColor.Init( 0.5f, 0.5f, 0.5f );
  1074. // Get the lighting at the point
  1075. LightingState_t lightingState;
  1076. LightcacheGetDynamic_Stats stats;
  1077. LightcacheGetDynamic( pTrace->endpos, lightingState, stats, LIGHTCACHEFLAGS_STATIC|LIGHTCACHEFLAGS_DYNAMIC|LIGHTCACHEFLAGS_LIGHTSTYLE|LIGHTCACHEFLAGS_ALLOWFAST );
  1078. // Convert the light parameters into something studiorender can digest
  1079. LightDesc_t desc[MAXLOCALLIGHTS];
  1080. int count = 0;
  1081. for (int i = 0; i < lightingState.numlights; ++i)
  1082. {
  1083. if (WorldLightToMaterialLight( lightingState.locallight[i], desc[count] ))
  1084. {
  1085. ++count;
  1086. }
  1087. }
  1088. // Ask studiorender to figure out the lighting
  1089. g_pStudioRender->ComputeLighting( lightingState.r_boxcolor,
  1090. count, desc, pTrace->endpos, pTrace->plane.normal, lighting );
  1091. return;
  1092. }
  1093. }
  1094. }
  1095. static CModelInfoClient g_ModelInfoClient;
  1096. EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CModelInfoClient, IVModelInfoClient, VMODELINFO_CLIENT_INTERFACE_VERSION, g_ModelInfoClient );
  1097. // Expose IVModelInfo to the engine
  1098. IVModelInfoClient *modelinfoclient = &g_ModelInfoClient;
  1099. #endif