Counter Strike : Global Offensive Source Code
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.

1454 lines
46 KiB

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