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.

2449 lines
76 KiB

  1. //===== Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. // $Revision: $
  6. // $NoKeywords: $
  7. //
  8. // This file contains code to allow us to associate client data with bsp leaves.
  9. //
  10. //===========================================================================//
  11. #include "staticpropmgr.h"
  12. #include "convar.h"
  13. #include "vcollide_parse.h"
  14. #include "engine/ICollideable.h"
  15. #include "iclientunknown.h"
  16. #include "iclientrenderable.h"
  17. #include "gamebspfile.h"
  18. #include "engine/ivmodelrender.h"
  19. #include "engine/IClientLeafSystem.h"
  20. #include "ispatialpartitioninternal.h"
  21. #include "utlbuffer.h"
  22. #include "utlvector.h"
  23. #include "filesystem.h"
  24. #include "gl_model_private.h"
  25. #include "gl_matsysiface.h"
  26. #include "materialsystem/imaterialsystemhardwareconfig.h"
  27. #include "materialsystem/ivballoctracker.h"
  28. #include "materialsystem/imesh.h"
  29. #include "lightcache.h"
  30. #include "tier0/vprof.h"
  31. #include "render.h"
  32. #include "cmodel_engine.h"
  33. #include "datacache/imdlcache.h"
  34. #include "ModelInfo.h"
  35. #include "cdll_engine_int.h"
  36. #include "tier0/dbg.h"
  37. #include "debugoverlay.h"
  38. #include "draw.h"
  39. #include "client.h"
  40. #include "server.h"
  41. #include "l_studio.h"
  42. #include "tier0/icommandline.h"
  43. #include "sys_dll.h"
  44. #include "generichash.h"
  45. #include "tier2/renderutils.h"
  46. #include "ipooledvballocator.h"
  47. #include "tier3/tier3.h"
  48. #include "gl_cvars.h"
  49. #include "shaderapi/ishaderapi.h"
  50. #include "iclientalphaproperty.h"
  51. #include "vgui_baseui_interface.h"
  52. // memdbgon must be the last include file in a .cpp file!!!
  53. #include "tier0/memdbgon.h"
  54. //-----------------------------------------------------------------------------
  55. // Convars!
  56. //-----------------------------------------------------------------------------
  57. static ConVar r_DrawSpecificStaticProp( "r_DrawSpecificStaticProp", "-1" );
  58. static ConVar r_drawstaticprops( "r_drawstaticprops", "1", FCVAR_CHEAT, "0=Off, 1=Normal, 2=Wireframe" );
  59. extern ConVar r_slowpathwireframe;
  60. static ConVar r_colorstaticprops( "r_colorstaticprops", "0", FCVAR_CHEAT );
  61. ConVar r_staticpropinfo( "r_staticpropinfo", "0" );
  62. ConVar r_drawmodeldecals( "r_drawmodeldecals", "1" );
  63. ConVar disableStaticPropLoading( "disable_static_prop_loading", "0", FCVAR_CHEAT, "If non-zero when a map loads, static props won't be loaded" );
  64. extern ConVar mat_fullbright;
  65. static bool g_MakingDevShots = false;
  66. ConVar r_shadow_deferred( "r_shadow_deferred", "0", FCVAR_CHEAT, "Toggle deferred shadow rendering");
  67. DEFINE_LOGGING_CHANNEL_NO_TAGS( LOG_StaticPropManager, "StaticPropManager", 0, LS_ERROR );
  68. //-----------------------------------------------------------------------------
  69. // Index into the fade list
  70. //-----------------------------------------------------------------------------
  71. enum
  72. {
  73. INVALID_FADE_INDEX = (unsigned short)~0
  74. };
  75. //-----------------------------------------------------------------------------
  76. // All static props have these bits set (to differentiate them from edict indices)
  77. //-----------------------------------------------------------------------------
  78. enum
  79. {
  80. // This bit will be set in GetRefEHandle for all static props
  81. STATICPROP_EHANDLE_MASK = 0x40000000
  82. };
  83. //-----------------------------------------------------------------------------
  84. // A default physics property for non-vphysics static props
  85. //-----------------------------------------------------------------------------
  86. static const objectparams_t g_PhysDefaultObjectParams =
  87. {
  88. NULL,
  89. 1.0, //mass
  90. 1.0, // inertia
  91. 0.1f, // damping
  92. 0.1f, // rotdamping
  93. 0.05f, // rotIntertiaLimit
  94. "DEFAULT",
  95. NULL,// game data
  96. 0.f, // volume (leave 0 if you don't have one or call physcollision->CollideVolume() to compute it)
  97. 1.0f, // drag coefficient
  98. true,// enable collisions?
  99. };
  100. // return true if the renderer should use the slow path that supports the various debug modes
  101. inline bool IsUsingStaticPropDebugModes()
  102. {
  103. if ( r_drawstaticprops.GetInt() != 1 ||
  104. r_DrawSpecificStaticProp.GetInt() >= 0 ||
  105. r_colorstaticprops.GetBool() ||
  106. r_staticpropinfo.GetInt() ||
  107. mat_fullbright.GetInt() ||
  108. r_drawmodellightorigin.GetBool() ||
  109. ShouldDrawInWireFrameMode() ||
  110. r_drawmodelstatsoverlay.GetBool() )
  111. return true;
  112. return false;
  113. }
  114. //-----------------------------------------------------------------------------
  115. // A static prop
  116. //-----------------------------------------------------------------------------
  117. class CStaticProp : public IClientUnknown, public IClientRenderable, public ICollideable, public IClientModelRenderable
  118. {
  119. public:
  120. CStaticProp();
  121. ~CStaticProp();
  122. // IHandleEntity overrides
  123. public:
  124. virtual void SetRefEHandle( const CBaseHandle &handle );
  125. virtual const CBaseHandle& GetRefEHandle() const;
  126. // IClientUnknown overrides.
  127. public:
  128. virtual IClientUnknown* GetIClientUnknown() { return this; }
  129. virtual ICollideable* GetCollideable() { return this; }
  130. virtual IClientNetworkable* GetClientNetworkable() { return NULL; }
  131. virtual IClientRenderable* GetClientRenderable() { return this; }
  132. virtual IClientEntity* GetIClientEntity() { return NULL; }
  133. virtual C_BaseEntity* GetBaseEntity() { return NULL; }
  134. virtual IClientThinkable* GetClientThinkable() { return NULL; }
  135. virtual IClientAlphaProperty* GetClientAlphaProperty() { return m_pClientAlphaProperty; }
  136. public:
  137. // These methods return a box defined in the space of the entity
  138. virtual const Vector& OBBMins( ) const;
  139. virtual const Vector& OBBMaxs( ) const;
  140. // custom collision test
  141. virtual bool TestCollision( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr );
  142. // Perform hitbox test, returns true *if hitboxes were tested at all*!!
  143. virtual bool TestHitboxes( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr );
  144. // Returns the BRUSH model index if this is a brush model. Otherwise, returns -1.
  145. virtual int GetCollisionModelIndex();
  146. // Return the model, if it's a studio model.
  147. virtual const model_t* GetCollisionModel();
  148. // Get angles and origin.
  149. virtual const Vector& GetCollisionOrigin() const;
  150. virtual const QAngle& GetCollisionAngles() const;
  151. virtual const matrix3x4_t& CollisionToWorldTransform() const;
  152. // Return a SOLID_ define.
  153. virtual SolidType_t GetSolid() const;
  154. virtual int GetSolidFlags() const;
  155. // Gets at the entity handle associated with the collideable
  156. virtual IHandleEntity *GetEntityHandle() { return this; }
  157. virtual int GetCollisionGroup() const { return COLLISION_GROUP_NONE; }
  158. virtual void WorldSpaceTriggerBounds( Vector* pVecWorldMins, Vector *pVecWorldMaxs ) const;
  159. virtual void WorldSpaceSurroundingBounds( Vector* pVecWorldMins, Vector *pVecWorldMaxs );
  160. virtual uint GetRequiredTriggerFlags() const { return 0; }
  161. virtual const matrix3x4_t *GetRootParentToWorldTransform() const { return NULL; }
  162. virtual IPhysicsObject *GetVPhysicsObject() const { return NULL; }
  163. // IClientRenderable overrides.
  164. public:
  165. virtual int GetBody() { return 0; }
  166. virtual int GetSkin() { return m_Skin; }
  167. virtual const Vector& GetRenderOrigin( );
  168. virtual const QAngle& GetRenderAngles( );
  169. virtual bool ShouldDraw();
  170. virtual uint8 OverrideAlphaModulation( uint8 nAlpha ) { return nAlpha; }
  171. virtual uint8 OverrideShadowAlphaModulation( uint8 nAlpha ) { return nAlpha; }
  172. virtual void OnThreadedDrawSetup() {}
  173. virtual const model_t* GetModel( ) const;
  174. virtual int DrawModel( int flags, const RenderableInstance_t &instance );
  175. virtual void GetColorModulation( float* color );
  176. virtual bool LODTest() { return true; } // NOTE: UNUSED
  177. virtual bool SetupBones( matrix3x4a_t *pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime );
  178. virtual void SetupWeights( const matrix3x4_t *pBoneToWorld, int nFlexWeightCount, float *pFlexWeights, float *pFlexDelayedWeights );
  179. virtual bool UsesFlexDelayedWeights() { return false; }
  180. virtual void DoAnimationEvents( void );
  181. virtual IPVSNotify* GetPVSNotifyInterface();
  182. virtual void GetRenderBounds( Vector& mins, Vector& maxs );
  183. virtual void GetRenderBoundsWorldspace( Vector& mins, Vector& maxs );
  184. virtual bool ShouldCacheRenderInfo();
  185. virtual bool ShouldReceiveProjectedTextures( int flags );
  186. virtual bool GetShadowCastDistance( float *pDist, ShadowType_t shadowType ) const { return false; }
  187. virtual bool GetShadowCastDirection( Vector *pDirection, ShadowType_t shadowType ) const { return false; }
  188. virtual int GetRenderFlags( void );
  189. virtual ClientShadowHandle_t GetShadowHandle() const { return CLIENTSHADOW_INVALID_HANDLE; }
  190. virtual ClientRenderHandle_t& RenderHandle();
  191. virtual void RecordToolMessage() {}
  192. virtual bool ShouldDrawForSplitScreenUser( int nSlot ) { return true; }
  193. // These normally call through to GetRenderAngles/GetRenderBounds, but some entities custom implement them.
  194. virtual void GetShadowRenderBounds( Vector &mins, Vector &maxs, ShadowType_t shadowType )
  195. {
  196. GetRenderBounds( mins, maxs );
  197. }
  198. // Other methods related to shadow rendering
  199. virtual bool IsShadowDirty( ) { return false; }
  200. virtual void MarkShadowDirty( bool bDirty ) {}
  201. // Iteration over shadow hierarchy
  202. virtual IClientRenderable *GetShadowParent() { return NULL; }
  203. virtual IClientRenderable *FirstShadowChild() { return NULL; }
  204. virtual IClientRenderable *NextShadowPeer() { return NULL; }
  205. // Returns the shadow cast type
  206. virtual ShadowType_t ShadowCastType() { return SHADOWS_NONE; }
  207. // Create/get/destroy model instance
  208. virtual void CreateModelInstance() { Assert(0); }
  209. virtual ModelInstanceHandle_t GetModelInstance();
  210. // Attachments
  211. virtual int LookupAttachment( const char *pAttachmentName ) { return -1; }
  212. virtual bool GetAttachment( int number, Vector &origin, QAngle &angles );
  213. virtual bool GetAttachment( int number, matrix3x4_t &matrix );
  214. virtual bool ComputeLightingOrigin( int nAttachmentIndex, Vector modelLightingCenter, const matrix3x4_t &matrix, Vector &transformedLightingCenter );
  215. // Rendering clip plane, should be 4 floats, return value of NULL indicates a disabled render clip plane
  216. virtual float *GetRenderClipPlane( void ) { return NULL; }
  217. // Returns the transform from RenderOrigin/RenderAngles to world
  218. virtual const matrix3x4_t &RenderableToWorldTransform()
  219. {
  220. return m_ModelToWorld;
  221. }
  222. virtual IClientModelRenderable* GetClientModelRenderable();
  223. // IClientModelRenderable overrides
  224. public:
  225. virtual bool GetRenderData( void *pData, ModelDataCategory_t nCategory );
  226. public:
  227. bool Init( int index, StaticPropLump_t &lump, model_t *pModel );
  228. // KD Tree
  229. void InsertPropIntoKDTree();
  230. void RemovePropFromKDTree();
  231. void PrecacheLighting();
  232. void RecomputeStaticLighting();
  233. int LeafCount() const;
  234. int FirstLeaf() const;
  235. LightCacheHandle_t GetLightCacheHandle() const;
  236. void SetModelInstance( ModelInstanceHandle_t handle );
  237. void SetRenderHandle( ClientRenderHandle_t handle );
  238. void CleanUpRenderHandle( );
  239. ClientRenderHandle_t GetRenderHandle() const;
  240. void CleanUpAlphaProperty();
  241. // Create VPhysics representation
  242. void CreateVPhysics( IPhysicsEnvironment *physenv, IVPhysicsKeyHandler *pDefaults, void *pGameData );
  243. float Radius() const { return m_flRadius; }
  244. int Flags() const { return m_Flags; }
  245. int FlagsEx() const { return m_FlagsEx; }
  246. void DisableCSMRendering( void ) { m_FlagsEx |= STATIC_PROP_FLAGS_EX_DISABLE_CSM; }
  247. int DrawModelSlow( int flags, const RenderableInstance_t &instance );
  248. private:
  249. // Diagnostic information for static props
  250. void DisplayStaticPropInfo( int nInfoType );
  251. inline void InitModelRenderInfo( ModelRenderInfo_t &sInfo, int flags )
  252. {
  253. sInfo.origin = m_Origin;
  254. sInfo.angles = m_Angles;
  255. sInfo.pRenderable = this;
  256. sInfo.pModel = m_pModel;
  257. sInfo.pModelToWorld = &m_ModelToWorld;
  258. sInfo.pLightingOffset = NULL;
  259. sInfo.pLightingOrigin = &m_LightingOrigin;
  260. sInfo.flags = flags;
  261. sInfo.entity_index = -1;
  262. sInfo.skin = m_Skin;
  263. sInfo.body = 0;
  264. sInfo.hitboxset = 0;
  265. sInfo.instance = m_ModelInstance;
  266. }
  267. private:
  268. friend class CStaticPropMgr;
  269. Vector m_Origin;
  270. QAngle m_Angles;
  271. model_t* m_pModel;
  272. SpatialPartitionHandle_t m_Partition;
  273. ModelInstanceHandle_t m_ModelInstance;
  274. unsigned char m_Alpha;
  275. unsigned char m_nSolidType;
  276. unsigned char m_Skin;
  277. unsigned char m_Flags;
  278. unsigned int m_FlagsEx;
  279. unsigned char m_nMinCPULevel;
  280. unsigned char m_nMaxCPULevel;
  281. unsigned char m_nMinGPULevel;
  282. unsigned char m_nMaxGPULevel;
  283. unsigned short m_FirstLeaf;
  284. unsigned short m_LeafCount;
  285. CBaseHandle m_EntHandle; // FIXME: Do I need client + server handles?
  286. ClientRenderHandle_t m_RenderHandle;
  287. unsigned short m_nReserved;
  288. IClientAlphaProperty* m_pClientAlphaProperty;
  289. // bbox is the same for both GetBounds and GetRenderBounds since static props never move.
  290. // GetRenderBounds is interpolated data, and GetBounds is last networked.
  291. Vector m_RenderBBoxMin;
  292. Vector m_RenderBBoxMax;
  293. matrix3x4_t m_ModelToWorld;
  294. float m_flRadius;
  295. Vector m_WorldRenderBBoxMin;
  296. Vector m_WorldRenderBBoxMax;
  297. // FIXME: This sucks. Need to store the lighting origin off
  298. // because the time at which the static props are unserialized
  299. // doesn't necessarily match the time at which we can initialize the light cache
  300. Vector m_LightingOrigin;
  301. Vector4D m_DiffuseModulation;
  302. };
  303. //-----------------------------------------------------------------------------
  304. // The engine's static prop manager
  305. //-----------------------------------------------------------------------------
  306. class CStaticPropMgr : public IStaticPropMgrEngine, public IStaticPropMgrClient, public IStaticPropMgrServer
  307. {
  308. public:
  309. // constructor, destructor
  310. CStaticPropMgr();
  311. virtual ~CStaticPropMgr();
  312. // methods of IStaticPropMgrEngine
  313. virtual bool Init();
  314. virtual void Shutdown();
  315. virtual void LevelInit();
  316. virtual void LevelInitClient();
  317. virtual void LevelShutdown();
  318. virtual void LevelShutdownClient();
  319. virtual bool IsPropInPVS( IHandleEntity *pHandleEntity, const byte *pVis ) const;
  320. virtual void DisableCSMRenderingForStaticProp( int staticPropIndex );
  321. virtual ICollideable *GetStaticProp( IHandleEntity *pHandleEntity );
  322. virtual void RecomputeStaticLighting( );
  323. virtual LightCacheHandle_t GetLightCacheHandleForStaticProp( IHandleEntity *pHandleEntity );
  324. inline bool IsStaticProp_Inline( IHandleEntity *pHandleEntity ) const
  325. {
  326. #if defined( _GAMECONSOLE )
  327. return (!pHandleEntity) || pHandleEntity->m_bIsStaticProp;
  328. #else
  329. return (!pHandleEntity) || ( (pHandleEntity->GetRefEHandle().GetSerialNumber() == (STATICPROP_EHANDLE_MASK >> NUM_SERIAL_NUM_SHIFT_BITS) ) != 0 );
  330. #endif
  331. }
  332. virtual bool IsStaticProp( IHandleEntity *pHandleEntity ) const;
  333. virtual bool IsStaticProp( CBaseHandle handle ) const;
  334. virtual int GetStaticPropIndex( IHandleEntity *pHandleEntity ) const;
  335. virtual ICollideable *GetStaticPropByIndex( int propIndex );
  336. // methods of IStaticPropMgrClient
  337. virtual void TraceRayAgainstStaticProp( const Ray_t& ray, int staticPropIndex, trace_t& tr );
  338. virtual void AddDecalToStaticProp( Vector const& rayStart, Vector const& rayEnd,
  339. int staticPropIndex, int decalIndex, bool doTrace, trace_t& tr, void *pvProxyUserData = NULL, const Vector* saxis = NULL, int32 nAdditionalDecalFlags = 0 ) OVERRIDE;
  340. virtual void AddShadowToStaticProp( unsigned short shadowHandle, IClientRenderable* pRenderable );
  341. virtual void RemoveAllShadowsFromStaticProp( IClientRenderable* pRenderable );
  342. virtual void GetStaticPropMaterialColorAndLighting( trace_t* pTrace,
  343. int staticPropIndex, Vector& lighting, Vector& matColor );
  344. virtual void CreateVPhysicsRepresentations( IPhysicsEnvironment *physenv, IVPhysicsKeyHandler *pDefaults, void *pGameData );
  345. // methods of IStaticPropMgrServer
  346. //Changes made specifically to support the Portal mod (smack Dave Kircher if something breaks)
  347. //===================================================================
  348. virtual void GetAllStaticProps( CUtlVector<ICollideable *> *pOutput );
  349. virtual void GetAllStaticPropsInAABB( const Vector &vMins, const Vector &vMaxs, CUtlVector<ICollideable *> *pOutput );
  350. virtual void GetAllStaticPropsInOBB( const Vector &ptOrigin, const Vector &vExtent1, const Vector &vExtent2, const Vector &vExtent3, CUtlVector<ICollideable *> *pOutput );
  351. //===================================================================
  352. virtual void GetLightingOrigins( Vector *pLightingOrigins, int nOriginStride, int nCount, IClientRenderable **ppRenderable, int nRenderableStride );
  353. virtual void ConfigureSystemLevel( int nCPULevel, int nGPULevel );
  354. virtual void RestoreStaticProps();
  355. // Internal methods
  356. const Vector &ViewOrigin() const { return m_vecLastViewOrigin; }
  357. // Computes the opacity for a single static prop
  358. void DrawStaticProps( IClientRenderable **pProps, const RenderableInstance_t *pInstances, int count, bool bShadowDepth, bool drawVCollideWireframe );
  359. void DrawStaticProps_Slow( IClientRenderable **pProps, const RenderableInstance_t *pInstances, int count, bool bShadowDepth, bool drawVCollideWireframe );
  360. void DrawStaticProps_Fast( IClientRenderable **pProps, const RenderableInstance_t *pInstances, int count, bool bShadowDepth );
  361. void DrawStaticProps_FastPipeline( IClientRenderable **pProps, const RenderableInstance_t *pInstances, int count, bool bShadowDepth );
  362. private:
  363. void OutputLevelStats( void );
  364. void PrecacheLighting();
  365. void UpdatePropVisibility( int nCPULevel, int nGPULevel );
  366. // Methods associated with unserializing static props
  367. void UnserializeModelDict( CUtlBuffer& buf );
  368. void UnserializeLeafList( CUtlBuffer& buf );
  369. void UnserializeModels( CUtlBuffer& buf );
  370. void UnserializeStaticProps();
  371. int HandleEntityToIndex( IHandleEntity *pHandleEntity ) const;
  372. private:
  373. // Unique static prop models
  374. // The list of all static props
  375. CUtlVector <model_t *> m_StaticPropDict;
  376. CUtlVector <CStaticProp> m_StaticProps;
  377. CUtlVector <StaticPropLeafLump_t> m_StaticPropLeaves;
  378. bool m_bLevelInitialized;
  379. bool m_bClientInitialized;
  380. Vector m_vecLastViewOrigin;
  381. float m_flLastViewFactor;
  382. int m_nLastCPULevel;
  383. int m_nLastGPULevel;
  384. };
  385. //-----------------------------------------------------------------------------
  386. // Expose Interface to the game + client DLLs.
  387. //-----------------------------------------------------------------------------
  388. static CStaticPropMgr s_StaticPropMgr;
  389. EXPOSE_SINGLE_INTERFACE_GLOBALVAR(CStaticPropMgr, IStaticPropMgrClient, INTERFACEVERSION_STATICPROPMGR_CLIENT, s_StaticPropMgr);
  390. EXPOSE_SINGLE_INTERFACE_GLOBALVAR(CStaticPropMgr, IStaticPropMgrServer, INTERFACEVERSION_STATICPROPMGR_SERVER, s_StaticPropMgr);
  391. //-----------------------------------------------------------------------------
  392. //
  393. // Static prop
  394. //
  395. //-----------------------------------------------------------------------------
  396. CStaticProp::CStaticProp() : m_pModel(0), m_Alpha(255)
  397. {
  398. #ifdef _GAMECONSOLE
  399. m_bIsStaticProp = true;
  400. #endif
  401. m_ModelInstance = MODEL_INSTANCE_INVALID;
  402. m_Partition = PARTITION_INVALID_HANDLE;
  403. m_EntHandle = INVALID_EHANDLE;
  404. m_RenderHandle = INVALID_CLIENT_RENDER_HANDLE;
  405. m_pClientAlphaProperty = NULL;
  406. }
  407. CStaticProp::~CStaticProp()
  408. {
  409. CleanUpAlphaProperty();
  410. RemovePropFromKDTree( );
  411. if (m_ModelInstance != MODEL_INSTANCE_INVALID)
  412. {
  413. modelrender->DestroyInstance( m_ModelInstance );
  414. }
  415. }
  416. //-----------------------------------------------------------------------------
  417. // Initialization
  418. //-----------------------------------------------------------------------------
  419. bool CStaticProp::Init( int index, StaticPropLump_t &lump, model_t *pModel )
  420. {
  421. m_EntHandle.Init(index, STATICPROP_EHANDLE_MASK >> NUM_SERIAL_NUM_SHIFT_BITS);
  422. m_Partition = PARTITION_INVALID_HANDLE;
  423. VectorCopy( lump.m_Origin, m_Origin );
  424. VectorCopy( lump.m_Angles, m_Angles );
  425. m_pModel = pModel;
  426. m_FirstLeaf = lump.m_FirstLeaf;
  427. m_LeafCount = lump.m_LeafCount;
  428. m_nSolidType = lump.m_Solid;
  429. m_DiffuseModulation[0] = lump.m_DiffuseModulation.r * ( 1.0f / 255.0f );
  430. m_DiffuseModulation[1] = lump.m_DiffuseModulation.g * ( 1.0f / 255.0f );
  431. m_DiffuseModulation[2] = lump.m_DiffuseModulation.b * ( 1.0f / 255.0f );
  432. m_DiffuseModulation[3] = lump.m_DiffuseModulation.a * ( 1.0f / 255.0f );
  433. MDLCACHE_CRITICAL_SECTION_( g_pMDLCache );
  434. studiohdr_t *pStudioHdr = modelinfo->GetStudiomodel( m_pModel );
  435. if ( pStudioHdr )
  436. {
  437. if ( !( pStudioHdr->flags & STUDIOHDR_FLAGS_STATIC_PROP ) )
  438. {
  439. static int nBitchCount = 0;
  440. if( nBitchCount < 100 )
  441. {
  442. Log_Warning( LOG_StaticPropManager, "model %s used as a static prop, but not compiled as a static prop\n", pStudioHdr->pszName() );
  443. nBitchCount++;
  444. }
  445. }
  446. }
  447. #ifndef DEDICATED
  448. // Initialize the alpha property
  449. if ( !sv.IsDedicated() )
  450. {
  451. CleanUpAlphaProperty();
  452. m_pClientAlphaProperty = g_pClientAlphaPropertyMgr->CreateClientAlphaProperty( this );
  453. m_pClientAlphaProperty->SetAlphaModulation( lump.m_DiffuseModulation.a );
  454. m_pClientAlphaProperty->SetDesyncOffset( index );
  455. m_pClientAlphaProperty->SetRenderFX( kRenderFxNone, kRenderTransTexture );
  456. float flForcedFadeScale = lump.m_flForcedFadeScale;
  457. if ( pStudioHdr->flags & STUDIOHDR_FLAGS_NO_FORCED_FADE )
  458. {
  459. flForcedFadeScale = 0.0f;
  460. }
  461. m_pClientAlphaProperty->SetFade( flForcedFadeScale, 0.0f, 0.0f );
  462. if ( lump.m_Flags & STATIC_PROP_FLAG_FADES )
  463. {
  464. m_pClientAlphaProperty->SetFade( flForcedFadeScale, lump.m_FadeMinDist, lump.m_FadeMaxDist );
  465. }
  466. }
  467. #endif
  468. switch ( m_nSolidType )
  469. {
  470. // These are valid
  471. case SOLID_VPHYSICS:
  472. case SOLID_BBOX:
  473. case SOLID_NONE:
  474. break;
  475. default:
  476. {
  477. char szModel[MAX_PATH];
  478. Q_strncpy( szModel, m_pModel ? modelloader->GetName( m_pModel ) : "unknown model", sizeof( szModel ) );
  479. Log_Warning( LOG_StaticPropManager, "CStaticProp::Init: Map error, static_prop with bogus SOLID_ flag (%d)! (%s)\n", m_nSolidType, szModel );
  480. m_nSolidType = SOLID_NONE;
  481. }
  482. break;
  483. }
  484. m_Alpha = 255;
  485. m_Skin = (unsigned char)lump.m_Skin;
  486. m_Flags = ( lump.m_Flags & ( STATIC_PROP_MARKED_FOR_FAST_REFLECTION | STATIC_PROP_NO_FLASHLIGHT | STATIC_PROP_NO_PER_VERTEX_LIGHTING ) );
  487. m_FlagsEx = (unsigned int)lump.m_FlagsEx;
  488. m_nMinCPULevel = lump.m_nMinCPULevel;
  489. m_nMaxCPULevel = lump.m_nMaxCPULevel;
  490. m_nMinGPULevel = lump.m_nMinGPULevel;
  491. m_nMaxGPULevel = lump.m_nMaxGPULevel;
  492. // Cache the model to world matrix since it never changes.
  493. AngleMatrix( lump.m_Angles, lump.m_Origin, m_ModelToWorld );
  494. // Cache the collision bounding box since it'll never change.
  495. modelinfo->GetModelRenderBounds( m_pModel, m_RenderBBoxMin, m_RenderBBoxMax );
  496. m_flRadius = m_RenderBBoxMin.DistTo( m_RenderBBoxMax ) * 0.5f;
  497. TransformAABB( m_ModelToWorld, m_RenderBBoxMin, m_RenderBBoxMax, m_WorldRenderBBoxMin, m_WorldRenderBBoxMax );
  498. // FIXME: Sucky, but unless we want to re-read the static prop lump when the client is
  499. // initialized (possible, but also gross), we need to cache off the illum center now
  500. if (lump.m_Flags & STATIC_PROP_USE_LIGHTING_ORIGIN)
  501. {
  502. m_LightingOrigin = lump.m_LightingOrigin;
  503. }
  504. else
  505. {
  506. modelinfo->GetIlluminationPoint( m_pModel, this, m_Origin, m_Angles, &m_LightingOrigin );
  507. }
  508. g_MakingDevShots = CommandLine()->FindParm( "-makedevshots" ) ? true : false;
  509. return true;
  510. }
  511. //-----------------------------------------------------------------------------
  512. // EHandle
  513. //-----------------------------------------------------------------------------
  514. void CStaticProp::SetRefEHandle( const CBaseHandle &handle )
  515. {
  516. // Only the static prop mgr should be setting this...
  517. Assert( 0 );
  518. }
  519. const CBaseHandle& CStaticProp::GetRefEHandle() const
  520. {
  521. return m_EntHandle;
  522. }
  523. //-----------------------------------------------------------------------------
  524. // These methods return a box defined in the space of the entity
  525. //-----------------------------------------------------------------------------
  526. const Vector& CStaticProp::OBBMins( ) const
  527. {
  528. if ( GetSolid() == SOLID_VPHYSICS )
  529. {
  530. return m_pModel->mins;
  531. }
  532. Vector& tv = AllocTempVector();
  533. // FIXME: why doesn't this just return m_RenderBBoxMin?
  534. VectorSubtract( m_WorldRenderBBoxMin, GetCollisionOrigin(), tv );
  535. return tv;
  536. }
  537. const Vector& CStaticProp::OBBMaxs( ) const
  538. {
  539. if ( GetSolid() == SOLID_VPHYSICS )
  540. {
  541. return m_pModel->maxs;
  542. }
  543. Vector& tv = AllocTempVector();
  544. // FIXME: why doesn't this just return m_RenderBBoxMax?
  545. VectorSubtract( m_WorldRenderBBoxMax, GetCollisionOrigin(), tv );
  546. return tv;
  547. }
  548. void CStaticProp::WorldSpaceTriggerBounds( Vector* pVecWorldMins, Vector *pVecWorldMaxs ) const
  549. {
  550. // This should never be called..
  551. Assert(0);
  552. }
  553. //-----------------------------------------------------------------------------
  554. // Surrounding box
  555. //-----------------------------------------------------------------------------
  556. void CStaticProp::WorldSpaceSurroundingBounds( Vector* pVecWorldMins, Vector *pVecWorldMaxs )
  557. {
  558. *pVecWorldMins = m_WorldRenderBBoxMin;
  559. *pVecWorldMaxs = m_WorldRenderBBoxMax;
  560. }
  561. //-----------------------------------------------------------------------------
  562. // Data accessors
  563. //-----------------------------------------------------------------------------
  564. const Vector& CStaticProp::GetRenderOrigin( void )
  565. {
  566. return m_Origin;
  567. }
  568. const QAngle& CStaticProp::GetRenderAngles( void )
  569. {
  570. return m_Angles;
  571. }
  572. bool CStaticProp::GetAttachment( int number, Vector &origin, QAngle &angles )
  573. {
  574. origin = m_Origin;
  575. angles = m_Angles;
  576. return true;
  577. }
  578. bool CStaticProp::GetAttachment( int number, matrix3x4_t &matrix )
  579. {
  580. MatrixCopy( RenderableToWorldTransform(), matrix );
  581. return true;
  582. }
  583. bool CStaticProp::ComputeLightingOrigin( int nAttachmentIndex, Vector modelLightingCenter, const matrix3x4_t &matrix, Vector &transformedLightingCenter )
  584. {
  585. if ( nAttachmentIndex <= 0 )
  586. {
  587. VectorTransform( modelLightingCenter, matrix, transformedLightingCenter );
  588. }
  589. else
  590. {
  591. matrix3x4_t attachmentTransform;
  592. GetAttachment( nAttachmentIndex, attachmentTransform );
  593. VectorTransform( modelLightingCenter, attachmentTransform, transformedLightingCenter );
  594. }
  595. return true;
  596. }
  597. bool CStaticProp::ShouldDraw()
  598. {
  599. return ( m_RenderHandle != INVALID_CLIENT_RENDER_HANDLE );
  600. }
  601. //-----------------------------------------------------------------------------
  602. // Render setup
  603. //-----------------------------------------------------------------------------
  604. bool CStaticProp::SetupBones( matrix3x4a_t *pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime )
  605. {
  606. if (!m_pModel)
  607. return false;
  608. MatrixCopy( m_ModelToWorld, pBoneToWorldOut[0] );
  609. return true;
  610. }
  611. void CStaticProp::SetupWeights( const matrix3x4_t *pBoneToWorld, int nFlexWeightCount, float *pFlexWeights, float *pFlexDelayedWeights )
  612. {
  613. }
  614. void CStaticProp::DoAnimationEvents( void )
  615. {
  616. }
  617. //-----------------------------------------------------------------------------
  618. // Render baby!
  619. //-----------------------------------------------------------------------------
  620. const model_t* CStaticProp::GetModel( ) const
  621. {
  622. return m_pModel;
  623. }
  624. //----------------------------------------------------------------------------
  625. // Hooks into the fast path render system
  626. //----------------------------------------------------------------------------
  627. IClientModelRenderable* CStaticProp::GetClientModelRenderable()
  628. {
  629. // FIXME: Can I cache off ModelHasMaterialProxy?
  630. // Don't bother using fast path if proxies are happening
  631. #ifndef DEDICATED
  632. if ( !m_pModel || modelinfoclient->ModelHasMaterialProxy( m_pModel ) )
  633. return NULL;
  634. #endif
  635. if ( IsUsingStaticPropDebugModes() )
  636. return NULL;
  637. return this;
  638. }
  639. bool CStaticProp::GetRenderData( void *pData, ModelDataCategory_t nCategory )
  640. {
  641. switch ( nCategory )
  642. {
  643. case MODEL_DATA_LIGHTING_MODEL:
  644. *(RenderableLightingModel_t*)pData = LIGHTING_MODEL_STATIC_PROP;
  645. return true;
  646. #if defined( _X360 )
  647. // Deferred shadow rendering:
  648. case MODEL_DATA_STENCIL:
  649. {
  650. if ( r_shadow_deferred.GetBool() )
  651. {
  652. // clear stencil and hi-stencil because static props don't cast shadows
  653. ShaderStencilState_t* pStencilState = reinterpret_cast<ShaderStencilState_t*>( pData );
  654. uint32 mask = 1 << 2;
  655. uint32 nRef = 0;
  656. pStencilState->m_bEnable = true;
  657. pStencilState->m_nTestMask = 0xFFFFFFFF;
  658. pStencilState->m_nWriteMask = mask;
  659. pStencilState->m_nReferenceValue = nRef;
  660. pStencilState->m_CompareFunc = SHADER_STENCILFUNC_ALWAYS;
  661. pStencilState->m_PassOp = SHADER_STENCILOP_SET_TO_REFERENCE;
  662. pStencilState->m_FailOp = SHADER_STENCILOP_KEEP;
  663. pStencilState->m_ZFailOp = SHADER_STENCILOP_KEEP;//SHADER_STENCILOP_SET_TO_REFERENCE;
  664. pStencilState->m_bHiStencilEnable = false;
  665. pStencilState->m_bHiStencilWriteEnable = true;
  666. pStencilState->m_HiStencilCompareFunc = SHADER_HI_STENCILFUNC_NOTEQUAL;
  667. pStencilState->m_nHiStencilReferenceValue = 0;
  668. return true;
  669. }
  670. }
  671. return false;
  672. #endif
  673. default:
  674. return false;
  675. }
  676. }
  677. //-----------------------------------------------------------------------------
  678. // Accessors
  679. //-----------------------------------------------------------------------------
  680. inline int CStaticProp::LeafCount() const
  681. {
  682. return m_LeafCount;
  683. }
  684. inline int CStaticProp::FirstLeaf() const
  685. {
  686. return m_FirstLeaf;
  687. }
  688. inline ModelInstanceHandle_t CStaticProp::GetModelInstance()
  689. {
  690. return m_ModelInstance;
  691. }
  692. inline void CStaticProp::SetModelInstance( ModelInstanceHandle_t handle )
  693. {
  694. m_ModelInstance = handle;
  695. }
  696. inline void CStaticProp::SetRenderHandle( ClientRenderHandle_t handle )
  697. {
  698. m_RenderHandle = handle;
  699. }
  700. inline ClientRenderHandle_t CStaticProp::GetRenderHandle() const
  701. {
  702. return m_RenderHandle;
  703. }
  704. void CStaticProp::CleanUpRenderHandle( )
  705. {
  706. if ( m_RenderHandle != INVALID_CLIENT_RENDER_HANDLE )
  707. {
  708. #ifndef DEDICATED
  709. clientleafsystem->RemoveRenderable( m_RenderHandle );
  710. #endif
  711. m_RenderHandle = INVALID_CLIENT_RENDER_HANDLE;
  712. }
  713. }
  714. void CStaticProp::CleanUpAlphaProperty()
  715. {
  716. if ( m_pClientAlphaProperty )
  717. {
  718. #ifndef DEDICATED
  719. g_pClientAlphaPropertyMgr->DestroyClientAlphaProperty( m_pClientAlphaProperty );
  720. #endif
  721. m_pClientAlphaProperty = NULL;
  722. }
  723. }
  724. //-----------------------------------------------------------------------------
  725. // Determine alpha and blend amount for transparent objects based on render state info
  726. //-----------------------------------------------------------------------------
  727. void CStaticProp::GetColorModulation( float* color )
  728. {
  729. memcpy( color, m_DiffuseModulation.Base(), sizeof( float ) * 3 );
  730. }
  731. //-----------------------------------------------------------------------------
  732. // custom collision test
  733. //-----------------------------------------------------------------------------
  734. bool CStaticProp::TestCollision( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr )
  735. {
  736. Assert(0);
  737. return false;
  738. }
  739. //-----------------------------------------------------------------------------
  740. // Perform hitbox test, returns true *if hitboxes were tested at all*!!
  741. //-----------------------------------------------------------------------------
  742. bool CStaticProp::TestHitboxes( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr )
  743. {
  744. return false;
  745. }
  746. //-----------------------------------------------------------------------------
  747. // Returns the BRUSH model index if this is a brush model. Otherwise, returns -1.
  748. //-----------------------------------------------------------------------------
  749. int CStaticProp::GetCollisionModelIndex()
  750. {
  751. return -1;
  752. }
  753. //-----------------------------------------------------------------------------
  754. // Return the model, if it's a studio model.
  755. //-----------------------------------------------------------------------------
  756. const model_t* CStaticProp::GetCollisionModel()
  757. {
  758. return m_pModel;
  759. }
  760. //-----------------------------------------------------------------------------
  761. // Get angles and origin.
  762. //-----------------------------------------------------------------------------
  763. const Vector& CStaticProp::GetCollisionOrigin() const
  764. {
  765. return m_Origin;
  766. }
  767. const QAngle& CStaticProp::GetCollisionAngles() const
  768. {
  769. if ( GetSolid() == SOLID_VPHYSICS )
  770. {
  771. return m_Angles;
  772. }
  773. return vec3_angle;
  774. }
  775. const matrix3x4_t& CStaticProp::CollisionToWorldTransform() const
  776. {
  777. return m_ModelToWorld;
  778. }
  779. //-----------------------------------------------------------------------------
  780. // Return a SOLID_ define.
  781. //-----------------------------------------------------------------------------
  782. SolidType_t CStaticProp::GetSolid() const
  783. {
  784. return (SolidType_t)m_nSolidType;
  785. }
  786. int CStaticProp::GetSolidFlags() const
  787. {
  788. return 0;
  789. }
  790. int CStaticProp::GetRenderFlags( void )
  791. {
  792. int nRet = 0;
  793. if ( m_pModel )
  794. {
  795. if ( m_pModel->flags & MODELFLAG_STUDIOHDR_USES_FB_TEXTURE )
  796. {
  797. nRet |= ERENDERFLAGS_NEEDS_POWER_OF_TWO_FB;
  798. }
  799. }
  800. return nRet;
  801. }
  802. ClientRenderHandle_t& CStaticProp::RenderHandle()
  803. {
  804. return m_RenderHandle;
  805. }
  806. IPVSNotify* CStaticProp::GetPVSNotifyInterface()
  807. {
  808. return NULL;
  809. }
  810. void CStaticProp::GetRenderBounds( Vector& mins, Vector& maxs )
  811. {
  812. mins = m_RenderBBoxMin;
  813. maxs = m_RenderBBoxMax;
  814. }
  815. void CStaticProp::GetRenderBoundsWorldspace( Vector& mins, Vector& maxs )
  816. {
  817. mins = m_WorldRenderBBoxMin;
  818. maxs = m_WorldRenderBBoxMax;
  819. }
  820. bool CStaticProp::ShouldReceiveProjectedTextures( int flags )
  821. {
  822. if ( m_Flags & STATIC_PROP_NO_FLASHLIGHT )
  823. return false;
  824. if( flags & ( SHADOW_FLAGS_FLASHLIGHT | SHADOW_FLAGS_SIMPLE_PROJECTION ) )
  825. {
  826. return true;
  827. }
  828. else
  829. {
  830. return false;
  831. }
  832. }
  833. bool CStaticProp::ShouldCacheRenderInfo()
  834. {
  835. return true;
  836. }
  837. void CStaticProp::PrecacheLighting()
  838. {
  839. #ifndef DEDICATED
  840. if ( m_ModelInstance == MODEL_INSTANCE_INVALID )
  841. {
  842. LightCacheHandle_t lightCacheHandle = CreateStaticLightingCache( m_LightingOrigin, m_WorldRenderBBoxMin, m_WorldRenderBBoxMax );
  843. m_ModelInstance = modelrender->CreateInstance( this, &lightCacheHandle );
  844. }
  845. #endif
  846. }
  847. void CStaticProp::RecomputeStaticLighting( void )
  848. {
  849. #ifndef DEDICATED
  850. modelrender->RecomputeStaticLighting( m_ModelInstance );
  851. #endif
  852. }
  853. //-----------------------------------------------------------------------------
  854. // Diagnostic information for static props
  855. //-----------------------------------------------------------------------------
  856. void CStaticProp::DisplayStaticPropInfo( int nInfoType )
  857. {
  858. #ifndef DEDICATED
  859. char buf[512];
  860. switch( nInfoType )
  861. {
  862. case 1:
  863. Q_snprintf( buf, sizeof( buf ), "%s", modelloader->GetName( m_pModel ) );
  864. break;
  865. case 2:
  866. Q_snprintf(buf, sizeof( buf ), "%d", (m_EntHandle.ToInt() & (~STATICPROP_EHANDLE_MASK)) );
  867. break;
  868. case 3:
  869. {
  870. float flDist = GetRenderOrigin().DistTo( s_StaticPropMgr.ViewOrigin() );
  871. Q_snprintf(buf, sizeof( buf ), "%.1f", flDist );
  872. }
  873. break;
  874. case 4:
  875. {
  876. CMatRenderContextPtr pRenderContext( materials );
  877. float flPixelWidth = pRenderContext->ComputePixelWidthOfSphere( GetRenderOrigin(), Radius() );
  878. Q_snprintf(buf, sizeof( buf ), "%.1f", flPixelWidth );
  879. }
  880. break;
  881. }
  882. Vector vecTextBox = ( m_WorldRenderBBoxMax + m_WorldRenderBBoxMin ) * 0.5f;
  883. vecTextBox.z = m_WorldRenderBBoxMax.z + 10;
  884. CDebugOverlay::AddTextOverlay( vecTextBox, 0.0f, buf );
  885. #endif
  886. }
  887. //-----------------------------------------------------------------------------
  888. // Draws the model
  889. //-----------------------------------------------------------------------------
  890. int CStaticProp::DrawModelSlow( int flags, const RenderableInstance_t &instance )
  891. {
  892. #ifndef DEDICATED
  893. VPROF_BUDGET( "CStaticProp::DrawModel", VPROF_BUDGETGROUP_STATICPROP_RENDERING );
  894. if ( !r_drawstaticprops.GetBool() )
  895. return 0;
  896. if ( r_drawstaticprops.GetInt() == 2 || r_slowpathwireframe.GetInt() )
  897. {
  898. flags |= STUDIO_WIREFRAME;
  899. }
  900. #ifdef _DEBUG
  901. if ( r_DrawSpecificStaticProp.GetInt() >= 0 )
  902. {
  903. if ( (m_EntHandle.ToInt() & (~STATICPROP_EHANDLE_MASK) ) != r_DrawSpecificStaticProp.GetInt() )
  904. return 0;
  905. }
  906. #endif
  907. if ( ( instance.m_nAlpha == 0 ) || !m_pModel )
  908. return 0;
  909. #ifdef _DEBUG
  910. studiohdr_t *pStudioHdr = modelinfo->GetStudiomodel( m_pModel );
  911. Assert( pStudioHdr );
  912. if ( !( pStudioHdr->flags & STUDIOHDR_FLAGS_STATIC_PROP ) )
  913. {
  914. return 0;
  915. }
  916. #endif
  917. if ( r_colorstaticprops.GetBool() )
  918. {
  919. // deterministic random sequence
  920. unsigned short hash[3];
  921. hash[0] = HashItem( m_ModelInstance );
  922. hash[1] = HashItem( hash[0] );
  923. hash[2] = HashItem( hash[1] );
  924. r_colormod[0] = (float)hash[0] * 1.0f/65535.0f;
  925. r_colormod[1] = (float)hash[1] * 1.0f/65535.0f;
  926. r_colormod[2] = (float)hash[2] * 1.0f/65535.0f;
  927. VectorNormalize( r_colormod );
  928. }
  929. flags |= STUDIO_STATIC_LIGHTING;
  930. int nInfoType = r_staticpropinfo.GetInt();
  931. if ( nInfoType )
  932. {
  933. DisplayStaticPropInfo( nInfoType );
  934. }
  935. // CDebugOverlay::AddBoxOverlay( vec3_origin, m_WorldRenderBBoxMin, m_WorldRenderBBoxMax, vec3_angle, 255, 0, 0, 32, 0.01 );
  936. // CDebugOverlay::AddBoxOverlay( GetRenderOrigin(), m_RenderBBoxMin, m_RenderBBoxMax, GetRenderAngles(), 0, 255, 0, 32, 0.01 );
  937. ModelRenderInfo_t sInfo;
  938. InitModelRenderInfo( sInfo, flags );
  939. g_pStudioRender->SetColorModulation( r_colormod );
  940. g_pStudioRender->SetAlphaModulation( instance.m_nAlpha / 255.0f );
  941. // Restore the matrices if we're skinning
  942. CMatRenderContextPtr pRenderContext( materials );
  943. pRenderContext->MatrixMode( MATERIAL_MODEL );
  944. pRenderContext->PushMatrix();
  945. pRenderContext->LoadIdentity();
  946. int drawn = modelrender->DrawModelEx( sInfo );
  947. pRenderContext->MatrixMode( MATERIAL_MODEL );
  948. pRenderContext->PopMatrix();
  949. if ( m_pModel && (flags & STUDIO_WIREFRAME_VCOLLIDE) )
  950. {
  951. if ( m_nSolidType == SOLID_VPHYSICS )
  952. {
  953. // This works because VCollideForModel only uses modelindex for mod_brush
  954. // and props are always mod_Studio.
  955. vcollide_t * pCollide = CM_VCollideForModel( -1, m_pModel );
  956. if ( pCollide && pCollide->solidCount == 1 )
  957. {
  958. static color32 debugColor = {0,255,255,0};
  959. DebugDrawPhysCollide( pCollide->solids[0], NULL, m_ModelToWorld, debugColor, false );
  960. }
  961. }
  962. else if ( m_nSolidType == SOLID_BBOX )
  963. {
  964. static Color debugColor( 0, 255, 255, 255 );
  965. RenderWireframeBox( m_Origin, vec3_angle, m_pModel->mins, m_pModel->maxs, debugColor, true );
  966. }
  967. }
  968. return drawn;
  969. #else
  970. return 0;
  971. #endif
  972. }
  973. int CStaticProp::DrawModel( int flags, const RenderableInstance_t &instance )
  974. {
  975. #ifndef DEDICATED
  976. VPROF_BUDGET( "CStaticProp::DrawModel", VPROF_BUDGETGROUP_STATICPROP_RENDERING );
  977. if ( ( instance.m_nAlpha == 0 ) || !m_pModel )
  978. return 0;
  979. if ( IsUsingStaticPropDebugModes() || (flags & (STUDIO_WIREFRAME_VCOLLIDE|STUDIO_WIREFRAME)) )
  980. return DrawModelSlow( flags, instance );
  981. flags |= STUDIO_STATIC_LIGHTING;
  982. ModelRenderInfo_t sInfo;
  983. InitModelRenderInfo( sInfo, flags );
  984. g_pStudioRender->SetColorModulation( r_colormod );
  985. g_pStudioRender->SetAlphaModulation( instance.m_nAlpha / 255.0f );
  986. // Restore the matrices if we're skinning
  987. CMatRenderContextPtr pRenderContext( materials );
  988. pRenderContext->MatrixMode( MATERIAL_MODEL );
  989. pRenderContext->PushMatrix();
  990. pRenderContext->LoadIdentity();
  991. #ifdef _X360
  992. ShaderStencilState_t stencilState;
  993. bool bDeferredShadows = r_shadow_deferred.GetBool();
  994. if ( bDeferredShadows )
  995. {
  996. // Deferred shadow rendering:
  997. // clear stencil and hi-stencil because static props don't cast shadows
  998. uint32 mask = 1 << 2;
  999. uint32 nRef = 0;
  1000. stencilState.m_bEnable = true;
  1001. stencilState.m_nTestMask = 0xFFFFFFFF;
  1002. stencilState.m_nWriteMask = mask;
  1003. stencilState.m_nReferenceValue = nRef;
  1004. stencilState.m_CompareFunc = SHADER_STENCILFUNC_ALWAYS;
  1005. stencilState.m_PassOp = SHADER_STENCILOP_SET_TO_REFERENCE;
  1006. stencilState.m_FailOp = SHADER_STENCILOP_KEEP;
  1007. stencilState.m_ZFailOp = SHADER_STENCILOP_KEEP;
  1008. stencilState.m_bHiStencilEnable = false;
  1009. stencilState.m_bHiStencilWriteEnable = true;
  1010. stencilState.m_HiStencilCompareFunc = SHADER_HI_STENCILFUNC_NOTEQUAL;
  1011. stencilState.m_nHiStencilReferenceValue = 0;
  1012. pRenderContext->SetStencilState( stencilState );
  1013. }
  1014. #endif
  1015. int drawn = modelrender->DrawModelExStaticProp( pRenderContext, sInfo );
  1016. pRenderContext->MatrixMode( MATERIAL_MODEL );
  1017. pRenderContext->PopMatrix();
  1018. #ifdef _X360
  1019. if ( bDeferredShadows )
  1020. {
  1021. ShaderStencilState_t stencilState;
  1022. stencilState.m_bEnable = false;
  1023. stencilState.m_bHiStencilWriteEnable = false;
  1024. pRenderContext->SetStencilState( stencilState );
  1025. }
  1026. #endif
  1027. return drawn;
  1028. #else
  1029. return 0;
  1030. #endif
  1031. }
  1032. //-----------------------------------------------------------------------------
  1033. // KD Tree
  1034. //-----------------------------------------------------------------------------
  1035. void CStaticProp::InsertPropIntoKDTree()
  1036. {
  1037. Assert( m_Partition == PARTITION_INVALID_HANDLE );
  1038. if ( m_nSolidType == SOLID_NONE )
  1039. return;
  1040. // Compute the bbox of the prop
  1041. Vector mins, maxs;
  1042. matrix3x4_t propToWorld;
  1043. AngleMatrix( m_Angles, m_Origin, propToWorld );
  1044. TransformAABB( propToWorld, m_pModel->mins, m_pModel->maxs, mins, maxs );
  1045. // If it's using vphysics, get a good AABB
  1046. if ( m_nSolidType == SOLID_VPHYSICS )
  1047. {
  1048. vcollide_t *pCollide = CM_VCollideForModel( -1, m_pModel );
  1049. if ( pCollide && pCollide->solidCount )
  1050. {
  1051. physcollision->CollideGetAABB( &mins, &maxs, pCollide->solids[0], m_Origin, m_Angles );
  1052. }
  1053. else
  1054. {
  1055. m_nSolidType = SOLID_NONE;
  1056. return;
  1057. }
  1058. }
  1059. // add the entity to the KD tree so we will collide against it
  1060. m_Partition = SpatialPartition()->CreateHandle( this,
  1061. PARTITION_CLIENT_SOLID_EDICTS | PARTITION_CLIENT_STATIC_PROPS |
  1062. PARTITION_ENGINE_SOLID_EDICTS | PARTITION_ENGINE_STATIC_PROPS,
  1063. mins, maxs );
  1064. Assert( m_Partition != PARTITION_INVALID_HANDLE );
  1065. }
  1066. void CStaticProp::RemovePropFromKDTree()
  1067. {
  1068. // Release the spatial partition handle
  1069. if ( m_Partition != PARTITION_INVALID_HANDLE )
  1070. {
  1071. SpatialPartition()->DestroyHandle( m_Partition );
  1072. m_Partition = PARTITION_INVALID_HANDLE;
  1073. }
  1074. }
  1075. //-----------------------------------------------------------------------------
  1076. // Create VPhysics representation
  1077. //-----------------------------------------------------------------------------
  1078. void CStaticProp::CreateVPhysics( IPhysicsEnvironment *pPhysEnv, IVPhysicsKeyHandler *pDefaults, void *pGameData )
  1079. {
  1080. if ( m_nSolidType == SOLID_NONE )
  1081. return;
  1082. vcollide_t *pVCollide = NULL;
  1083. solid_t solid;
  1084. CPhysCollide* pPhysCollide = NULL;
  1085. unsigned int iContents = MASK_ALL;
  1086. if ( m_pModel )
  1087. {
  1088. if ( m_nSolidType == SOLID_VPHYSICS )
  1089. {
  1090. // This works because VCollideForModel only uses modelindex for mod_brush
  1091. // and props are always mod_Studio.
  1092. pVCollide = CM_VCollideForModel( -1, m_pModel );
  1093. }
  1094. int nModelType = m_pModel->type;
  1095. if ( nModelType == mod_studio )
  1096. {
  1097. MDLHandle_t hStudioHdr = m_pModel->studio;
  1098. if ( hStudioHdr != MDLHANDLE_INVALID )
  1099. {
  1100. const studiohdr_t *pStudioHdr = mdlcache->GetStudioHdr( hStudioHdr );
  1101. iContents = pStudioHdr->contents;
  1102. }
  1103. }
  1104. else if ( nModelType == mod_brush )
  1105. {
  1106. iContents = m_pModel->brush.pShared->nodes[ m_pModel->brush.firstnode ].contents;
  1107. }
  1108. }
  1109. if (pVCollide)
  1110. {
  1111. pPhysCollide = pVCollide->solids[0];
  1112. IVPhysicsKeyParser *pParse = physcollision->VPhysicsKeyParserCreate( pVCollide );
  1113. while ( !pParse->Finished() )
  1114. {
  1115. const char *pBlock = pParse->GetCurrentBlockName();
  1116. if ( !strcmpi( pBlock, "solid" ) )
  1117. {
  1118. pParse->ParseSolid( &solid, pDefaults );
  1119. break;
  1120. }
  1121. else
  1122. {
  1123. pParse->SkipBlock();
  1124. }
  1125. }
  1126. physcollision->VPhysicsKeyParserDestroy( pParse );
  1127. }
  1128. else
  1129. {
  1130. if ( m_nSolidType != SOLID_BBOX )
  1131. {
  1132. char szModel[MAX_PATH];
  1133. Q_strncpy( szModel, m_pModel ? modelloader->GetName( m_pModel ) : "unknown model", sizeof( szModel ) );
  1134. Log_Warning( LOG_StaticPropManager, "Map Error: Static prop with bogus solid type %d! (%s)\n", m_nSolidType, szModel );
  1135. m_nSolidType = SOLID_NONE;
  1136. return;
  1137. }
  1138. // If there's no collide, we need a bbox...
  1139. pPhysCollide = physcollision->BBoxToCollide( m_pModel->mins, m_pModel->maxs );
  1140. solid.params = g_PhysDefaultObjectParams;
  1141. Q_strncpy( solid.surfaceprop, "default", sizeof( solid.surfaceprop ) );
  1142. }
  1143. Assert(pPhysCollide);
  1144. solid.params.enableCollisions = true;
  1145. solid.params.pGameData = pGameData;
  1146. solid.params.pName = "prop_static";
  1147. int surfaceData = physprops->GetSurfaceIndex( solid.surfaceprop );
  1148. IPhysicsObject *pPhysObject = pPhysEnv->CreatePolyObjectStatic( pPhysCollide,
  1149. surfaceData, m_Origin, m_Angles, &solid.params );
  1150. pPhysObject->SetContents( iContents );
  1151. if ( iContents & CONTENTS_SOLID )
  1152. {
  1153. pPhysObject->SetCollisionHints(COLLISION_HINT_STATICSOLID);
  1154. }
  1155. //PhysCheckAdd( pPhys, "Static" );
  1156. }
  1157. //-----------------------------------------------------------------------------
  1158. // Expose IStaticPropMgr to the engine
  1159. //-----------------------------------------------------------------------------
  1160. IStaticPropMgrEngine* StaticPropMgr()
  1161. {
  1162. return &s_StaticPropMgr;
  1163. }
  1164. //-----------------------------------------------------------------------------
  1165. // constructor, destructor
  1166. //-----------------------------------------------------------------------------
  1167. CStaticPropMgr::CStaticPropMgr()
  1168. {
  1169. m_bLevelInitialized = false;
  1170. m_bClientInitialized = false;
  1171. m_nLastCPULevel = m_nLastGPULevel = -1;
  1172. }
  1173. CStaticPropMgr::~CStaticPropMgr()
  1174. {
  1175. }
  1176. //-----------------------------------------------------------------------------
  1177. // Purpose:
  1178. // Output : Returns true on success, false on failure.
  1179. //-----------------------------------------------------------------------------
  1180. bool CStaticPropMgr::Init()
  1181. {
  1182. return true;
  1183. }
  1184. //-----------------------------------------------------------------------------
  1185. // Purpose:
  1186. //-----------------------------------------------------------------------------
  1187. void CStaticPropMgr::Shutdown()
  1188. {
  1189. if ( !m_bLevelInitialized )
  1190. return;
  1191. LevelShutdown();
  1192. }
  1193. //-----------------------------------------------------------------------------
  1194. // Configures the system level for static props
  1195. //-----------------------------------------------------------------------------
  1196. void CStaticPropMgr::ConfigureSystemLevel( int nCPULevel, int nGPULevel )
  1197. {
  1198. if ( nCPULevel == m_nLastCPULevel && nGPULevel == m_nLastGPULevel )
  1199. return;
  1200. m_nLastCPULevel = nCPULevel;
  1201. m_nLastGPULevel = nGPULevel;
  1202. if ( m_bClientInitialized )
  1203. {
  1204. UpdatePropVisibility( nCPULevel, nGPULevel );
  1205. }
  1206. }
  1207. void CStaticPropMgr::RestoreStaticProps( )
  1208. {
  1209. UpdatePropVisibility( m_nLastCPULevel, m_nLastGPULevel );
  1210. // It's possible in certain alt+tab situations that the mdl flags will not be set the first time we compute static lighting.
  1211. // Ensure that we recompute it here to catch any mdl flag changes after the alt+tab.
  1212. RecomputeStaticLighting();
  1213. }
  1214. void CStaticPropMgr::UpdatePropVisibility( int nCPULevel, int nGPULevel )
  1215. {
  1216. #ifdef DEDICATED
  1217. return;
  1218. #endif
  1219. if ( !m_bClientInitialized )
  1220. return;
  1221. int nCount = m_StaticProps.Count();
  1222. for ( int i = 0; i < nCount; ++i )
  1223. {
  1224. CStaticProp &prop = m_StaticProps[i];
  1225. bool bNoDraw = false;
  1226. if ( !IsGameConsole() )
  1227. {
  1228. if ( nCPULevel >= 0 )
  1229. {
  1230. bNoDraw = ( prop.m_nMinCPULevel && prop.m_nMinCPULevel-1 > nCPULevel );
  1231. bNoDraw = bNoDraw || ( prop.m_nMaxCPULevel && prop.m_nMaxCPULevel-1 < nCPULevel );
  1232. }
  1233. if ( nGPULevel >= 0 )
  1234. {
  1235. bNoDraw = bNoDraw || ( prop.m_nMinGPULevel && prop.m_nMinGPULevel-1 > nGPULevel );
  1236. bNoDraw = bNoDraw || ( prop.m_nMaxGPULevel && prop.m_nMaxGPULevel-1 < nGPULevel );
  1237. }
  1238. }
  1239. // Add the prop to all the leaves it lies in
  1240. if ( bNoDraw || !prop.LeafCount())
  1241. {
  1242. prop.CleanUpRenderHandle();
  1243. continue;
  1244. }
  1245. RenderableTranslucencyType_t nType = modelinfo->ComputeTranslucencyType( prop.m_pModel, prop.GetSkin(), prop.GetBody() );
  1246. if ( prop.RenderHandle() != INVALID_CLIENT_RENDER_HANDLE )
  1247. {
  1248. clientleafsystem->SetTranslucencyType( prop.RenderHandle(), nType );
  1249. clientleafsystem->RenderInFastReflections( prop.RenderHandle(), ( prop.m_Flags & STATIC_PROP_MARKED_FOR_FAST_REFLECTION ) != 0 );
  1250. clientleafsystem->DisableShadowDepthRendering( prop.RenderHandle(), ( prop.m_FlagsEx & STATIC_PROP_FLAGS_EX_DISABLE_SHADOW_DEPTH ) != 0 );
  1251. clientleafsystem->DisableCSMRendering( prop.RenderHandle(), (prop.m_FlagsEx & STATIC_PROP_FLAGS_EX_DISABLE_CSM) != 0 );
  1252. continue;
  1253. }
  1254. clientleafsystem->CreateRenderableHandle( &prop, false, nType, RENDERABLE_MODEL_STATIC_PROP );
  1255. ClientRenderHandle_t handle = prop.RenderHandle();
  1256. clientleafsystem->AddRenderableToLeaves( handle, prop.LeafCount(), (unsigned short*)&m_StaticPropLeaves[prop.FirstLeaf()] );
  1257. clientleafsystem->RenderInFastReflections( prop.RenderHandle(), ( prop.m_Flags & STATIC_PROP_MARKED_FOR_FAST_REFLECTION ) != 0 );
  1258. clientleafsystem->DisableShadowDepthRendering( prop.RenderHandle(), ( prop.m_FlagsEx & STATIC_PROP_FLAGS_EX_DISABLE_SHADOW_DEPTH ) != 0 );
  1259. clientleafsystem->DisableCSMRendering( prop.RenderHandle(), (prop.m_FlagsEx & STATIC_PROP_FLAGS_EX_DISABLE_CSM) != 0 );
  1260. }
  1261. }
  1262. //-----------------------------------------------------------------------------
  1263. // Unserialize static prop model dictionary
  1264. //-----------------------------------------------------------------------------
  1265. void CStaticPropMgr::UnserializeModelDict( CUtlBuffer& buf )
  1266. {
  1267. int count = buf.GetInt();
  1268. m_StaticPropDict.AddMultipleToTail( count );
  1269. COM_TimestampedLog( "Starting UnserializeModelDict for %d models\n", count );
  1270. for ( int i=0; i < count; i++ )
  1271. {
  1272. #ifndef DEDICATED
  1273. if ( !(i % 10 ) )
  1274. {
  1275. EngineVGui()->UpdateProgressBar(PROGRESS_DEFAULT);
  1276. }
  1277. #endif
  1278. StaticPropDictLump_t lump;
  1279. buf.Get( &lump, sizeof(StaticPropDictLump_t) );
  1280. m_StaticPropDict[i] = modelloader->GetModelForName( lump.m_Name, IModelLoader::FMODELLOADER_STATICPROP );
  1281. }
  1282. COM_TimestampedLog( "Finished UnserializeModelDict\n" );
  1283. }
  1284. void CStaticPropMgr::UnserializeLeafList( CUtlBuffer& buf )
  1285. {
  1286. int nCount = buf.GetInt();
  1287. m_StaticPropLeaves.Purge();
  1288. if ( nCount > 0 )
  1289. {
  1290. m_StaticPropLeaves.AddMultipleToTail( nCount );
  1291. buf.Get( m_StaticPropLeaves.Base(), nCount * sizeof(StaticPropLeafLump_t) );
  1292. }
  1293. }
  1294. void CStaticPropMgr::UnserializeModels( CUtlBuffer& buf )
  1295. {
  1296. // Version check
  1297. int nLumpVersion = Mod_GameLumpVersion( GAMELUMP_STATIC_PROPS );
  1298. if ( nLumpVersion < 4 )
  1299. {
  1300. Log_Warning( LOG_StaticPropManager, "Really old map format! Static props can't be loaded...\n" );
  1301. return;
  1302. }
  1303. int count = buf.GetInt();
  1304. // Gotta preallocate the static props here so no rellocations take place
  1305. // the leaf list stores pointers to these tricky little guys.
  1306. bool bSkip = false;
  1307. m_StaticProps.EnsureCapacity(count);
  1308. for ( int i = 0; i < count; ++i )
  1309. {
  1310. // Reset every loop.
  1311. bSkip = false;
  1312. StaticPropLump_t lump;
  1313. switch ( nLumpVersion )
  1314. {
  1315. case 4:
  1316. buf.Get( &lump, sizeof(StaticPropLumpV4_t) );
  1317. lump.m_flForcedFadeScale = 1.0f;
  1318. lump.m_nMinCPULevel = lump.m_nMaxCPULevel = lump.m_nMinGPULevel = lump.m_nMaxGPULevel = 0;
  1319. lump.m_DiffuseModulation.r = lump.m_DiffuseModulation.g = lump.m_DiffuseModulation.b = lump.m_DiffuseModulation.a = 255; // default color/alpha modulation to identity
  1320. lump.m_bDisableX360 = false;
  1321. lump.m_FlagsEx = 0;
  1322. break;
  1323. case 5:
  1324. buf.Get( &lump, sizeof(StaticPropLumpV5_t) );
  1325. lump.m_nMinCPULevel = lump.m_nMaxCPULevel = lump.m_nMinGPULevel = lump.m_nMaxGPULevel = 0;
  1326. lump.m_DiffuseModulation.r = lump.m_DiffuseModulation.g = lump.m_DiffuseModulation.b = lump.m_DiffuseModulation.a = 255; // default color/alpha modulation to identity
  1327. lump.m_bDisableX360 = false;
  1328. lump.m_FlagsEx = 0;
  1329. break;
  1330. case 6:
  1331. buf.Get( &lump, sizeof( StaticPropLumpV6_t ) );
  1332. lump.m_nMinCPULevel = lump.m_nMaxCPULevel = lump.m_nMinGPULevel = lump.m_nMaxGPULevel = 0;
  1333. lump.m_DiffuseModulation.r = lump.m_DiffuseModulation.g = lump.m_DiffuseModulation.b = lump.m_DiffuseModulation.a = 255; // default color/alpha modulation to identity
  1334. lump.m_bDisableX360 = false;
  1335. lump.m_FlagsEx = 0;
  1336. break;
  1337. case 7:
  1338. buf.Get( &lump, sizeof( StaticPropLumpV7_t ) );
  1339. lump.m_nMinCPULevel = lump.m_nMaxCPULevel = lump.m_nMinGPULevel = lump.m_nMaxGPULevel = 0;
  1340. lump.m_bDisableX360 = false;
  1341. lump.m_FlagsEx = 0;
  1342. break;
  1343. case 8:
  1344. buf.Get( &lump, sizeof( StaticPropLumpV8_t ) );
  1345. lump.m_bDisableX360 = false;
  1346. lump.m_FlagsEx = 0;
  1347. break;
  1348. case 9:
  1349. buf.Get( &lump, sizeof( StaticPropLumpV9_t ) );
  1350. lump.m_FlagsEx = 0;
  1351. break;
  1352. case 10:
  1353. buf.Get( &lump, sizeof( StaticPropLump_t ) );
  1354. break;
  1355. }
  1356. int j = m_StaticProps.AddToTail();
  1357. m_StaticProps[j].Init( j, lump, m_StaticPropDict[lump.m_PropType] );
  1358. // Add the prop to the K-D tree for collision
  1359. m_StaticProps[j].InsertPropIntoKDTree( );
  1360. #ifndef DEDICATED
  1361. if ( !(i % 10 ) )
  1362. {
  1363. EngineVGui()->UpdateProgressBar(PROGRESS_DEFAULT);
  1364. }
  1365. #endif
  1366. }
  1367. }
  1368. void CStaticPropMgr::OutputLevelStats( void )
  1369. {
  1370. // STATS
  1371. int i;
  1372. int totalVerts = 0;
  1373. for( i = 0; i < m_StaticProps.Count(); i++ )
  1374. {
  1375. CStaticProp *pStaticProp = &m_StaticProps[i];
  1376. model_t *pModel = (model_t*)pStaticProp->GetModel();
  1377. if( !pModel )
  1378. {
  1379. continue;
  1380. }
  1381. Assert( pModel->type == mod_studio );
  1382. studiohdr_t *pStudioHdr = ( studiohdr_t * )modelloader->GetExtraData( pModel );
  1383. int bodyPart;
  1384. for( bodyPart = 0; bodyPart < pStudioHdr->numbodyparts; bodyPart++ )
  1385. {
  1386. mstudiobodyparts_t *pBodyPart = pStudioHdr->pBodypart( bodyPart );
  1387. int model;
  1388. for( model = 0; model < pBodyPart->nummodels; model++ )
  1389. {
  1390. mstudiomodel_t *pModel = pBodyPart->pModel( model );
  1391. totalVerts += pModel->numvertices;
  1392. }
  1393. }
  1394. }
  1395. Log_Warning( LOG_StaticPropManager, "%d static prop instances in map\n", ( int )m_StaticProps.Count() );
  1396. Log_Warning( LOG_StaticPropManager, "%d static prop models in map\n", ( int )m_StaticPropDict.Count() );
  1397. Log_Warning( LOG_StaticPropManager, "%d static prop verts in map\n", ( int )totalVerts );
  1398. }
  1399. //-----------------------------------------------------------------------------
  1400. // Unserialize static props
  1401. //-----------------------------------------------------------------------------
  1402. void CStaticPropMgr::UnserializeStaticProps()
  1403. {
  1404. // Unserialize static props, insert them into the appropriate leaves
  1405. int size = Mod_GameLumpSize( GAMELUMP_STATIC_PROPS );
  1406. if (!size)
  1407. return;
  1408. COM_TimestampedLog( "UnserializeStaticProps - start");
  1409. MEM_ALLOC_CREDIT();
  1410. CUtlBuffer buf( 0, size );
  1411. if ( Mod_LoadGameLump( GAMELUMP_STATIC_PROPS, buf.PeekPut(), size ))
  1412. {
  1413. buf.SeekPut( CUtlBuffer::SEEK_HEAD, size );
  1414. COM_TimestampedLog( "UnserializeModelDict" );
  1415. UnserializeModelDict( buf );
  1416. COM_TimestampedLog( "UnserializeLeafList" );
  1417. UnserializeLeafList( buf );
  1418. COM_TimestampedLog( "UnserializeModels" );
  1419. UnserializeModels( buf );
  1420. }
  1421. COM_TimestampedLog( "UnserializeStaticProps - end");
  1422. }
  1423. //-----------------------------------------------------------------------------
  1424. // Level init, shutdown
  1425. //-----------------------------------------------------------------------------
  1426. void CStaticPropMgr::LevelInit()
  1427. {
  1428. if ( m_bLevelInitialized )
  1429. return;
  1430. Assert( !m_bClientInitialized );
  1431. m_bLevelInitialized = true;
  1432. // See if we should skip loading static props
  1433. if( disableStaticPropLoading.GetBool() == false )
  1434. {
  1435. // Read in static props that have been compiled into the bsp file
  1436. UnserializeStaticProps();
  1437. }
  1438. // OutputLevelStats();
  1439. }
  1440. void CStaticPropMgr::LevelShutdown()
  1441. {
  1442. if ( !m_bLevelInitialized )
  1443. return;
  1444. // Deal with client-side stuff, if appropriate
  1445. if ( m_bClientInitialized )
  1446. {
  1447. LevelShutdownClient();
  1448. }
  1449. m_bLevelInitialized = false;
  1450. m_StaticProps.Purge();
  1451. FOR_EACH_VEC( m_StaticPropDict, i )
  1452. {
  1453. modelloader->UnreferenceModel( m_StaticPropDict[i], IModelLoader::FMODELLOADER_STATICPROP );
  1454. }
  1455. m_StaticPropDict.Purge();
  1456. }
  1457. void CStaticPropMgr::LevelInitClient()
  1458. {
  1459. #ifndef DEDICATED
  1460. if ( sv.IsDedicated() )
  1461. return;
  1462. extern ConVar r_proplightingfromdisk;
  1463. bool bNeedsMapAccess = r_proplightingfromdisk.GetBool();
  1464. if ( bNeedsMapAccess )
  1465. {
  1466. g_pFileSystem->BeginMapAccess();
  1467. }
  1468. Assert( m_bLevelInitialized );
  1469. Assert( !m_bClientInitialized );
  1470. // Since the client will be ready at a later time than the server
  1471. // to set up its data, we need a separate call to handle that
  1472. int nCount = m_StaticProps.Count();
  1473. for ( int i = 0; i < nCount; ++i )
  1474. {
  1475. CStaticProp &prop = m_StaticProps[i];
  1476. if ( prop.LeafCount() <= 0 )
  1477. {
  1478. Vector origin = prop.GetCollisionOrigin();
  1479. Vector mins = prop.OBBMins();
  1480. Vector maxs = prop.OBBMaxs();
  1481. DevMsg( 1, "Static prop in 0 leaves! %s, @ %.1f, %.1f, %.1f\n", modelloader->GetName( prop.GetModel() ), origin.x, origin.y, origin.z );
  1482. continue;
  1483. }
  1484. }
  1485. m_bClientInitialized = true;
  1486. // swapping order of UpdatePropVisibility and PrecacheLighting - Precache now first since it updates the flag to determine if prop contributes to CSM
  1487. PrecacheLighting();
  1488. UpdatePropVisibility( m_nLastCPULevel, m_nLastGPULevel );
  1489. if ( bNeedsMapAccess )
  1490. {
  1491. g_pFileSystem->EndMapAccess();
  1492. }
  1493. #endif
  1494. }
  1495. void CStaticPropMgr::LevelShutdownClient()
  1496. {
  1497. if ( !m_bClientInitialized )
  1498. return;
  1499. Assert( m_bLevelInitialized );
  1500. for (int i = m_StaticProps.Count(); --i >= 0; )
  1501. {
  1502. m_StaticProps[i].CleanUpAlphaProperty();
  1503. m_StaticProps[i].CleanUpRenderHandle( );
  1504. modelrender->SetStaticLighting( m_StaticProps[i].GetModelInstance(), NULL );
  1505. }
  1506. #ifndef DEDICATED
  1507. // Make sure static prop lightcache is reset
  1508. ClearStaticLightingCache();
  1509. #endif
  1510. m_bClientInitialized = false;
  1511. }
  1512. //-----------------------------------------------------------------------------
  1513. // Create physics representations of props
  1514. //-----------------------------------------------------------------------------
  1515. void CStaticPropMgr::CreateVPhysicsRepresentations( IPhysicsEnvironment *pPhysEnv, IVPhysicsKeyHandler *pDefaults, void *pGameData )
  1516. {
  1517. // Walk through the static props + make collideable thingies for them.
  1518. int nCount = m_StaticProps.Count();
  1519. for ( int i = nCount; --i >= 0; )
  1520. {
  1521. m_StaticProps[i].CreateVPhysics( pPhysEnv, pDefaults, pGameData );
  1522. }
  1523. }
  1524. //-----------------------------------------------------------------------------
  1525. // Handles to props
  1526. //-----------------------------------------------------------------------------
  1527. inline int CStaticPropMgr::HandleEntityToIndex( IHandleEntity *pHandleEntity ) const
  1528. {
  1529. Assert( IsStaticProp_Inline( pHandleEntity ) );
  1530. return pHandleEntity->GetRefEHandle().GetEntryIndex();
  1531. }
  1532. ICollideable *CStaticPropMgr::GetStaticProp( IHandleEntity *pHandleEntity )
  1533. {
  1534. if ( !IsStaticProp_Inline( pHandleEntity ) )
  1535. {
  1536. return NULL;
  1537. }
  1538. int nIndex = pHandleEntity ? pHandleEntity->GetRefEHandle().GetEntryIndex() : -1;
  1539. if ( nIndex < 0 || nIndex > m_StaticProps.Count() )
  1540. {
  1541. return NULL;
  1542. }
  1543. return &m_StaticProps[nIndex];
  1544. }
  1545. ICollideable *CStaticPropMgr::GetStaticPropByIndex( int propIndex )
  1546. {
  1547. if ( propIndex < m_StaticProps.Count() )
  1548. {
  1549. return &m_StaticProps[propIndex];
  1550. }
  1551. Assert(0);
  1552. return NULL;
  1553. }
  1554. //-----------------------------------------------------------------------------
  1555. // Get large amounts of handles to static props
  1556. //-----------------------------------------------------------------------------
  1557. void CStaticPropMgr::GetAllStaticProps( CUtlVector<ICollideable *> *pOutput )
  1558. {
  1559. if ( pOutput == NULL ) return;
  1560. int iPropVectorSize = m_StaticProps.Count();
  1561. int counter;
  1562. for ( counter = 0; counter != iPropVectorSize; ++counter )
  1563. {
  1564. pOutput->AddToTail( &m_StaticProps[counter] );
  1565. }
  1566. }
  1567. void CStaticPropMgr::GetAllStaticPropsInAABB( const Vector &vMins, const Vector &vMaxs, CUtlVector<ICollideable *> *pOutput )
  1568. {
  1569. if ( pOutput == NULL ) return;
  1570. int iPropVectorSize = m_StaticProps.Count();
  1571. int counter;
  1572. for ( counter = 0; counter != iPropVectorSize; ++counter )
  1573. {
  1574. CStaticProp *pProp = &m_StaticProps[counter];
  1575. Vector vPropMins, vPropMaxs;
  1576. pProp->WorldSpaceSurroundingBounds( &vPropMins, &vPropMaxs );
  1577. if( vPropMaxs.x < vMins.x ) continue;
  1578. if( vPropMaxs.y < vMins.y ) continue;
  1579. if( vPropMaxs.z < vMins.z ) continue;
  1580. if( vPropMins.x > vMaxs.x ) continue;
  1581. if( vPropMins.y > vMaxs.y ) continue;
  1582. if( vPropMins.z > vMaxs.z ) continue;
  1583. pOutput->AddToTail( pProp );
  1584. }
  1585. }
  1586. void CStaticPropMgr::GetAllStaticPropsInOBB( const Vector &ptOrigin, const Vector &vExtent1, const Vector &vExtent2, const Vector &vExtent3, CUtlVector<ICollideable *> *pOutput )
  1587. {
  1588. if ( pOutput == NULL )
  1589. return;
  1590. int counter;
  1591. Vector vAABBMins, vAABBMaxs;
  1592. vAABBMins = ptOrigin;
  1593. vAABBMaxs = ptOrigin;
  1594. Vector ptAABBExtents[8];
  1595. Vector ptOBBExtents[8];
  1596. for( counter = 0; counter != 8; ++counter )
  1597. {
  1598. ptOBBExtents[counter] = ptOrigin;
  1599. if( counter & (1<<0) ) ptOBBExtents[counter] += vExtent1;
  1600. if( counter & (1<<1) ) ptOBBExtents[counter] += vExtent2;
  1601. if( counter & (1<<2) ) ptOBBExtents[counter] += vExtent3;
  1602. //expand AABB extents
  1603. if( ptOBBExtents[counter].x < vAABBMins.x ) vAABBMins.x = ptOBBExtents[counter].x;
  1604. if( ptOBBExtents[counter].x > vAABBMaxs.x ) vAABBMaxs.x = ptOBBExtents[counter].x;
  1605. if( ptOBBExtents[counter].y < vAABBMins.y ) vAABBMins.y = ptOBBExtents[counter].y;
  1606. if( ptOBBExtents[counter].y > vAABBMaxs.y ) vAABBMaxs.y = ptOBBExtents[counter].y;
  1607. if( ptOBBExtents[counter].z < vAABBMins.z ) vAABBMins.z = ptOBBExtents[counter].z;
  1608. if( ptOBBExtents[counter].z > vAABBMaxs.z ) vAABBMaxs.z = ptOBBExtents[counter].z;
  1609. }
  1610. //generate planes for the obb so we can use halfspace elimination
  1611. Vector vOBBPlaneNormals[6];
  1612. float fOBBPlaneDists[6];
  1613. vOBBPlaneNormals[0] = vExtent1;
  1614. vOBBPlaneNormals[0].NormalizeInPlace();
  1615. fOBBPlaneDists[0] = vOBBPlaneNormals[0].Dot( ptOrigin + vExtent1 );
  1616. vOBBPlaneNormals[1] = -vOBBPlaneNormals[0];
  1617. fOBBPlaneDists[1] = vOBBPlaneNormals[1].Dot( ptOrigin );
  1618. vOBBPlaneNormals[2] = vExtent2;
  1619. vOBBPlaneNormals[2].NormalizeInPlace();
  1620. fOBBPlaneDists[2] = vOBBPlaneNormals[2].Dot( ptOrigin + vExtent2 );
  1621. vOBBPlaneNormals[3] = -vOBBPlaneNormals[2];
  1622. fOBBPlaneDists[3] = vOBBPlaneNormals[3].Dot( ptOrigin );
  1623. vOBBPlaneNormals[4] = vExtent3;
  1624. vOBBPlaneNormals[4].NormalizeInPlace();
  1625. fOBBPlaneDists[4] = vOBBPlaneNormals[4].Dot( ptOrigin + vExtent3 );
  1626. vOBBPlaneNormals[5] = -vOBBPlaneNormals[4];
  1627. fOBBPlaneDists[5] = vOBBPlaneNormals[5].Dot( ptOrigin );
  1628. int iPropVectorSize = m_StaticProps.Count();
  1629. for ( counter = 0; counter != iPropVectorSize; ++counter )
  1630. {
  1631. CStaticProp *pProp = &m_StaticProps[counter];
  1632. Vector vPropMins, vPropMaxs;
  1633. pProp->WorldSpaceSurroundingBounds( &vPropMins, &vPropMaxs );
  1634. if( vPropMaxs.x < vAABBMins.x ) continue;
  1635. if( vPropMaxs.y < vAABBMins.y ) continue;
  1636. if( vPropMaxs.z < vAABBMins.z ) continue;
  1637. if( vPropMins.x > vAABBMaxs.x ) continue;
  1638. if( vPropMins.y > vAABBMaxs.y ) continue;
  1639. if( vPropMins.z > vAABBMaxs.z ) continue;
  1640. //static prop AABB and desired AABB intersect, do OBB tests
  1641. Vector vPropOBBMins = pProp->OBBMins();
  1642. Vector vPropOBBMaxs = pProp->OBBMaxs();
  1643. Vector ptPropExtents[8];
  1644. matrix3x4_t matPropWorld;
  1645. AngleMatrix( pProp->GetCollisionAngles(), pProp->GetCollisionOrigin(), matPropWorld );
  1646. int counter2, counter3;
  1647. //generate prop extents, TODO: update these to handle props with OBB's since it should be nearly trivial
  1648. for( counter2 = 0; counter2 != 8; ++counter2 )
  1649. {
  1650. /*ptPropExtents[counter2].x = (counter2 & (1<<0))?(vPropMaxs.x):(vPropMins.x);
  1651. ptPropExtents[counter2].y = (counter2 & (1<<1))?(vPropMaxs.y):(vPropMins.y);
  1652. ptPropExtents[counter2].z = (counter2 & (1<<2))?(vPropMaxs.z):(vPropMins.z);*/
  1653. Vector ptTemp;
  1654. ptTemp.x = (counter2 & (1<<0))?(vPropOBBMaxs.x):(vPropOBBMins.x);
  1655. ptTemp.y = (counter2 & (1<<1))?(vPropOBBMaxs.y):(vPropOBBMins.y);
  1656. ptTemp.z = (counter2 & (1<<2))?(vPropOBBMaxs.z):(vPropOBBMins.z);
  1657. VectorTransform( ptTemp, matPropWorld, ptPropExtents[counter2] );
  1658. }
  1659. for( counter2 = 0; counter2 != 6; ++counter2 ) //loop over OBB planes
  1660. {
  1661. for( counter3 = 0; counter3 != 8; ++counter3 ) //loop over prop extents
  1662. {
  1663. if( (ptPropExtents[counter3].Dot( vOBBPlaneNormals[counter2] ) - fOBBPlaneDists[counter2]) < 0.0f )
  1664. {
  1665. //an extent of the prop is within the OBB halfspace, this halfspace does not eliminate our prop, move to the next halfspace
  1666. break;
  1667. }
  1668. }
  1669. if( counter3 == 8 ) break; //if all 8 extents lie outside the halfspace, then the prop is not in the OBB
  1670. }
  1671. if( counter2 == 6 )
  1672. {
  1673. //if all 6 planes failed to eliminate the extents, the OBB and prop intersect
  1674. //FIXME: Halfspace elimination will never remove props that do intersect, but leaves some false positives in some cases.
  1675. pOutput->AddToTail( pProp );
  1676. }
  1677. }
  1678. }
  1679. //-----------------------------------------------------------------------------
  1680. // Are we a static prop?
  1681. //-----------------------------------------------------------------------------
  1682. bool CStaticPropMgr::IsStaticProp( IHandleEntity *pHandleEntity ) const
  1683. {
  1684. return IsStaticProp_Inline( pHandleEntity );
  1685. }
  1686. bool CStaticPropMgr::IsStaticProp( CBaseHandle handle ) const
  1687. {
  1688. return (handle.GetSerialNumber() == (STATICPROP_EHANDLE_MASK >> NUM_SERIAL_NUM_SHIFT_BITS));
  1689. }
  1690. int CStaticPropMgr::GetStaticPropIndex( IHandleEntity *pHandleEntity ) const
  1691. {
  1692. return HandleEntityToIndex( pHandleEntity );
  1693. }
  1694. //-----------------------------------------------------------------------------
  1695. // Returns lighting origins
  1696. //-----------------------------------------------------------------------------
  1697. void CStaticPropMgr::GetLightingOrigins( Vector *pLightingOrigins, int nOriginStride, int nCount, IClientRenderable **ppRenderable, int nRenderableStride )
  1698. {
  1699. for ( int i = 0; i < nCount; ++i,
  1700. ppRenderable = (IClientRenderable**)( (unsigned char*)ppRenderable + nRenderableStride ),
  1701. pLightingOrigins = (Vector*)( (unsigned char*)pLightingOrigins + nOriginStride ))
  1702. {
  1703. CStaticProp *pProp = assert_cast< CStaticProp* >( (*ppRenderable)->GetIClientUnknown() );
  1704. *pLightingOrigins = pProp->m_LightingOrigin;
  1705. }
  1706. }
  1707. //-----------------------------------------------------------------------------
  1708. // Compute static lighting
  1709. //-----------------------------------------------------------------------------
  1710. void CStaticPropMgr::PrecacheLighting()
  1711. {
  1712. COM_TimestampedLog( "CStaticPropMgr::PrecacheLighting - start");
  1713. int numVerts = 0;
  1714. if ( IsGameConsole() )
  1715. {
  1716. if ( g_bLoadedMapHasBakedPropLighting && g_pMaterialSystemHardwareConfig->SupportsStreamOffset() )
  1717. {
  1718. // total the static prop verts
  1719. int i = m_StaticProps.Count();
  1720. while ( --i >= 0 )
  1721. {
  1722. studiohwdata_t *pStudioHWData = g_pMDLCache->GetHardwareData( ( (model_t*)m_StaticProps[i].GetModel() )->studio );
  1723. for ( int lodID = pStudioHWData->m_RootLOD; lodID < pStudioHWData->m_NumLODs; lodID++ )
  1724. {
  1725. studioloddata_t *pLOD = &pStudioHWData->m_pLODs[lodID];
  1726. for ( int meshID = 0; meshID < pStudioHWData->m_NumStudioMeshes; meshID++ )
  1727. {
  1728. studiomeshdata_t *pMesh = &pLOD->m_pMeshData[meshID];
  1729. for ( int groupID = 0; groupID < pMesh->m_NumGroup; groupID++ )
  1730. {
  1731. numVerts += pMesh->m_pMeshGroup[groupID].m_NumVertices;
  1732. }
  1733. }
  1734. }
  1735. }
  1736. }
  1737. modelrender->SetupColorMeshes( numVerts );
  1738. }
  1739. int total = m_StaticProps.Count();
  1740. for ( int i = 0; i < total; i++ )
  1741. {
  1742. MDLCACHE_CRITICAL_SECTION_( g_pMDLCache );
  1743. m_StaticProps[i].PrecacheLighting();
  1744. #ifndef DEDICATED
  1745. EngineVGui()->UpdateProgressBar( PROGRESS_PRECACHELIGHTING );
  1746. #endif
  1747. }
  1748. COM_TimestampedLog( "CStaticPropMgr::PrecacheLighting - end" );
  1749. }
  1750. void CStaticPropMgr::RecomputeStaticLighting( )
  1751. {
  1752. int i = m_StaticProps.Count();
  1753. while ( --i >= 0 )
  1754. {
  1755. if ( m_StaticProps[i].RenderHandle() == INVALID_CLIENT_RENDER_HANDLE )
  1756. continue;
  1757. m_StaticProps[i].RecomputeStaticLighting();
  1758. }
  1759. }
  1760. //-----------------------------------------------------------------------------
  1761. // Is the prop in the PVS?
  1762. //-----------------------------------------------------------------------------
  1763. bool CStaticPropMgr::IsPropInPVS( IHandleEntity *pHandleEntity, const byte *pVis ) const
  1764. {
  1765. // Strip off the bits
  1766. int nIndex = HandleEntityToIndex( pHandleEntity );
  1767. // Get the prop
  1768. const CStaticProp &prop = m_StaticProps[nIndex];
  1769. int i;
  1770. int end = prop.FirstLeaf() + prop.LeafCount();
  1771. for( i = prop.FirstLeaf(); i < end; i++ )
  1772. {
  1773. Assert( i >= 0 && i < m_StaticPropLeaves.Count() );
  1774. int clusterID = CM_LeafCluster( m_StaticPropLeaves[i].m_Leaf );
  1775. if( pVis[ clusterID >> 3 ] & ( 1 << ( clusterID & 7 ) ) )
  1776. {
  1777. return true;
  1778. }
  1779. }
  1780. return false;
  1781. }
  1782. void CStaticPropMgr::DrawStaticProps_Slow( IClientRenderable **pProps, const RenderableInstance_t *pInstances, int count, bool bShadowDepth, bool drawVCollideWireframe )
  1783. {
  1784. VPROF("CStaticPropMgr::DrawStaticProps_Slow");
  1785. // slow mode
  1786. MDLCACHE_CRITICAL_SECTION_( g_pMDLCache );
  1787. int flags = STUDIO_RENDER;
  1788. if (bShadowDepth)
  1789. flags |= STUDIO_SHADOWDEPTHTEXTURE;
  1790. if ( drawVCollideWireframe )
  1791. flags |= STUDIO_WIREFRAME_VCOLLIDE;
  1792. for ( int i = 0; i < count; i++ )
  1793. {
  1794. CStaticProp *pProp = (CStaticProp *)(pProps[i]);
  1795. pProp->DrawModelSlow( flags, pInstances[i] );
  1796. }
  1797. }
  1798. void CStaticPropMgr::DrawStaticProps_Fast( IClientRenderable **pProps, const RenderableInstance_t *pInstances, int count, bool bShadowDepth )
  1799. {
  1800. VPROF("CStaticPropMgr::DrawStaticProps_Fast");
  1801. float color[3];
  1802. color[0] = color[1] = color[2] = 1.0f;
  1803. g_pStudioRender->SetColorModulation(color);
  1804. g_pStudioRender->SetAlphaModulation(1.0f);
  1805. g_pStudioRender->SetViewState( CurrentViewOrigin(), CurrentViewRight(), CurrentViewUp(), CurrentViewForward() );
  1806. CMatRenderContextPtr pRenderContext( materials );
  1807. pRenderContext->MatrixMode( MATERIAL_MODEL );
  1808. pRenderContext->PushMatrix();
  1809. pRenderContext->LoadIdentity();
  1810. ModelRenderInfo_t sInfo;
  1811. sInfo.flags = STUDIO_RENDER | STUDIO_STATIC_LIGHTING;
  1812. if (bShadowDepth)
  1813. sInfo.flags |= STUDIO_SHADOWDEPTHTEXTURE;
  1814. sInfo.entity_index = -1;
  1815. sInfo.body = 0;
  1816. sInfo.hitboxset = 0;
  1817. sInfo.pLightingOffset = NULL;
  1818. for ( int i = 0; i < count; i++ )
  1819. {
  1820. MDLCACHE_CRITICAL_SECTION_( g_pMDLCache );
  1821. CStaticProp *pProp = (CStaticProp *)(pProps[i]);
  1822. if ( !pProp->m_pModel )
  1823. continue;
  1824. sInfo.instance = pProp->m_ModelInstance;
  1825. sInfo.pModel = pProp->m_pModel;
  1826. sInfo.origin = pProp->m_Origin;
  1827. sInfo.angles = pProp->m_Angles;
  1828. sInfo.skin = pProp->m_Skin;
  1829. sInfo.pLightingOrigin = &pProp->m_LightingOrigin;
  1830. sInfo.pModelToWorld = &pProp->m_ModelToWorld;
  1831. sInfo.pRenderable = pProps[i];
  1832. modelrender->DrawModelExStaticProp( pRenderContext, sInfo );
  1833. }
  1834. // Restore the matrices if we're skinning
  1835. pRenderContext->MatrixMode( MATERIAL_MODEL );
  1836. pRenderContext->PopMatrix();
  1837. }
  1838. // NOTE: This is a work in progress for a new static prop (eventually new model) rendering pipeline
  1839. void CStaticPropMgr::DrawStaticProps_FastPipeline( IClientRenderable **pProps, const RenderableInstance_t *pInstances, int count, bool bShadowDepth )
  1840. {
  1841. VPROF("CStaticPropMgr::DrawStaticProps_FastPipeline");
  1842. const int MAX_OBJECTS = 2048;
  1843. StaticPropRenderInfo_t propList[MAX_OBJECTS];
  1844. int listCount = 0;
  1845. if ( count > MAX_OBJECTS )
  1846. {
  1847. DrawStaticProps_FastPipeline( pProps + MAX_OBJECTS, pInstances, count - MAX_OBJECTS, bShadowDepth );
  1848. count = MAX_OBJECTS;
  1849. }
  1850. for ( int i = 0; i < count; i++ )
  1851. {
  1852. CStaticProp *pProp = static_cast< CStaticProp * >(pProps[i]);
  1853. if ( !pProp->m_pModel )
  1854. continue;
  1855. propList[listCount].pModelToWorld = &pProp->m_ModelToWorld;
  1856. propList[listCount].pModel = pProp->m_pModel;
  1857. propList[listCount].instance = pProp->m_ModelInstance;
  1858. propList[listCount].skin = pProp->m_Skin;
  1859. propList[listCount].pRenderable = pProp;
  1860. propList[listCount].pLightingOrigin = &pProp->m_LightingOrigin;
  1861. propList[listCount].alpha = pInstances[i].m_nAlpha;
  1862. listCount++;
  1863. }
  1864. modelrender->DrawStaticPropArrayFast( propList, listCount, bShadowDepth );
  1865. }
  1866. // NOTE: Set this to zero to revert to the previous static prop lighting behavior
  1867. ConVar pipeline_static_props("pipeline_static_props", "1");
  1868. ConVar cl_skipslowpath( "cl_skipslowpath", "0", FCVAR_CHEAT, "Set to 1 to skip any models that don't go through the model fast path" );
  1869. void CStaticPropMgr::DrawStaticProps( IClientRenderable **pProps, const RenderableInstance_t *pInstances, int count, bool bShadowDepth, bool drawVCollideWireframe )
  1870. {
  1871. VPROF_BUDGET( "CStaticPropMgr::DrawStaticProps", VPROF_BUDGETGROUP_STATICPROP_RENDERING );
  1872. if ( !r_drawstaticprops.GetBool() || cl_skipslowpath.GetBool() )
  1873. return;
  1874. if ( IsUsingStaticPropDebugModes() || drawVCollideWireframe || r_slowpathwireframe.GetInt() )
  1875. {
  1876. DrawStaticProps_Slow( pProps, pInstances, count, bShadowDepth, drawVCollideWireframe );
  1877. }
  1878. else
  1879. {
  1880. // the fast pipeline is only supported on dx8+
  1881. if ( pipeline_static_props.GetBool() )
  1882. {
  1883. DrawStaticProps_FastPipeline( pProps, pInstances, count, bShadowDepth );
  1884. }
  1885. else
  1886. {
  1887. DrawStaticProps_Fast( pProps, pInstances, count, bShadowDepth );
  1888. }
  1889. }
  1890. }
  1891. //-----------------------------------------------------------------------------
  1892. // Returns the lightcache handle
  1893. //-----------------------------------------------------------------------------
  1894. LightCacheHandle_t CStaticPropMgr::GetLightCacheHandleForStaticProp( IHandleEntity *pHandleEntity )
  1895. {
  1896. int nIndex = HandleEntityToIndex(pHandleEntity);
  1897. return modelrender->GetStaticLighting( m_StaticProps[ nIndex ].GetModelInstance() );
  1898. }
  1899. //-----------------------------------------------------------------------------
  1900. // Purpose: Trace a ray against the specified static Prop. Returns point of intersection in trace_t
  1901. //-----------------------------------------------------------------------------
  1902. void CStaticPropMgr::TraceRayAgainstStaticProp( const Ray_t& ray, int staticPropIndex, trace_t& tr )
  1903. {
  1904. #ifndef DEDICATED
  1905. // Get the prop
  1906. CStaticProp& prop = m_StaticProps[staticPropIndex];
  1907. if (prop.GetSolid() != SOLID_NONE)
  1908. {
  1909. // FIXME: Better bloat?
  1910. // Bloat a little bit so we get the intersection
  1911. Ray_t temp = ray;
  1912. temp.m_Delta *= 1.1f;
  1913. g_pEngineTraceClient->ClipRayToEntity( temp, MASK_ALL, &prop, &tr );
  1914. }
  1915. else
  1916. {
  1917. // no collision
  1918. tr.fraction = 1.0f;
  1919. }
  1920. #endif
  1921. }
  1922. //-----------------------------------------------------------------------------
  1923. // Adds decals to static props, returns point of decal in trace_t
  1924. //-----------------------------------------------------------------------------
  1925. void CStaticPropMgr::AddDecalToStaticProp( Vector const& rayStart, Vector const& rayEnd,
  1926. int staticPropIndex, int decalIndex, bool doTrace, trace_t& tr, void *pvProxyUserData, const Vector* saxis, int32 nAdditionalDecalFlags )
  1927. {
  1928. #ifndef DEDICATED
  1929. // Invalid static prop? Blow it off!
  1930. if (staticPropIndex >= m_StaticProps.Count())
  1931. {
  1932. memset( &tr, 0, sizeof(trace_t) );
  1933. tr.fraction = 1.0f;
  1934. return;
  1935. }
  1936. Ray_t ray;
  1937. ray.Init( rayStart, rayEnd );
  1938. if (doTrace)
  1939. {
  1940. // Trace the ray against the prop
  1941. TraceRayAgainstStaticProp( ray, staticPropIndex, tr );
  1942. if (tr.fraction == 1.0f)
  1943. return;
  1944. }
  1945. if ( !r_drawmodeldecals.GetInt() )
  1946. return;
  1947. // Get the prop
  1948. CStaticProp& prop = m_StaticProps[staticPropIndex];
  1949. // Found the point, now lets apply the decals
  1950. Assert( prop.GetModelInstance() != MODEL_INSTANCE_INVALID );
  1951. // Choose a new ray along which to project the decal based on
  1952. // surface normal. This prevents decal skewing
  1953. bool noPokethru = false;
  1954. if (doTrace && (prop.GetSolid() == SOLID_VPHYSICS) && !tr.startsolid && !tr.allsolid)
  1955. {
  1956. Vector temp;
  1957. VectorSubtract( tr.endpos, tr.plane.normal, temp );
  1958. ray.Init( tr.endpos, temp );
  1959. noPokethru = true;
  1960. }
  1961. // Player sprays attempt to limit the smearing and backfaces application?
  1962. // but this code doesn't seem to work
  1963. /*
  1964. if ( !doTrace && !noPokethru && pvProxyUserData )
  1965. {
  1966. if ( (prop.GetSolid() == SOLID_VPHYSICS) && !tr.startsolid && !tr.allsolid )
  1967. {
  1968. Vector temp;
  1969. VectorSubtract( tr.endpos, tr.plane.normal, temp );
  1970. ray.Init( tr.endpos, temp );
  1971. noPokethru = true;
  1972. }
  1973. }
  1974. */
  1975. // FIXME: What to do about the body parameter?
  1976. Vector up(0, 0, 1);
  1977. if ( saxis )
  1978. {
  1979. up = (*saxis).Cross( rayEnd - rayStart );
  1980. }
  1981. modelrender->AddDecal( prop.GetModelInstance(), ray, up, decalIndex, 0, noPokethru, ADDDECAL_TO_ALL_LODS, NULL, 1.0f, 1.0f, pvProxyUserData, nAdditionalDecalFlags );
  1982. #endif
  1983. }
  1984. //-----------------------------------------------------------------------------
  1985. // Adds/removes shadows from static props
  1986. //-----------------------------------------------------------------------------
  1987. void CStaticPropMgr::AddShadowToStaticProp( unsigned short shadowHandle, IClientRenderable* pRenderable )
  1988. {
  1989. #ifndef DEDICATED
  1990. Assert( dynamic_cast<CStaticProp*>(pRenderable) != 0 );
  1991. CStaticProp* pProp = static_cast<CStaticProp*>(pRenderable);
  1992. g_pShadowMgr->AddShadowToModel( shadowHandle, pProp->GetModelInstance() );
  1993. #endif
  1994. }
  1995. void CStaticPropMgr::RemoveAllShadowsFromStaticProp( IClientRenderable* pRenderable )
  1996. {
  1997. #ifndef DEDICATED
  1998. Assert( dynamic_cast<CStaticProp*>(pRenderable) != 0 );
  1999. CStaticProp* pProp = static_cast<CStaticProp*>(pRenderable);
  2000. if (pProp->GetModelInstance() != MODEL_INSTANCE_INVALID)
  2001. {
  2002. g_pShadowMgr->RemoveAllShadowsFromModel( pProp->GetModelInstance() );
  2003. }
  2004. #endif
  2005. }
  2006. //-----------------------------------------------------------------------------
  2007. // disable rendering into cascade shadow maps
  2008. // TODO: flag could/should be set in vrad
  2009. //-----------------------------------------------------------------------------
  2010. void CStaticPropMgr::DisableCSMRenderingForStaticProp( int staticPropIndex )
  2011. {
  2012. // Invalid static prop? Blow it off!
  2013. if ( staticPropIndex >= m_StaticProps.Count() )
  2014. {
  2015. return;
  2016. }
  2017. // Get the prop
  2018. CStaticProp& prop = m_StaticProps[staticPropIndex];
  2019. if ( !( prop.Flags() & STATIC_PROP_NO_PER_VERTEX_LIGHTING ) )
  2020. {
  2021. prop.DisableCSMRendering();
  2022. }
  2023. }
  2024. //-----------------------------------------------------------------------------
  2025. // Gets the lighting + material color of a static prop
  2026. //-----------------------------------------------------------------------------
  2027. void CStaticPropMgr::GetStaticPropMaterialColorAndLighting( trace_t* pTrace,
  2028. int staticPropIndex, Vector& lighting, Vector& matColor )
  2029. {
  2030. #ifndef DEDICATED
  2031. // Invalid static prop? Blow it off!
  2032. if (staticPropIndex >= m_StaticProps.Count())
  2033. {
  2034. lighting.Init( 0, 0, 0 );
  2035. matColor.Init( 1, 1, 1 );
  2036. return;
  2037. }
  2038. // Get the prop
  2039. CStaticProp& prop = m_StaticProps[staticPropIndex];
  2040. // Ask the model info about what we need to know
  2041. modelinfoclient->GetModelMaterialColorAndLighting( (model_t*)prop.GetModel(),
  2042. prop.GetRenderOrigin(), prop.GetRenderAngles(), pTrace, lighting, matColor );
  2043. #endif
  2044. }
  2045. //-----------------------------------------------------------------------------
  2046. // Little debugger tool to report which prop we're looking at
  2047. //-----------------------------------------------------------------------------
  2048. void Cmd_PropCrosshair_f (void)
  2049. {
  2050. Vector endPoint;
  2051. VectorMA( MainViewOrigin(), COORD_EXTENT * 1.74f, MainViewForward(), endPoint );
  2052. Ray_t ray;
  2053. ray.Init( MainViewOrigin(), endPoint );
  2054. trace_t tr;
  2055. CTraceFilterWorldAndPropsOnly traceFilter;
  2056. g_pEngineTraceServer->TraceRay( ray, MASK_ALL, &traceFilter, &tr );
  2057. if ( tr.hitbox > 0 )
  2058. Msg( "hit prop %d\n", tr.hitbox - 1 );
  2059. else
  2060. Msg( "didn't hit a prop\n" );
  2061. }
  2062. static ConCommand prop_crosshair( "prop_crosshair", Cmd_PropCrosshair_f, "Shows name for prop looking at", FCVAR_CHEAT );