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.

969 lines
25 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "stdafx.h"
  8. #include "materialsystem/imaterialsystem.h"
  9. #include "istudiorender.h"
  10. #include "material.h"
  11. #include "materialsystem/imesh.h"
  12. #include "disp_common.h"
  13. #include "bsplighting.h"
  14. #include "interface.h"
  15. #include "filesystem.h"
  16. #include "hammer.h"
  17. #include "tier0/dbg.h"
  18. // memdbgon must be the last include file in a .cpp file!!!
  19. #include "tier0/memdbgon.h"
  20. bool SurfHasBumpedLightmaps( int flags )
  21. {
  22. return ( flags & SURF_BUMPLIGHT ) &&
  23. ( !( flags & SURF_NOLIGHT ) );
  24. }
  25. void InitLMSamples( Vector4D *pSamples, int nSamples, float value )
  26. {
  27. for( int i=0; i < nSamples; i++ )
  28. {
  29. pSamples[i][0] = pSamples[i][1] = pSamples[i][2] = value;
  30. pSamples[i][3] = 1.0f;
  31. }
  32. }
  33. void InitLMSamplesRed( Vector4D *pSamples, int nSamples )
  34. {
  35. for( int i=0; i < nSamples; i++ )
  36. {
  37. pSamples[i][0] = 1;
  38. pSamples[i][1] = pSamples[i][2] = 0;
  39. pSamples[i][3] = 1.0f;
  40. }
  41. }
  42. CBSPLighting::CMaterialBuf::CMaterialBuf()
  43. {
  44. m_nVerts = m_nIndices = 0;
  45. m_pMesh = NULL;
  46. }
  47. CBSPLighting::CMaterialBuf::~CMaterialBuf()
  48. {
  49. if( m_pMesh )
  50. {
  51. CMatRenderContextPtr pRenderContext( MaterialSystemInterface() );
  52. pRenderContext->DestroyStaticMesh( m_pMesh );
  53. }
  54. m_DrawCommands.PurgeAndDeleteElements();
  55. }
  56. CBSPLighting::CFaceMaterial::~CFaceMaterial()
  57. {
  58. m_MaterialBufs.PurgeAndDeleteElements();
  59. m_Faces.PurgeAndDeleteElements();
  60. }
  61. CBSPLighting::CBSPLighting()
  62. {
  63. m_nTotalTris = 0;
  64. m_hVRadDLL = 0;
  65. m_pVRadDLL = 0;
  66. m_pBSPLightingThread = 0;
  67. m_bLightingInProgress = false;
  68. }
  69. CBSPLighting::~CBSPLighting()
  70. {
  71. Term();
  72. }
  73. void CBSPLighting::Release()
  74. {
  75. delete this;
  76. }
  77. bool CBSPLighting::Load( char const *pFilename )
  78. {
  79. // Free everything.
  80. Term();
  81. // Load VRAD's DLL (and load the BSP file).
  82. if( !LoadVRADDLL( pFilename ) )
  83. return false;
  84. // Create the lighting thread.
  85. m_pBSPLightingThread = CreateBSPLightingThread( m_pVRadDLL );
  86. if( !m_pBSPLightingThread )
  87. return false;
  88. // Get the BSP file information from VRAD.
  89. CBSPInfo file;
  90. m_pVRadDLL->GetBSPInfo( &file );
  91. // Allocate faces and verts.
  92. CUtlVector<char> usedFaces;
  93. usedFaces.SetSize( file.numfaces );
  94. int nFaces = 0;
  95. int nVerts = 0;
  96. for( int iCountFace=0; iCountFace < file.numfaces; iCountFace++ )
  97. {
  98. usedFaces[iCountFace] = 0;
  99. if( file.dfaces[iCountFace].m_LightmapTextureSizeInLuxels[0] != 0 ||
  100. file.dfaces[iCountFace].m_LightmapTextureSizeInLuxels[0] != 0 )
  101. {
  102. texinfo_t *pTexInfo = &file.texinfo[ file.dfaces[iCountFace].texinfo ];
  103. if( !(pTexInfo->flags & SURF_NODRAW) )
  104. {
  105. ++nFaces;
  106. nVerts += file.dfaces[iCountFace].numedges;
  107. usedFaces[iCountFace] = 1;
  108. }
  109. }
  110. }
  111. CUtlVector<CFace> faces;
  112. faces.SetSize( nFaces );
  113. CUtlVector<CVert> verts;
  114. verts.SetSize( nVerts );
  115. m_StoredFaces.SetSize( nFaces );
  116. InitMaterialLUT( file );
  117. // Make lightmaps and translate the map faces over..
  118. IMaterialSystem *pMatSys = MaterialSystemInterface();
  119. // Add the BSP file as a search path so our FindMaterial calls will get
  120. // VMFs embedded in the BSP file.
  121. g_pFullFileSystem->AddSearchPath( pFilename, "GAME" );
  122. m_nTotalTris = 0;
  123. int iOutVert = 0;
  124. int iOutFace = 0;
  125. for( int iFace=0; iFace < file.numfaces; iFace++ )
  126. {
  127. dface_t *pIn = &file.dfaces[iFace];
  128. if( !usedFaces[iFace] )
  129. {
  130. continue;
  131. }
  132. CFace *pOut = &faces[iOutFace];
  133. CStoredFace *pStoredFace = &m_StoredFaces[iOutFace];
  134. ++iOutFace;
  135. pStoredFace->m_iMapFace = iFace;
  136. pStoredFace->m_pFace = pOut;
  137. pOut->m_pDFace = pIn;
  138. pOut->m_pStoredFace = pStoredFace;
  139. // Get its material.
  140. texinfo_t *pTexInfo = &file.texinfo[pIn->texinfo];
  141. dtexdata_t *pTexData = &file.dtexdata[pTexInfo->texdata];
  142. pStoredFace->m_pMaterial = FindOrAddMaterial( file, pTexData->nameStringTableID );
  143. if( pStoredFace->m_pMaterial )
  144. pStoredFace->m_pMaterial->m_Faces.AddToTail( pStoredFace );
  145. // Setup its lightmap.
  146. memcpy( pOut->m_LightmapVecs, file.texinfo[pIn->texinfo].lightmapVecsLuxelsPerWorldUnits, sizeof(pOut->m_LightmapVecs) );
  147. memcpy( pOut->m_LightmapTextureMinsInLuxels, pIn->m_LightmapTextureMinsInLuxels, sizeof(pOut->m_LightmapTextureMinsInLuxels) );
  148. pStoredFace->m_LightmapSize[0] = pIn->m_LightmapTextureSizeInLuxels[0]+1;
  149. pStoredFace->m_LightmapSize[1] = pIn->m_LightmapTextureSizeInLuxels[1]+1;
  150. // Setup the verts.
  151. pOut->m_iVertStart = iOutVert;
  152. pOut->m_nVerts = pIn->numedges;
  153. for( int iEdge=0; iEdge < pIn->numedges; iEdge++ )
  154. {
  155. int edgeVal = file.dsurfedges[ pIn->firstedge + iEdge ];
  156. if( edgeVal < 0 )
  157. verts[pOut->m_iVertStart+iEdge].m_vPos = file.dvertexes[ file.dedges[-edgeVal].v[1] ].point;
  158. else
  159. verts[pOut->m_iVertStart+iEdge].m_vPos = file.dvertexes[ file.dedges[edgeVal].v[0] ].point;
  160. }
  161. m_nTotalTris += pOut->m_nVerts - 2;
  162. iOutVert += pOut->m_nVerts;
  163. pOut->m_iDispInfo = pIn->dispinfo;
  164. }
  165. g_pFullFileSystem->RemoveSearchPath( pFilename, "GAME" );
  166. // Allocate lightmaps.. must be grouped by material.
  167. pMatSys->ResetMaterialLightmapPageInfo();
  168. pMatSys->BeginLightmapAllocation();
  169. FOR_EACH_LL( m_FaceMaterials, iMat )
  170. {
  171. CFaceMaterial *pMat = m_FaceMaterials[iMat];
  172. bool bNeedsBumpmap = pMat->m_pMaterial->GetPropertyFlag( MATERIAL_PROPERTY_NEEDS_BUMPED_LIGHTMAPS );
  173. FOR_EACH_LL( pMat->m_Faces, iFace )
  174. {
  175. CStoredFace *pStoredFace = pMat->m_Faces[iFace];
  176. CFace *pOut = pStoredFace->m_pFace;
  177. int bumpedSize = pStoredFace->m_LightmapSize[0];
  178. if( bNeedsBumpmap )
  179. bumpedSize *= 4;
  180. pOut->m_LightmapSortID = pMatSys->AllocateLightmap(
  181. bumpedSize,
  182. pStoredFace->m_LightmapSize[1],
  183. pStoredFace->m_OffsetIntoLightmapPage,
  184. pMat->m_pMaterial );
  185. }
  186. }
  187. pMatSys->EndLightmapAllocation();
  188. // Get sort IDs from the material system.
  189. CUtlVector<MaterialSystem_SortInfo_t> sortInfos;
  190. sortInfos.SetSize( pMatSys->GetNumSortIDs() );
  191. pMatSys->GetSortInfo( sortInfos.Base() );
  192. for( int iFace=0; iFace < faces.Count(); iFace++ )
  193. {
  194. m_StoredFaces[iFace].m_LightmapPageID = sortInfos[faces[iFace].m_LightmapSortID].lightmapPageID;
  195. }
  196. // Setup the gamma table.
  197. BuildGammaTable( 2.2f, 2.2f, 0, 1 );
  198. // Set lightmap texture coordinates.
  199. for( int iFace=0; iFace < faces.Count(); iFace++ )
  200. {
  201. CFace *pFace = &faces[iFace];
  202. CStoredFace *pStoredFace = &m_StoredFaces[iFace];
  203. texinfo_t *pTexInfo = &file.texinfo[pFace->m_pDFace->texinfo];
  204. int lightmapPageSize[2];
  205. pMatSys->GetLightmapPageSize( pFace->m_pStoredFace->m_LightmapPageID, &lightmapPageSize[0], &lightmapPageSize[1] );
  206. pStoredFace->m_BumpSTexCoordOffset = (float)pStoredFace->m_LightmapSize[0] / lightmapPageSize[0];
  207. // Set its texture coordinates.
  208. for( int iVert=0; iVert < pFace->m_nVerts; iVert++ )
  209. {
  210. CVert *pVert = &verts[ pFace->m_iVertStart + iVert ];
  211. Vector &vPos = pVert->m_vPos;
  212. for( int iCoord=0; iCoord < 2; iCoord++ )
  213. {
  214. float *lmVec = pFace->m_LightmapVecs[iCoord];
  215. float flVal = lmVec[0]*vPos[0] + lmVec[1]*vPos[1] + lmVec[2]*vPos[2] + lmVec[3] - pFace->m_LightmapTextureMinsInLuxels[iCoord];
  216. flVal += pFace->m_pStoredFace->m_OffsetIntoLightmapPage[iCoord];
  217. flVal += 0.5f; // bilinear...
  218. flVal /= lightmapPageSize[iCoord];
  219. Assert( _finite(flVal) );
  220. pVert->m_vLightCoords[iCoord] = flVal;
  221. pVert->m_vTexCoords[iCoord] =
  222. DotProduct( vPos, *((Vector*)pTexInfo->textureVecsTexelsPerWorldUnits[iCoord]) ) +
  223. pTexInfo->textureVecsTexelsPerWorldUnits[iCoord][3];
  224. if( pStoredFace->m_pMaterial )
  225. {
  226. if( iCoord == 0 )
  227. pVert->m_vTexCoords[iCoord] /= pStoredFace->m_pMaterial->m_pMaterial->GetMappingWidth();
  228. else
  229. pVert->m_vTexCoords[iCoord] /= pStoredFace->m_pMaterial->m_pMaterial->GetMappingHeight();
  230. }
  231. }
  232. }
  233. }
  234. // Create displacements.
  235. CUtlVector<CDispInfoFaces> dispInfos;
  236. CreateDisplacements( file, faces, dispInfos );
  237. BuildLMGroups( file, faces, verts, dispInfos );
  238. BuildDrawCommands();
  239. ReloadLightmaps();
  240. return true;
  241. }
  242. void CBSPLighting::Term()
  243. {
  244. if( m_pBSPLightingThread )
  245. {
  246. m_pBSPLightingThread->Release();
  247. m_pBSPLightingThread = 0;
  248. }
  249. m_nTotalTris = 0;
  250. if( m_hVRadDLL )
  251. {
  252. if( m_pVRadDLL )
  253. {
  254. // Save the .r0 and .bsp files.
  255. m_pVRadDLL->Serialize();
  256. m_pVRadDLL->Release();
  257. m_pVRadDLL = 0;
  258. }
  259. Sys_UnloadModule( m_hVRadDLL );
  260. m_hVRadDLL = 0;
  261. }
  262. m_StoredFaces.Purge();
  263. }
  264. bool CBSPLighting::Serialize()
  265. {
  266. if( m_pBSPLightingThread )
  267. {
  268. // Only serialize if we're not currently in the middle of lighting.
  269. if( m_pBSPLightingThread->GetCurrentState() == IBSPLightingThread::STATE_FINISHED )
  270. return m_pVRadDLL->Serialize();
  271. }
  272. return false;
  273. }
  274. void CBSPLighting::StartLighting( char const *pVMFFileWithEnts )
  275. {
  276. if( m_pBSPLightingThread )
  277. {
  278. m_pBSPLightingThread->StartLighting( pVMFFileWithEnts );
  279. m_bLightingInProgress = true;
  280. }
  281. }
  282. float CBSPLighting::GetPercentComplete()
  283. {
  284. if( m_bLightingInProgress && m_pBSPLightingThread )
  285. return m_pBSPLightingThread->GetPercentComplete();
  286. else
  287. return -1;
  288. }
  289. void CBSPLighting::Interrupt()
  290. {
  291. if( m_pBSPLightingThread )
  292. m_pBSPLightingThread->Interrupt();
  293. }
  294. bool CBSPLighting::CheckForNewLightmaps()
  295. {
  296. if( !m_pBSPLightingThread )
  297. return false;
  298. // Has it finished lighting?
  299. int curState = m_pBSPLightingThread->GetCurrentState();
  300. if( m_bLightingInProgress )
  301. {
  302. if( curState == IBSPLightingThread::STATE_FINISHED )
  303. {
  304. m_bLightingInProgress = false;
  305. ReloadLightmaps();
  306. return true;
  307. }
  308. else if( curState == IBSPLightingThread::STATE_IDLE )
  309. {
  310. m_bLightingInProgress = false;
  311. }
  312. }
  313. return false;
  314. }
  315. #define DRAWLIGHTMAPPAGE
  316. #if defined( DRAWLIGHTMAPPAGE )
  317. void DrawLightmapPage( IMaterialSystem *materialSystemInterface, int lightmapPageID )
  318. {
  319. IMaterial *g_materialDebugLightmap = materialSystemInterface->FindMaterial( "debug/debuglightmap", TEXTURE_GROUP_OTHER );
  320. // assumes that we are already in ortho mode.
  321. int lightmapPageWidth, lightmapPageHeight;
  322. CMatRenderContextPtr pRenderContext( materialSystemInterface );
  323. IMesh* pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, g_materialDebugLightmap );
  324. materialSystemInterface->GetLightmapPageSize( lightmapPageID, &lightmapPageWidth, &lightmapPageHeight );
  325. pRenderContext->BindLightmapPage( lightmapPageID );
  326. CMeshBuilder meshBuilder;
  327. meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 );
  328. // texcoord 1 is lightmaptexcoord for fixed function.
  329. static int yOffset = 30;
  330. meshBuilder.TexCoord2f( 1, 0.0f, 0.0f );
  331. meshBuilder.Position3f( 0.0f, yOffset, 0.0f );
  332. meshBuilder.AdvanceVertex();
  333. meshBuilder.TexCoord2f( 1, 1.0f, 0.0f );
  334. meshBuilder.Position3f( lightmapPageWidth, yOffset, 0.0f );
  335. meshBuilder.AdvanceVertex();
  336. meshBuilder.TexCoord2f( 1, 1.0f, 1.0f );
  337. meshBuilder.Position3f( lightmapPageWidth, yOffset+lightmapPageHeight, 0.0f );
  338. meshBuilder.AdvanceVertex();
  339. meshBuilder.TexCoord2f( 1, 0.0f, 1.0f );
  340. meshBuilder.Position3f( 0.0f, yOffset+lightmapPageHeight, 0.0f );
  341. meshBuilder.AdvanceVertex();
  342. meshBuilder.End();
  343. pMesh->Draw();
  344. }
  345. #endif
  346. void CBSPLighting::Draw()
  347. {
  348. if( m_FaceMaterials.Count() == 0 )
  349. return;
  350. IMaterialSystem *pMatSys = MaterialSystemInterface();
  351. if( !pMatSys )
  352. return;
  353. CMatRenderContextPtr pRenderContext( pMatSys );
  354. CheckForNewLightmaps();
  355. pRenderContext->Flush();
  356. #if defined( DRAWLIGHTMAPPAGE )
  357. static bool bDrawIt = false;
  358. if( bDrawIt )
  359. {
  360. pRenderContext->MatrixMode( MATERIAL_VIEW );
  361. pRenderContext->PushMatrix();
  362. pRenderContext->LoadIdentity();
  363. pRenderContext->MatrixMode( MATERIAL_MODEL );
  364. pRenderContext->PushMatrix();
  365. pRenderContext->LoadIdentity();
  366. pRenderContext->MatrixMode( MATERIAL_PROJECTION );
  367. pRenderContext->PushMatrix();
  368. pRenderContext->LoadIdentity();
  369. pRenderContext->Ortho( 0, 0, 300, 300, -99999, 99999 );
  370. static int iPageToDraw = 0;
  371. DrawLightmapPage( MaterialSystemInterface(), iPageToDraw );
  372. pRenderContext->MatrixMode( MATERIAL_VIEW );
  373. pRenderContext->PopMatrix();
  374. pRenderContext->MatrixMode( MATERIAL_MODEL );
  375. pRenderContext->PopMatrix();
  376. pRenderContext->MatrixMode( MATERIAL_PROJECTION );
  377. pRenderContext->PopMatrix();
  378. }
  379. #endif
  380. // Draw everything from each material.
  381. FOR_EACH_LL( m_FaceMaterials, iMat )
  382. {
  383. CFaceMaterial *pMat = m_FaceMaterials[iMat];
  384. pRenderContext->Bind( pMat->m_pMaterial );
  385. FOR_EACH_LL( pMat->m_MaterialBufs, iBuf )
  386. {
  387. CMaterialBuf *pBuf = pMat->m_MaterialBufs[iBuf];
  388. for( int iCmd=0; iCmd < pBuf->m_DrawCommands.Count(); iCmd++ )
  389. {
  390. CDrawCommand *pCmd = pBuf->m_DrawCommands[iCmd];
  391. pRenderContext->BindLightmapPage( pCmd->m_LightmapPageID );
  392. pBuf->m_pMesh->Draw( pCmd->m_PrimLists.Base(), pCmd->m_PrimLists.Count() );
  393. }
  394. }
  395. }
  396. pRenderContext->Flush();
  397. }
  398. void CBSPLighting::AssignFaceMaterialCounts(
  399. CBSPInfo &file,
  400. CUtlVector<CFace> &faces )
  401. {
  402. FOR_EACH_LL( m_FaceMaterials, i )
  403. {
  404. CFaceMaterial *pMat = m_FaceMaterials[i];
  405. // Start off an initial CMaterialBuf to dump the faces in.
  406. CMaterialBuf *pBuf = new CMaterialBuf;
  407. pMat->m_MaterialBufs.AddToTail( pBuf );
  408. FOR_EACH_LL( pMat->m_Faces, iFace )
  409. {
  410. CStoredFace *pStoredFace = pMat->m_Faces[iFace];
  411. CFace *pFace = pStoredFace->m_pFace;
  412. pStoredFace->m_iFirstIndex = pBuf->m_nIndices;
  413. if( pFace->m_iDispInfo == -1 )
  414. {
  415. pStoredFace->m_nIndices = (pFace->m_nVerts - 2) * 3;
  416. pBuf->m_nIndices += (pFace->m_nVerts - 2) * 3;
  417. pBuf->m_nVerts += pFace->m_nVerts;
  418. }
  419. else
  420. {
  421. ddispinfo_t *pDisp = &file.g_dispinfo[pFace->m_iDispInfo];
  422. int nTris = Square( 1 << pDisp->power ) * 2;
  423. int nVerts = Square( (1 << pDisp->power) + 1 );
  424. pStoredFace->m_nIndices = nTris * 3;
  425. pBuf->m_nIndices += nTris * 3;
  426. pBuf->m_nVerts += nVerts;
  427. }
  428. pBuf->m_Faces.AddToTail( pStoredFace );
  429. // Don't make the buffers too big..
  430. if( pBuf->m_nIndices > (16*1024) || pBuf->m_nVerts > (16*1024) )
  431. {
  432. pBuf = new CMaterialBuf;
  433. pMat->m_MaterialBufs.AddToTail( pBuf );
  434. }
  435. }
  436. }
  437. }
  438. //-----------------------------------------------------------------------------
  439. // Determines the appropriate vertex format for LMGroup meshes
  440. //-----------------------------------------------------------------------------
  441. VertexFormat_t CBSPLighting::ComputeLMGroupVertexFormat( IMaterial * pMaterial )
  442. {
  443. VertexFormat_t vertexFormat = pMaterial->GetVertexFormat();
  444. // FIXME: set VERTEX_FORMAT_COMPRESSED if there are no artifacts and if it saves enough memory (use 'mem_dumpvballocs')
  445. vertexFormat &= ~VERTEX_FORMAT_COMPRESSED;
  446. // FIXME: check for and strip unused vertex elements (bone weights+indices, TANGENT_S/T?) - requires reliable material vertex formats first
  447. return vertexFormat;
  448. }
  449. void CBSPLighting::BuildLMGroups(
  450. CBSPInfo &file,
  451. CUtlVector<CFace> &faces,
  452. CUtlVector<CVert> &verts,
  453. CUtlVector<CDispInfoFaces> &dispInfos
  454. )
  455. {
  456. // Count everything in each CFaceMaterial.
  457. AssignFaceMaterialCounts( file, faces );
  458. IMaterialSystem *pMatSys = MaterialSystemInterface();
  459. if( !pMatSys )
  460. return;
  461. CMatRenderContextPtr pRenderContext( pMatSys );
  462. // Now create the static buffers.
  463. FOR_EACH_LL( m_FaceMaterials, iMat )
  464. {
  465. CFaceMaterial *pMat = m_FaceMaterials[iMat];
  466. FOR_EACH_LL( pMat->m_MaterialBufs, iBuf )
  467. {
  468. CMaterialBuf *pBuf = pMat->m_MaterialBufs[iBuf];
  469. VertexFormat_t vertexFormat = ComputeLMGroupVertexFormat( pMat->m_pMaterial );
  470. pBuf->m_pMesh = pRenderContext->CreateStaticMesh( vertexFormat, "terd", pMat->m_pMaterial );
  471. if( !pBuf->m_pMesh )
  472. continue;
  473. bool bNeedsBumpmap = pMat->m_pMaterial->GetPropertyFlag( MATERIAL_PROPERTY_NEEDS_BUMPED_LIGHTMAPS );
  474. CMeshBuilder mb;
  475. mb.Begin( pBuf->m_pMesh, MATERIAL_TRIANGLES, pBuf->m_nVerts, pBuf->m_nIndices );
  476. // Write all the faces in.
  477. int iCurBaseVert = 0;
  478. FOR_EACH_LL( pBuf->m_Faces, iFace )
  479. {
  480. CStoredFace *pStoredFace = pBuf->m_Faces[iFace];
  481. CFace *pFace = pStoredFace->m_pFace;
  482. if( pFace->m_iDispInfo == -1 )
  483. {
  484. // It's a regular face.
  485. CVert *pVerts = &verts[pFace->m_iVertStart];
  486. for( int iVert=0; iVert < pFace->m_nVerts; iVert++ )
  487. {
  488. mb.Position3fv( (float*)&pVerts[iVert].m_vPos );
  489. mb.TexCoord2fv( 0, pVerts[iVert].m_vTexCoords.Base() );
  490. mb.TexCoord2fv( 1, pVerts[iVert].m_vLightCoords.Base() );
  491. if( bNeedsBumpmap )
  492. mb.TexCoord2f ( 2, pStoredFace->m_BumpSTexCoordOffset, 0 );
  493. mb.Color3f( 1,1,1 );
  494. mb.AdvanceVertex();
  495. }
  496. // Write the indices.
  497. for( int iTri=0; iTri < pFace->m_nVerts-2; iTri++ )
  498. {
  499. mb.Index( iCurBaseVert ); mb.AdvanceIndex();
  500. mb.Index( iCurBaseVert+iTri+1 ); mb.AdvanceIndex();
  501. mb.Index( iCurBaseVert+iTri+2 ); mb.AdvanceIndex();
  502. }
  503. iCurBaseVert += pFace->m_nVerts;
  504. }
  505. else
  506. {
  507. // It's a displacement.
  508. CDispInfoFaces *pDisp = &dispInfos[pFace->m_iDispInfo];
  509. // Generate the index list.
  510. unsigned short indices[ (1<<MAX_MAP_DISP_POWER) * (1<<MAX_MAP_DISP_POWER) * 6 ];
  511. int nRequired = DispCommon_GetNumTriIndices( pDisp->m_Power );
  512. Assert( nRequired <= sizeof(indices)/sizeof(indices[0]) );
  513. DispCommon_GenerateTriIndices( pDisp->m_Power, indices );
  514. for( int iIndex=0; iIndex < nRequired; iIndex++ )
  515. {
  516. mb.Index( indices[iIndex] + iCurBaseVert );
  517. mb.AdvanceIndex();
  518. }
  519. // Generate the vert list.
  520. for( int iVert=0; iVert < pDisp->m_Verts.Count(); iVert++ )
  521. {
  522. mb.Position3fv( (float*)&pDisp->m_Verts[iVert].m_vPos );
  523. mb.TexCoord2fv( 0, (float*)&pDisp->m_Verts[iVert].m_vTexCoords );
  524. mb.TexCoord2fv( 1, (float*)&pDisp->m_Verts[iVert].m_vLightCoords );
  525. if( bNeedsBumpmap )
  526. mb.TexCoord2f ( 2, pStoredFace->m_BumpSTexCoordOffset, 0 );
  527. mb.AdvanceVertex();
  528. }
  529. iCurBaseVert += pDisp->m_Verts.Count();;
  530. }
  531. }
  532. mb.End();
  533. }
  534. }
  535. }
  536. bool FindDrawCommand( CUtlVector<CBSPLighting::CDrawCommand*> &drawCommands, int lmPageID, int &index )
  537. {
  538. for( int i=0; i < drawCommands.Count(); i++ )
  539. {
  540. if( drawCommands[i]->m_LightmapPageID == lmPageID )
  541. {
  542. index = i;
  543. return true;
  544. }
  545. }
  546. return false;
  547. }
  548. void CBSPLighting::BuildDrawCommands()
  549. {
  550. FOR_EACH_LL( m_FaceMaterials, iMat )
  551. {
  552. CFaceMaterial *pMat = m_FaceMaterials[iMat];
  553. FOR_EACH_LL( pMat->m_MaterialBufs, iBuf )
  554. {
  555. CMaterialBuf *pBuf = pMat->m_MaterialBufs[iBuf];
  556. // Group by lightmap page IDs.
  557. FOR_EACH_LL( pBuf->m_Faces, iFace )
  558. {
  559. CStoredFace *pFace = pBuf->m_Faces[iFace];
  560. int index;
  561. if( !FindDrawCommand( pBuf->m_DrawCommands, pFace->m_LightmapPageID, index ) )
  562. {
  563. index = pBuf->m_DrawCommands.AddToTail( new CDrawCommand );
  564. pBuf->m_DrawCommands[index]->m_LightmapPageID = pFace->m_LightmapPageID;
  565. }
  566. CPrimList primList;
  567. primList.m_FirstIndex = pFace->m_iFirstIndex;
  568. primList.m_NumIndices = pFace->m_nIndices;
  569. pBuf->m_DrawCommands[index]->m_PrimLists.AddToTail( primList );
  570. }
  571. }
  572. }
  573. }
  574. void CBSPLighting::ReloadLightmaps()
  575. {
  576. if( !m_pVRadDLL )
  577. return;
  578. IMaterialSystem *pMatSys = MaterialSystemInterface();
  579. if( !pMatSys )
  580. return;
  581. CBSPInfo bspInfo;
  582. m_pVRadDLL->GetBSPInfo( &bspInfo );
  583. if( !bspInfo.lightdatasize )
  584. return;
  585. Vector4D blocklights[4][MAX_LIGHTMAP_DIM_INCLUDING_BORDER * MAX_LIGHTMAP_DIM_INCLUDING_BORDER];
  586. for( int iFace=0; iFace < m_StoredFaces.Count(); iFace++ )
  587. {
  588. CStoredFace *pFace = &m_StoredFaces[iFace];
  589. // Avoid updating lightmaps in faces that weren't touched.
  590. if( bspInfo.m_pFacesTouched && !bspInfo.m_pFacesTouched[pFace->m_iMapFace] )
  591. continue;
  592. dface_t *pIn = &bspInfo.dfaces[ pFace->m_iMapFace ];
  593. int nLuxels = pFace->m_LightmapSize[0] * pFace->m_LightmapSize[1];
  594. bool bNeedsBumpmap = pFace->m_pMaterial->m_pMaterial->GetPropertyFlag( MATERIAL_PROPERTY_NEEDS_BUMPED_LIGHTMAPS );
  595. texinfo_t *pTexInfo = &bspInfo.texinfo[ bspInfo.dfaces[pFace->m_iMapFace].texinfo ];
  596. bool bHasBumpmap = SurfHasBumpedLightmaps( pTexInfo->flags );
  597. int nLightmaps = 1;
  598. if( bNeedsBumpmap && bHasBumpmap )
  599. nLightmaps = 4;
  600. ColorRGBExp32 *pLightmap = (ColorRGBExp32 *)&bspInfo.dlightdata[pIn->lightofs];
  601. int iLightmap;
  602. for( iLightmap=0; iLightmap < nLightmaps; iLightmap++ )
  603. {
  604. for( int iLuxel=0; iLuxel < nLuxels; iLuxel++ )
  605. {
  606. blocklights[iLightmap][iLuxel][0] = TexLightToLinear( pLightmap->r, pLightmap->exponent );
  607. blocklights[iLightmap][iLuxel][1] = TexLightToLinear( pLightmap->g, pLightmap->exponent );
  608. blocklights[iLightmap][iLuxel][2] = TexLightToLinear( pLightmap->b, pLightmap->exponent );
  609. blocklights[iLightmap][iLuxel][3] = 1;
  610. ++pLightmap;
  611. }
  612. }
  613. // If it needs bumpmaps but doesn't have them in the file, then just copy
  614. // the lightmap data into the other lightmaps like the engine does.
  615. if( bNeedsBumpmap && !bHasBumpmap )
  616. {
  617. for( iLightmap=1; iLightmap < 4; iLightmap++ )
  618. {
  619. memcpy( blocklights[iLightmap], blocklights[0], nLuxels * sizeof( blocklights[0][0] ) );
  620. }
  621. }
  622. if( bNeedsBumpmap )
  623. {
  624. pMatSys->UpdateLightmap(
  625. pFace->m_LightmapPageID,
  626. pFace->m_LightmapSize,
  627. pFace->m_OffsetIntoLightmapPage,
  628. (float*)blocklights[0], (float*)blocklights[1], (float*)blocklights[2], (float*)blocklights[3] );
  629. }
  630. else
  631. {
  632. pMatSys->UpdateLightmap(
  633. pFace->m_LightmapPageID,
  634. pFace->m_LightmapSize,
  635. pFace->m_OffsetIntoLightmapPage,
  636. (float*)blocklights[0], NULL, NULL, NULL );
  637. }
  638. }
  639. }
  640. bool CBSPLighting::LoadVRADDLL( char const *pFilename )
  641. {
  642. // Load VRAD's DLL.
  643. m_hVRadDLL = Sys_LoadModule( "vrad_dll.dll" );
  644. if( !m_hVRadDLL )
  645. return false;
  646. CreateInterfaceFn fn = Sys_GetFactory( m_hVRadDLL );
  647. if( !fn )
  648. return false;
  649. int retCode = 0;
  650. m_pVRadDLL = (IVRadDLL*)fn( VRAD_INTERFACE_VERSION, &retCode );
  651. if( !m_pVRadDLL )
  652. return false;
  653. // Tell VRAD to load the BSP file.
  654. if( !m_pVRadDLL->Init( pFilename ) )
  655. return false;
  656. return true;
  657. }
  658. void CBSPLighting::CreateDisplacements( CBSPInfo &file, CUtlVector<CFace> &faces, CUtlVector<CDispInfoFaces> &dispInfos )
  659. {
  660. /*
  661. IMaterialSystem *pMatSys = MaterialSystemInterface();
  662. dispInfos.SetSize( file.g_numdispinfo );
  663. for( int iFace=0; iFace < faces.Size(); iFace++ )
  664. {
  665. CFace *pFace = &faces[iFace];
  666. CStoredFace *pStoredFace = &m_StoredFaces[iFace];
  667. dface_t *pInFace = pFace->m_pDFace;
  668. if( pInFace->dispinfo == -1 )
  669. continue;
  670. ddispinfo_t *pInDisp = &file.g_dispinfo[pInFace->dispinfo];
  671. CDispInfoFaces *pOutDisp = &dispInfos[pInFace->dispinfo];
  672. pOutDisp->m_Power = pInDisp->power;
  673. int nVertsPerSide = (1 << pInDisp->power) + 1;
  674. pOutDisp->m_Verts.SetSize( pInDisp->m_LODs[0].m_nVerts );
  675. int lightmapPageSize[2];
  676. pMatSys->GetLightmapPageSize( pFace->m_pStoredFace->m_LightmapPageID, &lightmapPageSize[0], &lightmapPageSize[1] );
  677. for( int iVert=0; iVert < pInDisp->m_LODs[0].m_nVerts; iVert++ )
  678. {
  679. ddisp_lod_vert_t *pInVert = &file.ddispverts[ pInDisp->m_LODs[0].m_iVertStart + iVert ];
  680. CVert *pOutVert = &pOutDisp->m_Verts[iVert];
  681. pOutVert->m_vPos = pInVert->m_vPos;
  682. for( int iCoord=0; iCoord < 2; iCoord++ )
  683. {
  684. float flVal = pInVert->m_LightCoords[iCoord];
  685. flVal += pFace->m_pStoredFace->m_OffsetIntoLightmapPage[iCoord];
  686. flVal += 0.5f;
  687. flVal /= lightmapPageSize[iCoord];
  688. Assert( _finite(flVal) );
  689. pOutVert->m_vLightCoords[iCoord] = flVal;
  690. pOutVert->m_vTexCoords[iCoord] = pInVert->m_TexCoords[iCoord];
  691. if( iCoord == 0 )
  692. pOutVert->m_vTexCoords[iCoord] /= pStoredFace->m_pMaterial->m_pMaterial->GetMappingWidth();
  693. else
  694. pOutVert->m_vTexCoords[iCoord] /= pStoredFace->m_pMaterial->m_pMaterial->GetMappingHeight();
  695. }
  696. }
  697. }
  698. */
  699. }
  700. void CBSPLighting::InitMaterialLUT( CBSPInfo &file )
  701. {
  702. m_StringTableIDToMaterial.SetSize( file.nTexDataStringTable );
  703. for( int i=0; i < m_StringTableIDToMaterial.Count(); i++ )
  704. m_StringTableIDToMaterial[i] = 0;
  705. }
  706. CBSPLighting::CFaceMaterial* CBSPLighting::FindOrAddMaterial( CBSPInfo &file, int stringTableID )
  707. {
  708. if( stringTableID >= m_StringTableIDToMaterial.Count() )
  709. {
  710. Assert( false );
  711. return 0;
  712. }
  713. if( m_StringTableIDToMaterial[stringTableID] )
  714. {
  715. return m_StringTableIDToMaterial[stringTableID];
  716. }
  717. else
  718. {
  719. IMaterial *pMaterial = 0;
  720. char *pMaterialName = &file.texDataStringData[ file.texDataStringTable[ stringTableID ] ];
  721. if( pMaterialName )
  722. pMaterial = MaterialSystemInterface()->FindMaterial( pMaterialName, TEXTURE_GROUP_OTHER );
  723. // Don't add CFaceMaterials without a material.
  724. if( !pMaterial )
  725. return 0;
  726. // This is lovely. We have to call this stuff to get it to precalculate the data it needs.
  727. pMaterial->GetMappingHeight();
  728. pMaterial->RecomputeStateSnapshots();
  729. CFaceMaterial *pMat = new CFaceMaterial;
  730. if( pMaterial->IsTranslucent() )
  731. m_FaceMaterials.AddToTail( pMat );
  732. else
  733. m_FaceMaterials.AddToHead( pMat );
  734. pMat->m_pMaterial = pMaterial;
  735. m_StringTableIDToMaterial[stringTableID] = pMat;
  736. return pMat;
  737. }
  738. }
  739. IBSPLighting* CreateBSPLighting()
  740. {
  741. return new CBSPLighting;
  742. }