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.

166 lines
4.9 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include "tier1/strtools.h"
  7. #include "macro_texture.h"
  8. #include "bsplib.h"
  9. #include "cmdlib.h"
  10. #include "vtf/vtf.h"
  11. #include "tier1/utldict.h"
  12. #include "tier1/utlbuffer.h"
  13. #include "bitmap/imageformat.h"
  14. class CMacroTextureData
  15. {
  16. public:
  17. int m_Width, m_Height;
  18. CUtlMemory<unsigned char> m_ImageData;
  19. };
  20. CMacroTextureData *g_pGlobalMacroTextureData = NULL;
  21. // Which macro texture each map face uses.
  22. static CUtlDict<CMacroTextureData*, int> g_MacroTextureLookup; // Stores a list of unique macro textures.
  23. static CUtlVector<CMacroTextureData*> g_FaceMacroTextures; // Which macro texture each face wants to use.
  24. static Vector g_MacroWorldMins, g_MacroWorldMaxs;
  25. CMacroTextureData* FindMacroTexture( const char *pFilename )
  26. {
  27. int index = g_MacroTextureLookup.Find( pFilename );
  28. if ( g_MacroTextureLookup.IsValidIndex( index ) )
  29. return g_MacroTextureLookup[index];
  30. else
  31. return NULL;
  32. }
  33. CMacroTextureData* LoadMacroTextureFile( const char *pFilename )
  34. {
  35. FileHandle_t hFile = g_pFileSystem->Open( pFilename, "rb" );
  36. if ( hFile == FILESYSTEM_INVALID_HANDLE )
  37. return NULL;
  38. // Read the file in.
  39. CUtlVector<char> tempData;
  40. tempData.SetSize( g_pFileSystem->Size( hFile ) );
  41. g_pFileSystem->Read( tempData.Base(), tempData.Count(), hFile );
  42. g_pFileSystem->Close( hFile );
  43. // Now feed the data into a CUtlBuffer (great...)
  44. CUtlBuffer buf;
  45. buf.Put( tempData.Base(), tempData.Count() );
  46. // Now make a texture out of it.
  47. IVTFTexture *pTex = CreateVTFTexture();
  48. if ( !pTex->Unserialize( buf ) )
  49. Error( "IVTFTexture::Unserialize( %s ) failed.", pFilename );
  50. pTex->ConvertImageFormat( IMAGE_FORMAT_RGBA8888, false ); // Get it in a format we like.
  51. // Now convert to a CMacroTextureData.
  52. CMacroTextureData *pData = new CMacroTextureData;
  53. pData->m_Width = pTex->Width();
  54. pData->m_Height = pTex->Height();
  55. pData->m_ImageData.EnsureCapacity( pData->m_Width * pData->m_Height * 4 );
  56. memcpy( pData->m_ImageData.Base(), pTex->ImageData(), pData->m_Width * pData->m_Height * 4 );
  57. DestroyVTFTexture( pTex );
  58. Msg( "-- LoadMacroTextureFile: %s\n", pFilename );
  59. return pData;
  60. }
  61. void InitMacroTexture( const char *pBSPFilename )
  62. {
  63. // Get the world bounds (same ones used by minimaps and level designers know how to use).
  64. int i = 0;
  65. for (i; i < num_entities; ++i)
  66. {
  67. char* pEntity = ValueForKey(&entities[i], "classname");
  68. if( !strcmp(pEntity, "worldspawn") )
  69. {
  70. GetVectorForKey( &entities[i], "world_mins", g_MacroWorldMins );
  71. GetVectorForKey( &entities[i], "world_maxs", g_MacroWorldMaxs );
  72. break;
  73. }
  74. }
  75. if ( i == num_entities )
  76. {
  77. Warning( "MaskOnMacroTexture: can't find worldspawn" );
  78. return;
  79. }
  80. // Load the macro texture that is mapped onto everything.
  81. char mapName[512], vtfFilename[512];
  82. Q_FileBase( pBSPFilename, mapName, sizeof( mapName ) );
  83. Q_snprintf( vtfFilename, sizeof( vtfFilename ), "materials/macro/%s/base.vtf", mapName );
  84. g_pGlobalMacroTextureData = LoadMacroTextureFile( vtfFilename );
  85. // Now load the macro texture for each face.
  86. g_FaceMacroTextures.SetSize( numfaces );
  87. for ( int iFace=0; iFace < numfaces; iFace++ )
  88. {
  89. g_FaceMacroTextures[iFace] = NULL;
  90. if ( iFace < g_FaceMacroTextureInfos.Count() )
  91. {
  92. unsigned short stringID = g_FaceMacroTextureInfos[iFace].m_MacroTextureNameID;
  93. if ( stringID != 0xFFFF )
  94. {
  95. const char *pMacroTextureName = &g_TexDataStringData[ g_TexDataStringTable[stringID] ];
  96. Q_snprintf( vtfFilename, sizeof( vtfFilename ), "%smaterials/%s.vtf", gamedir, pMacroTextureName );
  97. g_FaceMacroTextures[iFace] = FindMacroTexture( vtfFilename );
  98. if ( !g_FaceMacroTextures[iFace] )
  99. {
  100. g_FaceMacroTextures[iFace] = LoadMacroTextureFile( vtfFilename );
  101. if ( g_FaceMacroTextures[iFace] )
  102. {
  103. g_MacroTextureLookup.Insert( vtfFilename, g_FaceMacroTextures[iFace] );
  104. }
  105. }
  106. }
  107. }
  108. }
  109. }
  110. inline Vector SampleMacroTexture( const CMacroTextureData *t, const Vector &vWorldPos )
  111. {
  112. int ix = (int)RemapVal( vWorldPos.x, g_MacroWorldMins.x, g_MacroWorldMaxs.x, 0, t->m_Width-0.00001 );
  113. int iy = (int)RemapVal( vWorldPos.y, g_MacroWorldMins.y, g_MacroWorldMaxs.y, 0, t->m_Height-0.00001 );
  114. ix = clamp( ix, 0, t->m_Width-1 );
  115. iy = t->m_Height - 1 - clamp( iy, 0, t->m_Height-1 );
  116. const unsigned char *pInputColor = &t->m_ImageData[(iy*t->m_Width + ix) * 4];
  117. return Vector( pInputColor[0] / 255.0, pInputColor[1] / 255.0, pInputColor[2] / 255.0 );
  118. }
  119. void ApplyMacroTextures( int iFace, const Vector &vWorldPos, Vector &outLuxel )
  120. {
  121. // Add the global macro texture.
  122. Vector vGlobal;
  123. if ( g_pGlobalMacroTextureData )
  124. outLuxel *= SampleMacroTexture( g_pGlobalMacroTextureData, vWorldPos );
  125. // Now add the per-material macro texture.
  126. if ( g_FaceMacroTextures[iFace] )
  127. outLuxel *= SampleMacroTexture( g_FaceMacroTextures[iFace], vWorldPos );
  128. }