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.

2465 lines
89 KiB

  1. //========== Copyright (c) Valve Corporation, All rights reserved. ========
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include "pch_materialsystem.h"
  7. #ifndef _PS3
  8. #define MATSYS_INTERNAL
  9. #endif
  10. #include "cmatlightmaps.h"
  11. #include "colorspace.h"
  12. #include "IHardwareConfigInternal.h"
  13. #include "cmaterialsystem.h"
  14. // NOTE: This must be the last file included!!!
  15. #include "tier0/memdbgon.h"
  16. #include "bitmap/floatbitmap.h"
  17. static ConVar mat_lightmap_pfms( "mat_lightmap_pfms", "0", FCVAR_MATERIAL_SYSTEM_THREAD, "Outputs .pfm files containing lightmap data for each lightmap page when a level exits." ); // Write PFM files for each lightmap page in the game directory when exiting a level
  18. // Turning off 32 bit lightmaps for Portal 2, to save shader perf --Thorsten
  19. //#define USE_32BIT_LIGHTMAPS_ON_360 //uncomment to use 32bit lightmaps, be sure to keep this in sync with the same #define in stdshaders/lightmappedgeneric_ps2_3_x.h
  20. #ifdef _X360
  21. // 7LS - fixup support for lightmap alpha channel data for csm's, definitely do this when/if turning dynamic lightmaps back on
  22. // #define X360_USE_SIMD_LIGHTMAP
  23. #endif
  24. //-----------------------------------------------------------------------------
  25. inline IMaterialInternal* CMatLightmaps::GetCurrentMaterialInternal() const
  26. {
  27. return GetMaterialSystem()->GetRenderContextInternal()->GetCurrentMaterialInternal();
  28. }
  29. inline void CMatLightmaps::SetCurrentMaterialInternal(IMaterialInternal* pCurrentMaterial)
  30. {
  31. return GetMaterialSystem()->GetRenderContextInternal()->SetCurrentMaterialInternal( pCurrentMaterial );
  32. }
  33. inline IMaterialInternal *CMatLightmaps::GetMaterialInternal( MaterialHandle_t idx ) const
  34. {
  35. return GetMaterialSystem()->GetMaterialInternal( idx );
  36. }
  37. inline const IMatRenderContextInternal *CMatLightmaps::GetRenderContextInternal() const
  38. {
  39. return GetMaterialSystem()->GetRenderContextInternal();
  40. }
  41. inline IMatRenderContextInternal *CMatLightmaps::GetRenderContextInternal()
  42. {
  43. return GetMaterialSystem()->GetRenderContextInternal();
  44. }
  45. inline const CMaterialDict *CMatLightmaps::GetMaterialDict() const
  46. {
  47. return GetMaterialSystem()->GetMaterialDict();
  48. }
  49. inline CMaterialDict *CMatLightmaps::GetMaterialDict()
  50. {
  51. return GetMaterialSystem()->GetMaterialDict();
  52. }
  53. //-----------------------------------------------------------------------------
  54. //
  55. //-----------------------------------------------------------------------------
  56. CMatLightmaps::CMatLightmaps()
  57. {
  58. m_currentWhiteLightmapMaterial = NULL;
  59. m_pLightmapPages = NULL;
  60. m_NumLightmapPages = 0;
  61. m_numSortIDs = 0;
  62. m_nUpdatingLightmapsStackDepth = 0;
  63. m_nLockedLightmap = -1;
  64. m_pLightmapDataPtrArray = NULL;
  65. m_eLightmapsState = STATE_DEFAULT;
  66. }
  67. //-----------------------------------------------------------------------------
  68. //
  69. //-----------------------------------------------------------------------------
  70. void CMatLightmaps::Shutdown( )
  71. {
  72. // Clean up all lightmaps
  73. CleanupLightmaps();
  74. }
  75. //-----------------------------------------------------------------------------
  76. // Assign enumeration IDs to all materials
  77. //-----------------------------------------------------------------------------
  78. void CMatLightmaps::EnumerateMaterials( void )
  79. {
  80. // iterate in sorted order
  81. int id = 0;
  82. for (MaterialHandle_t i = GetMaterialDict()->FirstMaterial(); i != GetMaterialDict()->InvalidMaterial(); i = GetMaterialDict()->NextMaterial(i) )
  83. {
  84. GetMaterialInternal(i)->SetEnumerationID( id );
  85. ++id;
  86. }
  87. }
  88. //-----------------------------------------------------------------------------
  89. // Gets the maximum lightmap page size...
  90. //-----------------------------------------------------------------------------
  91. int CMatLightmaps::GetMaxLightmapPageWidth() const
  92. {
  93. // FIXME: It's unclear which we want here.
  94. // It doesn't drastically increase primitives per DrawIndexedPrimitive
  95. // call at the moment to increase it, so let's not for now.
  96. // If we're using dynamic textures though, we want bigger that's for sure.
  97. // The tradeoff here is how much memory we waste if we don't fill the lightmap
  98. // We need to go to 512x256 textures because that's the only way bumped
  99. // lighting on displacements can work given the 128x128 allowance..
  100. int nWidth = 512;
  101. if ( nWidth > HardwareConfig()->MaxTextureWidth() )
  102. nWidth = HardwareConfig()->MaxTextureWidth();
  103. return nWidth;
  104. }
  105. //-----------------------------------------------------------------------------
  106. //
  107. //-----------------------------------------------------------------------------
  108. int CMatLightmaps::GetMaxLightmapPageHeight() const
  109. {
  110. int nHeight = 256;
  111. if ( nHeight > HardwareConfig()->MaxTextureHeight() )
  112. nHeight = HardwareConfig()->MaxTextureHeight();
  113. return nHeight;
  114. }
  115. //-----------------------------------------------------------------------------
  116. // Returns the lightmap page size
  117. //-----------------------------------------------------------------------------
  118. void CMatLightmaps::GetLightmapPageSize( int lightmapPageID, int *pWidth, int *pHeight ) const
  119. {
  120. switch( lightmapPageID )
  121. {
  122. default:
  123. Assert( lightmapPageID >= 0 && lightmapPageID < GetNumLightmapPages() );
  124. *pWidth = m_pLightmapPages[lightmapPageID].m_Width;
  125. *pHeight = m_pLightmapPages[lightmapPageID].m_Height;
  126. break;
  127. case MATERIAL_SYSTEM_LIGHTMAP_PAGE_USER_DEFINED:
  128. *pWidth = *pHeight = 1;
  129. AssertOnce( !"Can't use CMatLightmaps to get properties of MATERIAL_SYSTEM_LIGHTMAP_PAGE_USER_DEFINED" );
  130. break;
  131. case MATERIAL_SYSTEM_LIGHTMAP_PAGE_WHITE:
  132. case MATERIAL_SYSTEM_LIGHTMAP_PAGE_WHITE_BUMP:
  133. *pWidth = *pHeight = 1;
  134. break;
  135. }
  136. }
  137. //-----------------------------------------------------------------------------
  138. //
  139. //-----------------------------------------------------------------------------
  140. int CMatLightmaps::GetLightmapWidth( int lightmapPageID ) const
  141. {
  142. switch( lightmapPageID )
  143. {
  144. default:
  145. Assert( lightmapPageID >= 0 && lightmapPageID < GetNumLightmapPages() );
  146. return m_pLightmapPages[lightmapPageID].m_Width;
  147. case MATERIAL_SYSTEM_LIGHTMAP_PAGE_USER_DEFINED:
  148. AssertOnce( !"Can't use CMatLightmaps to get properties of MATERIAL_SYSTEM_LIGHTMAP_PAGE_USER_DEFINED" );
  149. return 1;
  150. case MATERIAL_SYSTEM_LIGHTMAP_PAGE_WHITE:
  151. case MATERIAL_SYSTEM_LIGHTMAP_PAGE_WHITE_BUMP:
  152. return 1;
  153. }
  154. }
  155. //-----------------------------------------------------------------------------
  156. //
  157. //-----------------------------------------------------------------------------
  158. int CMatLightmaps::GetLightmapHeight( int lightmapPageID ) const
  159. {
  160. switch( lightmapPageID )
  161. {
  162. default:
  163. Assert( lightmapPageID >= 0 && lightmapPageID < GetNumLightmapPages() );
  164. return m_pLightmapPages[lightmapPageID].m_Height;
  165. case MATERIAL_SYSTEM_LIGHTMAP_PAGE_USER_DEFINED:
  166. AssertOnce( !"Can't use CMatLightmaps to get properties of MATERIAL_SYSTEM_LIGHTMAP_PAGE_USER_DEFINED" );
  167. return 1;
  168. case MATERIAL_SYSTEM_LIGHTMAP_PAGE_WHITE:
  169. case MATERIAL_SYSTEM_LIGHTMAP_PAGE_WHITE_BUMP:
  170. return 1;
  171. }
  172. }
  173. //-----------------------------------------------------------------------------
  174. // Clean up lightmap pages.
  175. //-----------------------------------------------------------------------------
  176. void CMatLightmaps::CleanupLightmaps()
  177. {
  178. GetMaterialSystem()->GetPaintmaps()->CleanupPaintmaps();
  179. if ( mat_lightmap_pfms.GetBool())
  180. {
  181. // Write PFM files containing lightmap data for this page
  182. for (int lightmap = 0; lightmap < GetNumLightmapPages(); lightmap++)
  183. {
  184. if ((NULL != m_pLightmapDataPtrArray) && (NULL != m_pLightmapDataPtrArray[lightmap]))
  185. {
  186. char szPFMFileName[MAX_PATH];
  187. sprintf(szPFMFileName, "Lightmap-Page-%d.pfm", lightmap);
  188. m_pLightmapDataPtrArray[lightmap]->WritePFM(szPFMFileName);
  189. }
  190. }
  191. }
  192. // Remove the lightmap data bitmap representations
  193. if (m_pLightmapDataPtrArray)
  194. {
  195. int i;
  196. for( i = 0; i < GetNumLightmapPages(); i++ )
  197. {
  198. delete m_pLightmapDataPtrArray[i];
  199. }
  200. delete [] m_pLightmapDataPtrArray;
  201. m_pLightmapDataPtrArray = NULL;
  202. }
  203. // delete old lightmap pages
  204. if( m_pLightmapPages )
  205. {
  206. int i;
  207. for( i = 0; i < GetNumLightmapPages(); i++ )
  208. {
  209. g_pShaderAPI->DeleteTexture( m_LightmapPageTextureHandles[i] );
  210. }
  211. delete [] m_pLightmapPages;
  212. m_pLightmapPages = 0;
  213. }
  214. m_NumLightmapPages = 0;
  215. }
  216. //-----------------------------------------------------------------------------
  217. // Resets the lightmap page info for each material
  218. //-----------------------------------------------------------------------------
  219. void CMatLightmaps::ResetMaterialLightmapPageInfo( void )
  220. {
  221. for (MaterialHandle_t i = GetMaterialDict()->FirstMaterial(); i != GetMaterialDict()->InvalidMaterial(); i = GetMaterialDict()->NextMaterial(i) )
  222. {
  223. IMaterialInternal *pMaterial = GetMaterialInternal(i);
  224. pMaterial->SetMinLightmapPageID( 9999 );
  225. pMaterial->SetMaxLightmapPageID( -9999 );
  226. pMaterial->SetNeedsWhiteLightmap( false );
  227. }
  228. }
  229. //-----------------------------------------------------------------------------
  230. // This is called before any lightmap allocations take place
  231. //-----------------------------------------------------------------------------
  232. void CMatLightmaps::BeginLightmapAllocation()
  233. {
  234. // we clean up lightmaps on console right before we load the next map
  235. if ( IsPC() )
  236. {
  237. CleanupLightmaps();
  238. }
  239. m_ImagePackers.RemoveAll();
  240. int i = m_ImagePackers.AddToTail();
  241. m_ImagePackers[i].Reset( 0, GetMaxLightmapPageWidth(), GetMaxLightmapPageHeight() );
  242. SetCurrentMaterialInternal(0);
  243. m_currentWhiteLightmapMaterial = 0;
  244. m_numSortIDs = 0;
  245. // need to set the min and max sorting id number for each material to
  246. // a default value that basically means that it hasn't been used yet.
  247. ResetMaterialLightmapPageInfo();
  248. EnumerateMaterials();
  249. }
  250. //-----------------------------------------------------------------------------
  251. // Allocates space in the lightmaps; must be called after BeginLightmapAllocation
  252. //-----------------------------------------------------------------------------
  253. int CMatLightmaps::AllocateLightmap( int width, int height,
  254. int offsetIntoLightmapPage[2],
  255. IMaterial *iMaterial )
  256. {
  257. IMaterialInternal *pMaterial = static_cast<IMaterialInternal *>( iMaterial );
  258. if ( !pMaterial )
  259. {
  260. Warning( "Programming error: CMatRenderContext::AllocateLightmap: NULL material\n" );
  261. return m_numSortIDs;
  262. }
  263. pMaterial = pMaterial->GetRealTimeVersion(); //always work with the real time versions of materials internally
  264. // material change
  265. int i;
  266. int nPackCount = m_ImagePackers.Count();
  267. if ( GetCurrentMaterialInternal() != pMaterial )
  268. {
  269. // If this happens, then we need to close out all image packers other than
  270. // the last one so as to produce as few sort IDs as possible
  271. for ( i = nPackCount - 1; --i >= 0; )
  272. {
  273. // NOTE: We *must* use the order preserving one here so the remaining one
  274. // is the last lightmap
  275. m_ImagePackers.Remove( i );
  276. --nPackCount;
  277. }
  278. // If it's not the first material, increment the sort id
  279. if (GetCurrentMaterialInternal())
  280. {
  281. m_ImagePackers[0].IncrementSortId( );
  282. ++m_numSortIDs;
  283. }
  284. SetCurrentMaterialInternal(pMaterial);
  285. // This assertion guarantees we don't see the same material twice in this loop.
  286. Assert( pMaterial->GetMinLightmapPageID( ) > pMaterial->GetMaxLightmapPageID() );
  287. // NOTE: We may not use this lightmap page, but we might
  288. // we won't know for sure until the next material is passed in.
  289. // So, for now, we're going to forcibly add the current lightmap
  290. // page to this material so the sort IDs work out correctly.
  291. GetCurrentMaterialInternal()->SetMinLightmapPageID( GetNumLightmapPages() );
  292. GetCurrentMaterialInternal()->SetMaxLightmapPageID( GetNumLightmapPages() );
  293. }
  294. // Try to add it to any of the current images...
  295. bool bAdded = false;
  296. for ( i = 0; i < nPackCount; ++i )
  297. {
  298. bAdded = m_ImagePackers[i].AddBlock( width, height, &offsetIntoLightmapPage[0], &offsetIntoLightmapPage[1] );
  299. if ( bAdded )
  300. break;
  301. }
  302. if ( !bAdded )
  303. {
  304. ++m_numSortIDs;
  305. i = m_ImagePackers.AddToTail();
  306. m_ImagePackers[i].Reset( m_numSortIDs, GetMaxLightmapPageWidth(), GetMaxLightmapPageHeight() );
  307. ++m_NumLightmapPages;
  308. if ( !m_ImagePackers[i].AddBlock( width, height, &offsetIntoLightmapPage[0], &offsetIntoLightmapPage[1] ) )
  309. {
  310. Error( "MaterialSystem_Interface_t::AllocateLightmap: lightmap (%dx%d) too big to fit in page (%dx%d)\n",
  311. width, height, GetMaxLightmapPageWidth(), GetMaxLightmapPageHeight() );
  312. }
  313. // Add this lightmap to the material...
  314. GetCurrentMaterialInternal()->SetMaxLightmapPageID( GetNumLightmapPages() );
  315. }
  316. return m_ImagePackers[i].GetSortId();
  317. }
  318. // UNDONE: This needs testing, but it appears as though creating these textures managed
  319. // results in huge stalls whenever they are locked for modify.
  320. // That makes sense given the d3d docs, but these have been flagged as managed for quite some time.
  321. #define DYNAMIC_TEXTURES_NO_BACKING 1
  322. void CMatLightmaps::EndLightmapAllocation()
  323. {
  324. // count the last page that we were on.if it wasn't
  325. // and count the last sortID that we were on
  326. m_NumLightmapPages++;
  327. m_numSortIDs++;
  328. m_firstDynamicLightmap = m_NumLightmapPages;
  329. // UNDONE: Until we start using the separate dynamic lighting textures don't allocate them
  330. // NOTE: Enable this if we want to stop locking the base lightmaps and instead only lock update
  331. // these completely dynamic pages
  332. // m_NumLightmapPages += COUNT_DYNAMIC_LIGHTMAP_PAGES;
  333. m_dynamic.Init();
  334. // Compute the dimensions of the last lightmap
  335. int lastLightmapPageWidth, lastLightmapPageHeight;
  336. int nLastIdx = m_ImagePackers.Count();
  337. m_ImagePackers[nLastIdx - 1].GetMinimumDimensions( &lastLightmapPageWidth, &lastLightmapPageHeight );
  338. m_ImagePackers.Purge();
  339. m_pLightmapPages = new LightmapPageInfo_t[GetNumLightmapPages()];
  340. Assert( m_pLightmapPages );
  341. if ( mat_lightmap_pfms.GetBool())
  342. {
  343. // This array will be used to write PFM files full of lightmap data
  344. m_pLightmapDataPtrArray = new FloatBitMap_t*[GetNumLightmapPages()];
  345. }
  346. if( GetMaterialSystem()->GetPaintmaps()->IsEnabled() )
  347. {
  348. GetMaterialSystem()->GetPaintmaps()->BeginPaintTextureAllocation( GetNumLightmapPages() );
  349. }
  350. int i;
  351. m_LightmapPageTextureHandles.EnsureCapacity( GetNumLightmapPages() );
  352. for ( i = 0; i < GetNumLightmapPages(); i++ )
  353. {
  354. // Compute lightmap dimensions
  355. bool lastStaticLightmap = ( i == (m_firstDynamicLightmap-1));
  356. m_pLightmapPages[i].m_Width = (unsigned short)(lastStaticLightmap ? lastLightmapPageWidth : GetMaxLightmapPageWidth());
  357. m_pLightmapPages[i].m_Height = (unsigned short)(lastStaticLightmap ? lastLightmapPageHeight : GetMaxLightmapPageHeight());
  358. m_pLightmapPages[i].m_Flags = 0;
  359. AllocateLightmapTexture( i );
  360. if ( GetMaterialSystem()->GetPaintmaps()->IsEnabled() )
  361. {
  362. GetMaterialSystem()->GetPaintmaps()->AllocatePaintmap( i, GetLightmapWidth(i), GetLightmapHeight(i) );
  363. }
  364. if ( mat_lightmap_pfms.GetBool())
  365. {
  366. // Initialize the pointers to lightmap data
  367. m_pLightmapDataPtrArray[i] = NULL;
  368. }
  369. }
  370. if( GetMaterialSystem()->GetPaintmaps()->IsEnabled() )
  371. {
  372. GetMaterialSystem()->GetPaintmaps()->EndPaintTextureAllocation();
  373. }
  374. }
  375. ConVar mat_dynamiclightmaps( "mat_dynamiclightmaps", "0", FCVAR_CHEAT );
  376. //-----------------------------------------------------------------------------
  377. // Allocate lightmap textures
  378. //-----------------------------------------------------------------------------
  379. void CMatLightmaps::AllocateLightmapTexture( int lightmap )
  380. {
  381. bool bUseDynamicTextures = HardwareConfig()->PreferDynamicTextures() && mat_dynamiclightmaps.GetBool();
  382. int flags = 0;
  383. if ( bUseDynamicTextures || IsPS3() ) // On PS3, we need the dynamic flag as a hint that we're going to update this texture incrementally in the future
  384. {
  385. flags |= TEXTURE_CREATE_DYNAMIC;
  386. }
  387. else
  388. {
  389. flags |= TEXTURE_CREATE_MANAGED;
  390. }
  391. int nPreviousTextureHandles = m_LightmapPageTextureHandles.Count();
  392. m_LightmapPageTextureHandles.EnsureCount( lightmap + 1 );
  393. for ( int nLightmap = nPreviousTextureHandles; nLightmap <= lightmap; ++nLightmap )
  394. {
  395. m_LightmapPageTextureHandles[ nLightmap ] = INVALID_SHADERAPI_TEXTURE_HANDLE;
  396. }
  397. char debugName[256];
  398. Q_snprintf( debugName, sizeof( debugName ), "[lightmap %d]", lightmap );
  399. ImageFormat imageFormat;
  400. switch ( HardwareConfig()->GetHDRType() )
  401. {
  402. default:
  403. Assert( 0 );
  404. // fall through.
  405. case HDR_TYPE_NONE:
  406. #if !defined( _X360 )
  407. imageFormat = IMAGE_FORMAT_RGBA8888;
  408. flags |= TEXTURE_CREATE_SRGB;
  409. #else
  410. imageFormat = IMAGE_FORMAT_LINEAR_RGBA8888;
  411. #endif
  412. break;
  413. case HDR_TYPE_INTEGER:
  414. #if !defined( _X360 )
  415. imageFormat = IMAGE_FORMAT_RGBA16161616;
  416. #else
  417. # if ( defined( USE_32BIT_LIGHTMAPS_ON_360 ) )
  418. imageFormat = IMAGE_FORMAT_LINEAR_RGBA8888;
  419. # else
  420. imageFormat = IMAGE_FORMAT_LINEAR_RGBA16161616;
  421. # endif
  422. #endif
  423. break;
  424. case HDR_TYPE_FLOAT:
  425. imageFormat = IMAGE_FORMAT_RGBA16161616F;
  426. break;
  427. }
  428. #ifdef _PS3
  429. // PS3 needs 16F textures...but the HDR_TYPE_FLOAT codepath has a lot of other baggage with it. Just lie here.
  430. imageFormat = IMAGE_FORMAT_RGBA16161616F;
  431. #endif // _PS3
  432. switch ( m_eLightmapsState )
  433. {
  434. case STATE_DEFAULT:
  435. // Allow allocations in default state
  436. {
  437. int iWidth = GetLightmapWidth(lightmap);
  438. int iHeight = GetLightmapHeight(lightmap);
  439. m_LightmapPageTextureHandles[lightmap] = g_pShaderAPI->CreateTexture(
  440. iWidth, iHeight, 1,
  441. imageFormat,
  442. 1, 1, flags, debugName, TEXTURE_GROUP_LIGHTMAP ); // don't mipmap lightmaps
  443. // Load up the texture data
  444. g_pShaderAPI->ModifyTexture( m_LightmapPageTextureHandles[lightmap] );
  445. g_pShaderAPI->TexMinFilter( SHADER_TEXFILTERMODE_LINEAR );
  446. g_pShaderAPI->TexMagFilter( SHADER_TEXFILTERMODE_LINEAR );
  447. if ( !bUseDynamicTextures )
  448. {
  449. g_pShaderAPI->TexSetPriority( 1 );
  450. }
  451. // Blat out the lightmap bits
  452. InitLightmapBits( lightmap );
  453. }
  454. break;
  455. case STATE_RELEASED:
  456. // Not assigned m_LightmapPageTextureHandles[lightmap];
  457. DevMsg( "AllocateLightmapTexture(%d) in released lightmap state (STATE_RELEASED), delayed till \"Restore\".\n", lightmap );
  458. return;
  459. default:
  460. // Not assigned m_LightmapPageTextureHandles[lightmap];
  461. Warning( "AllocateLightmapTexture(%d) in unknown lightmap state (%d), skipped.\n", lightmap, m_eLightmapsState );
  462. Assert( !"AllocateLightmapTexture(?) in unknown lightmap state (?)" );
  463. return;
  464. }
  465. }
  466. int CMatLightmaps::AllocateWhiteLightmap( IMaterial *iMaterial )
  467. {
  468. IMaterialInternal *pMaterial = static_cast<IMaterialInternal *>( iMaterial );
  469. if( !pMaterial )
  470. {
  471. Warning( "Programming error: CMatRenderContext::AllocateWhiteLightmap: NULL material\n" );
  472. return m_numSortIDs;
  473. }
  474. pMaterial = pMaterial->GetRealTimeVersion(); //always work with the real time versions of materials internally
  475. if ( !m_currentWhiteLightmapMaterial || ( m_currentWhiteLightmapMaterial != pMaterial ) )
  476. {
  477. if ( !GetCurrentMaterialInternal() && !m_currentWhiteLightmapMaterial )
  478. {
  479. // don't increment if this is the very first material (ie. no lightmaps
  480. // allocated with AllocateLightmap
  481. // Assert( 0 );
  482. }
  483. else
  484. {
  485. // material change
  486. m_numSortIDs++;
  487. #if 0
  488. char buf[128];
  489. Q_snprintf( buf, sizeof( buf ), "AllocateWhiteLightmap: m_numSortIDs = %d %s\n", m_numSortIDs, pMaterial->GetName() );
  490. OutputDebugString( buf );
  491. #endif
  492. }
  493. // Warning( "%d material: \"%s\" lightmapPageID: -1\n", m_numSortIDs, pMaterial->GetName() );
  494. m_currentWhiteLightmapMaterial = pMaterial;
  495. pMaterial->SetNeedsWhiteLightmap( true );
  496. }
  497. return m_numSortIDs;
  498. }
  499. //-----------------------------------------------------------------------------
  500. // Releases/restores lightmap pages
  501. //-----------------------------------------------------------------------------
  502. void CMatLightmaps::ReleaseLightmapPages()
  503. {
  504. switch ( m_eLightmapsState )
  505. {
  506. case STATE_DEFAULT:
  507. // Allow release in default state only
  508. break;
  509. default:
  510. Warning( "ReleaseLightmapPages is expected in STATE_DEFAULT, current state = %d, discarded.\n", m_eLightmapsState );
  511. Assert( !"ReleaseLightmapPages is expected in STATE_DEFAULT" );
  512. return;
  513. }
  514. for( int i = 0; i < GetNumLightmapPages(); i++ )
  515. {
  516. g_pShaderAPI->DeleteTexture( m_LightmapPageTextureHandles[i] );
  517. }
  518. GetMaterialSystem()->GetPaintmaps()->ReleasePaintmaps();
  519. // We are now in released state
  520. m_eLightmapsState = STATE_RELEASED;
  521. }
  522. void CMatLightmaps::RestoreLightmapPages()
  523. {
  524. switch ( m_eLightmapsState )
  525. {
  526. case STATE_RELEASED:
  527. // Allow restore in released state only
  528. break;
  529. default:
  530. Warning( "RestoreLightmapPages is expected in STATE_RELEASED, current state = %d, discarded.\n", m_eLightmapsState );
  531. Assert( !"RestoreLightmapPages is expected in STATE_RELEASED" );
  532. return;
  533. }
  534. // Switch to default state to allow allocations
  535. m_eLightmapsState = STATE_DEFAULT;
  536. if( GetMaterialSystem()->GetPaintmaps()->IsEnabled() )
  537. {
  538. GetMaterialSystem()->GetPaintmaps()->RestorePaintmaps( GetNumLightmapPages() );
  539. }
  540. for( int i = 0; i < GetNumLightmapPages(); i++ )
  541. {
  542. AllocateLightmapTexture( i );
  543. }
  544. }
  545. //-----------------------------------------------------------------------------
  546. // This initializes the lightmap bits
  547. //-----------------------------------------------------------------------------
  548. void CMatLightmaps::InitLightmapBits( int lightmap )
  549. {
  550. VPROF_( "CMatLightmaps::InitLightmapBits", 1, VPROF_BUDGETGROUP_DLIGHT_RENDERING, false, 0 );
  551. int width = GetLightmapWidth(lightmap);
  552. int height = GetLightmapHeight(lightmap);
  553. CPixelWriter writer;
  554. g_pShaderAPI->ModifyTexture( m_LightmapPageTextureHandles[lightmap] );
  555. if ( !g_pShaderAPI->TexLock( 0, 0, 0, 0, width, height, writer ) )
  556. return;
  557. // Debug mode, make em green checkerboard
  558. if ( writer.IsUsingFloatFormat() )
  559. {
  560. for ( int j = 0; j < height; ++j )
  561. {
  562. writer.Seek( 0, j );
  563. for ( int k = 0; k < width; ++k )
  564. {
  565. #ifndef _DEBUG
  566. writer.WritePixel( 1.0f, 1.0f, 1.0f );
  567. #else // _DEBUG
  568. if( ( j + k ) & 1 )
  569. {
  570. writer.WritePixelF( 0.0f, 1.0f, 0.0f );
  571. }
  572. else
  573. {
  574. writer.WritePixelF( 0.0f, 0.0f, 0.0f );
  575. }
  576. #endif // _DEBUG
  577. }
  578. }
  579. }
  580. else
  581. {
  582. #if defined( _X360 ) && defined( _DEBUG )
  583. float vGreenData[4] = { 0.0f, 2.0f, 0.0f, 0.0f };
  584. fltx4 vGreen = LoadUnalignedSIMD( vGreenData );
  585. #endif
  586. for ( int j = 0; j < height; ++j )
  587. {
  588. writer.Seek( 0, j );
  589. for ( int k = 0; k < width; ++k )
  590. {
  591. #ifndef _DEBUG
  592. // note: make this white to find multisample centroid sampling problems.
  593. // writer.WritePixel( 255, 255, 255 );
  594. #ifdef _X360
  595. {
  596. writer.WritePixel( Four_Zeros );
  597. }
  598. #else
  599. {
  600. writer.WritePixel( 0, 0, 0 );
  601. }
  602. #endif
  603. #else // _DEBUG
  604. #ifdef _X360
  605. {
  606. if ( ( j + k ) & 1 )
  607. {
  608. writer.WritePixel( vGreen );
  609. }
  610. else
  611. {
  612. writer.WritePixel( Four_Zeros );
  613. }
  614. }
  615. #else
  616. {
  617. if ( ( j + k ) & 1 )
  618. {
  619. writer.WritePixel( 0, 255, 0 );
  620. }
  621. else
  622. {
  623. writer.WritePixel( 0, 0, 0 );
  624. }
  625. }
  626. #endif // _X360
  627. #endif // _DEBUG
  628. }
  629. }
  630. }
  631. g_pShaderAPI->TexUnlock();
  632. }
  633. bool CMatLightmaps::LockLightmap( int lightmap )
  634. {
  635. // Warning( "locking lightmap page: %d\n", lightmap );
  636. VPROF_INCREMENT_COUNTER( "lightmap fullpage texlock", 1 );
  637. if( m_nLockedLightmap != -1 )
  638. {
  639. g_pShaderAPI->TexUnlock();
  640. }
  641. g_pShaderAPI->ModifyTexture( m_LightmapPageTextureHandles[lightmap] );
  642. int pageWidth = m_pLightmapPages[lightmap].m_Width;
  643. int pageHeight = m_pLightmapPages[lightmap].m_Height;
  644. if (!g_pShaderAPI->TexLock( 0, 0, 0, 0, pageWidth, pageHeight, m_LightmapPixelWriter ))
  645. {
  646. Assert( 0 );
  647. return false;
  648. }
  649. m_nLockedLightmap = lightmap;
  650. return true;
  651. }
  652. Vector4D ConvertLightmapColorToRGBScale( const float *lightmapColor )
  653. {
  654. Vector4D result;
  655. float fScale = lightmapColor[0];
  656. for( int i = 1; i != 3; ++i )
  657. {
  658. if( lightmapColor[i] > fScale )
  659. fScale = lightmapColor[i];
  660. }
  661. fScale = ceil( fScale * (255.0f/16.0f) ) * (16.0f/255.0f);
  662. fScale = MIN( fScale, 16.0f );
  663. float fInvScale = 1.0f / fScale;
  664. for( int i = 0; i != 3; ++i )
  665. {
  666. result[i] = lightmapColor[i] * fInvScale;
  667. result[i] = ceil( result[i] * 255.0f ) * (1.0f/255.0f);
  668. result[i] = MIN( result[i], 1.0f );
  669. }
  670. fScale /= 16.0f;
  671. result.w = fScale;
  672. return result;
  673. }
  674. #ifdef _X360
  675. // SIMD version of above
  676. // input numbers from pSrc are on the domain [0..16]
  677. // output is RGBA
  678. // ignores contents of w channel of input
  679. // the shader does this: rOut = Rin * Ain * 16.0f
  680. // where Rin is [0..1], a float computed from a byte value [0..255]
  681. // Ain is therefore the brightest channel (say R) divided by 16 and quantized
  682. // Rin is computed from pSrc->r by dividing by Ain
  683. // this outputs RGBa where RGB are [0..255] and a is the shader's scaling factor (also 0..255)
  684. //
  685. // WARNING - this code appears to be vulnerable to a compiler bug. Be very careful modifying and be
  686. // sure to test
  687. fltx4 ConvertLightmapColorToRGBScale( FLTX4 lightmapColor )
  688. {
  689. static const fltx4 vTwoFiftyFive = {255.0f, 255.0f, 255.0f, 255.0f};
  690. static const fltx4 FourPoint1s = { 0.1, 0.1, 0.1, 0.1 };
  691. static const fltx4 vTwoFiftyFiveOverSixteen = {255.0f / 16.0f, 255.0f / 16.0f, 255.0f / 16.0f, 255.0f / 16.0f};
  692. // static const fltx4 vSixteenOverTwoFiftyFive = { 16.0f / 255.0f, 16.0f / 255.0f, 16.0f / 255.0f, 16.0f / 255.0f };
  693. // find the highest color value in lightmapColor and replicate it
  694. fltx4 scale = FindHighestSIMD3( lightmapColor );
  695. fltx4 minscale = FindLowestSIMD3( lightmapColor );
  696. fltx4 fl4OutofRange = OrSIMD( CmpGeSIMD( scale, Four_Ones ), CmpLeSIMD( scale, FourPoint1s ) );
  697. fl4OutofRange = OrSIMD( fl4OutofRange, CmpGtSIMD( minscale, MulSIMD( Four_PointFives, scale ) ) );
  698. // scale needs to be divided by 16 (because the shader multiplies it by 16)
  699. // then mapped to 0..255 and quantized.
  700. scale = __vrfip(MulSIMD(scale, vTwoFiftyFiveOverSixteen)); // scale = ceil(scale * 255/16)
  701. fltx4 result = MulSIMD(vTwoFiftyFive, lightmapColor); // start the scale cooking on the final result
  702. fltx4 invScale = ReciprocalEstSIMD(scale); // invScale = (16/255)(1/scale). may be +inf
  703. invScale = MulSIMD(invScale, vTwoFiftyFiveOverSixteen); // take the quantizing factor back out
  704. // of the inverse scale (one less
  705. // dependent op if you do it this way)
  706. // scale the input channels
  707. // compute so the numbers are all 0..255 ints. (if one happens to
  708. // be 256 due to numerical error in the reciprocation, the unsigned-saturate
  709. // store we'll use later on will bake it back down to 255)
  710. result = MulSIMD(result, invScale);
  711. // now, output --
  712. // if the input color was nonzero, slip the scale into return value's w
  713. // component and return. If the input was zero, return zero.
  714. result = MaskedAssign(
  715. fl4OutofRange,
  716. SetWSIMD( result, scale ),
  717. SetWSIMD( MulSIMD( lightmapColor, vTwoFiftyFive ), vTwoFiftyFiveOverSixteen ) );
  718. return result;
  719. }
  720. #endif
  721. // write bumped lightmap update to LDR 8-bit lightmap
  722. void CMatLightmaps::BumpedLightmapBitsToPixelWriter_LDR( float* pFloatImage, float *pFloatImageBump1, float *pFloatImageBump2,
  723. float *pFloatImageBump3, int pLightmapSize[2], int pOffsetIntoLightmapPage[2], FloatBitMap_t *pfmOut )
  724. {
  725. const int nLightmapSize0 = pLightmapSize[0];
  726. const int nLightmap0WriterSizeBytes = nLightmapSize0 * m_LightmapPixelWriter.GetPixelSize();
  727. const int nRewindToNextPixel = -( ( nLightmap0WriterSizeBytes * 3 ) - m_LightmapPixelWriter.GetPixelSize() );
  728. for( int t = 0; t < pLightmapSize[1]; t++ )
  729. {
  730. int srcTexelOffset = ( sizeof( Vector4D ) / sizeof( float ) ) * ( 0 + t * nLightmapSize0 );
  731. m_LightmapPixelWriter.Seek( pOffsetIntoLightmapPage[0], pOffsetIntoLightmapPage[1] + t );
  732. for( int s = 0; s < nLightmapSize0;
  733. s++, m_LightmapPixelWriter.SkipBytes(nRewindToNextPixel),srcTexelOffset += (sizeof(Vector4D)/sizeof(float)))
  734. {
  735. unsigned char color[4][4];
  736. ColorSpace::LinearToBumpedLightmap( &pFloatImage[srcTexelOffset],
  737. &pFloatImageBump1[srcTexelOffset], &pFloatImageBump2[srcTexelOffset],
  738. &pFloatImageBump3[srcTexelOffset],
  739. color[0], color[1], color[2], color[3] );
  740. if ( HardwareConfig()->GetCSMAccurateBlending() )
  741. {
  742. ColorSpace::LinearToBumpedLightmapAlpha( &pFloatImage[srcTexelOffset + 3],
  743. &pFloatImageBump1[srcTexelOffset + 3], &pFloatImageBump2[srcTexelOffset + 3], &pFloatImageBump3[srcTexelOffset + 3],
  744. &color[0][3], &color[1][3], &color[2][3], &color[3][3] );
  745. }
  746. else
  747. {
  748. unsigned char alpha = RoundFloatToByte( pFloatImage[srcTexelOffset+3] * 255.0f );
  749. color[0][3] = alpha;
  750. color[1][3] = alpha;
  751. color[2][3] = alpha;
  752. color[3][3] = alpha;
  753. }
  754. m_LightmapPixelWriter.WritePixelNoAdvance( color[0][0], color[0][1], color[0][2], color[0][3] );
  755. m_LightmapPixelWriter.SkipBytes( nLightmap0WriterSizeBytes );
  756. m_LightmapPixelWriter.WritePixelNoAdvance( color[1][0], color[1][1], color[1][2], color[1][3] );
  757. m_LightmapPixelWriter.SkipBytes( nLightmap0WriterSizeBytes );
  758. m_LightmapPixelWriter.WritePixelNoAdvance( color[2][0], color[2][1], color[2][2], color[2][3] );
  759. m_LightmapPixelWriter.SkipBytes( nLightmap0WriterSizeBytes );
  760. m_LightmapPixelWriter.WritePixelNoAdvance( color[3][0], color[3][1], color[3][2], color[3][3] );
  761. }
  762. }
  763. if ( pfmOut )
  764. {
  765. for( int t = 0; t < pLightmapSize[1]; t++ )
  766. {
  767. int srcTexelOffset = ( sizeof( Vector4D ) / sizeof( float ) ) * ( 0 + t * nLightmapSize0 );
  768. for( int s = 0; s < nLightmapSize0; s++,srcTexelOffset += (sizeof(Vector4D)/sizeof(float)))
  769. {
  770. unsigned char color[4][4];
  771. ColorSpace::LinearToBumpedLightmap( &pFloatImage[srcTexelOffset],
  772. &pFloatImageBump1[srcTexelOffset], &pFloatImageBump2[srcTexelOffset],
  773. &pFloatImageBump3[srcTexelOffset],
  774. color[0], color[1], color[2], color[3] );
  775. unsigned char alpha = RoundFloatToByte( pFloatImage[srcTexelOffset+3] * 255.0f );
  776. // Write data to the bitmapped represenations so that PFM files can be written
  777. PixRGBAF pixelData;
  778. pixelData.Red = color[0][0];
  779. pixelData.Green = color[0][1];
  780. pixelData.Blue = color[0][2];
  781. pixelData.Alpha = alpha;
  782. pfmOut->WritePixelRGBAF( pOffsetIntoLightmapPage[0] + s, pOffsetIntoLightmapPage[1] + t, 0, pixelData);
  783. }
  784. }
  785. }
  786. }
  787. // write bumped lightmap update to HDR float lightmap
  788. void CMatLightmaps::BumpedLightmapBitsToPixelWriter_HDRF( float* pFloatImage, float *pFloatImageBump1, float *pFloatImageBump2,
  789. float *pFloatImageBump3, int pLightmapSize[2], int pOffsetIntoLightmapPage[2], FloatBitMap_t *pfmOut )
  790. {
  791. if ( IsX360() )
  792. {
  793. // 360 does not support HDR float mode
  794. Assert( 0 );
  795. return;
  796. }
  797. Assert( !pfmOut ); // unsupported in this mode
  798. const int nLightmapSize0 = pLightmapSize[0];
  799. const int nLightmap0WriterSizeBytes = nLightmapSize0 * m_LightmapPixelWriter.GetPixelSize();
  800. const int nRewindToNextPixel = -( ( nLightmap0WriterSizeBytes * 3 ) - m_LightmapPixelWriter.GetPixelSize() );
  801. for( int t = 0; t < pLightmapSize[1]; t++ )
  802. {
  803. int srcTexelOffset = ( sizeof( Vector4D ) / sizeof( float ) ) * ( 0 + t * nLightmapSize0 );
  804. m_LightmapPixelWriter.Seek( pOffsetIntoLightmapPage[0], pOffsetIntoLightmapPage[1] + t );
  805. // if it's anything but 4 x float16 on a PPC...
  806. /*
  807. // The 'else' path uses ConvertFourFloatsTo16BitsAtOnce which is entirely broken
  808. // so we need to always use the main path.
  809. if ( !IsGameConsole() ||
  810. !(m_LightmapPixelWriter.GetPixelSize() == 4*sizeof(unsigned short)) ||
  811. !(m_LightmapPixelWriter.IsUsing16BitFloatFormat())
  812. )*/
  813. {
  814. for( int s = 0;
  815. s < nLightmapSize0;
  816. s++, m_LightmapPixelWriter.SkipBytes(nRewindToNextPixel),srcTexelOffset += (sizeof(Vector4D)/sizeof(float)))
  817. {
  818. float color[4][4];
  819. // [mariod] - LinearToBumpedLightmap() was entirely missing in the float path as of September '11
  820. // looks like this only affected PS3 (PC/X360 use linear 16bit tex formats)
  821. ColorSpace::LinearToBumpedLightmap( &pFloatImage[srcTexelOffset],
  822. &pFloatImageBump1[srcTexelOffset], &pFloatImageBump2[srcTexelOffset],
  823. &pFloatImageBump3[srcTexelOffset],
  824. color[0], color[1], color[2], color[3] );
  825. if ( HardwareConfig()->GetCSMAccurateBlending() )
  826. {
  827. ColorSpace::LinearToBumpedLightmapAlpha( &pFloatImage[srcTexelOffset + 3],
  828. &pFloatImageBump1[srcTexelOffset + 3], &pFloatImageBump2[srcTexelOffset + 3], &pFloatImageBump3[srcTexelOffset + 3],
  829. &color[0][3], &color[1][3], &color[2][3], &color[3][3] );
  830. }
  831. else
  832. {
  833. float alpha = pFloatImage[srcTexelOffset+3];
  834. color[0][3] = alpha;
  835. color[1][3] = alpha;
  836. color[2][3] = alpha;
  837. color[3][3] = alpha;
  838. }
  839. m_LightmapPixelWriter.WritePixelNoAdvanceF( color[0][0], color[0][1], color[0][2], color[0][3] );
  840. m_LightmapPixelWriter.SkipBytes( nLightmap0WriterSizeBytes );
  841. m_LightmapPixelWriter.WritePixelNoAdvanceF( color[1][0], color[1][1], color[1][2], color[1][3] );
  842. m_LightmapPixelWriter.SkipBytes( nLightmap0WriterSizeBytes );
  843. m_LightmapPixelWriter.WritePixelNoAdvanceF( color[2][0], color[2][1], color[2][2], color[2][3] );
  844. m_LightmapPixelWriter.SkipBytes( nLightmap0WriterSizeBytes );
  845. m_LightmapPixelWriter.WritePixelNoAdvanceF( color[3][0], color[3][1], color[3][2], color[3][3] );
  846. }
  847. }
  848. /*
  849. else // use a faster technique on PPC cores for float16 lightmaps, that's not so branchy and load-hit-store-y
  850. {
  851. for( int s = 0;
  852. s < nLightmapSize0;
  853. s++, m_LightmapPixelWriter.SkipBytes(nRewindToNextPixel),srcTexelOffset += (sizeof(Vector4D)/sizeof(float)))
  854. {
  855. float color[4][4];
  856. // [mariod] - LinearToBumpedLightmap() was entirely missing in the float path as of September '11
  857. // looks like this only affected PS3 (PC/X360 use linear 16bit tex formats)
  858. ColorSpace::LinearToBumpedLightmap( &pFloatImage[srcTexelOffset],
  859. &pFloatImageBump1[srcTexelOffset], &pFloatImageBump2[srcTexelOffset],
  860. &pFloatImageBump3[srcTexelOffset],
  861. color[0], color[1], color[2], color[3] );
  862. float alpha = pFloatImage[srcTexelOffset+3];
  863. float16::ConvertFourFloatsTo16BitsAtOnce( (float16*) m_LightmapPixelWriter.GetCurrentPixel(),
  864. &color[0][0], &color[0][1], &color[0][2], &alpha );
  865. m_LightmapPixelWriter.SkipBytes( nLightmap0WriterSizeBytes );
  866. float16::ConvertFourFloatsTo16BitsAtOnce( (float16*) m_LightmapPixelWriter.GetCurrentPixel(),
  867. &color[1][0], &color[1][1], &color[1][2], &alpha );
  868. m_LightmapPixelWriter.SkipBytes( nLightmap0WriterSizeBytes );
  869. float16::ConvertFourFloatsTo16BitsAtOnce( (float16*) m_LightmapPixelWriter.GetCurrentPixel(),
  870. &color[2][0], &color[2][1], &color[2][2], &alpha );
  871. m_LightmapPixelWriter.SkipBytes( nLightmap0WriterSizeBytes );
  872. float16::ConvertFourFloatsTo16BitsAtOnce( (float16*) m_LightmapPixelWriter.GetCurrentPixel(),
  873. &color[3][0], &color[3][1], &color[3][2], &alpha );
  874. }
  875. }
  876. */
  877. }
  878. }
  879. #ifdef _X360
  880. #pragma optimize("u", on)
  881. #endif
  882. #ifdef _X360
  883. namespace {
  884. // pack a pixel into BGRA8888 and return it with the data packed into the w component
  885. FORCEINLINE fltx4 PackPixel_BGRA8888( FLTX4 rgba )
  886. {
  887. // this happens to be in an order such that we can use the handy builtin packing op
  888. // clamp to 0..255 (coz it might have leaked over)
  889. static const fltx4 vTwoFiftyFive = {255.0f, 255.0f, 255.0f, 255.0f};
  890. // the magic number such that when mul-accummulated against rbga,
  891. // gets us a representation 3.0 + (r)*2^-22 -- puts the bits at
  892. // the bottom of the float
  893. static const XMVECTOR PackScale = { (1.0f / (FLOAT)(1 << 22)), (1.0f / (FLOAT)(1 << 22)), (1.0f / (FLOAT)(1 << 22)), (1.0f / (FLOAT)(1 << 22))}; // 255.0f / (FLOAT)(1 << 22)
  894. static const XMVECTOR Three = {3.0f, 3.0f, 3.0f, 3.0f};
  895. fltx4 N = MinSIMD(vTwoFiftyFive, rgba);
  896. N = __vmaddfp(N, PackScale, Three);
  897. N = __vpkd3d(N, N, VPACK_D3DCOLOR, VPACK_32, 0); // pack into w word
  898. return N;
  899. }
  900. // A small store-gather buffer used in the
  901. // BumpedLightmapBitsToPixelWriter_HDRI_BGRA_X360().
  902. // The store-gather buffers. Hopefully these will live in the L1
  903. // cache, which will make writing to them, then to memory, faster
  904. // than just using __stvewx to write directly into WC memory
  905. // one noncontiguous float at a time. (If there weren't a huge
  906. // compiler bug with __stvewx in the Apr07 XDK, that might not
  907. // be the case.)
  908. struct ALIGN128 CPixelWriterStoreGather
  909. {
  910. enum {
  911. kRows = 4,
  912. kWordsPerRow = 32,
  913. };
  914. ALIGN128 uint32 m_data[kRows][kWordsPerRow]; // four rows of bgra data, aligned to 4 cache lines. dwords so memcpy works better.
  915. int m_wordsGathered;
  916. int m_bytesBetweenWriterRows; // the number of bytes spacing the maps inside the writer from each other
  917. // if we weren't gathering, we'd SkipBytes this many between the base map, bump1, etc.
  918. // write four rows, as SIMD registers, into the buffers
  919. inline void write( CPixelWriter * RESTRICT pLightmapPixelWriter, FLTX4 row0, FLTX4 row1, FLTX4 row2, FLTX4 row3 ) RESTRICT
  920. {
  921. // if full, commit
  922. Assert(m_wordsGathered <= kWordsPerRow);
  923. AssertMsg((m_wordsGathered & 3) == 0, "Don't call CPixelWriterStoreGather::write after ::writeJustX"); // single-word writes have misaligned me
  924. if (m_wordsGathered >= kWordsPerRow)
  925. {
  926. commitWhenFull(pLightmapPixelWriter);
  927. }
  928. XMStoreVector4A( &m_data[0][m_wordsGathered], row0 );
  929. XMStoreVector4A( &m_data[1][m_wordsGathered], row1 );
  930. XMStoreVector4A( &m_data[2][m_wordsGathered], row2 );
  931. XMStoreVector4A( &m_data[3][m_wordsGathered], row3 );
  932. m_wordsGathered += 4 ; // four words per simd vec
  933. }
  934. // pluck the w component out of each of the rows, and store it into the gather buffer. Don't
  935. // call the other write function after calling this.
  936. inline void writeJustW( CPixelWriter * RESTRICT pLightmapPixelWriter, FLTX4 row0, FLTX4 row1, FLTX4 row2, FLTX4 row3 ) RESTRICT
  937. {
  938. // if full, commit
  939. Assert(m_wordsGathered <= kWordsPerRow);
  940. if (m_wordsGathered >= kWordsPerRow)
  941. {
  942. commitWhenFull(pLightmapPixelWriter);
  943. }
  944. // for each fltx4, splat out x and then use the __stvewx to store
  945. // whichever word happens to align with the float pointer through
  946. // that pointer.
  947. __stvewx(__vspltw(row0, 3), &m_data[0][m_wordsGathered], 0 );
  948. __stvewx(__vspltw(row1, 3), &m_data[1][m_wordsGathered], 0 );
  949. __stvewx(__vspltw(row2, 3), &m_data[2][m_wordsGathered], 0 );
  950. __stvewx(__vspltw(row3, 3), &m_data[3][m_wordsGathered], 0 );
  951. m_wordsGathered += 1 ; // only stored one word
  952. }
  953. // Commit my buffers to the pixelwriter's memory, and advance its
  954. // pointer.
  955. void commit(CPixelWriter * RESTRICT pLightmapPixelWriter) RESTRICT
  956. {
  957. if (m_wordsGathered > 0)
  958. {
  959. unsigned char* RESTRICT pWriteInto = pLightmapPixelWriter->GetCurrentPixel();
  960. // we have to use memcpy because we're writing to non-cacheable memory,
  961. // but we can't even assume that the addresses we're writing to are
  962. // vector-aligned.
  963. #ifdef memcpy // if someone's overriden the intrinsic, complain
  964. #pragma error("You have overridden memcpy(), which is an XBOX360 intrinsic. This function will not behave optimally.")
  965. #endif
  966. memcpy(pWriteInto, m_data[0], m_wordsGathered * sizeof(uint32));
  967. pWriteInto += m_bytesBetweenWriterRows;
  968. memcpy(pWriteInto, m_data[1], m_wordsGathered * sizeof(uint32));
  969. pWriteInto += m_bytesBetweenWriterRows;
  970. memcpy(pWriteInto, m_data[2], m_wordsGathered * sizeof(uint32));
  971. pWriteInto += m_bytesBetweenWriterRows;
  972. memcpy(pWriteInto, m_data[3], m_wordsGathered * sizeof(uint32));
  973. pLightmapPixelWriter->SkipBytes(m_wordsGathered * sizeof(uint32));
  974. m_wordsGathered = 0;
  975. }
  976. }
  977. // like commit, but the version we use when we know we're full.
  978. // Takes advantage of better compile-time generation for
  979. // memcpy.
  980. void commitWhenFull(CPixelWriter * RESTRICT pLightmapPixelWriter) RESTRICT
  981. {
  982. unsigned char* RESTRICT pWriteInto = pLightmapPixelWriter->GetCurrentPixel();
  983. // we have to use memcpy because we're writing to non-cacheable memory,
  984. // but we can't even assume that the addresses we're writing to are
  985. // vector-aligned.
  986. #ifdef memcpy // if someone's overriden the intrinsic, complain
  987. #pragma error("You have overridden memcpy(), which is an XBOX360 intrinsic. This function will not behave optimally.")
  988. #endif
  989. // if we're full, use compile-time known version of
  990. // mempcy to take advantage of its ability to generate
  991. // inline code. In fact, use the dword-aligned
  992. // version so that we use the 64-bit writing funcs.
  993. Assert( m_wordsGathered == kWordsPerRow );
  994. COMPILE_TIME_ASSERT((kWordsPerRow & 3) == 0); // the number of words per row has to be a multiple of four
  995. memcpy(pWriteInto, reinterpret_cast<uint64* RESTRICT>(m_data[0]), kWordsPerRow * sizeof(uint32));
  996. pWriteInto += m_bytesBetweenWriterRows;
  997. memcpy(pWriteInto, reinterpret_cast<uint64* RESTRICT>(m_data[1]), kWordsPerRow * sizeof(uint32));
  998. pWriteInto += m_bytesBetweenWriterRows;
  999. memcpy(pWriteInto, reinterpret_cast<uint64* RESTRICT>(m_data[2]), kWordsPerRow * sizeof(uint32));
  1000. pWriteInto += m_bytesBetweenWriterRows;
  1001. memcpy(pWriteInto, reinterpret_cast<uint64* RESTRICT>(m_data[3]), kWordsPerRow * sizeof(uint32));
  1002. pLightmapPixelWriter->SkipBytes(m_wordsGathered * sizeof(uint32));
  1003. m_wordsGathered = 0;
  1004. }
  1005. // parameter: space between bump pages in the pixelwriter
  1006. CPixelWriterStoreGather(int writerSizeBytes) : m_wordsGathered(0), m_bytesBetweenWriterRows(writerSizeBytes) {};
  1007. };
  1008. }
  1009. // this is a function for specifically writing bumped BGRA lightmaps -- in order for it
  1010. // to be properly scheduled, I needed to break out the inline functions. Also,
  1011. // to make the write-combined memory more efficient (and work around a bug in the
  1012. // April 2007 XDK), we need to store-gather our writes on the cache before blasting
  1013. // them out to write-combined memory. We can't simply write from the SIMD registers
  1014. // into the pixelwriter's data, because the difference between the output rows,
  1015. // eg nLightmap0WriterSizeBytes[0], might not be a multiple of 16. Unaligned stores
  1016. // to non-cacheable memory cause an alignment exception.
  1017. static void BumpedLightmapBitsToPixelWriter_HDRI_BGRA_X360( float* RESTRICT pFloatImage, float * RESTRICT pFloatImageBump1, float * RESTRICT pFloatImageBump2,
  1018. float * RESTRICT pFloatImageBump3, int pLightmapSize[2], int pOffsetIntoLightmapPage[2], FloatBitMap_t *pfmOut,
  1019. CPixelWriter * RESTRICT m_LightmapPixelWriter)
  1020. {
  1021. AssertMsg(m_LightmapPixelWriter->GetPixelSize() == 4, "BGRA format is no longer four bytes long? This is unsupported on 360, and probably immoral as well.");
  1022. const int nLightmap0WriterSizeBytes = pLightmapSize[0] * 4 /*m_LightmapPixelWriter->GetPixelSize()*/;
  1023. // const int nRewindToNextPixel = -( ( nLightmap0WriterSizeBytes * 3 ) - 4 );
  1024. // assert that 1 * 4 = 4
  1025. COMPILE_TIME_ASSERT(sizeof( Vector4D ) == sizeof(float) * 4);
  1026. AssertMsg(!pfmOut, "Runtime conversion of lightmaps to files is no longer supported on 360.\n");
  1027. // The store-gather buffers. Hopefully these will live in the L1
  1028. // cache, which will make writing to them, then to memory, faster
  1029. // than just using __stvewx to write directly into WC memory
  1030. // one noncontiguous float at a time. (If there weren't a huge
  1031. // compiler bug with __stvewx in the Apr07 XDK, that might not
  1032. // be the case.)
  1033. CPixelWriterStoreGather storeGather(nLightmap0WriterSizeBytes);
  1034. for( int t = 0; t < pLightmapSize[1]; t++ )
  1035. {
  1036. #define FOUR (sizeof( Vector4D ) / sizeof( float )) // make explicit when we're incrementing by length of a 4dvec
  1037. int srcTexelOffset = ( FOUR ) * ( 0 + t * pLightmapSize[0] );
  1038. m_LightmapPixelWriter->Seek( pOffsetIntoLightmapPage[0], pOffsetIntoLightmapPage[1] + t );
  1039. // Our code works best when we can process luxels in groups of four. So,
  1040. // figure out how many four-luxel groups we can process,
  1041. // then do them in groups, then process the remainder.
  1042. unsigned int groupsOfFourLimit = (((unsigned int)pLightmapSize[0]) & ~3);
  1043. // we want to hang on to this index when we're done with groups so we can do the remainder.
  1044. unsigned int s; // counts the number of luxels processed
  1045. for( s = 0;
  1046. s < groupsOfFourLimit;
  1047. s += 4, srcTexelOffset += 4 * ( FOUR ))
  1048. {
  1049. static const fltx4 vSixteen = {16.0f, 16.0f, 16.0f, 16.0f};
  1050. // the store-gather simds
  1051. fltx4 outBaseMap = Four_Zeros, outBump1 = Four_Zeros, outBump2 = Four_Zeros, outBump3 = Four_Zeros;
  1052. // we'll read four at a time
  1053. fltx4 vFloatImage[4], vFloatImageBump1[4], vFloatImageBump2[4], vFloatImageBump3[4];
  1054. // stripe these loads to cause less ERAT thrashing
  1055. vFloatImage[0] = LoadUnalignedSIMD(pFloatImage + srcTexelOffset );
  1056. vFloatImage[1] = LoadUnalignedSIMD(pFloatImage + srcTexelOffset + 4 );
  1057. vFloatImage[2] = LoadUnalignedSIMD(pFloatImage + srcTexelOffset + 8 );
  1058. vFloatImage[3] = LoadUnalignedSIMD(pFloatImage + srcTexelOffset + 12 );
  1059. vFloatImageBump1[0] = LoadUnalignedSIMD(pFloatImageBump1 + srcTexelOffset );
  1060. vFloatImageBump1[1] = LoadUnalignedSIMD(pFloatImageBump1 + srcTexelOffset + 4 );
  1061. vFloatImageBump1[2] = LoadUnalignedSIMD(pFloatImageBump1 + srcTexelOffset + 8 );
  1062. vFloatImageBump1[3] = LoadUnalignedSIMD(pFloatImageBump1 + srcTexelOffset + 12 );
  1063. vFloatImageBump2[0] = LoadUnalignedSIMD(pFloatImageBump2 + srcTexelOffset );
  1064. vFloatImageBump2[1] = LoadUnalignedSIMD(pFloatImageBump2 + srcTexelOffset + 4 );
  1065. vFloatImageBump2[2] = LoadUnalignedSIMD(pFloatImageBump2 + srcTexelOffset + 8 );
  1066. vFloatImageBump2[3] = LoadUnalignedSIMD(pFloatImageBump2 + srcTexelOffset + 12 );
  1067. vFloatImageBump3[0] = LoadUnalignedSIMD(pFloatImageBump3 + srcTexelOffset );
  1068. vFloatImageBump3[1] = LoadUnalignedSIMD(pFloatImageBump3 + srcTexelOffset + 4 );
  1069. vFloatImageBump3[2] = LoadUnalignedSIMD(pFloatImageBump3 + srcTexelOffset + 8 );
  1070. vFloatImageBump3[3] = LoadUnalignedSIMD(pFloatImageBump3 + srcTexelOffset + 12 );
  1071. // perform an arcane averaging operation upon the bump map values
  1072. // (todo: make this not an inline so it will schedule better -- inlining is
  1073. // done by the linker, which is too late for operation scheduling)
  1074. ColorSpace::LinearToBumpedLightmap( vFloatImage[0], vFloatImageBump1[0],
  1075. vFloatImageBump2[0], vFloatImageBump3[0],
  1076. // transform "in place":
  1077. vFloatImage[0], vFloatImageBump1[0],
  1078. vFloatImageBump2[0], vFloatImageBump3[0] );
  1079. ColorSpace::LinearToBumpedLightmap( vFloatImage[1], vFloatImageBump1[1],
  1080. vFloatImageBump2[1], vFloatImageBump3[1],
  1081. // transform "in place":
  1082. vFloatImage[1], vFloatImageBump1[1],
  1083. vFloatImageBump2[1], vFloatImageBump3[1] );
  1084. ColorSpace::LinearToBumpedLightmap( vFloatImage[2], vFloatImageBump1[2],
  1085. vFloatImageBump2[2], vFloatImageBump3[2],
  1086. // transform "in place":
  1087. vFloatImage[2], vFloatImageBump1[2],
  1088. vFloatImageBump2[2], vFloatImageBump3[2] );
  1089. ColorSpace::LinearToBumpedLightmap( vFloatImage[3], vFloatImageBump1[3],
  1090. vFloatImageBump2[3], vFloatImageBump3[3],
  1091. // transform "in place":
  1092. vFloatImage[3], vFloatImageBump1[3],
  1093. vFloatImageBump2[3], vFloatImageBump3[3] );
  1094. // convert each color to RGB scaled.
  1095. // DO NOT! make this into a for loop. The (April07 XDK) compiler
  1096. // in fact DOES NOT unroll them, and will perform very naive
  1097. // scheduling if you try.
  1098. // clamp to 0..16 float
  1099. vFloatImage[0] = MinSIMD(vFloatImage[0], vSixteen);
  1100. vFloatImageBump1[0] = MinSIMD(vFloatImageBump1[0], vSixteen);
  1101. vFloatImageBump2[0] = MinSIMD(vFloatImageBump2[0], vSixteen);
  1102. vFloatImageBump3[0] = MinSIMD(vFloatImageBump3[0], vSixteen);
  1103. vFloatImage[1] = MinSIMD(vFloatImage[1], vSixteen);
  1104. vFloatImageBump1[1] = MinSIMD(vFloatImageBump1[1], vSixteen);
  1105. vFloatImageBump2[1] = MinSIMD(vFloatImageBump2[1], vSixteen);
  1106. vFloatImageBump3[1] = MinSIMD(vFloatImageBump3[1], vSixteen);
  1107. vFloatImage[2] = MinSIMD(vFloatImage[2], vSixteen);
  1108. vFloatImageBump1[2] = MinSIMD(vFloatImageBump1[2], vSixteen);
  1109. vFloatImageBump2[2] = MinSIMD(vFloatImageBump2[2], vSixteen);
  1110. vFloatImageBump3[2] = MinSIMD(vFloatImageBump3[2], vSixteen);
  1111. vFloatImage[3] = MinSIMD(vFloatImage[3], vSixteen);
  1112. vFloatImageBump1[3] = MinSIMD(vFloatImageBump1[3], vSixteen);
  1113. vFloatImageBump2[3] = MinSIMD(vFloatImageBump2[3], vSixteen);
  1114. vFloatImageBump3[3] = MinSIMD(vFloatImageBump3[3], vSixteen);
  1115. // compute the scaling factor, place it in w, and
  1116. // scale the rest by it. Obliterates whatever was
  1117. // already in alpha.
  1118. // This code is why it is important to not use a for
  1119. // loop: you need to let the compiler keep the value
  1120. // on registers (which it can't do if you use a
  1121. // variable indexed array) and interleave the
  1122. // inlined instructions.
  1123. vFloatImage[0] = PackPixel_BGRA8888( ConvertLightmapColorToRGBScale(vFloatImage[0]) );
  1124. vFloatImageBump1[0] = PackPixel_BGRA8888( ConvertLightmapColorToRGBScale(vFloatImageBump1[0]) );
  1125. vFloatImageBump2[0] = PackPixel_BGRA8888( ConvertLightmapColorToRGBScale(vFloatImageBump2[0]) );
  1126. vFloatImageBump3[0] = PackPixel_BGRA8888( ConvertLightmapColorToRGBScale(vFloatImageBump3[0]) );
  1127. vFloatImage[1] = PackPixel_BGRA8888( ConvertLightmapColorToRGBScale(vFloatImage[1]) );
  1128. vFloatImageBump1[1] = PackPixel_BGRA8888( ConvertLightmapColorToRGBScale(vFloatImageBump1[1]) );
  1129. vFloatImageBump2[1] = PackPixel_BGRA8888( ConvertLightmapColorToRGBScale(vFloatImageBump2[1]) );
  1130. vFloatImageBump3[1] = PackPixel_BGRA8888( ConvertLightmapColorToRGBScale(vFloatImageBump3[1]) );
  1131. vFloatImage[2] = PackPixel_BGRA8888( ConvertLightmapColorToRGBScale(vFloatImage[2]) );
  1132. vFloatImageBump1[2] = PackPixel_BGRA8888( ConvertLightmapColorToRGBScale(vFloatImageBump1[2]) );
  1133. vFloatImageBump2[2] = PackPixel_BGRA8888( ConvertLightmapColorToRGBScale(vFloatImageBump2[2]) );
  1134. vFloatImageBump3[2] = PackPixel_BGRA8888( ConvertLightmapColorToRGBScale(vFloatImageBump3[2]) );
  1135. vFloatImage[3] = PackPixel_BGRA8888( ConvertLightmapColorToRGBScale(vFloatImage[3]) );
  1136. vFloatImageBump1[3] = PackPixel_BGRA8888( ConvertLightmapColorToRGBScale(vFloatImageBump1[3]) );
  1137. vFloatImageBump2[3] = PackPixel_BGRA8888( ConvertLightmapColorToRGBScale(vFloatImageBump2[3]) );
  1138. vFloatImageBump3[3] = PackPixel_BGRA8888( ConvertLightmapColorToRGBScale(vFloatImageBump3[3]) );
  1139. // Each of the registers above contains one RGBA 32-bit struct
  1140. // in their w word. So, combine them such that each of the assignees
  1141. // below contains four RGBAs, in xyzw order (big-endian).
  1142. outBaseMap = __vrlimi(outBaseMap, vFloatImage[0], 8, 3 ); // insert into x
  1143. outBump1 = __vrlimi(outBump1, vFloatImageBump1[0], 8, 3 ); // insert into x
  1144. outBump2 = __vrlimi(outBump2, vFloatImageBump2[0], 8, 3 ); // insert into x
  1145. outBump3 = __vrlimi(outBump3, vFloatImageBump3[0], 8, 3 ); // insert into x
  1146. outBaseMap = __vrlimi(outBaseMap, vFloatImage[1], 4, 2 ); // insert into y
  1147. outBump1 = __vrlimi(outBump1, vFloatImageBump1[1], 4, 2 ); // insert into y
  1148. outBump2 = __vrlimi(outBump2, vFloatImageBump2[1], 4, 2 ); // insert into y
  1149. outBump3 = __vrlimi(outBump3, vFloatImageBump3[1], 4, 2 ); // insert into y
  1150. outBaseMap = __vrlimi(outBaseMap, vFloatImage[2], 2, 1 ); // insert into z
  1151. outBump1 = __vrlimi(outBump1, vFloatImageBump1[2], 2, 1 ); // insert into z
  1152. outBump2 = __vrlimi(outBump2, vFloatImageBump2[2], 2, 1 ); // insert into z
  1153. outBump3 = __vrlimi(outBump3, vFloatImageBump3[2], 2, 1 ); // insert into z
  1154. outBaseMap = __vrlimi(outBaseMap, vFloatImage[3], 1, 0 ); // insert into w
  1155. outBump1 = __vrlimi(outBump1, vFloatImageBump1[3], 1, 0 ); // insert into w
  1156. outBump2 = __vrlimi(outBump2, vFloatImageBump2[3], 1, 0 ); // insert into w
  1157. outBump3 = __vrlimi(outBump3, vFloatImageBump3[3], 1, 0 ); // insert into w
  1158. // push the data through the store-gather buffer.
  1159. storeGather.write(m_LightmapPixelWriter, outBaseMap, outBump1, outBump2, outBump3);
  1160. }
  1161. // Once here, make sure we've committed any leftover changes, then process
  1162. // the remainders singly.
  1163. storeGather.commit(m_LightmapPixelWriter);
  1164. for( ; // s is where it should be from the loop above
  1165. s < (unsigned int) pLightmapSize[0];
  1166. s++,
  1167. // m_LightmapPixelWriter->SkipBytes(nRewindToNextPixel), // now handled by store-gather
  1168. srcTexelOffset += ( FOUR ))
  1169. {
  1170. static const fltx4 vSixteen = {16.0f, 16.0f, 16.0f, 16.0f};
  1171. fltx4 vColor[4];
  1172. fltx4 vFloatImage = LoadUnalignedSIMD(&pFloatImage[srcTexelOffset]);
  1173. fltx4 vFloatImageBump1 = LoadUnalignedSIMD(&pFloatImageBump1[srcTexelOffset]);
  1174. fltx4 vFloatImageBump2 = LoadUnalignedSIMD(&pFloatImageBump2[srcTexelOffset]);
  1175. fltx4 vFloatImageBump3 = LoadUnalignedSIMD(&pFloatImageBump3[srcTexelOffset]);
  1176. // perform an arcane averaging operation upon the bump map values
  1177. ColorSpace::LinearToBumpedLightmap( vFloatImage,
  1178. vFloatImageBump1, vFloatImageBump2,
  1179. vFloatImageBump3,
  1180. vColor[0], vColor[1], vColor[2], vColor[3] );
  1181. // convert each color to RGB scaled.
  1182. // DO NOT! make this into a for loop. The (April07 XDK) compiler
  1183. // in fact DOES NOT unroll them, and will perform very naive
  1184. // scheduling if you try.
  1185. // clamp to 0..16 float
  1186. vColor[0] = MinSIMD(vColor[0], vSixteen);
  1187. vColor[1] = MinSIMD(vColor[1], vSixteen);
  1188. vColor[2] = MinSIMD(vColor[2], vSixteen);
  1189. vColor[3] = MinSIMD(vColor[3], vSixteen);
  1190. // compute the scaling factor, place it in w, and
  1191. // scale the rest by it. Obliterates whatever was
  1192. // already in alpha.
  1193. // This code is why it is important to not use a for
  1194. // loop: you need to let the compiler interleave the
  1195. // inlined instructions.
  1196. vColor[0] = ConvertLightmapColorToRGBScale( vColor[0] );
  1197. vColor[1] = ConvertLightmapColorToRGBScale( vColor[1] );
  1198. vColor[2] = ConvertLightmapColorToRGBScale( vColor[2] );
  1199. vColor[3] = ConvertLightmapColorToRGBScale( vColor[3] );
  1200. #ifdef X360_DOUBLECHECK_LIGHTMAPS
  1201. unsigned short color[4][4];
  1202. ColorSpace::LinearToBumpedLightmap( &pFloatImage[srcTexelOffset],
  1203. &pFloatImageBump1[srcTexelOffset], &pFloatImageBump2[srcTexelOffset],
  1204. &pFloatImageBump3[srcTexelOffset],
  1205. color[0], color[1], color[2], color[3] );
  1206. unsigned short alpha = ColorSpace::LinearToUnsignedShort( pFloatImage[srcTexelOffset+3], 16 );
  1207. color[0][3] = color[1][3] = color[2][3] = color[3][3] = alpha;
  1208. if( IsX360() )
  1209. {
  1210. for( int i = 0; i != 4; ++i )
  1211. {
  1212. Vector4D vRGBScale;
  1213. vRGBScale.x = color[i][0] * (16.0f / 65535.0f);
  1214. vRGBScale.y = color[i][1] * (16.0f / 65535.0f);
  1215. vRGBScale.z = color[i][2] * (16.0f / 65535.0f);
  1216. vRGBScale = ConvertLightmapColorToRGBScale( &vRGBScale.x );
  1217. color[i][0] = RoundFloatToByte( vRGBScale.x * 255.0f );
  1218. color[i][1] = RoundFloatToByte( vRGBScale.y * 255.0f );
  1219. color[i][2] = RoundFloatToByte( vRGBScale.z * 255.0f );
  1220. color[i][3] = RoundFloatToByte( vRGBScale.w * 255.0f );
  1221. }
  1222. }
  1223. /*
  1224. for (int ii = 0; ii < 4; ++ii)
  1225. {
  1226. uint32 pack = (PackPixel_BGRA8888( vColor[ii] ).u[3]);
  1227. if (color[ii][3] != 0)
  1228. Assert( color[ii][0] == (pack & 0xFF0000) >> 16 &&
  1229. color[ii][1] == (pack & 0xFF00) >> 8 &&
  1230. color[ii][2] == (pack & 0xFF) &&
  1231. color[ii][3] == (pack & 0xFF000000) >> 24 );
  1232. }
  1233. */
  1234. #endif
  1235. vColor[0] = PackPixel_BGRA8888( vColor[0] );
  1236. vColor[1] = PackPixel_BGRA8888( vColor[1] );
  1237. vColor[2] = PackPixel_BGRA8888( vColor[2] );
  1238. vColor[3] = PackPixel_BGRA8888( vColor[3] );
  1239. storeGather.writeJustW(m_LightmapPixelWriter, vColor[0], vColor[1], vColor[2], vColor[3] );
  1240. /* // here is the old way of writing pixels:
  1241. // now we store-gather this
  1242. m_LightmapPixelWriter->WritePixelNoAdvance_BGRA8888( vColor[0] );
  1243. Assert(*reinterpret_cast<unsigned int *>(m_LightmapPixelWriter->GetCurrentPixel()) == PackPixel_BGRA8888( vColor[0] ).u[3] );
  1244. void * RESTRICT pBits = m_LightmapPixelWriter->SkipBytes( nLightmap0WriterSizeBytes );
  1245. m_LightmapPixelWriter->WritePixelNoAdvance_BGRA8888( vColor[1], pBits );
  1246. Assert(*reinterpret_cast<unsigned int *>(m_LightmapPixelWriter->GetCurrentPixel()) == PackPixel_BGRA8888( vColor[1] ).u[3] );
  1247. pBits = m_LightmapPixelWriter->SkipBytes( nLightmap0WriterSizeBytes );
  1248. m_LightmapPixelWriter->WritePixelNoAdvance_BGRA8888( vColor[2], pBits );
  1249. Assert(*reinterpret_cast<unsigned int *>(m_LightmapPixelWriter->GetCurrentPixel()) == PackPixel_BGRA8888( vColor[2] ).u[3] );
  1250. pBits = m_LightmapPixelWriter->SkipBytes( nLightmap0WriterSizeBytes );
  1251. m_LightmapPixelWriter->WritePixelNoAdvance_BGRA8888( vColor[3], pBits );
  1252. Assert(*reinterpret_cast<unsigned int *>(m_LightmapPixelWriter->GetCurrentPixel()) == PackPixel_BGRA8888( vColor[3] ).u[3] );
  1253. m_LightmapPixelWriter->SkipBytes(nRewindToNextPixel);
  1254. */
  1255. }
  1256. storeGather.commit(m_LightmapPixelWriter);
  1257. }
  1258. }
  1259. #endif //_X360
  1260. // write bumped lightmap update to HDR integer lightmap
  1261. void CMatLightmaps::BumpedLightmapBitsToPixelWriter_HDRI( float* RESTRICT pFloatImage, float * RESTRICT pFloatImageBump1, float * RESTRICT pFloatImageBump2,
  1262. float * RESTRICT pFloatImageBump3, int pLightmapSize[2], int pOffsetIntoLightmapPage[2], FloatBitMap_t *pfmOut ) RESTRICT
  1263. {
  1264. const int nLightmapSize0 = pLightmapSize[0];
  1265. const int nLightmap0WriterSizeBytes = nLightmapSize0 * m_LightmapPixelWriter.GetPixelSize();
  1266. const int nRewindToNextPixel = -( ( nLightmap0WriterSizeBytes * 3 ) - m_LightmapPixelWriter.GetPixelSize() );
  1267. if( m_LightmapPixelWriter.IsUsingFloatFormat() )
  1268. {
  1269. AssertMsg(!IsX360(), "Tried to use a floating-point pixel format for lightmaps on 360, which is not supported.");
  1270. if (!IsX360())
  1271. {
  1272. for( int t = 0; t < pLightmapSize[1]; t++ )
  1273. {
  1274. int srcTexelOffset = ( sizeof( Vector4D ) / sizeof( float ) ) * ( 0 + t * nLightmapSize0 );
  1275. m_LightmapPixelWriter.Seek( pOffsetIntoLightmapPage[0], pOffsetIntoLightmapPage[1] + t );
  1276. for( int s = 0;
  1277. s < nLightmapSize0;
  1278. s++, m_LightmapPixelWriter.SkipBytes(nRewindToNextPixel),srcTexelOffset += (sizeof(Vector4D)/sizeof(float)))
  1279. {
  1280. unsigned short color[4][4];
  1281. ColorSpace::LinearToBumpedLightmap( &pFloatImage[srcTexelOffset],
  1282. &pFloatImageBump1[srcTexelOffset], &pFloatImageBump2[srcTexelOffset],
  1283. &pFloatImageBump3[srcTexelOffset],
  1284. color[0], color[1], color[2], color[3] );
  1285. float alpha = pFloatImage[srcTexelOffset+3];
  1286. Assert( alpha >= 0.0f && alpha <= 1.0f );
  1287. if ( HardwareConfig()->GetCSMAccurateBlending() )
  1288. {
  1289. float alphaF[4];
  1290. ColorSpace::LinearToBumpedLightmapAlpha( &pFloatImage[srcTexelOffset + 3],
  1291. &pFloatImageBump1[srcTexelOffset + 3], &pFloatImageBump2[srcTexelOffset + 3], &pFloatImageBump3[srcTexelOffset + 3],
  1292. &alphaF[0], &alphaF[1], &alphaF[2], &alphaF[3] );
  1293. unsigned short alphaUS[4];
  1294. alphaUS[0] = ColorSpace::LinearToUnsignedShort( alphaF[0], 16 );
  1295. alphaUS[1] = ColorSpace::LinearToUnsignedShort( alphaF[1], 16 );
  1296. alphaUS[2] = ColorSpace::LinearToUnsignedShort( alphaF[2], 16 );
  1297. alphaUS[3] = ColorSpace::LinearToUnsignedShort( alphaF[3], 16 );
  1298. color[0][3] = alphaUS[0];
  1299. color[1][3] = alphaUS[1];
  1300. color[2][3] = alphaUS[2];
  1301. color[3][3] = alphaUS[3];
  1302. }
  1303. else
  1304. {
  1305. color[0][3] = color[1][3] = color[2][3] = color[3][3] = alpha;
  1306. }
  1307. float toFloat = ( 1.0f / ( float )( 1 << 16 ) );
  1308. /* // This code is now a can't-happen, because we do not allow float formats on 360.
  1309. #if ( defined( USE_32BIT_LIGHTMAPS_ON_360 ) )
  1310. if( IsX360() )
  1311. {
  1312. for( int i = 0; i != 4; ++i )
  1313. {
  1314. Vector4D vRGBScale;
  1315. vRGBScale.x = color[i][0] * (16.0f / 65535.0f);
  1316. vRGBScale.y = color[i][1] * (16.0f / 65535.0f);
  1317. vRGBScale.z = color[i][2] * (16.0f / 65535.0f);
  1318. vRGBScale = ConvertLightmapColorToRGBScale( &vRGBScale.x );
  1319. color[i][0] = RoundFloatToByte( vRGBScale.x * 255.0f );
  1320. color[i][1] = RoundFloatToByte( vRGBScale.y * 255.0f );
  1321. color[i][2] = RoundFloatToByte( vRGBScale.z * 255.0f );
  1322. color[i][3] = RoundFloatToByte( vRGBScale.w * 255.0f );
  1323. }
  1324. toFloat = ( 1.0f / ( float )( 1 << 8 ) );
  1325. }
  1326. #endif
  1327. */
  1328. m_LightmapPixelWriter.WritePixelNoAdvanceF( toFloat * color[0][0], toFloat * color[0][1], toFloat * color[0][2], toFloat * color[0][3] );
  1329. m_LightmapPixelWriter.SkipBytes( nLightmap0WriterSizeBytes );
  1330. m_LightmapPixelWriter.WritePixelNoAdvanceF( toFloat * color[1][0], toFloat * color[1][1], toFloat * color[1][2], toFloat * color[1][3] );
  1331. m_LightmapPixelWriter.SkipBytes( nLightmap0WriterSizeBytes );
  1332. m_LightmapPixelWriter.WritePixelNoAdvanceF( toFloat * color[2][0], toFloat * color[2][1], toFloat * color[2][2], toFloat * color[2][3] );
  1333. m_LightmapPixelWriter.SkipBytes( nLightmap0WriterSizeBytes );
  1334. m_LightmapPixelWriter.WritePixelNoAdvanceF( toFloat * color[3][0], toFloat * color[3][1], toFloat * color[3][2], toFloat * color[3][3] );
  1335. }
  1336. }
  1337. }
  1338. }
  1339. else
  1340. {
  1341. #ifndef X360_USE_SIMD_LIGHTMAP
  1342. for( int t = 0; t < pLightmapSize[1]; t++ )
  1343. {
  1344. int srcTexelOffset = ( sizeof( Vector4D ) / sizeof( float ) ) * ( 0 + t * nLightmapSize0 );
  1345. m_LightmapPixelWriter.Seek( pOffsetIntoLightmapPage[0], pOffsetIntoLightmapPage[1] + t );
  1346. for( int s = 0;
  1347. s < nLightmapSize0;
  1348. s++, m_LightmapPixelWriter.SkipBytes(nRewindToNextPixel),srcTexelOffset += (sizeof(Vector4D)/sizeof(float)))
  1349. {
  1350. unsigned short color[4][4];
  1351. ColorSpace::LinearToBumpedLightmap( &pFloatImage[srcTexelOffset],
  1352. &pFloatImageBump1[srcTexelOffset], &pFloatImageBump2[srcTexelOffset],
  1353. &pFloatImageBump3[srcTexelOffset],
  1354. color[0], color[1], color[2], color[3] );
  1355. if ( HardwareConfig()->GetCSMAccurateBlending() )
  1356. {
  1357. float alpha[4];
  1358. ColorSpace::LinearToBumpedLightmapAlpha( &pFloatImage[srcTexelOffset + 3],
  1359. &pFloatImageBump1[srcTexelOffset + 3], &pFloatImageBump2[srcTexelOffset + 3], &pFloatImageBump3[srcTexelOffset + 3],
  1360. &alpha[0], &alpha[1], &alpha[2], &alpha[3] );
  1361. unsigned short alphaUS[4];
  1362. alphaUS[0] = ColorSpace::LinearToUnsignedShort( alpha[0], 16 );
  1363. alphaUS[1] = ColorSpace::LinearToUnsignedShort( alpha[1], 16 );
  1364. alphaUS[2] = ColorSpace::LinearToUnsignedShort( alpha[2], 16 );
  1365. alphaUS[3] = ColorSpace::LinearToUnsignedShort( alpha[3], 16 );
  1366. color[0][3] = alphaUS[0];
  1367. color[1][3] = alphaUS[1];
  1368. color[2][3] = alphaUS[2];
  1369. color[3][3] = alphaUS[3];
  1370. }
  1371. else
  1372. {
  1373. unsigned short alpha = ColorSpace::LinearToUnsignedShort( pFloatImage[srcTexelOffset+3], 16 );
  1374. color[0][3] = color[1][3] = color[2][3] = color[3][3] = alpha;
  1375. }
  1376. #if ( defined( USE_32BIT_LIGHTMAPS_ON_360 ) )
  1377. if( IsX360() )
  1378. {
  1379. for( int i = 0; i != 4; ++i )
  1380. {
  1381. Vector4D vRGBScale;
  1382. vRGBScale.x = color[i][0] * (16.0f / 65535.0f);
  1383. vRGBScale.y = color[i][1] * (16.0f / 65535.0f);
  1384. vRGBScale.z = color[i][2] * (16.0f / 65535.0f);
  1385. vRGBScale = ConvertLightmapColorToRGBScale( &vRGBScale.x );
  1386. color[i][0] = RoundFloatToByte( vRGBScale.x * 255.0f );
  1387. color[i][1] = RoundFloatToByte( vRGBScale.y * 255.0f );
  1388. color[i][2] = RoundFloatToByte( vRGBScale.z * 255.0f );
  1389. color[i][3] = RoundFloatToByte( vRGBScale.w * 255.0f );
  1390. }
  1391. }
  1392. #endif
  1393. m_LightmapPixelWriter.WritePixelNoAdvance( color[0][0], color[0][1], color[0][2], color[0][3] );
  1394. m_LightmapPixelWriter.SkipBytes( nLightmap0WriterSizeBytes );
  1395. m_LightmapPixelWriter.WritePixelNoAdvance( color[1][0], color[1][1], color[1][2], color[1][3] );
  1396. m_LightmapPixelWriter.SkipBytes( nLightmap0WriterSizeBytes );
  1397. m_LightmapPixelWriter.WritePixelNoAdvance( color[2][0], color[2][1], color[2][2], color[2][3] );
  1398. m_LightmapPixelWriter.SkipBytes( nLightmap0WriterSizeBytes );
  1399. m_LightmapPixelWriter.WritePixelNoAdvance( color[3][0], color[3][1], color[3][2], color[3][3] );
  1400. // Write data to the bitmapped represenations so that PFM files can be written
  1401. if ( pfmOut )
  1402. {
  1403. PixRGBAF pixelData;
  1404. pixelData.Red = color[0][0];
  1405. pixelData.Green = color[0][1];
  1406. pixelData.Blue = color[0][2];
  1407. pixelData.Alpha = color[0][3];
  1408. pfmOut->WritePixelRGBAF(pOffsetIntoLightmapPage[0] + s, pOffsetIntoLightmapPage[1] + t, 0, pixelData);
  1409. }
  1410. }
  1411. }
  1412. #else
  1413. // this is an optimized XBOX implementation. For a clearer
  1414. // presentation of the algorithm, see the PC implementation
  1415. // above.
  1416. // First check for the most common case, using an efficient
  1417. // branch rather than a switch:
  1418. if (m_LightmapPixelWriter.GetFormat() == IMAGE_FORMAT_LINEAR_BGRA8888)
  1419. {
  1420. // broken out into a static to make things more readable
  1421. // and be nicer to the instruction cache
  1422. BumpedLightmapBitsToPixelWriter_HDRI_BGRA_X360( pFloatImage, pFloatImageBump1, pFloatImageBump2,
  1423. pFloatImageBump3, pLightmapSize, pOffsetIntoLightmapPage, pfmOut, &m_LightmapPixelWriter );
  1424. }
  1425. else
  1426. {
  1427. // This case is used in Portal 2 to fill RGBA16161616 lightmaps
  1428. Assert( m_LightmapPixelWriter.GetPixelSize() == 8 );
  1429. for( int t = 0; t < pLightmapSize[1]; t++ )
  1430. {
  1431. // assert that 1 * 4 = 4
  1432. COMPILE_TIME_ASSERT(sizeof( Vector4D ) == sizeof(float) * 4);
  1433. #define FOUR (sizeof( Vector4D ) / sizeof( float )) // in case this ever changes
  1434. int srcTexelOffset = ( FOUR ) * ( 0 + t * nLightmapSize0 );
  1435. m_LightmapPixelWriter.Seek( pOffsetIntoLightmapPage[0], pOffsetIntoLightmapPage[1] + t );
  1436. for( int s = 0;
  1437. s < nLightmapSize0;
  1438. s++, m_LightmapPixelWriter.SkipBytes(nRewindToNextPixel),srcTexelOffset += ( FOUR ))
  1439. {
  1440. static const fltx4 vSixteen = {16.0f, 16.0f, 16.0f, 16.0f};
  1441. fltx4 vColor[4];
  1442. fltx4 vFloatImage = LoadUnalignedSIMD(&pFloatImage[srcTexelOffset]);
  1443. fltx4 vFloatImageBump1 = LoadUnalignedSIMD(&pFloatImageBump1[srcTexelOffset]);
  1444. fltx4 vFloatImageBump2 = LoadUnalignedSIMD(&pFloatImageBump2[srcTexelOffset]);
  1445. fltx4 vFloatImageBump3 = LoadUnalignedSIMD(&pFloatImageBump3[srcTexelOffset]);
  1446. // perform an arcane averaging operation upon the bump map values
  1447. ColorSpace::LinearToBumpedLightmap( vFloatImage,
  1448. vFloatImageBump1, vFloatImageBump2,
  1449. vFloatImageBump3,
  1450. vColor[0], vColor[1], vColor[2], vColor[3] );
  1451. // convert each color to RGB scaled.
  1452. // DO NOT! make this into a for loop. The (April07 XDK) compiler
  1453. // in fact DOES NOT unroll them, and will perform very naive
  1454. // scheduling if you try.
  1455. // clamp to 0..16 float
  1456. vColor[0] = MinSIMD(vColor[0], vSixteen);
  1457. vColor[1] = MinSIMD(vColor[1], vSixteen);
  1458. vColor[2] = MinSIMD(vColor[2], vSixteen);
  1459. vColor[3] = MinSIMD(vColor[3], vSixteen);
  1460. // Not doing the following anymore. This path is for writing 16161616 int lightmaps.
  1461. /*
  1462. // compute the scaling factor, transform the RGB,
  1463. // and place the scale in w. Obliterates whatever was
  1464. // already in alpha.
  1465. // This code is why it is important to not use a for
  1466. // loop: you need to let the compiler interleave the
  1467. // inlined instructions.
  1468. vColor[0] = ConvertLightmapColorToRGBScale( vColor[0] );
  1469. vColor[1] = ConvertLightmapColorToRGBScale( vColor[1] );
  1470. vColor[2] = ConvertLightmapColorToRGBScale( vColor[2] );
  1471. vColor[3] = ConvertLightmapColorToRGBScale( vColor[3] );
  1472. */
  1473. m_LightmapPixelWriter.WritePixelNoAdvance( vColor[0] );
  1474. m_LightmapPixelWriter.SkipBytes( nLightmap0WriterSizeBytes );
  1475. m_LightmapPixelWriter.WritePixelNoAdvance( vColor[1] );
  1476. m_LightmapPixelWriter.SkipBytes( nLightmap0WriterSizeBytes );
  1477. m_LightmapPixelWriter.WritePixelNoAdvance( vColor[2] );
  1478. m_LightmapPixelWriter.SkipBytes( nLightmap0WriterSizeBytes );
  1479. m_LightmapPixelWriter.WritePixelNoAdvance( vColor[3] );
  1480. AssertMsg(!pfmOut, "Runtime conversion of lightmaps to files is no longer supported on 360.\n");
  1481. // Write data to the bitmapped represenations so that PFM files can be written
  1482. if ( pfmOut )
  1483. {
  1484. Warning("**************************************************\n"
  1485. "Lightmap output to files on 360 HAS BEEN DISABLED.\n"
  1486. "A grave error has just occurred.\n"
  1487. "**************************************************\n");
  1488. DebuggerBreakIfDebugging();
  1489. /*
  1490. PixRGBAF pixelData;
  1491. pixelData.Red = color[0][0];
  1492. pixelData.Green = color[0][1];
  1493. pixelData.Blue = color[0][2];
  1494. pixelData.Alpha = alpha;
  1495. pfmOut->WritePixelRGBAF(pOffsetIntoLightmapPage[0] + s, pOffsetIntoLightmapPage[1] + t, pixelData);
  1496. */
  1497. }
  1498. }
  1499. }
  1500. }
  1501. #endif
  1502. }
  1503. }
  1504. void CMatLightmaps::LightmapBitsToPixelWriter_LDR( float* pFloatImage, int pLightmapSize[2], int pOffsetIntoLightmapPage[2], FloatBitMap_t *pfmOut )
  1505. {
  1506. // non-HDR lightmap processing
  1507. float *pSrc = pFloatImage;
  1508. for( int t = 0; t < pLightmapSize[1]; ++t )
  1509. {
  1510. m_LightmapPixelWriter.Seek( pOffsetIntoLightmapPage[0], pOffsetIntoLightmapPage[1] + t );
  1511. for( int s = 0; s < pLightmapSize[0]; ++s, pSrc += (sizeof(Vector4D)/sizeof(*pSrc)) )
  1512. {
  1513. unsigned char color[4];
  1514. ColorSpace::LinearToLightmap( color, pSrc );
  1515. if ( HardwareConfig()->GetCSMAccurateBlending() )
  1516. {
  1517. ColorSpace::LinearToLightmapAlpha( &color[3], pSrc[3] );
  1518. }
  1519. else
  1520. {
  1521. color[3] = RoundFloatToByte( pSrc[3] * 255.0f );
  1522. }
  1523. m_LightmapPixelWriter.WritePixel( color[0], color[1], color[2], color[3] );
  1524. if ( pfmOut )
  1525. {
  1526. // Write data to the bitmapped represenations so that PFM files can be written
  1527. PixRGBAF pixelData;
  1528. pixelData.Red = color[0];
  1529. pixelData.Green = color[1];
  1530. pixelData.Blue = color[2];
  1531. pixelData.Alpha = color[3];
  1532. pfmOut->WritePixelRGBAF( pOffsetIntoLightmapPage[0] + s, pOffsetIntoLightmapPage[1] + t, 0, pixelData );
  1533. }
  1534. }
  1535. }
  1536. }
  1537. void CMatLightmaps::LightmapBitsToPixelWriter_HDRF( float* pFloatImage, int pLightmapSize[2], int pOffsetIntoLightmapPage[2], FloatBitMap_t *pfmOut )
  1538. {
  1539. if ( IsX360() )
  1540. {
  1541. // 360 does not support HDR float
  1542. Assert( 0 );
  1543. return;
  1544. }
  1545. // float HDR lightmap processing
  1546. float *pSrc = pFloatImage;
  1547. for ( int t = 0; t < pLightmapSize[1]; ++t )
  1548. {
  1549. m_LightmapPixelWriter.Seek( pOffsetIntoLightmapPage[0], pOffsetIntoLightmapPage[1] + t );
  1550. if ( HardwareConfig()->GetCSMAccurateBlending() )
  1551. {
  1552. ColorSpace::LinearToLightmapAlpha( &pSrc[3] );
  1553. }
  1554. for ( int s = 0; s < pLightmapSize[0]; ++s, pSrc += (sizeof(Vector4D)/sizeof(*pSrc)) )
  1555. {
  1556. m_LightmapPixelWriter.WritePixelF( pSrc[0], pSrc[1], pSrc[2], pSrc[3] );
  1557. }
  1558. }
  1559. }
  1560. // numbers come in on the domain [0..16]
  1561. void CMatLightmaps::LightmapBitsToPixelWriter_HDRI( float* RESTRICT pFloatImage, int pLightmapSize[2], int pOffsetIntoLightmapPage[2], FloatBitMap_t * RESTRICT pfmOut )
  1562. {
  1563. #ifndef X360_USE_SIMD_LIGHTMAP
  1564. // PC code (and old, pre-SIMD xbox version -- unshippably slow)
  1565. if ( m_LightmapPixelWriter.IsUsingFloatFormat() )
  1566. {
  1567. // integer HDR lightmap processing
  1568. float *pSrc = pFloatImage;
  1569. for ( int t = 0; t < pLightmapSize[1]; ++t )
  1570. {
  1571. m_LightmapPixelWriter.Seek( pOffsetIntoLightmapPage[0], pOffsetIntoLightmapPage[1] + t );
  1572. for ( int s = 0; s < pLightmapSize[0]; ++s, pSrc += (sizeof(Vector4D)/sizeof(*pSrc)) )
  1573. {
  1574. int r, g, b, a;
  1575. r = ColorSpace::LinearFloatToCorrectedShort( pSrc[0] );
  1576. g = ColorSpace::LinearFloatToCorrectedShort( pSrc[1] );
  1577. b = ColorSpace::LinearFloatToCorrectedShort( pSrc[2] );
  1578. if ( HardwareConfig()->GetCSMAccurateBlending() )
  1579. {
  1580. ColorSpace::LinearToLightmapAlpha( &a, pSrc[3] );
  1581. }
  1582. else
  1583. {
  1584. a = ColorSpace::LinearToUnsignedShort( pSrc[3], 16 );
  1585. }
  1586. float toFloat = ( 1.0f / ( float )( 1 << 16 ) );
  1587. #if ( defined( USE_32BIT_LIGHTMAPS_ON_360 ) )
  1588. if( IsX360() )
  1589. {
  1590. Vector4D vRGBScale;
  1591. vRGBScale.x = r * (16.0f / 65535.0f);
  1592. vRGBScale.y = g * (16.0f / 65535.0f);
  1593. vRGBScale.z = b * (16.0f / 65535.0f);
  1594. vRGBScale = ConvertLightmapColorToRGBScale( &vRGBScale.x );
  1595. r = RoundFloatToByte( vRGBScale.x * 255.0f );
  1596. g = RoundFloatToByte( vRGBScale.y * 255.0f );
  1597. b = RoundFloatToByte( vRGBScale.z * 255.0f );
  1598. a = RoundFloatToByte( vRGBScale.w * 255.0f );
  1599. toFloat = ( 1.0f / ( float )( 1 << 8 ) );
  1600. }
  1601. #endif
  1602. Assert( pSrc[3] >= 0.0f && pSrc[3] <= 1.0f );
  1603. m_LightmapPixelWriter.WritePixelF( r * toFloat, g * toFloat, b * toFloat, pSrc[3] );
  1604. }
  1605. }
  1606. }
  1607. else
  1608. {
  1609. // integer HDR lightmap processing
  1610. float *pSrc = pFloatImage;
  1611. for ( int t = 0; t < pLightmapSize[1]; ++t )
  1612. {
  1613. m_LightmapPixelWriter.Seek( pOffsetIntoLightmapPage[0], pOffsetIntoLightmapPage[1] + t );
  1614. for ( int s = 0; s < pLightmapSize[0]; ++s, pSrc += (sizeof(Vector4D)/sizeof(*pSrc)) )
  1615. {
  1616. int r, g, b, a;
  1617. r = ColorSpace::LinearFloatToCorrectedShort( pSrc[0] );
  1618. g = ColorSpace::LinearFloatToCorrectedShort( pSrc[1] );
  1619. b = ColorSpace::LinearFloatToCorrectedShort( pSrc[2] );
  1620. if ( HardwareConfig()->GetCSMAccurateBlending() )
  1621. {
  1622. ColorSpace::LinearToLightmapAlpha( &a, pSrc[3] );
  1623. }
  1624. else
  1625. {
  1626. a = ColorSpace::LinearToUnsignedShort( pSrc[3], 16 );
  1627. }
  1628. #if ( defined( USE_32BIT_LIGHTMAPS_ON_360 ) )
  1629. if( IsX360() )
  1630. {
  1631. Vector4D vRGBScale;
  1632. vRGBScale.x = r * (16.0f / 65535.0f);
  1633. vRGBScale.y = g * (16.0f / 65535.0f);
  1634. vRGBScale.z = b * (16.0f / 65535.0f);
  1635. vRGBScale = ConvertLightmapColorToRGBScale( &vRGBScale.x );
  1636. r = RoundFloatToByte( vRGBScale.x * 255.0f );
  1637. g = RoundFloatToByte( vRGBScale.y * 255.0f );
  1638. b = RoundFloatToByte( vRGBScale.z * 255.0f );
  1639. a = RoundFloatToByte( vRGBScale.w * 255.0f );
  1640. }
  1641. #endif
  1642. m_LightmapPixelWriter.WritePixel( r, g, b, a );
  1643. if ( pfmOut )
  1644. {
  1645. // Write data to the bitmapped represenations so that PFM files can be written
  1646. PixRGBAF pixelData;
  1647. pixelData.Red = pSrc[0];
  1648. pixelData.Green = pSrc[1];
  1649. pixelData.Blue = pSrc[2];
  1650. pixelData.Alpha = pSrc[3];
  1651. pfmOut->WritePixelRGBAF( pOffsetIntoLightmapPage[0] + s, pOffsetIntoLightmapPage[1] + t, 0, pixelData );
  1652. }
  1653. }
  1654. }
  1655. }
  1656. #else
  1657. // XBOX360 code
  1658. if ( m_LightmapPixelWriter.IsUsingFloatFormat() )
  1659. {
  1660. if( IsX360() )
  1661. {
  1662. AssertMsg( false, "Float-format pixel writers do not exist on x360." );
  1663. }
  1664. else
  1665. { // This code is here as an example only, in case floating point
  1666. // format is restored to 360.
  1667. // integer HDR lightmap processing
  1668. float * RESTRICT pSrc = pFloatImage;
  1669. for ( int t = 0; t < pLightmapSize[1]; ++t )
  1670. {
  1671. m_LightmapPixelWriter.Seek( pOffsetIntoLightmapPage[0], pOffsetIntoLightmapPage[1] + t );
  1672. for ( int s = 0; s < pLightmapSize[0]; ++s, pSrc += (sizeof(Vector4D)/sizeof(*pSrc)) )
  1673. {
  1674. int r, g, b, a;
  1675. r = ColorSpace::LinearFloatToCorrectedShort( pSrc[0] );
  1676. g = ColorSpace::LinearFloatToCorrectedShort( pSrc[1] );
  1677. b = ColorSpace::LinearFloatToCorrectedShort( pSrc[2] );
  1678. a = ColorSpace::LinearToUnsignedShort( pSrc[3], 16 );
  1679. float toFloat = ( 1.0f / ( float )( 1 << 16 ) );
  1680. #if ( defined( USE_32BIT_LIGHTMAPS_ON_360 ) )
  1681. if( IsX360() )
  1682. {
  1683. Vector4D vRGBScale;
  1684. vRGBScale.x = r * (16.0f / 65535.0f);
  1685. vRGBScale.y = g * (16.0f / 65535.0f);
  1686. vRGBScale.z = b * (16.0f / 65535.0f);
  1687. vRGBScale = ConvertLightmapColorToRGBScale( &vRGBScale.x );
  1688. r = RoundFloatToByte( vRGBScale.x * 255.0f );
  1689. g = RoundFloatToByte( vRGBScale.y * 255.0f );
  1690. b = RoundFloatToByte( vRGBScale.z * 255.0f );
  1691. a = RoundFloatToByte( vRGBScale.w * 255.0f );
  1692. toFloat = ( 1.0f / ( float )( 1 << 8 ) );
  1693. }
  1694. #endif
  1695. Assert( pSrc[3] >= 0.0f && pSrc[3] <= 1.0f );
  1696. m_LightmapPixelWriter.WritePixelF( r * toFloat, g * toFloat, b * toFloat, pSrc[3] );
  1697. }
  1698. }
  1699. }
  1700. }
  1701. else
  1702. {
  1703. // This is the fast X360 pathway.
  1704. // integer HDR lightmap processing
  1705. float * RESTRICT pSrc = pFloatImage;
  1706. // Assert((reinterpret_cast<unsigned int>(pSrc) & 15) == 0); // 16-byte aligned?
  1707. COMPILE_TIME_ASSERT(sizeof(Vector4D)/sizeof(*pSrc) == 4); // assert that 1 * 4 = 4
  1708. // input numbers from pSrc are on the domain [0..+inf]
  1709. // we clamp them to the range [0..16]
  1710. // output is RGBA
  1711. // the shader does this: rOut = Rin * Ain * 16.0f
  1712. // where Rin is [0..1], a float computed from a byte value [0..255]
  1713. // Ain is therefore the brightest channel (say R) divided by 16 and quantized
  1714. // Rin is computed from pSrc->r by dividing by Ain
  1715. // rather than switching inside WritePixel for each different format,
  1716. // thus causing a 23-cycle pipeline clear for every pixel, we'll
  1717. // branch on the format here. That will allow us to unroll the inline
  1718. // pixel write functions differently depending on their different
  1719. // latencies.
  1720. Assert(!pfmOut); // should never happen on 360.
  1721. #ifndef ALLOW_PFM_OUTPUT_ON_360
  1722. if ( pfmOut )
  1723. {
  1724. Warning("*****************************************\n"
  1725. "Lightmap output on 360 HAS BEEN DISABLED.\n"
  1726. "A grave error has just occurred.\n"
  1727. "*****************************************\n");
  1728. }
  1729. #endif
  1730. // switch once, here, outside the loop, rather than
  1731. // switching inside each pixel. Switches are not fast
  1732. // on x360: they are usually implemented as jumps
  1733. // through function tables, which have a 24-cycle
  1734. // stall.
  1735. switch (m_LightmapPixelWriter.GetFormat())
  1736. {
  1737. // note: format names are low-order-byte first.
  1738. case IMAGE_FORMAT_RGBA8888:
  1739. case IMAGE_FORMAT_LINEAR_RGBA8888:
  1740. {
  1741. for ( int t = 0; t < pLightmapSize[1]; ++t )
  1742. {
  1743. m_LightmapPixelWriter.Seek( pOffsetIntoLightmapPage[0], pOffsetIntoLightmapPage[1] + t );
  1744. for ( int s = 0; s < pLightmapSize[0]; ++s, pSrc += 4 )
  1745. {
  1746. static const fltx4 vSixteen = {16.0f, 16.0f, 16.0f, 16.0f};
  1747. fltx4 rgba = LoadUnalignedSIMD(pSrc);
  1748. // clamp to 0..16 float
  1749. rgba = MinSIMD(rgba, vSixteen);
  1750. // compute the scaling factor, place it in w, and
  1751. // scale the rest by it.
  1752. rgba = ConvertLightmapColorToRGBScale( rgba );
  1753. // rgba is now float 0..255 in each component
  1754. m_LightmapPixelWriter.WritePixelNoAdvance_RGBA8888(rgba);
  1755. /* // not supported on X360
  1756. if ( pfmOut )
  1757. {
  1758. // Write data to the bitmapped represenations so that PFM files can be written
  1759. PixRGBAF pixelData;
  1760. XMStoreVector4(&pixelData,rgba);
  1761. pfmOut->WritePixelRGBAF( pOffsetIntoLightmapPage[0] + s, pOffsetIntoLightmapPage[1] + t, pixelData );
  1762. }
  1763. */
  1764. }
  1765. }
  1766. break;
  1767. }
  1768. case IMAGE_FORMAT_BGRA8888: // NOTE! : the low order bits are first in this naming convention.
  1769. case IMAGE_FORMAT_LINEAR_BGRA8888:
  1770. {
  1771. for ( int t = 0; t < pLightmapSize[1]; ++t )
  1772. {
  1773. m_LightmapPixelWriter.Seek( pOffsetIntoLightmapPage[0], pOffsetIntoLightmapPage[1] + t );
  1774. for ( int s = 0; s < pLightmapSize[0]; ++s, pSrc += 4 )
  1775. {
  1776. static const fltx4 vSixteen = {16.0f, 16.0f, 16.0f, 16.0f};
  1777. fltx4 rgba = LoadUnalignedSIMD(pSrc);
  1778. // clamp to 0..16 float
  1779. rgba = MinSIMD(rgba, vSixteen);
  1780. // compute the scaling factor, place it in w, and
  1781. // scale the rest by it.
  1782. rgba = ConvertLightmapColorToRGBScale( rgba );
  1783. // rgba is now float 0..255 in each component
  1784. m_LightmapPixelWriter.WritePixelNoAdvance_BGRA8888(rgba);
  1785. // forcibly advance
  1786. m_LightmapPixelWriter.SkipBytes(4);
  1787. /* // not supported on X360
  1788. if ( pfmOut )
  1789. {
  1790. // Write data to the bitmapped represenations so that PFM files can be written
  1791. PixRGBAF pixelData;
  1792. XMStoreVector4(&pixelData,rgba);
  1793. pfmOut->WritePixelRGBAF( pOffsetIntoLightmapPage[0] + s, pOffsetIntoLightmapPage[1] + t, pixelData );
  1794. }
  1795. */
  1796. }
  1797. }
  1798. break;
  1799. }
  1800. case IMAGE_FORMAT_RGBA16161616:
  1801. case IMAGE_FORMAT_LINEAR_RGBA16161616:
  1802. {
  1803. for ( int t = 0; t < pLightmapSize[1]; ++t )
  1804. {
  1805. m_LightmapPixelWriter.Seek( pOffsetIntoLightmapPage[0], pOffsetIntoLightmapPage[1] + t );
  1806. for ( int s = 0; s < pLightmapSize[0]; ++s, pSrc += 4 )
  1807. {
  1808. static const fltx4 vSixteen = {16.0f, 16.0f, 16.0f, 16.0f};
  1809. fltx4 rgba = LoadUnalignedSIMD(pSrc);
  1810. rgba = MinSIMD(rgba, vSixteen); // clamp to 0..16 float
  1811. m_LightmapPixelWriter.WritePixelNoAdvance_RGBA16161616(rgba);
  1812. m_LightmapPixelWriter.SkipBytes(8);
  1813. }
  1814. }
  1815. break;
  1816. }
  1817. default:
  1818. AssertMsg1(false,"Unsupported pixel format %d while writing lightmaps!", m_LightmapPixelWriter.GetFormat() );
  1819. Warning("Unsupported pixel format used in lightmap. Lightmaps could not be downloaded.\n");
  1820. break;
  1821. }
  1822. }
  1823. #endif
  1824. }
  1825. void CMatLightmaps::BeginUpdateLightmaps( void )
  1826. {
  1827. CMatCallQueue *pCallQueue = GetMaterialSystem()->GetRenderContextInternal()->GetCallQueueInternal();
  1828. if ( pCallQueue )
  1829. {
  1830. pCallQueue->QueueCall( this, &CMatLightmaps::BeginUpdateLightmaps );
  1831. return;
  1832. }
  1833. m_nUpdatingLightmapsStackDepth++;
  1834. }
  1835. void CMatLightmaps::EndUpdateLightmaps( void )
  1836. {
  1837. CMatCallQueue *pCallQueue = GetMaterialSystem()->GetRenderContextInternal()->GetCallQueueInternal();
  1838. if ( pCallQueue )
  1839. {
  1840. pCallQueue->QueueCall( this, &CMatLightmaps::EndUpdateLightmaps );
  1841. return;
  1842. }
  1843. m_nUpdatingLightmapsStackDepth--;
  1844. Assert( m_nUpdatingLightmapsStackDepth >= 0 );
  1845. if( m_nUpdatingLightmapsStackDepth <= 0 && m_nLockedLightmap != -1 )
  1846. {
  1847. g_pShaderAPI->TexUnlock();
  1848. m_nLockedLightmap = -1;
  1849. }
  1850. }
  1851. int CMatLightmaps::AllocateDynamicLightmap( int lightmapSize[2], int *pOutOffsetIntoPage, int frameID )
  1852. {
  1853. // check frameID, fail if current
  1854. for ( int i = 0; i < COUNT_DYNAMIC_LIGHTMAP_PAGES; i++ )
  1855. {
  1856. int dynamicIndex = (m_dynamic.currentDynamicIndex + i) % COUNT_DYNAMIC_LIGHTMAP_PAGES;
  1857. int lightmapPageIndex = m_firstDynamicLightmap + dynamicIndex;
  1858. if ( m_dynamic.lightmapLockFrame[dynamicIndex] != frameID )
  1859. {
  1860. m_dynamic.lightmapLockFrame[dynamicIndex] = frameID;
  1861. m_dynamic.imagePackers[dynamicIndex].Reset( 0, m_pLightmapPages[lightmapPageIndex].m_Width, m_pLightmapPages[lightmapPageIndex].m_Height );
  1862. }
  1863. if ( m_dynamic.imagePackers[dynamicIndex].AddBlock( lightmapSize[0], lightmapSize[1], &pOutOffsetIntoPage[0], &pOutOffsetIntoPage[1] ) )
  1864. {
  1865. return lightmapPageIndex;
  1866. }
  1867. }
  1868. return -1;
  1869. }
  1870. //-----------------------------------------------------------------------------
  1871. // Updates the lightmap
  1872. //-----------------------------------------------------------------------------
  1873. void CMatLightmaps::UpdateLightmap( int lightmapPageID, int lightmapSize[2],
  1874. int offsetIntoLightmapPage[2],
  1875. float *pFloatImage, float *pFloatImageBump1,
  1876. float *pFloatImageBump2, float *pFloatImageBump3 )
  1877. {
  1878. VPROF( "CMatRenderContext::UpdateLightmap" );
  1879. bool hasBump = false;
  1880. int uSize = 1;
  1881. FloatBitMap_t *pfmOut = NULL;
  1882. if ( pFloatImageBump1 && pFloatImageBump2 && pFloatImageBump3 )
  1883. {
  1884. hasBump = true;
  1885. uSize = 4;
  1886. }
  1887. if ( lightmapPageID >= GetNumLightmapPages() || lightmapPageID < 0 )
  1888. {
  1889. Error( "MaterialSystem_Interface_t::UpdateLightmap lightmapPageID=%d out of range\n", lightmapPageID );
  1890. return;
  1891. }
  1892. bool bDynamic = IsDynamicLightmap(lightmapPageID);
  1893. if ( bDynamic )
  1894. {
  1895. int dynamicIndex = lightmapPageID-m_firstDynamicLightmap;
  1896. Assert(dynamicIndex < COUNT_DYNAMIC_LIGHTMAP_PAGES);
  1897. m_dynamic.currentDynamicIndex = (dynamicIndex + 1) % COUNT_DYNAMIC_LIGHTMAP_PAGES;
  1898. }
  1899. if ( mat_lightmap_pfms.GetBool())
  1900. {
  1901. // Allocate and initialize lightmap data that will be written to a PFM file
  1902. if (NULL == m_pLightmapDataPtrArray[lightmapPageID])
  1903. {
  1904. m_pLightmapDataPtrArray[lightmapPageID] = new FloatBitMap_t(m_pLightmapPages[lightmapPageID].m_Width, m_pLightmapPages[lightmapPageID].m_Height);
  1905. m_pLightmapDataPtrArray[lightmapPageID]->Clear(0, 0, 0, 1);
  1906. }
  1907. pfmOut = m_pLightmapDataPtrArray[lightmapPageID];
  1908. }
  1909. // NOTE: Change how the lock is taking place if you ever change how bumped
  1910. // lightmaps are put into the page. Right now, we assume that they're all
  1911. // added to the right of the original lightmap.
  1912. bool bLockSubRect;
  1913. {
  1914. VPROF_( "Locking lightmaps", 2, VPROF_BUDGETGROUP_DLIGHT_RENDERING, false, 0 ); // vprof scope
  1915. bLockSubRect = m_nUpdatingLightmapsStackDepth <= 0 && !bDynamic;
  1916. if( bLockSubRect )
  1917. {
  1918. VPROF_INCREMENT_COUNTER( "lightmap subrect texlock", 1 );
  1919. g_pShaderAPI->ModifyTexture( m_LightmapPageTextureHandles[lightmapPageID] );
  1920. if (!g_pShaderAPI->TexLock( 0, 0, offsetIntoLightmapPage[0], offsetIntoLightmapPage[1],
  1921. lightmapSize[0] * uSize, lightmapSize[1], m_LightmapPixelWriter ))
  1922. {
  1923. return;
  1924. }
  1925. }
  1926. else if( lightmapPageID != m_nLockedLightmap )
  1927. {
  1928. if ( !LockLightmap( lightmapPageID ) )
  1929. {
  1930. ExecuteNTimes( 10, Warning( "Failed to lock lightmap\n" ) );
  1931. return;
  1932. }
  1933. }
  1934. }
  1935. int subRectOffset[2] = {0,0};
  1936. {
  1937. // account for the part spent in math:
  1938. VPROF_( "LightmapBitsToPixelWriter", 2, VPROF_BUDGETGROUP_DLIGHT_RENDERING, false, 0 );
  1939. #ifdef _PS3
  1940. // PS3 uses 16-bit half floats per channel...but the HDR_TYPE_FLOAT codepath has a lot of other assumptions, so just
  1941. // lie about the format right here on PS3 only
  1942. if ( hasBump )
  1943. {
  1944. BumpedLightmapBitsToPixelWriter_HDRF( pFloatImage, pFloatImageBump1, pFloatImageBump2, pFloatImageBump3,
  1945. lightmapSize, bLockSubRect ? subRectOffset : offsetIntoLightmapPage, pfmOut );
  1946. }
  1947. else
  1948. {
  1949. LightmapBitsToPixelWriter_HDRF( pFloatImage, lightmapSize, bLockSubRect ? subRectOffset : offsetIntoLightmapPage, pfmOut );
  1950. }
  1951. #else // _PS3
  1952. if ( hasBump )
  1953. {
  1954. switch( HardwareConfig()->GetHDRType() )
  1955. {
  1956. case HDR_TYPE_NONE:
  1957. BumpedLightmapBitsToPixelWriter_LDR( pFloatImage, pFloatImageBump1, pFloatImageBump2, pFloatImageBump3,
  1958. lightmapSize, bLockSubRect ? subRectOffset : offsetIntoLightmapPage, pfmOut );
  1959. break;
  1960. case HDR_TYPE_INTEGER:
  1961. BumpedLightmapBitsToPixelWriter_HDRI( pFloatImage, pFloatImageBump1, pFloatImageBump2, pFloatImageBump3,
  1962. lightmapSize, bLockSubRect ? subRectOffset : offsetIntoLightmapPage, pfmOut );
  1963. break;
  1964. case HDR_TYPE_FLOAT:
  1965. BumpedLightmapBitsToPixelWriter_HDRF( pFloatImage, pFloatImageBump1, pFloatImageBump2, pFloatImageBump3,
  1966. lightmapSize, bLockSubRect ? subRectOffset : offsetIntoLightmapPage, pfmOut );
  1967. break;
  1968. }
  1969. }
  1970. else
  1971. {
  1972. switch ( HardwareConfig()->GetHDRType() )
  1973. {
  1974. case HDR_TYPE_NONE:
  1975. LightmapBitsToPixelWriter_LDR( pFloatImage, lightmapSize, bLockSubRect ? subRectOffset : offsetIntoLightmapPage, pfmOut );
  1976. break;
  1977. case HDR_TYPE_INTEGER:
  1978. LightmapBitsToPixelWriter_HDRI( pFloatImage, lightmapSize, bLockSubRect ? subRectOffset : offsetIntoLightmapPage, pfmOut );
  1979. break;
  1980. case HDR_TYPE_FLOAT:
  1981. LightmapBitsToPixelWriter_HDRF( pFloatImage, lightmapSize, bLockSubRect ? subRectOffset : offsetIntoLightmapPage, pfmOut );
  1982. break;
  1983. default:
  1984. Assert( 0 );
  1985. break;
  1986. }
  1987. }
  1988. #endif // !_PS3
  1989. }
  1990. if( bLockSubRect )
  1991. {
  1992. VPROF_( "Unlocking Lightmaps", 2, VPROF_BUDGETGROUP_DLIGHT_RENDERING, false, 0 );
  1993. g_pShaderAPI->TexUnlock();
  1994. }
  1995. }
  1996. //-----------------------------------------------------------------------------
  1997. //
  1998. //-----------------------------------------------------------------------------
  1999. int CMatLightmaps::GetNumSortIDs( void )
  2000. {
  2001. return m_numSortIDs;
  2002. }
  2003. //-----------------------------------------------------------------------------
  2004. //
  2005. //-----------------------------------------------------------------------------
  2006. void CMatLightmaps::ComputeSortInfo( MaterialSystem_SortInfo_t* pInfo, int& sortId, bool alpha )
  2007. {
  2008. int lightmapPageID;
  2009. for ( MaterialHandle_t i = GetMaterialDict()->FirstMaterial(); i != GetMaterialDict()->InvalidMaterial(); i = GetMaterialDict()->NextMaterial(i) )
  2010. {
  2011. IMaterialInternal* pMaterial = GetMaterialInternal(i);
  2012. if ( pMaterial->GetMinLightmapPageID() > pMaterial->GetMaxLightmapPageID() )
  2013. {
  2014. continue;
  2015. }
  2016. // const IMaterialVar *pTransVar = pMaterial->GetMaterialProperty( MATERIAL_PROPERTY_OPACITY );
  2017. // if( ( !alpha && ( pTransVar->GetIntValue() == MATERIAL_TRANSLUCENT ) ) ||
  2018. // ( alpha && !( pTransVar->GetIntValue() == MATERIAL_TRANSLUCENT ) ) )
  2019. // {
  2020. // return true;
  2021. // }
  2022. // Warning( "sort stuff: %s %s\n", material->GetName(), bAlpha ? "alpha" : "not alpha" );
  2023. // fill in the lightmapped materials
  2024. for ( lightmapPageID = pMaterial->GetMinLightmapPageID();
  2025. lightmapPageID <= pMaterial->GetMaxLightmapPageID(); ++lightmapPageID )
  2026. {
  2027. pInfo[sortId].material = pMaterial->GetQueueFriendlyVersion();
  2028. pInfo[sortId].lightmapPageID = lightmapPageID;
  2029. #if 0
  2030. char buf[128];
  2031. Q_snprintf( buf, sizeof( buf ), "ComputeSortInfo: %s lightmapPageID: %d sortID: %d\n", pMaterial->GetName(), lightmapPageID, sortId );
  2032. OutputDebugString( buf );
  2033. #endif
  2034. ++sortId;
  2035. }
  2036. }
  2037. }
  2038. //-----------------------------------------------------------------------------
  2039. //
  2040. //-----------------------------------------------------------------------------
  2041. void CMatLightmaps::ComputeWhiteLightmappedSortInfo( MaterialSystem_SortInfo_t* pInfo, int& sortId, bool alpha )
  2042. {
  2043. for (MaterialHandle_t i = GetMaterialDict()->FirstMaterial(); i != GetMaterialDict()->InvalidMaterial(); i = GetMaterialDict()->NextMaterial(i) )
  2044. {
  2045. IMaterialInternal* pMaterial = GetMaterialInternal(i);
  2046. // fill in the lightmapped materials that are actually used by this level
  2047. if( pMaterial->GetNeedsWhiteLightmap() &&
  2048. ( pMaterial->GetReferenceCount() > 0 ) )
  2049. {
  2050. // const IMaterialVar *pTransVar = pMaterial->GetMaterialProperty( MATERIAL_PROPERTY_OPACITY );
  2051. // if( ( !alpha && ( pTransVar->GetIntValue() == MATERIAL_TRANSLUCENT ) ) ||
  2052. // ( alpha && !( pTransVar->GetIntValue() == MATERIAL_TRANSLUCENT ) ) )
  2053. // {
  2054. // return true;
  2055. // }
  2056. pInfo[sortId].material = pMaterial->GetQueueFriendlyVersion();
  2057. if( pMaterial->GetPropertyFlag( MATERIAL_PROPERTY_NEEDS_BUMPED_LIGHTMAPS ) )
  2058. {
  2059. pInfo[sortId].lightmapPageID = MATERIAL_SYSTEM_LIGHTMAP_PAGE_WHITE_BUMP;
  2060. }
  2061. else
  2062. {
  2063. pInfo[sortId].lightmapPageID = MATERIAL_SYSTEM_LIGHTMAP_PAGE_WHITE;
  2064. }
  2065. sortId++;
  2066. }
  2067. }
  2068. }
  2069. //-----------------------------------------------------------------------------
  2070. //
  2071. //-----------------------------------------------------------------------------
  2072. void CMatLightmaps::GetSortInfo( MaterialSystem_SortInfo_t *pSortInfoArray )
  2073. {
  2074. // sort non-alpha blended materials first
  2075. int sortId = 0;
  2076. ComputeSortInfo( pSortInfoArray, sortId, false );
  2077. ComputeWhiteLightmappedSortInfo( pSortInfoArray, sortId, false );
  2078. Assert( m_numSortIDs == sortId );
  2079. }
  2080. //-----------------------------------------------------------------------------
  2081. //
  2082. //-----------------------------------------------------------------------------
  2083. void CMatLightmaps::EnableLightmapFiltering( bool enabled )
  2084. {
  2085. int i;
  2086. for( i = 0; i < GetNumLightmapPages(); i++ )
  2087. {
  2088. g_pShaderAPI->ModifyTexture( m_LightmapPageTextureHandles[i] );
  2089. if( enabled )
  2090. {
  2091. g_pShaderAPI->TexMinFilter( SHADER_TEXFILTERMODE_LINEAR );
  2092. g_pShaderAPI->TexMagFilter( SHADER_TEXFILTERMODE_LINEAR );
  2093. }
  2094. else
  2095. {
  2096. g_pShaderAPI->TexMinFilter( SHADER_TEXFILTERMODE_NEAREST );
  2097. g_pShaderAPI->TexMagFilter( SHADER_TEXFILTERMODE_NEAREST );
  2098. }
  2099. }
  2100. }