#include "stdafx.h" //#include "Util.h" #include "KRenderDevice.h" #include "KResource.h" #include "TerrainTextureInfo.h" #include "KResourceManager.h" #include #include #ifdef _MEMORY_LEAK_FIX_ const DWORD TEXTURE_HOLD_TIME = 0; #else const DWORD TEXTURE_HOLD_TIME = 300000; #endif CTerrainTextureInfo::CTerrainTextureInfo() : m_pDevice( NULL ) { m_dwLastTextureRemoveTime = GetSafeTickCount(); } CTerrainTextureInfo::~CTerrainTextureInfo() { Release(); } bool CTerrainTextureInfo::Initialize( const char* szTextureInfoFileName, K3DRenderDevice* pDevice ) { THREAD_SYNCRONIZE( m_lckTexture ); Release(); m_pDevice = pDevice; // dummy texture 생성 if( !InitializeDummyTexture() ) return false; // 파일로부터 text들을 읽어낸다. STRING_VECTOR TextLines; { KStream* pStream = KFileManager::Instance().CreateStreamFromResource( szTextureInfoFileName, false ); if( NULL == pStream ) return false; int nTextLength = int( pStream->GetLength() ); char* pEntireText = new char[ nTextLength + 1 ]; pStream->Read( pEntireText, sizeof(char) * nTextLength ); pEntireText[ nTextLength ] = '\0'; delete pStream; CStringUtil::GetTextLinesFromString( pEntireText, TextLines ); delete [] pEntireText; } const char* c_szCategory = "CATEGORY="; const char* c_szDetail = "DETAIL="; const char* c_szTexture = "TEXTURE="; int nCurrentCategory = 0; float fCurrentDetailRatio = 1.f; DWORD stime = GetSafeTickCount(); for( size_t n = 0; n < TextLines.size(); ++n ) { std::string strLine = TextLines[n]; if( ';' == strLine[0] ) continue; std::string strContent; // category if( CStringUtil::GetContentString( strLine, c_szCategory, strContent ) ) { if( strContent.size() > 0 ) { nCurrentCategory = (-1); for( size_t nCategory = 0; nCategory < m_CategoryNames.size(); ++nCategory ) { if( m_CategoryNames[nCategory] == strContent ) { // 이미 존재하는 category명인 경우 그대로 사용 nCurrentCategory = static_cast(nCategory); break; } } // 새로운 category명을 추가 if( (-1) == nCurrentCategory ) { m_CategoryNames.push_back( strContent ); nCurrentCategory = static_cast( m_CategoryNames.size() - 1 ); } } } // detail else if( CStringUtil::GetContentString( strLine, c_szDetail, strContent ) ) { fCurrentDetailRatio = (float)(::atof( strContent.c_str() )); if( 0.f == fCurrentDetailRatio ) fCurrentDetailRatio = 1.f; } // texture else if( CStringUtil::GetContentString( strLine, c_szTexture, strContent ) ) { // ',' 문자를 찾는다. int nCommaPos = static_cast( strContent.find( ',' ) ); if( nCommaPos != std::string::npos ) { // ',' 앞의 텍스쳐 번호 std::string strTexNum; strTexNum.assign( strContent, 0, nCommaPos ); // ',' 뒤의 텍스쳐 파일명 std::string strTexFileName; strTexFileName.assign( strContent, nCommaPos + 1, strContent.size() - (nCommaPos + 1) ); if( strTexNum.size() > 0 && strTexFileName.size() > 0 ) { WORD wTexNum = static_cast( ::atoi( strTexNum.c_str() ) ); K3DTexture* pTexture = NULL; #ifndef _RAC NX3LoadPack loadpack; loadpack.Init(); pTexture = KTextureManager::GetManager()->RefreshTexture( strTexFileName.c_str(), &loadpack ); #endif TEXINFO_STRUCT ts; ts.bIsLoadFailed = false; ts.nCategory = nCurrentCategory; ts.fDetailRatio = fCurrentDetailRatio; ts.spTexture = pTexture; ts.strName = strTexFileName; m_mapTexInfo[ wTexNum ] = ts; } } } } //_oprint( "TerrainTextureInfo Loading Time : %d\n", GetSafeTickCount()-stime ); // category가 한번도 안 나온 경우 if( m_CategoryNames.size() == 0 ) m_CategoryNames.push_back( "?" ); return true; } void CTerrainTextureInfo::Release() { THREAD_SYNCRONIZE( m_lckTexture ); ReleaseDummyTexture(); m_mapTexInfo.clear(); m_CategoryNames.clear(); } bool CTerrainTextureInfo::InitializeDummyTexture() { ReleaseDummyTexture(); const int c_nDummyLength = 16; m_spDummyTexture = m_pDevice->CreateTexture( c_nDummyLength, c_nDummyLength, K3DFMT_A1R5G5B5 ); if( m_spDummyTexture == NULL ) return false; WORD* pBuf; int nPitch; m_spDummyTexture->LockRect( NULL, (void**)&pBuf, nPitch ); if( pBuf == NULL ) return false; nPitch /= sizeof(WORD); for( int nY = 0; nY < c_nDummyLength; nY++ ) for( int nX = 0; nX < c_nDummyLength; nX++ ) pBuf[ (nY * nPitch) + nX ] = ( nX == nY || (c_nDummyLength - nX) == (nY + 1) ) ? 0xFC00 : 0xFFFF; m_spDummyTexture->Unlock(); return true; } void CTerrainTextureInfo::ReleaseDummyTexture() { } void CTerrainTextureInfo::RemoveUnnecessaryTexture() { if( m_dwLastTextureRemoveTime + TEXTURE_HOLD_TIME > GetSafeTickCount() ) return; THREAD_SYNCRONIZE( m_lckTexture ); DWORD dwCurrentTime = GetSafeTickCount(); for( std::map< WORD, TEXINFO_STRUCT >::iterator it = m_mapTexInfo.begin(); it != m_mapTexInfo.end(); ++it ) { if( !(*it).second.spTexture || (*it).second.bIsLoadFailed ) continue; if( (*it).second.spTexture->GetRefCount() > 1 ) continue; if( (*it).second.dwLastAccessTime + TEXTURE_HOLD_TIME > dwCurrentTime ) continue; (*it).second.spTexture = NULL; } m_dwLastTextureRemoveTime = GetSafeTickCount(); } K3DTexture* CTerrainTextureInfo::GetNotFoundTexture() { NX3LoadPack loadpack; loadpack.Init(); return KTextureManager::GetManager()->RefreshTexture( "NotFound.dds", &loadpack ); } K3DTexture* CTerrainTextureInfo::GetTexture( WORD wTextureNum ) { std::map< WORD, TEXINFO_STRUCT >::iterator it; { THREAD_SYNCRONIZE( m_lckTexture ); it = m_mapTexInfo.find( wTextureNum ); if( it == m_mapTexInfo.end() ) return NULL; (*it).second.dwLastAccessTime = GetSafeTickCount(); } // 로딩 실패했던 텍스쳐라면 KIN if( (*it).second.bIsLoadFailed ) return NULL; if( (*it).second.spTexture == NULL) { // TODO: In the process of adding resource option loading NX3LoadPack loadpack; loadpack.Init(); // Loading (*it).second.spTexture = KTextureManager::GetManager()->RefreshTexture( (*it).second.strName.c_str(), &loadpack ); if((*it).second.spTexture == NULL) { std::string str = (*it).second.strName; str += "\nNon-existent texture"; #ifndef _RAC AfxMessageBox( str.c_str(), MB_OK | MB_ICONERROR ); #endif return NULL; } if( (*it).second.spTexture != NULL) { //_oprint( "TERRAIN TEXTURE LOADING : %s (%d) (thread:%d)\n", (*it).second.strName.c_str(), wTextureNum, GetCurrentThreadId() ); } else { (*it).second.bIsLoadFailed = true; } } return (*it).second.spTexture; }