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.

3107 lines
105 KiB

  1. //===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose: Model loading / unloading interface
  4. //
  5. // $NoKeywords: $
  6. //===========================================================================//
  7. #include "render_pch.h"
  8. #include "Overlay.h"
  9. #include "bspfile.h"
  10. #include "modelloader.h"
  11. #include "materialsystem/imesh.h"
  12. #include "materialsystem/ivballoctracker.h"
  13. #include "disp.h"
  14. #include "collisionutils.h"
  15. #include "tier0/vprof.h"
  16. #include "render.h"
  17. #include "r_decal.h"
  18. #include "fmtstr.h"
  19. // memdbgon must be the last include file in a .cpp file!!!
  20. #include "tier0/memdbgon.h"
  21. //-----------------------------------------------------------------------------
  22. // Externs
  23. //-----------------------------------------------------------------------------
  24. int g_OverlayRenderFrameID;
  25. //-----------------------------------------------------------------------------
  26. // Convars
  27. //-----------------------------------------------------------------------------
  28. static ConVar r_renderoverlaybatch("r_renderoverlaybatch", "1", FCVAR_DEVELOPMENTONLY);
  29. static ConVar r_renderoverlayfragment("r_renderoverlayfragment", "1");
  30. static ConVar r_overlaywireframe( "r_overlaywireframe", "0" );
  31. static ConVar r_overlayfadeenable( "r_overlayfadeenable", "0" );
  32. static ConVar r_overlayfademin( "r_overlayfademin", "1750" );
  33. static ConVar r_overlayfademax( "r_overlayfademax", "2000" );
  34. //-----------------------------------------------------------------------------
  35. // Structures used to represent the overlay
  36. //-----------------------------------------------------------------------------
  37. typedef unsigned short OverlayFragmentList_t;
  38. enum
  39. {
  40. OVERLAY_FRAGMENT_LIST_INVALID = (OverlayFragmentList_t)~0,
  41. };
  42. enum
  43. {
  44. NUM_OVERLAY_TEXCOORDS = 2,
  45. };
  46. struct overlayvert_t
  47. {
  48. Vector pos;
  49. Vector normal;
  50. Vector2D texCoord[NUM_OVERLAY_TEXCOORDS]; // texcoord 0 = the mapped tex coord from worldcraft
  51. // texcoord 1 is used for alpha and maps the whole texture into the whole overlay
  52. Vector2D tmpDispUV;
  53. float lightCoord[2];
  54. int packedColor;
  55. overlayvert_t()
  56. {
  57. pos.Init();
  58. normal.Init();
  59. texCoord[0].Init();
  60. texCoord[1].Init();
  61. tmpDispUV.Init();
  62. lightCoord[0] = lightCoord[1] = 0.0f;
  63. packedColor = 0xFFFFFFFF;
  64. }
  65. };
  66. struct moverlayfragment_t
  67. {
  68. int m_nRenderFrameID; // So we only render a fragment once a frame!
  69. SurfaceHandle_t m_SurfId; // Surface Id
  70. int m_iOverlay; // Overlay Id
  71. OverlayFragmentHandle_t m_hNextRender;
  72. unsigned short m_nMaterialSortID;
  73. CUtlVector<overlayvert_t> m_aPrimVerts;
  74. float decalOffset;
  75. int m_iMesh; // Mesh Id
  76. int m_nVertexBufferIndex;
  77. bool m_bFaded;
  78. };
  79. // this draws in the unlit pass
  80. #define FOVERLAY_DRAW_UNLIT 0x0001
  81. struct moverlay_t
  82. {
  83. int m_nId;
  84. short m_nTexInfo;
  85. short m_nRenderOrder; // 0 - MAX_OVERLAY_RENDER_ORDERS
  86. OverlayFragmentList_t m_hFirstFragment;
  87. unsigned short m_nFlags;
  88. CUtlVector<SurfaceHandle_t> m_aFaces;
  89. float m_flU[2];
  90. float m_flV[2];
  91. Vector m_vecUVPoints[4];
  92. Vector m_vecOrigin;
  93. Vector m_vecBasis[3]; // 0 = u, 1 = v, 2 = normal
  94. void *m_pBindProxy; // client renderable for an overlay's material proxy to bind to
  95. float m_flFadeDistMinSq; // Distance from the overlay's origin at which we start fading (-1 = use max dist)
  96. float m_flFadeDistMaxSq; // Distance from the overlay's origin at which we fade out completely
  97. float m_flInvFadeRangeSq; // Precomputed 1.0f / ( m_flFadeDistMaxSq - m_flFadeDistMinSq )
  98. float m_flRadius; // max distance of an overlay vertex from the origin
  99. byte m_nMinCPULevel;
  100. byte m_nMaxCPULevel;
  101. byte m_nMinGPULevel;
  102. byte m_nMaxGPULevel;
  103. // TODO: Probably want to clear out some other stuff, but this is the only add for now!
  104. moverlay_t()
  105. {
  106. m_nMinCPULevel = 0;
  107. m_nMaxCPULevel = 0;
  108. m_nMinGPULevel = 0;
  109. m_nMaxGPULevel = 0;
  110. }
  111. bool ShouldDraw( int nCPULevel, int nGPULevel )
  112. {
  113. bool bDraw = true;
  114. if ( m_nMinCPULevel != 0 )
  115. {
  116. bDraw = nCPULevel >= ( m_nMinCPULevel - 1 );
  117. }
  118. if ( bDraw && m_nMaxCPULevel != 0 )
  119. {
  120. bDraw = nCPULevel <= ( m_nMaxCPULevel - 1 );
  121. }
  122. if ( bDraw && m_nMinGPULevel != 0 )
  123. {
  124. bDraw = nGPULevel >= ( m_nMinGPULevel - 1 );
  125. }
  126. if ( bDraw && m_nMaxGPULevel != 0 )
  127. {
  128. bDraw = nGPULevel <= ( m_nMaxGPULevel - 1 );
  129. }
  130. return bDraw;
  131. }
  132. };
  133. // Going away!
  134. void Overlay_BuildBasisOrigin( Vector &vecBasisOrigin, SurfaceHandle_t surfID );
  135. void Overlay_BuildBasis( const Vector &vecBasisNormal, Vector &vecBasisU, Vector &vecBasisV, bool bFlip );
  136. void Overlay_OverlayUVToOverlayPlane( const Vector &vecBasisOrigin, const Vector &vecBasisU,
  137. const Vector &vecBasisV, const Vector &vecUVPoint,
  138. Vector &vecPlanePoint );
  139. void Overlay_WorldToOverlayPlane( const Vector &vecBasisOrigin, const Vector &vecBasisNormal,
  140. const Vector &vecWorldPoint, Vector &vecPlanePoint );
  141. void Overlay_OverlayPlaneToWorld( const Vector &vecBasisNormal, SurfaceHandle_t surfID,
  142. const Vector &vecPlanePoint, Vector &vecWorldPoint );
  143. void Overlay_DispUVToWorld( CDispInfo *pDisp, CMeshReader *pReader, const Vector2D &vecUV, Vector &vecWorld, Vector &vecWorldNormal, moverlayfragment_t &surfaceFrag );
  144. void Overlay_TriTLToBR( CDispInfo *pDisp, Vector &vecWorld, Vector &vecWorldNormal, float flU, float flV,
  145. int nSnapU, int nSnapV, int nWidth, int nHeight );
  146. void Overlay_TriBLToTR( CDispInfo *pDisp, Vector &vecWorld, Vector &vecWorldNormal, float flU, float flV,
  147. int nSnapU, int nSnapV, int nWidth, int nHeight );
  148. //-----------------------------------------------------------------------------
  149. // Overlay manager class
  150. //-----------------------------------------------------------------------------
  151. class COverlayMgr : public IOverlayMgr
  152. {
  153. public:
  154. typedef CUtlVector<moverlayfragment_t*> OverlayFragmentVector_t;
  155. public:
  156. COverlayMgr();
  157. ~COverlayMgr();
  158. // Implementation of IOverlayMgr interface
  159. virtual bool LoadOverlays( );
  160. virtual void UnloadOverlays( );
  161. virtual void CreateFragments( void );
  162. virtual void ReSortMaterials( void );
  163. virtual void ClearRenderLists();
  164. virtual void ClearRenderLists( int nSortGroup );
  165. virtual void AddFragmentListToRenderList( int nSortGroup, OverlayFragmentHandle_t iFragment, bool bDisp );
  166. virtual void RenderOverlays( IMatRenderContext *pRenderContext, int nSortGroup );
  167. virtual void RenderAllUnlitOverlays( IMatRenderContext *pRenderContext, int nSortGroup );
  168. virtual void SetOverlayBindProxy( int iOverlayID, void *pBindProxy );
  169. virtual void UpdateOverlayRenderLevels( int nCPULevel, int nGPULevel );
  170. private:
  171. void RenderOverlaysBatch( IMatRenderContext *pRenderContext, int nSortGroup );
  172. // Create, destroy material sort order ids...
  173. int GetMaterialSortID( IMaterial* pMaterial, int nLightmapPage );
  174. void CleanupMaterial( unsigned short nSortOrder );
  175. moverlay_t *GetOverlay( int iOverlay );
  176. moverlayfragment_t *GetOverlayFragment( OverlayFragmentHandle_t iFragment );
  177. // Surfaces
  178. void Surf_CreateFragments( moverlay_t *pOverlay, SurfaceHandle_t surfID );
  179. bool Surf_PreClipFragment( moverlay_t *pOverlay, moverlayfragment_t &overlayFrag, SurfaceHandle_t surfID, moverlayfragment_t &surfaceFrag );
  180. void Surf_PostClipFragment( moverlay_t *pOverlay, moverlayfragment_t &overlayFrag, SurfaceHandle_t surfID );
  181. void Surf_ClipFragment( moverlay_t *pOverlay, moverlayfragment_t &overlayFrag, SurfaceHandle_t surfID, moverlayfragment_t &surfaceFrag );
  182. // Displacements
  183. void Disp_CreateFragments( moverlay_t *pOverlay, SurfaceHandle_t surfID );
  184. bool Disp_PreClipFragment( moverlay_t *pOverlay, OverlayFragmentVector_t &aDispFragments, SurfaceHandle_t surfID );
  185. void Disp_PostClipFragment( CDispInfo *pDisp, CMeshReader *pReader, moverlay_t *pOverlay, OverlayFragmentVector_t &aDispFragments, SurfaceHandle_t surfID );
  186. void Disp_ClipFragment( CDispInfo *pDisp, OverlayFragmentVector_t &aDispFragments );
  187. void Disp_DoClip( CDispInfo *pDisp, OverlayFragmentVector_t &aCurrentFragments, cplane_t &clipPlane,
  188. float clipDistStart, int nInterval, int nLoopStart, int nLoopEnd, int nLoopInc );
  189. // Utility
  190. OverlayFragmentHandle_t AddFragmentToFragmentList( int nSize );
  191. OverlayFragmentHandle_t AddFragmentToFragmentList( moverlayfragment_t *pSrc );
  192. bool FadeOverlayFragmentGlobal( moverlayfragment_t *pFragment );
  193. bool FadeOverlayFragment( moverlay_t *pOverlay, moverlayfragment_t *pFragment );
  194. moverlayfragment_t *CreateTempFragment( int nSize );
  195. moverlayfragment_t *CopyTempFragment( moverlayfragment_t *pSrc );
  196. void DestroyTempFragment( moverlayfragment_t *pFragment );
  197. void BuildClipPlanes( SurfaceHandle_t surfID, moverlayfragment_t &surfaceFrag, const Vector &vecBasisNormal, CUtlVector<cplane_t> &m_ClipPlanes );
  198. void DoClipFragment( moverlayfragment_t *pFragment, cplane_t *pClipPlane, moverlayfragment_t **ppFront, moverlayfragment_t **ppBack );
  199. void InitTexCoords( moverlay_t *pOverlay, moverlayfragment_t &overlayFrag );
  200. void BuildStaticBuffers();
  201. void DestroyStaticBuffers();
  202. int FindOrdAddMesh( IMaterial* pMaterial, int vertCount );
  203. void DrawBatches( IMatRenderContext *pRenderContext, IMesh* pIndices, bool bWireframe );
  204. void DrawFadedFragments( IMatRenderContext *pRenderContext, int nSortGroup, bool bWireframe );
  205. private:
  206. enum
  207. {
  208. RENDER_QUEUE_INVALID = 0xFFFF
  209. };
  210. // Structures used to assign sort order handles
  211. struct RenderQueueInfo_t
  212. {
  213. OverlayFragmentHandle_t m_hFirstFragment;
  214. unsigned short m_nNextRenderQueue; // Index of next queue that has stuff to render
  215. unsigned short m_nVertexCount;
  216. unsigned short m_nIndexCount;
  217. };
  218. struct RenderQueueHead_t
  219. {
  220. IMaterial *m_pMaterial;
  221. int m_nLightmapPage;
  222. RenderQueueInfo_t m_Queue[MAX_MAT_SORT_GROUPS];
  223. unsigned short m_nRefCount;
  224. };
  225. struct RenderBatch_t
  226. {
  227. int m_iMesh;
  228. unsigned short m_nFirstIndex;
  229. unsigned short m_nNumIndex;
  230. IMaterial * m_pMaterial;
  231. void * m_pBindProxy;
  232. int m_nLightmapPage;
  233. RenderBatch_t() : m_iMesh(0), m_nFirstIndex(0), m_nNumIndex(0), m_pMaterial(NULL), m_pBindProxy(NULL), m_nLightmapPage(0)
  234. {}
  235. };
  236. struct RenderMesh_t
  237. {
  238. IMesh* m_pMesh;
  239. IMaterial * m_pMaterial;
  240. int m_nVertCount;
  241. VertexFormat_t m_VertexFormat;
  242. };
  243. // First render queue to render
  244. unsigned short m_nFirstRenderQueue[MAX_MAT_SORT_GROUPS];
  245. // Used to assign sort order handles
  246. CUtlLinkedList<RenderQueueHead_t, unsigned short> m_RenderQueue;
  247. // All overlays
  248. CUtlVector<moverlay_t> m_aOverlays;
  249. // List of all overlay fragments. prev/next links point to the next fragment on a *surface*
  250. CUtlLinkedList< moverlayfragment_t, unsigned short, true > m_aFragments;
  251. // Used to find all fragments associated with a particular overlay
  252. CUtlLinkedList< OverlayFragmentHandle_t, unsigned short, true > m_OverlayFragments;
  253. // list of batches used to render overlays - static VB and dynamic IB
  254. CUtlVector<RenderBatch_t> m_RenderBatchList;
  255. // list of faded fragments - dynamic VB and dynamic IB
  256. CUtlVector<OverlayFragmentHandle_t> m_RenderFadedFragments;
  257. // List of static VB
  258. CUtlVector<RenderMesh_t> m_RenderMeshes;
  259. // Fade parameters.
  260. float m_flFadeMin2;
  261. float m_flFadeMax2;
  262. float m_flFadeDelta2;
  263. // Cache the gpu/cpu levels.
  264. int m_nCPULevel;
  265. int m_nGPULevel;
  266. };
  267. //-----------------------------------------------------------------------------
  268. // Singleton accessor
  269. //-----------------------------------------------------------------------------
  270. static COverlayMgr g_OverlayMgr;
  271. IOverlayMgr *OverlayMgr( void )
  272. {
  273. return &g_OverlayMgr;
  274. }
  275. //-----------------------------------------------------------------------------
  276. // Constructor
  277. //-----------------------------------------------------------------------------
  278. COverlayMgr::COverlayMgr()
  279. {
  280. for ( int i = 0; i < MAX_MAT_SORT_GROUPS; ++i )
  281. {
  282. m_nFirstRenderQueue[i] = RENDER_QUEUE_INVALID;
  283. }
  284. m_flFadeMin2 = 0.0f;
  285. m_flFadeMax2 = 0.0f;
  286. m_flFadeDelta2 = 0.0f;
  287. m_nCPULevel = -1;
  288. m_nGPULevel = -1;
  289. }
  290. //-----------------------------------------------------------------------------
  291. // Destructor
  292. //-----------------------------------------------------------------------------
  293. COverlayMgr::~COverlayMgr()
  294. {
  295. UnloadOverlays();
  296. }
  297. //-----------------------------------------------------------------------------
  298. // Returns a particular overlay
  299. //-----------------------------------------------------------------------------
  300. inline moverlay_t *COverlayMgr::GetOverlay( int iOverlay )
  301. {
  302. return &m_aOverlays[iOverlay];
  303. }
  304. //-----------------------------------------------------------------------------
  305. // Returns a particular overlay fragment
  306. //-----------------------------------------------------------------------------
  307. inline moverlayfragment_t *COverlayMgr::GetOverlayFragment( OverlayFragmentHandle_t iFragment )
  308. {
  309. return &m_aFragments[iFragment];
  310. }
  311. //-----------------------------------------------------------------------------
  312. // Cleanup overlays
  313. //-----------------------------------------------------------------------------
  314. void COverlayMgr::UnloadOverlays( )
  315. {
  316. FOR_EACH_LL( m_RenderQueue, i )
  317. {
  318. m_RenderQueue[i].m_pMaterial->DecrementReferenceCount();
  319. }
  320. int nOverlayCount = m_aOverlays.Count();
  321. for ( int iOverlay = 0; iOverlay < nOverlayCount; ++iOverlay )
  322. {
  323. moverlay_t *pOverlay = &m_aOverlays.Element( iOverlay );
  324. int hFrag = pOverlay->m_hFirstFragment;
  325. while ( hFrag != OVERLAY_FRAGMENT_INVALID )
  326. {
  327. int iFrag = m_OverlayFragments[hFrag];
  328. m_aFragments.Free( iFrag );
  329. hFrag = m_OverlayFragments.Next( hFrag );
  330. }
  331. }
  332. m_aOverlays.Purge();
  333. m_aFragments.Purge();
  334. m_OverlayFragments.Purge();
  335. m_RenderQueue.Purge();
  336. DestroyStaticBuffers();
  337. for ( int i = 0; i < MAX_MAT_SORT_GROUPS; ++i )
  338. {
  339. m_nFirstRenderQueue[i] = RENDER_QUEUE_INVALID;
  340. }
  341. }
  342. //-----------------------------------------------------------------------------
  343. // Create, destroy material sort order ids...
  344. //-----------------------------------------------------------------------------
  345. int COverlayMgr::GetMaterialSortID( IMaterial* pMaterial, int nLightmapPage )
  346. {
  347. // Search the sort order handles for an enumeration id match (means materials + lightmaps match)
  348. unsigned short i;
  349. for ( i = m_RenderQueue.Head(); i != m_RenderQueue.InvalidIndex();
  350. i = m_RenderQueue.Next(i) )
  351. {
  352. // Found a match, lets increment the refcount of this sort order id
  353. if ((m_RenderQueue[i].m_pMaterial == pMaterial) && (m_RenderQueue[i].m_nLightmapPage == nLightmapPage))
  354. {
  355. ++m_RenderQueue[i].m_nRefCount;
  356. return i;
  357. }
  358. }
  359. // Didn't find it, lets assign a new sort order ID, with a refcount of 1
  360. i = m_RenderQueue.AddToTail();
  361. RenderQueueHead_t &renderQueue = m_RenderQueue[i];
  362. renderQueue.m_pMaterial = pMaterial;
  363. renderQueue.m_nLightmapPage = nLightmapPage;
  364. renderQueue.m_nRefCount = 1;
  365. for ( int j = 0; j < MAX_MAT_SORT_GROUPS; ++j )
  366. {
  367. RenderQueueInfo_t &info = renderQueue.m_Queue[j];
  368. info.m_hFirstFragment = OVERLAY_FRAGMENT_INVALID;
  369. info.m_nNextRenderQueue = RENDER_QUEUE_INVALID;
  370. info.m_nVertexCount = 0;
  371. info.m_nIndexCount = 0;
  372. }
  373. pMaterial->IncrementReferenceCount();
  374. return i;
  375. }
  376. void COverlayMgr::CleanupMaterial( unsigned short nSortOrder )
  377. {
  378. RenderQueueHead_t &renderQueue = m_RenderQueue[nSortOrder];
  379. #ifdef _DEBUG
  380. for ( int i = 0; i < MAX_MAT_SORT_GROUPS; ++i )
  381. {
  382. // Shouldn't be cleaning up while we've got a render list
  383. Assert( renderQueue.m_Queue[i].m_nVertexCount == 0 );
  384. }
  385. #endif
  386. // Decrease the sort order reference count
  387. if (--renderQueue.m_nRefCount <= 0)
  388. {
  389. renderQueue.m_pMaterial->DecrementReferenceCount();
  390. // No one referencing the sort order number?
  391. // Then lets clean up the sort order id
  392. m_RenderQueue.Remove(nSortOrder);
  393. }
  394. }
  395. //-----------------------------------------------------------------------------
  396. // Clears the render lists
  397. //-----------------------------------------------------------------------------
  398. void COverlayMgr::ClearRenderLists()
  399. {
  400. for ( int i = 0; i < MAX_MAT_SORT_GROUPS; ++i )
  401. {
  402. ClearRenderLists( i );
  403. }
  404. if ( r_overlayfadeenable.GetBool() )
  405. {
  406. float flFadeMin = r_overlayfademin.GetFloat();
  407. float flFadeMax = r_overlayfademax.GetFloat();
  408. m_flFadeMin2 = flFadeMin * flFadeMin;
  409. m_flFadeMax2 = flFadeMax * flFadeMax;
  410. m_flFadeDelta2 = 1.0f / ( m_flFadeMax2 - m_flFadeMin2 );
  411. }
  412. }
  413. //-----------------------------------------------------------------------------
  414. // Calculate the fade using the global convars.
  415. //-----------------------------------------------------------------------------
  416. bool COverlayMgr::FadeOverlayFragmentGlobal( moverlayfragment_t *pFragment )
  417. {
  418. // Test the overlay distance and set alpha values.
  419. int iVert;
  420. bool bInRange = false;
  421. pFragment->m_bFaded = false;
  422. int nVertexCount = pFragment->m_aPrimVerts.Count();
  423. for ( iVert = 0; iVert < nVertexCount; ++iVert )
  424. {
  425. Vector vecSegment;
  426. VectorSubtract( CurrentViewOrigin(), pFragment->m_aPrimVerts.Element( iVert ).pos, vecSegment );
  427. float flLength2 = vecSegment.LengthSqr();
  428. // min dist of -1 means use max dist for fading
  429. if ( flLength2 < m_flFadeMin2 )
  430. {
  431. pFragment->m_aPrimVerts.Element( iVert ).packedColor = 0xFFFFFFFF;
  432. bInRange = true;
  433. }
  434. else if ( flLength2 > m_flFadeMax2 )
  435. {
  436. // Set vertex alpha to off.
  437. pFragment->m_aPrimVerts.Element( iVert ).packedColor = 0x00FFFFFF;
  438. }
  439. else
  440. {
  441. // Set the alpha based on distance inside of fadeMin and fadeMax
  442. float flAlpha = flLength2 - m_flFadeMin2;
  443. flAlpha *= m_flFadeDelta2;
  444. pFragment->m_aPrimVerts.Element( iVert ).packedColor = 0x00FFFFFF | (FastFToC(1.0f - flAlpha)<<24);
  445. pFragment->m_bFaded = true;
  446. bInRange = true;
  447. }
  448. }
  449. return bInRange;
  450. }
  451. //-----------------------------------------------------------------------------
  452. // Calculate the fade using per-overlay fade distances.
  453. //-----------------------------------------------------------------------------
  454. bool COverlayMgr::FadeOverlayFragment( moverlay_t *pOverlay, moverlayfragment_t *pFragment )
  455. {
  456. // min dist of -1 means use max dist for fading
  457. float flFadeDistMinSq = pOverlay->m_flFadeDistMinSq;
  458. float flFadeDistMaxSq = pOverlay->m_flFadeDistMaxSq;
  459. float flLength2 = pOverlay->m_vecOrigin.DistTo( CurrentViewOrigin() ) - pOverlay->m_flRadius;
  460. flLength2 *= flLength2;
  461. if ( flLength2 >= flFadeDistMaxSq )
  462. return false;
  463. int color = 0xFFFFFFFF;
  464. pFragment->m_bFaded = false;
  465. if ( ( flFadeDistMinSq >= 0 ) && ( flLength2 > flFadeDistMinSq ) )
  466. {
  467. float flAlpha = pOverlay->m_flInvFadeRangeSq * ( flFadeDistMaxSq - flLength2 );
  468. flAlpha = clamp( flAlpha, 0.0f, 1.0f );
  469. int alpha = FastFToC(flAlpha);
  470. color = 0x00FFFFFF | (alpha<<24);
  471. pFragment->m_bFaded = true;
  472. }
  473. int nVertexCount = pFragment->m_aPrimVerts.Count();
  474. for ( int iVert = 0; iVert < nVertexCount; ++iVert )
  475. {
  476. pFragment->m_aPrimVerts.Element( iVert ).packedColor = color;
  477. }
  478. return true;
  479. }
  480. //-----------------------------------------------------------------------------
  481. // Adds the fragment list to the list of fragments to render when RenderOverlays is called
  482. //-----------------------------------------------------------------------------
  483. void COverlayMgr::AddFragmentListToRenderList( int nSortGroup, OverlayFragmentHandle_t iFragment, bool bDisp )
  484. {
  485. OverlayFragmentHandle_t i;
  486. for ( i = iFragment; i != OVERLAY_FRAGMENT_INVALID; i = m_aFragments.Next(i) )
  487. {
  488. // Make sure we don't add the fragment twice...
  489. // FIXME: I currently have no way of ensuring a fragment doesn't end up in 2 sort groups
  490. // which would cause all manner of nastiness.
  491. moverlayfragment_t *pFragment = GetOverlayFragment(i);
  492. if ( !bDisp && pFragment->m_nRenderFrameID == g_OverlayRenderFrameID )
  493. continue;
  494. moverlay_t *pOverlay = &m_aOverlays[ pFragment->m_iOverlay ];
  495. if ( !pOverlay )
  496. continue;
  497. // Based on machine performance, should we be drawing this overlay?
  498. if ( !pOverlay->ShouldDraw( m_nCPULevel, m_nGPULevel ) )
  499. continue;
  500. // Triangle count too low? Skip it...
  501. int nVertexCount = pFragment->m_aPrimVerts.Count();
  502. if ( nVertexCount < 3 )
  503. continue;
  504. // See if we should fade the overlay.
  505. pFragment->m_bFaded = false;
  506. if ( r_overlayfadeenable.GetBool() )
  507. {
  508. // Fade using the convars that control distance.
  509. if ( !FadeOverlayFragmentGlobal( pFragment ) )
  510. continue;
  511. }
  512. else if ( pOverlay->m_flFadeDistMaxSq > 0 )
  513. {
  514. // Fade using per-overlay fade distances, configured by the level designer.
  515. if ( !FadeOverlayFragment( pOverlay, pFragment ) )
  516. continue;
  517. }
  518. // Update the frame count.
  519. pFragment->m_nRenderFrameID = g_OverlayRenderFrameID;
  520. // Determine the material associated with the fragment...
  521. int nMaterialSortID = pFragment->m_nMaterialSortID;
  522. // Insert the render queue into the list of render queues to render
  523. RenderQueueHead_t &renderQueue = m_RenderQueue[nMaterialSortID];
  524. RenderQueueInfo_t &info = renderQueue.m_Queue[nSortGroup];
  525. if ( info.m_hFirstFragment == OVERLAY_FRAGMENT_INVALID )
  526. {
  527. info.m_nNextRenderQueue = m_nFirstRenderQueue[nSortGroup];
  528. m_nFirstRenderQueue[nSortGroup] = nMaterialSortID;
  529. }
  530. // Add to list of fragments for this surface
  531. // NOTE: Render them in *reverse* order in which they appeared in the list
  532. // because they are stored in the list in *reverse* order in which they should be rendered.
  533. // Add the fragment to the bucket of fragments to render...
  534. pFragment->m_hNextRender = info.m_hFirstFragment;
  535. info.m_hFirstFragment = i;
  536. Assert( info.m_nVertexCount + nVertexCount < 65535 );
  537. info.m_nVertexCount += nVertexCount;
  538. info.m_nIndexCount += 3 * (nVertexCount - 2);
  539. }
  540. }
  541. //-----------------------------------------------------------------------------
  542. // Renders all queued up overlays
  543. //-----------------------------------------------------------------------------
  544. void COverlayMgr::ClearRenderLists( int nSortGroup )
  545. {
  546. g_OverlayRenderFrameID++;
  547. int nNextRenderQueue;
  548. for( int i = m_nFirstRenderQueue[nSortGroup]; i != RENDER_QUEUE_INVALID; i = nNextRenderQueue )
  549. {
  550. RenderQueueInfo_t &renderQueue = m_RenderQueue[i].m_Queue[nSortGroup];
  551. nNextRenderQueue = renderQueue.m_nNextRenderQueue;
  552. // Clean up the render queue for next time...
  553. renderQueue.m_nVertexCount = 0;
  554. renderQueue.m_nIndexCount = 0;
  555. renderQueue.m_hFirstFragment = OVERLAY_FRAGMENT_INVALID;
  556. renderQueue.m_nNextRenderQueue = RENDER_QUEUE_INVALID;
  557. }
  558. m_nFirstRenderQueue[nSortGroup] = RENDER_QUEUE_INVALID;
  559. }
  560. //-----------------------------------------------------------------------------
  561. //
  562. //-----------------------------------------------------------------------------
  563. void COverlayMgr::DrawBatches( IMatRenderContext *pRenderContext, IMesh* pIndices, bool bWireframe )
  564. {
  565. pRenderContext->BeginBatch( pIndices );
  566. for ( int i = 0; i < m_RenderBatchList.Count(); ++i )
  567. {
  568. RenderBatch_t& batch = m_RenderBatchList[i];
  569. if ( !bWireframe )
  570. {
  571. pRenderContext->BindBatch( m_RenderMeshes[batch.m_iMesh].m_pMesh, batch.m_pMaterial );
  572. pRenderContext->Bind( batch.m_pMaterial, batch.m_pBindProxy /*proxy*/ );
  573. pRenderContext->BindLightmapPage( batch.m_nLightmapPage );
  574. }
  575. else
  576. {
  577. pRenderContext->BindBatch( m_RenderMeshes[batch.m_iMesh].m_pMesh, g_materialWorldWireframe );
  578. pRenderContext->Bind( g_materialWorldWireframe, NULL );
  579. }
  580. pRenderContext->DrawBatch( MATERIAL_TRIANGLES, batch.m_nFirstIndex, batch.m_nNumIndex );
  581. }
  582. pRenderContext->EndBatch();
  583. m_RenderBatchList.RemoveAll();
  584. }
  585. //-----------------------------------------------------------------------------
  586. // Draw fragment that are fading - Dynamic BV and dynamic IB
  587. //-----------------------------------------------------------------------------
  588. void COverlayMgr::DrawFadedFragments( IMatRenderContext *pRenderContext, int nSortGroup, bool bWireframe )
  589. {
  590. IMesh *pMesh = NULL;
  591. CMeshBuilder meshBuilder;
  592. CUtlVectorFixedGrowable<int,256> polyList;
  593. int nCurrVertexCount = 0;
  594. int nCurrIndexCount = 0;
  595. int nMaxIndices = pRenderContext->GetMaxIndicesToRender();
  596. IMaterial* pCurrentMaterial = NULL;
  597. void* pCurrentBindProxy = NULL;
  598. bool bLightmappedMaterial = false;
  599. for ( int iFragment = 0; iFragment < m_RenderFadedFragments.Count(); ++iFragment )
  600. {
  601. moverlayfragment_t *pFragment = &m_aFragments[m_RenderFadedFragments[iFragment]];
  602. moverlay_t *pOverlay = &m_aOverlays[pFragment->m_iOverlay];
  603. RenderQueueHead_t &renderQueueHead = m_RenderQueue[pFragment->m_nMaterialSortID];
  604. RenderQueueInfo_t &renderQueue = renderQueueHead.m_Queue[nSortGroup];
  605. int nMaxVertices = pRenderContext->GetMaxVerticesToRender( !bWireframe ? renderQueueHead.m_pMaterial : g_materialWorldWireframe );
  606. int nVertCount = pFragment->m_aPrimVerts.Count();
  607. int nIndexCount = 3 * ( nVertCount - 2 );
  608. if ( pMesh )
  609. {
  610. bool bFlush = false;
  611. // Would this cause an overflow? Flush!
  612. if ( ( ( nCurrVertexCount + nVertCount ) > nMaxVertices ) ||
  613. ( ( nCurrIndexCount + nIndexCount ) > nMaxIndices ) )
  614. {
  615. bFlush = true;
  616. }
  617. // Changing material or bind proxy? Flush
  618. if ( ( renderQueueHead.m_pMaterial != pCurrentMaterial ) || ( pOverlay->m_pBindProxy != pCurrentBindProxy ) )
  619. {
  620. bFlush = true;
  621. }
  622. if ( bFlush )
  623. {
  624. CIndexBuilder &indexBuilder = meshBuilder;
  625. indexBuilder.FastPolygonList( 0, polyList.Base(), polyList.Count() );
  626. meshBuilder.End();
  627. pMesh->Draw();
  628. pMesh = NULL;
  629. polyList.RemoveAll();
  630. nCurrIndexCount = nCurrVertexCount = 0;
  631. }
  632. }
  633. nCurrVertexCount += nVertCount;
  634. nCurrIndexCount += nIndexCount;
  635. const overlayvert_t *pVert = &(pFragment->m_aPrimVerts[0]);
  636. PREFETCH360(pVert,0);
  637. int iVert;
  638. if ( !pMesh ) // have we output any vertices yet? if first verts, init material and meshbuilder
  639. {
  640. if ( !bWireframe )
  641. {
  642. pRenderContext->Bind( renderQueueHead.m_pMaterial, pOverlay->m_pBindProxy /*proxy*/ );
  643. pRenderContext->BindLightmapPage( renderQueueHead.m_nLightmapPage );
  644. bLightmappedMaterial = renderQueueHead.m_pMaterial->GetPropertyFlag( MATERIAL_PROPERTY_NEEDS_LIGHTMAP ) ||
  645. renderQueueHead.m_pMaterial->GetPropertyFlag( MATERIAL_PROPERTY_NEEDS_BUMPED_LIGHTMAPS );
  646. }
  647. pCurrentMaterial = renderQueueHead.m_pMaterial;
  648. pCurrentBindProxy = pOverlay->m_pBindProxy;
  649. // Create the mesh/mesh builder.
  650. pMesh = pRenderContext->GetDynamicMesh();
  651. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, MIN( renderQueue.m_nVertexCount, nMaxVertices ),
  652. MIN( renderQueue.m_nIndexCount, nMaxIndices ) );
  653. }
  654. if ( bLightmappedMaterial )
  655. {
  656. float flOffset = pFragment->decalOffset;
  657. PREFETCH360(pVert+1,0);
  658. for ( iVert = 0; iVert < nVertCount; ++iVert, ++pVert )
  659. {
  660. PREFETCH360(pVert+2,0);
  661. meshBuilder.Position3fv( pVert->pos.Base() );
  662. meshBuilder.Normal3fv( pVert->normal.Base() );
  663. meshBuilder.Color4Packed( pVert->packedColor );
  664. meshBuilder.TexCoord2fv( 0, pVert->texCoord[0].Base() );
  665. meshBuilder.TexCoord2fv( 1, pVert->lightCoord );
  666. meshBuilder.TexCoord2f( 2, flOffset, 0 );
  667. meshBuilder.AdvanceVertexF<VTX_HAVEPOS|VTX_HAVENORMAL|VTX_HAVECOLOR, 3>();
  668. }
  669. }
  670. else
  671. {
  672. PREFETCH360(pVert+1,0);
  673. for ( iVert = 0; iVert < nVertCount; ++iVert, ++pVert )
  674. {
  675. PREFETCH360(pVert+2,0);
  676. meshBuilder.Position3fv( pVert->pos.Base() );
  677. meshBuilder.Normal3fv( pVert->normal.Base() );
  678. meshBuilder.Color4Packed( pVert->packedColor );
  679. meshBuilder.TexCoord2fv( 0, pVert->texCoord[0].Base() );
  680. meshBuilder.TexCoord2fv( 1, pVert->lightCoord );
  681. meshBuilder.TexCoord2fv( 2, pVert->texCoord[1].Base() );
  682. meshBuilder.AdvanceVertexF<VTX_HAVEPOS|VTX_HAVENORMAL|VTX_HAVECOLOR, 3>();
  683. }
  684. }
  685. polyList.AddToTail( nVertCount );
  686. }
  687. if (pMesh)
  688. {
  689. CIndexBuilder &indexBuilder = meshBuilder;
  690. indexBuilder.FastPolygonList( 0, polyList.Base(), polyList.Count() );
  691. meshBuilder.End();
  692. pMesh->Draw();
  693. }
  694. pMesh = NULL;
  695. m_RenderFadedFragments.RemoveAll();
  696. }
  697. //-----------------------------------------------------------------------------
  698. // Renders all queued up overlays (in batch)
  699. // Static VB and dynamic IB for non fading fragments
  700. // Dynamic VB and dynamic IB for fading fragments
  701. //-----------------------------------------------------------------------------
  702. void COverlayMgr::RenderOverlaysBatch( IMatRenderContext *pRenderContext, int nSortGroup )
  703. {
  704. bool bWireframeFragments = ( r_overlaywireframe.GetInt() != 0 );
  705. if ( bWireframeFragments )
  706. {
  707. pRenderContext->Bind( g_materialWorldWireframe );
  708. }
  709. IMesh *pMesh = NULL;
  710. CMeshBuilder meshBuilder;
  711. // Render sorted by material + lightmap...
  712. // Render them in order of their m_nRenderOrder parameter (set in the entity).
  713. int iCurrentRenderOrder = 0;
  714. int iHighestRenderOrder = 0;
  715. int nMaxIndices = pRenderContext->GetMaxIndicesToRender();
  716. int nCurrIndexCount = 0;
  717. RenderBatch_t currentBatch;
  718. while ( iCurrentRenderOrder <= iHighestRenderOrder )
  719. {
  720. // Draw fragment that are not fading first
  721. int nNextRenderQueue;
  722. for( int i = m_nFirstRenderQueue[nSortGroup]; i != RENDER_QUEUE_INVALID; i = nNextRenderQueue )
  723. {
  724. RenderQueueHead_t &renderQueueHead = m_RenderQueue[i];
  725. RenderQueueInfo_t &renderQueue = renderQueueHead.m_Queue[nSortGroup];
  726. nNextRenderQueue = renderQueue.m_nNextRenderQueue;
  727. Assert( renderQueue.m_nVertexCount > 0 );
  728. // Run this list for each bind proxy
  729. OverlayFragmentHandle_t hStartFragment = renderQueue.m_hFirstFragment;
  730. while ( hStartFragment != OVERLAY_FRAGMENT_INVALID )
  731. {
  732. void *pCurrentBindProxy = m_aOverlays[ m_aFragments[ hStartFragment ].m_iOverlay ].m_pBindProxy;
  733. int iCurrentMesh = m_aFragments[ hStartFragment ].m_iMesh;
  734. currentBatch.m_iMesh = iCurrentMesh;
  735. currentBatch.m_pMaterial = renderQueueHead.m_pMaterial;
  736. currentBatch.m_pBindProxy = pCurrentBindProxy;
  737. currentBatch.m_nLightmapPage = renderQueueHead.m_nLightmapPage;
  738. // We just need to make sure there's a unique sort ID for that. Then we bind once per queue
  739. OverlayFragmentHandle_t hFragment = hStartFragment;
  740. hStartFragment = OVERLAY_FRAGMENT_INVALID;
  741. for ( ; hFragment != OVERLAY_FRAGMENT_INVALID; hFragment = m_aFragments[hFragment].m_hNextRender )
  742. {
  743. moverlayfragment_t *pFragment = &m_aFragments[hFragment];
  744. moverlay_t *pOverlay = &m_aOverlays[pFragment->m_iOverlay];
  745. if ( pOverlay->m_pBindProxy != pCurrentBindProxy )
  746. {
  747. // This is from a different bind proxy
  748. if ( hStartFragment == OVERLAY_FRAGMENT_INVALID )
  749. {
  750. // Start at the first different bind proxy when we rerun the fragment list
  751. hStartFragment = hFragment;
  752. }
  753. continue;
  754. }
  755. // Only render the current render order.
  756. int iThisOverlayRenderOrder = pOverlay->m_nRenderOrder;
  757. iHighestRenderOrder = MAX( iThisOverlayRenderOrder, iHighestRenderOrder );
  758. if ( iThisOverlayRenderOrder != iCurrentRenderOrder )
  759. continue;
  760. // Keeps track of "fading fragments" (to be rendered later)
  761. if ( pFragment->m_bFaded )
  762. {
  763. m_RenderFadedFragments.AddToTail( hFragment );
  764. continue;
  765. }
  766. int nVertCount = pFragment->m_aPrimVerts.Count();
  767. int nIndexCount = 3 * ( nVertCount - 2 );
  768. if ( pFragment->m_iMesh != iCurrentMesh )
  769. {
  770. // Add batch
  771. if ( currentBatch.m_nNumIndex )
  772. {
  773. m_RenderBatchList.AddToTail( currentBatch );
  774. currentBatch.m_nFirstIndex += currentBatch.m_nNumIndex;
  775. currentBatch.m_nNumIndex = 0;
  776. }
  777. iCurrentMesh = pFragment->m_iMesh;
  778. currentBatch.m_iMesh = iCurrentMesh;
  779. }
  780. if ( pMesh )
  781. {
  782. // Would this cause an overflow? Flush!
  783. if ( ( nCurrIndexCount + nIndexCount ) > nMaxIndices )
  784. {
  785. meshBuilder.End();
  786. DrawBatches( pRenderContext, pMesh, bWireframeFragments );
  787. nCurrIndexCount = 0;
  788. pMesh = NULL;
  789. }
  790. }
  791. if ( !pMesh ) // have we output any vertices yet? if first verts, init material and meshbuilder
  792. {
  793. if ( !bWireframeFragments )
  794. {
  795. pRenderContext->Bind( renderQueueHead.m_pMaterial, pOverlay->m_pBindProxy );
  796. pRenderContext->BindLightmapPage( renderQueueHead.m_nLightmapPage );
  797. }
  798. // Create the mesh/mesh builder.
  799. pMesh = pRenderContext->GetDynamicMesh(false);
  800. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, 0, nMaxIndices );
  801. currentBatch.m_nFirstIndex = 0;
  802. currentBatch.m_nNumIndex = 0;
  803. }
  804. // Setup indices.
  805. int nTriCount = ( nVertCount - 2 );
  806. CIndexBuilder &indexBuilder = meshBuilder;
  807. indexBuilder.FastPolygon( pFragment->m_nVertexBufferIndex, nTriCount );
  808. nCurrIndexCount += nIndexCount;
  809. currentBatch.m_nNumIndex += nIndexCount;
  810. }
  811. // Add batch
  812. if ( currentBatch.m_nNumIndex )
  813. {
  814. m_RenderBatchList.AddToTail( currentBatch );
  815. currentBatch.m_nFirstIndex += currentBatch.m_nNumIndex;
  816. currentBatch.m_nNumIndex = 0;
  817. }
  818. // Draw fragment that are fading
  819. if ( m_RenderFadedFragments.Count() > 0 )
  820. {
  821. // Render non faded fragment first
  822. if ( pMesh )
  823. {
  824. meshBuilder.End();
  825. DrawBatches( pRenderContext, pMesh, bWireframeFragments );
  826. nCurrIndexCount = 0;
  827. pMesh = NULL;
  828. }
  829. DrawFadedFragments( pRenderContext, nSortGroup, bWireframeFragments );
  830. }
  831. }
  832. }
  833. ++iCurrentRenderOrder;
  834. }
  835. if ( pMesh )
  836. {
  837. meshBuilder.End();
  838. DrawBatches( pRenderContext, pMesh, bWireframeFragments );
  839. }
  840. m_RenderBatchList.RemoveAll();
  841. m_RenderFadedFragments.RemoveAll();
  842. }
  843. //-----------------------------------------------------------------------------
  844. // Renders all queued up overlays
  845. //-----------------------------------------------------------------------------
  846. void COverlayMgr::RenderOverlays( IMatRenderContext *pRenderContext, int nSortGroup )
  847. {
  848. #ifndef DEDICATED
  849. VPROF_BUDGET( "COverlayMgr::RenderOverlays", VPROF_BUDGETGROUP_OVERLAYS );
  850. if ( r_renderoverlayfragment.GetInt() == 0 )
  851. {
  852. ClearRenderLists( nSortGroup );
  853. return;
  854. }
  855. if ( r_renderoverlaybatch.GetBool() )
  856. {
  857. RenderOverlaysBatch( pRenderContext, nSortGroup );
  858. return;
  859. }
  860. bool bWireframeFragments = ( r_overlaywireframe.GetInt() != 0 );
  861. if ( bWireframeFragments )
  862. {
  863. pRenderContext->Bind( g_materialWorldWireframe );
  864. }
  865. // Render sorted by material + lightmap...
  866. // Render them in order of their m_nRenderOrder parameter (set in the entity).
  867. int iCurrentRenderOrder = 0;
  868. int iHighestRenderOrder = 0;
  869. bool bLightmappedMaterial = false;
  870. int nMaxIndices = pRenderContext->GetMaxIndicesToRender();
  871. while ( iCurrentRenderOrder <= iHighestRenderOrder )
  872. {
  873. int nNextRenderQueue;
  874. for( int i = m_nFirstRenderQueue[nSortGroup]; i != RENDER_QUEUE_INVALID; i = nNextRenderQueue )
  875. {
  876. RenderQueueHead_t &renderQueueHead = m_RenderQueue[i];
  877. RenderQueueInfo_t &renderQueue = renderQueueHead.m_Queue[nSortGroup];
  878. nNextRenderQueue = renderQueue.m_nNextRenderQueue;
  879. Assert( renderQueue.m_nVertexCount > 0 );
  880. int nMaxVertices = pRenderContext->GetMaxVerticesToRender( !bWireframeFragments ? renderQueueHead.m_pMaterial : g_materialWorldWireframe );
  881. // Run this list for each bind proxy
  882. OverlayFragmentHandle_t hStartFragment = renderQueue.m_hFirstFragment;
  883. while ( hStartFragment != OVERLAY_FRAGMENT_INVALID )
  884. {
  885. void *pCurrentBindProxy = m_aOverlays[ m_aFragments[ hStartFragment ].m_iOverlay ].m_pBindProxy;
  886. IMesh* pMesh = 0; // only init when we actually have something
  887. CMeshBuilder meshBuilder;
  888. CUtlVectorFixedGrowable<int,256> polyList;
  889. int nCurrVertexCount = 0;
  890. int nCurrIndexCount = 0;
  891. bool bBoundMaterial = false;
  892. // We just need to make sure there's a unique sort ID for that. Then we bind once per queue
  893. OverlayFragmentHandle_t hFragment = hStartFragment;
  894. hStartFragment = OVERLAY_FRAGMENT_INVALID;
  895. for ( ; hFragment != OVERLAY_FRAGMENT_INVALID; hFragment = m_aFragments[hFragment].m_hNextRender )
  896. {
  897. moverlayfragment_t *pFragment = &m_aFragments[hFragment];
  898. moverlay_t *pOverlay = &m_aOverlays[pFragment->m_iOverlay];
  899. if ( pOverlay->m_pBindProxy != pCurrentBindProxy )
  900. {
  901. // This is from a different bind proxy
  902. if ( hStartFragment == OVERLAY_FRAGMENT_INVALID )
  903. {
  904. // Start at the first different bind proxy when we rerun the fragment list
  905. hStartFragment = hFragment;
  906. }
  907. continue;
  908. }
  909. // Only render the current render order.
  910. int iThisOverlayRenderOrder = pOverlay->m_nRenderOrder;
  911. iHighestRenderOrder = MAX( iThisOverlayRenderOrder, iHighestRenderOrder );
  912. if ( iThisOverlayRenderOrder != iCurrentRenderOrder )
  913. continue;
  914. int nVertCount = pFragment->m_aPrimVerts.Count();
  915. int nIndexCount = 3 * ( nVertCount - 2 );
  916. if ( pMesh )
  917. {
  918. // Would this cause an overflow? Flush!
  919. if ( ( ( nCurrVertexCount + nVertCount ) > nMaxVertices ) ||
  920. ( ( nCurrIndexCount + nIndexCount ) > nMaxIndices ) )
  921. {
  922. CIndexBuilder &indexBuilder = meshBuilder;
  923. indexBuilder.FastPolygonList( 0, polyList.Base(), polyList.Count() );
  924. meshBuilder.End();
  925. pMesh->Draw();
  926. pMesh = NULL;
  927. polyList.RemoveAll();
  928. nCurrIndexCount = nCurrVertexCount = 0;
  929. }
  930. }
  931. nCurrVertexCount += nVertCount;
  932. nCurrIndexCount += nIndexCount;
  933. const overlayvert_t *pVert = &(pFragment->m_aPrimVerts[0]);
  934. PREFETCH360(pVert,0);
  935. int iVert;
  936. if ( !pMesh ) // have we output any vertices yet? if first verts, init material and meshbuilder
  937. {
  938. if ( !bWireframeFragments && !bBoundMaterial )
  939. {
  940. pRenderContext->Bind( renderQueueHead.m_pMaterial, pOverlay->m_pBindProxy /*proxy*/ );
  941. pRenderContext->BindLightmapPage( renderQueueHead.m_nLightmapPage );
  942. bLightmappedMaterial = renderQueueHead.m_pMaterial->GetPropertyFlag( MATERIAL_PROPERTY_NEEDS_LIGHTMAP ) ||
  943. renderQueueHead.m_pMaterial->GetPropertyFlag( MATERIAL_PROPERTY_NEEDS_BUMPED_LIGHTMAPS );
  944. bBoundMaterial = true;
  945. }
  946. // Create the mesh/mesh builder.
  947. pMesh = pRenderContext->GetDynamicMesh();
  948. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, MIN( renderQueue.m_nVertexCount, nMaxVertices ),
  949. MIN( renderQueue.m_nIndexCount, nMaxIndices ) );
  950. }
  951. if ( bLightmappedMaterial )
  952. {
  953. float flOffset = pFragment->decalOffset;
  954. PREFETCH360(pVert+1,0);
  955. for ( iVert = 0; iVert < nVertCount; ++iVert, ++pVert )
  956. {
  957. PREFETCH360(pVert+2,0);
  958. meshBuilder.Position3fv( pVert->pos.Base() );
  959. meshBuilder.Normal3fv( pVert->normal.Base() );
  960. meshBuilder.Color4Packed( pVert->packedColor );
  961. meshBuilder.TexCoord2fv( 0, pVert->texCoord[0].Base() );
  962. meshBuilder.TexCoord2fv( 1, pVert->lightCoord );
  963. meshBuilder.TexCoord2f( 2, flOffset, 0 );
  964. meshBuilder.AdvanceVertexF<VTX_HAVEPOS|VTX_HAVENORMAL|VTX_HAVECOLOR, 3>();
  965. }
  966. }
  967. else
  968. {
  969. PREFETCH360(pVert+1,0);
  970. for ( iVert = 0; iVert < nVertCount; ++iVert, ++pVert )
  971. {
  972. PREFETCH360(pVert+2,0);
  973. meshBuilder.Position3fv( pVert->pos.Base() );
  974. meshBuilder.Normal3fv( pVert->normal.Base() );
  975. meshBuilder.Color4Packed( pVert->packedColor );
  976. meshBuilder.TexCoord2fv( 0, pVert->texCoord[0].Base() );
  977. meshBuilder.TexCoord2fv( 1, pVert->lightCoord );
  978. meshBuilder.TexCoord2fv( 2, pVert->texCoord[1].Base() );
  979. meshBuilder.AdvanceVertexF<VTX_HAVEPOS|VTX_HAVENORMAL|VTX_HAVECOLOR, 3>();
  980. }
  981. }
  982. polyList.AddToTail( nVertCount );
  983. }
  984. if (pMesh)
  985. {
  986. CIndexBuilder &indexBuilder = meshBuilder;
  987. indexBuilder.FastPolygonList( 0, polyList.Base(), polyList.Count() );
  988. meshBuilder.End();
  989. pMesh->Draw();
  990. }
  991. }
  992. }
  993. ++iCurrentRenderOrder;
  994. }
  995. #endif
  996. }
  997. void COverlayMgr::RenderAllUnlitOverlays( IMatRenderContext *pRenderContext, int nSortGroup )
  998. {
  999. for ( int i = 0; i < m_aOverlays.Count(); i++ )
  1000. {
  1001. if ( m_aOverlays[i].m_nFlags & FOVERLAY_DRAW_UNLIT )
  1002. {
  1003. for ( int hFrag = m_aOverlays[i].m_hFirstFragment; hFrag != OVERLAY_FRAGMENT_INVALID; hFrag = m_OverlayFragments.Next( hFrag ) )
  1004. {
  1005. AddFragmentListToRenderList( nSortGroup, m_OverlayFragments[ hFrag ], false );
  1006. }
  1007. }
  1008. }
  1009. RenderOverlays( pRenderContext, nSortGroup );
  1010. ClearRenderLists( nSortGroup );
  1011. }
  1012. void COverlayMgr::SetOverlayBindProxy( int iOverlayID, void *pBindProxy )
  1013. {
  1014. moverlay_t *pOverlay = GetOverlay( iOverlayID );
  1015. if ( pOverlay )
  1016. pOverlay->m_pBindProxy = pBindProxy;
  1017. }
  1018. //-----------------------------------------------------------------------------
  1019. //-----------------------------------------------------------------------------
  1020. bool COverlayMgr::Surf_PreClipFragment( moverlay_t *pOverlay, moverlayfragment_t &overlayFrag,
  1021. SurfaceHandle_t surfID, moverlayfragment_t &surfaceFrag )
  1022. {
  1023. MEM_ALLOC_CREDIT();
  1024. // Convert the overlay uv points to overlay plane points.
  1025. overlayFrag.m_aPrimVerts.SetCount( 4 );
  1026. for( int iVert = 0; iVert < 4; ++iVert )
  1027. {
  1028. Overlay_OverlayUVToOverlayPlane( pOverlay->m_vecOrigin, pOverlay->m_vecBasis[0],
  1029. pOverlay->m_vecBasis[1], pOverlay->m_vecUVPoints[iVert],
  1030. overlayFrag.m_aPrimVerts[iVert].pos );
  1031. }
  1032. // Overlay texture coordinates.
  1033. InitTexCoords( pOverlay, overlayFrag );
  1034. // Surface
  1035. int nVertCount = surfaceFrag.m_aPrimVerts.Count();
  1036. for ( int iVert = 0; iVert < nVertCount; ++iVert )
  1037. {
  1038. // Position.
  1039. Overlay_WorldToOverlayPlane( pOverlay->m_vecOrigin, pOverlay->m_vecBasis[2],
  1040. surfaceFrag.m_aPrimVerts[iVert].pos, surfaceFrag.m_aPrimVerts[iVert].pos );
  1041. }
  1042. return true;
  1043. }
  1044. //-----------------------------------------------------------------------------
  1045. //-----------------------------------------------------------------------------
  1046. void COverlayMgr::Surf_PostClipFragment( moverlay_t *pOverlay, moverlayfragment_t &overlayFrag,
  1047. SurfaceHandle_t surfID )
  1048. {
  1049. #ifndef DEDICATED
  1050. // Get fragment vertex count.
  1051. int nVertCount = overlayFrag.m_aPrimVerts.Count();
  1052. if ( nVertCount == 0 )
  1053. return;
  1054. // Create fragment.
  1055. OverlayFragmentHandle_t hFragment = AddFragmentToFragmentList( nVertCount );
  1056. moverlayfragment_t *pFragment = GetOverlayFragment( hFragment );
  1057. // Get surface context.
  1058. SurfaceCtx_t ctx;
  1059. SurfSetupSurfaceContext( ctx, surfID );
  1060. pFragment->m_iOverlay = pOverlay->m_nId;
  1061. pFragment->m_SurfId = surfID;
  1062. pFragment->decalOffset = ComputeDecalLightmapOffset( surfID );
  1063. const Vector &vNormal = MSurf_Plane( surfID ).normal;
  1064. moverlayfragment_t origOverlay;
  1065. origOverlay.m_aPrimVerts.SetSize( 4 );
  1066. for ( int iPoint = 0; iPoint < 4; ++iPoint )
  1067. {
  1068. Overlay_OverlayUVToOverlayPlane( pOverlay->m_vecOrigin, pOverlay->m_vecBasis[0],
  1069. pOverlay->m_vecBasis[1], pOverlay->m_vecUVPoints[iPoint],
  1070. origOverlay.m_aPrimVerts[iPoint].pos );
  1071. }
  1072. InitTexCoords( pOverlay, origOverlay );
  1073. for ( int iVert = 0; iVert < nVertCount; ++iVert )
  1074. {
  1075. Vector2D vecUV;
  1076. PointInQuadToBarycentric( origOverlay.m_aPrimVerts[0].pos,
  1077. origOverlay.m_aPrimVerts[3].pos,
  1078. origOverlay.m_aPrimVerts[2].pos,
  1079. origOverlay.m_aPrimVerts[1].pos,
  1080. overlayFrag.m_aPrimVerts[iVert].pos, vecUV );
  1081. Overlay_OverlayPlaneToWorld( pOverlay->m_vecBasis[2], surfID,
  1082. overlayFrag.m_aPrimVerts[iVert].pos,
  1083. pFragment->m_aPrimVerts[iVert].pos );
  1084. // Texture coordinates.
  1085. Vector2D vecTexCoord;
  1086. for ( int iTexCoord=0; iTexCoord < NUM_OVERLAY_TEXCOORDS; iTexCoord++ )
  1087. {
  1088. TexCoordInQuadFromBarycentric( origOverlay.m_aPrimVerts[0].texCoord[iTexCoord], origOverlay.m_aPrimVerts[3].texCoord[iTexCoord],
  1089. origOverlay.m_aPrimVerts[2].texCoord[iTexCoord], origOverlay.m_aPrimVerts[1].texCoord[iTexCoord],
  1090. vecUV, vecTexCoord );
  1091. pFragment->m_aPrimVerts[iVert].texCoord[iTexCoord][0] = vecTexCoord.x;
  1092. pFragment->m_aPrimVerts[iVert].texCoord[iTexCoord][1] = vecTexCoord.y;
  1093. }
  1094. // Normals : FIXME this isn't an interpolated normal.
  1095. pFragment->m_aPrimVerts[iVert].normal = vNormal;
  1096. // Lightmap coordinates.
  1097. Vector2D uv;
  1098. SurfComputeLightmapCoordinate( ctx, surfID, pFragment->m_aPrimVerts[iVert].pos, uv );
  1099. pFragment->m_aPrimVerts[iVert].lightCoord[0] = uv.x;
  1100. pFragment->m_aPrimVerts[iVert].lightCoord[1] = uv.y;
  1101. // Push -just- off the surface to avoid z-clipping errors.
  1102. pFragment->m_aPrimVerts[iVert].pos += vNormal * OVERLAY_AVOID_FLICKER_NORMAL_OFFSET;
  1103. }
  1104. // Create the sort ID for this fragment
  1105. const MaterialSystem_SortInfo_t &sortInfo = materialSortInfoArray[MSurf_MaterialSortID( surfID )];
  1106. mtexinfo_t *pTexInfo = &host_state.worldbrush->texinfo[pOverlay->m_nTexInfo];
  1107. pFragment->m_nMaterialSortID = GetMaterialSortID( pTexInfo->material, sortInfo.lightmapPageID );
  1108. // Add to list of fragments for this overlay
  1109. MEM_ALLOC_CREDIT();
  1110. OverlayFragmentList_t i = m_OverlayFragments.Alloc( true );
  1111. m_OverlayFragments[i] = hFragment;
  1112. m_OverlayFragments.LinkBefore( pOverlay->m_hFirstFragment, i );
  1113. pOverlay->m_hFirstFragment = i;
  1114. // Add to list of fragments for this surface
  1115. // NOTE: Store them in *reverse* order so that when we pull them off for
  1116. // rendering, we can do *that* in reverse order too? Reduces the amount of iteration necessary
  1117. // Therefore, we need to add to the head of the list
  1118. m_aFragments.LinkBefore( MSurf_OverlayFragmentList( surfID ), hFragment );
  1119. MSurf_OverlayFragmentList( surfID ) = hFragment;
  1120. #endif // !DEDICATED
  1121. }
  1122. //-----------------------------------------------------------------------------
  1123. // Clips an overlay to a surface
  1124. //-----------------------------------------------------------------------------
  1125. void COverlayMgr::Surf_ClipFragment( moverlay_t *pOverlay, moverlayfragment_t &overlayFrag,
  1126. SurfaceHandle_t surfID, moverlayfragment_t &surfaceFrag )
  1127. {
  1128. MEM_ALLOC_CREDIT();
  1129. // Create the clip planes.
  1130. CUtlVector<cplane_t> m_ClipPlanes;
  1131. BuildClipPlanes( surfID, surfaceFrag, pOverlay->m_vecBasis[2], m_ClipPlanes );
  1132. // Copy the overlay fragment (initial clipped fragment).
  1133. moverlayfragment_t *pClippedFrag = CopyTempFragment( &overlayFrag );
  1134. for( int iPlane = 0; iPlane < m_ClipPlanes.Count(); ++iPlane )
  1135. {
  1136. moverlayfragment_t *pFront = NULL, *pBack = NULL;
  1137. DoClipFragment( pClippedFrag, &m_ClipPlanes[iPlane], &pFront, &pBack );
  1138. DestroyTempFragment( pClippedFrag );
  1139. pClippedFrag = NULL;
  1140. // Keep the backside and continue clipping.
  1141. if ( pBack )
  1142. {
  1143. pClippedFrag = pBack;
  1144. }
  1145. if ( pFront )
  1146. {
  1147. DestroyTempFragment( pFront );
  1148. }
  1149. }
  1150. m_ClipPlanes.Purge();
  1151. // Copy the clipped polygon back to the overlay frag.
  1152. overlayFrag.m_aPrimVerts.RemoveAll();
  1153. if ( pClippedFrag )
  1154. {
  1155. overlayFrag.m_aPrimVerts.SetCount( pClippedFrag->m_aPrimVerts.Count() );
  1156. for ( int iVert = 0; iVert < pClippedFrag->m_aPrimVerts.Count(); ++iVert )
  1157. {
  1158. overlayFrag.m_aPrimVerts[iVert].pos = pClippedFrag->m_aPrimVerts[iVert].pos;
  1159. memcpy( overlayFrag.m_aPrimVerts[iVert].texCoord, pClippedFrag->m_aPrimVerts[iVert].texCoord, sizeof( overlayFrag.m_aPrimVerts[iVert].texCoord ) );
  1160. }
  1161. }
  1162. DestroyTempFragment( pClippedFrag );
  1163. }
  1164. //-----------------------------------------------------------------------------
  1165. // Creates overlay fragments for a particular surface
  1166. //-----------------------------------------------------------------------------
  1167. void COverlayMgr::Surf_CreateFragments( moverlay_t *pOverlay, SurfaceHandle_t surfID )
  1168. {
  1169. moverlayfragment_t overlayFrag, surfaceFrag;
  1170. // The faces get fan tesselated into triangles when rendered - do the same to
  1171. // create the fragments!
  1172. int iFirstVert = MSurf_FirstVertIndex( surfID );
  1173. int nSurfTriangleCount = MSurf_VertCount( surfID ) - 2;
  1174. for( int iTri = 0; iTri < nSurfTriangleCount; ++iTri )
  1175. {
  1176. // 3 Points in a triangle.
  1177. surfaceFrag.m_aPrimVerts.SetCount( 3 );
  1178. int iVert = host_state.worldbrush->vertindices[(iFirstVert)];
  1179. mvertex_t *pVert = &host_state.worldbrush->vertexes[iVert];
  1180. surfaceFrag.m_aPrimVerts[0].pos = pVert->position;
  1181. iVert = host_state.worldbrush->vertindices[(iFirstVert+iTri+1)];
  1182. pVert = &host_state.worldbrush->vertexes[iVert];
  1183. surfaceFrag.m_aPrimVerts[1].pos = pVert->position;
  1184. iVert = host_state.worldbrush->vertindices[(iFirstVert+iTri+2)];
  1185. pVert = &host_state.worldbrush->vertexes[iVert];
  1186. surfaceFrag.m_aPrimVerts[2].pos = pVert->position;
  1187. if ( TriangleArea( surfaceFrag.m_aPrimVerts[0].pos, surfaceFrag.m_aPrimVerts[1].pos, surfaceFrag.m_aPrimVerts[2].pos ) > 1.0f )
  1188. {
  1189. if ( Surf_PreClipFragment( pOverlay, overlayFrag, surfID, surfaceFrag ) )
  1190. {
  1191. Surf_ClipFragment( pOverlay, overlayFrag, surfID, surfaceFrag );
  1192. Surf_PostClipFragment( pOverlay, overlayFrag, surfID );
  1193. }
  1194. }
  1195. // Clean up!
  1196. surfaceFrag.m_aPrimVerts.RemoveAll();
  1197. overlayFrag.m_aPrimVerts.RemoveAll();
  1198. }
  1199. }
  1200. //-----------------------------------------------------------------------------
  1201. // Creates fragments from the overlays loaded in from file
  1202. //-----------------------------------------------------------------------------
  1203. void COverlayMgr::CreateFragments( void )
  1204. {
  1205. int nOverlayCount = m_aOverlays.Count();
  1206. for ( int iOverlay = 0; iOverlay < nOverlayCount; ++iOverlay )
  1207. {
  1208. moverlay_t *pOverlay = &m_aOverlays.Element( iOverlay );
  1209. int nFaceCount = pOverlay->m_aFaces.Count();
  1210. if ( nFaceCount == 0 )
  1211. continue;
  1212. // Build the overlay basis.
  1213. bool bFlip = ( pOverlay->m_vecUVPoints[3].z == 1.0f );
  1214. pOverlay->m_vecUVPoints[3].z = 0.0f;
  1215. Overlay_BuildBasis( pOverlay->m_vecBasis[2], pOverlay->m_vecBasis[0], pOverlay->m_vecBasis[1], bFlip );
  1216. // Clip against each face in the face list.
  1217. for( int iFace = 0; iFace < nFaceCount; ++iFace )
  1218. {
  1219. SurfaceHandle_t surfID = pOverlay->m_aFaces[iFace];
  1220. if ( SurfaceHasDispInfo( surfID ) )
  1221. {
  1222. Disp_CreateFragments( pOverlay, surfID );
  1223. }
  1224. else
  1225. {
  1226. Surf_CreateFragments( pOverlay, surfID );
  1227. }
  1228. }
  1229. }
  1230. // Radius computation (for fades)
  1231. for ( int iOverlay = 0; iOverlay < nOverlayCount; ++iOverlay )
  1232. {
  1233. float flRadiusSq = 0.0f;
  1234. moverlay_t *pOverlay = &m_aOverlays.Element( iOverlay );
  1235. for ( int hFrag = pOverlay->m_hFirstFragment; hFrag != OVERLAY_FRAGMENT_INVALID; hFrag = m_OverlayFragments.Next( hFrag ) )
  1236. {
  1237. int iFrag = m_OverlayFragments[hFrag];
  1238. moverlayfragment_t *pFrag = &m_aFragments[iFrag];
  1239. int nVertCount = pFrag->m_aPrimVerts.Count();
  1240. for ( int iVert = 0; iVert < nVertCount; ++iVert )
  1241. {
  1242. overlayvert_t *pVert = &pFrag->m_aPrimVerts[iVert];
  1243. float flDistSq = pVert->pos.DistToSqr( pOverlay->m_vecOrigin );
  1244. flRadiusSq = MAX( flRadiusSq, flDistSq );
  1245. }
  1246. }
  1247. pOverlay->m_flRadius = sqrt( flRadiusSq );
  1248. }
  1249. // Overlay checking!
  1250. for ( int iOverlay = 0; iOverlay < nOverlayCount; ++iOverlay )
  1251. {
  1252. moverlay_t *pOverlay = &m_aOverlays.Element( iOverlay );
  1253. mtexinfo_t *pTexInfo = &host_state.worldbrush->texinfo[pOverlay->m_nTexInfo];
  1254. const char *pShaderName = pTexInfo->material->GetShaderName();
  1255. if ( !V_stricmp( pShaderName, "UnlitGeneric") || !V_stricmp( pShaderName, "DecalModulate") )
  1256. {
  1257. pOverlay->m_nFlags = FOVERLAY_DRAW_UNLIT;
  1258. }
  1259. else
  1260. {
  1261. pOverlay->m_nFlags = 0;
  1262. }
  1263. int hFrag = pOverlay->m_hFirstFragment;
  1264. while ( hFrag != OVERLAY_FRAGMENT_INVALID )
  1265. {
  1266. int iFrag = m_OverlayFragments[hFrag];
  1267. moverlayfragment_t *pFrag = &m_aFragments[iFrag];
  1268. if ( !IsFinite( pFrag->decalOffset ) )
  1269. {
  1270. Assert( 0 );
  1271. DevMsg( 1, "Bad overlay decal offset - %d with material '%s'\n", iOverlay,
  1272. ( pTexInfo && pTexInfo->material ) ? pTexInfo->material->GetName() : "" );
  1273. }
  1274. int nVertCount = pFrag->m_aPrimVerts.Count();
  1275. for ( int iVert = 0; iVert < nVertCount; ++iVert )
  1276. {
  1277. overlayvert_t *pVert = &pFrag->m_aPrimVerts[iVert];
  1278. if ( !pVert->pos.IsValid() )
  1279. {
  1280. Assert( 0 );
  1281. DevMsg( 1, "Bad overlay vert - %d at (%f, %f, %f) with material '%s'\n", iOverlay,
  1282. pOverlay->m_vecOrigin.x, pOverlay->m_vecOrigin.y, pOverlay->m_vecOrigin.z,
  1283. ( pTexInfo && pTexInfo->material ) ? pTexInfo->material->GetName() : "" );
  1284. }
  1285. if ( !pVert->normal.IsValid() )
  1286. {
  1287. Assert( 0 );
  1288. DevMsg( 1, "Bad overlay normal - %d at (%f, %f, %f) with material '%s'\n", iOverlay,
  1289. pOverlay->m_vecOrigin.x, pOverlay->m_vecOrigin.y, pOverlay->m_vecOrigin.z,
  1290. ( pTexInfo && pTexInfo->material ) ? pTexInfo->material->GetName() : "" );
  1291. }
  1292. if ( !pVert->texCoord[0].IsValid() || !pVert->texCoord[1].IsValid() )
  1293. {
  1294. Assert( 0 );
  1295. DevMsg( 1, "Bad overlay texture coords - %d at (%f, %f, %f) with material '%s'\n", iOverlay,
  1296. pOverlay->m_vecOrigin.x, pOverlay->m_vecOrigin.y, pOverlay->m_vecOrigin.z,
  1297. ( pTexInfo && pTexInfo->material ) ? pTexInfo->material->GetName() : "" );
  1298. }
  1299. }
  1300. hFrag = m_OverlayFragments.Next( hFrag );
  1301. }
  1302. }
  1303. BuildStaticBuffers();
  1304. }
  1305. //-----------------------------------------------------------------------------
  1306. // COverlayMgr::BuildStaticBuffers
  1307. //-----------------------------------------------------------------------------
  1308. void COverlayMgr::BuildStaticBuffers()
  1309. {
  1310. int nOverlayCount = m_aOverlays.Count();
  1311. for ( int iOverlay = 0; iOverlay < nOverlayCount; ++iOverlay )
  1312. {
  1313. moverlay_t *pOverlay = &m_aOverlays.Element( iOverlay );
  1314. int hFrag = pOverlay->m_hFirstFragment;
  1315. while ( hFrag != OVERLAY_FRAGMENT_INVALID )
  1316. {
  1317. int iFrag = m_OverlayFragments[hFrag];
  1318. moverlayfragment_t* pFragment = &m_aFragments[iFrag];
  1319. // Get material associated with the fragment
  1320. IMaterial* pMaterial = m_RenderQueue[pFragment->m_nMaterialSortID].m_pMaterial;
  1321. pFragment->m_iMesh = FindOrdAddMesh( pMaterial, pFragment->m_aPrimVerts.Count() );
  1322. hFrag = m_OverlayFragments.Next( hFrag );
  1323. }
  1324. }
  1325. CMatRenderContextPtr pRenderContext( materials );
  1326. for ( int iMesh = 0; iMesh < m_RenderMeshes.Count(); ++iMesh )
  1327. {
  1328. Assert( m_RenderMeshes[iMesh].m_nVertCount > 0 );
  1329. if ( g_VBAllocTracker )
  1330. g_VBAllocTracker->TrackMeshAllocations( "OverlayMeshCreate" );
  1331. m_RenderMeshes[iMesh].m_pMesh = pRenderContext->CreateStaticMesh( m_RenderMeshes[iMesh].m_VertexFormat, TEXTURE_GROUP_STATIC_VERTEX_BUFFER_OTHER, m_RenderMeshes[iMesh].m_pMaterial );
  1332. int vertBufferIndex = 0;
  1333. // NOTE: Index count is zero because this will be a static vertex buffer!!!
  1334. CMeshBuilder meshBuilder;
  1335. meshBuilder.Begin( m_RenderMeshes[iMesh].m_pMesh, MATERIAL_TRIANGLES, m_RenderMeshes[iMesh].m_nVertCount, 0 );
  1336. for ( int iOverlay = 0; iOverlay < nOverlayCount; ++iOverlay )
  1337. {
  1338. moverlay_t *pOverlay = &m_aOverlays.Element( iOverlay );
  1339. int hFrag = pOverlay->m_hFirstFragment;
  1340. while ( hFrag != OVERLAY_FRAGMENT_INVALID )
  1341. {
  1342. int iFrag = m_OverlayFragments[hFrag];
  1343. moverlayfragment_t* pFragment = &m_aFragments[iFrag];
  1344. int meshId = pFragment->m_iMesh;
  1345. if ( meshId == iMesh )
  1346. {
  1347. IMaterial* pMaterial = m_RenderQueue[pFragment->m_nMaterialSortID].m_pMaterial;
  1348. bool bLightmappedMaterial = pMaterial->GetPropertyFlag( MATERIAL_PROPERTY_NEEDS_LIGHTMAP ) ||
  1349. pMaterial->GetPropertyFlag( MATERIAL_PROPERTY_NEEDS_BUMPED_LIGHTMAPS );
  1350. int nVertCount = pFragment->m_aPrimVerts.Count();
  1351. const overlayvert_t *pVert = &(pFragment->m_aPrimVerts[0]);
  1352. if ( bLightmappedMaterial )
  1353. {
  1354. float flOffset = pFragment->decalOffset;
  1355. for ( int iVert = 0; iVert < nVertCount; ++iVert, ++pVert )
  1356. {
  1357. meshBuilder.Position3fv( pVert->pos.Base() );
  1358. meshBuilder.Normal3fv( pVert->normal.Base() );
  1359. meshBuilder.Color4Packed( 0xFFFFFFFF );
  1360. meshBuilder.TexCoord2fv( 0, pVert->texCoord[0].Base() );
  1361. meshBuilder.TexCoord2fv( 1, pVert->lightCoord );
  1362. meshBuilder.TexCoord2f( 2, flOffset, 0 );
  1363. meshBuilder.AdvanceVertexF<VTX_HAVEPOS|VTX_HAVENORMAL|VTX_HAVECOLOR, 3>();
  1364. }
  1365. }
  1366. else
  1367. {
  1368. for ( int iVert = 0; iVert < nVertCount; ++iVert, ++pVert )
  1369. {
  1370. meshBuilder.Position3fv( pVert->pos.Base() );
  1371. meshBuilder.Normal3fv( pVert->normal.Base() );
  1372. meshBuilder.Color4Packed( 0xFFFFFFFF );
  1373. meshBuilder.TexCoord2fv( 0, pVert->texCoord[0].Base() );
  1374. meshBuilder.TexCoord2fv( 1, pVert->lightCoord );
  1375. meshBuilder.TexCoord2fv( 2, pVert->texCoord[1].Base() );
  1376. meshBuilder.AdvanceVertexF<VTX_HAVEPOS|VTX_HAVENORMAL|VTX_HAVECOLOR, 3>();
  1377. }
  1378. }
  1379. pFragment->m_nVertexBufferIndex = vertBufferIndex;
  1380. vertBufferIndex += nVertCount;
  1381. }
  1382. hFrag = m_OverlayFragments.Next( hFrag );
  1383. }
  1384. }
  1385. meshBuilder.End();
  1386. Assert(vertBufferIndex == m_RenderMeshes[iMesh].m_nVertCount);
  1387. if ( g_VBAllocTracker )
  1388. g_VBAllocTracker->TrackMeshAllocations( NULL );
  1389. }
  1390. }
  1391. //-----------------------------------------------------------------------------
  1392. // COverlayMgr::DestroyStaticBuffers
  1393. //-----------------------------------------------------------------------------
  1394. void COverlayMgr::DestroyStaticBuffers()
  1395. {
  1396. // Destroy static vertex buffers
  1397. if ( m_RenderMeshes.Count() > 0 )
  1398. {
  1399. CMatRenderContextPtr pRenderContext( materials );
  1400. for ( int i = 0; i < m_RenderMeshes.Count(); i++ )
  1401. {
  1402. pRenderContext->DestroyStaticMesh( m_RenderMeshes[i].m_pMesh );
  1403. }
  1404. }
  1405. m_RenderMeshes.Purge();
  1406. }
  1407. //-----------------------------------------------------------------------------
  1408. // Purpose:
  1409. //-----------------------------------------------------------------------------
  1410. int COverlayMgr::FindOrdAddMesh( IMaterial* pMaterial, int vertCount )
  1411. {
  1412. VertexFormat_t format = ( pMaterial->GetVertexFormat() & ~VERTEX_FORMAT_COMPRESSED );
  1413. CMatRenderContextPtr pRenderContext( materials );
  1414. int nMaxVertices = pRenderContext->GetMaxVerticesToRender( pMaterial );
  1415. for ( int i = 0; i < m_RenderMeshes.Count(); i++ )
  1416. {
  1417. if ( m_RenderMeshes[i].m_VertexFormat != format )
  1418. continue;
  1419. if ( m_RenderMeshes[i].m_nVertCount + vertCount > nMaxVertices )
  1420. continue;
  1421. m_RenderMeshes[i].m_nVertCount += vertCount;
  1422. return i;
  1423. }
  1424. int index = m_RenderMeshes.AddToTail();
  1425. m_RenderMeshes[index].m_nVertCount = vertCount;
  1426. m_RenderMeshes[index].m_VertexFormat = format;
  1427. m_RenderMeshes[index].m_pMaterial = pMaterial;
  1428. return index;
  1429. }
  1430. //-----------------------------------------------------------------------------
  1431. // Purpose:
  1432. //-----------------------------------------------------------------------------
  1433. void COverlayMgr::UpdateOverlayRenderLevels( int nCPULevel, int nGPULevel )
  1434. {
  1435. m_nCPULevel = nCPULevel;
  1436. m_nGPULevel = nGPULevel;
  1437. }
  1438. //-----------------------------------------------------------------------------
  1439. // Purpose:
  1440. //-----------------------------------------------------------------------------
  1441. void COverlayMgr::ReSortMaterials( void )
  1442. {
  1443. #ifndef DEDICATED
  1444. // Clear the old render queue.
  1445. m_RenderQueue.Purge();
  1446. for ( int iSort = 0; iSort < MAX_MAT_SORT_GROUPS; ++iSort )
  1447. {
  1448. m_nFirstRenderQueue[iSort] = RENDER_QUEUE_INVALID;
  1449. }
  1450. // Update all fragments.
  1451. if ( host_state.worldbrush )
  1452. {
  1453. int nOverlayCount = m_aOverlays.Count();
  1454. for (int iOverlay = 0; iOverlay < nOverlayCount; ++iOverlay)
  1455. {
  1456. moverlay_t *pOverlay = &m_aOverlays.Element( iOverlay );
  1457. if (!pOverlay)
  1458. continue;
  1459. mtexinfo_t *pTexInfo = &host_state.worldbrush->texinfo[pOverlay->m_nTexInfo];
  1460. if (!pTexInfo)
  1461. continue;
  1462. int hFrag = pOverlay->m_hFirstFragment;
  1463. while (hFrag != OVERLAY_FRAGMENT_INVALID)
  1464. {
  1465. int iFrag = m_OverlayFragments[hFrag];
  1466. moverlayfragment_t *pFrag = &m_aFragments[iFrag];
  1467. if (pFrag)
  1468. {
  1469. const MaterialSystem_SortInfo_t &sortInfo = materialSortInfoArray[MSurf_MaterialSortID( pFrag->m_SurfId )];
  1470. pFrag->m_nMaterialSortID = GetMaterialSortID( pTexInfo->material, sortInfo.lightmapPageID );
  1471. // Get surface context.
  1472. SurfaceCtx_t ctx;
  1473. SurfSetupSurfaceContext( ctx, pFrag->m_SurfId );
  1474. if ( SurfaceHasDispInfo( pFrag->m_SurfId ) )
  1475. {
  1476. IDispInfo *pIDisp = MSurf_DispInfo( pFrag->m_SurfId );
  1477. CDispInfo *pDisp = static_cast<CDispInfo*>(pIDisp);
  1478. CMeshReader *pReader;
  1479. if ( pDisp )
  1480. {
  1481. pReader = &pDisp->m_MeshReader;
  1482. Vector2D lightCoords[4];
  1483. int nInterval = pDisp->GetSideLength();
  1484. pReader->TexCoord2f( 0, DISP_LMCOORDS_STAGE, lightCoords[0].x, lightCoords[0].y );
  1485. pReader->TexCoord2f( nInterval - 1, DISP_LMCOORDS_STAGE, lightCoords[1].x, lightCoords[1].y );
  1486. pReader->TexCoord2f( (nInterval * nInterval) - 1, DISP_LMCOORDS_STAGE, lightCoords[2].x, lightCoords[2].y );
  1487. pReader->TexCoord2f( nInterval * (nInterval - 1), DISP_LMCOORDS_STAGE, lightCoords[3].x, lightCoords[3].y );
  1488. int nVertCount = pFrag->m_aPrimVerts.Count();
  1489. for ( int iVert = 0; iVert < nVertCount; ++iVert )
  1490. {
  1491. // Lightmap coordinates.
  1492. Vector2D uv;
  1493. TexCoordInQuadFromBarycentric( lightCoords[0], lightCoords[1], lightCoords[2], lightCoords[3], pFrag->m_aPrimVerts[iVert].tmpDispUV, uv );
  1494. pFrag->m_aPrimVerts[iVert].lightCoord[0] = uv.x;
  1495. pFrag->m_aPrimVerts[iVert].lightCoord[1] = uv.y;
  1496. }
  1497. }
  1498. }
  1499. else
  1500. {
  1501. int nVertCount = pFrag->m_aPrimVerts.Count();
  1502. for ( int iVert = 0; iVert < nVertCount; ++iVert )
  1503. {
  1504. const Vector originalPos = pFrag->m_aPrimVerts[iVert].pos - (pFrag->m_aPrimVerts[iVert].normal * OVERLAY_AVOID_FLICKER_NORMAL_OFFSET);
  1505. // Lightmap coordinates.
  1506. Vector2D uv;
  1507. SurfComputeLightmapCoordinate( ctx, pFrag->m_SurfId, originalPos, uv );
  1508. pFrag->m_aPrimVerts[iVert].lightCoord[0] = uv.x;
  1509. pFrag->m_aPrimVerts[iVert].lightCoord[1] = uv.y;
  1510. }
  1511. }
  1512. }
  1513. hFrag = m_OverlayFragments.Next( hFrag );
  1514. }
  1515. }
  1516. }
  1517. // Rebuild static buffers since geometry has changes
  1518. DestroyStaticBuffers();
  1519. BuildStaticBuffers();
  1520. #endif // !DEDICATED
  1521. }
  1522. //-----------------------------------------------------------------------------
  1523. // Loads overlays from the lump
  1524. //-----------------------------------------------------------------------------
  1525. bool COverlayMgr::LoadOverlays( )
  1526. {
  1527. CMapLoadHelper lh( LUMP_OVERLAYS );
  1528. CMapLoadHelper lh2( LUMP_WATEROVERLAYS );
  1529. CMapLoadHelper lhOverlayFades( LUMP_OVERLAY_FADES );
  1530. CMapLoadHelper lhOverlaySystemLevel( LUMP_OVERLAY_SYSTEM_LEVELS );
  1531. doverlay_t *pOverlayIn;
  1532. dwateroverlay_t *pWaterOverlayIn;
  1533. pOverlayIn = ( doverlay_t* )lh.LumpBase();
  1534. if ( lh.LumpSize() % sizeof( doverlay_t ) )
  1535. return false;
  1536. pWaterOverlayIn = ( dwateroverlay_t* )lh2.LumpBase();
  1537. if ( lh2.LumpSize() % sizeof( dwateroverlay_t ) )
  1538. return false;
  1539. // Fade distances are in a parallel lump
  1540. doverlayfade_t *pOverlayFadesIn = (doverlayfade_t *)lhOverlayFades.LumpBase();
  1541. if ( lhOverlayFades.LumpSize() % sizeof( doverlayfade_t ) )
  1542. return false;
  1543. // System levels are in yet another parallel lump
  1544. doverlaysystemlevel_t *pOverlaySystemLevelIn = (doverlaysystemlevel_t *)lhOverlaySystemLevel.LumpBase();
  1545. if ( lhOverlaySystemLevel.LumpSize() % sizeof( doverlaysystemlevel_t ) )
  1546. return false;
  1547. int nOverlayCount = lh.LumpSize() / sizeof( doverlay_t );
  1548. int nWaterOverlayCount = lh2.LumpSize() / sizeof( dwateroverlay_t );
  1549. // Memory allocation!
  1550. m_aOverlays.SetSize( nOverlayCount + nWaterOverlayCount );
  1551. for ( int iOverlay = 0; iOverlay < nOverlayCount; ++iOverlay, ++pOverlayIn )
  1552. {
  1553. moverlay_t *pOverlayOut = &m_aOverlays.Element( iOverlay );
  1554. // Use the system if it exists - not all maps were recompiled.
  1555. if ( pOverlaySystemLevelIn )
  1556. {
  1557. pOverlayOut->m_nMinCPULevel = pOverlaySystemLevelIn->nMinCPULevel;
  1558. pOverlayOut->m_nMaxCPULevel = pOverlaySystemLevelIn->nMaxCPULevel;
  1559. pOverlayOut->m_nMinGPULevel = pOverlaySystemLevelIn->nMinGPULevel;
  1560. pOverlayOut->m_nMaxGPULevel = pOverlaySystemLevelIn->nMaxGPULevel;
  1561. pOverlaySystemLevelIn++;
  1562. }
  1563. pOverlayOut->m_nId = iOverlay;
  1564. pOverlayOut->m_nTexInfo = pOverlayIn->nTexInfo;
  1565. pOverlayOut->m_nRenderOrder = pOverlayIn->GetRenderOrder();
  1566. pOverlayOut->m_nFlags = 0;
  1567. if ( pOverlayOut->m_nRenderOrder >= OVERLAY_NUM_RENDER_ORDERS )
  1568. Error( "COverlayMgr::LoadOverlays: invalid render order (%d) for an overlay.", pOverlayOut->m_nRenderOrder );
  1569. pOverlayOut->m_flU[0] = pOverlayIn->flU[0];
  1570. pOverlayOut->m_flU[1] = pOverlayIn->flU[1];
  1571. pOverlayOut->m_flV[0] = pOverlayIn->flV[0];
  1572. pOverlayOut->m_flV[1] = pOverlayIn->flV[1];
  1573. if ( pOverlayFadesIn )
  1574. {
  1575. pOverlayOut->m_flFadeDistMinSq = pOverlayFadesIn->flFadeDistMinSq;
  1576. pOverlayOut->m_flFadeDistMaxSq = pOverlayFadesIn->flFadeDistMaxSq;
  1577. pOverlayOut->m_flInvFadeRangeSq = 1.0f / ( pOverlayFadesIn->flFadeDistMaxSq - pOverlayFadesIn->flFadeDistMinSq );
  1578. pOverlayFadesIn++;
  1579. }
  1580. else
  1581. {
  1582. pOverlayOut->m_flFadeDistMinSq = -1.0f;
  1583. pOverlayOut->m_flFadeDistMaxSq = 0;
  1584. pOverlayOut->m_flInvFadeRangeSq = 1.0f;
  1585. }
  1586. VectorCopy( pOverlayIn->vecOrigin, pOverlayOut->m_vecOrigin );
  1587. VectorCopy( pOverlayIn->vecUVPoints[0], pOverlayOut->m_vecUVPoints[0] );
  1588. VectorCopy( pOverlayIn->vecUVPoints[1], pOverlayOut->m_vecUVPoints[1] );
  1589. VectorCopy( pOverlayIn->vecUVPoints[2], pOverlayOut->m_vecUVPoints[2] );
  1590. VectorCopy( pOverlayIn->vecUVPoints[3], pOverlayOut->m_vecUVPoints[3] );
  1591. VectorCopy( pOverlayIn->vecBasisNormal, pOverlayOut->m_vecBasis[2] );
  1592. // Basis U is encoded in the z components of the UVPoints 0, 1, 2
  1593. pOverlayOut->m_vecBasis[0].x = pOverlayOut->m_vecUVPoints[0].z;
  1594. pOverlayOut->m_vecBasis[0].y = pOverlayOut->m_vecUVPoints[1].z;
  1595. pOverlayOut->m_vecBasis[0].z = pOverlayOut->m_vecUVPoints[2].z;
  1596. if ( pOverlayOut->m_vecBasis[0].x == 0.0f && pOverlayOut->m_vecBasis[0].y == 0.0f && pOverlayOut->m_vecBasis[0].z == 0.0f )
  1597. {
  1598. Warning( "Bad overlay basis at (%f %f %f)!\n", pOverlayOut->m_vecOrigin.x, pOverlayOut->m_vecOrigin.y, pOverlayOut->m_vecOrigin.z );
  1599. }
  1600. CrossProduct( pOverlayOut->m_vecBasis[2], pOverlayOut->m_vecBasis[0], pOverlayOut->m_vecBasis[1] );
  1601. VectorNormalize( pOverlayOut->m_vecBasis[1] );
  1602. pOverlayOut->m_vecUVPoints[0].z = 0.0f;
  1603. pOverlayOut->m_vecUVPoints[1].z = 0.0f;
  1604. pOverlayOut->m_vecUVPoints[2].z = 0.0f;
  1605. pOverlayOut->m_aFaces.SetSize( pOverlayIn->GetFaceCount() );
  1606. for( int iFace = 0; iFace < pOverlayIn->GetFaceCount(); ++iFace )
  1607. {
  1608. pOverlayOut->m_aFaces[iFace] = SurfaceHandleFromIndex( pOverlayIn->aFaces[iFace], lh.GetMap() );
  1609. }
  1610. pOverlayOut->m_hFirstFragment = OVERLAY_FRAGMENT_LIST_INVALID;
  1611. pOverlayOut->m_pBindProxy = NULL;
  1612. }
  1613. for( int iWaterOverlay = 0; iWaterOverlay < nWaterOverlayCount; ++iWaterOverlay, ++pWaterOverlayIn )
  1614. {
  1615. moverlay_t *pOverlayOut = &m_aOverlays.Element( nOverlayCount + iWaterOverlay );
  1616. pOverlayOut->m_nId = nOverlayCount + iWaterOverlay;
  1617. pOverlayOut->m_nTexInfo = pWaterOverlayIn->nTexInfo;
  1618. pOverlayOut->m_nRenderOrder = pWaterOverlayIn->GetRenderOrder();
  1619. pOverlayOut->m_nFlags = 0;
  1620. if ( pOverlayOut->m_nRenderOrder >= OVERLAY_NUM_RENDER_ORDERS )
  1621. Error( "COverlayMgr::LoadOverlays: invalid render order (%d) for an overlay.", pOverlayOut->m_nRenderOrder );
  1622. pOverlayOut->m_flU[0] = pWaterOverlayIn->flU[0];
  1623. pOverlayOut->m_flU[1] = pWaterOverlayIn->flU[1];
  1624. pOverlayOut->m_flV[0] = pWaterOverlayIn->flV[0];
  1625. pOverlayOut->m_flV[1] = pWaterOverlayIn->flV[1];
  1626. VectorCopy( pWaterOverlayIn->vecOrigin, pOverlayOut->m_vecOrigin );
  1627. VectorCopy( pWaterOverlayIn->vecUVPoints[0], pOverlayOut->m_vecUVPoints[0] );
  1628. VectorCopy( pWaterOverlayIn->vecUVPoints[1], pOverlayOut->m_vecUVPoints[1] );
  1629. VectorCopy( pWaterOverlayIn->vecUVPoints[2], pOverlayOut->m_vecUVPoints[2] );
  1630. VectorCopy( pWaterOverlayIn->vecUVPoints[3], pOverlayOut->m_vecUVPoints[3] );
  1631. VectorCopy( pWaterOverlayIn->vecBasisNormal, pOverlayOut->m_vecBasis[2] );
  1632. // Basis U is encoded in the z components of the UVPoints 0, 1, 2
  1633. pOverlayOut->m_vecBasis[0].x = pOverlayOut->m_vecUVPoints[0].z;
  1634. pOverlayOut->m_vecBasis[0].y = pOverlayOut->m_vecUVPoints[1].z;
  1635. pOverlayOut->m_vecBasis[0].z = pOverlayOut->m_vecUVPoints[2].z;
  1636. if ( pOverlayOut->m_vecBasis[0].x == 0.0f && pOverlayOut->m_vecBasis[0].y == 0.0f && pOverlayOut->m_vecBasis[0].z == 0.0f )
  1637. {
  1638. Warning( "Bad overlay basis at (%f %f %f)!\n", pOverlayOut->m_vecOrigin.x, pOverlayOut->m_vecOrigin.y, pOverlayOut->m_vecOrigin.z );
  1639. }
  1640. CrossProduct( pOverlayOut->m_vecBasis[2], pOverlayOut->m_vecBasis[0], pOverlayOut->m_vecBasis[1] );
  1641. VectorNormalize( pOverlayOut->m_vecBasis[1] );
  1642. pOverlayOut->m_vecUVPoints[0].z = 0.0f;
  1643. pOverlayOut->m_vecUVPoints[1].z = 0.0f;
  1644. pOverlayOut->m_vecUVPoints[2].z = 0.0f;
  1645. pOverlayOut->m_aFaces.SetSize( pWaterOverlayIn->GetFaceCount() );
  1646. for( int iFace = 0; iFace < pWaterOverlayIn->GetFaceCount(); ++iFace )
  1647. {
  1648. pOverlayOut->m_aFaces[iFace] = SurfaceHandleFromIndex( pWaterOverlayIn->aFaces[iFace], lh2.GetMap() );
  1649. }
  1650. pOverlayOut->m_hFirstFragment = OVERLAY_FRAGMENT_LIST_INVALID;
  1651. pOverlayOut->m_pBindProxy = NULL;
  1652. }
  1653. return true;
  1654. }
  1655. //-----------------------------------------------------------------------------
  1656. // Purpose:
  1657. //-----------------------------------------------------------------------------
  1658. void COverlayMgr::Disp_CreateFragments( moverlay_t *pOverlay, SurfaceHandle_t surfID )
  1659. {
  1660. OverlayFragmentVector_t aDispFragments;
  1661. if ( Disp_PreClipFragment( pOverlay, aDispFragments, surfID ) )
  1662. {
  1663. IDispInfo *pIDisp = MSurf_DispInfo( surfID );
  1664. CDispInfo *pDisp = static_cast<CDispInfo*>( pIDisp );
  1665. if ( pDisp )
  1666. {
  1667. Disp_ClipFragment( pDisp, aDispFragments );
  1668. Disp_PostClipFragment( pDisp, &pDisp->m_MeshReader, pOverlay, aDispFragments, surfID );
  1669. }
  1670. }
  1671. for ( int i = aDispFragments.Count(); --i >= 0; )
  1672. {
  1673. DestroyTempFragment( aDispFragments[i] );
  1674. }
  1675. }
  1676. //-----------------------------------------------------------------------------
  1677. // Purpose:
  1678. //-----------------------------------------------------------------------------
  1679. bool COverlayMgr::Disp_PreClipFragment( moverlay_t *pOverlay, OverlayFragmentVector_t &aDispFragments,
  1680. SurfaceHandle_t surfID )
  1681. {
  1682. MEM_ALLOC_CREDIT();
  1683. // The faces are not tesselated when they are displaced faces.
  1684. int iFirstVert = MSurf_FirstVertIndex( surfID );
  1685. // Displaced faces are quads.
  1686. moverlayfragment_t surfaceFrag;
  1687. surfaceFrag.m_aPrimVerts.SetCount( 4 );
  1688. for( int iVert = 0; iVert < 4; ++iVert )
  1689. {
  1690. int iVertex = host_state.worldbrush->vertindices[(iFirstVert+iVert)];
  1691. mvertex_t *pVert = &host_state.worldbrush->vertexes[iVertex];
  1692. surfaceFrag.m_aPrimVerts[iVert].pos = pVert->position;
  1693. }
  1694. // Setup the base fragment to be clipped by the base surface previous to the
  1695. // displaced surface.
  1696. moverlayfragment_t overlayFrag;
  1697. if ( !Surf_PreClipFragment( pOverlay, overlayFrag, surfID, surfaceFrag ) )
  1698. return false;
  1699. Surf_ClipFragment( pOverlay, overlayFrag, surfID, surfaceFrag );
  1700. // Get fragment vertex count.
  1701. int nVertCount = overlayFrag.m_aPrimVerts.Count();
  1702. if ( nVertCount == 0 )
  1703. return false;
  1704. // Setup
  1705. moverlayfragment_t *pFragment = CopyTempFragment( &overlayFrag );
  1706. aDispFragments.AddToTail( pFragment );
  1707. IDispInfo *pIDispInfo = MSurf_DispInfo( surfID );
  1708. CDispInfo *pDispInfo = static_cast<CDispInfo*>( pIDispInfo );
  1709. int iPointStart = pDispInfo->m_iPointStart;
  1710. Vector2D vecTmpUV;
  1711. for ( int iVert = 0; iVert < nVertCount; ++iVert )
  1712. {
  1713. PointInQuadToBarycentric( surfaceFrag.m_aPrimVerts[iPointStart].pos,
  1714. surfaceFrag.m_aPrimVerts[(iPointStart+3)%4].pos,
  1715. surfaceFrag.m_aPrimVerts[(iPointStart+2)%4].pos,
  1716. surfaceFrag.m_aPrimVerts[(iPointStart+1)%4].pos,
  1717. overlayFrag.m_aPrimVerts[iVert].pos,
  1718. vecTmpUV );
  1719. if ( !vecTmpUV.IsValid() )
  1720. {
  1721. mtexinfo_t *pTexInfo = &host_state.worldbrush->texinfo[pOverlay->m_nTexInfo];
  1722. DevWarning( 1, "Bad overlay geometry at %s with material '%s'\n", VecToString(pOverlay->m_vecOrigin),
  1723. ( pTexInfo && pTexInfo->material ) ? pTexInfo->material->GetName() : "" );
  1724. return false;
  1725. }
  1726. pFragment->m_aPrimVerts[iVert].pos.x = vecTmpUV.x;
  1727. pFragment->m_aPrimVerts[iVert].pos.y = vecTmpUV.y;
  1728. pFragment->m_aPrimVerts[iVert].pos.z = 0.0f;
  1729. }
  1730. return true;
  1731. }
  1732. //-----------------------------------------------------------------------------
  1733. // Purpose:
  1734. //-----------------------------------------------------------------------------
  1735. void COverlayMgr::Disp_PostClipFragment( CDispInfo *pDisp, CMeshReader *pReader, moverlay_t *pOverlay,
  1736. OverlayFragmentVector_t &aDispFragments, SurfaceHandle_t surfID )
  1737. {
  1738. #ifndef DEDICATED
  1739. if ( aDispFragments.Count() == 0 )
  1740. return;
  1741. // Get surface context.
  1742. SurfaceCtx_t ctx;
  1743. SurfSetupSurfaceContext( ctx, surfID );
  1744. // The faces are not tesselated when they are displaced faces.
  1745. int iFirstVert = MSurf_FirstVertIndex( surfID );
  1746. // Displaced faces are quads.
  1747. moverlayfragment_t surfaceFrag;
  1748. surfaceFrag.m_aPrimVerts.SetCount( 4 );
  1749. for( int iVert = 0; iVert < 4; ++iVert )
  1750. {
  1751. int iVertex = host_state.worldbrush->vertindices[(iFirstVert+iVert)];
  1752. mvertex_t *pVert = &host_state.worldbrush->vertexes[iVertex];
  1753. surfaceFrag.m_aPrimVerts[iVert].pos = pVert->position;
  1754. }
  1755. Vector2D lightCoords[4];
  1756. int nInterval = pDisp->GetSideLength();
  1757. pReader->TexCoord2f( 0, DISP_LMCOORDS_STAGE, lightCoords[0].x, lightCoords[0].y );
  1758. pReader->TexCoord2f( nInterval - 1, DISP_LMCOORDS_STAGE, lightCoords[1].x, lightCoords[1].y );
  1759. pReader->TexCoord2f( ( nInterval * nInterval ) - 1, DISP_LMCOORDS_STAGE, lightCoords[2].x, lightCoords[2].y );
  1760. pReader->TexCoord2f( nInterval * ( nInterval - 1 ), DISP_LMCOORDS_STAGE, lightCoords[3].x, lightCoords[3].y );
  1761. // Get the number of displacement fragments.
  1762. int nFragCount = aDispFragments.Count();
  1763. for ( int iFrag = 0; iFrag < nFragCount; ++iFrag )
  1764. {
  1765. moverlayfragment_t *pDispFragment = aDispFragments[iFrag];
  1766. if ( !pDispFragment )
  1767. continue;
  1768. int nVertCount = pDispFragment->m_aPrimVerts.Count();
  1769. if ( nVertCount < 3 )
  1770. continue;
  1771. // Create fragment.
  1772. OverlayFragmentHandle_t hFragment = AddFragmentToFragmentList( nVertCount );
  1773. moverlayfragment_t *pFragment = GetOverlayFragment( hFragment );
  1774. pFragment->m_iOverlay = pOverlay->m_nId;
  1775. pFragment->m_SurfId = surfID;
  1776. pFragment->decalOffset = ComputeDecalLightmapOffset( surfID );
  1777. Vector2D vecTmpUV;
  1778. Vector vecTmp;
  1779. for ( int iVert = 0; iVert < nVertCount; ++iVert )
  1780. {
  1781. vecTmpUV.x = pDispFragment->m_aPrimVerts[iVert].pos.x;
  1782. vecTmpUV.y = pDispFragment->m_aPrimVerts[iVert].pos.y;
  1783. vecTmpUV.x = clamp( vecTmpUV.x, 0.0f, 1.0f );
  1784. vecTmpUV.y = clamp( vecTmpUV.y, 0.0f, 1.0f );
  1785. Overlay_DispUVToWorld( pDisp, pReader, vecTmpUV, pFragment->m_aPrimVerts[iVert].pos, pFragment->m_aPrimVerts[iVert].normal, surfaceFrag );
  1786. // Texture coordinates.
  1787. pFragment->m_aPrimVerts[iVert].texCoord[0] = pDispFragment->m_aPrimVerts[iVert].texCoord[0];
  1788. pFragment->m_aPrimVerts[iVert].texCoord[1] = pDispFragment->m_aPrimVerts[iVert].texCoord[1];
  1789. // cache for use in ReSortMaterials
  1790. pFragment->m_aPrimVerts[iVert].tmpDispUV = vecTmpUV;
  1791. // Lightmap coordinates.
  1792. Vector2D uv;
  1793. TexCoordInQuadFromBarycentric( lightCoords[0], lightCoords[1], lightCoords[2], lightCoords[3], vecTmpUV, uv );
  1794. pFragment->m_aPrimVerts[iVert].lightCoord[0] = uv.x;
  1795. pFragment->m_aPrimVerts[iVert].lightCoord[1] = uv.y;
  1796. }
  1797. // Create the sort ID for this fragment
  1798. const MaterialSystem_SortInfo_t &sortInfo = materialSortInfoArray[MSurf_MaterialSortID( surfID )];
  1799. mtexinfo_t *pTexInfo = &host_state.worldbrush->texinfo[pOverlay->m_nTexInfo];
  1800. pFragment->m_nMaterialSortID = GetMaterialSortID( pTexInfo->material, sortInfo.lightmapPageID );
  1801. // Add to list of fragments for this overlay
  1802. MEM_ALLOC_CREDIT();
  1803. OverlayFragmentList_t i = m_OverlayFragments.Alloc( true );
  1804. m_OverlayFragments[i] = hFragment;
  1805. m_OverlayFragments.LinkBefore( pOverlay->m_hFirstFragment, i );
  1806. pOverlay->m_hFirstFragment = i;
  1807. // Add to list of fragments for this surface
  1808. // NOTE: Store them in *reverse* order so that when we pull them off for
  1809. // rendering, we can do *that* in reverse order too? Reduces the amount of iteration necessary
  1810. // Therefore, we need to add to the head of the list
  1811. m_aFragments.LinkBefore( MSurf_OverlayFragmentList( surfID ), hFragment );
  1812. MSurf_OverlayFragmentList( surfID ) = hFragment;
  1813. }
  1814. #endif // !DEDICATED
  1815. }
  1816. //-----------------------------------------------------------------------------
  1817. // Purpose:
  1818. //-----------------------------------------------------------------------------
  1819. void COverlayMgr::Disp_ClipFragment( CDispInfo *pDisp, OverlayFragmentVector_t &aDispFragments )
  1820. {
  1821. cplane_t clipPlane;
  1822. // Cache the displacement interval.
  1823. const CPowerInfo *pPowerInfo = pDisp->GetPowerInfo();
  1824. int nInterval = ( 1 << pPowerInfo->GetPower() );
  1825. // Displacement-space clipping in V.
  1826. clipPlane.normal.Init( 1.0f, 0.0f, 0.0f );
  1827. Disp_DoClip( pDisp, aDispFragments, clipPlane, 1.0f, nInterval, 1, nInterval, 1 );
  1828. // Displacement-space clipping in U.
  1829. clipPlane.normal.Init( 0.0f, 1.0f, 0.0f );
  1830. Disp_DoClip( pDisp, aDispFragments, clipPlane, 1.0f, nInterval, 1, nInterval, 1 );
  1831. // Displacement-space clipping UV from top-left to bottom-right.
  1832. clipPlane.normal.Init( 0.707f, 0.707f, 0.0f ); // 45 degrees
  1833. Disp_DoClip( pDisp, aDispFragments, clipPlane, 0.707f, nInterval, 2, ( nInterval * 2 - 1 ), 2 );
  1834. // Displacement-space clipping UV from bottom-left to top-right.
  1835. clipPlane.normal.Init( -0.707f, 0.707f, 0.0f ); // 135 degrees
  1836. Disp_DoClip( pDisp, aDispFragments, clipPlane, 0.707f, nInterval, -( nInterval - 2 ), ( nInterval - 1 ), 2 );
  1837. }
  1838. //-----------------------------------------------------------------------------
  1839. //-----------------------------------------------------------------------------
  1840. void COverlayMgr::Disp_DoClip( CDispInfo *pDisp, OverlayFragmentVector_t &aDispFragments, cplane_t &clipPlane,
  1841. float clipDistStart, int nInterval,
  1842. int nLoopStart, int nLoopEnd, int nLoopInc )
  1843. {
  1844. // Setup interval information.
  1845. float flInterval = static_cast<float>( nInterval );
  1846. float flOOInterval = 1.0f / flInterval;
  1847. // Holds the current set of clipped faces.
  1848. OverlayFragmentVector_t aClippedFragments;
  1849. for ( int iInterval = nLoopStart; iInterval < nLoopEnd; iInterval += nLoopInc )
  1850. {
  1851. // Copy the current list to clipped face list.
  1852. aClippedFragments.CopyArray( aDispFragments.Base(), aDispFragments.Count() );
  1853. aDispFragments.Purge();
  1854. // Clip in V.
  1855. int nFragCount = aClippedFragments.Count();
  1856. for ( int iFrag = 0; iFrag < nFragCount; iFrag++ )
  1857. {
  1858. moverlayfragment_t *pClipFrag = aClippedFragments[iFrag];
  1859. if ( pClipFrag )
  1860. {
  1861. moverlayfragment_t *pFront = NULL, *pBack = NULL;
  1862. clipPlane.dist = clipDistStart * ( ( float )iInterval * flOOInterval );
  1863. DoClipFragment( pClipFrag, &clipPlane, &pFront, &pBack );
  1864. DestroyTempFragment( pClipFrag );
  1865. pClipFrag = NULL;
  1866. if ( pFront )
  1867. {
  1868. aDispFragments.AddToTail( pFront );
  1869. }
  1870. if ( pBack )
  1871. {
  1872. aDispFragments.AddToTail( pBack );
  1873. }
  1874. }
  1875. }
  1876. }
  1877. }
  1878. //-----------------------------------------------------------------------------
  1879. // Purpose:
  1880. //-----------------------------------------------------------------------------
  1881. void COverlayMgr::InitTexCoords( moverlay_t *pOverlay, moverlayfragment_t &overlayFrag )
  1882. {
  1883. // Overlay texture coordinates.
  1884. overlayFrag.m_aPrimVerts[0].texCoord[0].Init( pOverlay->m_flU[0], pOverlay->m_flV[0] );
  1885. overlayFrag.m_aPrimVerts[1].texCoord[0].Init( pOverlay->m_flU[0], pOverlay->m_flV[1] );
  1886. overlayFrag.m_aPrimVerts[2].texCoord[0].Init( pOverlay->m_flU[1], pOverlay->m_flV[1] );
  1887. overlayFrag.m_aPrimVerts[3].texCoord[0].Init( pOverlay->m_flU[1], pOverlay->m_flV[0] );
  1888. overlayFrag.m_aPrimVerts[0].texCoord[1].Init( 0, 0 );
  1889. overlayFrag.m_aPrimVerts[1].texCoord[1].Init( 0, 1 );
  1890. overlayFrag.m_aPrimVerts[2].texCoord[1].Init( 1, 1 );
  1891. overlayFrag.m_aPrimVerts[3].texCoord[1].Init( 1, 0 );
  1892. }
  1893. //-----------------------------------------------------------------------------
  1894. //-----------------------------------------------------------------------------
  1895. void COverlayMgr::DoClipFragment( moverlayfragment_t *pFragment, cplane_t *pClipPlane,
  1896. moverlayfragment_t **ppFront, moverlayfragment_t **ppBack )
  1897. {
  1898. const float OVERLAY_EPSILON = 0.0001f;
  1899. // Verify.
  1900. if ( !pFragment )
  1901. return;
  1902. float flDists[128];
  1903. int nSides[128];
  1904. int nSideCounts[3];
  1905. //
  1906. // Determine "sidedness" of all the polygon points.
  1907. //
  1908. nSideCounts[0] = nSideCounts[1] = nSideCounts[2] = 0;
  1909. int iVert = 0;
  1910. for ( ; iVert < pFragment->m_aPrimVerts.Count(); ++iVert )
  1911. {
  1912. flDists[iVert] = pClipPlane->normal.Dot( pFragment->m_aPrimVerts[iVert].pos ) - pClipPlane->dist;
  1913. if ( flDists[iVert] > OVERLAY_EPSILON )
  1914. {
  1915. nSides[iVert] = SIDE_FRONT;
  1916. }
  1917. else if ( flDists[iVert] < -OVERLAY_EPSILON )
  1918. {
  1919. nSides[iVert] = SIDE_BACK;
  1920. }
  1921. else
  1922. {
  1923. nSides[iVert] = SIDE_ON;
  1924. }
  1925. nSideCounts[nSides[iVert]]++;
  1926. }
  1927. // Wrap around (close the polygon).
  1928. nSides[iVert] = nSides[0];
  1929. flDists[iVert] = flDists[0];
  1930. // All points in back - no split (copy face to back).
  1931. if( !nSideCounts[SIDE_FRONT] )
  1932. {
  1933. *ppBack = CopyTempFragment( pFragment );
  1934. return;
  1935. }
  1936. // All points in front - no split (copy face to front).
  1937. if( !nSideCounts[SIDE_BACK] )
  1938. {
  1939. *ppFront = CopyTempFragment( pFragment );
  1940. return;
  1941. }
  1942. // Build new front and back faces.
  1943. // NOTE: Gotta create them first
  1944. moverlayfragment_t *pFront = CreateTempFragment( 0 );
  1945. moverlayfragment_t *pBack = CreateTempFragment( 0 );
  1946. if ( !pFront || !pBack )
  1947. {
  1948. DestroyTempFragment( pFront );
  1949. DestroyTempFragment( pBack );
  1950. return;
  1951. }
  1952. MEM_ALLOC_CREDIT();
  1953. int nVertCount = pFragment->m_aPrimVerts.Count();
  1954. for ( iVert = 0; iVert < nVertCount; ++iVert )
  1955. {
  1956. // "On" clip plane.
  1957. if ( nSides[iVert] == SIDE_ON )
  1958. {
  1959. pFront->m_aPrimVerts.AddToTail( pFragment->m_aPrimVerts[iVert] );
  1960. pBack->m_aPrimVerts.AddToTail( pFragment->m_aPrimVerts[iVert] );
  1961. continue;
  1962. }
  1963. // "In back" of clip plane.
  1964. if ( nSides[iVert] == SIDE_BACK )
  1965. {
  1966. pBack->m_aPrimVerts.AddToTail( pFragment->m_aPrimVerts[iVert] );
  1967. }
  1968. // "In front" of clip plane.
  1969. if ( nSides[iVert] == SIDE_FRONT )
  1970. {
  1971. pFront->m_aPrimVerts.AddToTail( pFragment->m_aPrimVerts[iVert] );
  1972. }
  1973. if ( nSides[iVert+1] == SIDE_ON || nSides[iVert+1] == nSides[iVert] )
  1974. continue;
  1975. // Split!
  1976. float fraction = flDists[iVert] / ( flDists[iVert] - flDists[iVert+1] );
  1977. overlayvert_t vert;
  1978. vert.pos = pFragment->m_aPrimVerts[iVert].pos + fraction * ( pFragment->m_aPrimVerts[(iVert+1)%nVertCount].pos -
  1979. pFragment->m_aPrimVerts[iVert].pos );
  1980. for ( int iTexCoord=0; iTexCoord < NUM_OVERLAY_TEXCOORDS; iTexCoord++ )
  1981. {
  1982. vert.texCoord[iTexCoord][0] = pFragment->m_aPrimVerts[iVert].texCoord[iTexCoord][0] + fraction * ( pFragment->m_aPrimVerts[(iVert+1)%nVertCount].texCoord[iTexCoord][0] -
  1983. pFragment->m_aPrimVerts[iVert].texCoord[iTexCoord][0] );
  1984. vert.texCoord[iTexCoord][1] = pFragment->m_aPrimVerts[iVert].texCoord[iTexCoord][1] + fraction * ( pFragment->m_aPrimVerts[(iVert+1)%nVertCount].texCoord[iTexCoord][1] -
  1985. pFragment->m_aPrimVerts[iVert].texCoord[iTexCoord][1] );
  1986. }
  1987. pFront->m_aPrimVerts.AddToTail( vert );
  1988. pBack->m_aPrimVerts.AddToTail( vert );
  1989. }
  1990. *ppFront = pFront;
  1991. *ppBack = pBack;
  1992. }
  1993. //-----------------------------------------------------------------------------
  1994. // Copies a fragment into the main fragment list
  1995. //-----------------------------------------------------------------------------
  1996. OverlayFragmentHandle_t COverlayMgr::AddFragmentToFragmentList( int nSize )
  1997. {
  1998. MEM_ALLOC_CREDIT();
  1999. // Add to list of fragments.
  2000. int iFragment = m_aFragments.Alloc( true );
  2001. moverlayfragment_t &frag = m_aFragments[iFragment];
  2002. frag.m_SurfId = SURFACE_HANDLE_INVALID;
  2003. frag.m_iOverlay = -1;
  2004. frag.m_nRenderFrameID = -1;
  2005. frag.m_nMaterialSortID = 0xFFFF;
  2006. frag.m_hNextRender = OVERLAY_FRAGMENT_INVALID;
  2007. if ( nSize > 0 )
  2008. {
  2009. frag.m_aPrimVerts.SetSize( nSize );
  2010. }
  2011. return iFragment;
  2012. }
  2013. //-----------------------------------------------------------------------------
  2014. // Copies a fragment into the main fragment list
  2015. //-----------------------------------------------------------------------------
  2016. OverlayFragmentHandle_t COverlayMgr::AddFragmentToFragmentList( moverlayfragment_t *pSrc )
  2017. {
  2018. MEM_ALLOC_CREDIT();
  2019. // Add to list of fragments.
  2020. int iFragment = m_aFragments.Alloc( true );
  2021. moverlayfragment_t &frag = m_aFragments[iFragment];
  2022. frag.m_SurfId = pSrc->m_SurfId;
  2023. frag.m_iOverlay = pSrc->m_iOverlay;
  2024. frag.decalOffset = pSrc->decalOffset;
  2025. frag.m_aPrimVerts.CopyArray( pSrc->m_aPrimVerts.Base(), pSrc->m_aPrimVerts.Count() );
  2026. return iFragment;
  2027. }
  2028. //-----------------------------------------------------------------------------
  2029. // Temp fragments for clipping algorithms
  2030. //-----------------------------------------------------------------------------
  2031. moverlayfragment_t *COverlayMgr::CreateTempFragment( int nSize )
  2032. {
  2033. MEM_ALLOC_CREDIT();
  2034. moverlayfragment_t *pDst = new moverlayfragment_t;
  2035. if ( pDst )
  2036. {
  2037. pDst->m_SurfId = SURFACE_HANDLE_INVALID;
  2038. pDst->m_iOverlay = -1;
  2039. if ( nSize > 0 )
  2040. {
  2041. pDst->m_aPrimVerts.SetSize( nSize );
  2042. }
  2043. }
  2044. return pDst;
  2045. }
  2046. //-----------------------------------------------------------------------------
  2047. // Temp fragments for clipping algorithms
  2048. //-----------------------------------------------------------------------------
  2049. moverlayfragment_t *COverlayMgr::CopyTempFragment( moverlayfragment_t *pSrc )
  2050. {
  2051. MEM_ALLOC_CREDIT();
  2052. moverlayfragment_t *pDst = new moverlayfragment_t;
  2053. if ( pDst )
  2054. {
  2055. pDst->m_SurfId = pSrc->m_SurfId;
  2056. pDst->m_iOverlay = pSrc->m_iOverlay;
  2057. pDst->m_aPrimVerts.CopyArray( pSrc->m_aPrimVerts.Base(), pSrc->m_aPrimVerts.Count() );
  2058. }
  2059. return pDst;
  2060. }
  2061. //-----------------------------------------------------------------------------
  2062. // Temp fragments for clipping algorithms
  2063. //-----------------------------------------------------------------------------
  2064. void COverlayMgr::DestroyTempFragment( moverlayfragment_t *pFragment )
  2065. {
  2066. if ( pFragment )
  2067. {
  2068. delete pFragment;
  2069. }
  2070. }
  2071. //-----------------------------------------------------------------------------
  2072. //-----------------------------------------------------------------------------
  2073. void COverlayMgr::BuildClipPlanes( SurfaceHandle_t surfID, moverlayfragment_t &surfaceFrag,
  2074. const Vector &vecBasisNormal,
  2075. CUtlVector<cplane_t> &m_ClipPlanes )
  2076. {
  2077. int nVertCount = surfaceFrag.m_aPrimVerts.Count();
  2078. for ( int iVert = 0; iVert < nVertCount; ++iVert )
  2079. {
  2080. Vector vecEdge;
  2081. vecEdge = surfaceFrag.m_aPrimVerts[(iVert+1)%nVertCount].pos - surfaceFrag.m_aPrimVerts[iVert].pos;
  2082. VectorNormalize( vecEdge );
  2083. int iPlane = m_ClipPlanes.AddToTail();
  2084. cplane_t *pPlane = &m_ClipPlanes[iPlane];
  2085. pPlane->normal = vecBasisNormal.Cross( vecEdge );
  2086. pPlane->dist = pPlane->normal.Dot( surfaceFrag.m_aPrimVerts[iVert].pos );
  2087. pPlane->type = 3;
  2088. // Check normal facing.
  2089. float flDistance = pPlane->normal.Dot( surfaceFrag.m_aPrimVerts[(iVert+2)%nVertCount].pos ) - pPlane->dist;
  2090. if ( flDistance > 0.0 )
  2091. {
  2092. // Flip
  2093. pPlane->normal.Negate();
  2094. pPlane->dist = -pPlane->dist;
  2095. }
  2096. }
  2097. }
  2098. //=============================================================================
  2099. //
  2100. // Code below this line will get moved out into common code!!!!!!!!!!!!!
  2101. //
  2102. //-----------------------------------------------------------------------------
  2103. // Purpose:
  2104. //-----------------------------------------------------------------------------
  2105. void Overlay_BuildBasisOrigin( Vector &vecBasisOrigin, SurfaceHandle_t surfID )
  2106. {
  2107. cplane_t surfacePlane = MSurf_Plane( surfID );
  2108. VectorNormalize( surfacePlane.normal );
  2109. // Get the distance from entity origin to face plane.
  2110. float flDist = surfacePlane.normal.Dot( vecBasisOrigin ) - surfacePlane.dist;
  2111. // Move the basis origin to the position of the entity projected into the face plane.
  2112. vecBasisOrigin = vecBasisOrigin - ( flDist * surfacePlane.normal );
  2113. }
  2114. //-----------------------------------------------------------------------------
  2115. //-----------------------------------------------------------------------------
  2116. bool Overlay_IsBasisFlipped( int *pFlip, int iAxis, int iComponent )
  2117. {
  2118. if ( iAxis < 0 || iAxis > 2 || iComponent < 0 || iComponent > 2 )
  2119. return false;
  2120. int nValue = ( 1 << iComponent );
  2121. return ( ( pFlip[iAxis] & nValue ) != 0 );
  2122. }
  2123. //-----------------------------------------------------------------------------
  2124. // Purpose:
  2125. //-----------------------------------------------------------------------------
  2126. void Overlay_BuildBasis( const Vector &vecBasisNormal, Vector &vecBasisU, Vector &vecBasisV, bool bFlip )
  2127. {
  2128. // Verify incoming data.
  2129. Assert( vecBasisNormal.IsValid() );
  2130. if ( !vecBasisNormal.IsValid() )
  2131. return;
  2132. vecBasisV = vecBasisNormal.Cross( vecBasisU );
  2133. if ( bFlip )
  2134. {
  2135. vecBasisV.Negate();
  2136. }
  2137. }
  2138. //-----------------------------------------------------------------------------
  2139. // Purpose:
  2140. //-----------------------------------------------------------------------------
  2141. void Overlay_TriTLToBR(
  2142. CDispInfo *pDisp,
  2143. CMeshReader *pReader,
  2144. Vector &vecWorld,
  2145. Vector &vecWorldNormal,
  2146. float flU,
  2147. float flV,
  2148. int nWidth,
  2149. const Vector &vecIntersectPoint )
  2150. {
  2151. const float TRIEDGE_EPSILON = 0.000001f;
  2152. int nHeight = nWidth;
  2153. int nSnapU = static_cast<int>( flU );
  2154. int nSnapV = static_cast<int>( flV );
  2155. int nNextU = nSnapU + 1;
  2156. int nNextV = nSnapV + 1;
  2157. if ( nNextU == nWidth) { --nNextU; }
  2158. if ( nNextV == nHeight ) { --nNextV; }
  2159. float flFracU = flU - static_cast<float>( nSnapU );
  2160. float flFracV = flV - static_cast<float>( nSnapV );
  2161. Vector vecVerts[3], vecFlatVerts[3], vecNormals[3];
  2162. if( ( flFracU + flFracV ) >= ( 1.0f + TRIEDGE_EPSILON ) )
  2163. {
  2164. int nIndices[3];
  2165. nIndices[0] = nNextV * nWidth + nSnapU;
  2166. nIndices[1] = nNextV * nWidth + nNextU;
  2167. nIndices[2] = nSnapV * nWidth + nNextU;
  2168. for( int iVert = 0; iVert < 3; ++iVert )
  2169. {
  2170. vecVerts[iVert] = GetOverlayPos( pReader, nIndices[iVert] );
  2171. vecFlatVerts[iVert] = pDisp->GetFlatVert( nIndices[iVert] );
  2172. pReader->Normal( nIndices[iVert], vecNormals[iVert] );
  2173. }
  2174. if ( nSnapU == nNextU )
  2175. {
  2176. if ( nSnapV == nNextV )
  2177. {
  2178. vecWorld = vecVerts[0];
  2179. vecWorldNormal = vecNormals[0];
  2180. }
  2181. else
  2182. {
  2183. float flFrac = ( vecIntersectPoint - vecFlatVerts[0] ).Length() / ( vecFlatVerts[2] - vecFlatVerts[0] ).Length();
  2184. vecWorld = vecVerts[0] + ( flFrac * ( vecVerts[2] - vecVerts[0] ) );
  2185. vecWorldNormal = vecNormals[0] + ( flFrac * ( vecNormals[2] - vecNormals[0] ) );
  2186. }
  2187. }
  2188. else if ( nSnapV == nNextV )
  2189. {
  2190. if ( nSnapU == nNextU )
  2191. {
  2192. vecWorld = vecVerts[0];
  2193. vecWorldNormal = vecNormals[0];
  2194. }
  2195. else
  2196. {
  2197. float flFrac = ( vecIntersectPoint - vecFlatVerts[0] ).Length() / ( vecFlatVerts[2] - vecFlatVerts[0] ).Length();
  2198. vecWorld = vecVerts[0] + ( flFrac * ( vecVerts[2] - vecVerts[0] ) );
  2199. vecWorldNormal = vecNormals[0] + ( flFrac * ( vecNormals[2] - vecNormals[0] ) );
  2200. }
  2201. }
  2202. else
  2203. {
  2204. float flCfs[3];
  2205. if ( CalcBarycentricCooefs( vecFlatVerts[0], vecFlatVerts[1], vecFlatVerts[2], vecIntersectPoint, flCfs[0], flCfs[1], flCfs[2] ) )
  2206. {
  2207. vecWorld = ( vecVerts[0] * flCfs[0] ) + ( vecVerts[1] * flCfs[1] ) + ( vecVerts[2] * flCfs[2] );
  2208. vecWorldNormal = ( vecNormals[0] * flCfs[0] ) + ( vecNormals[1] * flCfs[1] ) + ( vecNormals[2] * flCfs[2] );
  2209. }
  2210. else
  2211. {
  2212. int nIndices[3];
  2213. nIndices[0] = nSnapV * nWidth + nSnapU;
  2214. nIndices[1] = nNextV * nWidth + nSnapU;
  2215. nIndices[2] = nSnapV * nWidth + nNextU;
  2216. for( int iVert = 0; iVert < 3; ++iVert )
  2217. {
  2218. vecVerts[iVert] = GetOverlayPos( pReader, nIndices[iVert] );
  2219. vecFlatVerts[iVert] = pDisp->GetFlatVert( nIndices[iVert] );
  2220. pReader->Normal( nIndices[iVert], vecNormals[iVert] );
  2221. }
  2222. if ( nSnapU == nNextU )
  2223. {
  2224. if ( nSnapV == nNextV )
  2225. {
  2226. vecWorld = vecVerts[0];
  2227. vecWorldNormal = vecNormals[0];
  2228. }
  2229. else
  2230. {
  2231. float flFrac = ( vecIntersectPoint - vecFlatVerts[0] ).Length() / ( vecFlatVerts[1] - vecFlatVerts[0] ).Length();
  2232. vecWorld = vecVerts[0] + ( flFrac * ( vecVerts[1] - vecVerts[0] ) );
  2233. vecWorldNormal = vecNormals[0] + ( flFrac * ( vecNormals[1] - vecNormals[0] ) );
  2234. }
  2235. }
  2236. else if ( nSnapV == nNextV )
  2237. {
  2238. if ( nSnapU == nNextU )
  2239. {
  2240. vecWorld = vecVerts[0];
  2241. vecWorldNormal = vecNormals[0];
  2242. }
  2243. else
  2244. {
  2245. float flFrac = ( vecIntersectPoint - vecFlatVerts[0] ).Length() / ( vecFlatVerts[2] - vecFlatVerts[0] ).Length();
  2246. vecWorld = vecVerts[0] + ( flFrac * ( vecVerts[2] - vecVerts[0] ) );
  2247. vecWorldNormal = vecNormals[0] + ( flFrac * ( vecNormals[2] - vecNormals[0] ) );
  2248. }
  2249. }
  2250. else
  2251. {
  2252. float flCfs[3];
  2253. CalcBarycentricCooefs( vecFlatVerts[0], vecFlatVerts[1], vecFlatVerts[2], vecIntersectPoint, flCfs[0], flCfs[1], flCfs[2] );
  2254. vecWorld = ( vecVerts[0] * flCfs[0] ) + ( vecVerts[1] * flCfs[1] ) + ( vecVerts[2] * flCfs[2] );
  2255. vecWorldNormal = ( vecNormals[0] * flCfs[0] ) + ( vecNormals[1] * flCfs[1] ) + ( vecNormals[2] * flCfs[2] );
  2256. }
  2257. }
  2258. }
  2259. }
  2260. else
  2261. {
  2262. int nIndices[3];
  2263. nIndices[0] = nSnapV * nWidth + nSnapU;
  2264. nIndices[1] = nNextV * nWidth + nSnapU;
  2265. nIndices[2] = nSnapV * nWidth + nNextU;
  2266. for( int iVert = 0; iVert < 3; ++iVert )
  2267. {
  2268. vecVerts[iVert] = GetOverlayPos( pReader, nIndices[iVert] );
  2269. vecFlatVerts[iVert] = pDisp->GetFlatVert( nIndices[iVert] );
  2270. pReader->Normal( nIndices[iVert], vecNormals[iVert] );
  2271. }
  2272. if ( nSnapU == nNextU )
  2273. {
  2274. if ( nSnapV == nNextV )
  2275. {
  2276. vecWorld = vecVerts[0];
  2277. vecWorldNormal = vecNormals[0];
  2278. }
  2279. else
  2280. {
  2281. float flFrac = ( vecIntersectPoint - vecFlatVerts[0] ).Length() / ( vecFlatVerts[1] - vecFlatVerts[0] ).Length();
  2282. vecWorld = vecVerts[0] + ( flFrac * ( vecVerts[1] - vecVerts[0] ) );
  2283. vecWorldNormal = vecNormals[0] + ( flFrac * ( vecNormals[1] - vecNormals[0] ) );
  2284. }
  2285. }
  2286. else if ( nSnapV == nNextV )
  2287. {
  2288. if ( nSnapU == nNextU )
  2289. {
  2290. vecWorld = vecVerts[0];
  2291. vecWorldNormal = vecNormals[0];
  2292. }
  2293. else
  2294. {
  2295. float flFrac = ( vecIntersectPoint - vecFlatVerts[0] ).Length() / ( vecFlatVerts[2] - vecFlatVerts[0] ).Length();
  2296. vecWorld = vecVerts[0] + ( flFrac * ( vecVerts[2] - vecVerts[0] ) );
  2297. vecWorldNormal = vecNormals[0] + ( flFrac * ( vecNormals[2] - vecNormals[0] ) );
  2298. }
  2299. }
  2300. else
  2301. {
  2302. float flCfs[3];
  2303. if ( CalcBarycentricCooefs( vecFlatVerts[0], vecFlatVerts[1], vecFlatVerts[2], vecIntersectPoint, flCfs[0], flCfs[1], flCfs[2] ) )
  2304. {
  2305. vecWorld = ( vecVerts[0] * flCfs[0] ) + ( vecVerts[1] * flCfs[1] ) + ( vecVerts[2] * flCfs[2] );
  2306. vecWorldNormal = ( vecNormals[0] * flCfs[0] ) + ( vecNormals[1] * flCfs[1] ) + ( vecNormals[2] * flCfs[2] );
  2307. }
  2308. else
  2309. {
  2310. int nIndices[3];
  2311. nIndices[0] = nNextV * nWidth + nSnapU;
  2312. nIndices[1] = nNextV * nWidth + nNextU;
  2313. nIndices[2] = nSnapV * nWidth + nNextU;
  2314. for( int iVert = 0; iVert < 3; ++iVert )
  2315. {
  2316. vecVerts[iVert] = GetOverlayPos( pReader, nIndices[iVert] );
  2317. vecFlatVerts[iVert] = pDisp->GetFlatVert( nIndices[iVert] );
  2318. pReader->Normal( nIndices[iVert], vecNormals[iVert] );
  2319. }
  2320. if ( nSnapU == nNextU )
  2321. {
  2322. if ( nSnapV == nNextV )
  2323. {
  2324. vecWorld = vecVerts[0];
  2325. vecWorldNormal = vecNormals[0];
  2326. }
  2327. else
  2328. {
  2329. float flFrac = ( vecIntersectPoint - vecFlatVerts[0] ).Length() / ( vecFlatVerts[2] - vecFlatVerts[0] ).Length();
  2330. vecWorld = vecVerts[0] + ( flFrac * ( vecVerts[2] - vecVerts[0] ) );
  2331. vecWorldNormal = vecNormals[0] + ( flFrac * ( vecNormals[2] - vecNormals[0] ) );
  2332. }
  2333. }
  2334. else if ( nSnapV == nNextV )
  2335. {
  2336. if ( nSnapU == nNextU )
  2337. {
  2338. vecWorld = vecVerts[0];
  2339. vecWorldNormal = vecNormals[0];
  2340. }
  2341. else
  2342. {
  2343. float flFrac = ( vecIntersectPoint - vecFlatVerts[0] ).Length() / ( vecFlatVerts[2] - vecFlatVerts[0] ).Length();
  2344. vecWorld = vecVerts[0] + ( flFrac * ( vecVerts[2] - vecVerts[0] ) );
  2345. vecWorldNormal = vecNormals[0] + ( flFrac * ( vecNormals[2] - vecNormals[0] ) );
  2346. }
  2347. }
  2348. else
  2349. {
  2350. float flCfs[3];
  2351. CalcBarycentricCooefs( vecFlatVerts[0], vecFlatVerts[1], vecFlatVerts[2], vecIntersectPoint, flCfs[0], flCfs[1], flCfs[2] );
  2352. vecWorld = ( vecVerts[0] * flCfs[0] ) + ( vecVerts[1] * flCfs[1] ) + ( vecVerts[2] * flCfs[2] );
  2353. vecWorldNormal = ( vecNormals[0] * flCfs[0] ) + ( vecNormals[1] * flCfs[1] ) + ( vecNormals[2] * flCfs[2] );
  2354. }
  2355. }
  2356. }
  2357. }
  2358. vecWorldNormal.NormalizeInPlace();
  2359. }
  2360. //-----------------------------------------------------------------------------
  2361. // Purpose:
  2362. //-----------------------------------------------------------------------------
  2363. void Overlay_TriBLToTR(
  2364. CDispInfo *pDisp,
  2365. CMeshReader *pReader,
  2366. Vector &vecWorld,
  2367. Vector &vecWorldNormal,
  2368. float flU,
  2369. float flV,
  2370. int nWidth,
  2371. const Vector &vecIntersectPoint )
  2372. {
  2373. int nHeight = nWidth;
  2374. int nSnapU = static_cast<int>( flU );
  2375. int nSnapV = static_cast<int>( flV );
  2376. int nNextU = nSnapU + 1;
  2377. int nNextV = nSnapV + 1;
  2378. if ( nNextU == nWidth) { --nNextU; }
  2379. if ( nNextV == nHeight ) { --nNextV; }
  2380. float flFracU = flU - static_cast<float>( nSnapU );
  2381. float flFracV = flV - static_cast<float>( nSnapV );
  2382. // The fractions are not correct all the time - but they are a good first guess!
  2383. Vector vecVerts[3], vecFlatVerts[3], vecNormals[3];
  2384. if( flFracU < flFracV )
  2385. {
  2386. int nIndices[3];
  2387. nIndices[0] = nSnapV * nWidth + nSnapU;
  2388. nIndices[1] = nNextV * nWidth + nSnapU;
  2389. nIndices[2] = nNextV * nWidth + nNextU;
  2390. for( int iVert = 0; iVert < 3; ++iVert )
  2391. {
  2392. vecVerts[iVert] = GetOverlayPos( pReader, nIndices[iVert] );
  2393. vecFlatVerts[iVert] = pDisp->GetFlatVert( nIndices[iVert] );
  2394. pReader->Normal( nIndices[iVert], vecNormals[iVert] );
  2395. }
  2396. if ( nSnapU == nNextU )
  2397. {
  2398. if ( nSnapV == nNextV )
  2399. {
  2400. vecWorld = vecVerts[0];
  2401. vecWorldNormal = vecNormals[0];
  2402. }
  2403. else
  2404. {
  2405. float flFrac = ( vecIntersectPoint - vecFlatVerts[0] ).Length() / ( vecFlatVerts[2] - vecFlatVerts[0] ).Length();
  2406. vecWorld = vecVerts[0] + ( flFrac * ( vecVerts[2] - vecVerts[0] ) );
  2407. vecWorldNormal = vecNormals[0] + ( flFrac * ( vecNormals[2] - vecNormals[0] ) );
  2408. }
  2409. }
  2410. else if ( nSnapV == nNextV )
  2411. {
  2412. if ( nSnapU == nNextU )
  2413. {
  2414. vecWorld = vecVerts[0];
  2415. vecWorldNormal = vecNormals[0];
  2416. }
  2417. else
  2418. {
  2419. float flFrac = ( vecIntersectPoint - vecFlatVerts[0] ).Length() / ( vecFlatVerts[2] - vecFlatVerts[0] ).Length();
  2420. vecWorld = vecVerts[0] + ( flFrac * ( vecVerts[2] - vecVerts[0] ) );
  2421. vecWorldNormal = vecNormals[0] + ( flFrac * ( vecNormals[2] - vecNormals[0] ) );
  2422. }
  2423. }
  2424. else
  2425. {
  2426. float flCfs[3];
  2427. if ( CalcBarycentricCooefs( vecFlatVerts[0], vecFlatVerts[1], vecFlatVerts[2], vecIntersectPoint, flCfs[0], flCfs[1], flCfs[2] ) )
  2428. {
  2429. vecWorld = ( vecVerts[0] * flCfs[0] ) + ( vecVerts[1] * flCfs[1] ) + ( vecVerts[2] * flCfs[2] );
  2430. vecWorldNormal = ( vecNormals[0] * flCfs[0] ) + ( vecNormals[1] * flCfs[1] ) + ( vecNormals[2] * flCfs[2] );
  2431. }
  2432. else
  2433. {
  2434. int nIndices[3];
  2435. nIndices[0] = nSnapV * nWidth + nSnapU;
  2436. nIndices[1] = nNextV * nWidth + nNextU;
  2437. nIndices[2] = nSnapV * nWidth + nNextU;
  2438. for( int iVert = 0; iVert < 3; ++iVert )
  2439. {
  2440. vecVerts[iVert] = GetOverlayPos( pReader, nIndices[iVert] );
  2441. vecFlatVerts[iVert] = pDisp->GetFlatVert( nIndices[iVert] );
  2442. pReader->Normal( nIndices[iVert], vecNormals[iVert] );
  2443. }
  2444. if ( nSnapU == nNextU )
  2445. {
  2446. if ( nSnapV == nNextV )
  2447. {
  2448. vecWorld = vecVerts[0];
  2449. vecWorldNormal = vecNormals[0];
  2450. }
  2451. else
  2452. {
  2453. float flFrac = ( vecIntersectPoint - vecFlatVerts[0] ).Length() / ( vecFlatVerts[1] - vecFlatVerts[0] ).Length();
  2454. vecWorld = vecVerts[0] + ( flFrac * ( vecVerts[1] - vecVerts[0] ) );
  2455. vecWorldNormal = vecNormals[0] + ( flFrac * ( vecNormals[1] - vecNormals[0] ) );
  2456. }
  2457. }
  2458. else if ( nSnapV == nNextV )
  2459. {
  2460. if ( nSnapU == nNextU )
  2461. {
  2462. vecWorld = vecVerts[0];
  2463. vecWorldNormal = vecNormals[0];
  2464. }
  2465. else
  2466. {
  2467. float flFrac = ( vecIntersectPoint - vecFlatVerts[0] ).Length() / ( vecFlatVerts[2] - vecFlatVerts[0] ).Length();
  2468. vecWorld = vecVerts[0] + ( flFrac * ( vecVerts[2] - vecVerts[0] ) );
  2469. vecWorldNormal = vecNormals[0] + ( flFrac * ( vecNormals[2] - vecNormals[0] ) );
  2470. }
  2471. }
  2472. else
  2473. {
  2474. float flCfs[3];
  2475. CalcBarycentricCooefs( vecFlatVerts[0], vecFlatVerts[1], vecFlatVerts[2], vecIntersectPoint, flCfs[0], flCfs[1], flCfs[2] );
  2476. vecWorld = ( vecVerts[0] * flCfs[0] ) + ( vecVerts[1] * flCfs[1] ) + ( vecVerts[2] * flCfs[2] );
  2477. vecWorldNormal = ( vecNormals[0] * flCfs[0] ) + ( vecNormals[1] * flCfs[1] ) + ( vecNormals[2] * flCfs[2] );
  2478. }
  2479. }
  2480. }
  2481. }
  2482. else
  2483. {
  2484. int nIndices[3];
  2485. nIndices[0] = nSnapV * nWidth + nSnapU;
  2486. nIndices[1] = nNextV * nWidth + nNextU;
  2487. nIndices[2] = nSnapV * nWidth + nNextU;
  2488. for( int iVert = 0; iVert < 3; ++iVert )
  2489. {
  2490. vecVerts[iVert] = GetOverlayPos( pReader, nIndices[iVert] );
  2491. vecFlatVerts[iVert] = pDisp->GetFlatVert( nIndices[iVert] );
  2492. pReader->Normal( nIndices[iVert], vecNormals[iVert] );
  2493. }
  2494. if ( nSnapU == nNextU )
  2495. {
  2496. if ( nSnapV == nNextV )
  2497. {
  2498. vecWorld = vecVerts[0];
  2499. vecWorldNormal = vecNormals[0];
  2500. }
  2501. else
  2502. {
  2503. float flFrac = ( vecIntersectPoint - vecFlatVerts[0] ).Length() / ( vecFlatVerts[1] - vecFlatVerts[0] ).Length();
  2504. vecWorld = vecVerts[0] + ( flFrac * ( vecVerts[1] - vecVerts[0] ) );
  2505. vecWorldNormal = vecNormals[0] + ( flFrac * ( vecNormals[1] - vecNormals[0] ) );
  2506. }
  2507. }
  2508. else if ( nSnapV == nNextV )
  2509. {
  2510. if ( nSnapU == nNextU )
  2511. {
  2512. vecWorld = vecVerts[0];
  2513. vecWorldNormal = vecNormals[0];
  2514. }
  2515. else
  2516. {
  2517. float flFrac = ( vecIntersectPoint - vecFlatVerts[0] ).Length() / ( vecFlatVerts[2] - vecFlatVerts[0] ).Length();
  2518. vecWorld = vecVerts[0] + ( flFrac * ( vecVerts[2] - vecVerts[0] ) );
  2519. vecWorldNormal = vecNormals[0] + ( flFrac * ( vecNormals[2] - vecNormals[0] ) );
  2520. }
  2521. }
  2522. else
  2523. {
  2524. float flCfs[3];
  2525. if ( CalcBarycentricCooefs( vecFlatVerts[0], vecFlatVerts[1], vecFlatVerts[2], vecIntersectPoint, flCfs[0], flCfs[1], flCfs[2] ) )
  2526. {
  2527. vecWorld = ( vecVerts[0] * flCfs[0] ) + ( vecVerts[1] * flCfs[1] ) + ( vecVerts[2] * flCfs[2] );
  2528. vecWorldNormal = ( vecNormals[0] * flCfs[0] ) + ( vecNormals[1] * flCfs[1] ) + ( vecNormals[2] * flCfs[2] );
  2529. }
  2530. else
  2531. {
  2532. int nIndices[3];
  2533. nIndices[0] = nSnapV * nWidth + nSnapU;
  2534. nIndices[1] = nNextV * nWidth + nSnapU;
  2535. nIndices[2] = nNextV * nWidth + nNextU;
  2536. for( int iVert = 0; iVert < 3; ++iVert )
  2537. {
  2538. vecVerts[iVert] = GetOverlayPos( pReader, nIndices[iVert] );
  2539. vecFlatVerts[iVert] = pDisp->GetFlatVert( nIndices[iVert] );
  2540. pReader->Normal( nIndices[iVert], vecNormals[iVert] );
  2541. }
  2542. if ( nSnapU == nNextU )
  2543. {
  2544. if ( nSnapV == nNextV )
  2545. {
  2546. vecWorld = vecVerts[0];
  2547. vecWorldNormal = vecNormals[0];
  2548. }
  2549. else
  2550. {
  2551. float flFrac = ( vecIntersectPoint - vecFlatVerts[0] ).Length() / ( vecFlatVerts[2] - vecFlatVerts[0] ).Length();
  2552. vecWorld = vecVerts[0] + ( flFrac * ( vecVerts[2] - vecVerts[0] ) );
  2553. vecWorldNormal = vecNormals[0] + ( flFrac * ( vecNormals[2] - vecNormals[0] ) );
  2554. }
  2555. }
  2556. else if ( nSnapV == nNextV )
  2557. {
  2558. if ( nSnapU == nNextU )
  2559. {
  2560. vecWorld = vecVerts[0];
  2561. vecWorldNormal = vecNormals[0];
  2562. }
  2563. else
  2564. {
  2565. float flFrac = ( vecIntersectPoint - vecFlatVerts[0] ).Length() / ( vecFlatVerts[2] - vecFlatVerts[0] ).Length();
  2566. vecWorld = vecVerts[0] + ( flFrac * ( vecVerts[2] - vecVerts[0] ) );
  2567. vecWorldNormal = vecNormals[0] + ( flFrac * ( vecNormals[2] - vecNormals[0] ) );
  2568. }
  2569. }
  2570. else
  2571. {
  2572. float flCfs[3];
  2573. CalcBarycentricCooefs( vecFlatVerts[0], vecFlatVerts[1], vecFlatVerts[2], vecIntersectPoint, flCfs[0], flCfs[1], flCfs[2] );
  2574. vecWorld = ( vecVerts[0] * flCfs[0] ) + ( vecVerts[1] * flCfs[1] ) + ( vecVerts[2] * flCfs[2] );
  2575. vecWorldNormal = ( vecNormals[0] * flCfs[0] ) + ( vecNormals[1] * flCfs[1] ) + ( vecNormals[2] * flCfs[2] );
  2576. }
  2577. }
  2578. }
  2579. }
  2580. vecWorldNormal.NormalizeInPlace();
  2581. }
  2582. //-----------------------------------------------------------------------------
  2583. // Purpose:
  2584. //-----------------------------------------------------------------------------
  2585. void Overlay_DispUVToWorld( CDispInfo *pDisp, CMeshReader *pReader, const Vector2D &vecUV, Vector &vecWorld, Vector &vecWorldNormal, moverlayfragment_t &surfaceFrag )
  2586. {
  2587. // Get the displacement power.
  2588. const CPowerInfo *pPowerInfo = pDisp->GetPowerInfo();
  2589. int nWidth = ( ( 1 << pPowerInfo->GetPower() ) + 1 );
  2590. int nHeight = nWidth;
  2591. Vector vecIntersectPoint;
  2592. PointInQuadFromBarycentric( surfaceFrag.m_aPrimVerts[(0+pDisp->m_iPointStart)%4].pos,
  2593. surfaceFrag.m_aPrimVerts[(3+pDisp->m_iPointStart)%4].pos,
  2594. surfaceFrag.m_aPrimVerts[(2+pDisp->m_iPointStart)%4].pos,
  2595. surfaceFrag.m_aPrimVerts[(1+pDisp->m_iPointStart)%4].pos,
  2596. vecUV, vecIntersectPoint );
  2597. // Scale the U, V coordinates to the displacement grid size.
  2598. float flU = vecUV.x * static_cast<float>( nWidth - 1.000001f );
  2599. float flV = vecUV.y * static_cast<float>( nHeight - 1.000001f );
  2600. // Find the base U, V.
  2601. int nSnapU = static_cast<int>( flU );
  2602. int nSnapV = static_cast<int>( flV );
  2603. // Use this to get the triangle orientation.
  2604. bool bOdd = ( ( ( nSnapV * nWidth ) + nSnapU ) % 2 == 1 );
  2605. // Top Left to Bottom Right
  2606. if( bOdd )
  2607. {
  2608. Overlay_TriTLToBR( pDisp, pReader, vecWorld, vecWorldNormal, flU, flV, nWidth, vecIntersectPoint );
  2609. }
  2610. // Bottom Left to Top Right
  2611. else
  2612. {
  2613. Overlay_TriBLToTR( pDisp, pReader, vecWorld, vecWorldNormal, flU, flV, nWidth, vecIntersectPoint );
  2614. }
  2615. }
  2616. //-----------------------------------------------------------------------------
  2617. //-----------------------------------------------------------------------------
  2618. void Overlay_OverlayUVToOverlayPlane( const Vector &vecBasisOrigin, const Vector &vecBasisU,
  2619. const Vector &vecBasisV, const Vector &vecUVPoint,
  2620. Vector &vecPlanePoint )
  2621. {
  2622. vecPlanePoint = ( vecUVPoint.x * vecBasisU ) + ( vecUVPoint.y * vecBasisV );
  2623. vecPlanePoint += vecBasisOrigin;
  2624. }
  2625. //-----------------------------------------------------------------------------
  2626. //-----------------------------------------------------------------------------
  2627. void Overlay_WorldToOverlayPlane( const Vector &vecBasisOrigin, const Vector &vecBasisNormal,
  2628. const Vector &vecWorldPoint, Vector &vecPlanePoint )
  2629. {
  2630. Vector vecDelta = vecWorldPoint - vecBasisOrigin;
  2631. float flDistance = vecBasisNormal.Dot( vecDelta );
  2632. vecPlanePoint = vecWorldPoint - ( flDistance * vecBasisNormal );
  2633. }
  2634. //-----------------------------------------------------------------------------
  2635. //-----------------------------------------------------------------------------
  2636. void Overlay_OverlayPlaneToWorld( const Vector &vecBasisNormal, SurfaceHandle_t surfID,
  2637. const Vector &vecPlanePoint, Vector &vecWorldPoint )
  2638. {
  2639. cplane_t surfacePlane = MSurf_Plane( surfID );
  2640. VectorNormalize( surfacePlane.normal );
  2641. float flDistanceToSurface = surfacePlane.normal.Dot( vecPlanePoint ) - surfacePlane.dist;
  2642. float flDenom = surfacePlane.normal.Dot( vecBasisNormal );
  2643. float flDistance;
  2644. if( flDenom != 0.0f )
  2645. {
  2646. flDistance = ( 1.0f / flDenom ) * flDistanceToSurface;
  2647. }
  2648. else
  2649. {
  2650. flDistance = flDistanceToSurface;
  2651. }
  2652. vecWorldPoint = vecPlanePoint - ( vecBasisNormal * flDistance );
  2653. }