Team Fortress 2 Source Code as on 22/4/2020
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.

1469 lines
43 KiB

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