图片纹理格式转换和压缩代码
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" );
//-------------------------------