DXT5 DXT1 D3DFMT_A8R8G8B8 转换

// Author: FreeKnightDuzhi

// http://hi.baidu.com/freedomknightduzhi

#include "stdafx.h"

// 线形渐进次数
int    g_nLinePerPitch[ETF_Count] = { 4,      4,     1,
1,      1,     1 };
// 平均每象素单次占用位数表
// (DXT压缩时会将4*4的16位RGB纹理256字节压缩为2个16位R5G6B5值和16个2位索引。)
int    g_nPerPixelBit[ETF_Count] = { 4,      8,     24,
32,      16,     16 };
// 实际上平均每象素占用的内存字节数表
// 补:实际内存字节数 = (单象素占用位数 * 渐进次数) / 8
int    g_nPerPixelSpace[ETF_Count] = { 2,      4,     3,
4,      2,     2 };
// 数据格式类型表
D3DFORMAT g_eDataFormat[ETF_Count] = { D3DFMT_DXT1,   D3DFMT_DXT5, D3DFMT_R8G8B8,
D3DFMT_A8R8G8B8, D3DFMT_R5G6B5, D3DFMT_A4R4G4B4 };
// 实际保存的格式类型
D3DFORMAT g_eSaveFormat[ETF_Count] = { D3DFMT_DXT1,   D3DFMT_DXT5, D3DFMT_X8R8G8B8,
D3DFMT_A8R8G8B8, D3DFMT_R5G6B5, D3DFMT_A4R4G4B4 };

//-------------------------------------------------------------------

CTexture::CTexture()
: m_pTextures ( NULL )
, m_pD3DDev   ( NULL )
{
m_tagHead = TAG_FKTHeadInfo();
m_szTextureName = string("");
}

//-------------------------------------------------------------------

CTexture::~CTexture()
{
Release();
}

//-------------------------------------------------------------------

// 释放本贴图    
void CTexture::Release()
{
if ( m_pTextures != NULL)
{
   // 释放所有桢
   for ( unsigned int i = 0; i < m_tagHead.unFrameCount ; ++i )
   {
    if ( m_pTextures[i] )
    {
     m_pTextures[i]->Release();
     m_pTextures[i] = NULL;
    }
   }
   delete [] m_pTextures;
}

m_tagHead    = TAG_FKTHeadInfo();
m_szTextureName   = string("");
m_pTextures    = NULL;
m_pD3DDev    = NULL;
}

//-------------------------------------------------------------------

// 载入指定图片
bool CTexture::LoadTexture( LPDIRECT3DDEVICE9 pD3DDev, LPCTSTR szTextureName )
{
// 希望名称合法
assert( szTextureName != NULL );
assert( strlen( szTextureName ) >= 4 );

// 取文件尾四位后缀
LPCTSTR szExt = szTextureName + strlen( szTextureName ) - 4;

if ( _stricmp(".fkt", szExt) )
{
   return _LoadNormalTexture( pD3DDev, szTextureName );
}
else
{
   return _LoadFKTexture( pD3DDev, szTextureName );
}
}

//-------------------------------------------------------------------

// 载入普通图片
bool CTexture::_LoadNormalTexture( LPDIRECT3DDEVICE9 pD3DDev, LPCTSTR szTextureName )
{
LPDIRECT3DTEXTURE9 pTempTexture;

// 使用D3DX库载入
if ( FAILED( D3DXCreateTextureFromFile( pD3DDev, szTextureName, &pTempTexture )))
{
   return false;
}

// 获取文件信息
D3DSURFACE_DESC tagDesc;
pTempTexture->GetLevelDesc( 0 , &tagDesc );
if ( pTempTexture )
{
   pTempTexture->Release();
   pTempTexture = NULL;
}

// 设置新图片的格式信息
TAG_FKTHeadInfo tagTempHeadInfo;
memset( &tagTempHeadInfo, 0, sizeof(TAG_FKTHeadInfo));
// 将原图大小设置为2的次方大小
for ( tagTempHeadInfo.unWidth = 1; tagTempHeadInfo.unWidth < tagDesc.Width ; )
{
   tagTempHeadInfo.unWidth *= 2;
}
for ( tagTempHeadInfo.unHeight = 1; tagTempHeadInfo.unHeight < tagDesc.Height ; )
{
   tagTempHeadInfo.unHeight *= 2;
}
tagTempHeadInfo.eTextureFormat = ETF_A8R8G8B8;
tagTempHeadInfo.unFrameCount = 1;

// 创建新图(该图大小为2的次方,格式为D3DFMT_A8R8G8B8)
if ( FAILED(D3DXCreateTextureFromFileEx( pD3DDev, szTextureName,
   tagTempHeadInfo.unWidth, tagTempHeadInfo.unHeight, 0, 0, D3DFMT_A8R8G8B8,
   D3DPOOL_MANAGED, D3DX_FILTER_NONE, D3DX_FILTER_NONE, 0, NULL, NULL, &pTempTexture)) )
{
   return false;
}
// 纹理过滤一下
if ( FAILED( D3DXFilterTexture( pTempTexture, NULL, 0, D3DX_FILTER_TRIANGLE )))
{
   return false;
}

// 重新保存信息
pTempTexture->GetLevelDesc( 0 , &tagDesc );
// 做最后一次成功判断,确保创建无误
if (( tagDesc.Format != D3DFMT_A8R8G8B8 ) || ( tagDesc.Width != tagTempHeadInfo.unWidth )
   || ( tagDesc.Height != tagTempHeadInfo.unHeight ))
{
   if ( pTempTexture )
   {
    pTempTexture->Release();
    pTempTexture = NULL;
   }
   return false;
}

// OK,先清空自身其他信息再保存,完成
Release();

m_szTextureName   = szTextureName;
m_pD3DDev    = pD3DDev;
m_tagHead    = tagTempHeadInfo;
m_pTextures    = new LPDIRECT3DTEXTURE9[1];
m_pTextures[0]   = pTempTexture;

return true;
}

//-------------------------------------------------------------------

// 载入FKT图片
bool CTexture::_LoadFKTexture( LPDIRECT3DDEVICE9 pD3DDev, LPCTSTR szTextureName )
{
// 清空自身数据
Release();

m_pD3DDev   = pD3DDev;
m_szTextureName = szTextureName;

// 读入文件头
ifstream FileStream( szTextureName, ios::binary | ios::in );
unsigned long ulRes;
unsigned long ulVersion;
FileStream.read( (char*)&ulRes, sizeof(unsigned long) );
FileStream.read( (char*)&ulVersion, sizeof(unsigned long) );

// 若信息不合法
if (( ulRes != MAKEFOURCC('F', 'K', 'T', 0) ) || ( ulVersion > TEXTURE_VERSION ))
{
   return false;
}

if ( ulVersion < TEXTURE_VERSION )
{
   // TODO: 若版本比当前版本低,则在这里进行进一步处理
}

// 读取图象头信息
FileStream.read( (char*)&m_tagHead, sizeof(TAG_FKTHeadInfo) );

unsigned int unTextureSpace   = m_tagHead.unWidth * g_nPerPixelSpace[m_tagHead.eTextureFormat];
unsigned int unPerPixelBit   = g_nPerPixelBit[m_tagHead.eTextureFormat];
D3DFORMAT eFormat     = g_eDataFormat[m_tagHead.eTextureFormat];

// 将FKT格式每桢转换为D3DFMT_A8R8G8B8格式进行读入
m_pTextures = new LPDIRECT3DTEXTURE9[m_tagHead.unFrameCount];

// 逐桢循环
for ( unsigned int i = 0; i < m_tagHead.unFrameCount ; ++i )
{
   // 创建D3DFMT_A8R8G8B8
   if ( D3D_OK != D3DXCreateTexture( pD3DDev, m_tagHead.unWidth, m_tagHead.unHeight,
    1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &m_pTextures[i]) )
   {
    FileStream.close();
    Release();
    return false;
   }
   // 获取转换后的图片信息
   D3DSURFACE_DESC tagTempDesc;
   m_pTextures[i]->GetLevelDesc( 0 , &tagTempDesc );

   // 求得本图片本桢最大的一个MipMap图所需的内存大小
   unsigned int unSize = (m_tagHead.unWidth * m_tagHead.unHeight * g_nPerPixelBit[m_tagHead.eTextureFormat]) / 8;
   // 求得本图片本桢所有的MipMap图所需的内存大小
   unsigned int unWholeSize = 0;
   for ( unsigned int j = 0; j < m_tagHead.unMipMapLevel ; unSize >> 2, ++j )
   {
    unWholeSize += unSize;
   }

   // 分配足够空间并将数据填充内存
   unsigned char* pBuf = new unsigned char[unWholeSize];
   FileStream.read((char*)pBuf, unWholeSize);

   // 从内存中载入图片数据
   LPDIRECT3DSURFACE9 pTempSur;
   m_pTextures[i]->GetSurfaceLevel( 0, &pTempSur );
   RECT tagRect = { 0, 0, m_tagHead.unWidth, m_tagHead.unHeight };

   if ( FAILED( D3DXLoadSurfaceFromMemory( pTempSur, NULL, NULL, pBuf, eFormat,
    unTextureSpace, NULL, &tagRect, D3DX_FILTER_NONE, 0)))
   {
    if ( pTempSur )
    {
     pTempSur->Release();
     pTempSur = NULL;
    }
    FileStream.close();
    Release();
    return false;
   }
   // 纹理过滤一下
   if ( FAILED( D3DXFilterTexture(m_pTextures[i], NULL, 0, D3DX_FILTER_TRIANGLE ) ) )
   {
    return false;
   }
   // 释放内存
   delete []pBuf;
}
FileStream.close();
return true;
}

//-------------------------------------------------------------------

// 为本图片加入新的桢
bool CTexture::AddFrame( LPCTSTR szFrameFileName )
{
// 读入图片并标准化
CTexture tagTempDestTexture;
if ( FAILED (tagTempDestTexture.LoadTexture(m_pD3DDev, szFrameFileName) ) )
{
   return false;
}
// 强制要求插入新桢的大小需要和原图大小一致
if (( tagTempDestTexture.m_tagHead.unWidth != m_tagHead.unWidth ) ||
   ( tagTempDestTexture.m_tagHead.unWidth != m_tagHead.unWidth ))
{
   return false;
}
// 增加桢计数,分配新内存空间( 这里要考虑到原图和新加桢图都可能是多桢图的可能 )
m_tagHead.unFrameCount++;
LPDIRECT3DTEXTURE9 * pTempTextures = new LPDIRECT3DTEXTURE9
     [ m_tagHead.unFrameCount + tagTempDestTexture.m_tagHead.unFrameCount ];
// 拷贝原图指针
unsigned int i = 0;
for ( i = 0; i < m_tagHead.unFrameCount ; ++i )
{
   pTempTextures[i] = m_pTextures[i];
}
// 拷贝新图指针( 这里i不要清0,因为我们需要保存pTempTextures[i]指针 )
for ( ; i < m_tagHead.unFrameCount + tagTempDestTexture.m_tagHead.unFrameCount ; ++i )
{
   pTempTextures[i] = tagTempDestTexture.m_pTextures[ i - m_tagHead.unFrameCount ];
   pTempTextures[i]->AddRef();
}
// 保存新指针
delete [] m_pTextures;
m_pTextures = pTempTextures;

return true;
}

//-------------------------------------------------------------------

// 保存图片
bool CTexture::SaveTexture( ENUM_SaveTextureFormat eSaveTextureFormat, LPCTSTR szSaveTextureName, LPDIRECT3DDEVICE9 pD3DDev,
         ENUM_TextureFormat eFormat, unsigned int unMipMap, unsigned int unFrameCircle )
{
if ( szSaveTextureName == NULL )
{
   return false;
}
if ( eSaveTextureFormat == ESTF_TGA )
{
   return _SaveTextureAsTGA( szSaveTextureName );
}
if ( eSaveTextureFormat == ESTF_FKTexture )
{
   return _SaveTextureAsFKT ( szSaveTextureName, eFormat, unMipMap, unFrameCircle, pD3DDev );
}
return false;
}

//-------------------------------------------------------------------

// 将图片保存为tga格式
bool CTexture::_SaveTextureAsTGA( LPCTSTR szSaveTextureName )
{
// 声明TGA文件头和文件类型
TAG_TGAHeadInfo tagTGAHeadInfo = { 0, 0, 2, 0, 0, 32, 0, 0, m_tagHead.unWidth, m_tagHead.unHeight, 32, 32 };
SetFileAttributes( szSaveTextureName, FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_ARCHIVE );

// 若有多桢,需逐桢处理
for ( unsigned int i = 0; i < m_tagHead.unFrameCount ; ++i )
{
   // 去后缀
   CString szRealSaveTextureName = szSaveTextureName;
   for (int j = 0; j < szRealSaveTextureName.GetLength(); ++j )
   {
    if ( szRealSaveTextureName[j] == '.' )
    {
     szRealSaveTextureName.Delete( j, szRealSaveTextureName.GetLength() );
     break;
    }
   }
   // 若多桢,则需在文件名尾加以编号
   if ( m_tagHead.unFrameCount > 1 )
   {
    char szBuf[256];
    sprintf( szBuf, "_%d", i );
    szRealSaveTextureName += szBuf;
   }
   // 重加后缀
   szRealSaveTextureName += ".tga";

   // 写入文件头
   ofstream File( szRealSaveTextureName, ios::binary | ios::out );
   unsigned long ulRes = MAKEFOURCC( 'F', 'K', 'T', 0 );
   unsigned long ulVersion = TEXTURE_VERSION;
   File.write( (char*)&tagTGAHeadInfo, sizeof(TAG_TGAHeadInfo) );

   // 保存图片数据
   D3DLOCKED_RECT tagRect;
   m_pTextures[i]->LockRect( 0, &tagRect, NULL, 0 );
   File.write( (char*)tagRect.pBits, m_tagHead.unWidth * m_tagHead.unHeight * 4 );
   m_pTextures[i]->UnlockRect(0);
}

return true;
}

//-------------------------------------------------------------------

// 将图片保存为fkt格式
bool CTexture::_SaveTextureAsFKT( LPCTSTR szSaveTextureName, ENUM_TextureFormat eFormat,
          unsigned int unMipMap, unsigned int unFrameCircle, LPDIRECT3DDEVICE9 pD3DDev)
{
// 声明文件类型
SetFileAttributes( szSaveTextureName, FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_ARCHIVE );
// 声明FKTexture格式头
TAG_FKTHeadInfo tagSaveHead;
tagSaveHead = m_tagHead;
if ( ETF_Unknown == eFormat )
{
   eFormat = GetTextureFormat();
}
tagSaveHead.eTextureFormat = eFormat;
tagSaveHead.unMipMapLevel = unMipMap;
tagSaveHead.unFrameCircle = unFrameCircle > 65535 ? 65535 : unFrameCircle;

// 若希望进行DXT压缩,强制要求图象大小要大于4 * 4象素
if (( eFormat == ETF_DXT1) || ( eFormat == ETF_DXT5 ))
{
   if (( m_tagHead.unWidth < 4 ) || ( m_tagHead.unHeight < 4 ))
   {
    return false;
   }
}
// 若未指定MipMap层级,则自行计算
if ( tagSaveHead.unMipMapLevel == 0 )
{
   for ( unsigned int unWidth = tagSaveHead.unWidth,unHeight = tagSaveHead.unHeight;
    (unWidth >= 4) && (unHeight >= 4) ;
    unWidth = unWidth >> 1, unHeight = unHeight >> 1 )
   {
    tagSaveHead.unMipMapLevel++;
   }
}

// 创建DXT格式贴图
int nPerPixelBit = g_nPerPixelBit[tagSaveHead.eTextureFormat];
LPDIRECT3DTEXTURE9 pCompressTexture = NULL;
if ( FAILED( D3DXCreateTexture( pD3DDev, tagSaveHead.unWidth, tagSaveHead.unHeight, 0, 0,
   g_eDataFormat[tagSaveHead.eTextureFormat], D3DPOOL_MANAGED, &pCompressTexture) ) )
{
   return false;
}

// 填充描述字符格式
D3DSURFACE_DESC tagDesc;
pCompressTexture->GetLevelDesc( 0, &tagDesc );

// 保存文件头
ofstream File( szSaveTextureName, ios::binary | ios::out );
unsigned int unRes = MAKEFOURCC( 'F', 'K', 'T', 0 );
unsigned int unVersion = TEXTURE_VERSION;
File.write( (char*)&unRes, sizeof(unsigned int) );
File.write( (char*)&unVersion, sizeof(unsigned int) );
File.write( (char*)&tagSaveHead, sizeof(TAG_FKTHeadInfo) );

// 逐桢写入文件数据
for ( unsigned int i = 0; i < m_tagHead.unFrameCount; ++i )
{
   D3DLOCKED_RECT tagRect;
   m_pTextures[i]->LockRect( 0, &tagRect, NULL, 0 );
   char* pcBuf = (char*) tagRect.pBits;

   IDirect3DSurface9* pSurface;
   pCompressTexture->GetSurfaceLevel( 0, &pSurface );
   RECT tagTempRect = { 0, 0, tagSaveHead.unWidth, tagSaveHead.unHeight };

   // 将内存中的图片数据载入
   if ( FAILED( D3DXLoadSurfaceFromMemory( pSurface, NULL, NULL, pcBuf, D3DFMT_A8R8G8B8,
    tagRect.Pitch, NULL, &tagTempRect, D3DX_FILTER_NONE, 0 ) ) )
   {
    if (pSurface != NULL)
    {
     pSurface->Release();
     pSurface = NULL;
    }
    if (pCompressTexture != NULL)
    {
     pCompressTexture->Release();
     pCompressTexture = NULL;
    }
    File.close();
    return false;
   }
   // 不再使用Surface释放.
   if (pSurface != NULL)
   {
    pSurface->Release();
    pSurface = NULL;
   }

   // 检查并压缩
   pCompressTexture->LockRect( 0, &tagRect, NULL, 0 );
   _CheckCompress( (unsigned char*)tagRect.pBits, g_eDataFormat[tagSaveHead.eTextureFormat],
    (unsigned char*)pcBuf, D3DFMT_A8R8G8B8, tagSaveHead.unWidth, tagSaveHead.unHeight );
   pCompressTexture->UnlockRect( 0 );

   m_pTextures[i]->UnlockRect( 0 );

   // 纹理过滤
   if ( FAILED( D3DXFilterTexture( pCompressTexture, NULL, 0, D3DX_FILTER_TRIANGLE ) ) )
   {
    return false;
   }

   // 创建每一桢的MIPMAP
   for (unsigned int unWidth = tagSaveHead.unWidth, unHeight = tagSaveHead.unHeight, i = 0;
    i < tagSaveHead.unMipMapLevel;
    unWidth = unWidth >> 1, unHeight = unHeight >> 1, ++i)
   {
    unsigned int unSize = unWidth * g_nPerPixelSpace[tagSaveHead.eTextureFormat];
    pCompressTexture->LockRect( i, &tagRect, NULL, 0 );
    // 根据格式去保存文件
    if ( tagSaveHead.eTextureFormat == ETF_R8G8B8 )
    {
     unsigned int * pBuf = (unsigned int *)tagRect.pBits;
     for (unsigned int n = 0 ; n < unHeight; ++n, pBuf += (tagRect.Pitch / 4))
     {
      for (unsigned int m = 0; m < unWidth; ++m)
      {
       File.write( (char*)&pBuf[m], 3 );
      }
     }
    }
    else
    {
     char* pBuf = (char*)tagRect.pBits;
     for (unsigned int n = 0; n < unHeight; n += g_nLinePerPitch[tagSaveHead.eTextureFormat], pBuf += tagRect.Pitch )
     {
      File.write( pBuf, unSize );
     }
    }
    pCompressTexture->UnlockRect( i );
   }
}

File.close();
pCompressTexture->Release();

return true;
}

//-------------------------------------------------------------------

// 将图片进行检查压缩
void CTexture::_CheckCompress(unsigned char* pcDestBuf, D3DFORMAT eDestFormat,
     unsigned char* pcSrcBuf, D3DFORMAT eSrcFormat, unsigned int unWidth, unsigned int unHeight )
{
if (( eSrcFormat == D3DFMT_A8R8G8B8 ) && (( eDestFormat == D3DFMT_DXT4) || ( eDestFormat == D3DFMT_DXT5 )))
{
   unsigned long * pTempSrcBuf = (unsigned long *)pcSrcBuf;
   unsigned char * pTempDestBuf = pcDestBuf;
   unsigned long ulTempVector[16];
   unsigned int i = 0;
   unsigned int j = 0;
   unsigned int n = 0;
   unsigned int m = 0;
   int nSpace = ( eDestFormat == D3DFMT_DXT1 ) ? 2 : 4;
   int nSize = nSpace * 4;
   // DXT格式是以 4 * 4 象素做为一个单元的,我们逐单元块处理
   for ( i = 0; i < unHeight / 4; ++i )
   {
    for ( j = 0; j < unWidth / 4; ++j )
    {
     for ( m = 0; m < 4; ++m )
     {
      for ( n = 0; n < 4; ++n )
      {
       ulTempVector[ m * 4 + n ] = pTempSrcBuf[ ( i * 4 + m ) * unWidth + j * 4 + n ];
      }
     }
     _CheckARGB2DXT( pTempDestBuf, ulTempVector, eSrcFormat );
     pTempDestBuf += nSize;
    }
   }
}
}

//-------------------------------------------------------------------

// 单位区域重复压缩( 修正压缩时Alpha错误 )
void CTexture::_CheckARGB2DXT(unsigned char* pcCompressBuf, unsigned long* pNoCompressBuf, D3DFORMAT eFormat)
{
unsigned char ucAlpha[8];
unsigned char ucCompress[16];
unsigned char ucNoCompress[16];

for (unsigned int i = 0; i < 16; ++i)
{
   ucNoCompress[i] = (unsigned char)(pNoCompressBuf[i] >> 24);
}

// 首先解压缩统计偏差
ucAlpha[0] = pcCompressBuf[0];
ucAlpha[1] = pcCompressBuf[1];
if ( ucAlpha[0] > ucAlpha[1] )
{
   ucAlpha[2] = ( 6 * ucAlpha[0] + 1 * ucAlpha[1] + 3 ) / 7; // 010
   ucAlpha[3] = ( 5 * ucAlpha[0] + 2 * ucAlpha[1] + 3 ) / 7; // 011
   ucAlpha[4] = ( 4 * ucAlpha[0] + 3 * ucAlpha[1] + 3 ) / 7; // 100
   ucAlpha[5] = ( 3 * ucAlpha[0] + 4 * ucAlpha[1] + 3 ) / 7; // 101
   ucAlpha[6] = ( 2 * ucAlpha[0] + 5 * ucAlpha[1] + 3 ) / 7; // 110
   ucAlpha[7] = ( 1 * ucAlpha[0] + 6 * ucAlpha[1] + 3 ) / 7; // 111
}
else
{
   ucAlpha[2] = ( 4 * ucAlpha[0] + 1 * ucAlpha[1] + 2 ) / 5; // 010
   ucAlpha[3] = ( 3 * ucAlpha[0] + 2 * ucAlpha[1] + 2 ) / 5; // 011
   ucAlpha[4] = ( 2 * ucAlpha[0] + 3 * ucAlpha[1] + 2 ) / 5; // 100
   ucAlpha[5] = ( 1 * ucAlpha[0] + 4 * ucAlpha[1] + 2 ) / 5; // 101
   ucAlpha[6] = 0;             // 110
   ucAlpha[7] = 255;            // 111
}

for (unsigned int i = 0, j = 0; i < 16; ++i )
{
   int nTemp1 = j / 8;
   int nTemp2 = j % 8;
   unsigned char ucTemp;
   if ( nTemp2 < 6 )
   {
    ucTemp = ( (pcCompressBuf[ 2 + nTemp1 ]) >> nTemp2 ) & 0x7 ;
   }
   else if ( nTemp2 == 6 )
   {
    ucTemp = ( ( (pcCompressBuf[ 2 + nTemp1 ]) >> nTemp2 ) & 0x7 ) |
     ( ( (pcCompressBuf[ 3 + nTemp1 ]) >> 2 ) & 0x7 ) ;
   }
   else if ( nTemp2 == 7 )
   {
    ucTemp = ( ( (pcCompressBuf[ 2 + nTemp1 ]) >> nTemp2 ) & 0x7 ) |
     ( ( (pcCompressBuf[ 3 + nTemp1 ]) >> 1 ) & 0x7 ) ;
   }

   ucCompress[i] = ucAlpha[ucTemp];
   j += 3;
}

// 获取偏差
int nWarp = 0;
for ( unsigned int i = 0; i < 16; ++i )
{
   nWarp += abs( ucCompress[i] - ucNoCompress[i] );
}

// 若偏差很小,则不再处理,否则则重新压缩
if ( nWarp <= 256 )
{
   return;
}

ucAlpha[0] = ucNoCompress[0];
ucAlpha[1] = ucNoCompress[1];
// 选出Alpha最大的两个值
for (unsigned int i = 0; i < 16; ++i )
{
   if ( ucNoCompress[i] > ucAlpha[0] )
   {
    ucAlpha[0] = ucNoCompress[i];
   }
   if ( ucNoCompress[i] < ucAlpha[1] )
   {
    ucAlpha[1] = ucNoCompress[i];
   }
}

pcCompressBuf[0] = ucAlpha[0];
pcCompressBuf[1] = ucAlpha[1];
pcCompressBuf[2] = 0;
pcCompressBuf[3] = 0;
pcCompressBuf[4] = 0;
pcCompressBuf[5] = 0;
pcCompressBuf[6] = 0;
pcCompressBuf[7] = 0;

// 线形插值出其他六个Alpha值
if ( ucAlpha[0] > ucAlpha[1] )
{
   ucAlpha[2] = ( 6 * ucAlpha[0] + 1 * ucAlpha[1] + 3 ) / 7; // 010
   ucAlpha[3] = ( 5 * ucAlpha[0] + 2 * ucAlpha[1] + 3 ) / 7; // 011
   ucAlpha[4] = ( 4 * ucAlpha[0] + 3 * ucAlpha[1] + 3 ) / 7; // 100
   ucAlpha[5] = ( 3 * ucAlpha[0] + 4 * ucAlpha[1] + 3 ) / 7; // 101
   ucAlpha[6] = ( 2 * ucAlpha[0] + 5 * ucAlpha[1] + 3 ) / 7; // 110
   ucAlpha[7] = ( 1 * ucAlpha[0] + 6 * ucAlpha[1] + 3 ) / 7; // 111
}
else
{
   ucAlpha[2] = ( 4 * ucAlpha[0] + 1 * ucAlpha[1] + 2 ) / 5; // 010
   ucAlpha[3] = ( 3 * ucAlpha[0] + 2 * ucAlpha[1] + 2 ) / 5; // 011
   ucAlpha[4] = ( 2 * ucAlpha[0] + 3 * ucAlpha[1] + 2 ) / 5; // 100
   ucAlpha[5] = ( 1 * ucAlpha[0] + 4 * ucAlpha[1] + 2 ) / 5; // 101
   ucAlpha[6] = 0;             // 110
   ucAlpha[7] = 255;            // 111
}

// 为 4 * 4 个点选择合适的Alpha值,并将索引重新写入
for ( unsigned int i = 0, j = 0; i < 16; ++i )
{
   int nTemp1 = j / 8;
   int nTemp2 = j % 8;
   int nAlin = 0;
   int nMax = 255;

   for ( unsigned int k = 0; k < 8; ++k )
   {
    if ( abs( ucAlpha[k] - ucNoCompress[i] ) < nMax )
    {
     nMax = abs( ucAlpha[k] - ucNoCompress[i] );
     nAlin = k;
    }
   }

   pcCompressBuf[ 2 + nTemp1 ] |= nAlin << nTemp2;
   if ( nTemp2 == 6 )
   {
    pcCompressBuf[ 3 + nTemp1 ] |= nAlin >> 2;
   }
   else if ( nTemp2 == 7)
   {
    pcCompressBuf[ 3 + nTemp1 ] |= nAlin >> 1;
   }

   j += 3;

}
}

//-------------------------------------------------------------------

// 获取当前贴图指针
LPDIRECT3DTEXTURE9 CTexture::GetTexture() const
{
if ( m_tagHead.unFrameCount > 1 )
{
   return m_pTextures[ (GetTickCount() / max( m_tagHead.unFrameCircle, 1)) % m_tagHead.unFrameCount ];
}
else
{
   return m_pTextures ? m_pTextures[0] : NULL;
}
}

//-------------------------------------------------------------------

CTexture.h

//-------------------------------------------------------------------

#pragma once


// 定义组合4CC宏
#ifndef MAKEFOURCC
#define MAKEFOURCC (ch0, ch1, ch2, ch3)      \
   (((unsigned long)(unsigned char)(ch0)) |   \
   ((unsigned long)(unsigned char)(ch1) << 8) | \
   ((unsigned long)(unsigned char)(ch2) << 16) | \
   ((unsigned long)(unsigned char)(ch3) << 24)))
#endif


// 枚举可识别的纹理图片格式(注意,这里的枚举值需与下面全局常量组对应起来)
enum ENUM_TextureFormat
{
ETF_Unknown   = -1,

ETF_DXT1   = 0,
ETF_DXT5,
ETF_R8G8B8,
ETF_A8R8G8B8,
ETF_R5G6B5,
ETF_A4R4G4B4,

ETF_Count,
};

// 枚举可保存的纹理图片格式
enum ENUM_SaveTextureFormat
{
ESTF_TGA   = 0x0010,
ESTF_FKTexture = 0x0100,
};

// 定义当前贴图版本(该版本向下兼容)
const unsigned int TEXTURE_VERSION = 10000;


#pragma pack(push,1)    
// FKT贴图头结构信息
struct TAG_FKTHeadInfo
{
   ENUM_TextureFormat eTextureFormat; // 贴图文件格式
   unsigned int   unWidth;   // 贴图宽
   unsigned int   unHeight;   // 贴图高
   unsigned int   unMipMapLevel; // MipMap层数
   unsigned int   unFrameCount; // 贴图桢数
   unsigned int   unFrameCircle; // 贴图桢周期
};

// TGA贴图头结构信息
struct TAG_TGAHeadInfo
{
   unsigned char   ucImageInfoBlockSize; // 图象信息大小
   unsigned char   ucTableType;    // 颜色表类型
   unsigned char   ucImageType;    // 图象类型
   unsigned short   usTableAddress;    // 颜色表首地址
   unsigned short   usTableLength;    // 颜色表长度
   unsigned char   ucTableBitSize;    // 颜色表表项位数
   unsigned short   usStartX;     // 图象X坐标起始位置
   unsigned short   usStartY;     // 图象Y坐标起始位置
   unsigned short   usWidth;     // 图象宽度
   unsigned short   usHeight;     // 图象高度
   unsigned char   ucPixelBitSize;    // 图象中每象素所占用的位数
   unsigned char   ucImageScript;    // 图象描述符字节
};
#pragma pack(pop)

// 贴图类
class CTexture
{
public:
CTexture();
~CTexture();

public:
// 释放本贴图
void Release();
// 载入指定图片
bool LoadTexture( LPDIRECT3DDEVICE9 pD3DDev, LPCTSTR szTextureName );
// 为本图片加入新的桢
bool AddFrame( LPCTSTR szFrameFileName );
// 保存图片
bool SaveTexture( ENUM_SaveTextureFormat eSaveTextureFormat, LPCTSTR szSaveTextureName, LPDIRECT3DDEVICE9 pD3DDev = NULL,
   ENUM_TextureFormat eFormat = ETF_Unknown, unsigned int unMipMap = 0, unsigned int unFrameCircle = 0);
public:
// 是否有数据
bool IsValid()         const
{ return m_pTextures != NULL ; }
// 获取图片宽度
unsigned int GetWidth()       const
{ return m_tagHead.unWidth; }
// 获取图片高度
unsigned int GetHeight()      const
{ return m_tagHead.unHeight; }
// 获取图片格式
ENUM_TextureFormat GetFormat()     const
{ return m_tagHead.eTextureFormat; }
// 获取贴图文件类型
ENUM_TextureFormat GetTextureFormat()   const
{ return m_tagHead.eTextureFormat; }
// 获取文件名称
const std::string GetName()      const
{ return m_szTextureName; }
// 获取图片MipMap数量
unsigned int GetMipMapLevel()     const
{ return m_tagHead.unMipMapLevel; }
// 获取图片桢数
unsigned int GetFrameCount()     const
{ return m_tagHead.unFrameCount; }
// 获取图片桢周期
unsigned int GetFrameCircle()     const
{ return m_tagHead.unFrameCircle; }
// 获取当前贴图指针
LPDIRECT3DTEXTURE9 GetTexture()     const;
private:
// 载入普通图片
bool _LoadNormalTexture( LPDIRECT3DDEVICE9 pD3DDev, LPCTSTR szTextureName );
// 载入FKT图片
bool _LoadFKTexture( LPDIRECT3DDEVICE9 pD3DDev, LPCTSTR szTextureName );
// 将图片保存为tga格式
bool _SaveTextureAsTGA( LPCTSTR szSaveTextureName );
// 将图片保存为fkt格式
bool _SaveTextureAsFKT( LPCTSTR szSaveTextureName, ENUM_TextureFormat eFormat,
   unsigned int unMipMap, unsigned int unFrameCircle, LPDIRECT3DDEVICE9 pD3DDev );
// 将图片进行检查压缩
// param pcDestBuf 目标压缩缓冲区
// param eDestFormat 目标压缩缓冲区格式
// param pcSrcBuf 未压缩源缓冲区
// param eSrcFormat 未压缩源缓冲区格式
// param unWidth 需压缩图片宽
// param unHeight 需压缩图片高
void _CheckCompress(unsigned char* pcDestBuf, D3DFORMAT eDestFormat,
   unsigned char* pcSrcBuf, D3DFORMAT eSrcFormat, unsigned int unWidth, unsigned int unHeight );
// 单位区域压缩
// param pcCompressBuf 压缩缓冲区
// param pNoCompressBuf 未压缩缓冲区
// param eFormat 压缩缓冲区格式
inline void _CheckARGB2DXT(unsigned char* pcCompressBuf, unsigned long* pNoCompressBuf, D3DFORMAT eFormat);
private:
TAG_FKTHeadInfo    m_tagHead;          // 文件头
std::string     m_szTextureName;    // 文件名称
LPDIRECT3DTEXTURE9*   m_pTextures;        // 贴图表的指针
LPDIRECT3DDEVICE9   m_pD3DDev;    // D3D环境指针
};

//-------------------------------

#include <windows.h>
#include <iostream>
#include <tchar.h>
#include <d3d9.h>
#include <d3dx9.h>
#include <string>
#include <assert.h>
#include <fstream>
#include <atlstr.h>

#include "CTexture.h"

using namespace std;

#pragma comment(lib, "d3d9.lib")
#pragma comment(lib, "d3dx9.lib")


LPDIRECT3D9             g_pD3D       = NULL; // Used to create the D3DDevice
LPDIRECT3DDEVICE9       g_pd3dDevice = NULL; // Our rendering device

   if( NULL == ( g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )
    return FALSE;
   D3DPRESENT_PARAMETERS d3dpp;
   ZeroMemory( &d3dpp, sizeof(d3dpp) );
   d3dpp.Windowed = TRUE;
   d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
   d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
   if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_REF, hWnd,
    D3DCREATE_SOFTWARE_VERTEXPROCESSING,
    &d3dpp, &g_pd3dDevice ) ) )
   {
    return FALSE;
   }

CTexture pTex;

   pTex.LoadTexture( g_pd3dDevice, "E:\\4.tex" );
   pTex.SaveTexture( ESTF_TGA, "E:\\4.tga" );

//-------------------------------