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.

1461 lines
44 KiB

  1. //========= Copyright � 1996-2007, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=====================================================================================//
  7. #include "render_pch.h"
  8. #include "decal_private.h"
  9. #include "disp_defs.h"
  10. #include "disp.h"
  11. #include "gl_model_private.h"
  12. #include "gl_matsysiface.h"
  13. #include "gl_cvars.h"
  14. #include "gl_rsurf.h"
  15. #include "gl_lightmap.h"
  16. #include "con_nprint.h"
  17. #include "surfinfo.h"
  18. #include "Overlay.h"
  19. #include "cl_main.h"
  20. #include "r_decal.h"
  21. #include "materialsystem/materialsystem_config.h"
  22. #include "debugoverlay.h"
  23. #include "paint.h"
  24. #include "tier0/vprof.h"
  25. // memdbgon must be the last include file in a .cpp file!!!
  26. #include "tier0/memdbgon.h"
  27. // ----------------------------------------------------------------------------- //
  28. // Shadow decals + fragments
  29. // ----------------------------------------------------------------------------- //
  30. static CUtlLinkedList< CDispShadowDecal, DispShadowHandle_t, true > s_DispShadowDecals;
  31. static CUtlLinkedList< CDispShadowFragment, DispShadowFragmentHandle_t, true > s_DispShadowFragments;
  32. static CUtlLinkedList< CDispDecal, DispShadowHandle_t, true > s_DispDecals;
  33. static CUtlLinkedList< CDispDecalFragment, DispShadowFragmentHandle_t, true > s_DispDecalFragments;
  34. // This mutex protects the s_DispShadowFragments and s_DispShadowDecals list during in AllocateShadowFragment() during
  35. // threaded shadow clipping. It is NOT safe to Allocate and free shadow decal fragments from multiple threads.
  36. static CThreadFastMutex s_ShadowFragmentAllocLock;
  37. void CDispInfo::GetIntersectingSurfaces( GetIntersectingSurfaces_Struct *pStruct )
  38. {
  39. if ( !m_Verts.Count() || !m_nIndices )
  40. return;
  41. // Walk through all of our triangles and add them one by one.
  42. SurfInfo *pOut = &pStruct->m_pInfos[ pStruct->m_nSetInfos ];
  43. for ( int iVert=0; iVert < m_MeshReader.NumIndices(); iVert += 3 )
  44. {
  45. // Is the list going to overflow?
  46. if ( pStruct->m_nSetInfos >= pStruct->m_nMaxInfos )
  47. break;
  48. Vector const &a = m_MeshReader.Position( m_MeshReader.Index(iVert+0) - m_iVertOffset );
  49. Vector const &b = m_MeshReader.Position( m_MeshReader.Index(iVert+1) - m_iVertOffset );
  50. Vector const &c = m_MeshReader.Position( m_MeshReader.Index(iVert+2) - m_iVertOffset );
  51. // Get the boundaries.
  52. Vector vMin;
  53. VectorMin( a, b, vMin );
  54. VectorMin( c, vMin, vMin );
  55. Vector vMax;
  56. VectorMax( a, b, vMax );
  57. VectorMax( c, vMax, vMax );
  58. // See if it touches the sphere.
  59. int iDim;
  60. for ( iDim=0; iDim < 3; iDim++ )
  61. {
  62. if ( ((*pStruct->m_pCenter)[iDim]+pStruct->m_Radius) < vMin[iDim] ||
  63. ((*pStruct->m_pCenter)[iDim]-pStruct->m_Radius) > vMax[iDim] )
  64. {
  65. break;
  66. }
  67. }
  68. if ( iDim == 3 )
  69. {
  70. // Couldn't reject the sphere in the loop above, so add this surface.
  71. pOut->m_nVerts = 3;
  72. pOut->m_Verts[0] = a;
  73. pOut->m_Verts[1] = b;
  74. pOut->m_Verts[2] = c;
  75. pOut->m_Plane.m_Normal = ( c - a ).Cross( b - a );
  76. VectorNormalize( pOut->m_Plane.m_Normal );
  77. pOut->m_Plane.m_Dist = pOut->m_Plane.m_Normal.Dot( a );
  78. ++pStruct->m_nSetInfos;
  79. ++pOut;
  80. }
  81. }
  82. }
  83. // ----------------------------------------------------------------------------- //
  84. // CDispInfo implementation of IDispInfo.
  85. // ----------------------------------------------------------------------------- //
  86. void CDispInfo::RenderWireframeInLightmapPage( int pageId )
  87. {
  88. #ifndef DEDICATED
  89. // render displacement as wireframe into lightmap pages
  90. SurfaceHandle_t surfID = GetParent();
  91. Assert( ( MSurf_MaterialSortID( surfID ) >= 0 ) && ( MSurf_MaterialSortID( surfID ) < g_WorldStaticMeshes.Count() ) );
  92. if( materialSortInfoArray[MSurf_MaterialSortID( surfID ) ].lightmapPageID != pageId )
  93. return;
  94. Shader_DrawLightmapPageSurface( surfID, 0.0f, 0.0f, 1.0f );
  95. #endif
  96. }
  97. void CDispInfo::GetBoundingBox( Vector& bbMin, Vector& bbMax )
  98. {
  99. bbMin = m_BBoxMin;
  100. bbMax = m_BBoxMax;
  101. }
  102. void CDispInfo::SetParent( SurfaceHandle_t surfID )
  103. {
  104. m_ParentSurfID = surfID;
  105. }
  106. // returns surfID
  107. SurfaceHandle_t CDispInfo::GetParent( void )
  108. {
  109. return m_ParentSurfID;
  110. }
  111. unsigned int CDispInfo::ComputeDynamicLightMask( dlight_t *pLights )
  112. {
  113. int lightMask = 0;
  114. #ifndef DEDICATED
  115. if( !IS_SURF_VALID( m_ParentSurfID ) )
  116. {
  117. Assert( !"CDispInfo::ComputeDynamicLightMask: no parent surface" );
  118. return 0;
  119. }
  120. for ( int lnum = 0, testBit = 1, mask = r_dlightactive; lnum < MAX_DLIGHTS && mask != 0; lnum++, mask >>= 1, testBit <<= 1 )
  121. {
  122. if ( mask & 1 )
  123. {
  124. // not lit by this light
  125. if ( !(MSurf_DLightBits( m_ParentSurfID ) & testBit ) )
  126. continue;
  127. // This light doesn't affect the world
  128. if ( pLights[lnum].flags & DLIGHT_NO_WORLD_ILLUMINATION)
  129. continue;
  130. // This is used to ensure a maximum number of dlights in a frame
  131. if ( !R_CanUseVisibleDLight( lnum ) )
  132. continue;
  133. lightMask |= testBit;
  134. }
  135. }
  136. #endif
  137. return lightMask;
  138. }
  139. void CDispInfo::AddDynamicLights( dlight_t *pLights, unsigned int mask )
  140. {
  141. #ifndef DEDICATED
  142. if( !IS_SURF_VALID( m_ParentSurfID ) )
  143. {
  144. Assert( !"CDispInfo::AddDynamicLights: no parent surface" );
  145. return;
  146. }
  147. for ( int lnum = 0; lnum < MAX_DLIGHTS && mask != 0; lnum++, mask >>= 1 )
  148. {
  149. if ( mask & 1 )
  150. {
  151. if ( (pLights[lnum].flags & DLIGHT_DISPLACEMENT_MASK) == 0)
  152. {
  153. if( NumLightMaps() == 1 )
  154. {
  155. AddSingleDynamicLight( pLights[lnum] );
  156. }
  157. else
  158. {
  159. AddSingleDynamicLightBumped( pLights[lnum] );
  160. }
  161. }
  162. else
  163. {
  164. AddSingleDynamicAlphaLight( pLights[lnum]);
  165. }
  166. }
  167. }
  168. #endif
  169. }
  170. //-----------------------------------------------------------------------------
  171. // Allocates fragments...
  172. //-----------------------------------------------------------------------------
  173. CDispDecalFragment* CDispInfo::AllocateDispDecalFragment( DispDecalHandle_t h, int nVerts )
  174. {
  175. DispDecalFragmentHandle_t f = s_DispDecalFragments.Alloc(true);
  176. s_DispDecalFragments.LinkBefore( s_DispDecals[h].m_FirstFragment, f );
  177. s_DispDecals[h].m_FirstFragment = f;
  178. CDispDecalFragment* pf = &s_DispDecalFragments[f];
  179. // Initialize the vert count:
  180. pf->m_nVerts = nVerts;
  181. pf->m_pVerts = new CDecalVert[nVerts];
  182. return pf;
  183. }
  184. //-----------------------------------------------------------------------------
  185. // Clears decal fragment lists
  186. //-----------------------------------------------------------------------------
  187. void CDispInfo::ClearDecalFragments( DispDecalHandle_t h )
  188. {
  189. // Iterate over all fragments associated with each shadow decal
  190. CDispDecal& decal = s_DispDecals[h];
  191. DispDecalFragmentHandle_t f = decal.m_FirstFragment;
  192. DispDecalFragmentHandle_t next;
  193. while( f != DISP_DECAL_FRAGMENT_HANDLE_INVALID )
  194. {
  195. next = s_DispDecalFragments.Next(f);
  196. s_DispDecalFragments.Free(f); // Destructs the decal, freeing the memory.
  197. f = next;
  198. }
  199. // Blat out the list
  200. decal.m_FirstFragment = DISP_DECAL_FRAGMENT_HANDLE_INVALID;
  201. // Mark is as not computed
  202. decal.m_Flags &= ~CDispDecalBase::FRAGMENTS_COMPUTED;
  203. // Update the number of triangles in the decal
  204. decal.m_nTris = 0;
  205. decal.m_nVerts = 0;
  206. }
  207. void CDispInfo::ClearAllDecalFragments()
  208. {
  209. // Iterate over all shadow decals on the displacement
  210. DispDecalHandle_t h = m_FirstDecal;
  211. while( h != DISP_SHADOW_HANDLE_INVALID )
  212. {
  213. ClearDecalFragments( h );
  214. h = s_DispDecals.Next(h);
  215. }
  216. }
  217. // ----------------------------------------------------------------------------- //
  218. // Add/remove decals
  219. // ----------------------------------------------------------------------------- //
  220. DispDecalHandle_t CDispInfo::NotifyAddDecal( decal_t *pDecal, float flSize )
  221. {
  222. // Create a new decal, link it in
  223. DispDecalHandle_t h = s_DispDecals.Alloc( true );
  224. if ( h != s_DispDecals.InvalidIndex() )
  225. {
  226. #ifndef DEDICATED
  227. int nDecalCount = 0;
  228. int iDecal = m_FirstDecal;
  229. int iLastDecal = s_DispDecals.InvalidIndex();
  230. while( iDecal != s_DispDecals.InvalidIndex() )
  231. {
  232. if ( 0 == ( s_DispDecals[ iDecal ].m_pDecal->flags & FDECAL_PLAYERSPRAY ) )
  233. { // Do not count player sprays for the purpose of unlinking decals
  234. iLastDecal = iDecal;
  235. ++nDecalCount;
  236. }
  237. iDecal = s_DispDecals.Next( iDecal );
  238. }
  239. if ( nDecalCount >= MAX_DISP_DECALS )
  240. {
  241. R_DecalUnlink( s_DispDecals[iLastDecal].m_pDecal, host_state.worldbrush );
  242. }
  243. #endif
  244. s_DispDecals.LinkBefore( m_FirstDecal, h );
  245. m_FirstDecal = h;
  246. CDispDecal *pDispDecal = &s_DispDecals[h];
  247. pDispDecal->m_pDecal = pDecal;
  248. pDispDecal->m_FirstFragment = DISP_DECAL_FRAGMENT_HANDLE_INVALID;
  249. pDispDecal->m_nVerts = 0;
  250. pDispDecal->m_nTris = 0;
  251. pDispDecal->m_flSize = flSize;
  252. // Setup a basis for it.
  253. CDecalVert *pOutVerts = NULL;
  254. R_SetupDecalClip( pOutVerts, pDispDecal->m_pDecal, MSurf_Plane( m_ParentSurfID ).normal, pDispDecal->m_pDecal->material,
  255. pDispDecal->m_TextureSpaceBasis, pDispDecal->m_DecalWorldScale );
  256. // Recurse and precalculate which nodes this thing can touch.
  257. SetupDecalNodeIntersect( m_pPowerInfo->m_RootNode, 0, pDispDecal, 0 );
  258. }
  259. return h;
  260. }
  261. void CDispInfo::NotifyRemoveDecal( DispDecalHandle_t h )
  262. {
  263. // Any fragments we got we don't need
  264. ClearDecalFragments(h);
  265. // Reset the head of the list
  266. if (m_FirstDecal == h)
  267. m_FirstDecal = s_DispDecals.Next(h);
  268. // Blow away the decal
  269. s_DispDecals.Free( h );
  270. }
  271. //-----------------------------------------------------------------------------
  272. // Allocates fragments...
  273. //-----------------------------------------------------------------------------
  274. CDispShadowFragment* CDispInfo::AllocateShadowDecalFragment( DispShadowHandle_t h, int nCount )
  275. {
  276. s_ShadowFragmentAllocLock.Lock();
  277. DispShadowFragmentHandle_t f = s_DispShadowFragments.Alloc(true);
  278. s_DispShadowFragments.LinkBefore( s_DispShadowDecals[h].m_FirstFragment, f );
  279. s_DispShadowDecals[h].m_FirstFragment = f;
  280. CDispShadowFragment* pf = &s_DispShadowFragments[f];
  281. pf->m_nVerts = nCount;
  282. pf->m_ShadowVerts = new ShadowVertex_t[nCount];
  283. s_ShadowFragmentAllocLock.Unlock();
  284. return pf;
  285. }
  286. //-----------------------------------------------------------------------------
  287. // Clears shadow decal fragment lists
  288. //-----------------------------------------------------------------------------
  289. void CDispInfo::ClearShadowDecalFragments( DispShadowHandle_t h )
  290. {
  291. // Iterate over all fragments associated with each shadow decal
  292. CDispShadowDecal& decal = s_DispShadowDecals[h];
  293. DispShadowFragmentHandle_t f = decal.m_FirstFragment;
  294. DispShadowFragmentHandle_t next;
  295. while( f != DISP_SHADOW_FRAGMENT_HANDLE_INVALID )
  296. {
  297. next = s_DispShadowFragments.Next(f);
  298. s_DispShadowFragments.Free(f);
  299. f = next;
  300. }
  301. // Blat out the list
  302. decal.m_FirstFragment = DISP_SHADOW_FRAGMENT_HANDLE_INVALID;
  303. // Mark is as not computed
  304. decal.m_Flags &= ~CDispDecalBase::FRAGMENTS_COMPUTED;
  305. // Update the number of triangles in the decal
  306. decal.m_nTris = 0;
  307. decal.m_nVerts = 0;
  308. }
  309. void CDispInfo::ClearAllShadowDecalFragments()
  310. {
  311. // Iterate over all shadow decals on the displacement
  312. DispShadowHandle_t h = m_FirstShadowDecal;
  313. while( h != DISP_SHADOW_HANDLE_INVALID )
  314. {
  315. ClearShadowDecalFragments( h );
  316. h = s_DispShadowDecals.Next(h);
  317. }
  318. }
  319. // ----------------------------------------------------------------------------- //
  320. // Add/remove shadow decals
  321. // ----------------------------------------------------------------------------- //
  322. DispShadowHandle_t CDispInfo::AddShadowDecal( ShadowHandle_t shadowHandle )
  323. {
  324. // Create a new shadow decal, link it in
  325. DispShadowHandle_t h = s_DispShadowDecals.Alloc( true );
  326. s_DispShadowDecals.LinkBefore( m_FirstShadowDecal, h );
  327. m_FirstShadowDecal = h;
  328. CDispShadowDecal* pShadowDecal = &s_DispShadowDecals[h];
  329. pShadowDecal->m_nTris = 0;
  330. pShadowDecal->m_nVerts = 0;
  331. pShadowDecal->m_Shadow = shadowHandle;
  332. pShadowDecal->m_FirstFragment = DISP_SHADOW_FRAGMENT_HANDLE_INVALID;
  333. return h;
  334. }
  335. void CDispInfo::RemoveShadowDecal( DispShadowHandle_t h )
  336. {
  337. // Any fragments we got we don't need
  338. ClearShadowDecalFragments(h);
  339. // Reset the head of the list
  340. if (m_FirstShadowDecal == h)
  341. m_FirstShadowDecal = s_DispShadowDecals.Next(h);
  342. // Blow away the decal
  343. s_DispShadowDecals.Free( h );
  344. }
  345. // ----------------------------------------------------------------------------- //
  346. // This little beastie generate decal fragments
  347. // ----------------------------------------------------------------------------- //
  348. void CDispInfo::GenerateDecalFragments_R( CVertIndex const &nodeIndex,
  349. int iNodeBitIndex, unsigned short decalHandle, CDispDecalBase *pDispDecal, int iLevel )
  350. {
  351. // Get the node info for this node...
  352. Assert( iNodeBitIndex < m_pPowerInfo->m_NodeCount );
  353. DispNodeInfo_t const& nodeInfo = m_pNodeInfo[iNodeBitIndex];
  354. int iNodeIndex = VertIndex( nodeIndex );
  355. // Don't bother adding decals if the node doesn't have decal info.
  356. if( !pDispDecal->m_NodeIntersect.Get( iNodeBitIndex ) )
  357. return;
  358. // Recurse into child nodes, but only if they have triangles.
  359. if ( ( iLevel+1 < m_Power ) && (nodeInfo.m_Flags & DispNodeInfo_t::CHILDREN_HAVE_TRIANGLES) )
  360. {
  361. int iChildNodeBit = iNodeBitIndex + 1;
  362. for( int iChild=0; iChild < 4; iChild++ )
  363. {
  364. CVertIndex const &childNode = m_pPowerInfo->m_pChildVerts[iNodeIndex].m_Verts[iChild];
  365. bool bActiveChild = m_ActiveVerts.Get( VertIndex( childNode ) ) != 0;
  366. if ( bActiveChild )
  367. GenerateDecalFragments_R( childNode, iChildNodeBit, decalHandle, pDispDecal, iLevel + 1
  368. );
  369. iChildNodeBit += m_pPowerInfo->m_NodeIndexIncrements[iLevel];
  370. }
  371. }
  372. // Create the decal fragments on the node triangles
  373. bool isShadow = (pDispDecal->m_Flags & CDispDecalBase::DECAL_SHADOW) != 0;
  374. int index = nodeInfo.m_FirstTesselationIndex;
  375. for ( int i = 0; i < nodeInfo.m_Count; i += 3 )
  376. {
  377. if (isShadow)
  378. TestAddDecalTri( index + i, decalHandle, static_cast<CDispShadowDecal*>(pDispDecal)
  379. );
  380. else
  381. TestAddDecalTri( index + i, decalHandle, static_cast<CDispDecal*>(pDispDecal) );
  382. }
  383. }
  384. void CDispInfo::GenerateDecalFragments( CVertIndex const &nodeIndex,
  385. int iNodeBitIndex, unsigned short decalHandle, CDispDecalBase *pDispDecal )
  386. {
  387. GenerateDecalFragments_R( nodeIndex, iNodeBitIndex, decalHandle, pDispDecal, 0 );
  388. pDispDecal->m_Flags |= CDispDecalBase::FRAGMENTS_COMPUTED;
  389. }
  390. // ----------------------------------------------------------------------------- //
  391. // Compute shadow fragments for a particular shadow
  392. // ----------------------------------------------------------------------------- //
  393. bool CDispInfo::ComputeShadowFragments( DispShadowHandle_t h, int& vertexCount, int& indexCount )
  394. {
  395. #ifndef DEDICATED
  396. CDispShadowDecal* pShadowDecal = &s_DispShadowDecals[h];
  397. // If we already have fragments, that means the data's already cached.
  398. if ((pShadowDecal->m_Flags & CDispDecalBase::FRAGMENTS_COMPUTED) != 0)
  399. {
  400. vertexCount = pShadowDecal->m_nVerts;
  401. indexCount = 3 * pShadowDecal->m_nTris;
  402. return true;
  403. }
  404. Assert( pShadowDecal->m_nTris == 0);
  405. Assert( pShadowDecal->m_FirstFragment == DISP_SHADOW_FRAGMENT_HANDLE_INVALID);
  406. ShadowInfo_t const& info = g_pShadowMgr->GetInfo( pShadowDecal->m_Shadow );
  407. unsigned short pIntersectingNodes[ 85 ]; // shorts to save stack space
  408. int nNumIntersectingNodes = 0;
  409. VMatrix matZScale( SetupMatrixScale( Vector( 1.0f, 1.0f, 1.0f/info.m_MaxDist ) ) );
  410. VMatrix normalizedWorldToShadow;
  411. MatrixMultiply( matZScale, info.m_WorldToShadow, normalizedWorldToShadow );
  412. Frustum_t shadowFrustum;
  413. VMatrix shadowToWorld;
  414. MatrixInverseGeneral( normalizedWorldToShadow, shadowToWorld );
  415. FrustumPlanesFromMatrix( shadowToWorld, shadowFrustum );
  416. FindNodesInShadowFrustum( shadowFrustum, pIntersectingNodes, &nNumIntersectingNodes, 0, 0 );
  417. if ( nNumIntersectingNodes == 0 )
  418. {
  419. return false;
  420. }
  421. AddNodeTrisToDecal( pShadowDecal, h, pIntersectingNodes, nNumIntersectingNodes );
  422. pShadowDecal->m_Flags |= CDispDecalBase::FRAGMENTS_COMPUTED;
  423. // Compute the index + vertex counts
  424. vertexCount = pShadowDecal->m_nVerts;
  425. indexCount = 3 * pShadowDecal->m_nTris;
  426. #endif
  427. return true;
  428. }
  429. struct VisitedNodeData_t
  430. {
  431. unsigned char iNodeBit;
  432. unsigned char iLevel;
  433. };
  434. // ----------------------------------------------------------------------------- //
  435. // Hierarchical node culling using AABB tree
  436. // ----------------------------------------------------------------------------- //
  437. void CDispInfo::FindNodesInShadowFrustum( const Frustum_t& frustum, unsigned short* pNodeArray, int* pNumNodes, int iNodeBit, int iLevel )
  438. {
  439. VisitedNodeData_t nodeList[85];
  440. nodeList[0].iNodeBit = 0;
  441. nodeList[0].iLevel = 0;
  442. int listIndex = 0;
  443. int maxIndex = 0;
  444. while ( listIndex <= maxIndex )
  445. {
  446. int iNodeBit = nodeList[listIndex].iNodeBit;
  447. int iLevel = nodeList[listIndex].iLevel;
  448. ++listIndex;
  449. DispNodeInfo_t& nodeInfo = m_pNodeInfo[iNodeBit];
  450. if ( nodeInfo.m_mins.x == FLT_MAX )
  451. {
  452. // empty node
  453. continue;
  454. }
  455. // TODO: SIMD intersection routine? Replace recursion with queue?
  456. if ( frustum.CullBox( nodeInfo.m_mins, nodeInfo.m_maxs ) )
  457. {
  458. continue;
  459. }
  460. if ( iLevel+1 < m_Power )
  461. {
  462. // Need to check child nodes. put them at end of list
  463. int iChildNodeBit = iNodeBit + 1;
  464. for( int iChild=0; iChild < 4; iChild++ )
  465. {
  466. ++maxIndex;
  467. nodeList[maxIndex].iNodeBit = iChildNodeBit;
  468. nodeList[maxIndex].iLevel = iLevel + 1;
  469. iChildNodeBit += m_pPowerInfo->m_NodeIndexIncrements[iLevel];
  470. }
  471. }
  472. else
  473. {
  474. // leaf node
  475. //CDebugOverlay::AddBoxOverlay( Vector( 0.0f, 0.0f, 0.0f ), nodeInfo.m_mins, nodeInfo.m_maxs, QAngle( 0, 0, 0 ), 255, 255, 255, 0, 0.0f );
  476. pNodeArray[*pNumNodes] = iNodeBit;
  477. ++(*pNumNodes);
  478. }
  479. }
  480. }
  481. // ----------------------------------------------------------------------------- //
  482. // Takes an array of node indices and adds all of their tris to a decal
  483. // ----------------------------------------------------------------------------- //
  484. void CDispInfo::AddNodeTrisToDecal( CDispShadowDecal *pDispDecal, unsigned short decalHandle, unsigned short* pNodeIndices, int nNumIndices )
  485. {
  486. for ( int j = 0; j < nNumIndices; ++j )
  487. {
  488. // Get the node info for this node...
  489. DispNodeInfo_t const& nodeInfo = m_pNodeInfo[ pNodeIndices[j] ];
  490. int index = nodeInfo.m_FirstTesselationIndex;
  491. for ( int i = 0; i < nodeInfo.m_Count; i += 3 )
  492. {
  493. TestAddDecalTri( index + i, decalHandle, pDispDecal );
  494. }
  495. }
  496. }
  497. //-----------------------------------------------------------------------------
  498. // Generate vertex lists
  499. //-----------------------------------------------------------------------------
  500. bool CDispInfo::GetTag()
  501. {
  502. return m_Tag == m_pDispArray->m_CurTag;
  503. }
  504. void CDispInfo::SetTag()
  505. {
  506. m_Tag = m_pDispArray->m_CurTag;
  507. }
  508. //-----------------------------------------------------------------------------
  509. // Helpers for global functions.
  510. //-----------------------------------------------------------------------------
  511. void DispInfo_BuildPrimLists( int nSortGroup, SurfaceHandle_t *pList, int listCount, bool bDepthOnly,
  512. CDispInfo *visibleDisps[MAX_MAP_DISPINFO], int &nVisibleDisps )
  513. {
  514. VPROF("DispInfo_BuildPrimLists");
  515. nVisibleDisps = 0;
  516. for( int i = 0; i < listCount; i++ )
  517. {
  518. CDispInfo *pDisp = static_cast<CDispInfo*>( pList[i]->pDispInfo );
  519. if( !pDisp->Render( pDisp->m_pMesh, false ) )
  520. continue;
  521. // Add it to the list of visible displacements.
  522. if( nVisibleDisps < MAX_MAP_DISPINFO )
  523. {
  524. visibleDisps[nVisibleDisps++] = pDisp;
  525. }
  526. }
  527. }
  528. void DispInfo_GetVisibleDispsAndAddOverlayFragmentsToRenderList( int nSortGroup, SurfaceHandle_t *pList, int listCount,
  529. CDispInfo *visibleDisps[MAX_MAP_DISPINFO], int &nVisibleDisps )
  530. {
  531. VPROF( "DispInfo_GetVisibleDispsAndAddOverlayFragmentsToRenderList" );
  532. nVisibleDisps = 0;
  533. #ifndef DEDICATED
  534. for( int i = 0; i < listCount; i++ )
  535. {
  536. CDispInfo *pDisp = static_cast<CDispInfo*>( pList[i]->pDispInfo );
  537. // Add it to the list of visible displacements.
  538. if( nVisibleDisps < MAX_MAP_DISPINFO )
  539. {
  540. visibleDisps[nVisibleDisps++] = pDisp;
  541. }
  542. OverlayMgr()->AddFragmentListToRenderList( nSortGroup, MSurf_OverlayFragmentList( pList[i] ), true );
  543. }
  544. #endif
  545. }
  546. ConVar disp_dynamic( "disp_dynamic", "0" );
  547. void DispInfo_DrawPrimLists( IMatRenderContext *pRenderContext, ERenderDepthMode_t DepthMode )
  548. {
  549. #ifndef DEDICATED
  550. VPROF("DispInfo_DrawPrimLists");
  551. int nDispGroupsSize = g_DispGroups.Count();
  552. int nFullbright = g_pMaterialSystemConfig->nFullbright;
  553. for( int iGroup=0; iGroup < nDispGroupsSize; iGroup++ )
  554. {
  555. CDispGroup *pGroup = g_DispGroups[iGroup];
  556. if( pGroup->m_nVisible == 0 )
  557. continue;
  558. if ( DepthMode != DEPTH_MODE_NORMAL )
  559. {
  560. // Select proper override material
  561. int nAlphaTest = (int) pGroup->m_pMaterial->IsAlphaTested();
  562. int nNoCull = (int) pGroup->m_pMaterial->IsTwoSided();
  563. IMaterial *pDepthWriteMaterial;
  564. if ( DepthMode == DEPTH_MODE_SHADOW )
  565. {
  566. pDepthWriteMaterial = g_pMaterialDepthWrite[ nAlphaTest ][ nNoCull ];
  567. }
  568. else
  569. {
  570. pDepthWriteMaterial = g_pMaterialSSAODepthWrite[ nAlphaTest ][ nNoCull ];
  571. }
  572. if ( nAlphaTest == 1 )
  573. {
  574. static unsigned int originalTextureVarCache = 0;
  575. IMaterialVar *pOriginalTextureVar = pGroup->m_pMaterial->FindVarFast( "$basetexture", &originalTextureVarCache );
  576. static unsigned int originalTextureFrameVarCache = 0;
  577. IMaterialVar *pOriginalTextureFrameVar = pGroup->m_pMaterial->FindVarFast( "$frame", &originalTextureFrameVarCache );
  578. static unsigned int originalAlphaRefCache = 0;
  579. IMaterialVar *pOriginalAlphaRefVar = pGroup->m_pMaterial->FindVarFast( "$AlphaTestReference", &originalAlphaRefCache );
  580. static unsigned int textureVarCache = 0;
  581. IMaterialVar *pTextureVar = pDepthWriteMaterial->FindVarFast( "$basetexture", &textureVarCache );
  582. static unsigned int textureFrameVarCache = 0;
  583. IMaterialVar *pTextureFrameVar = pDepthWriteMaterial->FindVarFast( "$frame", &textureFrameVarCache );
  584. static unsigned int alphaRefCache = 0;
  585. IMaterialVar *pAlphaRefVar = pDepthWriteMaterial->FindVarFast( "$AlphaTestReference", &alphaRefCache );
  586. if( pTextureVar && pOriginalTextureVar )
  587. {
  588. pTextureVar->SetTextureValue( pOriginalTextureVar->GetTextureValue() );
  589. }
  590. if( pTextureFrameVar && pOriginalTextureFrameVar )
  591. {
  592. pTextureFrameVar->SetIntValue( pOriginalTextureFrameVar->GetIntValue() );
  593. }
  594. if( pAlphaRefVar && pOriginalAlphaRefVar )
  595. {
  596. pAlphaRefVar->SetFloatValue( pOriginalAlphaRefVar->GetFloatValue() );
  597. }
  598. }
  599. pRenderContext->Bind( pDepthWriteMaterial );
  600. }
  601. else
  602. {
  603. pRenderContext->Bind( pGroup->m_pMaterial );
  604. }
  605. if ( nFullbright != 1 && DepthMode == DEPTH_MODE_NORMAL )
  606. {
  607. pRenderContext->BindLightmapPage( pGroup->m_LightmapPageID );
  608. }
  609. else
  610. {
  611. // If this code gets removed again, I'm chopping fingers off!
  612. if( pGroup->m_pMaterial->GetPropertyFlag( MATERIAL_PROPERTY_NEEDS_BUMPED_LIGHTMAPS ) )
  613. {
  614. pRenderContext->BindLightmapPage( MATERIAL_SYSTEM_LIGHTMAP_PAGE_WHITE_BUMP );
  615. }
  616. else
  617. {
  618. pRenderContext->BindLightmapPage( MATERIAL_SYSTEM_LIGHTMAP_PAGE_WHITE );
  619. }
  620. }
  621. int nMeshesSize = pGroup->m_Meshes.Count();
  622. for( int iMesh=0; iMesh < nMeshesSize; iMesh++ )
  623. {
  624. CGroupMesh *pMesh = pGroup->m_Meshes[iMesh];
  625. if( pMesh->m_nVisible == 0 )
  626. continue;
  627. if ( disp_dynamic.GetInt() )
  628. {
  629. for ( int iVisible=0; iVisible < pMesh->m_nVisible; iVisible++ )
  630. {
  631. pMesh->m_VisibleDisps[iVisible]->SpecifyDynamicMesh();
  632. }
  633. }
  634. else
  635. {
  636. pMesh->m_pMesh->Draw( pMesh->m_Visible.Base(), pMesh->m_nVisible );
  637. }
  638. pMesh->m_nVisible = 0;
  639. }
  640. }
  641. #endif
  642. }
  643. //-----------------------------------------------------------------------------
  644. // Purpose:
  645. //-----------------------------------------------------------------------------
  646. void DecalDispSurfacesInit( void )
  647. {
  648. #ifndef DEDICATED
  649. g_aDispDecalSortPool.RemoveAll();
  650. ++g_nDispDecalSortCheckCount;
  651. #endif
  652. }
  653. //-----------------------------------------------------------------------------
  654. // Purpose: Batch up visible displacement decals and build them if necessary.
  655. //-----------------------------------------------------------------------------
  656. void DispInfo_BatchDecals( CDispInfo **pVisibleDisps, int nVisibleDisps )
  657. {
  658. #ifndef DEDICATED
  659. // Performance analysis.
  660. VPROF( "DispInfo_BatchDecals" );
  661. // Increment the decal sort check count and clear the pool.
  662. DecalDispSurfacesInit();
  663. // Do we have any visible displacements?
  664. if( !nVisibleDisps )
  665. return;
  666. for( int iDisp = 0; iDisp < nVisibleDisps; ++iDisp )
  667. {
  668. // Get the current visible displacement and see if it has any decals.
  669. CDispInfo *pDisp = pVisibleDisps[iDisp];
  670. if( pDisp->m_FirstDecal == DISP_DECAL_HANDLE_INVALID )
  671. continue;
  672. DispDecalHandle_t hDecal = pDisp->m_FirstDecal;
  673. while ( hDecal != DISP_DECAL_HANDLE_INVALID )
  674. {
  675. CDispDecal &decal = s_DispDecals[hDecal];
  676. // If we're an immediate cleanup decal, flag this for cleanup next frame. We do this by virtue of considering
  677. // drawing, rather than actually drawing it. We do still want to draw it, though.
  678. if ( decal.m_pDecal->flags & FDECAL_IMMEDIATECLEANUP )
  679. {
  680. extern void R_DecalAddToDestroyList( decal_t *pDecal );
  681. R_DecalAddToDestroyList( decal.m_pDecal );
  682. }
  683. // Create the displacement fragment if necessary.
  684. if ( ( decal.m_Flags & CDispDecalBase::FRAGMENTS_COMPUTED ) == 0 )
  685. {
  686. pDisp->GenerateDecalFragments( pDisp->m_pPowerInfo->m_RootNode, 0, hDecal, &decal );
  687. }
  688. // Don't draw if there's no triangles.
  689. if ( decal.m_nTris == 0 )
  690. {
  691. hDecal = s_DispDecals.Next( hDecal );
  692. continue;
  693. }
  694. // Get the decal material.
  695. IMaterial *pMaterial = decal.m_pDecal->material;
  696. if ( !pMaterial )
  697. {
  698. DevMsg( "DispInfo_BatchDecals: material is NULL, decal %i.\n", hDecal );
  699. hDecal = s_DispDecals.Next( hDecal );
  700. continue;
  701. }
  702. // Lightmap decals.
  703. int iTreeType = -1;
  704. if ( pMaterial->GetPropertyFlag( MATERIAL_PROPERTY_NEEDS_LIGHTMAP ) )
  705. {
  706. // Permanent lightmapped decals.
  707. if ( decal.m_pDecal->flags & FDECAL_PERMANENT )
  708. {
  709. iTreeType = PERMANENT_LIGHTMAP;
  710. }
  711. // Non-permanent lightmapped decals.
  712. else
  713. {
  714. iTreeType = LIGHTMAP;
  715. }
  716. }
  717. // Non-lightmapped decals.
  718. else
  719. {
  720. iTreeType = NONLIGHTMAP;
  721. }
  722. // There is only one group at a time.
  723. int iGroup = 0;
  724. intp iPool = g_aDispDecalSortPool.Alloc( true );
  725. g_aDispDecalSortPool[iPool] = decal.m_pDecal;
  726. int iSortTree = decal.m_pDecal->m_iSortTree;
  727. int iSortMaterial = decal.m_pDecal->m_iSortMaterial;
  728. DecalMaterialBucket_t &materialBucket = g_aDispDecalSortTrees[iSortTree].m_aDecalSortBuckets[iGroup][iTreeType].Element( iSortMaterial );
  729. if ( materialBucket.m_nCheckCount == g_nDispDecalSortCheckCount )
  730. {
  731. // intp iTail = materialBucket.m_iTail;
  732. // g_aDispDecalSortPool.LinkAfter( iTail, iPool );
  733. // materialBucket.m_iTail = iPool;
  734. // Displacement decals on the ground happen to render back-to-front, so link before head
  735. intp iHead = materialBucket.m_iHead;
  736. g_aDispDecalSortPool.LinkBefore( iHead, iPool );
  737. materialBucket.m_iHead = iPool;
  738. }
  739. else
  740. {
  741. materialBucket.m_iHead = materialBucket.m_iTail = iPool;
  742. materialBucket.m_nCheckCount = g_nDispDecalSortCheckCount;
  743. }
  744. hDecal = s_DispDecals.Next( hDecal );
  745. }
  746. }
  747. #endif
  748. }
  749. //-----------------------------------------------------------------------------
  750. //
  751. //-----------------------------------------------------------------------------
  752. inline void DispInfo_DrawDecalMeshList( IMatRenderContext *pRenderContext, DecalMeshList_t &meshList )
  753. {
  754. bool bMatFullbright = ( g_pMaterialSystemConfig->nFullbright == 1 );
  755. int nBatchCount = meshList.m_aBatches.Count();
  756. for ( int iBatch = 0; iBatch < nBatchCount; ++iBatch )
  757. {
  758. const DecalBatchList_t &batch = meshList.m_aBatches[iBatch];
  759. if ( !bMatFullbright )
  760. {
  761. pRenderContext->BindLightmapPage( batch.m_iLightmapPage );
  762. }
  763. else
  764. {
  765. pRenderContext->BindLightmapPage( MATERIAL_SYSTEM_LIGHTMAP_PAGE_WHITE );
  766. }
  767. pRenderContext->Bind( batch.m_pMaterial, batch.m_pProxy );
  768. meshList.m_pMesh->Draw( batch.m_iStartIndex, batch.m_nIndexCount );
  769. }
  770. }
  771. void DispInfo_DrawDecalsGroup( IMatRenderContext *pRenderContext, int iGroup, int iTreeType )
  772. {
  773. #ifndef DEDICATED
  774. int nSortTreeCount = g_aDecalSortTrees.Count();
  775. if ( !nSortTreeCount )
  776. return;
  777. DecalMeshList_t meshList;
  778. CMeshBuilder meshBuilder;
  779. int nVertCount = 0;
  780. int nIndexCount = 0;
  781. int nDecalSortMaxVerts = g_nMaxDecals * 5;
  782. // NOTE: This is sort of a hack. The decal wireframe material is 20 bytes; this assumes
  783. // we're going to render vertices no larger than 80 bytes/vert.
  784. nDecalSortMaxVerts = MIN( nDecalSortMaxVerts, pRenderContext->GetMaxVerticesToRender( g_materialDecalWireframe ) / 4 );
  785. int nDecalSortMaxIndices = nDecalSortMaxVerts * 3;
  786. nDecalSortMaxIndices = MIN( nDecalSortMaxIndices, pRenderContext->GetMaxIndicesToRender() );
  787. bool bMatWireframe = ShouldDrawInWireFrameMode();
  788. for ( int iSortTree = 0; iSortTree < nSortTreeCount; ++iSortTree )
  789. {
  790. bool bMeshInit = true;
  791. uint16 unPlayerDecalStickerKitID = 0; // player decals must be split into separate calls by actual basetexture, but overall keep the state so they are bucketed by same material
  792. const CUtlVector<DecalMaterialBucket_t> &materialBucketList = g_aDispDecalSortTrees[iSortTree].m_aDecalSortBuckets[iGroup][iTreeType];
  793. int nBucketCount = materialBucketList.Count();
  794. for ( int iBucket = 0; iBucket < nBucketCount; ++iBucket )
  795. {
  796. if ( materialBucketList.Element( iBucket ).m_nCheckCount != g_nDispDecalSortCheckCount )
  797. continue;
  798. intp iHead = materialBucketList.Element( iBucket ).m_iHead;
  799. if ( !g_aDispDecalSortPool.IsValidIndex( iHead ) )
  800. continue;
  801. decal_t *pDecalHead = g_aDispDecalSortPool.Element( iHead );
  802. Assert( pDecalHead->material );
  803. if ( !pDecalHead->material )
  804. continue;
  805. // Vertex format.
  806. VertexFormat_t vertexFormat = pDecalHead->material->GetVertexFormat();
  807. if ( vertexFormat == 0 )
  808. continue;
  809. // New bucket = new batch.
  810. DecalBatchList_t *pBatch = NULL;
  811. bool bBatchInit = true;
  812. int nCount;
  813. intp iElement = iHead;
  814. while ( iElement != g_aDispDecalSortPool.InvalidIndex() )
  815. {
  816. decal_t *pDecal = g_aDispDecalSortPool.Element( iElement );
  817. iElement = g_aDispDecalSortPool.Next( iElement );
  818. CDispDecal &decal = s_DispDecals[pDecal->m_DispDecal];
  819. // Now draw all the fragments with this material.
  820. IMaterial* pMaterial = decal.m_pDecal->material;
  821. if ( !pMaterial )
  822. {
  823. DevMsg( "DispInfo_DrawDecalsGroup: material is NULL decal %i.\n", pDecal->m_DispDecal );
  824. continue;
  825. }
  826. DispDecalFragmentHandle_t hFrag = decal.m_FirstFragment;
  827. while ( hFrag != DISP_DECAL_FRAGMENT_HANDLE_INVALID )
  828. {
  829. CDispDecalFragment &fragment = s_DispDecalFragments[hFrag];
  830. hFrag = s_DispDecalFragments.Next( hFrag );
  831. nCount = fragment.m_nVerts;
  832. // Overflow - new mesh, batch.
  833. if ( ( ( nVertCount + nCount ) >= nDecalSortMaxVerts ) || ( nIndexCount + ( nCount - 2 ) >= nDecalSortMaxIndices )
  834. || ( !bMeshInit && ( pDecal->flags & FDECAL_PLAYERSPRAY ) && ( uint16( reinterpret_cast< uintp >( pDecal->userdata ) ) != unPlayerDecalStickerKitID ) ) )
  835. {
  836. // Finish this batch.
  837. if ( pBatch )
  838. {
  839. pBatch->m_nIndexCount = ( nIndexCount - pBatch->m_iStartIndex );
  840. }
  841. // End the mesh building phase and render.
  842. meshBuilder.End();
  843. DispInfo_DrawDecalMeshList( pRenderContext, meshList );
  844. // Reset.
  845. bMeshInit = true;
  846. pBatch = NULL;
  847. bBatchInit = true;
  848. unPlayerDecalStickerKitID = 0;
  849. }
  850. // Create the mesh.
  851. if ( bMeshInit )
  852. {
  853. // Reset the mesh list.
  854. meshList.m_pMesh = NULL;
  855. meshList.m_aBatches.RemoveAll();
  856. if ( !bMatWireframe )
  857. {
  858. meshList.m_pMesh = pRenderContext->GetDynamicMesh( false, NULL, NULL, pDecalHead->material );
  859. }
  860. else
  861. {
  862. meshList.m_pMesh = pRenderContext->GetDynamicMesh( false, NULL, NULL, g_materialDecalWireframe );
  863. }
  864. meshBuilder.Begin( meshList.m_pMesh, MATERIAL_TRIANGLES, nDecalSortMaxVerts, nDecalSortMaxIndices );
  865. nVertCount = 0;
  866. nIndexCount = 0;
  867. bMeshInit = false;
  868. unPlayerDecalStickerKitID = ( pDecal->flags & FDECAL_PLAYERSPRAY )
  869. ? uint16( reinterpret_cast< uintp >( pDecal->userdata ) )
  870. : 0; // Keep track of playerdecal proxy state for batches roll over
  871. }
  872. // Create the batch.
  873. if ( bBatchInit )
  874. {
  875. // Create a batch for this bucket = material/lightmap pair.
  876. int iBatchList = meshList.m_aBatches.AddToTail();
  877. pBatch = &meshList.m_aBatches[iBatchList];
  878. pBatch->m_iStartIndex = nIndexCount;
  879. if ( !bMatWireframe )
  880. {
  881. pBatch->m_pMaterial = pDecalHead->material;
  882. if ( pDecal->flags & FDECAL_PLAYERSPRAY )
  883. pBatch->m_pProxy = pDecal->userdata; // Player sprays must use individual proxies, probably all materials can, but this is a safe change
  884. else
  885. pBatch->m_pProxy = pDecalHead->userdata;
  886. pBatch->m_iLightmapPage = materialSortInfoArray[MSurf_MaterialSortID( pDecalHead->surfID )].lightmapPageID;
  887. }
  888. else
  889. {
  890. pBatch->m_pMaterial = g_materialDecalWireframe;
  891. }
  892. bBatchInit = false;
  893. }
  894. Assert ( pBatch );
  895. // Setup verts.
  896. float flOffset = fragment.m_pDecal->lightmapOffset;
  897. for ( int iVert = 0; iVert < fragment.m_nVerts; ++iVert )
  898. {
  899. const CDecalVert &vert = fragment.m_pVerts[iVert];
  900. meshBuilder.Position3fv( vert.m_vPos.Base() );
  901. // FIXME!! Really want the normal from the displacement, not from the base surface.
  902. Vector &normal = MSurf_Plane( fragment.m_pDecal->surfID ).normal;
  903. meshBuilder.Normal3fv( normal.Base() );
  904. meshBuilder.Color4ub( 255, 255, 255, 255 );
  905. meshBuilder.TexCoord2f( 0, vert.m_ctCoords.x, vert.m_ctCoords.y );
  906. meshBuilder.TexCoord2f( 1, vert.m_cLMCoords.x, vert.m_cLMCoords.y );
  907. meshBuilder.TexCoord1f( 2, flOffset );
  908. meshBuilder.AdvanceVertex();
  909. }
  910. // Setup indices.
  911. int nTriCount = ( nCount - 2 );
  912. CIndexBuilder &indexBuilder = meshBuilder;
  913. indexBuilder.FastPolygon( nVertCount, nTriCount );
  914. // Update counters.
  915. nVertCount += nCount;
  916. nIndexCount += ( nTriCount * 3 );
  917. }
  918. if ( pBatch )
  919. {
  920. pBatch->m_nIndexCount = ( nIndexCount - pBatch->m_iStartIndex );
  921. }
  922. }
  923. }
  924. if ( !bMeshInit )
  925. {
  926. meshBuilder.End();
  927. DispInfo_DrawDecalMeshList( pRenderContext, meshList );
  928. nVertCount = 0;
  929. nIndexCount = 0;
  930. }
  931. }
  932. #endif
  933. }
  934. void DispInfo_DrawDecals( IMatRenderContext *pRenderContext, CDispInfo **visibleDisps, int nVisibleDisps )
  935. {
  936. #ifndef DEDICATED
  937. VPROF( "DispInfo_DrawDecals" );
  938. int iGroup = 0;
  939. // Draw world decals.
  940. DispInfo_DrawDecalsGroup( pRenderContext, iGroup, PERMANENT_LIGHTMAP );
  941. // Draw lightmapped non-world decals.
  942. DispInfo_DrawDecalsGroup( pRenderContext, iGroup, LIGHTMAP );
  943. // Draw non-lit(mod2x) decals.
  944. DispInfo_DrawDecalsGroup( pRenderContext, iGroup, NONLIGHTMAP );
  945. #endif
  946. }
  947. // ----------------------------------------------------------------------------- //
  948. // Adds shadow rendering data to a particular mesh builder
  949. // ----------------------------------------------------------------------------- //
  950. int DispInfo_AddShadowsToMeshBuilder( CMeshBuilder& meshBuilder, DispShadowHandle_t h, int baseIndex )
  951. {
  952. #ifdef DEDICATED
  953. return 0;
  954. #else
  955. ShadowDecalRenderInfo_t info;
  956. CDispShadowDecal* pShadowDecal = &s_DispShadowDecals[h];
  957. g_pShadowMgr->ComputeRenderInfo( &info, pShadowDecal->m_Shadow );
  958. // It had better be computed by now...
  959. Assert( pShadowDecal->m_Flags & CDispDecalBase::FRAGMENTS_COMPUTED );
  960. #ifdef _DEBUG
  961. int triCount = 0;
  962. int vertCount = 0;
  963. #endif
  964. Vector2D texCoord;
  965. DispShadowFragmentHandle_t f = pShadowDecal->m_FirstFragment;
  966. CIndexBuilder &indexBuilder = meshBuilder;
  967. int nVertices = 0;
  968. int nIndices = 0;
  969. while ( f != DISP_SHADOW_FRAGMENT_HANDLE_INVALID )
  970. {
  971. const CDispShadowFragment& fragment = s_DispShadowFragments[f];
  972. const ShadowVertex_t *pShadowVert = fragment.m_ShadowVerts;
  973. // Add in the vertices + indices, use two loops to minimize tests...
  974. int i;
  975. int triangleCount = fragment.m_nVerts-2;
  976. indexBuilder.FastPolygon( nIndices, baseIndex, triangleCount );
  977. nIndices += 3 * triangleCount;
  978. for ( i = 0; i < triangleCount; ++i, ++pShadowVert )
  979. {
  980. // Transform + offset the texture coords
  981. Vector2DMultiply( pShadowVert->m_ShadowSpaceTexCoord.AsVector2D(), info.m_vTexSize, texCoord );
  982. texCoord += info.m_vTexOrigin;
  983. meshBuilder.Position3fv( nVertices, pShadowVert->m_Position.Base() );
  984. meshBuilder.TexCoord3f( nVertices, 0, texCoord.x, texCoord.y, pShadowVert->m_ShadowSpaceTexCoord.z );
  985. meshBuilder.TexCoord3fv( nVertices, 1, info.m_vShadowFalloffParams.Base() );
  986. ++nVertices;
  987. }
  988. Vector2DMultiply( pShadowVert->m_ShadowSpaceTexCoord.AsVector2D(), info.m_vTexSize, texCoord );
  989. texCoord += info.m_vTexOrigin;
  990. meshBuilder.Position3fv( nVertices, pShadowVert->m_Position.Base() );
  991. meshBuilder.TexCoord3f( nVertices, 0, texCoord.x, texCoord.y, pShadowVert->m_ShadowSpaceTexCoord.z );
  992. meshBuilder.TexCoord3fv( nVertices, 1, info.m_vShadowFalloffParams.Base() );
  993. ++pShadowVert;
  994. ++nVertices;
  995. Vector2DMultiply( pShadowVert->m_ShadowSpaceTexCoord.AsVector2D(), info.m_vTexSize, texCoord );
  996. texCoord += info.m_vTexOrigin;
  997. meshBuilder.Position3fv( nVertices, pShadowVert->m_Position.Base() );
  998. meshBuilder.TexCoord3f( nVertices, 0, texCoord.x, texCoord.y, pShadowVert->m_ShadowSpaceTexCoord.z );
  999. meshBuilder.TexCoord3fv( nVertices, 1, info.m_vShadowFalloffParams.Base() );
  1000. ++nVertices;
  1001. baseIndex += fragment.m_nVerts;
  1002. f = s_DispShadowFragments.Next(f);
  1003. #ifdef _DEBUG
  1004. triCount += fragment.m_nVerts - 2;
  1005. vertCount += fragment.m_nVerts;
  1006. #endif
  1007. }
  1008. meshBuilder.AdvanceVertices( nVertices );
  1009. meshBuilder.AdvanceIndices( nIndices );
  1010. #ifdef _DEBUG
  1011. Assert( triCount == pShadowDecal->m_nTris );
  1012. Assert( vertCount == pShadowDecal->m_nVerts );
  1013. #endif
  1014. return baseIndex;
  1015. #endif
  1016. }
  1017. HDISPINFOARRAY DispInfo_CreateArray( int nElements )
  1018. {
  1019. CDispArray *pRet = new CDispArray;
  1020. pRet->m_CurTag = 1;
  1021. pRet->m_nDispInfos = nElements;
  1022. if ( nElements )
  1023. {
  1024. pRet->m_pDispInfos = new CDispInfo[nElements];
  1025. }
  1026. else
  1027. {
  1028. pRet->m_pDispInfos = NULL;
  1029. }
  1030. for( int i=0; i < nElements; i++ )
  1031. pRet->m_pDispInfos[i].m_pDispArray = pRet;
  1032. return (HDISPINFOARRAY)pRet;
  1033. }
  1034. void DispInfo_DeleteArray( HDISPINFOARRAY hArray )
  1035. {
  1036. CDispArray *pArray = static_cast<CDispArray*>( hArray );
  1037. if( !pArray )
  1038. return;
  1039. delete [] pArray->m_pDispInfos;
  1040. delete pArray;
  1041. }
  1042. IDispInfo* DispInfo_IndexArray( HDISPINFOARRAY hArray, int iElement )
  1043. {
  1044. CDispArray *pArray = static_cast<CDispArray*>( hArray );
  1045. if( !pArray )
  1046. return NULL;
  1047. Assert( iElement >= 0 && iElement < pArray->m_nDispInfos );
  1048. return &pArray->m_pDispInfos[iElement];
  1049. }
  1050. int DispInfo_ComputeIndex( HDISPINFOARRAY hArray, IDispInfo* pInfo )
  1051. {
  1052. CDispArray *pArray = static_cast<CDispArray*>( hArray );
  1053. if( !pArray )
  1054. return NULL;
  1055. int iElement = size_cast< int >( ((intp)pInfo - (intp)(pArray->m_pDispInfos)) / sizeof(CDispInfo) );
  1056. Assert( iElement >= 0 && iElement < pArray->m_nDispInfos );
  1057. return iElement;
  1058. }
  1059. void DispInfo_ClearAllTags( HDISPINFOARRAY hArray )
  1060. {
  1061. CDispArray *pArray = static_cast<CDispArray*>( hArray );
  1062. if( !pArray )
  1063. return;
  1064. ++pArray->m_CurTag;
  1065. if( pArray->m_CurTag == 0xFFFF )
  1066. {
  1067. // Reset all the tags.
  1068. pArray->m_CurTag = 1;
  1069. for( int i=0; i < pArray->m_nDispInfos; i++ )
  1070. pArray->m_pDispInfos[i].m_Tag = 0;
  1071. }
  1072. }
  1073. //-----------------------------------------------------------------------------
  1074. // Renders normals for the displacements
  1075. //-----------------------------------------------------------------------------
  1076. static void DispInfo_DrawChainNormals( IMatRenderContext *pRenderContext, SurfaceHandle_t *pList, int listCount )
  1077. {
  1078. #ifndef DEDICATED
  1079. // Only do it in debug because we're only storing the info then
  1080. Vector p;
  1081. pRenderContext->Bind( g_pMaterialWireframeVertexColor );
  1082. for ( int i = 0; i < listCount; i++ )
  1083. {
  1084. CDispInfo *pDisp = static_cast<CDispInfo*>( pList[i]->pDispInfo );
  1085. int nVerts = pDisp->NumVerts();
  1086. IMesh *pMesh = pRenderContext->GetDynamicMesh( );
  1087. CMeshBuilder meshBuilder;
  1088. meshBuilder.Begin( pMesh, MATERIAL_LINES, nVerts * 3 );
  1089. for( int iVert=0; iVert < nVerts; iVert++ )
  1090. {
  1091. CDispRenderVert* pVert = pDisp->GetVertex(iVert);
  1092. meshBuilder.Position3fv( pVert->m_vPos.Base() );
  1093. meshBuilder.Color3ub( 0, 0, 255 );
  1094. meshBuilder.AdvanceVertex();
  1095. VectorMA( pVert->m_vPos, 5.0f, pVert->m_vNormal, p );
  1096. meshBuilder.Position3fv( p.Base() );
  1097. meshBuilder.Color3ub( 0, 0, 255 );
  1098. meshBuilder.AdvanceVertex();
  1099. meshBuilder.Position3fv( pVert->m_vPos.Base() );
  1100. meshBuilder.Color3ub( 255, 0, 0 );
  1101. meshBuilder.AdvanceVertex();
  1102. VectorMA( pVert->m_vPos, 5.0f, pVert->m_vSVector, p );
  1103. meshBuilder.Position3fv( p.Base() );
  1104. meshBuilder.Color3ub( 255, 0, 0 );
  1105. meshBuilder.AdvanceVertex();
  1106. meshBuilder.Position3fv( pVert->m_vPos.Base() );
  1107. meshBuilder.Color3ub( 0, 255, 0 );
  1108. meshBuilder.AdvanceVertex();
  1109. VectorMA( pVert->m_vPos, 5.0f, pVert->m_vTVector, p );
  1110. meshBuilder.Position3fv( p.Base() );
  1111. meshBuilder.Color3ub( 0, 255, 0 );
  1112. meshBuilder.AdvanceVertex();
  1113. }
  1114. meshBuilder.End();
  1115. pMesh->Draw();
  1116. }
  1117. #endif
  1118. }
  1119. //-----------------------------------------------------------------------------
  1120. // Renders debugging information for displacements
  1121. //-----------------------------------------------------------------------------
  1122. void DispInfo_RenderListDebug( IMatRenderContext *pRenderContext, SurfaceHandle_t *pList, int listCount )
  1123. {
  1124. #ifndef DEDICATED
  1125. VPROF("DispInfo_DrawDebugInformation");
  1126. if ( DispInfoRenderDebugModes() )
  1127. {
  1128. for( int i = 0; i < listCount; i++ )
  1129. {
  1130. CDispInfo *pDisp = static_cast<CDispInfo*>( pList[i]->pDispInfo );
  1131. pDisp->Render( pDisp->m_pMesh, true );
  1132. }
  1133. }
  1134. // Overlay with normals if we're in that mode
  1135. if( mat_normals.GetInt() )
  1136. {
  1137. DispInfo_DrawChainNormals(pRenderContext, pList, listCount);
  1138. }
  1139. #endif
  1140. }
  1141. //-----------------------------------------------------------------------------
  1142. // Renders all displacements in sorted order
  1143. //-----------------------------------------------------------------------------
  1144. void DispInfo_RenderListWorld( IMatRenderContext *pRenderContext, int nSortGroup, SurfaceHandle_t *pList, int listCount, bool bOrtho, unsigned long flags, int DepthMode )
  1145. {
  1146. #ifndef DEDICATED
  1147. if( !r_DrawDisp.GetInt() || !listCount || !( flags & DRAWWORLDLISTS_DRAW_WORLD_GEOMETRY ) )
  1148. return;
  1149. g_bDispOrthoRender = bOrtho;
  1150. // Build up the CPrimLists for all the displacements.
  1151. CDispInfo *visibleDisps[MAX_MAP_DISPINFO];
  1152. int nVisibleDisps;
  1153. DispInfo_BuildPrimLists( nSortGroup, pList, listCount, DepthMode != DEPTH_MODE_NORMAL, visibleDisps, nVisibleDisps );
  1154. // Draw..
  1155. DispInfo_DrawPrimLists( pRenderContext, (ERenderDepthMode_t) DepthMode );
  1156. #endif
  1157. }
  1158. //-----------------------------------------------------------------------------
  1159. // Renders all displacements in sorted order
  1160. //-----------------------------------------------------------------------------
  1161. void DispInfo_RenderListDecalsAndOverlays( IMatRenderContext *pRenderContext, int nSortGroup, SurfaceHandle_t *pList, int listCount, bool bOrtho, unsigned long flags )
  1162. {
  1163. #ifndef DEDICATED
  1164. if( !r_DrawDisp.GetInt() || !listCount || !( flags & DRAWWORLDLISTS_DRAW_DECALS_AND_OVERLAYS ) )
  1165. return;
  1166. g_bDispOrthoRender = bOrtho;
  1167. // Build up the CPrimLists for all the displacements.
  1168. CDispInfo *visibleDisps[MAX_MAP_DISPINFO];
  1169. int nVisibleDisps;
  1170. DispInfo_GetVisibleDispsAndAddOverlayFragmentsToRenderList( nSortGroup, pList, listCount, visibleDisps, nVisibleDisps );
  1171. // Add all displacements to the shadow render list
  1172. for ( int i = 0; i < listCount; i++ )
  1173. {
  1174. SurfaceHandle_t pCur = pList[i];
  1175. ShadowDecalHandle_t decalHandle = MSurf_ShadowDecals( pCur );
  1176. if ( decalHandle != SHADOW_DECAL_HANDLE_INVALID )
  1177. {
  1178. g_pShadowMgr->AddShadowsOnSurfaceToRenderList( decalHandle );
  1179. }
  1180. }
  1181. bool bFlashlightMask = !( (flags & DRAWWORLDLISTS_DRAW_REFRACTION ) || (flags & DRAWWORLDLISTS_DRAW_REFLECTION ));
  1182. // Draw flashlight lighting for displacements
  1183. g_pShadowMgr->RenderFlashlights( bFlashlightMask, false );
  1184. // Draw overlays
  1185. OverlayMgr()->RenderOverlays( pRenderContext, nSortGroup );
  1186. // Draw flashlight overlays
  1187. g_pShadowMgr->DrawFlashlightOverlays( pRenderContext, nSortGroup, bFlashlightMask );
  1188. OverlayMgr()->ClearRenderLists( nSortGroup );
  1189. // Draw decals
  1190. DispInfo_BatchDecals( visibleDisps, nVisibleDisps );
  1191. DispInfo_DrawDecals( pRenderContext, visibleDisps, nVisibleDisps );
  1192. // Draw flashlight decals
  1193. g_pShadowMgr->DrawFlashlightDecalsOnDisplacements( pRenderContext, nSortGroup, visibleDisps, nVisibleDisps, bFlashlightMask );
  1194. g_pShadowMgr->RenderFlashlights( bFlashlightMask, true );
  1195. // draw shadows
  1196. g_pShadowMgr->RenderShadows( pRenderContext );
  1197. g_pShadowMgr->ClearShadowRenderList();
  1198. #endif
  1199. }