summaryrefslogtreecommitdiff
path: root/vtf/s3tc_decode.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /vtf/s3tc_decode.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'vtf/s3tc_decode.cpp')
-rw-r--r--vtf/s3tc_decode.cpp395
1 files changed, 395 insertions, 0 deletions
diff --git a/vtf/s3tc_decode.cpp b/vtf/s3tc_decode.cpp
new file mode 100644
index 0000000..65909eb
--- /dev/null
+++ b/vtf/s3tc_decode.cpp
@@ -0,0 +1,395 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+
+#ifdef _WIN32
+#include <windows.h>
+#endif
+#include "bitmap/imageformat.h"
+#include "basetypes.h"
+#include "tier0/dbg.h"
+#include <malloc.h>
+#include <memory.h>
+#include "nvtc.h"
+#include "mathlib/mathlib.h"
+#include "mathlib/vector.h"
+#include "utlmemory.h"
+#include "tier1/strtools.h"
+#include "s3tc_decode.h"
+#include "utlvector.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+// This is in s3tc.lib. Nvidia added it specially for us. It can be set to 4, 8, or 12.
+// When set to 8 or 12, it generates a palette given an 8x4 or 12x4 texture.
+extern int S3TC_BLOCK_WIDTH;
+
+
+class S3Palette
+{
+public:
+ S3RGBA m_Colors[4];
+};
+
+
+class S3TCBlock_DXT1
+{
+public:
+ unsigned short m_Ref1; // The two colors that this block blends betwixt.
+ unsigned short m_Ref2;
+ unsigned int m_PixelBits;
+};
+
+
+class S3TCBlock_DXT5
+{
+public:
+ unsigned char m_AlphaRef[2];
+ unsigned char m_AlphaBits[6];
+
+ unsigned short m_Ref1; // The two colors that this block blends betwixt.
+ unsigned short m_Ref2;
+ unsigned int m_PixelBits;
+};
+
+
+
+// ------------------------------------------------------------------------------------------ //
+// S3TCBlock
+// ------------------------------------------------------------------------------------------ //
+
+int ReadBitInt( const char *pBits, int iBaseBit, int nBits )
+{
+ int ret = 0;
+ for ( int i=0; i < nBits; i++ )
+ {
+ int iBit = iBaseBit + i;
+ int val = ((pBits[iBit>>3] >> (iBit&7)) & 1) << i;
+ ret |= val;
+ }
+ return ret;
+}
+
+void WriteBitInt( char *pBits, int iBaseBit, int nBits, int val )
+{
+ for ( int i=0; i < nBits; i++ )
+ {
+ int iBit = iBaseBit + i;
+ pBits[iBit>>3] &= ~(1 << (iBit & 7));
+ if ( (val >> i) & 1 )
+ pBits[iBit>>3] |= (1 << (iBit & 7));
+ }
+}
+
+int S3TC_BytesPerBlock( ImageFormat format )
+{
+ if ( format == IMAGE_FORMAT_DXT1 || format == IMAGE_FORMAT_ATI1N )
+ {
+ return 8;
+ }
+ else
+ {
+ Assert( format == IMAGE_FORMAT_DXT5 || format == IMAGE_FORMAT_ATI2N );
+ return 16;
+ }
+}
+
+
+/*
+
+// We're not using this, but I'll keep it around for reference.
+void S3TC_BuildPalette( ImageFormat format, const char *pS3Block, S3RGBA palette[4] )
+{
+ if ( format == IMAGE_FORMAT_DXT1 )
+ {
+ const S3TCBlock_DXT1 *pBlock = reinterpret_cast<const S3TCBlock_DXT1 *>( pS3Block );
+
+ palette[0] = S3TC_RGBAFrom565( pBlock->m_Ref1, 255 );
+
+ if ( pBlock->m_Ref1 <= pBlock->m_Ref2 )
+ {
+ // Opaque and transparent texels are defined. The lookup is 3 colors. 11 means
+ // a black, transparent pixel.
+ palette[1] = S3TC_RGBAFrom565( pBlock->m_Ref2, 255 );
+ palette[2] = S3TC_RGBABlend( palette[0], palette[1], 1, 1, 2 );
+ palette[3].r = palette[3].g = palette[3].b = palette[3].a = 0;
+ }
+ else
+ {
+ // Only opaque texels are defined. The lookup is 4 colors.
+ palette[1] = S3TC_RGBAFrom565( pBlock->m_Ref2, 255 );
+ palette[2] = S3TC_RGBABlend( palette[0], palette[1], 2, 1, 3 );
+ palette[3] = S3TC_RGBABlend( palette[0], palette[1], 1, 2, 3 );
+ }
+ }
+ else
+ {
+ Assert( format == IMAGE_FORMAT_DXT5 );
+ }
+}
+
+*/
+
+
+S3PaletteIndex S3TC_GetPixelPaletteIndex( ImageFormat format, const char *pS3Block, int x, int y )
+{
+ Assert( x >= 0 && x < 4 );
+ Assert( y >= 0 && y < 4 );
+ int iQuadPixel = y*4 + x;
+ S3PaletteIndex ret = { 0, 0 };
+
+ if ( format == IMAGE_FORMAT_DXT1 )
+ {
+ const S3TCBlock_DXT1 *pBlock = reinterpret_cast<const S3TCBlock_DXT1 *>( pS3Block );
+ ret.m_ColorIndex = (pBlock->m_PixelBits >> (iQuadPixel << 1)) & 3;
+ ret.m_AlphaIndex = 0;
+ }
+ else
+ {
+ Assert( format == IMAGE_FORMAT_DXT5 );
+
+ const S3TCBlock_DXT5 *pBlock = reinterpret_cast<const S3TCBlock_DXT5 *>( pS3Block );
+
+ int64 &alphaBits = *((int64*)pBlock->m_AlphaBits);
+ ret.m_ColorIndex = (unsigned char)((pBlock->m_PixelBits >> (iQuadPixel << 1)) & 3);
+ ret.m_AlphaIndex = (unsigned char)((alphaBits >> (iQuadPixel * 3)) & 7);
+ }
+
+ return ret;
+}
+
+
+void S3TC_SetPixelPaletteIndex( ImageFormat format, char *pS3Block, int x, int y, S3PaletteIndex iPaletteIndex )
+{
+ Assert( x >= 0 && x < 4 );
+ Assert( y >= 0 && y < 4 );
+ Assert( iPaletteIndex.m_ColorIndex >= 0 && iPaletteIndex.m_ColorIndex < 4 );
+ Assert( iPaletteIndex.m_AlphaIndex >= 0 && iPaletteIndex.m_AlphaIndex < 8 );
+
+ int iQuadPixel = y*4 + x;
+ int iColorBit = iQuadPixel * 2;
+
+ if ( format == IMAGE_FORMAT_DXT1 )
+ {
+ S3TCBlock_DXT1 *pBlock = reinterpret_cast<S3TCBlock_DXT1 *>( pS3Block );
+
+ pBlock->m_PixelBits &= ~( 3 << iColorBit );
+ pBlock->m_PixelBits |= (unsigned int)iPaletteIndex.m_ColorIndex << iColorBit;
+ }
+ else
+ {
+ Assert( format == IMAGE_FORMAT_DXT5 );
+
+ S3TCBlock_DXT5 *pBlock = reinterpret_cast<S3TCBlock_DXT5 *>( pS3Block );
+
+ // Copy the color portion in.
+ pBlock->m_PixelBits &= ~( 3 << iColorBit );
+ pBlock->m_PixelBits |= (unsigned int)iPaletteIndex.m_ColorIndex << iColorBit;
+
+ // Copy the alpha portion in.
+ WriteBitInt( (char*)pBlock->m_AlphaBits, iQuadPixel*3, 3, iPaletteIndex.m_AlphaIndex );
+ }
+}
+
+
+const char* S3TC_GetBlock(
+ const void *pCompressed,
+ ImageFormat format,
+ int nBlocksWidth,
+ int xBlock,
+ int yBlock )
+{
+ int nBytesPerBlock = S3TC_BytesPerBlock( format );
+ return &((const char*)pCompressed)[ ((yBlock * nBlocksWidth) + xBlock) * nBytesPerBlock ];
+}
+
+
+char* S3TC_GetBlock(
+ void *pCompressed,
+ ImageFormat format,
+ int nBlocksWidth,
+ int xBlock,
+ int yBlock )
+{
+ return (char*)S3TC_GetBlock( (const void *)pCompressed, format, nBlocksWidth, xBlock, yBlock );
+}
+
+
+void GenerateRepresentativePalette(
+ ImageFormat format,
+ S3RGBA **pOriginals, // Original RGBA colors in the texture. This allows it to avoid doubly compressing.
+ int nBlocks,
+ int lPitch, // (in BYTES)
+ char mergedBlocks[16*MAX_S3TC_BLOCK_BYTES]
+ )
+{
+ Error( "GenerateRepresentativePalette: not implemented" );
+#if 0 // this code was ifdefed out. no idea under what circumstances it was meant to be called.
+
+ Assert( nBlocks == 2 || nBlocks == 3 );
+
+ S3RGBA values[12*4];
+ memset( values, 0xFF, sizeof( values ) );
+ int width = nBlocks * 4;
+ for ( int i=0; i < nBlocks; i++ )
+ {
+ for ( int y=0; y < 4; y++ )
+ {
+ for ( int x=0; x < 4; x++ )
+ {
+ int outIndex = y*width+(i*4+x);
+ values[outIndex] = pOriginals[i][y * (lPitch/4) + x];
+ }
+ }
+ }
+
+ DDSURFACEDESC descIn;
+ DDSURFACEDESC descOut;
+ memset( &descIn, 0, sizeof(descIn) );
+ memset( &descOut, 0, sizeof(descOut) );
+
+ descIn.dwSize = sizeof(descIn);
+ descIn.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_LPSURFACE | DDSD_PIXELFORMAT;
+ descIn.dwWidth = width;
+ descIn.dwHeight = 4;
+ descIn.lPitch = width * 4;
+ descIn.lpSurface = values;
+ descIn.ddpfPixelFormat.dwSize = sizeof( DDPIXELFORMAT );
+
+ descIn.ddpfPixelFormat.dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
+ descIn.ddpfPixelFormat.dwRGBBitCount = 32;
+ descIn.ddpfPixelFormat.dwRBitMask = 0xff0000;
+ descIn.ddpfPixelFormat.dwGBitMask = 0x00ff00;
+ descIn.ddpfPixelFormat.dwBBitMask = 0x0000ff;
+ descIn.ddpfPixelFormat.dwRGBAlphaBitMask = 0xff000000;
+
+ descOut.dwSize = sizeof( descOut );
+
+ float weight[3] = {0.3086f, 0.6094f, 0.0820f};
+
+ S3TC_BLOCK_WIDTH = nBlocks * 4;
+
+ DWORD encodeFlags = S3TC_ENCODE_RGB_FULL;
+ if ( format == IMAGE_FORMAT_DXT5 )
+ encodeFlags |= S3TC_ENCODE_ALPHA_INTERPOLATED;
+
+ S3TCencode( &descIn, NULL, &descOut, mergedBlocks, encodeFlags, weight );
+
+ S3TC_BLOCK_WIDTH = 4;
+#endif
+}
+
+void S3TC_MergeBlocks(
+ char **blocks,
+ S3RGBA **pOriginals, // Original RGBA colors in the texture. This allows it to avoid doubly compressing.
+ int nBlocks,
+ int lPitch, // (in BYTES)
+ ImageFormat format
+ )
+{
+ // Figure out a good palette to represent all of these blocks.
+ char mergedBlocks[16*MAX_S3TC_BLOCK_BYTES];
+ GenerateRepresentativePalette( format, pOriginals, nBlocks, lPitch, mergedBlocks );
+
+ // Build a remap table to remap block 2's colors to block 1's colors.
+ if ( format == IMAGE_FORMAT_DXT1 )
+ {
+ // Grab the palette indices that s3tc.lib made for us.
+ const char *pBase = (const char*)mergedBlocks;
+ pBase += 4;
+
+ for ( int iBlock=0; iBlock < nBlocks; iBlock++ )
+ {
+ S3TCBlock_DXT1 *pBlock = ((S3TCBlock_DXT1*)blocks[iBlock]);
+
+ // Remap all of the block's pixels.
+ for ( int x=0; x < 4; x++ )
+ {
+ for ( int y=0; y < 4; y++ )
+ {
+ int iBaseBit = (y*nBlocks*4 + x + iBlock*4) * 2;
+
+ S3PaletteIndex index = {0, 0};
+ index.m_ColorIndex = ReadBitInt( pBase, iBaseBit, 2 );
+
+ S3TC_SetPixelPaletteIndex( format, (char*)pBlock, x, y, index );
+ }
+ }
+
+ // Copy block 1's palette to block 2.
+ pBlock->m_Ref1 = ((S3TCBlock_DXT1*)mergedBlocks)->m_Ref1;
+ pBlock->m_Ref2 = ((S3TCBlock_DXT1*)mergedBlocks)->m_Ref2;
+ }
+ }
+ else
+ {
+ Assert( format == IMAGE_FORMAT_DXT5 );
+
+ // Skip past the alpha palette.
+ const char *pAlphaPalette = mergedBlocks;
+ const char *pAlphaBits = mergedBlocks + 2;
+
+ // Skip past the alpha pixel bits and past the color palette.
+ const char *pColorPalette = pAlphaBits + 6*nBlocks;
+ const char *pColorBits = pColorPalette + 4;
+
+ for ( int iBlock=0; iBlock < nBlocks; iBlock++ )
+ {
+ S3TCBlock_DXT5 *pBlock = ((S3TCBlock_DXT5*)blocks[iBlock]);
+
+ // Remap all of the block's pixels.
+ for ( int x=0; x < 4; x++ )
+ {
+ for ( int y=0; y < 4; y++ )
+ {
+ int iBasePixel = (y*nBlocks*4 + x + iBlock*4);
+
+ S3PaletteIndex index;
+ index.m_ColorIndex = ReadBitInt( pColorBits, iBasePixel * 2, 2 );
+ index.m_AlphaIndex = ReadBitInt( pAlphaBits, iBasePixel * 3, 3 );
+
+ S3TC_SetPixelPaletteIndex( format, (char*)pBlock, x, y, index );
+ }
+ }
+
+ // Copy block 1's palette to block 2.
+ pBlock->m_AlphaRef[0] = pAlphaPalette[0];
+ pBlock->m_AlphaRef[1] = pAlphaPalette[1];
+ pBlock->m_Ref1 = *((unsigned short*)pColorPalette);
+ pBlock->m_Ref2 = *((unsigned short*)(pColorPalette + 2));
+ }
+ }
+}
+
+
+S3PaletteIndex S3TC_GetPaletteIndex(
+ unsigned char *pFaceData,
+ ImageFormat format,
+ int imageWidth,
+ int x,
+ int y )
+{
+ char *pBlock = S3TC_GetBlock( pFaceData, format, imageWidth>>2, x>>2, y>>2 );
+ return S3TC_GetPixelPaletteIndex( format, pBlock, x&3, y&3 );
+}
+
+
+void S3TC_SetPaletteIndex(
+ unsigned char *pFaceData,
+ ImageFormat format,
+ int imageWidth,
+ int x,
+ int y,
+ S3PaletteIndex paletteIndex )
+{
+ char *pBlock = S3TC_GetBlock( pFaceData, format, imageWidth>>2, x>>2, y>>2 );
+ S3TC_SetPixelPaletteIndex( format, pBlock, x&3, y&3, paletteIndex );
+}
+
+
+
+