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.

395 lines
10 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #ifdef _WIN32
  7. #include <windows.h>
  8. #endif
  9. #include "bitmap/imageformat.h"
  10. #include "basetypes.h"
  11. #include "tier0/dbg.h"
  12. #include <malloc.h>
  13. #include <memory.h>
  14. #include "nvtc.h"
  15. #include "mathlib/mathlib.h"
  16. #include "mathlib/vector.h"
  17. #include "utlmemory.h"
  18. #include "tier1/strtools.h"
  19. #include "s3tc_decode.h"
  20. #include "utlvector.h"
  21. // memdbgon must be the last include file in a .cpp file!!!
  22. #include "tier0/memdbgon.h"
  23. // This is in s3tc.lib. Nvidia added it specially for us. It can be set to 4, 8, or 12.
  24. // When set to 8 or 12, it generates a palette given an 8x4 or 12x4 texture.
  25. extern int S3TC_BLOCK_WIDTH;
  26. class S3Palette
  27. {
  28. public:
  29. S3RGBA m_Colors[4];
  30. };
  31. class S3TCBlock_DXT1
  32. {
  33. public:
  34. unsigned short m_Ref1; // The two colors that this block blends betwixt.
  35. unsigned short m_Ref2;
  36. unsigned int m_PixelBits;
  37. };
  38. class S3TCBlock_DXT5
  39. {
  40. public:
  41. unsigned char m_AlphaRef[2];
  42. unsigned char m_AlphaBits[6];
  43. unsigned short m_Ref1; // The two colors that this block blends betwixt.
  44. unsigned short m_Ref2;
  45. unsigned int m_PixelBits;
  46. };
  47. // ------------------------------------------------------------------------------------------ //
  48. // S3TCBlock
  49. // ------------------------------------------------------------------------------------------ //
  50. int ReadBitInt( const char *pBits, int iBaseBit, int nBits )
  51. {
  52. int ret = 0;
  53. for ( int i=0; i < nBits; i++ )
  54. {
  55. int iBit = iBaseBit + i;
  56. int val = ((pBits[iBit>>3] >> (iBit&7)) & 1) << i;
  57. ret |= val;
  58. }
  59. return ret;
  60. }
  61. void WriteBitInt( char *pBits, int iBaseBit, int nBits, int val )
  62. {
  63. for ( int i=0; i < nBits; i++ )
  64. {
  65. int iBit = iBaseBit + i;
  66. pBits[iBit>>3] &= ~(1 << (iBit & 7));
  67. if ( (val >> i) & 1 )
  68. pBits[iBit>>3] |= (1 << (iBit & 7));
  69. }
  70. }
  71. int S3TC_BytesPerBlock( ImageFormat format )
  72. {
  73. if ( format == IMAGE_FORMAT_DXT1 || format == IMAGE_FORMAT_ATI1N )
  74. {
  75. return 8;
  76. }
  77. else
  78. {
  79. Assert( format == IMAGE_FORMAT_DXT5 || format == IMAGE_FORMAT_ATI2N );
  80. return 16;
  81. }
  82. }
  83. /*
  84. // We're not using this, but I'll keep it around for reference.
  85. void S3TC_BuildPalette( ImageFormat format, const char *pS3Block, S3RGBA palette[4] )
  86. {
  87. if ( format == IMAGE_FORMAT_DXT1 )
  88. {
  89. const S3TCBlock_DXT1 *pBlock = reinterpret_cast<const S3TCBlock_DXT1 *>( pS3Block );
  90. palette[0] = S3TC_RGBAFrom565( pBlock->m_Ref1, 255 );
  91. if ( pBlock->m_Ref1 <= pBlock->m_Ref2 )
  92. {
  93. // Opaque and transparent texels are defined. The lookup is 3 colors. 11 means
  94. // a black, transparent pixel.
  95. palette[1] = S3TC_RGBAFrom565( pBlock->m_Ref2, 255 );
  96. palette[2] = S3TC_RGBABlend( palette[0], palette[1], 1, 1, 2 );
  97. palette[3].r = palette[3].g = palette[3].b = palette[3].a = 0;
  98. }
  99. else
  100. {
  101. // Only opaque texels are defined. The lookup is 4 colors.
  102. palette[1] = S3TC_RGBAFrom565( pBlock->m_Ref2, 255 );
  103. palette[2] = S3TC_RGBABlend( palette[0], palette[1], 2, 1, 3 );
  104. palette[3] = S3TC_RGBABlend( palette[0], palette[1], 1, 2, 3 );
  105. }
  106. }
  107. else
  108. {
  109. Assert( format == IMAGE_FORMAT_DXT5 );
  110. }
  111. }
  112. */
  113. S3PaletteIndex S3TC_GetPixelPaletteIndex( ImageFormat format, const char *pS3Block, int x, int y )
  114. {
  115. Assert( x >= 0 && x < 4 );
  116. Assert( y >= 0 && y < 4 );
  117. int iQuadPixel = y*4 + x;
  118. S3PaletteIndex ret = { 0, 0 };
  119. if ( format == IMAGE_FORMAT_DXT1 )
  120. {
  121. const S3TCBlock_DXT1 *pBlock = reinterpret_cast<const S3TCBlock_DXT1 *>( pS3Block );
  122. ret.m_ColorIndex = (pBlock->m_PixelBits >> (iQuadPixel << 1)) & 3;
  123. ret.m_AlphaIndex = 0;
  124. }
  125. else
  126. {
  127. Assert( format == IMAGE_FORMAT_DXT5 );
  128. const S3TCBlock_DXT5 *pBlock = reinterpret_cast<const S3TCBlock_DXT5 *>( pS3Block );
  129. int64 &alphaBits = *((int64*)pBlock->m_AlphaBits);
  130. ret.m_ColorIndex = (unsigned char)((pBlock->m_PixelBits >> (iQuadPixel << 1)) & 3);
  131. ret.m_AlphaIndex = (unsigned char)((alphaBits >> (iQuadPixel * 3)) & 7);
  132. }
  133. return ret;
  134. }
  135. void S3TC_SetPixelPaletteIndex( ImageFormat format, char *pS3Block, int x, int y, S3PaletteIndex iPaletteIndex )
  136. {
  137. Assert( x >= 0 && x < 4 );
  138. Assert( y >= 0 && y < 4 );
  139. Assert( iPaletteIndex.m_ColorIndex >= 0 && iPaletteIndex.m_ColorIndex < 4 );
  140. Assert( iPaletteIndex.m_AlphaIndex >= 0 && iPaletteIndex.m_AlphaIndex < 8 );
  141. int iQuadPixel = y*4 + x;
  142. int iColorBit = iQuadPixel * 2;
  143. if ( format == IMAGE_FORMAT_DXT1 )
  144. {
  145. S3TCBlock_DXT1 *pBlock = reinterpret_cast<S3TCBlock_DXT1 *>( pS3Block );
  146. pBlock->m_PixelBits &= ~( 3 << iColorBit );
  147. pBlock->m_PixelBits |= (unsigned int)iPaletteIndex.m_ColorIndex << iColorBit;
  148. }
  149. else
  150. {
  151. Assert( format == IMAGE_FORMAT_DXT5 );
  152. S3TCBlock_DXT5 *pBlock = reinterpret_cast<S3TCBlock_DXT5 *>( pS3Block );
  153. // Copy the color portion in.
  154. pBlock->m_PixelBits &= ~( 3 << iColorBit );
  155. pBlock->m_PixelBits |= (unsigned int)iPaletteIndex.m_ColorIndex << iColorBit;
  156. // Copy the alpha portion in.
  157. WriteBitInt( (char*)pBlock->m_AlphaBits, iQuadPixel*3, 3, iPaletteIndex.m_AlphaIndex );
  158. }
  159. }
  160. const char* S3TC_GetBlock(
  161. const void *pCompressed,
  162. ImageFormat format,
  163. int nBlocksWidth,
  164. int xBlock,
  165. int yBlock )
  166. {
  167. int nBytesPerBlock = S3TC_BytesPerBlock( format );
  168. return &((const char*)pCompressed)[ ((yBlock * nBlocksWidth) + xBlock) * nBytesPerBlock ];
  169. }
  170. char* S3TC_GetBlock(
  171. void *pCompressed,
  172. ImageFormat format,
  173. int nBlocksWidth,
  174. int xBlock,
  175. int yBlock )
  176. {
  177. return (char*)S3TC_GetBlock( (const void *)pCompressed, format, nBlocksWidth, xBlock, yBlock );
  178. }
  179. void GenerateRepresentativePalette(
  180. ImageFormat format,
  181. S3RGBA **pOriginals, // Original RGBA colors in the texture. This allows it to avoid doubly compressing.
  182. int nBlocks,
  183. int lPitch, // (in BYTES)
  184. char mergedBlocks[16*MAX_S3TC_BLOCK_BYTES]
  185. )
  186. {
  187. Error( "GenerateRepresentativePalette: not implemented" );
  188. #if 0 // this code was ifdefed out. no idea under what circumstances it was meant to be called.
  189. Assert( nBlocks == 2 || nBlocks == 3 );
  190. S3RGBA values[12*4];
  191. memset( values, 0xFF, sizeof( values ) );
  192. int width = nBlocks * 4;
  193. for ( int i=0; i < nBlocks; i++ )
  194. {
  195. for ( int y=0; y < 4; y++ )
  196. {
  197. for ( int x=0; x < 4; x++ )
  198. {
  199. int outIndex = y*width+(i*4+x);
  200. values[outIndex] = pOriginals[i][y * (lPitch/4) + x];
  201. }
  202. }
  203. }
  204. DDSURFACEDESC descIn;
  205. DDSURFACEDESC descOut;
  206. memset( &descIn, 0, sizeof(descIn) );
  207. memset( &descOut, 0, sizeof(descOut) );
  208. descIn.dwSize = sizeof(descIn);
  209. descIn.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_LPSURFACE | DDSD_PIXELFORMAT;
  210. descIn.dwWidth = width;
  211. descIn.dwHeight = 4;
  212. descIn.lPitch = width * 4;
  213. descIn.lpSurface = values;
  214. descIn.ddpfPixelFormat.dwSize = sizeof( DDPIXELFORMAT );
  215. descIn.ddpfPixelFormat.dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
  216. descIn.ddpfPixelFormat.dwRGBBitCount = 32;
  217. descIn.ddpfPixelFormat.dwRBitMask = 0xff0000;
  218. descIn.ddpfPixelFormat.dwGBitMask = 0x00ff00;
  219. descIn.ddpfPixelFormat.dwBBitMask = 0x0000ff;
  220. descIn.ddpfPixelFormat.dwRGBAlphaBitMask = 0xff000000;
  221. descOut.dwSize = sizeof( descOut );
  222. float weight[3] = {0.3086f, 0.6094f, 0.0820f};
  223. S3TC_BLOCK_WIDTH = nBlocks * 4;
  224. DWORD encodeFlags = S3TC_ENCODE_RGB_FULL;
  225. if ( format == IMAGE_FORMAT_DXT5 )
  226. encodeFlags |= S3TC_ENCODE_ALPHA_INTERPOLATED;
  227. S3TCencode( &descIn, NULL, &descOut, mergedBlocks, encodeFlags, weight );
  228. S3TC_BLOCK_WIDTH = 4;
  229. #endif
  230. }
  231. void S3TC_MergeBlocks(
  232. char **blocks,
  233. S3RGBA **pOriginals, // Original RGBA colors in the texture. This allows it to avoid doubly compressing.
  234. int nBlocks,
  235. int lPitch, // (in BYTES)
  236. ImageFormat format
  237. )
  238. {
  239. // Figure out a good palette to represent all of these blocks.
  240. char mergedBlocks[16*MAX_S3TC_BLOCK_BYTES];
  241. GenerateRepresentativePalette( format, pOriginals, nBlocks, lPitch, mergedBlocks );
  242. // Build a remap table to remap block 2's colors to block 1's colors.
  243. if ( format == IMAGE_FORMAT_DXT1 )
  244. {
  245. // Grab the palette indices that s3tc.lib made for us.
  246. const char *pBase = (const char*)mergedBlocks;
  247. pBase += 4;
  248. for ( int iBlock=0; iBlock < nBlocks; iBlock++ )
  249. {
  250. S3TCBlock_DXT1 *pBlock = ((S3TCBlock_DXT1*)blocks[iBlock]);
  251. // Remap all of the block's pixels.
  252. for ( int x=0; x < 4; x++ )
  253. {
  254. for ( int y=0; y < 4; y++ )
  255. {
  256. int iBaseBit = (y*nBlocks*4 + x + iBlock*4) * 2;
  257. S3PaletteIndex index = {0, 0};
  258. index.m_ColorIndex = ReadBitInt( pBase, iBaseBit, 2 );
  259. S3TC_SetPixelPaletteIndex( format, (char*)pBlock, x, y, index );
  260. }
  261. }
  262. // Copy block 1's palette to block 2.
  263. pBlock->m_Ref1 = ((S3TCBlock_DXT1*)mergedBlocks)->m_Ref1;
  264. pBlock->m_Ref2 = ((S3TCBlock_DXT1*)mergedBlocks)->m_Ref2;
  265. }
  266. }
  267. else
  268. {
  269. Assert( format == IMAGE_FORMAT_DXT5 );
  270. // Skip past the alpha palette.
  271. const char *pAlphaPalette = mergedBlocks;
  272. const char *pAlphaBits = mergedBlocks + 2;
  273. // Skip past the alpha pixel bits and past the color palette.
  274. const char *pColorPalette = pAlphaBits + 6*nBlocks;
  275. const char *pColorBits = pColorPalette + 4;
  276. for ( int iBlock=0; iBlock < nBlocks; iBlock++ )
  277. {
  278. S3TCBlock_DXT5 *pBlock = ((S3TCBlock_DXT5*)blocks[iBlock]);
  279. // Remap all of the block's pixels.
  280. for ( int x=0; x < 4; x++ )
  281. {
  282. for ( int y=0; y < 4; y++ )
  283. {
  284. int iBasePixel = (y*nBlocks*4 + x + iBlock*4);
  285. S3PaletteIndex index;
  286. index.m_ColorIndex = ReadBitInt( pColorBits, iBasePixel * 2, 2 );
  287. index.m_AlphaIndex = ReadBitInt( pAlphaBits, iBasePixel * 3, 3 );
  288. S3TC_SetPixelPaletteIndex( format, (char*)pBlock, x, y, index );
  289. }
  290. }
  291. // Copy block 1's palette to block 2.
  292. pBlock->m_AlphaRef[0] = pAlphaPalette[0];
  293. pBlock->m_AlphaRef[1] = pAlphaPalette[1];
  294. pBlock->m_Ref1 = *((unsigned short*)pColorPalette);
  295. pBlock->m_Ref2 = *((unsigned short*)(pColorPalette + 2));
  296. }
  297. }
  298. }
  299. S3PaletteIndex S3TC_GetPaletteIndex(
  300. unsigned char *pFaceData,
  301. ImageFormat format,
  302. int imageWidth,
  303. int x,
  304. int y )
  305. {
  306. char *pBlock = S3TC_GetBlock( pFaceData, format, imageWidth>>2, x>>2, y>>2 );
  307. return S3TC_GetPixelPaletteIndex( format, pBlock, x&3, y&3 );
  308. }
  309. void S3TC_SetPaletteIndex(
  310. unsigned char *pFaceData,
  311. ImageFormat format,
  312. int imageWidth,
  313. int x,
  314. int y,
  315. S3PaletteIndex paletteIndex )
  316. {
  317. char *pBlock = S3TC_GetBlock( pFaceData, format, imageWidth>>2, x>>2, y>>2 );
  318. S3TC_SetPixelPaletteIndex( format, pBlock, x&3, y&3, paletteIndex );
  319. }