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.

971 lines
25 KiB

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