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.

3069 lines
96 KiB

  1. //===== Copyright 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose: Draws grasses and other small objects
  4. //
  5. // $Revision: $
  6. // $NoKeywords: $
  7. //===========================================================================//
  8. #include "cbase.h"
  9. #undef max
  10. #undef min
  11. #include <algorithm>
  12. #include "detailobjectsystem.h"
  13. #include "gamebspfile.h"
  14. #include "utlbuffer.h"
  15. #include "tier1/utlmap.h"
  16. #include "view.h"
  17. #include "clientmode.h"
  18. #include "iviewrender.h"
  19. #include "bsptreedata.h"
  20. #include "tier0/vprof.h"
  21. #include "engine/ivmodelinfo.h"
  22. #include "materialsystem/imesh.h"
  23. #include "model_types.h"
  24. #include "env_detail_controller.h"
  25. #include "tier0/icommandline.h"
  26. #include "tier1/callqueue.h"
  27. #include "c_world.h"
  28. #if defined(CSTRIKE_DLL)
  29. #define USE_DETAIL_SHAPES
  30. #endif
  31. #ifdef USE_DETAIL_SHAPES
  32. #include "engine/ivdebugoverlay.h"
  33. #include "playerenumerator.h"
  34. #endif
  35. #include "materialsystem/imaterialsystemhardwareconfig.h"
  36. // memdbgon must be the last include file in a .cpp file!!!
  37. #include "tier0/memdbgon.h"
  38. #define DETAIL_SPRITE_MATERIAL "detail/detailsprites"
  39. //-----------------------------------------------------------------------------
  40. // forward declarations
  41. //-----------------------------------------------------------------------------
  42. struct model_t;
  43. #if defined( USE_DETAIL_SHAPES )
  44. ConVar cl_detail_max_sway( "cl_detail_max_sway", "0", FCVAR_ARCHIVE, "Amplitude of the detail prop sway" );
  45. ConVar cl_detail_avoid_radius( "cl_detail_avoid_radius", "0", FCVAR_ARCHIVE, "radius around detail sprite to avoid players" );
  46. ConVar cl_detail_avoid_force( "cl_detail_avoid_force", "0", FCVAR_ARCHIVE, "force with which to avoid players ( in units, percentage of the width of the detail sprite )" );
  47. ConVar cl_detail_avoid_recover_speed( "cl_detail_avoid_recover_speed", "0", FCVAR_ARCHIVE, "how fast to recover position after avoiding players" );
  48. #endif
  49. ConVar r_FlashlightDetailProps( "r_FlashlightDetailProps", "1", 0, "Enable a flashlight drawing pass on detail props. 0 = off, 1 = single pass, 2 = multipass (multipass is PC ONLY)" );
  50. ConVar r_ThreadedDetailProps( "r_threadeddetailprops", "1", 0, "enable threading of detail prop drawing" );
  51. enum DetailPropFlashlightMode_t
  52. {
  53. DPFM_NONE,
  54. DPFM_SINGLEPASS,
  55. DPFM_MULTIPASS,
  56. };
  57. inline DetailPropFlashlightMode_t DetailPropFlashlightMode( void )
  58. {
  59. switch( r_FlashlightDetailProps.GetInt() )
  60. {
  61. case 1:
  62. return DPFM_SINGLEPASS;
  63. #ifndef _GAMECONSOLE
  64. case 2:
  65. return DPFM_MULTIPASS;
  66. #endif
  67. case 0:
  68. default:
  69. return DPFM_NONE;
  70. }
  71. }
  72. // Per detail instance information
  73. struct DetailModelAdvInfo_t
  74. {
  75. // precaculated angles for shaped sprites
  76. Vector m_vecAnglesForward[3];
  77. Vector m_vecAnglesRight[3]; // better to save this mem and calc per sprite ?
  78. Vector m_vecAnglesUp[3];
  79. // direction we're avoiding the player
  80. Vector m_vecCurrentAvoid;
  81. // yaw to sway on
  82. float m_flSwayYaw;
  83. // size of the shape
  84. float m_flShapeSize;
  85. int m_iShapeAngle;
  86. float m_flSwayAmount;
  87. };
  88. class CDetailObjectSystemPerLeafData
  89. {
  90. unsigned short m_FirstDetailProp;
  91. unsigned short m_DetailPropCount;
  92. int m_DetailPropRenderFrame;
  93. CDetailObjectSystemPerLeafData( void )
  94. {
  95. m_FirstDetailProp = 0;
  96. m_DetailPropCount = 0;
  97. m_DetailPropRenderFrame = -1;
  98. }
  99. };
  100. static void DrawMeshCallback( void *pMesh )
  101. {
  102. ((IMesh *)pMesh)->Draw();
  103. }
  104. //-----------------------------------------------------------------------------
  105. // Detail models
  106. //-----------------------------------------------------------------------------
  107. struct SpriteInfo_t
  108. {
  109. unsigned short m_nSpriteIndex;
  110. float16 m_flScale;
  111. };
  112. class CDetailModel : public IClientUnknown, public IClientRenderable
  113. {
  114. DECLARE_CLASS_NOBASE( CDetailModel );
  115. public:
  116. CDetailModel();
  117. ~CDetailModel();
  118. // Initialization
  119. bool InitCommon( int index, const Vector& org, const QAngle& angles );
  120. bool Init( int index, const Vector& org, const QAngle& angles, model_t* pModel,
  121. ColorRGBExp32 lighting, int lightstyle, unsigned char lightstylecount, int orientation );
  122. bool InitSprite( int index, bool bFlipped, const Vector& org, const QAngle& angles,
  123. unsigned short nSpriteIndex,
  124. ColorRGBExp32 lighting, int lightstyle, unsigned char lightstylecount,
  125. int orientation, float flScale, unsigned char type,
  126. unsigned char shapeAngle, unsigned char shapeSize, unsigned char swayAmount );
  127. bool IsTranslucent() const { return m_bIsTranslucent; }
  128. // IClientUnknown overrides.
  129. public:
  130. virtual IClientUnknown* GetIClientUnknown() { return this; }
  131. virtual ICollideable* GetCollideable() { return 0; } // Static props DO implement this.
  132. virtual IClientNetworkable* GetClientNetworkable() { return 0; }
  133. virtual IClientRenderable* GetClientRenderable() { return this; }
  134. virtual IClientEntity* GetIClientEntity() { return 0; }
  135. virtual C_BaseEntity* GetBaseEntity() { return 0; }
  136. virtual IClientThinkable* GetClientThinkable() { return 0; }
  137. virtual IClientModelRenderable* GetClientModelRenderable() { return 0; }
  138. virtual IClientAlphaProperty* GetClientAlphaProperty() { return 0; }
  139. // IClientRenderable overrides.
  140. public:
  141. virtual int GetBody() { return 0; }
  142. virtual const Vector& GetRenderOrigin( );
  143. virtual const QAngle& GetRenderAngles( );
  144. virtual const matrix3x4_t & RenderableToWorldTransform();
  145. virtual bool ShouldDraw();
  146. virtual uint8 OverrideAlphaModulation( uint8 nAlpha ) { return nAlpha; }
  147. virtual uint8 OverrideShadowAlphaModulation( uint8 nAlpha ) { return nAlpha; }
  148. virtual void OnThreadedDrawSetup() {}
  149. virtual const model_t* GetModel( ) const;
  150. virtual int DrawModel( int flags, const RenderableInstance_t &instance );
  151. virtual bool SetupBones( matrix3x4a_t *pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime );
  152. virtual void SetupWeights( const matrix3x4_t *pBoneToWorld, int nFlexWeightCount, float *pFlexWeights, float *pFlexDelayedWeights );
  153. virtual bool UsesFlexDelayedWeights() { return false; }
  154. virtual void DoAnimationEvents( void );
  155. virtual void GetRenderBounds( Vector& mins, Vector& maxs );
  156. virtual IPVSNotify* GetPVSNotifyInterface();
  157. virtual void GetRenderBoundsWorldspace( Vector& mins, Vector& maxs );
  158. virtual bool ShouldReceiveProjectedTextures( int flags );
  159. virtual bool GetShadowCastDistance( float *pDist, ShadowType_t shadowType ) const { return false; }
  160. virtual bool GetShadowCastDirection( Vector *pDirection, ShadowType_t shadowType ) const { return false; }
  161. virtual int GetRenderFlags( void );
  162. virtual bool LODTest() { return true; }
  163. virtual ClientShadowHandle_t GetShadowHandle() const;
  164. virtual ClientRenderHandle_t& RenderHandle();
  165. virtual void GetShadowRenderBounds( Vector &mins, Vector &maxs, ShadowType_t shadowType );
  166. virtual bool IsShadowDirty( ) { return false; }
  167. virtual void MarkShadowDirty( bool bDirty ) {}
  168. virtual IClientRenderable *GetShadowParent() { return NULL; }
  169. virtual IClientRenderable *FirstShadowChild(){ return NULL; }
  170. virtual IClientRenderable *NextShadowPeer() { return NULL; }
  171. virtual ShadowType_t ShadowCastType() { return SHADOWS_NONE; }
  172. virtual void CreateModelInstance() {}
  173. virtual ModelInstanceHandle_t GetModelInstance() { return MODEL_INSTANCE_INVALID; }
  174. virtual int LookupAttachment( const char *pAttachmentName ) { return -1; }
  175. virtual bool GetAttachment( int number, matrix3x4_t &matrix );
  176. virtual bool GetAttachment( int number, Vector &origin, QAngle &angles );
  177. virtual bool ComputeLightingOrigin( int nAttachmentIndex, Vector modelLightingCenter, const matrix3x4_t &matrix, Vector &transformedLightingCenter );
  178. virtual float * GetRenderClipPlane() { return NULL; }
  179. virtual int GetSkin() { return 0; }
  180. virtual void RecordToolMessage() {}
  181. virtual bool ShouldDrawForSplitScreenUser( int nSlot ) { return true; }
  182. void GetColorModulation( float* color );
  183. // Computes the render angles for screen alignment
  184. void ComputeAngles( void );
  185. // Calls the correct rendering func
  186. void DrawSprite( CMeshBuilder &meshBuilder, uint8 nAlpha );
  187. // Returns the number of quads the sprite will draw
  188. int QuadsToDraw() const;
  189. // Draw functions for the different types of sprite
  190. void DrawTypeSprite( CMeshBuilder &meshBuilder, uint8 nAlpha );
  191. #ifdef USE_DETAIL_SHAPES
  192. void DrawTypeShapeCross( CMeshBuilder &meshBuilder, uint8 nAlpha );
  193. void DrawTypeShapeTri( CMeshBuilder &meshBuilder, uint8 nAlpha );
  194. // check for players nearby and angle away from them
  195. void UpdatePlayerAvoid( void );
  196. void InitShapedSprite( unsigned char shapeAngle, unsigned char shapeSize, unsigned char swayAmount );
  197. void InitShapeTri();
  198. void InitShapeCross();
  199. void DrawSwayingQuad( CMeshBuilder &meshBuilder, Vector vecOrigin, Vector vecSway, Vector2D texul, Vector2D texlr, unsigned char *color,
  200. Vector width, Vector height );
  201. #endif
  202. int GetType() const { return m_Type; }
  203. bool IsDetailModelTranslucent();
  204. // IHandleEntity stubs.
  205. public:
  206. virtual void SetRefEHandle( const CBaseHandle &handle ) { Assert( false ); }
  207. virtual const CBaseHandle& GetRefEHandle() const { Assert( false ); return *((CBaseHandle*)0); }
  208. //---------------------------------
  209. struct LightStyleInfo_t
  210. {
  211. unsigned int m_LightStyle:24;
  212. unsigned int m_LightStyleCount:8;
  213. };
  214. protected:
  215. Vector m_Origin;
  216. QAngle m_Angles;
  217. ColorRGBExp32 m_Color;
  218. unsigned char m_Orientation:2;
  219. unsigned char m_Type:2;
  220. unsigned char m_bHasLightStyle:1;
  221. unsigned char m_bFlipped:1;
  222. unsigned char m_bIsTranslucent:1;
  223. static CUtlMap<CDetailModel *, LightStyleInfo_t> gm_LightStylesMap;
  224. #pragma warning( disable : 4201 ) //warning C4201: nonstandard extension used : nameless struct/union
  225. union
  226. {
  227. model_t* m_pModel;
  228. SpriteInfo_t m_SpriteInfo;
  229. };
  230. #pragma warning( default : 4201 )
  231. #ifdef USE_DETAIL_SHAPES
  232. // pointer to advanced properties
  233. DetailModelAdvInfo_t *m_pAdvInfo;
  234. #endif
  235. };
  236. static ConVar mat_fullbright( "mat_fullbright", "0", FCVAR_CHEAT ); // hook into engine's cvars..
  237. extern ConVar r_DrawDetailProps;
  238. //-----------------------------------------------------------------------------
  239. // Dictionary for detail sprites
  240. //-----------------------------------------------------------------------------
  241. struct DetailPropSpriteDict_t
  242. {
  243. Vector2D m_UL; // Coordinate of upper left
  244. Vector2D m_LR; // Coordinate of lower right
  245. Vector2D m_TexUL; // Texcoords of upper left
  246. Vector2D m_TexLR; // Texcoords of lower left
  247. };
  248. struct FastSpriteX4_t
  249. {
  250. // mess with this structure without care and you'll be in a world of trouble. layout matters.
  251. FourVectors m_Pos;
  252. fltx4 m_HalfWidth;
  253. fltx4 m_Height;
  254. uint8 m_RGBColor[4][4];
  255. DetailPropSpriteDict_t *m_pSpriteDefs[4];
  256. void ReplicateFirstEntryToOthers( void )
  257. {
  258. m_HalfWidth = ReplicateX4( SubFloat( m_HalfWidth, 0 ) );
  259. m_Height = ReplicateX4( SubFloat( m_Height, 0 ) );
  260. for( int i = 1; i < 4; i++ )
  261. for( int j = 0; j < 4; j++ )
  262. {
  263. m_RGBColor[i][j] = m_RGBColor[0][j];
  264. }
  265. m_Pos.x = ReplicateX4( SubFloat( m_Pos.x, 0 ) );
  266. m_Pos.y = ReplicateX4( SubFloat( m_Pos.y, 0 ) );
  267. m_Pos.z = ReplicateX4( SubFloat( m_Pos.z, 0 ) );
  268. }
  269. };
  270. struct FastSpriteQuadBuildoutBufferX4_t
  271. {
  272. // mess with this structure without care and you'll be in a world of trouble. layout matters.
  273. FourVectors m_Coords[4];
  274. uint8 m_RGBColor[4][4];
  275. fltx4 m_Alpha;
  276. DetailPropSpriteDict_t *m_pSpriteDefs[4];
  277. Vector4D m_Normal;
  278. };
  279. struct FastSpriteQuadBuildoutBufferNonSIMDView_t
  280. {
  281. // mess with this structure without care and you'll be in a world of trouble. layout matters.
  282. float m_flX0[4], m_flY0[4], m_flZ0[4];
  283. float m_flX1[4], m_flY1[4], m_flZ1[4];
  284. float m_flX2[4], m_flY2[4], m_flZ2[4];
  285. float m_flX3[4], m_flY3[4], m_flZ3[4];
  286. uint8 m_RGBColor[4][4];
  287. float m_Alpha[4];
  288. DetailPropSpriteDict_t *m_pSpriteDefs[4];
  289. Vector4D m_Normal;
  290. };
  291. FourVectors vgarbage;
  292. class CFastDetailLeafSpriteList : public CClientLeafSubSystemData
  293. {
  294. friend class CDetailObjectSystem;
  295. int m_nNumSprites;
  296. int m_nNumSIMDSprites; // #sprites/4, rounded up
  297. // simd pointers into larger array - don't free individually or you will be sad
  298. FastSpriteX4_t *m_pSprites;
  299. // state for partially drawn sprite lists
  300. int m_nNumPendingSprites;
  301. int m_nStartSpriteIndex;
  302. CFastDetailLeafSpriteList( void )
  303. {
  304. m_nNumPendingSprites = 0;
  305. m_nStartSpriteIndex = 0;
  306. }
  307. void TouchData( void )
  308. {
  309. vgarbage.x = Four_Zeros;
  310. vgarbage.y = Four_Zeros;
  311. vgarbage.z = Four_Zeros;
  312. for( int i =0; i < m_nNumSIMDSprites; i++ )
  313. {
  314. vgarbage += m_pSprites[i].m_Pos;
  315. }
  316. }
  317. };
  318. #define CACHED_SPRITE_SUB_SPLIT_COUNT 16
  319. //-----------------------------------------------------------------------------
  320. // Responsible for managing detail objects
  321. //-----------------------------------------------------------------------------
  322. class CDetailObjectSystem : public IDetailObjectSystem
  323. {
  324. public:
  325. char const *Name() { return "DetailObjectSystem"; }
  326. // constructor, destructor
  327. CDetailObjectSystem();
  328. ~CDetailObjectSystem();
  329. bool IsPerFrame() { return false; }
  330. // Init, shutdown
  331. bool Init()
  332. {
  333. m_flDetailFadeStart = 0.0f;
  334. m_flDetailFadeEnd = 0.0f;
  335. return true;
  336. }
  337. void PostInit() {}
  338. void Shutdown() {}
  339. // Level init, shutdown
  340. void LevelInitPreEntity();
  341. void LevelInitPostEntity();
  342. void LevelShutdownPreEntity();
  343. void LevelShutdownPostEntity();
  344. void OnSave() {}
  345. void OnRestore() {}
  346. void SafeRemoveIfDesired() {}
  347. // Gets a particular detail object
  348. virtual IClientRenderable* GetDetailModel( int idx );
  349. virtual int GetDetailModelCount() const;
  350. virtual void BuildRenderingData( DetailRenderableList_t &list, const SetupRenderInfo_t &info, float flDetailDist, const DistanceFadeInfo_t &fadeInfo );
  351. virtual float ComputeDetailFadeInfo( DistanceFadeInfo_t *pInfo );
  352. // Renders all opaque detail objects in a particular set of leaves
  353. void RenderOpaqueDetailObjects( int nLeafCount, LeafIndex_t *pLeafList );
  354. // Renders all translucent detail objects in a particular set of leaves
  355. void RenderTranslucentDetailObjects( const DistanceFadeInfo_t &info, const Vector &viewOrigin, const Vector &viewForward, const Vector &viewRight, const Vector &viewUp, int nLeafCount, LeafIndex_t *pLeafList );
  356. // Renders all translucent detail objects in a particular leaf up to a particular point
  357. void RenderTranslucentDetailObjectsInLeaf( const DistanceFadeInfo_t &info, const Vector &viewOrigin, const Vector &viewForward, const Vector &viewRight, const Vector &viewUp, int nLeaf, const Vector *pVecClosestPoint );
  358. void RenderFastTranslucentDetailObjectsInLeaf( CFastDetailLeafSpriteList *pData, const DistanceFadeInfo_t &info, const Vector &viewOrigin, const Vector &viewForward, const Vector &viewRight, const Vector &viewUp, int nLeaf, const Vector &vecClosestPoint, bool bFirstLeaf );
  359. // Call this before rendering translucent detail objects
  360. void BeginTranslucentDetailRendering( );
  361. DetailPropLightstylesLump_t& DetailLighting( int i ) { return m_DetailLighting[i]; }
  362. DetailPropSpriteDict_t& DetailSpriteDict( int i ) { return m_DetailSpriteDict[i]; }
  363. void RenderFastSprites( const DistanceFadeInfo_t &info, const Vector &viewOrigin, const Vector &viewForward, const Vector &viewRight, const Vector &viewUp, int nLeafCount, LeafIndex_t const * pLeafList );
  364. uint8 ComputeDistanceFade( float *pDistSqr, const DistanceFadeInfo_t &info, const Vector &vecViewOrigin, const Vector &vecRenderOrigin ) const;
  365. void UpdateDetailFadeValues();
  366. #if defined(_PS3)
  367. virtual bool ShouldDrawDetailObjects( void );
  368. virtual void GetDetailFadeValues( float &flDetailFadeStart, float &flDetailFadeEnd );
  369. int GetDetailObjectsCount( void ) { return m_DetailObjects.Count(); };
  370. void *GetDetailObjectsBase( void ) { return (void *)m_DetailObjects.Base(); };
  371. void *GetDetailObjectsOriginOffset( void ) { return (void *)&m_DetailObjects.Base()->GetRenderOrigin(); };
  372. int GetCDetailModelStride( void ) { return sizeof(CDetailModel); };
  373. #endif
  374. private:
  375. struct DetailModelDict_t
  376. {
  377. model_t* m_pModel;
  378. };
  379. struct EnumContext_t
  380. {
  381. Vector m_vViewOrigin;
  382. int m_BuildWorldListNumber;
  383. };
  384. struct SortInfo_t
  385. {
  386. int m_nIndex : 24;
  387. int m_nAlpha : 8;
  388. float m_flDistance;
  389. };
  390. int BuildOutSortedSprites( CFastDetailLeafSpriteList *pData,
  391. const DistanceFadeInfo_t &info,
  392. Vector const &viewOrigin,
  393. Vector const &viewForward,
  394. Vector const &viewRight,
  395. Vector const &viewUp );
  396. void UnserializeFastSprite( FastSpriteX4_t *pSpritex4, int nSubField, DetailObjectLump_t const &lump, bool bFlipped, Vector const &posOffset );
  397. // Unserialization
  398. void ScanForCounts( CUtlBuffer& buf, int *pNumOldStyleObjects,
  399. int *pNumFastSpritesToAllocate, int *nMaxOldInLeaf,
  400. int *nMaxFastInLeaf ) const;
  401. void UnserializeModelDict( CUtlBuffer& buf );
  402. void UnserializeDetailSprites( CUtlBuffer& buf );
  403. void UnserializeModels( CUtlBuffer& buf );
  404. void UnserializeModelLighting( CUtlBuffer& buf );
  405. Vector GetSpriteMiddleBottomPosition( DetailObjectLump_t const &lump ) const;
  406. // Count the number of detail sprites in the leaf list
  407. int CountSpritesInLeafList( int nLeafCount, LeafIndex_t *pLeafList ) const;
  408. // Count the number of detail sprite quads in the leaf list
  409. int CountSpriteQuadsInLeafList( int nLeafCount, LeafIndex_t *pLeafList ) const;
  410. int CountFastSpritesInLeafList( int nLeafCount, LeafIndex_t const *pLeafList, int *nMaxInLeaf ) const;
  411. void FreeSortBuffers( void );
  412. // Sorts sprites in back-to-front order
  413. static bool SortLessFunc( const SortInfo_t &left, const SortInfo_t &right );
  414. int SortSpritesBackToFront( int nLeaf, const Vector &viewOrigin, const DistanceFadeInfo_t &fadeInfo, SortInfo_t *pSortInfo );
  415. // For fast detail object insertion
  416. IterationRetval_t EnumElement( int userId, int context );
  417. CUtlVector<DetailModelDict_t> m_DetailObjectDict;
  418. CUtlVector<CDetailModel> m_DetailObjects;
  419. CUtlVector<DetailPropSpriteDict_t> m_DetailSpriteDict;
  420. CUtlVector<DetailPropSpriteDict_t> m_DetailSpriteDictFlipped;
  421. CUtlVector<DetailPropLightstylesLump_t> m_DetailLighting;
  422. FastSpriteX4_t *m_pFastSpriteData;
  423. // Necessary to get sprites to batch correctly
  424. CMaterialReference m_DetailSpriteMaterial;
  425. CMaterialReference m_DetailWireframeMaterial;
  426. // State stored off for rendering detail sprites in a single leaf
  427. int m_nSpriteCount;
  428. int m_nFirstSprite;
  429. int m_nSortedLeaf;
  430. int m_nSortedFastLeaf;
  431. SortInfo_t *m_pSortInfo;
  432. SortInfo_t *m_pFastSortInfo;
  433. FastSpriteQuadBuildoutBufferX4_t *m_pBuildoutBuffer;
  434. bool m_bFirstLeaf;
  435. float m_flDetailFadeStart;
  436. float m_flDetailFadeEnd;
  437. IMesh *m_pCachedSpriteMesh[MAX_MAP_LEAFS][CACHED_SPRITE_SUB_SPLIT_COUNT];
  438. CUtlVector<IMesh**> m_nCachedSpriteMeshPtrs;
  439. CUniformRandomStream m_randomStream;
  440. void DestroyCachedSpriteMeshes( void );
  441. };
  442. //-----------------------------------------------------------------------------
  443. // System for dealing with detail objects
  444. //-----------------------------------------------------------------------------
  445. static CDetailObjectSystem s_DetailObjectSystem;
  446. IDetailObjectSystem *g_pDetailObjectSystem = &s_DetailObjectSystem;
  447. static void DetailFadeCallback( IConVar *var, const char *pOldValue, float flOldValue )
  448. {
  449. s_DetailObjectSystem.UpdateDetailFadeValues();
  450. }
  451. //ConVar cl_detaildist( "cl_detaildist", "2000", FCVAR_DEVELOPMENTONLY, "Distance at which detail props are no longer visible", DetailFadeCallback );
  452. //ConVar cl_detailfade( "cl_detailfade", "400", FCVAR_DEVELOPMENTONLY, "Distance across which detail props fade in", DetailFadeCallback );
  453. //-----------------------------------------------------------------------------
  454. // Initialization
  455. //-----------------------------------------------------------------------------
  456. CUtlMap<CDetailModel *, CDetailModel::LightStyleInfo_t> CDetailModel::gm_LightStylesMap( DefLessFunc( CDetailModel * ) );
  457. bool CDetailModel::InitCommon( int index, const Vector& org, const QAngle& angles )
  458. {
  459. VectorCopy( org, m_Origin );
  460. VectorCopy( angles, m_Angles );
  461. return true;
  462. }
  463. //-----------------------------------------------------------------------------
  464. // Inline methods
  465. //-----------------------------------------------------------------------------
  466. // NOTE: If DetailPropType_t enum changes, change CDetailModel::QuadsToDraw
  467. static int s_pQuadCount[4] =
  468. {
  469. 0, //DETAIL_PROP_TYPE_MODEL
  470. 1, //DETAIL_PROP_TYPE_SPRITE
  471. 4, //DETAIL_PROP_TYPE_SHAPE_CROSS
  472. 3, //DETAIL_PROP_TYPE_SHAPE_TRI
  473. };
  474. inline int CDetailModel::QuadsToDraw() const
  475. {
  476. return s_pQuadCount[m_Type];
  477. }
  478. //-----------------------------------------------------------------------------
  479. // Data accessors
  480. //-----------------------------------------------------------------------------
  481. const Vector& CDetailModel::GetRenderOrigin( void )
  482. {
  483. return m_Origin;
  484. }
  485. const QAngle& CDetailModel::GetRenderAngles( void )
  486. {
  487. return m_Angles;
  488. }
  489. const matrix3x4_t &CDetailModel::RenderableToWorldTransform()
  490. {
  491. // Setup our transform.
  492. static matrix3x4_t mat;
  493. AngleMatrix( GetRenderAngles(), GetRenderOrigin(), mat );
  494. return mat;
  495. }
  496. bool CDetailModel::GetAttachment( int number, matrix3x4_t &matrix )
  497. {
  498. MatrixCopy( RenderableToWorldTransform(), matrix );
  499. return true;
  500. }
  501. bool CDetailModel::GetAttachment( int number, Vector &origin, QAngle &angles )
  502. {
  503. origin = m_Origin;
  504. angles = m_Angles;
  505. return true;
  506. }
  507. bool CDetailModel::ComputeLightingOrigin( int nAttachmentIndex, Vector modelLightingCenter, const matrix3x4_t &matrix, Vector &transformedLightingCenter )
  508. {
  509. if ( nAttachmentIndex <= 0 )
  510. {
  511. VectorTransform( modelLightingCenter, matrix, transformedLightingCenter );
  512. }
  513. else
  514. {
  515. matrix3x4_t attachmentTransform;
  516. GetAttachment( nAttachmentIndex, attachmentTransform );
  517. VectorTransform( modelLightingCenter, attachmentTransform, transformedLightingCenter );
  518. }
  519. return true;
  520. }
  521. bool CDetailModel::ShouldDraw()
  522. {
  523. // Don't draw in commander mode
  524. return GetClientMode()->ShouldDrawDetailObjects();
  525. }
  526. void CDetailModel::GetRenderBounds( Vector& mins, Vector& maxs )
  527. {
  528. if ( m_Type == DETAIL_PROP_TYPE_MODEL )
  529. {
  530. int nModelType = modelinfo->GetModelType( m_pModel );
  531. if ( nModelType == mod_studio || nModelType == mod_brush )
  532. {
  533. modelinfo->GetModelRenderBounds( GetModel(), mins, maxs );
  534. }
  535. else
  536. {
  537. mins.Init( 0,0,0 );
  538. maxs.Init( 0,0,0 );
  539. }
  540. return;
  541. }
  542. // NOTE: Sway isn't taken into account here
  543. DetailPropSpriteDict_t &dict = s_DetailObjectSystem.DetailSpriteDict( m_SpriteInfo.m_nSpriteIndex );
  544. Vector2D ul, lr;
  545. float flScale = m_SpriteInfo.m_flScale.GetFloat();
  546. Vector2DMultiply( dict.m_UL, flScale, ul );
  547. Vector2DMultiply( dict.m_LR, flScale, lr );
  548. float flSizeX = MAX( fabs(lr.x), fabs(ul.x) );
  549. float flSizeY = MAX( fabs(lr.y), fabs(ul.y) );
  550. float flRadius = sqrt( flSizeX * flSizeX + flSizeY * flSizeY );
  551. mins.Init( -flRadius, -flRadius, -flRadius );
  552. maxs.Init( flRadius, flRadius, flRadius );
  553. }
  554. IPVSNotify* CDetailModel::GetPVSNotifyInterface()
  555. {
  556. return NULL;
  557. }
  558. void CDetailModel::GetRenderBoundsWorldspace( Vector& mins, Vector& maxs )
  559. {
  560. DefaultRenderBoundsWorldspace( this, mins, maxs );
  561. }
  562. bool CDetailModel::ShouldReceiveProjectedTextures( int flags )
  563. {
  564. return false;
  565. }
  566. int CDetailModel::GetRenderFlags( void )
  567. {
  568. return 0;
  569. }
  570. void CDetailModel::GetShadowRenderBounds( Vector &mins, Vector &maxs, ShadowType_t shadowType )
  571. {
  572. GetRenderBounds( mins, maxs );
  573. }
  574. ClientShadowHandle_t CDetailModel::GetShadowHandle() const
  575. {
  576. return CLIENTSHADOW_INVALID_HANDLE;
  577. }
  578. ClientRenderHandle_t& CDetailModel::RenderHandle()
  579. {
  580. AssertMsg( 0, "CDetailModel has no render handle" );
  581. return *((ClientRenderHandle_t*)NULL);
  582. }
  583. //-----------------------------------------------------------------------------
  584. // Render setup
  585. //-----------------------------------------------------------------------------
  586. bool CDetailModel::SetupBones( matrix3x4a_t *pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime )
  587. {
  588. if (!m_pModel)
  589. return false;
  590. // Setup our transform.
  591. matrix3x4a_t parentTransform;
  592. const QAngle &vRenderAngles = GetRenderAngles();
  593. const Vector &vRenderOrigin = GetRenderOrigin();
  594. AngleMatrix( vRenderAngles, parentTransform );
  595. parentTransform[0][3] = vRenderOrigin.x;
  596. parentTransform[1][3] = vRenderOrigin.y;
  597. parentTransform[2][3] = vRenderOrigin.z;
  598. // Just copy it on down baby
  599. studiohdr_t *pStudioHdr = modelinfo->GetStudiomodel( m_pModel );
  600. for (int i = 0; i < pStudioHdr->numbones; i++)
  601. {
  602. MatrixCopy( parentTransform, pBoneToWorldOut[i] );
  603. }
  604. return true;
  605. }
  606. void CDetailModel::SetupWeights( const matrix3x4_t *pBoneToWorld, int nFlexWeightCount, float *pFlexWeights, float *pFlexDelayedWeights )
  607. {
  608. }
  609. void CDetailModel::DoAnimationEvents( void )
  610. {
  611. }
  612. //-----------------------------------------------------------------------------
  613. // Render baby!
  614. //-----------------------------------------------------------------------------
  615. const model_t* CDetailModel::GetModel( ) const
  616. {
  617. return m_pModel;
  618. }
  619. int CDetailModel::DrawModel( int flags, const RenderableInstance_t &instance )
  620. {
  621. if (( instance.m_nAlpha == 0) || (!m_pModel))
  622. return 0;
  623. render->SetBlend( instance.m_nAlpha / 255.0f );
  624. int drawn = modelrender->DrawModel(
  625. flags,
  626. this,
  627. MODEL_INSTANCE_INVALID,
  628. -1, // no entity index
  629. m_pModel,
  630. m_Origin,
  631. m_Angles,
  632. 0, // skin
  633. 0, // body
  634. 0 // hitboxset
  635. );
  636. return drawn;
  637. }
  638. //-----------------------------------------------------------------------------
  639. // Detail models stuff
  640. //-----------------------------------------------------------------------------
  641. CDetailModel::CDetailModel()
  642. {
  643. m_Color.r = m_Color.g = m_Color.b = 255;
  644. m_Color.exponent = 0;
  645. m_bFlipped = 0;
  646. m_bHasLightStyle = 0;
  647. m_bIsTranslucent = false;
  648. #ifdef USE_DETAIL_SHAPES
  649. m_pAdvInfo = NULL;
  650. #endif
  651. }
  652. //-----------------------------------------------------------------------------
  653. // Destructor
  654. //-----------------------------------------------------------------------------
  655. CDetailModel::~CDetailModel()
  656. {
  657. #ifdef USE_DETAIL_SHAPES
  658. // delete advanced
  659. if ( m_pAdvInfo )
  660. {
  661. delete m_pAdvInfo;
  662. m_pAdvInfo = NULL;
  663. }
  664. #endif
  665. if ( m_bHasLightStyle )
  666. gm_LightStylesMap.Remove( this );
  667. }
  668. //-----------------------------------------------------------------------------
  669. // Initialization
  670. //-----------------------------------------------------------------------------
  671. bool CDetailModel::Init( int index, const Vector& org, const QAngle& angles,
  672. model_t* pModel, ColorRGBExp32 lighting, int lightstyle, unsigned char lightstylecount,
  673. int orientation)
  674. {
  675. m_Color = lighting;
  676. if ( lightstylecount > 0)
  677. {
  678. m_bHasLightStyle = 1;
  679. int iInfo = gm_LightStylesMap.Insert( this );
  680. if ( lightstyle >= 0x1000000 || lightstylecount >= 100 )
  681. Error( "Light style overflow\n" );
  682. gm_LightStylesMap[iInfo].m_LightStyle = lightstyle;
  683. gm_LightStylesMap[iInfo].m_LightStyleCount = lightstylecount;
  684. }
  685. m_Orientation = orientation;
  686. m_Type = DETAIL_PROP_TYPE_MODEL;
  687. m_pModel = pModel;
  688. m_bIsTranslucent = modelinfo->IsTranslucent( m_pModel );
  689. return InitCommon( index, org, angles );
  690. }
  691. bool CDetailModel::InitSprite( int index, bool bFlipped, const Vector& org, const QAngle& angles, unsigned short nSpriteIndex,
  692. ColorRGBExp32 lighting, int lightstyle, unsigned char lightstylecount, int orientation, float flScale,
  693. unsigned char type, unsigned char shapeAngle, unsigned char shapeSize, unsigned char swayAmount )
  694. {
  695. m_Color = lighting;
  696. if ( lightstylecount > 0)
  697. {
  698. m_bHasLightStyle = 1;
  699. int iInfo = gm_LightStylesMap.Insert( this );
  700. if ( lightstyle >= 0x1000000 || lightstylecount >= 100 )
  701. Error( "Light style overflow\n" );
  702. gm_LightStylesMap[iInfo].m_LightStyle = lightstyle;
  703. gm_LightStylesMap[iInfo].m_LightStyleCount = lightstylecount;
  704. }
  705. m_Orientation = orientation;
  706. m_SpriteInfo.m_nSpriteIndex = nSpriteIndex;
  707. m_Type = type;
  708. m_SpriteInfo.m_flScale.SetFloat( flScale );
  709. m_bIsTranslucent = true;
  710. #ifdef USE_DETAIL_SHAPES
  711. m_pAdvInfo = NULL;
  712. Assert( type <= 3 );
  713. // precalculate angles for shapes
  714. if ( type == DETAIL_PROP_TYPE_SHAPE_TRI || type == DETAIL_PROP_TYPE_SHAPE_CROSS || swayAmount > 0 )
  715. {
  716. m_Angles = angles;
  717. InitShapedSprite( shapeAngle, shapeSize, swayAmount);
  718. }
  719. #endif
  720. m_bFlipped = bFlipped;
  721. return InitCommon( index, org, angles );
  722. }
  723. #ifdef USE_DETAIL_SHAPES
  724. void CDetailModel::InitShapedSprite( unsigned char shapeAngle, unsigned char shapeSize, unsigned char swayAmount )
  725. {
  726. // Set up pointer to advanced shape properties object ( per instance )
  727. Assert( m_pAdvInfo == NULL );
  728. m_pAdvInfo = new DetailModelAdvInfo_t;
  729. Assert( m_pAdvInfo );
  730. if ( m_pAdvInfo )
  731. {
  732. m_pAdvInfo->m_iShapeAngle = shapeAngle;
  733. m_pAdvInfo->m_flSwayAmount = (float)swayAmount / 255.0f;
  734. m_pAdvInfo->m_flShapeSize = (float)shapeSize / 255.0f;
  735. m_pAdvInfo->m_vecCurrentAvoid = vec3_origin;
  736. m_pAdvInfo->m_flSwayYaw = random->RandomFloat( 0, 180 );
  737. }
  738. switch ( m_Type )
  739. {
  740. case DETAIL_PROP_TYPE_SHAPE_TRI:
  741. InitShapeTri();
  742. break;
  743. case DETAIL_PROP_TYPE_SHAPE_CROSS:
  744. InitShapeCross();
  745. break;
  746. default: // sprite will get here
  747. break;
  748. }
  749. }
  750. void CDetailModel::InitShapeTri( void )
  751. {
  752. // store the three sets of directions
  753. matrix3x4_t matrix;
  754. // Convert roll/pitch only to matrix
  755. AngleMatrix( m_Angles, matrix );
  756. // calculate the vectors for the three sides so they can be used in the sorting test
  757. // as well as in drawing
  758. for ( int i=0; i<3; i++ )
  759. {
  760. // Convert desired rotation to angles
  761. QAngle anglesRotated( m_pAdvInfo->m_iShapeAngle, i*120, 0 );
  762. Vector rotForward, rotRight, rotUp;
  763. AngleVectors( anglesRotated, &rotForward, &rotRight, &rotUp );
  764. // Rotate direction vectors
  765. VectorRotate( rotForward, matrix, m_pAdvInfo->m_vecAnglesForward[i] );
  766. VectorRotate( rotRight, matrix, m_pAdvInfo->m_vecAnglesRight[i] );
  767. VectorRotate( rotUp, matrix, m_pAdvInfo->m_vecAnglesUp[i] );
  768. }
  769. }
  770. void CDetailModel::InitShapeCross( void )
  771. {
  772. AngleVectors( m_Angles,
  773. &m_pAdvInfo->m_vecAnglesForward[0],
  774. &m_pAdvInfo->m_vecAnglesRight[0],
  775. &m_pAdvInfo->m_vecAnglesUp[0] );
  776. }
  777. #endif
  778. //-----------------------------------------------------------------------------
  779. // Color, alpha modulation
  780. //-----------------------------------------------------------------------------
  781. void CDetailModel::GetColorModulation( float *color )
  782. {
  783. if (mat_fullbright.GetInt() == 1)
  784. {
  785. color[0] = color[1] = color[2] = 1.0f;
  786. return;
  787. }
  788. Vector tmp;
  789. Vector normal( 1, 0, 0);
  790. engine->ComputeDynamicLighting( m_Origin, &normal, tmp );
  791. float val = engine->LightStyleValue( 0 );
  792. color[0] = tmp[0] + val * TexLightToLinear( m_Color.r, m_Color.exponent );
  793. color[1] = tmp[1] + val * TexLightToLinear( m_Color.g, m_Color.exponent );
  794. color[2] = tmp[2] + val * TexLightToLinear( m_Color.b, m_Color.exponent );
  795. // Add in the lightstyles
  796. if ( m_bHasLightStyle )
  797. {
  798. int iInfo = gm_LightStylesMap.Find( this );
  799. Assert( iInfo != gm_LightStylesMap.InvalidIndex() );
  800. if ( iInfo != gm_LightStylesMap.InvalidIndex() )
  801. {
  802. int nLightStyles = gm_LightStylesMap[iInfo].m_LightStyleCount;
  803. int iLightStyle = gm_LightStylesMap[iInfo].m_LightStyle;
  804. for (int i = 0; i < nLightStyles; ++i)
  805. {
  806. DetailPropLightstylesLump_t& lighting = s_DetailObjectSystem.DetailLighting( iLightStyle + i );
  807. val = engine->LightStyleValue( lighting.m_Style );
  808. if (val != 0)
  809. {
  810. color[0] += val * TexLightToLinear( lighting.m_Lighting.r, lighting.m_Lighting.exponent );
  811. color[1] += val * TexLightToLinear( lighting.m_Lighting.g, lighting.m_Lighting.exponent );
  812. color[2] += val * TexLightToLinear( lighting.m_Lighting.b, lighting.m_Lighting.exponent );
  813. }
  814. }
  815. }
  816. }
  817. // Gamma correct....
  818. engine->LinearToGamma( color, color );
  819. }
  820. //-----------------------------------------------------------------------------
  821. // Is the model itself translucent, regardless of modulation?
  822. //-----------------------------------------------------------------------------
  823. bool CDetailModel::IsDetailModelTranslucent()
  824. {
  825. // FIXME: This is only true for my first pass of this feature
  826. if (m_Type >= DETAIL_PROP_TYPE_SPRITE)
  827. return true;
  828. return modelinfo->IsTranslucent(GetModel());
  829. }
  830. //-----------------------------------------------------------------------------
  831. // Computes the render angles for screen alignment
  832. //-----------------------------------------------------------------------------
  833. void CDetailModel::ComputeAngles( void )
  834. {
  835. switch( m_Orientation )
  836. {
  837. case 0:
  838. break;
  839. case 1:
  840. {
  841. Vector vecDir;
  842. VectorSubtract( CurrentViewOrigin(), m_Origin, vecDir );
  843. VectorAngles( vecDir, m_Angles );
  844. }
  845. break;
  846. case 2:
  847. {
  848. Vector vecDir;
  849. VectorSubtract( CurrentViewOrigin(), m_Origin, vecDir );
  850. vecDir.z = 0.0f;
  851. VectorAngles( vecDir, m_Angles );
  852. }
  853. break;
  854. }
  855. }
  856. //-----------------------------------------------------------------------------
  857. // Select which rendering func to call
  858. //-----------------------------------------------------------------------------
  859. void CDetailModel::DrawSprite( CMeshBuilder &meshBuilder, uint8 nAlpha )
  860. {
  861. switch( m_Type )
  862. {
  863. #ifdef USE_DETAIL_SHAPES
  864. case DETAIL_PROP_TYPE_SHAPE_CROSS:
  865. DrawTypeShapeCross( meshBuilder, nAlpha );
  866. break;
  867. case DETAIL_PROP_TYPE_SHAPE_TRI:
  868. DrawTypeShapeTri( meshBuilder, nAlpha );
  869. break;
  870. #endif
  871. case DETAIL_PROP_TYPE_SPRITE:
  872. DrawTypeSprite( meshBuilder, nAlpha );
  873. break;
  874. default:
  875. Assert(0);
  876. break;
  877. }
  878. }
  879. //-----------------------------------------------------------------------------
  880. // Draws the single sprite type
  881. //-----------------------------------------------------------------------------
  882. void CDetailModel::DrawTypeSprite( CMeshBuilder &meshBuilder, uint8 nAlpha )
  883. {
  884. Assert( m_Type == DETAIL_PROP_TYPE_SPRITE );
  885. Vector vecColor;
  886. GetColorModulation( vecColor.Base() );
  887. unsigned char color[4];
  888. color[0] = (unsigned char)(vecColor[0] * 255.0f);
  889. color[1] = (unsigned char)(vecColor[1] * 255.0f);
  890. color[2] = (unsigned char)(vecColor[2] * 255.0f);
  891. color[3] = nAlpha;
  892. DetailPropSpriteDict_t &dict = s_DetailObjectSystem.DetailSpriteDict( m_SpriteInfo.m_nSpriteIndex );
  893. Vector vecOrigin, dx, dy, dz;
  894. AngleVectors( m_Angles, &dz, &dx, &dy );
  895. Vector2D ul, lr;
  896. float scale = m_SpriteInfo.m_flScale.GetFloat();
  897. Vector2DMultiply( dict.m_UL, scale, ul );
  898. Vector2DMultiply( dict.m_LR, scale, lr );
  899. #ifdef USE_DETAIL_SHAPES
  900. UpdatePlayerAvoid();
  901. Vector vecSway = vec3_origin;
  902. if ( m_pAdvInfo )
  903. {
  904. vecSway = m_pAdvInfo->m_vecCurrentAvoid * m_SpriteInfo.m_flScale.GetFloat();
  905. float flSwayAmplitude = m_pAdvInfo->m_flSwayAmount * cl_detail_max_sway.GetFloat();
  906. if ( flSwayAmplitude > 0 )
  907. {
  908. // sway based on time plus a random seed that is constant for this instance of the sprite
  909. vecSway += dx * sin(gpGlobals->curtime+m_Origin.x) * flSwayAmplitude;
  910. }
  911. }
  912. #endif
  913. VectorMA( m_Origin, ul.x, dx, vecOrigin );
  914. VectorMA( vecOrigin, ul.y, dy, vecOrigin );
  915. dx *= (lr.x - ul.x);
  916. dy *= (lr.y - ul.y);
  917. Vector2D texul, texlr;
  918. texul = dict.m_TexUL;
  919. texlr = dict.m_TexLR;
  920. if ( !m_bFlipped )
  921. {
  922. texul.x = dict.m_TexLR.x;
  923. texlr.x = dict.m_TexUL.x;
  924. }
  925. #ifndef USE_DETAIL_SHAPES
  926. meshBuilder.Position3fv( vecOrigin.Base() );
  927. #else
  928. meshBuilder.Position3fv( (vecOrigin+vecSway).Base() );
  929. #endif
  930. meshBuilder.Color4ubv( color );
  931. meshBuilder.TexCoord2fv( 0, texul.Base() );
  932. meshBuilder.Normal3fv( &dz.x );
  933. meshBuilder.AdvanceVertex();
  934. vecOrigin += dy;
  935. meshBuilder.Position3fv( vecOrigin.Base() );
  936. meshBuilder.Color4ubv( color );
  937. meshBuilder.TexCoord2f( 0, texul.x, texlr.y );
  938. meshBuilder.Normal3fv( &dz.x );
  939. meshBuilder.AdvanceVertex();
  940. vecOrigin += dx;
  941. meshBuilder.Position3fv( vecOrigin.Base() );
  942. meshBuilder.Color4ubv( color );
  943. meshBuilder.TexCoord2fv( 0, texlr.Base() );
  944. meshBuilder.Normal3fv( &dz.x );
  945. meshBuilder.AdvanceVertex();
  946. vecOrigin -= dy;
  947. #ifndef USE_DETAIL_SHAPES
  948. meshBuilder.Position3fv( vecOrigin.Base() );
  949. #else
  950. meshBuilder.Position3fv( (vecOrigin+vecSway).Base() );
  951. #endif
  952. meshBuilder.Color4ubv( color );
  953. meshBuilder.TexCoord2f( 0, texlr.x, texul.y );
  954. meshBuilder.Normal3fv( &dz.x );
  955. meshBuilder.AdvanceVertex();
  956. }
  957. //-----------------------------------------------------------------------------
  958. // draws a procedural model, cross shape
  959. // two perpendicular sprites
  960. //-----------------------------------------------------------------------------
  961. #ifdef USE_DETAIL_SHAPES
  962. void CDetailModel::DrawTypeShapeCross( CMeshBuilder &meshBuilder, uint8 nAlpha )
  963. {
  964. Assert( m_Type == DETAIL_PROP_TYPE_SHAPE_CROSS );
  965. Vector vecColor;
  966. GetColorModulation( vecColor.Base() );
  967. unsigned char color[4];
  968. color[0] = (unsigned char)(vecColor[0] * 255.0f);
  969. color[1] = (unsigned char)(vecColor[1] * 255.0f);
  970. color[2] = (unsigned char)(vecColor[2] * 255.0f);
  971. color[3] = nAlpha;
  972. DetailPropSpriteDict_t &dict = s_DetailObjectSystem.DetailSpriteDict( m_SpriteInfo.m_nSpriteIndex );
  973. Vector2D texul, texlr;
  974. texul = dict.m_TexUL;
  975. texlr = dict.m_TexLR;
  976. // What a shameless re-use of bits (m_pModel == 0 when it should be flipped horizontally)
  977. if ( !m_pModel )
  978. {
  979. texul.x = dict.m_TexLR.x;
  980. texlr.x = dict.m_TexUL.x;
  981. }
  982. Vector2D texumid, texlmid;
  983. texumid.y = texul.y;
  984. texlmid.y = texlr.y;
  985. texumid.x = texlmid.x = ( texul.x + texlr.x ) / 2;
  986. Vector2D texll;
  987. texll.x = texul.x;
  988. texll.y = texlr.y;
  989. Vector2D ul, lr;
  990. float flScale = m_SpriteInfo.m_flScale.GetFloat();
  991. Vector2DMultiply( dict.m_UL, flScale, ul );
  992. Vector2DMultiply( dict.m_LR, flScale, lr );
  993. float flSizeX = ( lr.x - ul.x ) / 2;
  994. float flSizeY = ( lr.y - ul.y );
  995. UpdatePlayerAvoid();
  996. // sway based on time plus a random seed that is constant for this instance of the sprite
  997. Vector vecSway = ( m_pAdvInfo->m_vecCurrentAvoid * flSizeX * 2 );
  998. float flSwayAmplitude = m_pAdvInfo->m_flSwayAmount * cl_detail_max_sway.GetFloat();
  999. if ( flSwayAmplitude > 0 )
  1000. {
  1001. vecSway += UTIL_YawToVector( m_pAdvInfo->m_flSwayYaw ) * sin(gpGlobals->curtime+m_Origin.x) * flSwayAmplitude;
  1002. }
  1003. Vector vecOrigin;
  1004. VectorMA( m_Origin, ul.y, m_pAdvInfo->m_vecAnglesUp[0], vecOrigin );
  1005. Vector forward, right, up;
  1006. forward = m_pAdvInfo->m_vecAnglesForward[0] * flSizeX;
  1007. right = m_pAdvInfo->m_vecAnglesRight[0] * flSizeX;
  1008. up = m_pAdvInfo->m_vecAnglesUp[0] * flSizeY;
  1009. // figure out drawing order so the branches sort properly
  1010. // do dot products with the forward and right vectors to determine the quadrant the viewer is in
  1011. // assume forward points North , right points East
  1012. /*
  1013. N
  1014. |
  1015. 3 | 0
  1016. W---------E
  1017. 2 | 1
  1018. |
  1019. S
  1020. */
  1021. // eg if they are in quadrant 0, set iBranch to 0, and the draw order will be
  1022. // 0, 1, 2, 3, or South, west, north, east
  1023. Vector viewOffset = CurrentViewOrigin() - m_Origin;
  1024. bool bForward = ( DotProduct( forward, viewOffset ) > 0 );
  1025. bool bRight = ( DotProduct( right, viewOffset ) > 0 );
  1026. int iBranch = bForward ? ( bRight ? 0 : 3 ) : ( bRight ? 1 : 2 );
  1027. //debugoverlay->AddLineOverlay( m_Origin, m_Origin + right * 20, 255, 0, 0, true, 0.01 );
  1028. //debugoverlay->AddLineOverlay( m_Origin, m_Origin + forward * 20, 0, 0, 255, true, 0.01 );
  1029. int iDrawn = 0;
  1030. while( iDrawn < 4 )
  1031. {
  1032. switch( iBranch )
  1033. {
  1034. case 0: // south
  1035. DrawSwayingQuad( meshBuilder, vecOrigin, vecSway, texumid, texlr, color, -forward, up );
  1036. break;
  1037. case 1: // west
  1038. DrawSwayingQuad( meshBuilder, vecOrigin, vecSway, texumid, texll, color, -right, up );
  1039. break;
  1040. case 2: // north
  1041. DrawSwayingQuad( meshBuilder, vecOrigin, vecSway, texumid, texll, color, forward, up );
  1042. break;
  1043. case 3: // east
  1044. DrawSwayingQuad( meshBuilder, vecOrigin, vecSway, texumid, texlr, color, right, up );
  1045. break;
  1046. }
  1047. iDrawn++;
  1048. iBranch++;
  1049. if ( iBranch > 3 )
  1050. iBranch = 0;
  1051. }
  1052. }
  1053. #endif
  1054. //-----------------------------------------------------------------------------
  1055. // draws a procedural model, tri shape
  1056. //-----------------------------------------------------------------------------
  1057. #ifdef USE_DETAIL_SHAPES
  1058. void CDetailModel::DrawTypeShapeTri( CMeshBuilder &meshBuilder, uint8 nAlpha )
  1059. {
  1060. Assert( m_Type == DETAIL_PROP_TYPE_SHAPE_TRI );
  1061. Vector vecColor;
  1062. GetColorModulation( vecColor.Base() );
  1063. unsigned char color[4];
  1064. color[0] = (unsigned char)(vecColor[0] * 255.0f);
  1065. color[1] = (unsigned char)(vecColor[1] * 255.0f);
  1066. color[2] = (unsigned char)(vecColor[2] * 255.0f);
  1067. color[3] = nAlpha;
  1068. DetailPropSpriteDict_t &dict = s_DetailObjectSystem.DetailSpriteDict( m_SpriteInfo.m_nSpriteIndex );
  1069. Vector2D texul, texlr;
  1070. texul = dict.m_TexUL;
  1071. texlr = dict.m_TexLR;
  1072. // What a shameless re-use of bits (m_pModel == 0 when it should be flipped horizontally)
  1073. if ( !m_pModel )
  1074. {
  1075. texul.x = dict.m_TexLR.x;
  1076. texlr.x = dict.m_TexUL.x;
  1077. }
  1078. Vector2D ul, lr;
  1079. float flScale = m_SpriteInfo.m_flScale.GetFloat();
  1080. Vector2DMultiply( dict.m_UL, flScale, ul );
  1081. Vector2DMultiply( dict.m_LR, flScale, lr );
  1082. // sort the sides relative to the view origin
  1083. Vector viewOffset = CurrentViewOrigin() - m_Origin;
  1084. // three sides, A, B, C, counter-clockwise from A is the unrotated side
  1085. bool bOutsideA = DotProduct( m_pAdvInfo->m_vecAnglesForward[0], viewOffset ) > 0;
  1086. bool bOutsideB = DotProduct( m_pAdvInfo->m_vecAnglesForward[1], viewOffset ) > 0;
  1087. bool bOutsideC = DotProduct( m_pAdvInfo->m_vecAnglesForward[2], viewOffset ) > 0;
  1088. int iBranch = 0;
  1089. if ( bOutsideA && !bOutsideB )
  1090. iBranch = 1;
  1091. else if ( bOutsideB && !bOutsideC )
  1092. iBranch = 2;
  1093. float flHeight, flWidth;
  1094. flHeight = (lr.y - ul.y);
  1095. flWidth = (lr.x - ul.x);
  1096. Vector vecSway;
  1097. Vector vecOrigin;
  1098. Vector vecHeight, vecWidth;
  1099. UpdatePlayerAvoid();
  1100. Vector vecSwayYaw = UTIL_YawToVector( m_pAdvInfo->m_flSwayYaw );
  1101. float flSwayAmplitude = m_pAdvInfo->m_flSwayAmount * cl_detail_max_sway.GetFloat();
  1102. int iDrawn = 0;
  1103. while( iDrawn < 3 )
  1104. {
  1105. vecHeight = m_pAdvInfo->m_vecAnglesUp[iBranch] * flHeight;
  1106. vecWidth = m_pAdvInfo->m_vecAnglesRight[iBranch] * flWidth;
  1107. VectorMA( m_Origin, ul.x, m_pAdvInfo->m_vecAnglesRight[iBranch], vecOrigin );
  1108. VectorMA( vecOrigin, ul.y, m_pAdvInfo->m_vecAnglesUp[iBranch], vecOrigin );
  1109. VectorMA( vecOrigin, m_pAdvInfo->m_flShapeSize*flWidth, m_pAdvInfo->m_vecAnglesForward[iBranch], vecOrigin );
  1110. // sway is calculated per side so they don't sway exactly the same
  1111. Vector vecSway = ( m_pAdvInfo->m_vecCurrentAvoid * flWidth ) +
  1112. vecSwayYaw * sin(gpGlobals->curtime+m_Origin.x+iBranch) * flSwayAmplitude;
  1113. DrawSwayingQuad( meshBuilder, vecOrigin, vecSway, texul, texlr, color, vecWidth, vecHeight );
  1114. iDrawn++;
  1115. iBranch++;
  1116. if ( iBranch > 2 )
  1117. iBranch = 0;
  1118. }
  1119. }
  1120. #endif
  1121. //-----------------------------------------------------------------------------
  1122. // checks for nearby players and pushes the detail to the side
  1123. //-----------------------------------------------------------------------------
  1124. #ifdef USE_DETAIL_SHAPES
  1125. void CDetailModel::UpdatePlayerAvoid( void )
  1126. {
  1127. float flForce = cl_detail_avoid_force.GetFloat();
  1128. if ( flForce < 0.1 )
  1129. return;
  1130. if ( m_pAdvInfo == NULL )
  1131. return;
  1132. // get players in a radius
  1133. float flRadius = cl_detail_avoid_radius.GetFloat();
  1134. float flRecoverSpeed = cl_detail_avoid_recover_speed.GetFloat();
  1135. Vector vecAvoid;
  1136. C_BaseEntity *pEnt;
  1137. float flMaxForce = 0;
  1138. Vector vecMaxAvoid(0,0,0);
  1139. CPlayerEnumerator avoid( flRadius, m_Origin );
  1140. ::partition->EnumerateElementsInSphere( PARTITION_CLIENT_SOLID_EDICTS, m_Origin, flRadius, false, &avoid );
  1141. // Okay, decide how to avoid if there's anything close by
  1142. int c = avoid.GetObjectCount();
  1143. for ( int i=0; i<c+1; i++ ) // +1 for the local player we tack on the end
  1144. {
  1145. if ( i == c )
  1146. {
  1147. pEnt = C_BasePlayer::GetLocalPlayer();
  1148. if ( !pEnt ) continue;
  1149. }
  1150. else
  1151. pEnt = avoid.GetObject( i );
  1152. vecAvoid = m_Origin - pEnt->GetAbsOrigin();
  1153. vecAvoid.z = 0;
  1154. float flDist = vecAvoid.Length2D();
  1155. if ( flDist > flRadius )
  1156. continue;
  1157. float flForceScale = RemapValClamped( flDist, 0, flRadius, flForce, 0.0 );
  1158. if ( flForceScale > flMaxForce )
  1159. {
  1160. flMaxForce = flForceScale;
  1161. vecAvoid.NormalizeInPlace();
  1162. vecAvoid *= flMaxForce;
  1163. vecMaxAvoid = vecAvoid;
  1164. }
  1165. }
  1166. // if we are being moved, move fast. Else we recover at a slow rate
  1167. if ( vecMaxAvoid.Length2D() > m_pAdvInfo->m_vecCurrentAvoid.Length2D() )
  1168. flRecoverSpeed = 10; // fast approach
  1169. m_pAdvInfo->m_vecCurrentAvoid[0] = Approach( vecMaxAvoid[0], m_pAdvInfo->m_vecCurrentAvoid[0], flRecoverSpeed );
  1170. m_pAdvInfo->m_vecCurrentAvoid[1] = Approach( vecMaxAvoid[1], m_pAdvInfo->m_vecCurrentAvoid[1], flRecoverSpeed );
  1171. m_pAdvInfo->m_vecCurrentAvoid[2] = Approach( vecMaxAvoid[2], m_pAdvInfo->m_vecCurrentAvoid[2], flRecoverSpeed );
  1172. }
  1173. #endif
  1174. //-----------------------------------------------------------------------------
  1175. // draws a quad that sways on the top two vertices
  1176. // pass vecOrigin as the top left vertex position
  1177. //-----------------------------------------------------------------------------
  1178. #ifdef USE_DETAIL_SHAPES
  1179. void CDetailModel::DrawSwayingQuad( CMeshBuilder &meshBuilder, Vector vecOrigin, Vector vecSway, Vector2D texul, Vector2D texlr, unsigned char *color,
  1180. Vector width, Vector height )
  1181. {
  1182. meshBuilder.Position3fv( (vecOrigin + vecSway).Base() );
  1183. meshBuilder.TexCoord2fv( 0, texul.Base() );
  1184. meshBuilder.Color4ubv( color );
  1185. meshBuilder.AdvanceVertex();
  1186. vecOrigin += height;
  1187. meshBuilder.Position3fv( vecOrigin.Base() );
  1188. meshBuilder.TexCoord2f( 0, texul.x, texlr.y );
  1189. meshBuilder.Color4ubv( color );
  1190. meshBuilder.AdvanceVertex();
  1191. vecOrigin += width;
  1192. meshBuilder.Position3fv( vecOrigin.Base() );
  1193. meshBuilder.TexCoord2fv( 0, texlr.Base() );
  1194. meshBuilder.Color4ubv( color );
  1195. meshBuilder.AdvanceVertex();
  1196. vecOrigin -= height;
  1197. meshBuilder.Position3fv( (vecOrigin + vecSway).Base() );
  1198. meshBuilder.TexCoord2f( 0, texlr.x, texul.y );
  1199. meshBuilder.Color4ubv( color );
  1200. meshBuilder.AdvanceVertex();
  1201. }
  1202. #endif
  1203. //-----------------------------------------------------------------------------
  1204. // constructor, destructor
  1205. //-----------------------------------------------------------------------------
  1206. CDetailObjectSystem::CDetailObjectSystem() : m_DetailSpriteDict( 0, 32 ), m_DetailObjectDict( 0, 32 ), m_DetailSpriteDictFlipped( 0, 32 )
  1207. {
  1208. m_pFastSpriteData = NULL;
  1209. m_pSortInfo = NULL;
  1210. m_pFastSortInfo = NULL;
  1211. m_pBuildoutBuffer = NULL;
  1212. m_pCachedSpriteMesh[MAX_MAP_LEAFS][CACHED_SPRITE_SUB_SPLIT_COUNT] = {NULL};
  1213. m_nCachedSpriteMeshPtrs.RemoveAll();
  1214. }
  1215. void CDetailObjectSystem::DestroyCachedSpriteMeshes( void )
  1216. {
  1217. if ( m_nCachedSpriteMeshPtrs.Count() )
  1218. {
  1219. CMatRenderContextPtr pRenderContext( materials );
  1220. FOR_EACH_VEC( m_nCachedSpriteMeshPtrs, n )
  1221. {
  1222. Assert( m_nCachedSpriteMeshPtrs[n] );
  1223. pRenderContext->DestroyStaticMesh( *m_nCachedSpriteMeshPtrs[n] );
  1224. *m_nCachedSpriteMeshPtrs[n] = NULL;
  1225. }
  1226. m_nCachedSpriteMeshPtrs.Purge();
  1227. }
  1228. }
  1229. void CDetailObjectSystem::FreeSortBuffers( void )
  1230. {
  1231. if ( m_pSortInfo )
  1232. {
  1233. MemAlloc_FreeAligned( m_pSortInfo );
  1234. m_pSortInfo = NULL;
  1235. }
  1236. if ( m_pFastSortInfo )
  1237. {
  1238. MemAlloc_FreeAligned( m_pFastSortInfo );
  1239. m_pFastSortInfo = NULL;
  1240. }
  1241. if ( m_pBuildoutBuffer )
  1242. {
  1243. MemAlloc_FreeAligned( m_pBuildoutBuffer );
  1244. m_pBuildoutBuffer = NULL;
  1245. }
  1246. }
  1247. CDetailObjectSystem::~CDetailObjectSystem()
  1248. {
  1249. if ( m_pFastSpriteData )
  1250. {
  1251. MemAlloc_FreeAligned( m_pFastSpriteData );
  1252. m_pFastSpriteData = NULL;
  1253. }
  1254. FreeSortBuffers();
  1255. DestroyCachedSpriteMeshes();
  1256. }
  1257. //-----------------------------------------------------------------------------
  1258. // Level init, shutdown
  1259. //-----------------------------------------------------------------------------
  1260. void CDetailObjectSystem::LevelInitPreEntity()
  1261. {
  1262. if ( m_pFastSpriteData )
  1263. {
  1264. MemAlloc_FreeAligned( m_pFastSpriteData );
  1265. m_pFastSpriteData = NULL;
  1266. }
  1267. FreeSortBuffers();
  1268. DestroyCachedSpriteMeshes();
  1269. // Prepare the translucent detail sprite material; we only have 1!
  1270. const char *pDetailSpriteMaterial = DETAIL_SPRITE_MATERIAL;
  1271. C_World *pWorld = GetClientWorldEntity();
  1272. if ( pWorld && pWorld->GetDetailSpriteMaterial() && *(pWorld->GetDetailSpriteMaterial()) )
  1273. {
  1274. pDetailSpriteMaterial = pWorld->GetDetailSpriteMaterial();
  1275. }
  1276. m_DetailSpriteMaterial.Init( pDetailSpriteMaterial, TEXTURE_GROUP_OTHER );
  1277. m_DetailWireframeMaterial.Init( "debug/debugspritewireframe", TEXTURE_GROUP_OTHER );
  1278. // Version check
  1279. if (engine->GameLumpVersion( GAMELUMP_DETAIL_PROPS ) < 4)
  1280. {
  1281. Warning("Map uses old detail prop file format.. ignoring detail props\n");
  1282. return;
  1283. }
  1284. MEM_ALLOC_CREDIT();
  1285. // Unserialize
  1286. int size = engine->GameLumpSize( GAMELUMP_DETAIL_PROPS );
  1287. CUtlMemory<unsigned char> fileMemory;
  1288. fileMemory.EnsureCapacity( size );
  1289. if (engine->LoadGameLump( GAMELUMP_DETAIL_PROPS, fileMemory.Base(), size ))
  1290. {
  1291. CUtlBuffer buf( fileMemory.Base(), size, CUtlBuffer::READ_ONLY );
  1292. UnserializeModelDict( buf );
  1293. switch (engine->GameLumpVersion( GAMELUMP_DETAIL_PROPS ) )
  1294. {
  1295. case 4:
  1296. UnserializeDetailSprites( buf );
  1297. UnserializeModels( buf );
  1298. break;
  1299. }
  1300. }
  1301. if ( m_DetailObjects.Count() || m_DetailSpriteDict.Count() )
  1302. {
  1303. // There are detail objects in the level, so precache the material
  1304. PrecacheMaterial( DETAIL_SPRITE_MATERIAL );
  1305. IMaterial *pMat = m_DetailSpriteMaterial;
  1306. // adjust for non-square textures (cropped)
  1307. float flRatio = pMat->GetMappingWidth() / pMat->GetMappingHeight();
  1308. if ( flRatio > 1.0 )
  1309. {
  1310. for( int i = 0; i<m_DetailSpriteDict.Count(); i++ )
  1311. {
  1312. m_DetailSpriteDict[i].m_TexUL.y *= flRatio;
  1313. m_DetailSpriteDict[i].m_TexLR.y *= flRatio;
  1314. m_DetailSpriteDictFlipped[i].m_TexUL.y *= flRatio;
  1315. m_DetailSpriteDictFlipped[i].m_TexLR.y *= flRatio;
  1316. }
  1317. }
  1318. }
  1319. int detailPropLightingLump;
  1320. if( g_pMaterialSystemHardwareConfig->GetHDRType() != HDR_TYPE_NONE )
  1321. {
  1322. detailPropLightingLump = GAMELUMP_DETAIL_PROP_LIGHTING_HDR;
  1323. }
  1324. else
  1325. {
  1326. detailPropLightingLump = GAMELUMP_DETAIL_PROP_LIGHTING;
  1327. }
  1328. size = engine->GameLumpSize( detailPropLightingLump );
  1329. fileMemory.EnsureCapacity( size );
  1330. if (engine->LoadGameLump( detailPropLightingLump, fileMemory.Base(), size ))
  1331. {
  1332. CUtlBuffer buf( fileMemory.Base(), size, CUtlBuffer::READ_ONLY );
  1333. UnserializeModelLighting( buf );
  1334. }
  1335. }
  1336. void CDetailObjectSystem::UpdateDetailFadeValues()
  1337. {
  1338. // FIXME: pipe through to the vertex shader
  1339. m_flDetailFadeEnd = 2000.0f;//cl_detaildist.GetInt();
  1340. m_flDetailFadeStart = 1800.0f;//m_flDetailFadeEnd - cl_detailfade.GetInt();
  1341. if ( m_flDetailFadeStart < 0 )
  1342. {
  1343. m_flDetailFadeStart = 0;
  1344. }
  1345. if ( GetDetailController() )
  1346. {
  1347. m_flDetailFadeStart = Min( m_flDetailFadeStart, GetDetailController()->m_flFadeStartDist.Get() );
  1348. m_flDetailFadeEnd = Min( m_flDetailFadeEnd, GetDetailController()->m_flFadeEndDist.Get() );
  1349. }
  1350. }
  1351. void CDetailObjectSystem::LevelInitPostEntity()
  1352. {
  1353. const char *pDetailSpriteMaterial = DETAIL_SPRITE_MATERIAL;
  1354. C_World *pWorld = GetClientWorldEntity();
  1355. if ( pWorld && pWorld->GetDetailSpriteMaterial() && *(pWorld->GetDetailSpriteMaterial()) )
  1356. {
  1357. pDetailSpriteMaterial = pWorld->GetDetailSpriteMaterial();
  1358. }
  1359. m_DetailSpriteMaterial.Init( pDetailSpriteMaterial, TEXTURE_GROUP_OTHER );
  1360. UpdateDetailFadeValues();
  1361. }
  1362. void CDetailObjectSystem::LevelShutdownPreEntity()
  1363. {
  1364. m_DetailObjects.Purge();
  1365. m_DetailObjectDict.Purge();
  1366. m_DetailSpriteDict.Purge();
  1367. m_DetailSpriteDictFlipped.Purge();
  1368. m_DetailLighting.Purge();
  1369. }
  1370. void CDetailObjectSystem::LevelShutdownPostEntity()
  1371. {
  1372. m_DetailSpriteMaterial.Shutdown();
  1373. m_DetailWireframeMaterial.Shutdown();
  1374. DestroyCachedSpriteMeshes();
  1375. }
  1376. //-----------------------------------------------------------------------------
  1377. // Computes distance fade
  1378. //-----------------------------------------------------------------------------
  1379. inline uint8 CDetailObjectSystem::ComputeDistanceFade( float *pDistSqr, const DistanceFadeInfo_t &info, const Vector &vecViewOrigin, const Vector &vecRenderOrigin ) const
  1380. {
  1381. float flDistSq = vecViewOrigin.DistToSqr( vecRenderOrigin );
  1382. *pDistSqr = flDistSq;
  1383. if ( flDistSq >= info.m_flMaxDistSqr )
  1384. return 0;
  1385. uint8 nAlpha = 255;
  1386. if ( flDistSq > info.m_flMinDistSqr )
  1387. {
  1388. nAlpha = 255.0f * info.m_flFalloffFactor * ( info.m_flMaxDistSqr - flDistSq );
  1389. }
  1390. return nAlpha;
  1391. }
  1392. //-----------------------------------------------------------------------------
  1393. // Before each view, blat out the stored detail sprite state
  1394. //-----------------------------------------------------------------------------
  1395. void CDetailObjectSystem::BeginTranslucentDetailRendering( )
  1396. {
  1397. m_nSortedLeaf = -1;
  1398. m_bFirstLeaf = true;
  1399. m_nSpriteCount = m_nFirstSprite = 0;
  1400. }
  1401. //-----------------------------------------------------------------------------
  1402. // Gets a particular detail object
  1403. //-----------------------------------------------------------------------------
  1404. IClientRenderable* CDetailObjectSystem::GetDetailModel( int idx )
  1405. {
  1406. // FIXME: This is necessary because we have intermixed models + sprites
  1407. // in a single list (m_DetailObjects)
  1408. if (m_DetailObjects[idx].GetType() != DETAIL_PROP_TYPE_MODEL)
  1409. return NULL;
  1410. return &m_DetailObjects[idx];
  1411. }
  1412. // How many detail models (as opposed to sprites) are there in the level?
  1413. int CDetailObjectSystem::GetDetailModelCount() const
  1414. {
  1415. return m_DetailObjects.Count();
  1416. }
  1417. //-----------------------------------------------------------------------------
  1418. // Unserialization
  1419. //-----------------------------------------------------------------------------
  1420. void CDetailObjectSystem::UnserializeModelDict( CUtlBuffer& buf )
  1421. {
  1422. int count = buf.GetInt();
  1423. m_DetailObjectDict.EnsureCapacity( count );
  1424. while ( --count >= 0 )
  1425. {
  1426. DetailObjectDictLump_t lump;
  1427. buf.Get( &lump, sizeof(DetailObjectDictLump_t) );
  1428. DetailModelDict_t dict;
  1429. dict.m_pModel = (model_t *)engine->LoadModel( lump.m_Name, true );
  1430. // Don't allow vertex-lit models
  1431. if (modelinfo->IsModelVertexLit(dict.m_pModel))
  1432. {
  1433. Warning("Detail prop model %s is using vertex-lit materials!\nIt must use unlit materials!\n", lump.m_Name );
  1434. dict.m_pModel = (model_t *)engine->LoadModel( "models/error.mdl" );
  1435. }
  1436. m_DetailObjectDict.AddToTail( dict );
  1437. }
  1438. }
  1439. void CDetailObjectSystem::UnserializeDetailSprites( CUtlBuffer& buf )
  1440. {
  1441. int count = buf.GetInt();
  1442. m_DetailSpriteDict.EnsureCapacity( count );
  1443. m_DetailSpriteDictFlipped.EnsureCapacity( count );
  1444. while ( --count >= 0 )
  1445. {
  1446. int i = m_DetailSpriteDict.AddToTail();
  1447. buf.Get( &m_DetailSpriteDict[i], sizeof(DetailSpriteDictLump_t) );
  1448. int flipi = m_DetailSpriteDictFlipped.AddToTail();
  1449. m_DetailSpriteDictFlipped[flipi] = m_DetailSpriteDict[i];
  1450. V_swap( m_DetailSpriteDictFlipped[flipi].m_TexUL.x, m_DetailSpriteDictFlipped[flipi].m_TexLR.x );
  1451. }
  1452. }
  1453. void CDetailObjectSystem::UnserializeModelLighting( CUtlBuffer& buf )
  1454. {
  1455. int count = buf.GetInt();
  1456. m_DetailLighting.EnsureCapacity( count );
  1457. while ( --count >= 0 )
  1458. {
  1459. int i = m_DetailLighting.AddToTail();
  1460. buf.Get( &m_DetailLighting[i], sizeof(DetailPropLightstylesLump_t) );
  1461. }
  1462. }
  1463. ConVar cl_detail_multiplier( "cl_detail_multiplier", "1", FCVAR_CHEAT, "extra details to create" );
  1464. #define SPRITE_MULTIPLIER ( cl_detail_multiplier.GetInt() )
  1465. ConVar cl_fastdetailsprites( "cl_fastdetailsprites", "1", FCVAR_CHEAT, "whether to use new detail sprite system");
  1466. static bool DetailObjectIsFastSprite( DetailObjectLump_t const & lump )
  1467. {
  1468. // For now, we're ALWAYS fast, since we'll do sprite orienting in the vertex shader.
  1469. return ( lump.m_Type == DETAIL_PROP_TYPE_SPRITE );
  1470. //return (
  1471. // ( cl_fastdetailsprites.GetInt() ) &&
  1472. // ( lump.m_Type == DETAIL_PROP_TYPE_SPRITE ) &&
  1473. // ( lump.m_LightStyleCount == 0 ) &&
  1474. // ( lump.m_Orientation == 2 ) &&
  1475. // ( lump.m_ShapeAngle == 0 ) &&
  1476. // ( lump.m_ShapeSize == 0 ) &&
  1477. // ( lump.m_SwayAmount == 0 ) );
  1478. }
  1479. void CDetailObjectSystem::ScanForCounts( CUtlBuffer& buf,
  1480. int *pNumOldStyleObjects,
  1481. int *pNumFastSpritesToAllocate,
  1482. int *nMaxNumOldSpritesInLeaf,
  1483. int *nMaxNumFastSpritesInLeaf
  1484. ) const
  1485. {
  1486. int oldpos = buf.TellGet(); // we need to seek back
  1487. int count = buf.GetInt();
  1488. int nOld = 0;
  1489. int nFast = 0;
  1490. int detailObjectLeaf = -1;
  1491. int nNumOldInLeaf = 0;
  1492. int nNumFastInLeaf = 0;
  1493. int nMaxOld = 0;
  1494. int nMaxFast = 0;
  1495. while ( --count >= 0 )
  1496. {
  1497. DetailObjectLump_t lump;
  1498. buf.Get( &lump, sizeof(DetailObjectLump_t) );
  1499. // We rely on the fact that details objects are sorted by leaf in the
  1500. // bsp file for this
  1501. if ( detailObjectLeaf != lump.m_Leaf )
  1502. {
  1503. // need to pad nfast to next sse boundary
  1504. nFast += ( 0 - nFast ) & 3;
  1505. nMaxFast = MAX( nMaxFast, nNumFastInLeaf );
  1506. nMaxOld = MAX( nMaxOld, nNumOldInLeaf );
  1507. nNumOldInLeaf = 0;
  1508. nNumFastInLeaf = 0;
  1509. detailObjectLeaf = lump.m_Leaf;
  1510. }
  1511. if ( DetailObjectIsFastSprite( lump ) )
  1512. {
  1513. nFast += SPRITE_MULTIPLIER;
  1514. nNumFastInLeaf += SPRITE_MULTIPLIER;
  1515. }
  1516. else
  1517. {
  1518. nOld += SPRITE_MULTIPLIER;
  1519. nNumOldInLeaf += SPRITE_MULTIPLIER;
  1520. }
  1521. }
  1522. // need to pad nfast to next sse boundary
  1523. nFast += ( 0 - nFast ) & 3;
  1524. nMaxFast = MAX( nMaxFast, nNumFastInLeaf );
  1525. nMaxOld = MAX( nMaxOld, nNumOldInLeaf );
  1526. buf.SeekGet( CUtlBuffer::SEEK_HEAD, oldpos );
  1527. *pNumFastSpritesToAllocate = nFast;
  1528. *pNumOldStyleObjects = nOld;
  1529. nMaxFast = ( 3 + nMaxFast ) & ~3;
  1530. *nMaxNumOldSpritesInLeaf = nMaxOld;
  1531. *nMaxNumFastSpritesInLeaf = nMaxFast;
  1532. }
  1533. //-----------------------------------------------------------------------------
  1534. // Unserialize all models
  1535. //-----------------------------------------------------------------------------
  1536. void CDetailObjectSystem::UnserializeModels( CUtlBuffer& buf )
  1537. {
  1538. int firstDetailObject = 0;
  1539. int detailObjectCount = 0;
  1540. int detailObjectLeaf = -1;
  1541. int nNumOldStyleObjects;
  1542. int nNumFastSpritesToAllocate;
  1543. int nMaxOldInLeaf;
  1544. int nMaxFastInLeaf;
  1545. ScanForCounts( buf, &nNumOldStyleObjects, &nNumFastSpritesToAllocate, &nMaxOldInLeaf, &nMaxFastInLeaf );
  1546. FreeSortBuffers();
  1547. if ( nMaxOldInLeaf )
  1548. {
  1549. m_pSortInfo = reinterpret_cast<SortInfo_t *> (
  1550. MemAlloc_AllocAligned( (3 + nMaxOldInLeaf ) * sizeof( SortInfo_t ), sizeof( fltx4 ) ) );
  1551. Assert( m_pSortInfo );
  1552. }
  1553. if ( nMaxFastInLeaf )
  1554. {
  1555. m_pFastSortInfo = reinterpret_cast<SortInfo_t *> (
  1556. MemAlloc_AllocAligned( (3 + nMaxFastInLeaf ) * sizeof( SortInfo_t ), sizeof( fltx4 ) ) );
  1557. Assert( m_pFastSortInfo );
  1558. m_pBuildoutBuffer = reinterpret_cast<FastSpriteQuadBuildoutBufferX4_t *> (
  1559. MemAlloc_AllocAligned(
  1560. ( 1 + nMaxFastInLeaf / 4 ) * sizeof( FastSpriteQuadBuildoutBufferX4_t ),
  1561. sizeof( fltx4 ) ) );
  1562. Assert( m_pBuildoutBuffer );
  1563. }
  1564. if ( nNumFastSpritesToAllocate )
  1565. {
  1566. Assert( ( nNumFastSpritesToAllocate & 3 ) == 0 );
  1567. Assert( ! m_pFastSpriteData ); // wtf? didn't free?
  1568. m_pFastSpriteData = reinterpret_cast<FastSpriteX4_t *> (
  1569. MemAlloc_AllocAligned(
  1570. ( nNumFastSpritesToAllocate >> 2 ) * sizeof( FastSpriteX4_t ),
  1571. sizeof( fltx4 ) ) );
  1572. Assert( m_pFastSpriteData );
  1573. }
  1574. if ( nNumOldStyleObjects >= 1 << 24 )
  1575. {
  1576. Assert( 0 );
  1577. Warning( "*** CDetailObjectSystem::UnserializeModels: Error! Too many detail objects!\n" );
  1578. }
  1579. m_DetailObjects.EnsureCapacity( nNumOldStyleObjects );
  1580. int count = buf.GetInt();
  1581. int nCurFastObject = 0;
  1582. int nNumFastObjectsInCurLeaf = 0;
  1583. FastSpriteX4_t *pCurFastSpriteOut = m_pFastSpriteData;
  1584. bool bFlipped = true;
  1585. while ( --count >= 0 )
  1586. {
  1587. bFlipped = !bFlipped;
  1588. DetailObjectLump_t lump;
  1589. buf.Get( &lump, sizeof(DetailObjectLump_t) );
  1590. // We rely on the fact that details objects are sorted by leaf in the
  1591. // bsp file for this
  1592. if ( detailObjectLeaf != lump.m_Leaf )
  1593. {
  1594. if (detailObjectLeaf != -1)
  1595. {
  1596. if ( nNumFastObjectsInCurLeaf )
  1597. {
  1598. CFastDetailLeafSpriteList *pNew = new CFastDetailLeafSpriteList;
  1599. pNew->m_nNumSprites = nNumFastObjectsInCurLeaf;
  1600. pNew->m_nNumSIMDSprites = ( 3 + nNumFastObjectsInCurLeaf ) >> 2;
  1601. pNew->m_pSprites = pCurFastSpriteOut;
  1602. pCurFastSpriteOut += pNew->m_nNumSIMDSprites;
  1603. ClientLeafSystem()->SetSubSystemDataInLeaf(
  1604. detailObjectLeaf, CLSUBSYSTEM_DETAILOBJECTS, pNew );
  1605. engine->SetLeafFlag( detailObjectLeaf, LEAF_FLAGS_CONTAINS_DETAILOBJECTS ); // for fast searches
  1606. // round to see boundary
  1607. nCurFastObject += ( 0 - nCurFastObject ) & 3;
  1608. nNumFastObjectsInCurLeaf = 0;
  1609. }
  1610. ClientLeafSystem()->SetDetailObjectsInLeaf( detailObjectLeaf,
  1611. firstDetailObject, detailObjectCount );
  1612. }
  1613. detailObjectLeaf = lump.m_Leaf;
  1614. firstDetailObject = m_DetailObjects.Count();
  1615. detailObjectCount = 0;
  1616. }
  1617. if ( DetailObjectIsFastSprite( lump ) )
  1618. {
  1619. m_randomStream.SetSeed( lump.m_Leaf );
  1620. for( int i =0 ; i < SPRITE_MULTIPLIER ; i++)
  1621. {
  1622. FastSpriteX4_t *pSpritex4 = m_pFastSpriteData + (nCurFastObject >> 2 );
  1623. int nSubField = ( nCurFastObject & 3 );
  1624. Vector pos(0,0,0);
  1625. if ( i )
  1626. {
  1627. pos.x += m_randomStream.RandomInt(0,1) ? m_randomStream.RandomFloat( 10, 40 ) : m_randomStream.RandomFloat( -10, -40 );
  1628. pos.y += m_randomStream.RandomInt(0,1) ? m_randomStream.RandomFloat( 10, 40 ) : m_randomStream.RandomFloat( -10, -40 );
  1629. pos.z -= (abs(pos.x) + abs(pos.y)) * 0.25f;
  1630. bFlipped = m_randomStream.RandomInt(0,1) == 0;
  1631. }
  1632. UnserializeFastSprite( pSpritex4, nSubField, lump, bFlipped, pos );
  1633. if ( nSubField == 0 )
  1634. pSpritex4->ReplicateFirstEntryToOthers(); // keep bad numbers out to prevent denormals, etc
  1635. nCurFastObject++;
  1636. nNumFastObjectsInCurLeaf++;
  1637. }
  1638. }
  1639. else
  1640. {
  1641. switch( lump.m_Type )
  1642. {
  1643. case DETAIL_PROP_TYPE_MODEL:
  1644. {
  1645. int newObj = m_DetailObjects.AddToTail();
  1646. m_DetailObjects[newObj].Init(
  1647. newObj, lump.m_Origin, lump.m_Angles,
  1648. m_DetailObjectDict[lump.m_DetailModel].m_pModel, lump.m_Lighting,
  1649. lump.m_LightStyles, lump.m_LightStyleCount, lump.m_Orientation );
  1650. ++detailObjectCount;
  1651. }
  1652. break;
  1653. case DETAIL_PROP_TYPE_SPRITE:
  1654. case DETAIL_PROP_TYPE_SHAPE_CROSS:
  1655. case DETAIL_PROP_TYPE_SHAPE_TRI:
  1656. {
  1657. for( int i=0;i<SPRITE_MULTIPLIER;i++)
  1658. {
  1659. Vector pos = lump.m_Origin;
  1660. if ( i != 0)
  1661. {
  1662. pos += RandomVector( -50, 50 );
  1663. pos. z = lump.m_Origin.z;
  1664. }
  1665. int newObj = m_DetailObjects.AddToTail();
  1666. m_DetailObjects[newObj].InitSprite(
  1667. newObj, bFlipped, pos, lump.m_Angles,
  1668. lump.m_DetailModel, lump.m_Lighting,
  1669. lump.m_LightStyles, lump.m_LightStyleCount, lump.m_Orientation, lump.m_flScale,
  1670. lump.m_Type, lump.m_ShapeAngle, lump.m_ShapeSize, lump.m_SwayAmount );
  1671. ++detailObjectCount;
  1672. }
  1673. }
  1674. break;
  1675. }
  1676. }
  1677. }
  1678. if (detailObjectLeaf != -1)
  1679. {
  1680. if ( nNumFastObjectsInCurLeaf )
  1681. {
  1682. CFastDetailLeafSpriteList *pNew = new CFastDetailLeafSpriteList;
  1683. pNew->m_nNumSprites = nNumFastObjectsInCurLeaf;
  1684. pNew->m_nNumSIMDSprites = ( 3 + nNumFastObjectsInCurLeaf ) >> 2;
  1685. pNew->m_pSprites = pCurFastSpriteOut;
  1686. pCurFastSpriteOut += pNew->m_nNumSIMDSprites;
  1687. ClientLeafSystem()->SetSubSystemDataInLeaf(
  1688. detailObjectLeaf, CLSUBSYSTEM_DETAILOBJECTS, pNew );
  1689. engine->SetLeafFlag( detailObjectLeaf, LEAF_FLAGS_CONTAINS_DETAILOBJECTS ); // for fast searches
  1690. }
  1691. ClientLeafSystem()->SetDetailObjectsInLeaf( detailObjectLeaf,
  1692. firstDetailObject, detailObjectCount );
  1693. }
  1694. engine->RecalculateBSPLeafFlags();
  1695. }
  1696. Vector CDetailObjectSystem::GetSpriteMiddleBottomPosition( DetailObjectLump_t const &lump ) const
  1697. {
  1698. DetailPropSpriteDict_t &dict = s_DetailObjectSystem.DetailSpriteDict( lump.m_DetailModel );
  1699. Vector vecDir;
  1700. QAngle Angles;
  1701. VectorSubtract( lump.m_Origin + Vector(0,-100,0), lump.m_Origin, vecDir );
  1702. vecDir.z = 0.0f;
  1703. VectorAngles( vecDir, Angles );
  1704. Vector vecOrigin, dx, dy;
  1705. AngleVectors( Angles, NULL, &dx, &dy );
  1706. Vector2D ul, lr;
  1707. float scale = lump.m_flScale;
  1708. Vector2DMultiply( dict.m_UL, scale, ul );
  1709. Vector2DMultiply( dict.m_LR, scale, lr );
  1710. VectorMA( lump.m_Origin, ul.x, dx, vecOrigin );
  1711. VectorMA( vecOrigin, ul.y, dy, vecOrigin );
  1712. dx *= (lr.x - ul.x);
  1713. dy *= (lr.y - ul.y);
  1714. Vector2D texul, texlr;
  1715. texul = dict.m_TexUL;
  1716. texlr = dict.m_TexLR;
  1717. return vecOrigin + dy + 0.5 * dx;
  1718. }
  1719. void CDetailObjectSystem::UnserializeFastSprite( FastSpriteX4_t *pSpritex4, int nSubField, DetailObjectLump_t const &lump, bool bFlipped, Vector const &posOffset )
  1720. {
  1721. Vector pos = GetSpriteMiddleBottomPosition( lump ) + posOffset;
  1722. pSpritex4->m_Pos.X( nSubField ) = pos.x;
  1723. pSpritex4->m_Pos.Y( nSubField ) = pos.y;
  1724. pSpritex4->m_Pos.Z( nSubField ) = pos.z;
  1725. DetailPropSpriteDict_t *pSDef = &m_DetailSpriteDict[lump.m_DetailModel];
  1726. SubFloat( pSpritex4->m_HalfWidth, nSubField ) = 0.5 * lump.m_flScale * ( pSDef->m_LR.x - pSDef->m_UL.x );
  1727. SubFloat( pSpritex4->m_Height, nSubField ) = lump.m_flScale * ( pSDef->m_LR.y - pSDef->m_UL.y );
  1728. if ( !bFlipped )
  1729. {
  1730. pSDef = &m_DetailSpriteDictFlipped[lump.m_DetailModel];
  1731. }
  1732. // do packed color
  1733. ColorRGBExp32 rgbcolor = lump.m_Lighting;
  1734. float color[4];
  1735. color[0] = TexLightToLinear( rgbcolor.r, rgbcolor.exponent );
  1736. color[1] = TexLightToLinear( rgbcolor.g, rgbcolor.exponent );
  1737. color[2] = TexLightToLinear( rgbcolor.b, rgbcolor.exponent );
  1738. color[3] = 255;
  1739. pSpritex4->m_RGBColor[nSubField][0] = (uint8) clamp( 255.0 * LinearToGammaFullRange( color[0] ), 0, 255 );
  1740. pSpritex4->m_RGBColor[nSubField][1] = (uint8) clamp( 255.0 * LinearToGammaFullRange( color[1] ), 0, 255 );
  1741. pSpritex4->m_RGBColor[nSubField][2] = (uint8) clamp( 255.0 * LinearToGammaFullRange( color[2] ), 0, 255 );
  1742. pSpritex4->m_RGBColor[nSubField][3] = 255;
  1743. pSpritex4->m_pSpriteDefs[nSubField] = pSDef;
  1744. }
  1745. //-----------------------------------------------------------------------------
  1746. // Count the number of detail sprites in the leaf list
  1747. //-----------------------------------------------------------------------------
  1748. int CDetailObjectSystem::CountSpritesInLeafList( int nLeafCount, LeafIndex_t *pLeafList ) const
  1749. {
  1750. VPROF_BUDGET( "CDetailObjectSystem::CountSpritesInLeafList", VPROF_BUDGETGROUP_DETAILPROP_RENDERING );
  1751. int nPropCount = 0;
  1752. int nFirstDetailObject, nDetailObjectCount;
  1753. for ( int i = 0; i < nLeafCount; ++i )
  1754. {
  1755. // FIXME: This actually counts *everything* in the leaf, which is ok for now
  1756. // given how we're using it
  1757. ClientLeafSystem()->GetDetailObjectsInLeaf( pLeafList[i], nFirstDetailObject, nDetailObjectCount );
  1758. nPropCount += nDetailObjectCount;
  1759. }
  1760. return nPropCount;
  1761. }
  1762. //-----------------------------------------------------------------------------
  1763. // Count the number of fast sprites in the leaf list
  1764. //-----------------------------------------------------------------------------
  1765. int CDetailObjectSystem::CountFastSpritesInLeafList( int nLeafCount, LeafIndex_t const *pLeafList,
  1766. int *nMaxFoundInLeaf ) const
  1767. {
  1768. VPROF_BUDGET( "CDetailObjectSystem::CountSpritesInLeafList", VPROF_BUDGETGROUP_DETAILPROP_RENDERING );
  1769. int nCount = 0;
  1770. int nMax = 0;
  1771. for ( int i = 0; i < nLeafCount; ++i )
  1772. {
  1773. CFastDetailLeafSpriteList *pData = reinterpret_cast< CFastDetailLeafSpriteList *> (
  1774. ClientLeafSystem()->GetSubSystemDataInLeaf( pLeafList[i], CLSUBSYSTEM_DETAILOBJECTS ) );
  1775. if ( pData )
  1776. {
  1777. nCount += pData->m_nNumSprites;
  1778. nMax = MAX( nMax, pData->m_nNumSprites );
  1779. }
  1780. }
  1781. *nMaxFoundInLeaf = ( nMax + 3 ) & ~3; // round up
  1782. return nCount;
  1783. }
  1784. //-----------------------------------------------------------------------------
  1785. // Count the number of detail sprite quads in the leaf list
  1786. //-----------------------------------------------------------------------------
  1787. int CDetailObjectSystem::CountSpriteQuadsInLeafList( int nLeafCount, LeafIndex_t *pLeafList ) const
  1788. {
  1789. #ifdef USE_DETAIL_SHAPES
  1790. VPROF_BUDGET( "CDetailObjectSystem::CountSpritesInLeafList", VPROF_BUDGETGROUP_DETAILPROP_RENDERING );
  1791. int nQuadCount = 0;
  1792. int nFirstDetailObject, nDetailObjectCount;
  1793. for ( int i = 0; i < nLeafCount; ++i )
  1794. {
  1795. // FIXME: This actually counts *everything* in the leaf, which is ok for now
  1796. // given how we're using it
  1797. ClientLeafSystem()->GetDetailObjectsInLeaf( pLeafList[i], nFirstDetailObject, nDetailObjectCount );
  1798. for ( int j = 0; j < nDetailObjectCount; ++j )
  1799. {
  1800. nQuadCount += m_DetailObjects[j + nFirstDetailObject].QuadsToDraw();
  1801. }
  1802. }
  1803. return nQuadCount;
  1804. #else
  1805. return CountSpritesInLeafList( nLeafCount, pLeafList );
  1806. #endif
  1807. }
  1808. #define TREATASINT(x) ( *( ( (int32 const *)( &(x) ) ) ) )
  1809. //-----------------------------------------------------------------------------
  1810. // Sorts sprites in back-to-front order
  1811. //-----------------------------------------------------------------------------
  1812. inline bool CDetailObjectSystem::SortLessFunc( const CDetailObjectSystem::SortInfo_t &left, const CDetailObjectSystem::SortInfo_t &right )
  1813. {
  1814. return TREATASINT( left.m_flDistance ) > TREATASINT( right.m_flDistance );
  1815. }
  1816. int CDetailObjectSystem::SortSpritesBackToFront( int nLeaf, const Vector &viewOrigin, const DistanceFadeInfo_t &fadeInfo, SortInfo_t *pSortInfo )
  1817. {
  1818. VPROF_BUDGET( "CDetailObjectSystem::SortSpritesBackToFront", VPROF_BUDGETGROUP_DETAILPROP_RENDERING );
  1819. int nFirstDetailObject, nDetailObjectCount;
  1820. ClientLeafSystem()->GetDetailObjectsInLeaf( nLeaf, nFirstDetailObject, nDetailObjectCount );
  1821. Vector vecDelta;
  1822. int nCount = 0;
  1823. nDetailObjectCount += nFirstDetailObject;
  1824. for ( int j = nFirstDetailObject; j < nDetailObjectCount; ++j )
  1825. {
  1826. CDetailModel &model = m_DetailObjects[j];
  1827. if ( model.GetType() == DETAIL_PROP_TYPE_MODEL )
  1828. continue;
  1829. float flSqDist;
  1830. uint8 nAlpha = ComputeDistanceFade( &flSqDist, fadeInfo, viewOrigin, model.GetRenderOrigin() );
  1831. if ( nAlpha == 0 )
  1832. continue;
  1833. // Perform screen alignment if necessary.
  1834. model.ComputeAngles();
  1835. SortInfo_t *pSortInfoCurrent = &pSortInfo[nCount];
  1836. pSortInfoCurrent->m_nIndex = j;
  1837. pSortInfoCurrent->m_nAlpha = nAlpha;
  1838. // Compute distance from the camera to each object
  1839. pSortInfoCurrent->m_flDistance = flSqDist;
  1840. ++nCount;
  1841. }
  1842. if ( nCount )
  1843. {
  1844. VPROF( "CDetailObjectSystem::SortSpritesBackToFront -- Sort" );
  1845. std::make_heap( pSortInfo, pSortInfo + nCount, SortLessFunc );
  1846. std::sort_heap( pSortInfo, pSortInfo + nCount, SortLessFunc );
  1847. }
  1848. return nCount;
  1849. }
  1850. #define MAGIC_NUMBER (1<<23)
  1851. #ifdef PLAT_BIG_ENDIAN
  1852. #define MANTISSA_LSB_OFFSET 3
  1853. #else
  1854. #define MANTISSA_LSB_OFFSET 0
  1855. #endif
  1856. static fltx4 Four_MagicNumbers={ MAGIC_NUMBER, MAGIC_NUMBER, MAGIC_NUMBER, MAGIC_NUMBER };
  1857. static fltx4 Four_255s={ 255.0, 255.0, 255.0, 255.0 };
  1858. static ALIGN16 int32 And255Mask[4] ALIGN16_POST = {0xff,0xff,0xff,0xff};
  1859. #define PIXMASK ( * ( reinterpret_cast< fltx4 *>( &And255Mask ) ) )
  1860. int CDetailObjectSystem::BuildOutSortedSprites( CFastDetailLeafSpriteList *pData,
  1861. const DistanceFadeInfo_t &info,
  1862. Vector const &viewOrigin,
  1863. Vector const &viewForward,
  1864. Vector const &viewRight,
  1865. Vector const &viewUp )
  1866. {
  1867. // part 1 - do all vertex math, fading, etc into a buffer, using as much simd as we can
  1868. int nSIMDSprites = pData->m_nNumSIMDSprites;
  1869. FastSpriteX4_t const *pSprites = pData->m_pSprites;
  1870. SortInfo_t *pOut = m_pFastSortInfo;
  1871. pOut[0].m_nIndex = 1;
  1872. FastSpriteQuadBuildoutBufferX4_t *pQuadBufferOut = m_pBuildoutBuffer;
  1873. pQuadBufferOut->m_Coords[0].x = Four_Zeros;
  1874. int curidx = 0;
  1875. int nLastBfMask = 0;
  1876. Vector4D vNormal( -viewForward.x, -viewForward.y, -viewForward.z, 0.0 );
  1877. FourVectors vecViewPos;
  1878. vecViewPos.DuplicateVector( viewOrigin );
  1879. fltx4 maxsqdist = ReplicateX4( info.m_flMaxDistSqr );
  1880. fltx4 falloffFactor = ReplicateX4( 1.0/ ( info.m_flMaxDistSqr - info.m_flMinDistSqr ) );
  1881. fltx4 startFade = ReplicateX4( info.m_flMinDistSqr );
  1882. FourVectors vecUp;
  1883. vecUp.DuplicateVector(Vector(0,0,1) );
  1884. FourVectors vecFwd;
  1885. vecFwd.DuplicateVector( viewForward );
  1886. do
  1887. {
  1888. // calculate alpha
  1889. FourVectors ofs = pSprites->m_Pos;
  1890. ofs -= vecViewPos;
  1891. fltx4 ofsDotFwd = ofs * vecFwd;
  1892. fltx4 distanceSquared = ofs * ofs;
  1893. nLastBfMask = TestSignSIMD( OrSIMD( ofsDotFwd, CmpGtSIMD( distanceSquared, maxsqdist ) ) ); // cull
  1894. if ( nLastBfMask != 0xf )
  1895. {
  1896. FourVectors dx1;
  1897. dx1.x = fnegate( ofs.y );
  1898. dx1.y = ( ofs.x );
  1899. dx1.z = Four_Zeros;
  1900. dx1.VectorNormalizeFast();
  1901. FourVectors vecDx = dx1;
  1902. FourVectors vecDy = vecUp;
  1903. FourVectors vecPos0 = pSprites->m_Pos;
  1904. vecDx *= pSprites->m_HalfWidth;
  1905. vecDy *= pSprites->m_Height;
  1906. fltx4 alpha = MulSIMD( falloffFactor, SubSIMD( distanceSquared, startFade ) );
  1907. alpha = SubSIMD( Four_Ones, MinSIMD( MaxSIMD( alpha, Four_Zeros), Four_Ones ) );
  1908. pQuadBufferOut->m_Alpha = AddSIMD( Four_MagicNumbers,
  1909. MulSIMD( Four_255s,alpha ) );
  1910. vecPos0 += vecDx;
  1911. pQuadBufferOut->m_Coords[0] = vecPos0;
  1912. vecPos0 -= vecDy;
  1913. pQuadBufferOut->m_Coords[1] = vecPos0;
  1914. vecPos0 -= vecDx;
  1915. vecPos0 -= vecDx;
  1916. pQuadBufferOut->m_Coords[2] = vecPos0;
  1917. vecPos0 += vecDy;
  1918. pQuadBufferOut->m_Coords[3] = vecPos0;
  1919. fltx4 fetch4 = *( ( fltx4 *) ( &pSprites->m_pSpriteDefs[0] ) );
  1920. *( (fltx4 *) ( & ( pQuadBufferOut->m_pSpriteDefs[0] ) ) ) = fetch4;
  1921. fetch4 = *( ( fltx4 *) ( &pSprites->m_RGBColor[0][0] ) );
  1922. *( (fltx4 *) ( & ( pQuadBufferOut->m_RGBColor[0][0] ) ) ) = fetch4;
  1923. //!! bug!! store distance
  1924. // !! speed!! simd?
  1925. pOut[0].m_nIndex = curidx;
  1926. pOut[0].m_flDistance = SubFloat( distanceSquared, 0 );
  1927. pOut[1].m_nIndex = curidx+1;
  1928. pOut[1].m_flDistance = SubFloat( distanceSquared, 1 );
  1929. pOut[2].m_nIndex = curidx+2;
  1930. pOut[2].m_flDistance = SubFloat( distanceSquared, 2 );
  1931. pOut[3].m_nIndex = curidx+3;
  1932. pOut[3].m_flDistance = SubFloat( distanceSquared, 3 );
  1933. pQuadBufferOut->m_Normal = vNormal;
  1934. curidx += 4;
  1935. pOut += 4;
  1936. pQuadBufferOut++;
  1937. }
  1938. pSprites++;
  1939. } while( --nSIMDSprites );
  1940. // adjust count for tail
  1941. int nCount = pOut - m_pFastSortInfo;
  1942. if ( nLastBfMask != 0xf ) // if last not skipped
  1943. nCount -= ( 0 - pData->m_nNumSprites ) & 3;
  1944. // part 2 - sort
  1945. if ( nCount )
  1946. {
  1947. VPROF( "CDetailObjectSystem::SortSpritesBackToFront -- Sort" );
  1948. std::make_heap( m_pFastSortInfo, m_pFastSortInfo + nCount, SortLessFunc );
  1949. std::sort_heap( m_pFastSortInfo, m_pFastSortInfo + nCount, SortLessFunc );
  1950. }
  1951. return nCount;
  1952. }
  1953. static void s_RenderFastSpriteGuts( CDetailObjectSystem *pThis, DistanceFadeInfo_t info, Vector viewOrigin, Vector viewForward, Vector viewRight, Vector viewUp, int nNumLeafs, CUtlEnvelope<LeafIndex_t> const &leaflist )
  1954. {
  1955. pThis->RenderFastSprites( info, viewOrigin, viewForward, viewRight, viewUp, nNumLeafs, leaflist );
  1956. }
  1957. static void UTIL_MeshBuildSpriteQuad( CMeshBuilder* meshBuilder, const Vector &vecPos, const float &flHalfWidth, const float &flHeight, const DetailPropSpriteDict_t *spriteDef, const uint8 *vecRBGColor )
  1958. {
  1959. meshBuilder->Position3f( vecPos.x, vecPos.y, vecPos.z );
  1960. meshBuilder->Color4ubv( vecRBGColor );
  1961. meshBuilder->TexCoord4f( 0, spriteDef->m_TexLR.x, spriteDef->m_TexLR.y, flHalfWidth, 0 );
  1962. meshBuilder->AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>();
  1963. meshBuilder->Position3f( vecPos.x, vecPos.y, vecPos.z );
  1964. meshBuilder->Color4ubv( vecRBGColor );
  1965. meshBuilder->TexCoord4f( 0, spriteDef->m_TexLR.x, spriteDef->m_TexUL.y, flHalfWidth, flHeight);
  1966. meshBuilder->AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>();
  1967. meshBuilder->Position3f( vecPos.x, vecPos.y, vecPos.z );
  1968. meshBuilder->Color4ubv( vecRBGColor );
  1969. meshBuilder->TexCoord4f( 0, spriteDef->m_TexUL.x, spriteDef->m_TexUL.y, -flHalfWidth, flHeight);
  1970. meshBuilder->AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>();
  1971. meshBuilder->Position3f( vecPos.x, vecPos.y, vecPos.z );
  1972. meshBuilder->Color4ubv( vecRBGColor );
  1973. meshBuilder->TexCoord4f( 0, spriteDef->m_TexUL.x, spriteDef->m_TexLR.y, -flHalfWidth, 0 );
  1974. meshBuilder->AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>();
  1975. }
  1976. #define CACHED_SPRITE_MESH_QUADS_PER_BATCH 4096
  1977. void CDetailObjectSystem::RenderFastSprites( const DistanceFadeInfo_t &info, const Vector &viewOrigin, const Vector &viewForward, const Vector &viewRight, const Vector &viewUp, int nLeafCount, LeafIndex_t const * pLeafList )
  1978. {
  1979. // Here, we must draw all detail objects
  1980. // Count the total # of detail quads we possibly could render
  1981. int nMaxInLeaf;
  1982. int nQuadCount = CountFastSpritesInLeafList( nLeafCount, pLeafList, &nMaxInLeaf );
  1983. if ( nQuadCount == 0 )
  1984. return;
  1985. if ( r_DrawDetailProps.GetInt() == 0 )
  1986. return;
  1987. IMaterial *pMaterial = m_DetailSpriteMaterial;
  1988. if ( ShouldDrawInWireFrameMode() || r_DrawDetailProps.GetInt() == 2 )
  1989. {
  1990. pMaterial = m_DetailWireframeMaterial;
  1991. }
  1992. if(pMaterial == NULL)
  1993. {
  1994. // Should never happen, but we crash if this fails so abort here as a failsafe.
  1995. // (I believe this bug is fixed elsewhere but I like to be thorough, especially
  1996. // with crashes -- REI)
  1997. return;
  1998. }
  1999. CMatRenderContextPtr pRenderContext( materials );
  2000. pRenderContext->MatrixMode( MATERIAL_MODEL );
  2001. pRenderContext->PushMatrix();
  2002. pRenderContext->LoadIdentity();
  2003. pRenderContext->Bind( pMaterial );
  2004. //DetailPropFlashlightMode_t flashlightMode = DetailPropFlashlightMode();
  2005. IMesh *pMesh = NULL;
  2006. // render detail sprites per leaf in cached batches
  2007. for ( int i = 0; i < nLeafCount; ++i )
  2008. {
  2009. int nLeaf = pLeafList[i];
  2010. int nSubSplit = 0;
  2011. if ( m_pCachedSpriteMesh[nLeaf][0] != NULL )
  2012. {
  2013. for ( int n = 0; m_pCachedSpriteMesh[nLeaf][n] != NULL && n < CACHED_SPRITE_SUB_SPLIT_COUNT; n++ )
  2014. {
  2015. m_pCachedSpriteMesh[nLeaf][n]->Draw();
  2016. }
  2017. continue;
  2018. }
  2019. else
  2020. {
  2021. m_pCachedSpriteMesh[nLeaf][0] = pRenderContext->CreateStaticMesh( pMaterial->GetVertexFormat() & ~VERTEX_FORMAT_COMPRESSED, TEXTURE_GROUP_STATIC_VERTEX_BUFFER_OTHER, pMaterial );
  2022. m_nCachedSpriteMeshPtrs.AddToTail( &m_pCachedSpriteMesh[nLeaf][0] );
  2023. pMesh = m_pCachedSpriteMesh[nLeaf][0];
  2024. }
  2025. CFastDetailLeafSpriteList *pData = reinterpret_cast<CFastDetailLeafSpriteList *> ( ClientLeafSystem()->GetSubSystemDataInLeaf( nLeaf, CLSUBSYSTEM_DETAILOBJECTS ) );
  2026. if ( pData )
  2027. {
  2028. Assert( pData->m_nNumSprites );
  2029. int nCount = pData->m_nNumSIMDSprites;
  2030. CMeshBuilder meshBuilder;
  2031. meshBuilder.Begin( pMesh, MATERIAL_QUADS, MIN( pData->m_nNumSprites, CACHED_SPRITE_MESH_QUADS_PER_BATCH ) );
  2032. int nQuadsBuiltInThisBatch = 0;
  2033. int nQuadsLeft = pData->m_nNumSprites;
  2034. FastSpriteX4_t const *pSprites = pData->m_pSprites;
  2035. int x4;
  2036. do
  2037. {
  2038. for ( x4=0; x4<4; x4++ )
  2039. {
  2040. if ( nQuadsLeft )
  2041. {
  2042. UTIL_MeshBuildSpriteQuad( &meshBuilder,
  2043. pSprites->m_Pos.Vec(x4),
  2044. SubFloat( pSprites->m_HalfWidth, x4 ),
  2045. SubFloat( pSprites->m_Height, x4 ),
  2046. pSprites->m_pSpriteDefs[x4],
  2047. pSprites->m_RGBColor[x4] );
  2048. nQuadsBuiltInThisBatch++; nQuadsLeft--;
  2049. }
  2050. else
  2051. {
  2052. break;
  2053. }
  2054. }
  2055. if ( nQuadsBuiltInThisBatch > CACHED_SPRITE_MESH_QUADS_PER_BATCH )
  2056. {
  2057. meshBuilder.End();
  2058. pMesh->Draw();
  2059. //if( flashlightMode == DPFM_MULTIPASS )
  2060. // shadowmgr->FlashlightDrawCallback( DrawMeshCallback, pMesh );
  2061. nSubSplit++;
  2062. if ( nSubSplit >= CACHED_SPRITE_SUB_SPLIT_COUNT )
  2063. {
  2064. AssertMsg(0, "Detail sprite mesh exceeds 128,000 tris in a single leaf! This is too heavy, even for the gpu.");
  2065. break;
  2066. }
  2067. m_pCachedSpriteMesh[nLeaf][nSubSplit] = pRenderContext->CreateStaticMesh( pMaterial->GetVertexFormat() & ~VERTEX_FORMAT_COMPRESSED, TEXTURE_GROUP_STATIC_VERTEX_BUFFER_OTHER, pMaterial );
  2068. m_nCachedSpriteMeshPtrs.AddToTail( &m_pCachedSpriteMesh[nLeaf][nSubSplit] );
  2069. pMesh = m_pCachedSpriteMesh[nLeaf][nSubSplit];
  2070. meshBuilder.Begin( pMesh, MATERIAL_QUADS, MIN( nQuadsLeft, CACHED_SPRITE_MESH_QUADS_PER_BATCH ) );
  2071. nQuadsBuiltInThisBatch = 0;
  2072. }
  2073. pSprites++;
  2074. } while (--nCount);
  2075. meshBuilder.End();
  2076. pMesh->Draw();
  2077. //if( flashlightMode == DPFM_MULTIPASS )
  2078. // shadowmgr->FlashlightDrawCallback( DrawMeshCallback, pMesh );
  2079. }
  2080. }
  2081. pRenderContext->PopMatrix();
  2082. }
  2083. static void PushSinglePassFlashLightState( DetailPropFlashlightMode_t nMode )
  2084. {
  2085. //#ifndef _GAMECONSOLE
  2086. shadowmgr->PushSinglePassFlashlightStateEnabled( nMode == DPFM_SINGLEPASS );
  2087. //#endif
  2088. }
  2089. static void PopSinglePassFlashLightState( void )
  2090. {
  2091. //#ifndef _GAMECONSOLE
  2092. shadowmgr->PopSinglePassFlashlightStateEnabled();
  2093. //#endif
  2094. }
  2095. //-----------------------------------------------------------------------------
  2096. // Renders all translucent detail objects in a particular set of leaves
  2097. //-----------------------------------------------------------------------------
  2098. void CDetailObjectSystem::RenderTranslucentDetailObjects( const DistanceFadeInfo_t &info, const Vector &viewOrigin, const Vector &viewForward, const Vector &viewRight, const Vector &viewUp, int nLeafCount, LeafIndex_t *pLeafList )
  2099. {
  2100. VPROF_BUDGET( "CDetailObjectSystem::RenderTranslucentDetailObjects", VPROF_BUDGETGROUP_DETAILPROP_RENDERING );
  2101. if (nLeafCount == 0)
  2102. return;
  2103. // We better not have any partially drawn leaf of detail sprites!
  2104. Assert( m_nSpriteCount == m_nFirstSprite );
  2105. DetailPropFlashlightMode_t flashlightMode = DetailPropFlashlightMode();
  2106. PushSinglePassFlashLightState( flashlightMode );
  2107. // Here, we must draw all detail objects back-to-front
  2108. CMatRenderContextPtr pRenderContext( materials );
  2109. Assert( m_pFastSortInfo );
  2110. ICallQueue *pQueue = pRenderContext->GetCallQueue();
  2111. if ( pQueue && r_ThreadedDetailProps.GetInt() )
  2112. {
  2113. pQueue->QueueCall( s_RenderFastSpriteGuts, this, info, viewOrigin, viewForward, viewRight, viewUp, nLeafCount, CUtlEnvelope<LeafIndex_t>( pLeafList, nLeafCount ) );
  2114. }
  2115. else
  2116. RenderFastSprites( info, viewOrigin, viewForward, viewRight, viewUp, nLeafCount, pLeafList );
  2117. PopSinglePassFlashLightState();
  2118. // FIXME: Cache off a sorted list so we don't have to re-sort every frame
  2119. // Count the total # of detail quads we possibly could render
  2120. int nQuadCount = CountSpriteQuadsInLeafList( nLeafCount, pLeafList );
  2121. if ( nQuadCount == 0 )
  2122. return;
  2123. PushSinglePassFlashLightState( flashlightMode );
  2124. pRenderContext->MatrixMode( MATERIAL_MODEL );
  2125. pRenderContext->PushMatrix();
  2126. pRenderContext->LoadIdentity();
  2127. IMaterial *pMaterial = m_DetailSpriteMaterial;
  2128. if ( ShouldDrawInWireFrameMode() || r_DrawDetailProps.GetInt() == 2 )
  2129. {
  2130. pMaterial = m_DetailWireframeMaterial;
  2131. }
  2132. CMeshBuilder meshBuilder;
  2133. IMesh *pMesh = pRenderContext->GetDynamicMesh( flashlightMode != DPFM_MULTIPASS, NULL, NULL, pMaterial );
  2134. int nMaxVerts, nMaxIndices;
  2135. pRenderContext->GetMaxToRender( pMesh, false, &nMaxVerts, &nMaxIndices );
  2136. int nMaxQuadsToDraw = nMaxIndices / 6;
  2137. if ( nMaxQuadsToDraw > nMaxVerts / 4 )
  2138. {
  2139. nMaxQuadsToDraw = nMaxVerts / 4;
  2140. }
  2141. if ( nMaxQuadsToDraw == 0 )
  2142. return;
  2143. int nQuadsToDraw = nQuadCount;
  2144. if ( nQuadsToDraw > nMaxQuadsToDraw )
  2145. {
  2146. nQuadsToDraw = nMaxQuadsToDraw;
  2147. }
  2148. meshBuilder.Begin( pMesh, MATERIAL_QUADS, nQuadsToDraw );
  2149. int nQuadsDrawn = 0;
  2150. for ( int i = 0; i < nLeafCount; ++i )
  2151. {
  2152. int nLeaf = pLeafList[i];
  2153. int nFirstDetailObject, nDetailObjectCount;
  2154. ClientLeafSystem()->GetDetailObjectsInLeaf( nLeaf, nFirstDetailObject, nDetailObjectCount );
  2155. // Sort detail sprites in each leaf independently; then render them
  2156. SortInfo_t *pSortInfo = m_pSortInfo;
  2157. int nCount = SortSpritesBackToFront( nLeaf, viewOrigin, info, pSortInfo );
  2158. for ( int j = 0; j < nCount; ++j )
  2159. {
  2160. CDetailModel &model = m_DetailObjects[ pSortInfo[j].m_nIndex ];
  2161. int nQuadsInModel = model.QuadsToDraw();
  2162. // Prevent the batches from getting too large
  2163. if ( nQuadsDrawn + nQuadsInModel > nQuadsToDraw )
  2164. {
  2165. meshBuilder.End();
  2166. pMesh->Draw();
  2167. if( flashlightMode == DPFM_MULTIPASS )
  2168. shadowmgr->FlashlightDrawCallback( DrawMeshCallback, pMesh );
  2169. nQuadCount -= nQuadsDrawn;
  2170. nQuadsToDraw = nQuadCount;
  2171. if (nQuadsToDraw > nMaxQuadsToDraw)
  2172. {
  2173. nQuadsToDraw = nMaxQuadsToDraw;
  2174. }
  2175. meshBuilder.Begin( pMesh, MATERIAL_QUADS, nQuadsToDraw );
  2176. nQuadsDrawn = 0;
  2177. }
  2178. model.DrawSprite( meshBuilder, pSortInfo[j].m_nAlpha );
  2179. nQuadsDrawn += nQuadsInModel;
  2180. }
  2181. }
  2182. meshBuilder.End();
  2183. pMesh->Draw();
  2184. if( flashlightMode == DPFM_MULTIPASS )
  2185. shadowmgr->FlashlightDrawCallback( DrawMeshCallback, pMesh );
  2186. PopSinglePassFlashLightState();
  2187. pRenderContext->PopMatrix();
  2188. }
  2189. void CDetailObjectSystem::RenderFastTranslucentDetailObjectsInLeaf( CFastDetailLeafSpriteList *pData, const DistanceFadeInfo_t &info, const Vector &viewOrigin, const Vector &viewForward, const Vector &viewRight, const Vector &viewUp, int nLeaf, const Vector &vecClosestPoint, bool bFirstCallThisFrame )
  2190. {
  2191. if ( bFirstCallThisFrame || ( m_nSortedFastLeaf != nLeaf ) )
  2192. {
  2193. m_nSortedFastLeaf = nLeaf;
  2194. pData->m_nNumPendingSprites = BuildOutSortedSprites( pData, info, viewOrigin, viewForward, viewRight, viewUp );
  2195. pData->m_nStartSpriteIndex = 0;
  2196. }
  2197. if ( pData->m_nNumPendingSprites == 0 )
  2198. {
  2199. return;
  2200. }
  2201. Vector vecDelta;
  2202. VectorSubtract( vecClosestPoint, viewOrigin, vecDelta );
  2203. float flMinDistance = vecDelta.LengthSqr();
  2204. // we're not supposed to render sprites < flmindistance
  2205. if ( m_pFastSortInfo[pData->m_nStartSpriteIndex].m_flDistance < flMinDistance )
  2206. {
  2207. return;
  2208. }
  2209. int nCount = pData->m_nNumPendingSprites;
  2210. CMatRenderContextPtr pRenderContext( materials );
  2211. pRenderContext->MatrixMode( MATERIAL_MODEL );
  2212. pRenderContext->PushMatrix();
  2213. pRenderContext->LoadIdentity();
  2214. IMaterial *pMaterial = m_DetailSpriteMaterial;
  2215. if ( ShouldDrawInWireFrameMode() || r_DrawDetailProps.GetInt() == 2 )
  2216. {
  2217. pMaterial = m_DetailWireframeMaterial;
  2218. }
  2219. CMeshBuilder meshBuilder;
  2220. DetailPropFlashlightMode_t flashlightMode = DetailPropFlashlightMode();
  2221. IMesh *pMesh = pRenderContext->GetDynamicMesh( false /*flashlightMode != DPFM_MULTIPASS*/, NULL, NULL, pMaterial );
  2222. int nMaxVerts, nMaxIndices;
  2223. pRenderContext->GetMaxToRender( pMesh, false, &nMaxVerts, &nMaxIndices );
  2224. int nMaxQuadsToDraw = nMaxIndices / 6;
  2225. if ( nMaxQuadsToDraw > nMaxVerts / 4 )
  2226. {
  2227. nMaxQuadsToDraw = nMaxVerts / 4;
  2228. }
  2229. if ( nMaxQuadsToDraw == 0 )
  2230. return;
  2231. int nQuadsToDraw = MIN( nCount, nMaxQuadsToDraw );
  2232. int nQuadsRemaining = nQuadsToDraw;
  2233. meshBuilder.Begin( pMesh, MATERIAL_QUADS, nQuadsToDraw );
  2234. SortInfo_t const *pDraw = m_pFastSortInfo + pData->m_nStartSpriteIndex;
  2235. FastSpriteQuadBuildoutBufferNonSIMDView_t const *pQuadBuffer =
  2236. ( FastSpriteQuadBuildoutBufferNonSIMDView_t const *) m_pBuildoutBuffer;
  2237. while( nCount && ( pDraw->m_flDistance >= flMinDistance ) )
  2238. {
  2239. if ( ! nQuadsRemaining ) // no room left?
  2240. {
  2241. meshBuilder.End();
  2242. pMesh->Draw();
  2243. if( flashlightMode == DPFM_MULTIPASS )
  2244. shadowmgr->FlashlightDrawCallback( DrawMeshCallback, pMesh );
  2245. nQuadsRemaining = nQuadsToDraw;
  2246. meshBuilder.Begin( pMesh, MATERIAL_QUADS, nQuadsToDraw );
  2247. }
  2248. int nToDraw = MIN( nCount, nQuadsRemaining );
  2249. nCount -= nToDraw;
  2250. nQuadsRemaining -= nToDraw;
  2251. while( nToDraw-- )
  2252. {
  2253. // draw the sucker
  2254. int nSIMDIdx = pDraw->m_nIndex >> 2;
  2255. int nSubIdx = pDraw->m_nIndex & 3;
  2256. FastSpriteQuadBuildoutBufferNonSIMDView_t const *pquad = pQuadBuffer+nSIMDIdx;
  2257. const Vector4D &vNormal = pquad->m_Normal;
  2258. // voodoo - since everything is in 4s, offset structure pointer by a couple of floats to handle sub-index
  2259. pquad = (FastSpriteQuadBuildoutBufferNonSIMDView_t const *) ( ( (intp) ( pquad ) )+ ( nSubIdx << 2 ) );
  2260. uint8 const *pColorsCasted = reinterpret_cast<uint8 const *> ( pquad->m_Alpha );
  2261. uint8 color[4];
  2262. color[0] = pquad->m_RGBColor[0][0];
  2263. color[1] = pquad->m_RGBColor[0][1];
  2264. color[2] = pquad->m_RGBColor[0][2];
  2265. color[3] = pColorsCasted[MANTISSA_LSB_OFFSET];
  2266. DetailPropSpriteDict_t *pDict = pquad->m_pSpriteDefs[0];
  2267. meshBuilder.Position3f( pquad->m_flX0[0], pquad->m_flY0[0], pquad->m_flZ0[0] );
  2268. meshBuilder.Color4ubv( color );
  2269. meshBuilder.TexCoord2f( 0, pDict->m_TexLR.x, pDict->m_TexLR.y );
  2270. meshBuilder.Normal3fv( vNormal.Base() );
  2271. meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR | VTX_HAVENORMAL, 1>();
  2272. meshBuilder.Position3f( pquad->m_flX1[0], pquad->m_flY1[0], pquad->m_flZ1[0] );
  2273. meshBuilder.Color4ubv( color );
  2274. meshBuilder.TexCoord2f( 0, pDict->m_TexLR.x, pDict->m_TexUL.y );
  2275. meshBuilder.Normal3fv( vNormal.Base() );
  2276. meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR | VTX_HAVENORMAL, 1>();
  2277. meshBuilder.Position3f( pquad->m_flX2[0], pquad->m_flY2[0], pquad->m_flZ2[0] );
  2278. meshBuilder.Color4ubv( color );
  2279. meshBuilder.TexCoord2f( 0, pDict->m_TexUL.x, pDict->m_TexUL.y );
  2280. meshBuilder.Normal3fv( vNormal.Base() );
  2281. meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR | VTX_HAVENORMAL, 1>();
  2282. meshBuilder.Position3f( pquad->m_flX3[0], pquad->m_flY3[0], pquad->m_flZ3[0] );
  2283. meshBuilder.Color4ubv( color );
  2284. meshBuilder.TexCoord2f( 0, pDict->m_TexUL.x, pDict->m_TexLR.y );
  2285. meshBuilder.Normal3fv( vNormal.Base() );
  2286. meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR | VTX_HAVENORMAL, 1>();
  2287. pDraw++;
  2288. }
  2289. }
  2290. pData->m_nNumPendingSprites = nCount;
  2291. pData->m_nStartSpriteIndex = pDraw - m_pFastSortInfo;
  2292. meshBuilder.End();
  2293. pMesh->Draw();
  2294. if( flashlightMode == DPFM_MULTIPASS )
  2295. shadowmgr->FlashlightDrawCallback( DrawMeshCallback, pMesh );
  2296. pRenderContext->PopMatrix();
  2297. }
  2298. //-----------------------------------------------------------------------------
  2299. // Renders a subset of the detail objects in a particular leaf (for interleaving with other translucent entities)
  2300. //-----------------------------------------------------------------------------
  2301. void CDetailObjectSystem::RenderTranslucentDetailObjectsInLeaf( const DistanceFadeInfo_t &info, const Vector &viewOrigin, const Vector &viewForward, const Vector &viewRight, const Vector &viewUp, int nLeaf, const Vector *pVecClosestPoint )
  2302. {
  2303. VPROF_BUDGET( "CDetailObjectSystem::RenderTranslucentDetailObjectsInLeaf", VPROF_BUDGETGROUP_DETAILPROP_RENDERING );
  2304. // FIXME: how to interleave around translucent props if we're not regenerating the cached sprite mesh? Could use a clipping plane?
  2305. {
  2306. LeafIndex_t oneLeaf[1] = { nLeaf };
  2307. RenderTranslucentDetailObjects( info, viewOrigin, viewForward, viewRight, viewUp, 1, oneLeaf );
  2308. return;
  2309. }
  2310. if ( r_DrawDetailProps.GetInt() == 0 )
  2311. return;
  2312. DetailPropFlashlightMode_t flashlightMode = DetailPropFlashlightMode();
  2313. CFastDetailLeafSpriteList *pData = reinterpret_cast< CFastDetailLeafSpriteList *> (
  2314. ClientLeafSystem()->GetSubSystemDataInLeaf( nLeaf, CLSUBSYSTEM_DETAILOBJECTS ) );
  2315. if ( pData )
  2316. {
  2317. shadowmgr->PushSinglePassFlashlightStateEnabled( flashlightMode == DPFM_SINGLEPASS );
  2318. CMatRenderContextPtr pRenderContext( materials );
  2319. Assert( m_pFastSortInfo );
  2320. ICallQueue *pQueue = pRenderContext->GetCallQueue();
  2321. Vector cpnt = viewOrigin;
  2322. if ( pVecClosestPoint )
  2323. {
  2324. cpnt = *pVecClosestPoint;
  2325. }
  2326. if ( pQueue && r_ThreadedDetailProps.GetInt() )
  2327. {
  2328. pQueue->QueueCall( this, &CDetailObjectSystem::RenderFastTranslucentDetailObjectsInLeaf,
  2329. pData, RefToVal( info ), viewOrigin, viewForward, viewRight, viewUp,
  2330. nLeaf, cpnt, m_bFirstLeaf );
  2331. }
  2332. else
  2333. {
  2334. RenderFastTranslucentDetailObjectsInLeaf( pData, info, viewOrigin, viewForward, viewRight, viewUp,
  2335. nLeaf, cpnt, m_bFirstLeaf );
  2336. }
  2337. m_bFirstLeaf = false;
  2338. shadowmgr->PopSinglePassFlashlightStateEnabled();
  2339. }
  2340. // We may have already sorted this leaf. If not, sort the leaf.
  2341. if ( m_nSortedLeaf != nLeaf )
  2342. {
  2343. m_nSortedLeaf = nLeaf;
  2344. m_nSpriteCount = 0;
  2345. m_nFirstSprite = 0;
  2346. // Count the total # of detail sprites we possibly could render
  2347. LeafIndex_t nLeafIndex = nLeaf;
  2348. int nSpriteCount = CountSpritesInLeafList( 1, &nLeafIndex );
  2349. if (nSpriteCount == 0)
  2350. return;
  2351. // Sort detail sprites in each leaf independently; then render them
  2352. m_nSpriteCount = SortSpritesBackToFront( nLeaf, viewOrigin, info, m_pSortInfo );
  2353. Assert( m_nSpriteCount <= nSpriteCount );
  2354. }
  2355. // No more to draw? Bye!
  2356. if ( m_nSpriteCount == m_nFirstSprite )
  2357. return;
  2358. float flMinDistance = 0.0f;
  2359. if ( pVecClosestPoint )
  2360. {
  2361. Vector vecDelta;
  2362. VectorSubtract( *pVecClosestPoint, viewOrigin, vecDelta );
  2363. flMinDistance = vecDelta.LengthSqr();
  2364. }
  2365. if ( m_pSortInfo[m_nFirstSprite].m_flDistance < flMinDistance )
  2366. return;
  2367. CMatRenderContextPtr pRenderContext( materials );
  2368. pRenderContext->MatrixMode( MATERIAL_MODEL );
  2369. pRenderContext->PushMatrix();
  2370. pRenderContext->LoadIdentity();
  2371. IMaterial *pMaterial = m_DetailSpriteMaterial;
  2372. if ( ShouldDrawInWireFrameMode() || r_DrawDetailProps.GetInt() == 2 )
  2373. {
  2374. pMaterial = m_DetailWireframeMaterial;
  2375. }
  2376. CMeshBuilder meshBuilder;
  2377. IMesh *pMesh = pRenderContext->GetDynamicMesh( flashlightMode != DPFM_MULTIPASS, NULL, NULL, pMaterial );
  2378. shadowmgr->PushSinglePassFlashlightStateEnabled( flashlightMode == DPFM_SINGLEPASS );
  2379. int nMaxVerts, nMaxIndices;
  2380. pRenderContext->GetMaxToRender( pMesh, false, &nMaxVerts, &nMaxIndices );
  2381. // needs to be * 4 since there are a max of 4 quads per detail object
  2382. int nQuadCount = ( m_nSpriteCount - m_nFirstSprite ) * 4;
  2383. int nMaxQuadsToDraw = nMaxIndices/6;
  2384. if ( nMaxQuadsToDraw > nMaxVerts / 4 )
  2385. {
  2386. nMaxQuadsToDraw = nMaxVerts / 4;
  2387. }
  2388. if ( nMaxQuadsToDraw == 0 )
  2389. return;
  2390. int nQuadsToDraw = nQuadCount;
  2391. if ( nQuadsToDraw > nMaxQuadsToDraw )
  2392. {
  2393. nQuadsToDraw = nMaxQuadsToDraw;
  2394. }
  2395. meshBuilder.Begin( pMesh, MATERIAL_QUADS, nQuadsToDraw );
  2396. int nQuadsDrawn = 0;
  2397. while ( m_nFirstSprite < m_nSpriteCount && m_pSortInfo[m_nFirstSprite].m_flDistance >= flMinDistance )
  2398. {
  2399. CDetailModel &model = m_DetailObjects[m_pSortInfo[m_nFirstSprite].m_nIndex];
  2400. int nQuadsInModel = model.QuadsToDraw();
  2401. if ( nQuadsDrawn + nQuadsInModel > nQuadsToDraw )
  2402. {
  2403. meshBuilder.End();
  2404. pMesh->Draw();
  2405. if( flashlightMode == DPFM_MULTIPASS )
  2406. shadowmgr->FlashlightDrawCallback( DrawMeshCallback, pMesh );
  2407. nQuadCount = ( m_nSpriteCount - m_nFirstSprite ) * 4;
  2408. nQuadsToDraw = nQuadCount;
  2409. if (nQuadsToDraw > nMaxQuadsToDraw)
  2410. {
  2411. nQuadsToDraw = nMaxQuadsToDraw;
  2412. }
  2413. meshBuilder.Begin( pMesh, MATERIAL_QUADS, nQuadsToDraw );
  2414. nQuadsDrawn = 0;
  2415. }
  2416. model.DrawSprite( meshBuilder, m_pSortInfo[m_nFirstSprite].m_nAlpha );
  2417. ++m_nFirstSprite;
  2418. nQuadsDrawn += nQuadsInModel;
  2419. }
  2420. meshBuilder.End();
  2421. pMesh->Draw();
  2422. if( flashlightMode == DPFM_MULTIPASS )
  2423. shadowmgr->FlashlightDrawCallback( DrawMeshCallback, pMesh );
  2424. shadowmgr->PopSinglePassFlashlightStateEnabled();
  2425. pRenderContext->PopMatrix();
  2426. }
  2427. //-----------------------------------------------------------------------------
  2428. // Computes a distance fade factor (returns fade distance)
  2429. //-----------------------------------------------------------------------------
  2430. float CDetailObjectSystem::ComputeDetailFadeInfo( DistanceFadeInfo_t *pInfo )
  2431. {
  2432. C_BasePlayer *pLocal = C_BasePlayer::GetLocalPlayer();
  2433. float flFactor = pLocal ? pLocal->GetFOVDistanceAdjustFactor() : 1.0f;
  2434. float flDetailDist = m_flDetailFadeEnd / flFactor;
  2435. pInfo->m_flMaxDistSqr = flDetailDist * flDetailDist;
  2436. pInfo->m_flMinDistSqr = m_flDetailFadeStart / flFactor;
  2437. pInfo->m_flMinDistSqr *= pInfo->m_flMinDistSqr;
  2438. pInfo->m_flMinDistSqr = MIN( pInfo->m_flMinDistSqr, pInfo->m_flMaxDistSqr - 1 );
  2439. pInfo->m_flFalloffFactor = 1.0f / ( pInfo->m_flMaxDistSqr - pInfo->m_flMinDistSqr );
  2440. return flDetailDist;
  2441. }
  2442. //-----------------------------------------------------------------------------
  2443. // Builds a list of renderable info for all detail objects to render
  2444. //-----------------------------------------------------------------------------
  2445. void CDetailObjectSystem::BuildRenderingData( DetailRenderableList_t &list, const SetupRenderInfo_t &info, float flDetailDist, const DistanceFadeInfo_t &fadeInfo )
  2446. {
  2447. SNPROF("CDetailObjectSystem::BuildRenderingData");
  2448. // Don't bother if we turned off detail props
  2449. if ( !GetClientMode()->ShouldDrawDetailObjects() || ( r_DrawDetailProps.GetInt() == 0 ) )
  2450. return;
  2451. // First, build the list of leaves which are within the appropriate range of detail dist
  2452. // [box/sphere tests of leaf bounds + sphere]
  2453. ISpatialQuery* pQuery = engine->GetBSPTreeQuery();
  2454. int nLeafCount = info.m_pWorldListInfo->m_LeafCount;
  2455. const WorldListLeafData_t *pLeafData = info.m_pWorldListInfo->m_pLeafDataList;
  2456. int *pValidLeafIndex = (int*)stackalloc( nLeafCount * sizeof(int) );
  2457. int nValidLeafs = pQuery->ListLeavesInSphereWithFlagSet(
  2458. pValidLeafIndex, info.m_vecRenderOrigin, flDetailDist, nLeafCount,
  2459. (const uint16*)pLeafData, sizeof(WorldListLeafData_t), LEAF_FLAGS_CONTAINS_DETAILOBJECTS );
  2460. if ( nValidLeafs == 0 )
  2461. return;
  2462. // FIXME: This loop is necessary to deal with marking leaves as needing detail
  2463. // props. Won't fly in multicore
  2464. int nFirstDetailObject, nDetailObjectCount;
  2465. for ( int i = 0; i < nValidLeafs; ++i )
  2466. {
  2467. int nListLeafIndex = pValidLeafIndex[ i ];
  2468. int nLeaf = pLeafData[ nListLeafIndex ].leafIndex;
  2469. // FIXME: Inherently not threadsafe ( use of nBuildWorldListNumber )
  2470. g_pClientLeafSystem->DrawDetailObjectsInLeaf( nLeaf, info.m_nDetailBuildFrame,
  2471. nFirstDetailObject, nDetailObjectCount );
  2472. }
  2473. // No detail objects? No work remaining.
  2474. if ( m_DetailObjects.Count() == 0 )
  2475. return;
  2476. // Then, for each leaf within range, compute alpha factor
  2477. float flDistSqr;
  2478. const Vector &vViewOrigin = info.m_vecRenderOrigin;
  2479. for ( int i = 0; i < nValidLeafs; ++i )
  2480. {
  2481. int nListLeafIndex = pValidLeafIndex[ i ];
  2482. int nLeaf = pLeafData[ nListLeafIndex ].leafIndex;
  2483. // FIXME: Inherently not threadsafe ( use of nBuildWorldListNumber )
  2484. g_pClientLeafSystem->GetDetailObjectsInLeaf( nLeaf, nFirstDetailObject, nDetailObjectCount );
  2485. // Compute the translucency. Need to do it now cause we need to
  2486. // know that when we're rendering (opaque stuff is rendered first)
  2487. for ( int j = 0; j < nDetailObjectCount; ++j)
  2488. {
  2489. // Calculate distance (badly)
  2490. CDetailModel& model = m_DetailObjects[ nFirstDetailObject + j ];
  2491. if ( model.GetType() != DETAIL_PROP_TYPE_MODEL )
  2492. continue;
  2493. uint8 nAlpha = ComputeDistanceFade( &flDistSqr, fadeInfo, vViewOrigin, model.GetRenderOrigin() );
  2494. if ( nAlpha == 0 )
  2495. continue;
  2496. // FIXME: Should we return a center + radius so culling can happen?
  2497. // right now, detail objects are not even frustum culled
  2498. int d = list.AddToTail();
  2499. DetailRenderableInfo_t &info = list[d];
  2500. info.m_pRenderable = &model;
  2501. info.m_InstanceData.m_nAlpha = nAlpha;
  2502. info.m_nRenderGroup = ( ( nAlpha != 255 ) || model.IsTranslucent() ) ? RENDER_GROUP_TRANSLUCENT : RENDER_GROUP_OPAQUE;
  2503. info.m_nLeafIndex = nListLeafIndex;
  2504. // FIXME: Inherently not threadsafe, not to mention not easily SIMDable
  2505. // move this to happen in DrawModel()
  2506. // Perform screen alignment if necessary.
  2507. model.ComputeAngles();
  2508. }
  2509. }
  2510. }
  2511. #if defined(_PS3)
  2512. //-----------------------------------------------------------------------------
  2513. // Helper for SPU job header
  2514. //-----------------------------------------------------------------------------
  2515. bool CDetailObjectSystem::ShouldDrawDetailObjects( void )
  2516. {
  2517. return( GetClientMode()->ShouldDrawDetailObjects() && ( r_DrawDetailProps.GetInt() != 0 ) );
  2518. }
  2519. //-----------------------------------------------------------------------------
  2520. // Helper for SPU job header
  2521. //-----------------------------------------------------------------------------
  2522. void CDetailObjectSystem::GetDetailFadeValues( float &flDetailFadeStart, float &flDetailFadeEnd )
  2523. {
  2524. flDetailFadeStart = m_flDetailFadeStart;
  2525. flDetailFadeEnd = m_flDetailFadeEnd;
  2526. };
  2527. #endif