Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

991 lines
26 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Contains all texture state for the material system surface to use
  4. //
  5. //===========================================================================//
  6. #include "bitmap/imageformat.h"
  7. #include "TextureDictionary.h"
  8. #include "utllinkedlist.h"
  9. #include "checksum_crc.h"
  10. #include "materialsystem/imaterial.h"
  11. #include "vguimatsurface.h"
  12. #include "materialsystem/imaterialsystem.h"
  13. #include "tier0/dbg.h"
  14. #include "KeyValues.h"
  15. #include "pixelwriter.h"
  16. #include "materialsystem/imaterialvar.h"
  17. #include "materialsystem/itexture.h"
  18. #include "vtf/vtf.h"
  19. // memdbgon must be the last include file in a .cpp file!!!
  20. #include "tier0/memdbgon.h"
  21. #define TEXTURE_ID_UNKNOWN -1
  22. class CMatSystemTexture;
  23. // Case-sensitive string checksum
  24. static CRC32_t Texture_CRCName( const char *string )
  25. {
  26. CRC32_t crc;
  27. CRC32_Init( &crc );
  28. CRC32_ProcessBuffer( &crc, (void *)string, strlen( string ) );
  29. CRC32_Final( &crc );
  30. return crc;
  31. }
  32. class CFontTextureRegen;
  33. //-----------------------------------------------------------------------------
  34. // Purpose:
  35. //-----------------------------------------------------------------------------
  36. class CMatSystemTexture
  37. {
  38. public:
  39. CMatSystemTexture( void );
  40. ~CMatSystemTexture( void );
  41. void SetId( int id ) { m_ID = id; };
  42. CRC32_t GetCRC() const;
  43. void SetCRC( CRC32_t val );
  44. void SetMaterial( const char *pFileName );
  45. void SetMaterial( IMaterial *pMaterial );
  46. void SetTexture( ITexture *pTexture ) { SafeAssign( &m_pOverrideTexture, pTexture ); }
  47. // This is used when we want different rendering state sharing the same procedural texture (fonts)
  48. void ReferenceOtherProcedural( CMatSystemTexture *pTexture, IMaterial *pMaterial );
  49. IMaterial *GetMaterial() { return m_pMaterial; }
  50. int Width() const { return m_iWide; }
  51. int Height() const { return m_iTall; }
  52. bool IsProcedural( void ) const;
  53. void SetProcedural( bool proc );
  54. bool IsReference() const { return m_Flags & TEXTURE_IS_REFERENCE; }
  55. void SetTextureRGBA( const char* rgba, int wide, int tall, ImageFormat format, bool bFixupTextCoordsForDimensions );
  56. void SetSubTextureRGBA( int drawX, int drawY, unsigned const char *rgba, int subTextureWide, int subTextureTall );
  57. void SetSubTextureRGBAEx( int drawX, int drawY, unsigned const char *rgba, int subTextureWide, int subTextureTall, ImageFormat imageFormat );
  58. void UpdateSubTextureRGBA( int drawX, int drawY, unsigned const char *rgba, int subTextureWide, int subTextureTall, ImageFormat imageFormat );
  59. float m_s0, m_t0, m_s1, m_t1;
  60. private:
  61. void CreateRegen( int nWidth, int nHeight, ImageFormat format );
  62. void ReleaseRegen( void );
  63. void CleanUpMaterial();
  64. ITexture *GetTextureValue( void );
  65. private:
  66. enum
  67. {
  68. TEXTURE_IS_PROCEDURAL = 0x1,
  69. TEXTURE_IS_REFERENCE = 0x2
  70. };
  71. CRC32_t m_crcFile;
  72. IMaterial *m_pMaterial;
  73. ITexture *m_pTexture;
  74. ITexture *m_pOverrideTexture;
  75. int m_iWide;
  76. int m_iTall;
  77. int m_iInputWide;
  78. int m_iInputTall;
  79. int m_ID;
  80. int m_Flags;
  81. CFontTextureRegen *m_pRegen;
  82. };
  83. //-----------------------------------------------------------------------------
  84. // A class that manages textures used by the material system surface
  85. //-----------------------------------------------------------------------------
  86. class CTextureDictionary : public ITextureDictionary
  87. {
  88. public:
  89. CTextureDictionary( void );
  90. // Create, destroy textures
  91. int CreateTexture( bool procedural = false );
  92. int CreateTextureByTexture( ITexture *pTexture, bool procedural = true ) OVERRIDE;
  93. void DestroyTexture( int id );
  94. void DestroyAllTextures();
  95. // Is this a valid id?
  96. bool IsValidId( int id ) const;
  97. // Binds a material to a texture
  98. virtual void BindTextureToFile( int id, const char *pFileName );
  99. virtual void BindTextureToMaterial( int id, IMaterial *pMaterial );
  100. virtual void BindTextureToMaterialReference( int id, int referenceId, IMaterial *pMaterial );
  101. // Texture info
  102. IMaterial *GetTextureMaterial( int id );
  103. void GetTextureSize(int id, int& iWide, int& iTall );
  104. void GetTextureTexCoords( int id, float &s0, float &t0, float &s1, float &t1 );
  105. void SetTextureRGBA( int id, const char* rgba, int wide, int tall );
  106. void SetTextureRGBAEx( int id, const char* rgba, int wide, int tall, ImageFormat format, bool bFixupTextCoordsForDimensions );
  107. void SetSubTextureRGBA( int id, int drawX, int drawY, unsigned const char *rgba, int subTextureWide, int subTextureTall );
  108. void SetSubTextureRGBAEx( int id, int drawX, int drawY, unsigned const char *rgba, int subTextureWide, int subTextureTall, ImageFormat imageFormat );
  109. void UpdateSubTextureRGBA( int id, int drawX, int drawY, unsigned const char *rgba, int subTextureWide, int subTextureTall, ImageFormat imageFormat );
  110. int FindTextureIdForTextureFile( char const *pFileName );
  111. public:
  112. CMatSystemTexture *GetTexture( int id );
  113. private:
  114. CUtlLinkedList< CMatSystemTexture, unsigned short > m_Textures;
  115. };
  116. static CTextureDictionary s_TextureDictionary;
  117. //-----------------------------------------------------------------------------
  118. // A texture regenerator that holds onto the bits at all times
  119. //-----------------------------------------------------------------------------
  120. class CFontTextureRegen : public ITextureRegenerator
  121. {
  122. public:
  123. CFontTextureRegen( int nWidth, int nHeight, ImageFormat format )
  124. {
  125. m_nFormat = format;
  126. m_nWidth = nWidth;
  127. m_nHeight = nHeight;
  128. if ( IsPC() )
  129. {
  130. int size = ImageLoader::GetMemRequired( m_nWidth, m_nHeight, 1, m_nFormat, false );
  131. m_pTextureBits = new unsigned char[size];
  132. memset( m_pTextureBits, 0, size );
  133. }
  134. else
  135. {
  136. // will be allocated as needed
  137. m_pTextureBits = NULL;
  138. }
  139. }
  140. ~CFontTextureRegen( void )
  141. {
  142. DeleteTextureBits();
  143. }
  144. void UpdateBackingBits( Rect_t &subRect, const unsigned char *pBits, Rect_t &uploadRect, ImageFormat format )
  145. {
  146. int size = ImageLoader::GetMemRequired( m_nWidth, m_nHeight, 1, m_nFormat, false );
  147. if ( IsPC() )
  148. {
  149. if ( !m_pTextureBits )
  150. return;
  151. }
  152. else
  153. {
  154. Assert( !m_pTextureBits );
  155. m_pTextureBits = new unsigned char[size];
  156. memset( m_pTextureBits, 0, size );
  157. }
  158. // Copy subrect into backing bits storage
  159. // source data is expected to be in same format as backing bits
  160. int y;
  161. if ( ImageLoader::SizeInBytes( m_nFormat ) == 4 )
  162. {
  163. bool bIsInputFullRect = ( subRect.width != uploadRect.width || subRect.height != uploadRect.height );
  164. Assert( (subRect.x >= 0) && (subRect.y >= 0) );
  165. Assert( (subRect.x + subRect.width <= m_nWidth) && (subRect.y + subRect.height <= m_nHeight) );
  166. for ( y=0; y < subRect.height; ++y )
  167. {
  168. int idx = ( (subRect.y + y) * m_nWidth + subRect.x ) << 2;
  169. unsigned int *pDst = (unsigned int*)(&m_pTextureBits[ idx ]);
  170. int offset = bIsInputFullRect ? (subRect.y+y)*uploadRect.width + subRect.x : y*uploadRect.width;
  171. const unsigned int *pSrc = (const unsigned int *)(&pBits[ offset << 2 ]);
  172. ImageLoader::ConvertImageFormat( (const unsigned char *)pSrc, format,(unsigned char *)pDst, m_nFormat, subRect.width, 1 );
  173. }
  174. }
  175. else
  176. {
  177. // cannot subrect copy when format is not RGBA
  178. if ( subRect.width != m_nWidth || subRect.height != m_nHeight )
  179. {
  180. Assert( 0 );
  181. return;
  182. }
  183. Q_memcpy( m_pTextureBits, pBits, size );
  184. }
  185. }
  186. virtual void RegenerateTextureBits( ITexture *pTexture, IVTFTexture *pVTFTexture, Rect_t *pSubRect )
  187. {
  188. if ( !m_pTextureBits )
  189. return;
  190. Assert( (pVTFTexture->Width() == m_nWidth) && (pVTFTexture->Height() == m_nHeight) );
  191. int nFormatBytes = ImageLoader::SizeInBytes( m_nFormat );
  192. if ( nFormatBytes == 4 )
  193. {
  194. if ( m_nFormat == pVTFTexture->Format() )
  195. {
  196. int ymax = pSubRect->y + pSubRect->height;
  197. for( int y = pSubRect->y; y < ymax; ++y )
  198. {
  199. // copy each row across for the update
  200. char *pchData = (char *)pVTFTexture->ImageData( 0, 0, 0, 0, y ) + pSubRect->x *nFormatBytes;
  201. int size = ImageLoader::GetMemRequired( pSubRect->width, 1, 1, m_nFormat, false );
  202. V_memcpy( pchData, m_pTextureBits + (y * m_nWidth + pSubRect->x) * nFormatBytes, size );
  203. }
  204. }
  205. else
  206. {
  207. // formats don't match so do a pixel by pixel swizel
  208. CPixelWriter pixelWriter;
  209. pixelWriter.SetPixelMemory(
  210. pVTFTexture->Format(),
  211. pVTFTexture->ImageData( 0, 0, 0 ),
  212. pVTFTexture->RowSizeInBytes( 0 ) );
  213. // Now upload the part we've been asked for
  214. int xmax = pSubRect->x + pSubRect->width;
  215. int ymax = pSubRect->y + pSubRect->height;
  216. int x, y;
  217. for( y = pSubRect->y; y < ymax; ++y )
  218. {
  219. pixelWriter.Seek( pSubRect->x, y );
  220. unsigned char *rgba = &m_pTextureBits[ (y * m_nWidth + pSubRect->x) * nFormatBytes ];
  221. for ( x=pSubRect->x; x < xmax; ++x )
  222. {
  223. pixelWriter.WritePixel( rgba[0], rgba[1], rgba[2], rgba[3] );
  224. rgba += nFormatBytes;
  225. }
  226. }
  227. }
  228. }
  229. else
  230. {
  231. // cannot subrect copy when format is not RGBA
  232. if ( pSubRect->width != m_nWidth || pSubRect->height != m_nHeight )
  233. {
  234. Assert( 0 );
  235. return;
  236. }
  237. int size = ImageLoader::GetMemRequired( m_nWidth, m_nHeight, 1, m_nFormat, false );
  238. Q_memcpy( pVTFTexture->ImageData( 0, 0, 0 ), m_pTextureBits, size );
  239. }
  240. }
  241. virtual void Release()
  242. {
  243. // Called by the material system when this needs to go away
  244. DeleteTextureBits();
  245. }
  246. void DeleteTextureBits()
  247. {
  248. if ( m_pTextureBits )
  249. {
  250. delete [] m_pTextureBits;
  251. m_pTextureBits = NULL;
  252. }
  253. }
  254. private:
  255. unsigned char *m_pTextureBits;
  256. short m_nWidth;
  257. short m_nHeight;
  258. ImageFormat m_nFormat;
  259. };
  260. //-----------------------------------------------------------------------------
  261. // Purpose:
  262. //-----------------------------------------------------------------------------
  263. CMatSystemTexture::CMatSystemTexture( void )
  264. {
  265. m_pMaterial = NULL;
  266. m_pTexture = NULL;
  267. m_pOverrideTexture = NULL;
  268. m_crcFile = (CRC32_t)0;
  269. m_iWide = m_iTall = 0;
  270. m_s0 = m_t0 = 0;
  271. m_s1 = m_t1 = 1;
  272. m_Flags = 0;
  273. m_pRegen = NULL;
  274. }
  275. //-----------------------------------------------------------------------------
  276. // Purpose:
  277. //-----------------------------------------------------------------------------
  278. CMatSystemTexture::~CMatSystemTexture( void )
  279. {
  280. if ( m_pOverrideTexture )
  281. {
  282. m_pOverrideTexture->Release();
  283. m_pOverrideTexture->DeleteIfUnreferenced();
  284. m_pOverrideTexture = NULL;
  285. }
  286. CleanUpMaterial();
  287. }
  288. bool CMatSystemTexture::IsProcedural( void ) const
  289. {
  290. return (m_Flags & TEXTURE_IS_PROCEDURAL) != 0;
  291. }
  292. void CMatSystemTexture::SetProcedural( bool proc )
  293. {
  294. if (proc)
  295. {
  296. m_Flags |= TEXTURE_IS_PROCEDURAL;
  297. }
  298. else
  299. {
  300. m_Flags &= ~TEXTURE_IS_PROCEDURAL;
  301. }
  302. }
  303. void CMatSystemTexture::CleanUpMaterial()
  304. {
  305. if ( m_pMaterial )
  306. {
  307. // causes the underlying texture (if unreferenced) to be deleted as well
  308. m_pMaterial->DecrementReferenceCount();
  309. m_pMaterial->DeleteIfUnreferenced();
  310. m_pMaterial = NULL;
  311. }
  312. if ( m_pTexture )
  313. {
  314. m_pTexture->SetTextureRegenerator( NULL );
  315. m_pTexture->DecrementReferenceCount();
  316. m_pTexture->DeleteIfUnreferenced();
  317. m_pTexture = NULL;
  318. }
  319. ReleaseRegen();
  320. }
  321. void CMatSystemTexture::CreateRegen( int nWidth, int nHeight, ImageFormat format )
  322. {
  323. Assert( IsProcedural() );
  324. if ( !m_pRegen )
  325. {
  326. m_pRegen = new CFontTextureRegen( nWidth, nHeight, format );
  327. }
  328. }
  329. void CMatSystemTexture::ReleaseRegen( void )
  330. {
  331. if (m_pRegen)
  332. {
  333. if (!IsReference())
  334. {
  335. delete m_pRegen;
  336. }
  337. m_pRegen = NULL;
  338. }
  339. }
  340. void CMatSystemTexture::SetTextureRGBA( const char *rgba, int wide, int tall, ImageFormat format, bool bFixupTextCoords )
  341. {
  342. Assert( IsProcedural() );
  343. if ( !IsProcedural() )
  344. return;
  345. if ( !m_pMaterial )
  346. {
  347. int width = wide;
  348. int height = tall;
  349. // find the minimum power-of-two to fit this in
  350. int i;
  351. for ( i = 0; i < 32 ; i++ )
  352. {
  353. width = (1<<i);
  354. if (width >= wide)
  355. {
  356. break;
  357. }
  358. }
  359. for (i = 0; i < 32; i++ )
  360. {
  361. height= (1<<i);
  362. if (height >= tall)
  363. {
  364. break;
  365. }
  366. }
  367. // create a procedural material to fit this texture into
  368. static int nTextureId = 0;
  369. char pTextureName[64];
  370. Q_snprintf( pTextureName, sizeof( pTextureName ), "__vgui_texture_%d", nTextureId );
  371. ++nTextureId;
  372. ITexture *pTexture = g_pMaterialSystem->CreateProceduralTexture(
  373. pTextureName,
  374. TEXTURE_GROUP_VGUI,
  375. width,
  376. height,
  377. format,
  378. TEXTUREFLAGS_CLAMPS | TEXTUREFLAGS_CLAMPT |
  379. TEXTUREFLAGS_NOMIP | TEXTUREFLAGS_NOLOD |
  380. TEXTUREFLAGS_PROCEDURAL | TEXTUREFLAGS_SINGLECOPY | TEXTUREFLAGS_POINTSAMPLE );
  381. KeyValues *pVMTKeyValues = new KeyValues( "UnlitGeneric" );
  382. pVMTKeyValues->SetInt( "$vertexcolor", 1 );
  383. pVMTKeyValues->SetInt( "$vertexalpha", 1 );
  384. pVMTKeyValues->SetInt( "$ignorez", 1 );
  385. pVMTKeyValues->SetInt( "$no_fullbright", 1 );
  386. pVMTKeyValues->SetInt( "$translucent", 1 );
  387. pVMTKeyValues->SetString( "$basetexture", pTextureName );
  388. IMaterial *pMaterial = g_pMaterialSystem->CreateMaterial( pTextureName, pVMTKeyValues );
  389. pMaterial->Refresh();
  390. // Has to happen after the refresh
  391. pTexture->DecrementReferenceCount();
  392. SetMaterial( pMaterial );
  393. m_iInputTall = tall;
  394. m_iInputWide = wide;
  395. if ( bFixupTextCoords && ( wide != width || tall != height ) )
  396. {
  397. m_s1 = (double)wide / width;
  398. m_t1 = (double)tall / height;
  399. }
  400. // undo the extra +1 refCount
  401. pMaterial->DecrementReferenceCount();
  402. }
  403. Assert( wide <= m_iWide );
  404. Assert( tall <= m_iTall );
  405. // Just replace the whole thing
  406. SetSubTextureRGBAEx( 0, 0, (const unsigned char *)rgba, wide, tall, format );
  407. }
  408. //-----------------------------------------------------------------------------
  409. // Purpose:
  410. //-----------------------------------------------------------------------------
  411. ITexture *CMatSystemTexture::GetTextureValue( void )
  412. {
  413. Assert( IsProcedural() );
  414. if ( !m_pMaterial )
  415. return NULL;
  416. if ( m_pOverrideTexture )
  417. return m_pOverrideTexture;
  418. return m_pTexture;
  419. }
  420. void CMatSystemTexture::SetSubTextureRGBA( int drawX, int drawY, unsigned const char *rgba, int subTextureWide, int subTextureTall )
  421. {
  422. SetSubTextureRGBAEx( drawX, drawY, rgba, subTextureWide, subTextureTall, IMAGE_FORMAT_RGBA8888 );
  423. }
  424. void CMatSystemTexture::SetSubTextureRGBAEx( int drawX, int drawY, unsigned const char *rgba, int subTextureWide, int subTextureTall, ImageFormat format )
  425. {
  426. ITexture *pTexture = GetTextureValue();
  427. if ( !pTexture )
  428. return;
  429. Assert( IsProcedural() );
  430. if ( !IsProcedural() )
  431. return;
  432. Assert( drawX < m_iWide );
  433. Assert( drawY < m_iTall );
  434. Assert( drawX + subTextureWide <= m_iWide );
  435. Assert( drawY + subTextureTall <= m_iTall );
  436. Assert( m_pRegen );
  437. Assert( rgba );
  438. Rect_t subRect;
  439. subRect.x = drawX;
  440. subRect.y = drawY;
  441. subRect.width = subTextureWide;
  442. subRect.height = subTextureTall;
  443. Rect_t textureSize;
  444. textureSize.x = 0;
  445. textureSize.y = 0;
  446. textureSize.width = subTextureWide;
  447. textureSize.height = subTextureTall;
  448. m_pRegen->UpdateBackingBits( subRect, rgba, textureSize, format );
  449. pTexture->Download( &subRect );
  450. if ( IsX360() )
  451. {
  452. // xboxissue - no need to persist "backing bits", saves memory
  453. // the texture (commonly font page) "backing bits" are allocated during UpdateBackingBits() which get blitted
  454. // into by procedural regeneration in preparation for download() which then subrect blits
  455. // out of and into target texture (d3d upload)
  456. // the "backing bits" are then no longer required
  457. m_pRegen->DeleteTextureBits();
  458. }
  459. }
  460. void CMatSystemTexture::UpdateSubTextureRGBA( int drawX, int drawY, unsigned const char *rgba, int subTextureWide, int subTextureTall, ImageFormat imageFormat )
  461. {
  462. ITexture *pTexture = GetTextureValue();
  463. if ( !pTexture )
  464. return;
  465. Assert( IsProcedural() );
  466. if ( !IsProcedural() )
  467. return;
  468. Assert( drawX < m_iWide );
  469. Assert( drawY < m_iTall );
  470. Assert( drawX + subTextureWide <= m_iWide );
  471. Assert( drawY + subTextureTall <= m_iTall );
  472. Assert( m_pRegen );
  473. Assert( rgba );
  474. Rect_t subRect;
  475. subRect.x = drawX;
  476. subRect.y = drawY;
  477. subRect.width = subTextureWide;
  478. subRect.height = subTextureTall;
  479. Rect_t textureSize;
  480. textureSize.x = 0;
  481. textureSize.y = 0;
  482. textureSize.width = m_iInputWide;
  483. textureSize.height = m_iInputTall;
  484. m_pRegen->UpdateBackingBits( subRect, rgba, textureSize, imageFormat );
  485. pTexture->Download( &subRect );
  486. if ( IsX360() )
  487. {
  488. // xboxissue - no need to persist "backing bits", saves memory
  489. // the texture (commonly font page) "backing bits" are allocated during UpdateBackingBits() which get blitted
  490. // into by procedural regeneration in preparation for download() which then subrect blits
  491. // out of and into target texture (d3d upload)
  492. // the "backing bits" are then no longer required
  493. m_pRegen->DeleteTextureBits();
  494. }
  495. }
  496. void CMatSystemTexture::SetCRC( CRC32_t val )
  497. {
  498. m_crcFile = val;
  499. }
  500. CRC32_t CMatSystemTexture::GetCRC() const
  501. {
  502. return m_crcFile;
  503. }
  504. void CMatSystemTexture::SetMaterial( IMaterial *pMaterial )
  505. {
  506. // Decrement references to old texture
  507. CleanUpMaterial();
  508. m_pMaterial = pMaterial;
  509. if (!m_pMaterial)
  510. {
  511. m_iWide = m_iTall = 0;
  512. m_s0 = m_t0 = 0.0f;
  513. m_s1 = m_t1 = 1.0f;
  514. return;
  515. }
  516. // Increment its reference count
  517. m_pMaterial->IncrementReferenceCount();
  518. // Compute texture size
  519. m_iWide = m_pMaterial->GetMappingWidth();
  520. m_iTall = m_pMaterial->GetMappingHeight();
  521. // Compute texture coordinates
  522. float flPixelCenterX = 0.0f;
  523. float flPixelCenterY = 0.0f;
  524. if ( m_iWide > 0.0f && m_iTall > 0.0f)
  525. {
  526. flPixelCenterX = 0.5f / m_iWide;
  527. flPixelCenterY = 0.5f / m_iTall;
  528. }
  529. m_s0 = flPixelCenterX;
  530. m_t0 = flPixelCenterY;
  531. // FIXME: Old code used +, it should be - yes?!??!
  532. m_s1 = 1.0 - flPixelCenterX;
  533. m_t1 = 1.0 - flPixelCenterY;
  534. if ( IsProcedural() )
  535. {
  536. bool bFound;
  537. IMaterialVar *tv = m_pMaterial->FindVar( "$baseTexture", &bFound );
  538. if ( bFound && tv->IsTexture() )
  539. {
  540. m_pTexture = tv->GetTextureValue();
  541. if ( m_pTexture )
  542. {
  543. m_pTexture->IncrementReferenceCount();
  544. // Upload new data
  545. CreateRegen( m_iWide, m_iTall, m_pTexture->GetImageFormat() );
  546. m_pTexture->SetTextureRegenerator( m_pRegen );
  547. }
  548. }
  549. }
  550. }
  551. //-----------------------------------------------------------------------------
  552. // This is used when we want different rendering state sharing the same procedural texture (fonts)
  553. //-----------------------------------------------------------------------------
  554. void CMatSystemTexture::ReferenceOtherProcedural( CMatSystemTexture *pTexture, IMaterial *pMaterial )
  555. {
  556. // Decrement references to old texture
  557. CleanUpMaterial();
  558. Assert( pTexture->IsProcedural() );
  559. m_Flags |= TEXTURE_IS_REFERENCE;
  560. m_pMaterial = pMaterial;
  561. if (!m_pMaterial)
  562. {
  563. m_iWide = m_iTall = 0;
  564. m_s0 = m_t0 = 0.0f;
  565. m_s1 = m_t1 = 1.0f;
  566. return;
  567. }
  568. m_iWide = pTexture->m_iWide;
  569. m_iTall = pTexture->m_iTall;
  570. m_s0 = pTexture->m_s0;
  571. m_t0 = pTexture->m_t0;
  572. m_s1 = pTexture->m_s1;
  573. m_t1 = pTexture->m_t1;
  574. Assert( (pMaterial->GetMappingWidth() == m_iWide) && (pMaterial->GetMappingHeight() == m_iTall) );
  575. // Increment its reference count
  576. m_pMaterial->IncrementReferenceCount();
  577. bool bFound;
  578. IMaterialVar *tv = m_pMaterial->FindVar( "$baseTexture", &bFound );
  579. if ( bFound )
  580. {
  581. m_pTexture = tv->GetTextureValue();
  582. if ( m_pTexture )
  583. {
  584. m_pTexture->IncrementReferenceCount();
  585. Assert( m_pTexture == pTexture->m_pTexture );
  586. // Reference, but do *not* create a new one!!!
  587. m_pRegen = pTexture->m_pRegen;
  588. }
  589. }
  590. }
  591. void CMatSystemTexture::SetMaterial( const char *pFileName )
  592. {
  593. // Get a pointer to the new material
  594. IMaterial *pMaterial = g_pMaterialSystem->FindMaterial( pFileName, TEXTURE_GROUP_VGUI );
  595. if ( IsErrorMaterial( pMaterial ) )
  596. {
  597. if (IsOSX())
  598. {
  599. printf( "\n ##### Missing Vgui material %s\n", pFileName );
  600. }
  601. Msg( "--- Missing Vgui material %s\n", pFileName );
  602. }
  603. SetMaterial( pMaterial );
  604. }
  605. //-----------------------------------------------------------------------------
  606. // Singleton instance
  607. //-----------------------------------------------------------------------------
  608. ITextureDictionary *TextureDictionary()
  609. {
  610. return &s_TextureDictionary;
  611. }
  612. CTextureDictionary::CTextureDictionary( void )
  613. {
  614. // First entry is bogus texture
  615. m_Textures.AddToTail();
  616. }
  617. //-----------------------------------------------------------------------------
  618. // Create, destroy textures
  619. //-----------------------------------------------------------------------------
  620. int CTextureDictionary::CreateTexture( bool procedural /*=false*/ )
  621. {
  622. int idx = m_Textures.AddToTail();
  623. CMatSystemTexture &texture = m_Textures[idx];
  624. texture.SetProcedural( procedural );
  625. texture.SetId( idx );
  626. return idx;
  627. }
  628. int CTextureDictionary::CreateTextureByTexture( ITexture *pTexture, bool procedural /*= true*/ )
  629. {
  630. int idx = m_Textures.AddToTail();
  631. CMatSystemTexture &texture = m_Textures[idx];
  632. texture.SetProcedural( procedural );
  633. texture.SetId( idx );
  634. texture.SetTexture( pTexture );
  635. return idx;
  636. }
  637. void CTextureDictionary::DestroyTexture( int id )
  638. {
  639. if ( m_Textures.Count() <= 1 )
  640. {
  641. // TextureDictionary already destroyed all the textures before this (something destructed late in shutdown)
  642. return;
  643. }
  644. if (id != INVALID_TEXTURE_ID)
  645. {
  646. Assert( id != m_Textures.InvalidIndex() );
  647. m_Textures.Remove( (unsigned short)id );
  648. }
  649. }
  650. void CTextureDictionary::DestroyAllTextures()
  651. {
  652. m_Textures.RemoveAll();
  653. // First entry is bogus texture
  654. m_Textures.AddToTail();
  655. CMatSystemTexture &texture = m_Textures[0];
  656. texture.SetId( 0 );
  657. }
  658. void CTextureDictionary::SetTextureRGBA( int id, const char* rgba, int wide, int tall )
  659. {
  660. SetTextureRGBAEx( id, rgba, wide, tall, IMAGE_FORMAT_RGBA8888, false );
  661. }
  662. void CTextureDictionary::SetTextureRGBAEx( int id, const char* rgba, int wide, int tall, ImageFormat format, bool bFixupTextCoordsForDimensions )
  663. {
  664. if (!IsValidId(id))
  665. {
  666. Msg( "SetTextureRGBA: Invalid texture id %i\n", id );
  667. return;
  668. }
  669. CMatSystemTexture &texture = m_Textures[id];
  670. texture.SetTextureRGBA( rgba, wide, tall, format, bFixupTextCoordsForDimensions );
  671. }
  672. void CTextureDictionary::SetSubTextureRGBA( int id, int drawX, int drawY, unsigned const char *rgba, int subTextureWide, int subTextureTall )
  673. {
  674. SetSubTextureRGBAEx( id, drawX, drawY, rgba, subTextureWide, subTextureTall, IMAGE_FORMAT_RGBA8888 );
  675. }
  676. void CTextureDictionary::SetSubTextureRGBAEx( int id, int drawX, int drawY, unsigned const char *rgba, int subTextureWide, int subTextureTall, ImageFormat format )
  677. {
  678. if (!IsValidId(id))
  679. {
  680. Msg( "SetSubTextureRGBA: Invalid texture id %i\n", id );
  681. return;
  682. }
  683. CMatSystemTexture &texture = m_Textures[id];
  684. texture.SetSubTextureRGBAEx( drawX, drawY, rgba, subTextureWide, subTextureTall, format );
  685. }
  686. void CTextureDictionary::UpdateSubTextureRGBA( int id, int drawX, int drawY, unsigned const char *rgba, int subTextureWide, int subTextureTall, ImageFormat imageFormat )
  687. {
  688. if (!IsValidId(id))
  689. {
  690. Msg( "UpdateSubTextureRGBA: Invalid texture id %i\n", id );
  691. return;
  692. }
  693. CMatSystemTexture &texture = m_Textures[id];
  694. texture.UpdateSubTextureRGBA( drawX, drawY, rgba, subTextureWide, subTextureTall, imageFormat );
  695. }
  696. //-----------------------------------------------------------------------------
  697. // Returns true if the id is valid
  698. //-----------------------------------------------------------------------------
  699. bool CTextureDictionary::IsValidId( int id ) const
  700. {
  701. Assert( id != 0 );
  702. if ( id == 0 )
  703. return false;
  704. return m_Textures.IsValidIndex( id );
  705. }
  706. //-----------------------------------------------------------------------------
  707. // Binds a file to a particular texture
  708. //-----------------------------------------------------------------------------
  709. void CTextureDictionary::BindTextureToFile( int id, const char *pFileName )
  710. {
  711. if (!IsValidId(id))
  712. {
  713. Msg( "BindTextureToFile: Invalid texture id for file %s\n", pFileName );
  714. return;
  715. }
  716. CMatSystemTexture &texture = m_Textures[id];
  717. // Reload from file if the material was never loaded, or if the filename has changed at all
  718. CRC32_t fileNameCRC = Texture_CRCName( pFileName );
  719. if ( !texture.GetMaterial() || fileNameCRC != texture.GetCRC() )
  720. {
  721. // New texture name
  722. texture.SetCRC( fileNameCRC );
  723. texture.SetMaterial( pFileName );
  724. }
  725. }
  726. //-----------------------------------------------------------------------------
  727. // Binds a material to a texture
  728. //-----------------------------------------------------------------------------
  729. void CTextureDictionary::BindTextureToMaterial( int id, IMaterial *pMaterial )
  730. {
  731. if (!IsValidId(id))
  732. {
  733. Msg( "BindTextureToFile: Invalid texture id %d\n", id );
  734. return;
  735. }
  736. CMatSystemTexture &texture = m_Textures[id];
  737. texture.SetMaterial( pMaterial );
  738. }
  739. //-----------------------------------------------------------------------------
  740. // Binds a material to a texture reference
  741. //-----------------------------------------------------------------------------
  742. void CTextureDictionary::BindTextureToMaterialReference( int id, int referenceId, IMaterial *pMaterial )
  743. {
  744. if (!IsValidId(id) || !IsValidId(referenceId))
  745. {
  746. Msg( "BindTextureToFile: Invalid texture ids %d %d\n", id, referenceId );
  747. return;
  748. }
  749. CMatSystemTexture &texture = m_Textures[id];
  750. CMatSystemTexture &textureSource = m_Textures[referenceId];
  751. texture.ReferenceOtherProcedural( &textureSource, pMaterial );
  752. }
  753. //-----------------------------------------------------------------------------
  754. // Returns the material associated with an id
  755. //-----------------------------------------------------------------------------
  756. IMaterial *CTextureDictionary::GetTextureMaterial( int id )
  757. {
  758. if (!IsValidId(id))
  759. return NULL;
  760. return m_Textures[id].GetMaterial();
  761. }
  762. //-----------------------------------------------------------------------------
  763. // Returns the material size associated with an id
  764. //-----------------------------------------------------------------------------
  765. void CTextureDictionary::GetTextureSize(int id, int& iWide, int& iTall )
  766. {
  767. if (!IsValidId(id))
  768. {
  769. iWide = iTall = 0;
  770. return;
  771. }
  772. iWide = m_Textures[id].Width();
  773. iTall = m_Textures[id].Height();
  774. }
  775. void CTextureDictionary::GetTextureTexCoords( int id, float &s0, float &t0, float &s1, float &t1 )
  776. {
  777. if (!IsValidId(id))
  778. {
  779. s0 = t0 = 0.0f;
  780. s1 = t1 = 1.0f;
  781. return;
  782. }
  783. s0 = m_Textures[id].m_s0;
  784. t0 = m_Textures[id].m_t0;
  785. s1 = m_Textures[id].m_s1;
  786. t1 = m_Textures[id].m_t1;
  787. }
  788. //-----------------------------------------------------------------------------
  789. // Purpose:
  790. // Input : id -
  791. // Output : CMatSystemTexture
  792. //-----------------------------------------------------------------------------
  793. CMatSystemTexture *CTextureDictionary::GetTexture( int id )
  794. {
  795. if (!IsValidId(id))
  796. return NULL;
  797. return &m_Textures[ id ];
  798. }
  799. //-----------------------------------------------------------------------------
  800. // Purpose:
  801. // Input : *pFileName -
  802. //-----------------------------------------------------------------------------
  803. int CTextureDictionary::FindTextureIdForTextureFile( char const *pFileName )
  804. {
  805. for ( int i = m_Textures.Head(); i != m_Textures.InvalidIndex(); i = m_Textures.Next( i ) )
  806. {
  807. CMatSystemTexture *tex = &m_Textures[i];
  808. if ( !tex )
  809. continue;
  810. IMaterial *mat = tex->GetMaterial();
  811. if ( !mat )
  812. continue;
  813. if ( !stricmp( mat->GetName(), pFileName ) )
  814. return i;
  815. }
  816. return -1;
  817. }