Move git root from Client/ to src/ to track all source code: - Client: Game client source (moved to Client/Client/) - Server: Game server source - GameTools: Development tools - CryptoSource: Encryption utilities - database: Database scripts - Script: Game scripts - rylCoder_16.02.2008_src: Legacy coder tools - GMFont, Game: Additional resources 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
565 lines
12 KiB
C++
565 lines
12 KiB
C++
// Z3DTexture.cpp: implementation of the Z3DTexture class.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
#include "Z3DTexture.h"
|
|
#include <stdio.h>
|
|
#include <dds.h>
|
|
|
|
|
|
IDirect3DDevice8* Z3DTexture::ms_pDevice = NULL;
|
|
//char* Z3DTexture::ms_szDataPath = NULL;
|
|
SimpleString Z3DTexture::ms_strDataPath;
|
|
long Z3DTexture::ms_lDetailLevel = 0;
|
|
|
|
long Z3DTexture::ms_lMaxCacheCount;
|
|
long Z3DTexture::ms_lCacheCount;
|
|
Z3DTextureCacheNode* Z3DTexture::ms_pCacheChainHeader;
|
|
|
|
|
|
bool Z3DTexture::_Init( IDirect3DDevice8* pDevice, const char* szPath, long level, long lMaxCacheCount )
|
|
{
|
|
_ASSERT( pDevice );
|
|
ms_pDevice = pDevice;
|
|
|
|
_ASSERT( szPath );
|
|
int l = strlen( szPath );
|
|
if( szPath[l-1] == '\\' || szPath[l-1] == '/' )
|
|
{
|
|
ms_strDataPath( szPath );
|
|
}
|
|
else
|
|
{
|
|
ms_strDataPath( szPath, "/" );
|
|
}
|
|
|
|
ms_lDetailLevel = level;
|
|
|
|
ms_lMaxCacheCount = lMaxCacheCount;
|
|
ms_lCacheCount = 0;
|
|
ms_pCacheChainHeader = NULL;
|
|
|
|
return true;
|
|
}
|
|
|
|
void Z3DTexture::_Close()
|
|
{
|
|
Z3DTextureCacheNode* pChainNode = ms_pCacheChainHeader;
|
|
Z3DTextureCacheNode* pTmp;
|
|
|
|
while( pChainNode )
|
|
{
|
|
pTmp = pChainNode;
|
|
pChainNode = pChainNode->pNext;
|
|
SAFE_RELEASE( pTmp->pTexture );
|
|
SAFE_DELETE( pTmp );
|
|
}
|
|
//SAFE_DELETE( ms_szDataPath );
|
|
}
|
|
|
|
IDirect3DTexture8* Z3DTexture::_GetD3DTextureInterface( long lWidth, long lHeight, long lMipCount, D3DFORMAT fmt )
|
|
{
|
|
IDirect3DTexture8* pTexture = NULL;
|
|
Z3DTextureCacheNode* pChainNode = ms_pCacheChainHeader;
|
|
Z3DTextureCacheNode* pPrevNode = NULL;
|
|
|
|
while( pChainNode )
|
|
{
|
|
if( lWidth == pChainNode->lWidth &&
|
|
lHeight == pChainNode->lHeight &&
|
|
lMipCount == pChainNode->lMipCount &&
|
|
fmt == pChainNode->format )
|
|
{
|
|
pTexture = pChainNode->pTexture;
|
|
|
|
// 삭제될 노드의 앞-뒤 노드간 연결 설정
|
|
if( pPrevNode )
|
|
{
|
|
pPrevNode->pNext = pChainNode->pNext;
|
|
}
|
|
|
|
// 삭제될 노드가 head일경우 head pointer 조정
|
|
if( ms_pCacheChainHeader == pChainNode )
|
|
{
|
|
ms_pCacheChainHeader = pChainNode->pNext;
|
|
}
|
|
|
|
// 노드 삭제
|
|
SAFE_DELETE( pChainNode );
|
|
--ms_lCacheCount;
|
|
|
|
break;
|
|
}
|
|
|
|
pPrevNode = pChainNode;
|
|
pChainNode = pChainNode->pNext;
|
|
}
|
|
|
|
if( pTexture )
|
|
{
|
|
return pTexture;
|
|
}
|
|
|
|
if( FAILED(ms_pDevice->CreateTexture( lWidth, lHeight, lMipCount, 0, fmt, D3DPOOL_MANAGED, &pTexture )) )
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
return pTexture;
|
|
}
|
|
|
|
void Z3DTexture::_ReleaseD3DTextureInterface( IDirect3DTexture8* pTexture )
|
|
{
|
|
if( NULL == pTexture )
|
|
{
|
|
return;
|
|
}
|
|
|
|
|
|
Z3DTextureCacheNode* pNode;
|
|
Z3DTextureCacheNode* pPrev = NULL;
|
|
|
|
// max cache count 가 0이거나 음수이면 캐시 상한선이 없다(무한증식-_-a)
|
|
if( ms_lMaxCacheCount > 0 )
|
|
{
|
|
if( ms_lCacheCount == ms_lMaxCacheCount )
|
|
{
|
|
pNode = ms_pCacheChainHeader;
|
|
|
|
while( pNode->pNext )
|
|
{
|
|
pPrev = pNode;
|
|
pNode = pNode->pNext;
|
|
}
|
|
SAFE_RELEASE( pNode->pTexture );
|
|
SAFE_DELETE( pNode );
|
|
if( pPrev )
|
|
{
|
|
pPrev->pNext = NULL;
|
|
}
|
|
--ms_lCacheCount;
|
|
}
|
|
}
|
|
|
|
pNode = new Z3DTextureCacheNode;
|
|
D3DSURFACE_DESC d3dsd;
|
|
pTexture->GetLevelDesc( 0, &d3dsd );
|
|
pNode->lWidth = d3dsd.Width;
|
|
pNode->lHeight = d3dsd.Height;
|
|
pNode->format = d3dsd.Format;
|
|
pNode->lMipCount = pTexture->GetLevelCount();
|
|
if( 0 == pNode->lMipCount )
|
|
{
|
|
pNode->lMipCount = 1;
|
|
}
|
|
pNode->pTexture = pTexture;
|
|
pNode->pNext = ms_pCacheChainHeader;
|
|
ms_pCacheChainHeader = pNode;
|
|
++ms_lCacheCount;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Construction/Destruction
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
Z3DTexture::~Z3DTexture()
|
|
{
|
|
/*static int cnt = 0;
|
|
static char szFName[50];
|
|
|
|
if( m_pTexture )
|
|
{
|
|
sprintf( szFName, "dump_%d.dds", cnt );
|
|
cnt++;
|
|
Save( szFName );
|
|
}*/
|
|
|
|
|
|
//SAFE_RELEASE( m_pTexture );
|
|
_ReleaseD3DTextureInterface( m_pTexture );
|
|
}
|
|
|
|
bool Z3DTexture::ReadDDSheader( const char* szFileName, DDS_HEADER* pHeader )
|
|
{
|
|
_ASSERT( pHeader );
|
|
FILE* fp = NULL;
|
|
|
|
if( (fp = fopen(szFileName, "rb")) == NULL )
|
|
{
|
|
SimpleString strFileName( ms_strDataPath, szFileName );
|
|
|
|
if( (fp = fopen(strFileName, "rb")) == NULL )
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
fseek(fp, 4, SEEK_SET);
|
|
fread( pHeader, sizeof(DDS_HEADER), 1, fp );
|
|
|
|
fclose(fp);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool Z3DTexture::LoadAllMipSurfaces(LPDIRECT3DBASETEXTURE8 ptex,long numMips, FILE *fp)
|
|
{
|
|
HRESULT hr;
|
|
LPDIRECT3DSURFACE8 psurf;
|
|
D3DSURFACE_DESC sd;
|
|
D3DLOCKED_RECT lr;
|
|
LPDIRECT3DTEXTURE8 pmiptex = NULL;
|
|
DWORD dwBytesPerRow;
|
|
|
|
pmiptex = (LPDIRECT3DTEXTURE8)ptex;
|
|
|
|
long iLevel;
|
|
for (iLevel = 0; iLevel < numMips; iLevel++)
|
|
{
|
|
if (pmiptex != NULL)
|
|
hr = pmiptex->GetSurfaceLevel(iLevel, &psurf);
|
|
if (FAILED(hr))
|
|
return false;
|
|
psurf->GetDesc(&sd);
|
|
switch (sd.Format)
|
|
{
|
|
case D3DFMT_DXT1:
|
|
case D3DFMT_DXT2:
|
|
case D3DFMT_DXT3:
|
|
case D3DFMT_DXT4:
|
|
case D3DFMT_DXT5:
|
|
dwBytesPerRow = 0; // magic value indicates texture's memory is contiguous
|
|
break;
|
|
case D3DFMT_A8R8G8B8:
|
|
dwBytesPerRow = 4 * sd.Width;
|
|
break;
|
|
case D3DFMT_R8G8B8:
|
|
dwBytesPerRow = 3 * sd.Width;
|
|
break;
|
|
case D3DFMT_A1R5G5B5:
|
|
case D3DFMT_A4R4G4B4:
|
|
case D3DFMT_R5G6B5:
|
|
dwBytesPerRow = 2 * sd.Width;
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
|
|
if (pmiptex != NULL)
|
|
hr = pmiptex->LockRect(iLevel, &lr, NULL, 0);
|
|
if (FAILED(hr))
|
|
return false;
|
|
if (dwBytesPerRow == 0)
|
|
{
|
|
fread(lr.pBits,sd.Size,1,fp);
|
|
}
|
|
else
|
|
{
|
|
DWORD yp;
|
|
BYTE* pbDest = (BYTE*)lr.pBits;
|
|
for (yp = 0; yp < sd.Height; yp++)
|
|
{
|
|
fread(pbDest,dwBytesPerRow,1,fp);
|
|
pbDest += lr.Pitch;
|
|
}
|
|
}
|
|
|
|
if (pmiptex != NULL)
|
|
{
|
|
hr = pmiptex->UnlockRect(iLevel);
|
|
}
|
|
|
|
SAFE_RELEASE(psurf);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
bool Z3DTexture::Load( const char* szFileName, UINT width, UINT height )
|
|
{
|
|
FILE* fp = NULL;
|
|
DDS_HEADER ddsh;
|
|
|
|
if( (fp = fopen(szFileName, "rb")) == NULL )
|
|
{
|
|
SimpleString strFileName( ms_strDataPath, szFileName );
|
|
|
|
if( (fp = fopen(strFileName, "rb")) == NULL )
|
|
{
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
strcpy(m_strName,strFileName);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
strcpy(m_strName,szFileName);
|
|
}
|
|
|
|
fseek(fp, 4, SEEK_SET);
|
|
fread( &ddsh, sizeof(DDS_HEADER), 1, fp );
|
|
|
|
D3DFORMAT fmt;
|
|
if (ddsh.ddspf.dwFourCC == D3DFMT_DXT1)
|
|
fmt = D3DFMT_DXT1;
|
|
else if (ddsh.ddspf.dwFourCC == D3DFMT_DXT2)
|
|
fmt = D3DFMT_DXT2;
|
|
else if (ddsh.ddspf.dwFourCC == D3DFMT_DXT3)
|
|
fmt = D3DFMT_DXT3;
|
|
else if (ddsh.ddspf.dwFourCC == D3DFMT_DXT4)
|
|
fmt = D3DFMT_DXT4;
|
|
else if (ddsh.ddspf.dwFourCC == D3DFMT_DXT5)
|
|
fmt = D3DFMT_DXT5;
|
|
else if (ddsh.ddspf.dwFlags == DDS_RGBA && ddsh.ddspf.dwRGBBitCount == 32 && ddsh.ddspf.dwABitMask == 0xff000000)
|
|
fmt = D3DFMT_A8R8G8B8;
|
|
else if (ddsh.ddspf.dwFlags == DDS_RGB && ddsh.ddspf.dwRGBBitCount == 24)
|
|
fmt = D3DFMT_R8G8B8;
|
|
else if (ddsh.ddspf.dwFlags == DDS_RGB && ddsh.ddspf.dwRGBBitCount == 16 && ddsh.ddspf.dwGBitMask == 0x000007e0)
|
|
fmt = D3DFMT_R5G6B5;
|
|
else if (ddsh.ddspf.dwFlags == DDS_RGBA && ddsh.ddspf.dwRGBBitCount == 16 && ddsh.ddspf.dwABitMask == 0x00008000)
|
|
fmt = D3DFMT_A1R5G5B5;
|
|
else if (ddsh.ddspf.dwFlags == DDS_RGBA && ddsh.ddspf.dwRGBBitCount == 16 && ddsh.ddspf.dwABitMask == 0x0000f000)
|
|
fmt = D3DFMT_A4R4G4B4;
|
|
else
|
|
{
|
|
fclose( fp );
|
|
return false;
|
|
}
|
|
|
|
if( 0 == ddsh.dwMipMapCount )
|
|
{
|
|
ddsh.dwMipMapCount = 1;
|
|
}
|
|
if( NULL == ( m_pTexture = _GetD3DTextureInterface(
|
|
ddsh.dwWidth, ddsh.dwHeight, ddsh.dwMipMapCount, fmt ) ) )
|
|
{
|
|
fclose( fp );
|
|
return false;
|
|
}
|
|
|
|
if( false == (LoadAllMipSurfaces(m_pTexture, ddsh.dwMipMapCount, fp)) )
|
|
{
|
|
fclose( fp );
|
|
return false;
|
|
}
|
|
|
|
fclose( fp );
|
|
return true;
|
|
}
|
|
|
|
|
|
bool Z3DTexture::Save( const char* szFilename )
|
|
{
|
|
if( NULL == m_pTexture )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
FILE* fp;
|
|
if( (fp = fopen( szFilename, "wb" )) == NULL )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
HRESULT hr;
|
|
DDS_HEADER ddsh;
|
|
DWORD dwMagic;
|
|
D3DFORMAT fmt;
|
|
DWORD dwSize;
|
|
DWORD dwPitch = 0;
|
|
D3DLOCKED_RECT lr;
|
|
D3DSURFACE_DESC sd;
|
|
DWORD dwLCount;
|
|
|
|
|
|
m_pTexture->GetLevelDesc( 0, &sd );
|
|
|
|
dwMagic = MAKEFOURCC('D','D','S',' ');
|
|
fwrite( &dwMagic, sizeof(DWORD), 1, fp );
|
|
|
|
ZeroMemory(&ddsh, sizeof(ddsh));
|
|
ddsh.dwSize = sizeof(ddsh);
|
|
ddsh.dwHeaderFlags = DDS_HEADER_FLAGS_TEXTURE;
|
|
ddsh.dwWidth = sd.Width;
|
|
ddsh.dwHeight = sd.Height;
|
|
ddsh.dwSurfaceFlags = DDS_SURFACE_FLAGS_TEXTURE;
|
|
dwLCount = m_pTexture->GetLevelCount();
|
|
if ( dwLCount > 1)
|
|
{
|
|
ddsh.dwHeaderFlags |= DDS_HEADER_FLAGS_MIPMAP;
|
|
ddsh.dwSurfaceFlags |= DDS_SURFACE_FLAGS_MIPMAP;
|
|
ddsh.dwMipMapCount = dwLCount;
|
|
}
|
|
|
|
m_pTexture->GetLevelDesc(0, &sd);
|
|
fmt = sd.Format;
|
|
dwSize = sd.Size;
|
|
if (SUCCEEDED(m_pTexture->LockRect(0, &lr, NULL, D3DLOCK_READONLY)))
|
|
{
|
|
dwPitch = lr.Pitch;
|
|
m_pTexture->UnlockRect(0);
|
|
}
|
|
|
|
switch (fmt)
|
|
{
|
|
case D3DFMT_DXT1:
|
|
ddsh.ddspf = DDSPF_DXT1;
|
|
ddsh.dwHeaderFlags |= DDS_HEADER_FLAGS_LINEARSIZE;
|
|
ddsh.dwPitchOrLinearSize = dwSize;
|
|
break;
|
|
case D3DFMT_DXT2:
|
|
ddsh.ddspf = DDSPF_DXT2;
|
|
ddsh.dwHeaderFlags |= DDS_HEADER_FLAGS_LINEARSIZE;
|
|
ddsh.dwPitchOrLinearSize = dwSize;
|
|
break;
|
|
case D3DFMT_DXT3:
|
|
ddsh.ddspf = DDSPF_DXT3;
|
|
ddsh.dwHeaderFlags |= DDS_HEADER_FLAGS_LINEARSIZE;
|
|
ddsh.dwPitchOrLinearSize = dwSize;
|
|
break;
|
|
case D3DFMT_DXT4:
|
|
ddsh.ddspf = DDSPF_DXT4;
|
|
ddsh.dwHeaderFlags |= DDS_HEADER_FLAGS_LINEARSIZE;
|
|
ddsh.dwPitchOrLinearSize = dwSize;
|
|
break;
|
|
case D3DFMT_DXT5:
|
|
ddsh.ddspf = DDSPF_DXT5;
|
|
ddsh.dwHeaderFlags |= DDS_HEADER_FLAGS_LINEARSIZE;
|
|
ddsh.dwPitchOrLinearSize = dwSize;
|
|
break;
|
|
case D3DFMT_A8R8G8B8:
|
|
ddsh.ddspf = DDSPF_A8R8G8B8;
|
|
ddsh.dwHeaderFlags |= DDS_HEADER_FLAGS_PITCH;
|
|
ddsh.dwPitchOrLinearSize = dwPitch;
|
|
break;
|
|
case D3DFMT_A1R5G5B5:
|
|
ddsh.ddspf = DDSPF_A1R5G5B5;
|
|
ddsh.dwHeaderFlags |= DDS_HEADER_FLAGS_PITCH;
|
|
ddsh.dwPitchOrLinearSize = dwPitch;
|
|
break;
|
|
case D3DFMT_A4R4G4B4:
|
|
ddsh.ddspf = DDSPF_A4R4G4B4;
|
|
ddsh.dwHeaderFlags |= DDS_HEADER_FLAGS_PITCH;
|
|
ddsh.dwPitchOrLinearSize = dwPitch;
|
|
break;
|
|
case D3DFMT_R8G8B8:
|
|
ddsh.ddspf = DDSPF_R8G8B8;
|
|
ddsh.dwHeaderFlags |= DDS_HEADER_FLAGS_PITCH;
|
|
ddsh.dwPitchOrLinearSize = dwPitch;
|
|
break;
|
|
case D3DFMT_R5G6B5:
|
|
ddsh.ddspf = DDSPF_R5G6B5;
|
|
ddsh.dwHeaderFlags |= DDS_HEADER_FLAGS_PITCH;
|
|
ddsh.dwPitchOrLinearSize = dwPitch;
|
|
break;
|
|
default:
|
|
fclose( fp );
|
|
return false;
|
|
}
|
|
|
|
fwrite( &ddsh, sizeof(DDS_HEADER), 1, fp );
|
|
|
|
|
|
LPDIRECT3DSURFACE8 pSurf;
|
|
DWORD i;
|
|
|
|
for( i = 0; i < dwLCount; i++ )
|
|
{
|
|
hr = m_pTexture->GetSurfaceLevel(i, &pSurf);
|
|
if( FAILED(hr) )
|
|
{
|
|
fclose( fp );
|
|
return false;
|
|
}
|
|
|
|
pSurf->GetDesc(&sd);
|
|
hr = m_pTexture->LockRect( i, &lr, NULL, 0 );
|
|
if( FAILED(hr) )
|
|
{
|
|
fclose( fp );
|
|
return false;
|
|
}
|
|
|
|
if (sd.Format == D3DFMT_DXT1 ||
|
|
sd.Format == D3DFMT_DXT2 ||
|
|
sd.Format == D3DFMT_DXT3 ||
|
|
sd.Format == D3DFMT_DXT4 ||
|
|
sd.Format == D3DFMT_DXT5)
|
|
{
|
|
fwrite( lr.pBits, sd.Size, 1, fp );
|
|
}
|
|
else
|
|
{
|
|
DWORD yp;
|
|
BYTE* pbDest = (BYTE*)lr.pBits;
|
|
LONG dataBytesPerRow = 0;
|
|
if (sd.Format == D3DFMT_A8R8G8B8)
|
|
dataBytesPerRow = 4 * sd.Width;
|
|
else if (sd.Format == D3DFMT_R8G8B8)
|
|
dataBytesPerRow = 3 * sd.Width;
|
|
else
|
|
dataBytesPerRow = 2 * sd.Width;
|
|
for (yp = 0; yp < sd.Height; yp++)
|
|
{
|
|
fwrite( pbDest, dataBytesPerRow, 1, fp );
|
|
pbDest += lr.Pitch;
|
|
}
|
|
}
|
|
hr = m_pTexture->UnlockRect(i);
|
|
pSurf->Release();
|
|
}
|
|
|
|
fclose( fp );
|
|
return true;
|
|
}
|
|
|
|
|
|
bool Z3DTexture::Convert( const D3DFORMAT targetFormat )
|
|
{
|
|
if( NULL == m_pTexture )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
D3DSURFACE_DESC sd;
|
|
|
|
m_pTexture->GetLevelDesc( 0, &sd );
|
|
if( sd.Format == targetFormat )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
int l = m_pTexture->GetLevelCount();
|
|
|
|
IDirect3DTexture8* pTextureDest = NULL;
|
|
if( FAILED( ms_pDevice->CreateTexture( sd.Width, sd.Width, l, 0, targetFormat,
|
|
D3DPOOL_MANAGED, &pTextureDest ) ) )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
IDirect3DSurface8* pSurfSrc = NULL;
|
|
IDirect3DSurface8* pSurfDest = NULL;
|
|
|
|
for( int i = 0; i < l; i++ )
|
|
{
|
|
m_pTexture->GetSurfaceLevel( i, &pSurfSrc );
|
|
pTextureDest->GetSurfaceLevel( i, &pSurfDest );
|
|
|
|
D3DXLoadSurfaceFromSurface( pSurfDest, NULL, NULL, pSurfSrc, NULL, NULL,
|
|
D3DX_FILTER_TRIANGLE, 0 );
|
|
|
|
SAFE_RELEASE( pSurfSrc );
|
|
SAFE_RELEASE( pSurfDest );
|
|
}
|
|
|
|
SAFE_RELEASE( m_pTexture );
|
|
m_pTexture = pTextureDest;
|
|
|
|
return true;
|
|
}
|