2653 lines
69 KiB
C++
2653 lines
69 KiB
C++
#include "stdafx.h"
|
|
#include <kfile/KStream.h>
|
|
//#include "KRenderObject.h"
|
|
#include "KRenderDefine.h"
|
|
#include "KRenderObjectEtc.h"
|
|
#include "KRenderObjectBone.h"
|
|
#include "KRenderObjectMesh.h"
|
|
#include "KResourceManager.h"
|
|
#include "KUITextureManager.h"
|
|
#include "KResource.h"
|
|
#include "KNX3Loader.h"
|
|
#include <kfile/KBinaryFiler.h>
|
|
#include "KSpriteLoader.h"
|
|
#include "KDeviceManager.h"
|
|
#include "KThreadLoader.h"
|
|
#include <toolkit/khash.h>
|
|
#include <toolkit/XDirectoryScanner.h>
|
|
#include <toolkit/XEnv.h>
|
|
#include <toolkit/XStringUtil.h>
|
|
#include <mmo/ArTime.h>
|
|
|
|
#include <kfile/XOREn.h>
|
|
#include "KResourceManagerUtil.h"
|
|
#include "XLRUCacheContainer.h"
|
|
#include <kfile/XFileBasedFS.h>
|
|
#include <kfile/KFileManager.h>
|
|
|
|
//#include "KGameResourceManager.h"
|
|
#include <toolkit/XStringUtil.h>
|
|
//#include "KGameFileSystem.h"
|
|
//#include <kfile/KPackingFileSystem.h>
|
|
|
|
//#include <string>
|
|
//#include <vector>
|
|
|
|
//#include "SDebug_Util.h"
|
|
|
|
const int RELEASE_TIME = 300000; //5분
|
|
|
|
//XCriticalSection g_hashCS;
|
|
XCriticalSection g_SpriteAniCS;
|
|
|
|
//#ifdef _RAC
|
|
extern HWND g_hWnd;
|
|
//#endif
|
|
|
|
XFileBasedFS g_PackedFile;
|
|
|
|
//#define DEF_FILESYSTEM
|
|
|
|
#ifdef DEF_FILESYSTEM
|
|
KWin32FS g_FileSystem;
|
|
#endif
|
|
|
|
const char * pResLevel[] =
|
|
{
|
|
"_AA.", //상, 사용 하지 않음
|
|
"_CC.", //하,
|
|
};
|
|
|
|
int NX3LoadPack::nLoad_Level = 0;
|
|
bool NX3LoadPack::SetTextureLevel( int nLevel )
|
|
{
|
|
if( nLoad_Level == nLevel )
|
|
return false;
|
|
else
|
|
{
|
|
nLoad_Level = nLevel;
|
|
return true;
|
|
}
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//KTextureManager Implement
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
XCriticalSection g_texture_CS;
|
|
|
|
|
|
struct PR_DATA
|
|
{
|
|
const char * pStr;
|
|
int nRef;
|
|
};
|
|
|
|
struct PrintCompareFN
|
|
{
|
|
bool operator() ( const PR_DATA& pr1, const PR_DATA& pr2 ) const
|
|
{
|
|
return strlen(pr1.pStr) > strlen(pr2.pStr);
|
|
}
|
|
};
|
|
|
|
KTextureManager * KSingletoneResourceManager<KTextureManager>::s_pStaticManager = new KTextureManager;
|
|
KTextureManager::KTextureManager()
|
|
{
|
|
m_nTextureQualityLevel = 0; //최고 퀄리티
|
|
m_policy = ORG_THEN_DDS; // 일단 주어진 파일명으로 찾고, 실패하면 확장자를 dds 로 바꿔 다시 검색
|
|
}
|
|
KTextureManager::~KTextureManager()
|
|
{
|
|
DiscardAll();
|
|
}
|
|
|
|
void KTextureManager::init(void)
|
|
{
|
|
|
|
//////////////////////
|
|
#ifdef _DEV
|
|
_TextureModeReload();
|
|
_TextureModeBuild();
|
|
#endif
|
|
NX3LoadPack loadpack;
|
|
loadpack.Init();
|
|
|
|
_spSpecular[0]= GetTexture( "spec_01.dds",&loadpack,TRUE,0);
|
|
_spSpecular[1]= GetTexture( "spec_02.dds",&loadpack,TRUE,0);
|
|
_spSpecular[2]= GetTexture( "spec_03.dds",&loadpack,TRUE,0);
|
|
_spSpecular[3]= GetTexture( "spec_04.dds",&loadpack,TRUE,0);
|
|
|
|
_spSpecular[4]= GetTexture( "spec_30.dds",&loadpack,TRUE,0);
|
|
_spSpecular[5]= GetTexture( "spec_40.dds",&loadpack,TRUE,0);
|
|
_spSpecular[6]= GetTexture( "spec_50.dds",&loadpack,TRUE,0);
|
|
|
|
//_spSpecular = (void*) m_spSpecular;
|
|
|
|
|
|
}
|
|
|
|
|
|
void KTextureManager::makeHashString( char *buf, const char *filename, DWORD c1, DWORD c2, DWORD c3, DWORD c4 )
|
|
{
|
|
// Fraun textures loading change
|
|
//sprintf(buf, "%s@%08x", filename, c1);// , c2, c3, c4 );
|
|
sprintf( buf, "%s@%08x%08x%08x%08x", filename, c1, c2, c3, c4 );
|
|
}
|
|
|
|
void KTextureManager::makeFileName( char *buf, const char *hashname )
|
|
{
|
|
int len = static_cast<int>(strlen( hashname ));
|
|
strncpy( buf, hashname, len-33 );
|
|
buf[len-33] = '\0';
|
|
}
|
|
|
|
void KTextureManager::makeColor( const char *hashname, DWORD& c1, DWORD& c2, DWORD& c3, DWORD& c4 )
|
|
{
|
|
char szBuf[33] = { 0, };
|
|
int len = static_cast<int>(strlen( hashname ));
|
|
strncpy( szBuf, &hashname[len-32], 32 );
|
|
|
|
std::string strColor;
|
|
strColor = szBuf;
|
|
char *HEX_P;
|
|
|
|
c1 = strtoul( strColor.substr( 0, 8 ).c_str(), &HEX_P, 16);
|
|
c2 = strtoul( strColor.substr( 8, 8 ).c_str(), &HEX_P, 16);
|
|
c3 = strtoul( strColor.substr( 16, 8 ).c_str(), &HEX_P, 16);
|
|
c4 = strtoul( strColor.substr( 24, 8 ).c_str(), &HEX_P, 16);
|
|
}
|
|
|
|
void KTextureManager::PrintList( const char * pOutFileName )
|
|
{
|
|
K3DTexture *tex;
|
|
bool res;
|
|
|
|
THREAD_SYNCRONIZE( g_texture_CS );
|
|
|
|
res = m_texByName.get_first_value( tex );
|
|
|
|
std::vector< PR_DATA > strFileList;
|
|
|
|
if( res )
|
|
{
|
|
|
|
while ( res )
|
|
{
|
|
if ( tex != NULL )
|
|
{
|
|
PR_DATA pr;
|
|
pr.nRef = tex->GetRefCount();
|
|
pr.pStr = tex->GetName();
|
|
|
|
strFileList.push_back( pr );
|
|
}
|
|
res = m_texByName.get_next_value( tex );
|
|
}
|
|
}
|
|
|
|
if( !strFileList.empty() )
|
|
{
|
|
std::vector< PR_DATA >::iterator it;
|
|
|
|
std::sort( strFileList.begin(), strFileList.end(), PrintCompareFN() );
|
|
|
|
KFileStream * pFileStream = new KFileStream( pOutFileName, KFileStream::wronly );
|
|
pFileStream->Seek( 0, KFileStream::seekSet );
|
|
|
|
std::string strline = "\r\n";
|
|
std::string strName;
|
|
std::string strRef;
|
|
for( it = strFileList.begin(); it != strFileList.end(); ++it )
|
|
{
|
|
strName = (*it).pStr;
|
|
std::string::size_type pos = strName.rfind('@');
|
|
if( pos != std::string::npos )
|
|
{
|
|
pFileStream->Write( (*it).pStr, pos );
|
|
XStringUtil::Format( strRef, " - Ref Count : %d ", (*it).nRef );
|
|
pFileStream->Write( strRef.c_str(), strRef.length() );
|
|
pFileStream->Write( strline.c_str(), strline.length() );
|
|
}
|
|
}
|
|
XStringUtil::Format( strline, "\r\nTotal Texture Cnt : %d\r\n", strFileList.size() );
|
|
pFileStream->Write( strline.c_str(), strline.length() );
|
|
|
|
delete pFileStream;
|
|
}
|
|
}
|
|
|
|
void KTextureManager::EventTime( DWORD dwTime )
|
|
{
|
|
}
|
|
|
|
bool KTextureManager::IsExistTexture( const char *texname, const NX3LoadPack * pLoadPack )
|
|
{
|
|
char tempname[_MAX_PATH];
|
|
tempname[_MAX_PATH-1] = '\0';
|
|
std::vector< std::string > vList;
|
|
XStringUtil::Split( texname, vList, "\\", false );
|
|
|
|
if( KFileManager::Instance().IsValidResource( vList.back().c_str() ) ) return true;
|
|
|
|
strcpy( tempname, vList.back().c_str() );
|
|
|
|
if( KNX3Manager::GetManager()->GetSystemRequirements() == KNX3Manager::MINIMUM_SYSTEM ||
|
|
KNX3Manager::GetManager()->GetSystemRequirements() == KNX3Manager::MINIMUM_SYSTEM_BY_USER_SELECT )
|
|
{
|
|
changeExtFromFileName( tempname, pLoadPack ? 1 : 0, "dds" );
|
|
}
|
|
else
|
|
{
|
|
changeExtFromFileName( tempname, pLoadPack ? pLoadPack->nLoad_Level : 0, "dds" );
|
|
}
|
|
|
|
//_CC 또는 원본
|
|
//dds 혹은 원본 파일을 쓸 수 있음으로 둘다 체크하는 것 으로 수정함 2009.04.14 sfreer
|
|
if( KFileManager::Instance().IsValidResource( tempname ) || KFileManager::Instance().IsValidResource( vList.back().c_str() ) ) return true;
|
|
|
|
strcpy( tempname, vList.back().c_str() );
|
|
changeExtFromFileName( tempname, 0, "dds" );
|
|
|
|
return KFileManager::Instance().IsValidResource( tempname );
|
|
}
|
|
|
|
//#define _TEX_TEST
|
|
|
|
K3DTexture* KTextureManager::GetTexture( const char *texname, const NX3LoadPack * pLoadPack, bool bRegMissingRes, int nTextureQuality )
|
|
{
|
|
K3DTexture *restex = NULL;
|
|
char hashname[_MAX_PATH];
|
|
|
|
#ifdef _TEX_TEST
|
|
makeHashString( hashname, getFileNameFromPath( "4By4Tex.dds" ), 0, 0, 0, 0 );
|
|
#else
|
|
makeHashString( hashname, getFileNameFromPath( texname ), 0, 0, 0, 0 );
|
|
#endif
|
|
{
|
|
THREAD_SYNCRONIZE( g_texture_CS );
|
|
if ( m_texByName.lookup(hashname, restex ) == true )
|
|
return restex;
|
|
}
|
|
|
|
#ifdef _TEX_TEST
|
|
restex = loadTexture( "4By4Tex.dds", pLoadPack, bRegMissingRes, nTextureQuality );
|
|
#else
|
|
restex = loadTexture( texname, pLoadPack, bRegMissingRes, nTextureQuality );
|
|
#endif
|
|
|
|
{
|
|
THREAD_SYNCRONIZE( g_texture_CS );
|
|
|
|
if(restex)
|
|
{
|
|
restex->SetLoadedTime( GetSafeTickCount() );
|
|
restex->SetName( hashname ); // for later use
|
|
// _oprint( "m_texByName.add 01: %d %s\n", restex->GetID(), hashname );
|
|
restex->SetManagedByTexManager();
|
|
m_texByName.add( hashname, restex ); // doesn't null-check for performance
|
|
}
|
|
|
|
|
|
return restex;
|
|
}
|
|
}
|
|
|
|
K3DTexture* KTextureManager::GetTexture( const char *texname, const NX3LoadPack * pLoadPack, DWORD c1, DWORD c2, DWORD c3, DWORD c4, int nTextureQuality, short nMode/* = 0*/ )
|
|
{
|
|
K3DTexture *restex = NULL;
|
|
char hashname[_MAX_PATH];
|
|
|
|
#ifdef _TEX_TEST
|
|
makeHashString( hashname, getFileNameFromPath( "4By4Tex.dds" ), c1, c2, c3, c4 );
|
|
#else
|
|
makeHashString( hashname, getFileNameFromPath( texname ), c1, c2, c3, c4 );
|
|
#endif
|
|
|
|
{
|
|
THREAD_SYNCRONIZE( g_texture_CS );
|
|
if ( m_texByName.lookup( hashname, restex ) == true)
|
|
return restex;
|
|
}
|
|
|
|
if ( c1 == 0 && c2 == 0 && c3 == 0 && c4 == 0 )
|
|
{
|
|
#ifdef _TEX_TEST
|
|
restex = loadTexture( "4By4Tex.dds", pLoadPack, true, nTextureQuality );
|
|
#else
|
|
restex = loadTexture( texname, pLoadPack, true, nTextureQuality );
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
#ifdef _TEX_TEST
|
|
restex = loadColorizedTexture( "4By4Tex.dds", pLoadPack, c1, c2, c3, c4, nTextureQuality, nMode );
|
|
#else
|
|
restex = loadColorizedTexture( texname, pLoadPack, c1, c2, c3, c4, nTextureQuality, nMode );
|
|
#endif
|
|
}
|
|
|
|
{
|
|
THREAD_SYNCRONIZE( g_texture_CS );
|
|
|
|
if(restex)
|
|
{
|
|
restex->SetLoadedTime( GetSafeTickCount() );
|
|
restex->SetName( hashname);
|
|
// _oprint( "m_texByName.add 02: %d %s\n", restex->GetID(), hashname );
|
|
restex->SetManagedByTexManager();
|
|
m_texByName.add( hashname, restex ); // doesn't null-check for performance
|
|
}
|
|
|
|
}
|
|
|
|
return restex;
|
|
}
|
|
|
|
K3DTexture* KTextureManager::GetTexture( K3DTexture *tex, const NX3LoadPack * pLoadPack, DWORD c1, DWORD c2, DWORD c3, DWORD c4, int nTextureQuality, short nMode/* = 0*/ )
|
|
{
|
|
if ( tex == NULL )
|
|
return NULL;
|
|
|
|
char filename[_MAX_PATH];
|
|
makeFileName( filename, tex->GetName() );
|
|
|
|
return GetTexture( filename, pLoadPack, c1, c2, c3, c4, nTextureQuality, nMode );
|
|
}
|
|
|
|
K3DTexture* KTextureManager::RefreshTexture( const char *texname, const NX3LoadPack * pLoadPack, DWORD c1, DWORD c2 /* = 0 */, DWORD c3 /* = 0 */, DWORD c4 /* = 0 */ )
|
|
{
|
|
K3DTexture *restex = NULL;
|
|
char hashname[_MAX_PATH];
|
|
makeHashString( hashname, getFileNameFromPath( texname ), c1, c2, c3, c4 );
|
|
|
|
THREAD_SYNCRONIZE( g_texture_CS );
|
|
|
|
if ( m_texByName.lookup( hashname, restex ) == true )
|
|
{
|
|
if ( restex == NULL )
|
|
{
|
|
// _oprint( "m_texByName.erase 02 : %d %s\n", restex->GetID(), hashname );
|
|
m_texByName.erase( hashname );
|
|
return GetTexture( texname, pLoadPack, c1, c2, c3, c4 );
|
|
}
|
|
char tempname[_MAX_PATH];
|
|
tempname[_MAX_PATH-1] = '\0';
|
|
strcpy( tempname, texname );
|
|
|
|
KStream *stream = NULL;
|
|
|
|
|
|
if ( m_policy & ORG_ONLY && !checkExtFromFileName(texname,"DDS") )
|
|
{
|
|
stream = KFileManager::Instance().CreateStreamFromResource( texname );
|
|
}
|
|
|
|
if ( (!stream && (m_policy & DDS_ONLY)) || checkExtFromFileName(texname,"DDS") )
|
|
{
|
|
if( KNX3Manager::GetManager()->GetSystemRequirements() == KNX3Manager::MINIMUM_SYSTEM ||
|
|
KNX3Manager::GetManager()->GetSystemRequirements() == KNX3Manager::MINIMUM_SYSTEM_BY_USER_SELECT )
|
|
{
|
|
changeExtFromFileName( tempname, pLoadPack ? 1 : 0, "DDS" );
|
|
}
|
|
else
|
|
{
|
|
changeExtFromFileName( tempname, pLoadPack ? pLoadPack->nLoad_Level : 0, "DDS" );
|
|
}
|
|
|
|
stream = KFileManager::Instance().CreateStreamFromResource( tempname );
|
|
}
|
|
|
|
if ( stream )
|
|
{
|
|
restex->Refresh( *stream, GetMipMapBiasLevel() );
|
|
KFileManager::Instance().DeleteStream( stream );
|
|
return restex;
|
|
}
|
|
|
|
//m_policy 설정에 따라 dds가 아닌 원본 파일이 우선 load 될 수 있다.
|
|
/*
|
|
KStream *stream = KFileManager::Instance().CreateStreamFromResource( tempname );
|
|
if ( stream )
|
|
{
|
|
restex->Refresh( *stream, GetMipMapBiasLevel() );
|
|
KFileManager::Instance().DeleteStream( stream );
|
|
return restex;
|
|
}
|
|
else
|
|
{
|
|
stream = KFileManager::Instance().CreateStreamFromResource( texname );
|
|
if ( stream )
|
|
{
|
|
restex->Refresh( *stream, GetMipMapBiasLevel() );
|
|
KFileManager::Instance().DeleteStream( stream );
|
|
return restex;
|
|
}
|
|
}*/
|
|
}
|
|
|
|
return GetTexture(texname, pLoadPack, c1, c2, c3, c4, GetMipMapBiasLevel() );
|
|
}
|
|
|
|
K3DTexture* KTextureManager::GetTexture(KStream& stream,const char *texname, const NX3LoadPack * pLoadPack, int nTextureQuality )
|
|
{
|
|
K3DTexture *restex = NULL;
|
|
char hashname[_MAX_PATH];
|
|
makeHashString( hashname, getFileNameFromPath( texname ), 0, 0, 0, 0 );
|
|
|
|
{
|
|
THREAD_SYNCRONIZE( g_texture_CS );
|
|
if ( m_texByName.lookup( hashname, restex ) == true ) return restex;
|
|
}
|
|
|
|
restex = loadTexture( stream, pLoadPack, nTextureQuality );
|
|
|
|
{
|
|
THREAD_SYNCRONIZE( g_texture_CS );
|
|
|
|
if(restex)
|
|
{
|
|
restex->SetLoadedTime( GetSafeTickCount() );
|
|
restex->SetName( hashname ); // for later use
|
|
// _oprint( "m_texByName.add 03: %d %s\n", restex->GetID(), hashname );
|
|
restex->SetManagedByTexManager();
|
|
m_texByName.add( hashname, restex ); // doesn't null-check for performance
|
|
}
|
|
|
|
return restex;
|
|
}
|
|
}
|
|
|
|
static const char *getTextureFormatInfo( int nFormat )
|
|
{
|
|
|
|
struct TextureFormatInfo
|
|
{
|
|
int nFormat;
|
|
char* pszName;
|
|
};
|
|
|
|
static TextureFormatInfo s_TextureFormatInfo[]
|
|
= {
|
|
{K3DFMT_UNKNOWN, "K3DFMT_UNKNOWN"},
|
|
|
|
{K3DFMT_R8G8B8, "K3DFMT_R8G8B8"},
|
|
{K3DFMT_A8R8G8B8, "K3DFMT_A8R8G8B8"},
|
|
{K3DFMT_X8R8G8B8, "K3DFMT_X8R8G8B8"},
|
|
{K3DFMT_R5G6B5, "K3DFMT_R5G6B5"},
|
|
{K3DFMT_X1R5G5B5, "K3DFMT_X1R5G5B5"},
|
|
{K3DFMT_A1R5G5B5, "K3DFMT_A1R5G5B5"},
|
|
{K3DFMT_A4R4G4B4, "K3DFMT_A4R4G4B4"},
|
|
{K3DFMT_R3G3B2, "K3DFMT_R3G3B2"},
|
|
{K3DFMT_A8, "K3DFMT_A8"},
|
|
{K3DFMT_A8R3G3B2, "K3DFMT_A8R3G3B2"},
|
|
{K3DFMT_X4R4G4B4, "K3DFMT_X4R4G4B4"},
|
|
{K3DFMT_A2B10G10R10, "K3DFMT_A2B10G10R10"},
|
|
{K3DFMT_G16R16, "K3DFMT_G16R16"},
|
|
|
|
{K3DFMT_A8P8, "K3DFMT_A8P8"},
|
|
{K3DFMT_P8, "K3DFMT_P8"},
|
|
|
|
{K3DFMT_L8, "K3DFMT_L8"},
|
|
{K3DFMT_A8L8, "K3DFMT_A8L8"},
|
|
{K3DFMT_A4L4, "K3DFMT_A4L4"},
|
|
|
|
{K3DFMT_V8U8, "K3DFMT_V8U8"},
|
|
{K3DFMT_L6V5U5, "K3DFMT_L6V5U5"},
|
|
{K3DFMT_X8L8V8U8, "K3DFMT_X8L8V8U8"},
|
|
{K3DFMT_Q8W8V8U8, "K3DFMT_Q8W8V8U8"},
|
|
{K3DFMT_V16U16, "K3DFMT_V16U16"},
|
|
{K3DFMT_W11V11U10, "K3DFMT_W11V11U10"},
|
|
{K3DFMT_A2W10V10U10, "K3DFMT_A2W10V10U10"},
|
|
|
|
{K3DFMT_UYVY, "K3DFMT_UYVY"},
|
|
{K3DFMT_YUY2, "K3DFMT_YUY2"},
|
|
{K3DFMT_DXT1, "K3DFMT_DXT1"},
|
|
{K3DFMT_DXT2, "K3DFMT_DXT2"},
|
|
{K3DFMT_DXT3, "K3DFMT_DXT3"},
|
|
{K3DFMT_DXT4, "K3DFMT_DXT4"},
|
|
{K3DFMT_DXT5, "K3DFMT_DXT5"},
|
|
|
|
{K3DFMT_D16_LOCKABLE, "K3DFMT_D16_LOCKABLE"},
|
|
{K3DFMT_D32, "K3DFMT_D32"},
|
|
{K3DFMT_D15S1, "K3DFMT_D15S1"},
|
|
{K3DFMT_D24S8, "K3DFMT_D24S8"},
|
|
{K3DFMT_D16, "K3DFMT_D16"},
|
|
{K3DFMT_D24X8, "K3DFMT_D24X8"},
|
|
{K3DFMT_D24X4S4, "K3DFMT_D24X4S4"},
|
|
|
|
|
|
{K3DFMT_VERTEXDATA, "K3DFMT_VERTEXDATA"},
|
|
{K3DFMT_INDEX16, "K3DFMT_INDEX16"},
|
|
{K3DFMT_INDEX32, "K3DFMT_INDEX32"},
|
|
|
|
{K3DFMT_R32F, "K3DFMT_R32F"},
|
|
|
|
{K3DFMT_FORCE_DWORD, "K3DFMT_FORCE_DWORD"},
|
|
{ 0, NULL },
|
|
};
|
|
|
|
TextureFormatInfo *p = &s_TextureFormatInfo[0];
|
|
while( p->pszName )
|
|
{
|
|
if( p->nFormat == nFormat ) return p->pszName;
|
|
p++;
|
|
}
|
|
|
|
return "UNKNOWN";
|
|
}
|
|
|
|
K3DTexture* KTextureManager::loadTexture( const char *texname, const NX3LoadPack * pLoadPack, bool bRegMissingRes, int nTextureQuality )
|
|
{
|
|
DWORD dwStartTime = GetSafeTickCount();
|
|
|
|
// _oprint( "loadTexture %s\n", texname );
|
|
|
|
K3DTexture* restex = NULL;
|
|
KStream* stream = NULL;
|
|
char tempname[_MAX_PATH];
|
|
|
|
std::vector< std::string > vList;
|
|
|
|
if ( m_policy & ORG_ONLY && !checkExtFromFileName(texname,"DDS") )
|
|
{
|
|
vList.clear();
|
|
tempname[_MAX_PATH-1] = '\0';
|
|
strcpy( tempname, texname );
|
|
|
|
//if ( m_policy == DDS_ONLY )
|
|
// changeExtFromFileName( tempname, pLoadPack ? pLoadPack->nLoad_Level : 0, "DDS" );
|
|
|
|
XStringUtil::Split( tempname, vList, "\\", false );
|
|
|
|
assert( vList.size() );
|
|
|
|
//if (vList.empty())
|
|
//{
|
|
// // Fraun texture change
|
|
// return nullptr;
|
|
//}
|
|
|
|
stream = KFileManager::Instance().CreateStreamFromResource( vList.back().c_str() );
|
|
|
|
}
|
|
|
|
|
|
if ( (!stream && (m_policy & DDS_ONLY)) || checkExtFromFileName(texname,"DDS") )
|
|
{
|
|
vList.clear();
|
|
tempname[_MAX_PATH-1] = '\0';
|
|
strcpy( tempname, texname );
|
|
|
|
if( KNX3Manager::GetManager()->GetSystemRequirements() == KNX3Manager::MINIMUM_SYSTEM ||
|
|
KNX3Manager::GetManager()->GetSystemRequirements() == KNX3Manager::MINIMUM_SYSTEM_BY_USER_SELECT )
|
|
{
|
|
changeExtFromFileName( tempname, pLoadPack ? 1 : 0, "DDS" );
|
|
|
|
}
|
|
else
|
|
{
|
|
changeExtFromFileName( tempname, pLoadPack ? pLoadPack->nLoad_Level : 0, "DDS" );
|
|
}
|
|
|
|
XStringUtil::Split( tempname, vList, "\\", false );
|
|
|
|
stream = KFileManager::Instance().CreateStreamFromResource( vList.back().c_str() );
|
|
|
|
if ( !stream )
|
|
{
|
|
vList.clear();
|
|
tempname[_MAX_PATH-1] = '\0';
|
|
strcpy( tempname, texname );
|
|
|
|
changeExtFromFileName( tempname, 0, "DDS" );
|
|
XStringUtil::Split( tempname, vList, "\\", false );
|
|
|
|
stream = KFileManager::Instance().CreateStreamFromResource( vList.back().c_str() );
|
|
|
|
}
|
|
}
|
|
|
|
int nSize = 0;
|
|
|
|
if ( stream )
|
|
{
|
|
nSize = stream->GetLength();
|
|
restex = loadTexture( *stream, pLoadPack, nTextureQuality );
|
|
KFileManager::Instance().DeleteStream( stream );
|
|
|
|
_oprint( "\n");
|
|
}
|
|
else
|
|
{
|
|
/// 2012.04.05 다른 내용 디버깅에 방해가 되서 주석 처리함 - prodongi
|
|
//_oprint( "loadTexture Not Found %s\n", tempname );
|
|
}
|
|
|
|
// 여기의 assert() 와 경고박스를 절.대.로. 없애지 말것!!!
|
|
// 해결 방법은 assert() 를 지우는것이 아니라 없는 리소스를 읽는 일이 없도록 만드는 것임.
|
|
#ifndef NDEBUG
|
|
if( !restex )
|
|
{
|
|
// char buf[1024];
|
|
std::string buf;
|
|
XStringUtil::Format( buf, "Attempted to read a non-existent texture: %s\n", texname );
|
|
if( ENV().IsExist( "no_err_box" ) == false )
|
|
{
|
|
//::MessageBox( ::g_hWnd, buf.c_str() , "RESOURCE ERROR", MB_OK | MB_ICONEXCLAMATION );
|
|
}
|
|
}
|
|
#endif
|
|
|
|
DWORD dwLoadTime = GetSafeTickCount() - dwStartTime;
|
|
int nTextureFormat = 0;
|
|
if( restex )
|
|
{
|
|
nTextureFormat = restex->GetFormat();
|
|
restex->GetTextureMode((char*)texname);
|
|
}
|
|
// If the texture loading time takes more than 20ms, the format is not DXT-compressed, or it's larger than 256KB, a loading log will be recorded
|
|
if( restex && (
|
|
dwLoadTime >= 30 ||
|
|
( nTextureFormat != K3DFMT_DXT1 && nTextureFormat != K3DFMT_DXT2 && nTextureFormat != K3DFMT_DXT3 && nTextureFormat != K3DFMT_DXT4 && nTextureFormat != K3DFMT_DXT5 ) ||
|
|
nSize > 256*1024 ) )
|
|
{
|
|
_oprint( "TEXLOG : %s (%dms) (%dKB) (%dx%d) (%s) (Mips:%d) (%d:%d) ThreadId:%d", tempname, dwLoadTime, nSize/1024, restex->GetWidth(), restex->GetHeight(), getTextureFormatInfo( nTextureFormat ), restex->GetMipsLevels(), pLoadPack == 0 ? 1 : 0, pLoadPack ? pLoadPack->nLoad_Level : 0, GetCurrentThreadId() );
|
|
}
|
|
|
|
return restex;
|
|
}
|
|
|
|
K3DTexture* KTextureManager::loadTexture( KStream& stream, const NX3LoadPack * pLoadPack, int nTextureQuality )
|
|
{
|
|
K3DTexture *restex = NULL;
|
|
if (stream.IsValid() )
|
|
{
|
|
restex = KDeviceManager::GetDeviceManager()->GetRenderDevice()->CreateTexture( stream, nTextureQuality );
|
|
|
|
return restex;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
K3DTexture* KTextureManager::loadColorizedTexture( const char *texname, const NX3LoadPack * pLoadPack, DWORD c1, DWORD c2, DWORD c3, DWORD c4, int nTextureQuality, short nMode )
|
|
{
|
|
K3DTexture *restex = GetTexture( texname, pLoadPack, true, nTextureQuality );
|
|
|
|
if(restex)
|
|
{
|
|
int height = restex->GetHeight();
|
|
int width = restex->GetWidth();
|
|
K3DTexture *newtex = KDeviceManager::GetDeviceManager()->GetRenderDevice()->CreateTexture( width, height, K3DFMT_A8R8G8B8, D3DPOOL_MANAGED, restex->GetMipsLevels() );
|
|
|
|
if( newtex )
|
|
{
|
|
newtex->SetColorizedMode( nMode );
|
|
//기존 텍스쳐 밉맵 포함 복사, 포맷에 상관 없이 가능
|
|
if( restex->LoadSurfaceFromSurface( newtex, c1, c2, c3, c4, nMode ) != S_OK ) return NULL;
|
|
|
|
newtex->GetTextureMode((char*)texname);
|
|
return newtex;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
K3DTexture* KTextureManager::GetTextureOriginal( const char *texname, const NX3LoadPack * pLoadPack, bool bRegMissingRes/* = true*/ )
|
|
{
|
|
// 없는 텍스쳐라우..
|
|
if( !texname || *texname == '0' ) return NULL;
|
|
|
|
K3DTexture* pTex = GetTexture( texname, pLoadPack, bRegMissingRes, 10000 );
|
|
if ( pTex )
|
|
pTex->Flags() |= TEXFLAG_ORIGINAL;
|
|
|
|
return pTex;
|
|
}
|
|
|
|
void KTextureManager::RemoveTexture( K3DTexture *tex )
|
|
{
|
|
THREAD_SYNCRONIZE( g_texture_CS );
|
|
|
|
if ( tex != NULL )
|
|
{
|
|
if( strlen(tex->GetName()) > 0 && tex->GetManagedByTexManager() )
|
|
{
|
|
// _oprint( "m_texByName.erase 01 : %d %s\n", tex->GetID(), tex->GetName() );
|
|
m_texByName.erase( tex->GetName() );
|
|
}
|
|
}
|
|
}
|
|
|
|
int KTextureManager::GetMipMapBiasLevel()
|
|
{
|
|
return m_nTextureQualityLevel;
|
|
}
|
|
|
|
void KTextureManager::SetMipMapBiasLevel( int nLevel )
|
|
{
|
|
if( m_nTextureQualityLevel != nLevel )
|
|
{
|
|
m_nTextureQualityLevel = nLevel;
|
|
_oprint( "Adjust texture quality (nLevel: %d)\n", m_nTextureQualityLevel );
|
|
//KDeviceManager::GetDeviceManager()->GetRenderDevice()->SetMipBias((float) nLevel * 0.5f);
|
|
}
|
|
}
|
|
|
|
void KTextureManager::ReloadRes( bool bRepair, unsigned char withMask, unsigned char withoutMask )
|
|
{
|
|
bool res;
|
|
char buf[_MAX_PATH];
|
|
|
|
KHash<K3DTexture*,hashPr_string_nocase>::node *_node = NULL;
|
|
|
|
THREAD_SYNCRONIZE( g_texture_CS );
|
|
res = m_texByName.get_first_node( _node );
|
|
|
|
int nTexQuality = GetMipMapBiasLevel();
|
|
|
|
//TODO : 리소스 옵션 로딩 추가 작업 중.
|
|
NX3LoadPack loadpack;
|
|
loadpack.Init();
|
|
|
|
DWORD c1, c2, c3, c4;
|
|
|
|
for (; res; res = m_texByName.get_next_node( _node ) )
|
|
{
|
|
if ( _node->value != NULL )
|
|
{
|
|
unsigned char flags = _node->value->GetFlags();
|
|
if ( withMask != 0 && (flags & withMask) != withMask )
|
|
continue;
|
|
if ( withoutMask != 0 && (flags & withoutMask) != 0 )
|
|
continue;
|
|
|
|
makeFileName( buf, _node->key.m_pStr );
|
|
makeColor( _node->key.m_pStr, c1, c2, c3, c4 );
|
|
|
|
// 리전이나 셀렉트관련 텍스쳐는 텍스쳐설정과 상관없이 최상옵션으로 적용된다.
|
|
if ( !strcmp ( buf, "rcfx_skillregion_on.dds" ) || !strcmp ( buf, "rcfx_select_on01.dds" ) || !strcmp ( buf, "rcfx_select_on02.dds" ) )
|
|
continue;
|
|
// m_policy옵션에 따라 원래 확장자를 dds확장자보다 우선순위를 높인다.
|
|
|
|
|
|
KStream *stream = NULL;
|
|
if ( m_policy & ORG_ONLY && !checkExtFromFileName(buf,"DDS") )
|
|
{
|
|
stream = KFileManager::Instance().CreateStreamFromResource( buf );
|
|
}
|
|
|
|
if ( (!stream && (m_policy & DDS_ONLY)) || checkExtFromFileName(buf,"DDS") )
|
|
{
|
|
if( KNX3Manager::GetManager()->GetSystemRequirements() == KNX3Manager::MINIMUM_SYSTEM ||
|
|
KNX3Manager::GetManager()->GetSystemRequirements() == KNX3Manager::MINIMUM_SYSTEM_BY_USER_SELECT )
|
|
{
|
|
changeExtFromFileName( buf, 1, "DDS" );
|
|
}
|
|
else
|
|
{
|
|
changeExtFromFileName( buf, loadpack.GetTextureLevel(), "DDS" );
|
|
}
|
|
|
|
stream = KFileManager::Instance().CreateStreamFromResource( buf );
|
|
}
|
|
|
|
|
|
/*
|
|
if( KNX3Manager::GetManager()->GetSystemRequirements() == KNX3Manager::MINIMUM_SYSTEM ||
|
|
KNX3Manager::GetManager()->GetSystemRequirements() == KNX3Manager::MINIMUM_SYSTEM_BY_USER_SELECT )
|
|
{
|
|
changeExtFromFileName( buf, 1, "DDS" );
|
|
}
|
|
else
|
|
{
|
|
changeExtFromFileName( buf, loadpack.GetTextureLevel(), "DDS" );
|
|
}*/
|
|
|
|
|
|
bool bFind = flags & TEXFLAG_ORIGINAL;
|
|
|
|
if( c1 != 0 || c2 != 0 || c3 != 0 || c4 != 0 )
|
|
{ //칼라 라이즈 된 텍스쳐
|
|
//_LEAK_SUN
|
|
if( stream )
|
|
KFileManager::Instance().DeleteStream( stream );
|
|
}
|
|
else
|
|
{
|
|
//KStream *stream = KFileManager::Instance().CreateStreamFromResource( buf );
|
|
if ( stream )
|
|
{
|
|
//복구가 아니라면, bFind는 다시 Load 할 필요가 없다.
|
|
if( bRepair ) //복구는 다 Load
|
|
_node->value->Refresh( *stream, bFind ? 0 : GetMipMapBiasLevel() );
|
|
else
|
|
{ //복구가 아니다. 텍스쳐 퀄리티가 0인 것은 다시 로드 하지 않는다.
|
|
if( !bFind )
|
|
_node->value->Refresh( *stream, GetMipMapBiasLevel() );
|
|
}
|
|
KFileManager::Instance().DeleteStream( stream );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//여기는 애초에 리소스를 찾지 못 했을 경우에 들어 온다.
|
|
makeFileName( buf, _node->key.m_pStr );
|
|
|
|
//Load 가 처음 부터 안되었으므로 모두 다시 Load 시도 한다.
|
|
_node->value = loadTexture( buf, &loadpack, true, GetMipMapBiasLevel() );
|
|
}
|
|
}
|
|
}
|
|
|
|
void KTextureManager::DiscardAll()
|
|
{
|
|
K3DTexture *tex;
|
|
bool res;
|
|
|
|
THREAD_SYNCRONIZE( g_texture_CS );
|
|
|
|
res = m_texByName.get_first_value( tex );
|
|
while ( res )
|
|
{
|
|
if ( tex != NULL )
|
|
{
|
|
tex->Discard();
|
|
}
|
|
res = m_texByName.get_next_value( tex );
|
|
}
|
|
m_texByName.clear();
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//KSoundManager Implement
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//KSoundManager *KSingletoneResourceManager<KSoundManager>::s_pStaticManager = new KSoundManager;
|
|
//KSoundManager::KSoundManager()
|
|
//{
|
|
//}
|
|
//KSoundManager::~KSoundManager()
|
|
//{
|
|
// DiscardAll();
|
|
//}
|
|
//
|
|
//KSoundData* KSoundManager::GetSound(const char * soundName)
|
|
//{
|
|
// KSoundData * pSound = NULL;
|
|
//
|
|
// char lower_name[MAX_PATH];
|
|
// strcpy( lower_name, soundName );
|
|
// strlwr( lower_name );
|
|
//
|
|
// if ( m_soundByName.lookup( lower_name, pSound ) == true )
|
|
// return pSound;
|
|
//
|
|
// THREAD_SYNCRONIZE( &KResourceManager::GetLockInstance() );
|
|
//
|
|
// pSound = _LoadSound(lower_name);
|
|
// if(pSound)
|
|
// {
|
|
// m_soundByName.add(lower_name,pSound);
|
|
// }
|
|
//
|
|
//
|
|
//
|
|
// return pSound;
|
|
//
|
|
//}
|
|
//void KSoundManager::ReloadRes()
|
|
//{
|
|
// bool res;
|
|
// KHash<KSoundData*,hashPr_string>::node *_node = NULL;
|
|
//
|
|
// THREAD_SYNCRONIZE( &KResourceManager::GetLockInstance() );
|
|
//
|
|
// res = m_soundByName.get_first_node( _node );
|
|
// while ( res )
|
|
// {
|
|
// if ( _node->value != NULL )
|
|
// {
|
|
// _node->value->Reload(KDeviceManager::GetDeviceManager()->GetSoundDevice() );
|
|
// }
|
|
// else
|
|
// {
|
|
// _node->value = _LoadSound(_node->key.m_pStr);
|
|
// }
|
|
// res = m_soundByName.get_next_node( _node );
|
|
// }
|
|
//}
|
|
//
|
|
//void KSoundManager::DiscardAll()
|
|
//{
|
|
// KSoundData *pSound;
|
|
// bool res;
|
|
//
|
|
// THREAD_SYNCRONIZE( &KResourceManager::GetLockInstance() );
|
|
//
|
|
// res = m_soundByName.get_first_value( pSound );
|
|
// while ( res )
|
|
// {
|
|
// if ( pSound != NULL )
|
|
// delete pSound;
|
|
//
|
|
// res = m_soundByName.get_next_value( pSound);
|
|
// }
|
|
// m_soundByName.clear();
|
|
//
|
|
//
|
|
//}
|
|
//
|
|
//
|
|
//KSoundData* KSoundManager::_LoadSound( const char *soundName)
|
|
//{
|
|
// KSoundData *resSound = new KSoundData;
|
|
//
|
|
// std::string validName = KResourceManager::GetValidFileName(soundName);
|
|
//
|
|
// if ( validName.size() > 0)
|
|
// {
|
|
// if( resSound->LoadWAV(validName.c_str(), KDeviceManager::GetDeviceManager()->GetSoundDevice()) )
|
|
// {
|
|
// resSound->SetName( soundName ); // for later use
|
|
// return resSound;
|
|
// }
|
|
// else
|
|
// {
|
|
// SAFE_DELETE(resSound);
|
|
// }
|
|
// }
|
|
//
|
|
// return NULL;
|
|
//}
|
|
|
|
XCriticalSection g_nx3_CS;
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//KNX3Manager Implement
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
bool loadNX3( const char * szName, const NX3LoadPack * plodpack, KStream &stream, NX3SET *nx3set );
|
|
void loadMesh( std::vector<KSeqObject*> &vecMeshSeq, std::vector<KSeqObject*> &vecFXSeq, std::vector<KSeqObject*> &vecEvSeq, KNX3Mesh *mesh, std::vector<KNX3MeshTM*> &tmList );
|
|
KFXSeq *loadFXBillboard( KNX3Mesh *mesh, KNX3FX *fx );
|
|
KFXSeq *loadFXParticle( KNX3Mesh *mesh, KNX3FX *fx, DWORD dwParticleType);
|
|
KFXSeq *loadFXAfterImage( KNX3Mesh *mesh, KNX3FX *fx);
|
|
|
|
struct NX3SET
|
|
{
|
|
NX3SET()
|
|
{
|
|
// nRefCount = 0;
|
|
// _oprint( "NX3 CREATE : (0x%08X)\n", this );
|
|
}
|
|
~NX3SET();
|
|
// int nRefCount;
|
|
std::string strName;
|
|
std::string strProperty;
|
|
std::vector< KSeqObject* > vpMeshSeq;
|
|
std::vector< KSeqObject* > vpFXSeq;
|
|
std::vector< KSeqObject* > vpLightSeq;
|
|
std::vector< KSeqObject* > vpCamSeq;
|
|
std::vector< KSeqObject* > vpEventSeq;
|
|
std::vector< KSeqObject* > vpBoneSeq;
|
|
std::vector< KSeqObject* > vpPfxSeq;
|
|
};
|
|
|
|
struct NX3Data
|
|
{
|
|
#ifdef NDEBUG
|
|
NX3Data() : m_LRUList( 10, true )
|
|
#else
|
|
NX3Data() : m_LRUList( 10, true )
|
|
#endif
|
|
{
|
|
}
|
|
|
|
bool AddToLoadingList( const char *szResourceName )
|
|
{
|
|
THREAD_SYNCRONIZE( &m_lock );
|
|
|
|
if( IsLoading( szResourceName ) ) return false;
|
|
|
|
m_vLoadingList.push_back( szResourceName );
|
|
|
|
return true;
|
|
}
|
|
|
|
bool RemoveFromLoadingList( const char *szResourceName )
|
|
{
|
|
THREAD_SYNCRONIZE( &m_lock );
|
|
|
|
if( !IsLoading( szResourceName ) ) return false;
|
|
|
|
for( std::vector< std::string >::iterator it = m_vLoadingList.begin(); it != m_vLoadingList.end(); ++it )
|
|
{
|
|
if( _stricmp( (*it).c_str(), szResourceName ) ) continue;
|
|
|
|
m_vLoadingList.erase( it );
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool IsLoading( const char *szResourceName )
|
|
{
|
|
THREAD_SYNCRONIZE( &m_lock );
|
|
|
|
for( std::vector< std::string >::iterator it = m_vLoadingList.begin(); it != m_vLoadingList.end(); ++it )
|
|
{
|
|
if( _stricmp( (*it).c_str(), szResourceName ) ) continue;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
size_t GetLoadingCount()
|
|
{
|
|
THREAD_SYNCRONIZE( &m_lock );
|
|
return m_vLoadingList.size();
|
|
}
|
|
|
|
XCriticalSection m_lock;
|
|
std::vector< std::string > m_vLoadingList;
|
|
XLRUCacheContainer< std::string, hashPr_string_nocase, NX3SET* > m_LRUList;
|
|
};
|
|
|
|
KNX3Manager *KSingletoneResourceManager<KNX3Manager>::s_pStaticManager = new KNX3Manager;
|
|
KNX3Manager::SYSTEM_REQUIREMENTS KNX3Manager::s_nSysRequirements = KNX3Manager::MIXED_SYSTEM;
|
|
KNX3Manager::KNX3Manager() // 5분동안 사용 안되면 사라짐
|
|
{
|
|
m_pNX3Data = new NX3Data;
|
|
}
|
|
|
|
KNX3Manager::~KNX3Manager()
|
|
{
|
|
DiscardAll();
|
|
delete m_pNX3Data;
|
|
}
|
|
|
|
void KNX3Manager::ReloadRes( bool bRepair )
|
|
{
|
|
}
|
|
|
|
void KNX3Manager::ExceptListPrint()
|
|
{
|
|
THREAD_SYNCRONIZE( &g_nx3_CS );
|
|
|
|
std::vector< std::string > vExceptList;
|
|
|
|
m_pNX3Data->m_LRUList.EnumExceptList( vExceptList );
|
|
|
|
if( !vExceptList.empty() )
|
|
{
|
|
std::vector< std::string >::iterator it;
|
|
std::sort( vExceptList.begin(), vExceptList.end() );
|
|
|
|
KFileStream * pFileStream = new KFileStream( "ExceptList.txt", KFileStream::wronly );
|
|
pFileStream->Seek( 0, KFileStream::seekSet );
|
|
|
|
std::string strline = "\r\n";
|
|
std::string strRef;
|
|
for( it = vExceptList.begin(); it != vExceptList.end(); ++it )
|
|
{
|
|
pFileStream->Write( (*it).c_str(), (*it).length() );
|
|
|
|
pFileStream->Write( strline.c_str(), strline.length() );
|
|
}
|
|
XStringUtil::Format( strline, "\r\nTotal ExceptList Cnt : %d\r\n", vExceptList.size() );
|
|
pFileStream->Write( strline.c_str(), strline.length() );
|
|
|
|
delete pFileStream;
|
|
}
|
|
}
|
|
|
|
void KNX3Manager::AddToExceptList( const char * pName )
|
|
{
|
|
THREAD_SYNCRONIZE( &g_nx3_CS );
|
|
|
|
if( !m_pNX3Data->m_LRUList.IsInExceptList( pName ) )
|
|
m_pNX3Data->m_LRUList.AddToExceptList( pName );
|
|
}
|
|
|
|
void KNX3Manager::RemoveFromExceptList( const char * pName )
|
|
{
|
|
THREAD_SYNCRONIZE( &g_nx3_CS );
|
|
|
|
m_pNX3Data->m_LRUList.RemoveFromExceptList( pName );
|
|
}
|
|
|
|
bool KNX3Manager::IsInExceptList( const char * pName )
|
|
{
|
|
THREAD_SYNCRONIZE( &g_nx3_CS );
|
|
|
|
return m_pNX3Data->m_LRUList.IsInExceptList( pName );
|
|
}
|
|
|
|
void KNX3Manager::ClearExceptList()
|
|
{
|
|
THREAD_SYNCRONIZE( &g_nx3_CS );
|
|
|
|
m_pNX3Data->m_LRUList.ClearExceptList();
|
|
}
|
|
|
|
void KNX3Manager::ClearUnreferencedResource()
|
|
{
|
|
// assert( _CrtCheckMemory() && "Memory Error!!!" );
|
|
|
|
THREAD_SYNCRONIZE( &g_nx3_CS );
|
|
|
|
m_pNX3Data->m_LRUList.ClearUnreferencedResource();
|
|
|
|
// assert( _CrtCheckMemory() && "Memory Error!!!" );
|
|
}
|
|
|
|
void KNX3Manager::DiscardAll()
|
|
{
|
|
THREAD_SYNCRONIZE( &g_nx3_CS );
|
|
|
|
m_pNX3Data->m_LRUList.Clear();
|
|
}
|
|
|
|
NX3SET::~NX3SET()
|
|
{
|
|
THREAD_SYNCRONIZE( &g_nx3_CS );
|
|
|
|
if ( !vpMeshSeq.empty() )
|
|
{
|
|
for ( size_t i=0 ; i<vpMeshSeq.size() ; ++i ) delete vpMeshSeq[i];
|
|
}
|
|
|
|
if ( !vpFXSeq.empty() )
|
|
{
|
|
for ( size_t i=0 ; i<vpFXSeq.size() ; ++i ) delete vpFXSeq[i];
|
|
}
|
|
|
|
if ( !vpLightSeq.empty() )
|
|
{
|
|
for ( size_t i=0 ; i<vpLightSeq.size() ; ++i ) delete vpLightSeq[i];
|
|
}
|
|
|
|
if ( !vpCamSeq.empty() )
|
|
{
|
|
for ( size_t i=0 ; i<vpCamSeq.size() ; ++i ) delete vpCamSeq[i];
|
|
}
|
|
|
|
if ( !vpEventSeq.empty() )
|
|
{
|
|
for ( size_t i=0 ; i<vpEventSeq.size() ; ++i ) delete vpEventSeq[i];
|
|
}
|
|
|
|
if( !vpBoneSeq.empty() )
|
|
{
|
|
for ( size_t i=0 ; i<vpBoneSeq.size() ; ++i ) delete vpBoneSeq[i];
|
|
}
|
|
}
|
|
|
|
void KNX3Manager::PrintList( const char * pOutFileName )
|
|
{
|
|
THREAD_SYNCRONIZE( &g_nx3_CS );
|
|
|
|
std::vector< NX3SET* >::iterator it;
|
|
std::vector< NX3SET* > vNX3List;
|
|
m_pNX3Data->m_LRUList.Enum( vNX3List );
|
|
|
|
//
|
|
m_pNX3Data->m_LRUList.PrintList();
|
|
|
|
std::vector< PR_DATA > strFileList;
|
|
|
|
if( !vNX3List.empty() )
|
|
{
|
|
for( it = vNX3List.begin(); it != vNX3List.end(); ++it )
|
|
{
|
|
NX3SET* pSet = (*it);
|
|
|
|
PR_DATA pr;
|
|
pr.pStr = pSet->strName.c_str();
|
|
pr.nRef = 0;
|
|
|
|
strFileList.push_back( pr );
|
|
}
|
|
}
|
|
|
|
if( !strFileList.empty() )
|
|
{
|
|
std::vector< PR_DATA >::iterator it;
|
|
|
|
std::sort( strFileList.begin(), strFileList.end(), PrintCompareFN() );
|
|
|
|
KFileStream * pFileStream = new KFileStream( pOutFileName, KFileStream::wronly );
|
|
pFileStream->Seek( 0, KFileStream::seekSet );
|
|
|
|
std::string strline = "\r\n";
|
|
std::string strRef;
|
|
for( it = strFileList.begin(); it != strFileList.end(); ++it )
|
|
{
|
|
pFileStream->Write( (*it).pStr, strlen((*it).pStr) );
|
|
XStringUtil::Format( strRef, " - Ref Count : %d ", (*it).nRef );
|
|
pFileStream->Write( strRef.c_str(), strRef.length() );
|
|
pFileStream->Write( strline.c_str(), strline.length() );
|
|
}
|
|
XStringUtil::Format( strline, "\r\nTotal NX3 Cnt : %d\r\n", strFileList.size() );
|
|
pFileStream->Write( strline.c_str(), strline.length() );
|
|
|
|
delete pFileStream;
|
|
}
|
|
|
|
ExceptListPrint();
|
|
}
|
|
|
|
void KNX3Manager::EventTime( DWORD dwTime )
|
|
{
|
|
THREAD_SYNCRONIZE( &g_nx3_CS );
|
|
|
|
#ifdef _MEMORY_LEAK_FIX_
|
|
static DWORD LRU_CHECK_INTERVAL = 0;
|
|
#else
|
|
const DWORD LRU_CHECK_INTERVAL = 20000;
|
|
#endif
|
|
static DWORD m_PrevTime = dwTime;
|
|
|
|
if( m_PrevTime + LRU_CHECK_INTERVAL < dwTime )
|
|
{
|
|
m_pNX3Data->m_LRUList.Process();
|
|
m_PrevTime = dwTime;
|
|
}
|
|
}
|
|
|
|
void KNX3Manager::addSeqObjectToSeq( KSequencer* & seq, std::vector< KSeqObject* > & vObj )
|
|
{
|
|
if( vObj.empty() ) return;
|
|
|
|
if ( seq == NULL ) seq = new KSequencer(true);
|
|
|
|
for ( size_t i=0 ; i<vObj.size() ; ++i )
|
|
{
|
|
seq->AddSeqObject( vObj[i]->Clone() );
|
|
}
|
|
}
|
|
|
|
struct NX3ThreadLoader : XBossWorker::XWorker
|
|
{
|
|
NX3ThreadLoader( const char *szName, NX3Data *pData, const NX3LoadPack * plodpack ) : m_strName( szName ), m_pNX3Data( pData ), m_loadpack(*plodpack) {}
|
|
|
|
virtual bool onProcess( int nThreadNum )
|
|
{
|
|
DWORD dwTime = GetSafeTickCount();
|
|
|
|
KStream *stream = KFileManager::Instance().CreateStreamFromResource( m_strName.c_str() );
|
|
if ( stream == NULL ) return false;
|
|
|
|
size_t nSize = stream->GetLength();
|
|
|
|
NX3SET *nx3set = NULL;
|
|
nx3set = new NX3SET;
|
|
|
|
if ( !loadNX3( m_strName.c_str(), &m_loadpack, *stream, nx3set ) )
|
|
{
|
|
{
|
|
THREAD_SYNCRONIZE( &g_nx3_CS );
|
|
m_pNX3Data->RemoveFromLoadingList( m_strName.c_str() );
|
|
assert( 0 );
|
|
}
|
|
KFileManager::Instance().DeleteStream( stream );
|
|
delete nx3set;
|
|
return false;
|
|
}
|
|
|
|
KFileManager::Instance().DeleteStream( stream );
|
|
|
|
{
|
|
THREAD_SYNCRONIZE( &g_nx3_CS );
|
|
nx3set->strName = m_strName.c_str();
|
|
m_pNX3Data->m_LRUList.Add( m_strName.c_str(), nx3set, true );
|
|
}
|
|
|
|
DWORD dwLoadTime = GetSafeTickCount() - dwTime;
|
|
if( dwLoadTime > 50 )
|
|
{
|
|
_oprint( "NX3] END THREAD LOADING : %s (%dms) (%dKB) : %d\n", m_strName.c_str(), dwLoadTime, nSize/1024, GetCurrentThreadId() );
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
virtual void onEnd( bool bIsCancel )
|
|
{
|
|
m_pNX3Data->RemoveFromLoadingList( m_strName.c_str() );
|
|
delete this;
|
|
}
|
|
|
|
NX3LoadPack m_loadpack;
|
|
NX3Data* m_pNX3Data;
|
|
std::string m_strName;
|
|
};
|
|
|
|
//#define _NOT_THREAD_LOAD_
|
|
|
|
void KNX3Manager::RequestThreadLoading( const char *resname, const NX3LoadPack * plodpack )
|
|
{
|
|
{
|
|
THREAD_SYNCRONIZE( &g_nx3_CS );
|
|
if( m_pNX3Data->m_LRUList.IsExist( resname ) || m_pNX3Data->IsLoading( resname ) ) return;
|
|
m_pNX3Data->AddToLoadingList( resname );
|
|
// _oprint( "RequestThreadLoading : %s\n", resname );
|
|
}
|
|
|
|
#ifdef _NOT_THREAD_LOAD_
|
|
NX3ThreadLoader load( resname, this->m_pNX3Data, plodpack );
|
|
load.onProcess(0);
|
|
#else
|
|
KThreadResource::PendWorkToThreadPool( new NX3ThreadLoader( resname, this->m_pNX3Data, plodpack ) );
|
|
#endif
|
|
}
|
|
|
|
size_t KNX3Manager::GetThreadLoadingCount() const
|
|
{
|
|
{
|
|
THREAD_SYNCRONIZE( &g_nx3_CS );
|
|
return m_pNX3Data->GetLoadingCount();
|
|
}
|
|
}
|
|
|
|
KSequencer *KNX3Manager::CreateSequencer( const char *resname, const NX3LoadPack * plodpack, int reqtype )
|
|
{
|
|
// assert( _CrtCheckMemory() && "Memory Error!!!" );
|
|
bool bCheckValidRes = true;
|
|
const char* pResultName = resname;
|
|
if( s_nSysRequirements == MINIMUM_SYSTEM || s_nSysRequirements == MINIMUM_SYSTEM_BY_USER_SELECT )
|
|
{
|
|
char resorucename[_MAX_PATH];
|
|
|
|
strcpy( resorucename, resname );
|
|
|
|
if( resname != NULL )
|
|
{
|
|
char szExtName[10];
|
|
|
|
const char* pExtName = getExtFromFileName( resname );
|
|
if( pExtName )
|
|
{
|
|
strcpy( szExtName, pExtName );
|
|
|
|
changeExtFromFileName( resorucename, 1, szExtName );
|
|
|
|
if( KFileManager::Instance().IsValidResource( resorucename ) )
|
|
{
|
|
pResultName = resorucename;
|
|
bCheckValidRes = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if( bCheckValidRes )
|
|
{
|
|
if( !KFileManager::Instance().IsValidResource( pResultName ) )
|
|
return NULL;
|
|
}
|
|
|
|
NX3SET *nx3set = NULL;
|
|
|
|
bool bRtn = false;
|
|
{
|
|
THREAD_SYNCRONIZE( &g_nx3_CS );
|
|
bRtn = m_pNX3Data->m_LRUList.Get( pResultName, &nx3set );
|
|
}
|
|
|
|
// 이미 nx3set 이 캐쉬에 있는 경우
|
|
if( bRtn )
|
|
{
|
|
// assert( nx3set->nRefCount >= 0 && "당담자 호출!!!");
|
|
return getSequencerFromNX3Set( nx3set, reqtype );
|
|
}
|
|
|
|
// { 없다면 NX3를 로딩해서 시퀀서를 만든다
|
|
return createSequencer( pResultName, plodpack, reqtype );
|
|
// }
|
|
}
|
|
|
|
KSequencer* KNX3Manager::createSequencer( const char *resname, const NX3LoadPack * plodpack, int reqtype )
|
|
{
|
|
// assert( _CrtCheckMemory() && "Memory Error!!!" );
|
|
|
|
NX3SET *nx3set = NULL;
|
|
bool bRtn = false;
|
|
|
|
nx3set = new NX3SET;
|
|
|
|
bool bIsLoading = false;
|
|
{
|
|
THREAD_SYNCRONIZE( &g_nx3_CS );
|
|
|
|
if( m_pNX3Data->m_LRUList.Get( resname, &nx3set ) )
|
|
{
|
|
//assert( nx3set->nRefCount >= 0 && "당담자 호출!!!");
|
|
// _oprint( "NX3] Error Find! 01\n" );
|
|
return getSequencerFromNX3Set( nx3set, reqtype );
|
|
}
|
|
|
|
// 이미 다른 쓰레드에서 로딩 중인지 검사
|
|
bIsLoading = m_pNX3Data->IsLoading( resname );
|
|
|
|
if( !bIsLoading ) m_pNX3Data->AddToLoadingList( resname );
|
|
}
|
|
|
|
// 이미 다른 쓰레드에서 로딩 중이라면 로딩이 끝나는것을 기다려서 활용한다.
|
|
if( bIsLoading )
|
|
{
|
|
delete nx3set;
|
|
nx3set = NULL;
|
|
|
|
DWORD dwTime = GetSafeTickCount();
|
|
_oprint( "NX3] WAITING LOADING : %s\n", resname );
|
|
|
|
while( true )
|
|
{
|
|
NX3SET *nx3set_cached = NULL;
|
|
|
|
{
|
|
THREAD_SYNCRONIZE( &g_nx3_CS );
|
|
m_pNX3Data->m_LRUList.Get( resname, &nx3set_cached );
|
|
}
|
|
|
|
if( nx3set_cached )
|
|
{
|
|
_oprint( "NX3] WAIT COMPLETE : %s (%dms)\n", resname, GetSafeTickCount() - dwTime );
|
|
// assert( nx3set_cached->nRefCount >= 0 && "당담자 호출!!!");
|
|
return getSequencerFromNX3Set( nx3set_cached, reqtype );
|
|
}
|
|
|
|
Sleep( 20 );
|
|
}
|
|
}
|
|
|
|
KStream *stream = KFileManager::Instance().CreateStreamFromResource( resname );
|
|
if ( stream == NULL )
|
|
{
|
|
// 여기의 assert() 와 경고박스를 절.대.로. 없애지 말것!!!
|
|
// 해결 방법은 assert() 를 지우는것이 아니라 없는 리소스를 읽는 일이 없도록 만드는 것임.
|
|
|
|
#ifndef NDEBUG
|
|
// char buf[1024];
|
|
std::string buf;
|
|
XStringUtil::Format( buf, "Tried to read a non-existent resource: %s\n", resname );
|
|
if( ENV().IsExist( "no_err_box" ) == false )
|
|
{
|
|
//::MessageBox( ::g_hWnd, buf.c_str(), "RESOURCE ERROR", MB_OK | MB_ICONEXCLAMATION );
|
|
}
|
|
#endif
|
|
|
|
THREAD_SYNCRONIZE( &g_nx3_CS );
|
|
m_pNX3Data->RemoveFromLoadingList( resname );
|
|
return NULL;
|
|
}
|
|
|
|
if ( !loadNX3( resname, plodpack, *stream, nx3set ) )
|
|
{
|
|
{
|
|
THREAD_SYNCRONIZE( &g_nx3_CS );
|
|
m_pNX3Data->RemoveFromLoadingList( resname );
|
|
}
|
|
KFileManager::Instance().DeleteStream( stream );
|
|
delete nx3set;
|
|
return NULL;
|
|
}
|
|
|
|
KFileManager::Instance().DeleteStream( stream );
|
|
|
|
{
|
|
THREAD_SYNCRONIZE( &g_nx3_CS );
|
|
nx3set->strName = resname;
|
|
m_pNX3Data->RemoveFromLoadingList( resname );
|
|
m_pNX3Data->m_LRUList.Add( resname, nx3set );
|
|
}
|
|
|
|
// assert( _CrtCheckMemory() && "Memory Error!!!" );
|
|
|
|
// NX3Set 으로부터 Sequencer 를 만들어 리턴
|
|
// _oprint( "NX3] Error Find! 02\n" );
|
|
return getSequencerFromNX3Set( nx3set, reqtype );
|
|
}
|
|
|
|
KSequencer* KNX3Manager::getSequencerFromNX3Set( NX3SET *nx3set, int reqtype )
|
|
{
|
|
// assert( _CrtCheckMemory() && "Memory Error!!!" );
|
|
|
|
KSequencer *seq = NULL;
|
|
|
|
if ( nx3set == NULL )
|
|
return NULL;
|
|
|
|
seq = NULL;
|
|
|
|
if ( reqtype & SEQTYPE_CAMERA ) addSeqObjectToSeq( seq, nx3set->vpCamSeq );
|
|
|
|
if ( reqtype & SEQTYPE_LIGHT ) addSeqObjectToSeq( seq, nx3set->vpLightSeq );
|
|
|
|
if ( reqtype & SEQTYPE_BONE ) addSeqObjectToSeq( seq, nx3set->vpBoneSeq );
|
|
|
|
if ( reqtype & SEQTYPE_MESH )
|
|
{
|
|
addSeqObjectToSeq( seq, nx3set->vpMeshSeq );
|
|
addSeqObjectToSeq( seq, nx3set->vpEventSeq );
|
|
}
|
|
|
|
if ( reqtype & SEQTYPE_FX ) addSeqObjectToSeq( seq, nx3set->vpFXSeq );
|
|
|
|
if ( reqtype & SEQTYPE_PFX ) addSeqObjectToSeq( seq, nx3set->vpPfxSeq );
|
|
|
|
if ( seq )
|
|
{
|
|
THREAD_SYNCRONIZE( &g_nx3_CS );
|
|
seq->SetName( nx3set->strName.c_str() );
|
|
seq->LoadProp( nx3set->strProperty.c_str() );
|
|
//m_pNX3Data->m_LRUList.AddRef( nx3set->strName );
|
|
//nx3set->nRefCount++;
|
|
}
|
|
|
|
// assert( _CrtCheckMemory() && "Memory Error!!!" );
|
|
|
|
return seq;
|
|
}
|
|
|
|
void KNX3Manager::ReleaseRes( const char *resname )
|
|
{
|
|
THREAD_SYNCRONIZE( &g_nx3_CS );
|
|
|
|
//예외 리스트에 있으면 Skip
|
|
if( m_pNX3Data->m_LRUList.IsInExceptList( resname ) )
|
|
return;
|
|
|
|
if ( m_pNX3Data->m_LRUList.IsExist( resname ) == true )
|
|
{
|
|
m_pNX3Data->m_LRUList.ReleaseRef( resname );
|
|
}
|
|
}
|
|
|
|
template< typename T > static inline T _min( const T& a, const T& b ) { return a < b ? a : b; }
|
|
template< typename T > static inline T _max( const T& a, const T& b ) { return a > b ? a : b; }
|
|
|
|
KFXSeq *loadFXBillboard( KNX3Mesh *mesh, KNX3FX *fx )
|
|
{
|
|
if ( fx->GetFXElementSize() == 0 )
|
|
return NULL;
|
|
KNX3FXElement *fxele = fx->GetFxElementByIndeX(0);
|
|
|
|
if ( mesh->GetMeshElements().size() == 0 )
|
|
return NULL;
|
|
KNX3MeshElement *meshele = mesh->GetMeshElements()[0];
|
|
|
|
if ( meshele->GetFrameCount() == 0 )
|
|
return NULL;
|
|
KNX3MeshFrame *meshfr = meshele->GetFrame(0);
|
|
|
|
K3DVertexBuffer *vb = meshfr->GetVertexBuffer();//Vertex Buffer Add 일어남
|
|
int stride = vb->GetVertexStride();
|
|
int count = vb->GetVertexCount();
|
|
if ( count < 4 )
|
|
return NULL;
|
|
|
|
KFXBillboardSeq *seq = new KFXBillboardSeq;
|
|
KResFXBillboard *res = new KResFXBillboard;
|
|
|
|
res->SetRes( mesh->GetMatrixAniRes(), mesh->GetVisibilityRes() );
|
|
|
|
K3DVector ua = fxele->GetVectorValue( "uvani", K3DVector( 0.f, 0.f, 0.f ) );
|
|
res->SetUVAnimation( ua.x > .0f, static_cast<int>(ua.y), static_cast< int >( ua.z ) );
|
|
res->SetAlignedCameraMode( fxele->GetNumValue( "align", 0 ) != 0 );
|
|
res->SetAdditiveRenderMode( fxele->GetNumValue( "rendertype", 0 ) != 0 );
|
|
|
|
int base, vari;
|
|
base = 0; vari = 0;
|
|
fxele->GetVariNumValue( "loop", &base, &vari );
|
|
res->SetLoopMode( base != 0 );
|
|
res->SetRange( fxele->GetFrameTime(), vari * 160 );
|
|
res->SetScale( fxele->Get2DVectorValue( "scale", K3DVector( 1.f, 1.f, 1.f ) ) );
|
|
res->SetFixedAxis( fxele->GetNumValue( "fixedaxis", -1 ) );
|
|
res->SetRotateSpeed( fxele->GetFloatValue( "rotatespeed", 0.0f ) );
|
|
|
|
K3DVector cube_min(100.f,100.f,100.f), cube_max(-100.f,-100.f,-100.f);
|
|
|
|
char *vtxtempbuf = NULL;
|
|
K3DVertex vtx[4];
|
|
vb->Lock( (void**)&vtxtempbuf, count );
|
|
if( vtxtempbuf )
|
|
{
|
|
for ( int i=0 ; i<4 ; ++i )
|
|
{
|
|
vtx[i] = *((K3DVertex*)vtxtempbuf);
|
|
vtxtempbuf += stride;
|
|
|
|
// make axis aligned cube
|
|
cube_min.x = _min(cube_min.x , vtx[i].x);
|
|
cube_min.y = _min(cube_min.y , vtx[i].y);
|
|
cube_min.z = _min(cube_min.z , vtx[i].z);
|
|
cube_max.x = _max(cube_max.x , vtx[i].x);
|
|
cube_max.y = _max(cube_max.y , vtx[i].y);
|
|
cube_max.z = _max(cube_max.z , vtx[i].z);
|
|
}
|
|
}
|
|
vb->Unlock();
|
|
// vb->Release();
|
|
res->SetVertices( vtx );
|
|
|
|
res->SetTexture( meshele->GetTexture() );
|
|
|
|
seq->SetRes( res );
|
|
seq->SetCube( cube_min.x, cube_max.x, cube_min.y, cube_max.y, cube_min.z, cube_max.z );
|
|
|
|
return seq;
|
|
}
|
|
|
|
KFXSeq *loadFXParticle( KNX3Mesh *mesh, KNX3FX *fx, DWORD dwType)
|
|
{
|
|
if ( fx->GetFXElementSize() == 0 )
|
|
return NULL;
|
|
KNX3FXElement *fxele = fx->GetFxElementByIndeX(0);
|
|
|
|
if ( mesh->GetMeshElements().size() == 0 )
|
|
return NULL;
|
|
KNX3MeshElement *meshele = mesh->GetMeshElements()[0];
|
|
|
|
if ( meshele->GetFrameCount() == 0 )
|
|
return NULL;
|
|
KNX3MeshFrame *meshfr = meshele->GetFrame(0);
|
|
|
|
K3DVertexBuffer *vb = meshfr->GetVertexBuffer();//Vertex Buffer Add 일어남
|
|
int stride = vb->GetVertexStride();
|
|
int count = vb->GetVertexCount();
|
|
if ( count < 4 )
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
KFXParticleSeq *seq = new KFXParticleSeq(dwType);
|
|
KResFXParticle *res = new KResFXParticle;
|
|
|
|
res->SetRes( mesh->GetMatrixAniRes(), mesh->GetVisibilityRes() );
|
|
|
|
res->SetCreateTime( fxele->GetNumValue( "createtime", 100 ) );
|
|
res->SetBeginSpeed( fxele->GetVectorValue( "beginspeed", K3DVector( 1.f, 1.f, 1.f ) ) );
|
|
res->SetVelocity( fxele->GetVectorValue( "velocity", K3DVector( 1.f, 1.f, 1.f ) ) );
|
|
res->SetSpreadAngle( fxele->GetFloatValue( "angle", 0 ) );
|
|
int base, vari;
|
|
base = 1000; vari = 0;
|
|
fxele->GetVariNumValue( "lifetime", &base, &vari );
|
|
res->SetLifeTime( base, vari );
|
|
|
|
base = 0; vari = 0;
|
|
fxele->GetVariNumValue( "loop", &base, &vari );
|
|
res->SetLoopMode( base != 0 );
|
|
res->SetRange( fxele->GetFrameTime(), vari * 160 );
|
|
|
|
res->SetScale( fxele->Get2DVectorValue( "scale", K3DVector( 1.f, 1.f, 1.f ) ) );
|
|
res->SetAdditiveRenderMode( fxele->GetNumValue( "rendertype", 0 ) != 0 );
|
|
K3DVector ua = fxele->GetVectorValue( "uvani", K3DVector( 0.f, 0.f, 0.f ) );
|
|
res->SetUVAnimation( ua.x > .0f, static_cast<int>(ua.y), static_cast< int >( ua.z ) );
|
|
|
|
res->SetGravityAccel( fxele->GetFloatValue( "gravityaccel", 9.8f) );
|
|
res->SetGravity( fxele->GetVectorValue( "gravityvector", K3DVector( 0.f, 0.f, -1.f)) );
|
|
|
|
int attachparent = fxele->GetNumValue( "attachparent", 0 );
|
|
res->SetAttachParent( ( attachparent == 1 ) );
|
|
|
|
char *vtxtempbuf = NULL;
|
|
K3DVertex vtx[4];
|
|
vb->Lock( (void**)&vtxtempbuf, count );
|
|
if( vtxtempbuf )
|
|
{
|
|
for ( int i=0 ; i<4 ; ++i )
|
|
{
|
|
vtx[i] = *((K3DVertex*)vtxtempbuf);
|
|
vtxtempbuf += stride;
|
|
}
|
|
}
|
|
vb->Unlock();
|
|
// vb->Release();
|
|
res->SetVertices( vtx );
|
|
res->CalcNormal( vtx );
|
|
|
|
res->SetTexture( meshele->GetTexture() );
|
|
seq->SetRes( res );
|
|
return seq;
|
|
}
|
|
|
|
KFXSeq *loadFXAfterImage( KNX3Mesh *mesh, KNX3FX *fx )
|
|
{
|
|
if ( fx->GetFXElementSize() == 0 )
|
|
return NULL;
|
|
KNX3FXElement *fxele = fx->GetFxElementByIndeX(0);
|
|
|
|
if ( mesh->GetMeshElements().size() == 0 )
|
|
return NULL;
|
|
KNX3MeshElement *meshele = mesh->GetMeshElements()[0];
|
|
|
|
if ( meshele->GetFrameCount() == 0 )
|
|
return NULL;
|
|
KNX3MeshFrame *meshfr = meshele->GetFrame(0);
|
|
|
|
K3DVertexBuffer *vb = meshfr->GetVertexBuffer(); //Vertex Buffer Add 일어남
|
|
int stride = vb->GetVertexStride();
|
|
int count = vb->GetVertexCount();
|
|
if ( count < 4 )
|
|
return NULL;
|
|
|
|
KFXAfterImageSeq *seq = new KFXAfterImageSeq;
|
|
KResFXAfterImage *res = new KResFXAfterImage;
|
|
|
|
res->SetRes( mesh->GetMatrixAniRes(), mesh->GetVisibilityRes() );
|
|
int nFrameNumber = max( fxele->GetNumValue( "FrameNumber", 3 ), 1 );
|
|
int nFrameTime = max( fxele->GetNumValue( "FrameTime", 160 ), 1 );
|
|
res->SetFrameNumber( nFrameNumber );
|
|
res->SetFrameTime( nFrameTime );
|
|
res->SetBlendMode( meshele->GetBlendMode() );
|
|
|
|
char *vtxtempbuf = NULL;
|
|
K3DVertex vtx[4];
|
|
vb->Lock( (void**)&vtxtempbuf, count );
|
|
if( vtxtempbuf )
|
|
{
|
|
for ( int i=0 ; i<4 ; ++i )
|
|
{
|
|
vtx[i] = *((K3DVertex*)vtxtempbuf);
|
|
vtxtempbuf += stride;
|
|
}
|
|
}
|
|
vb->Unlock();
|
|
// vb->Release();
|
|
res->SetVertices( vtx );
|
|
|
|
res->SetTexture( meshele->GetTexture() );
|
|
seq->SetRes( res );
|
|
return seq;
|
|
}
|
|
|
|
void loadMesh( std::vector<KSeqObject*> &vecMeshSeq, std::vector<KSeqObject*> &vecFXSeq, std::vector<KSeqObject*> &vecEvSeq, KNX3Mesh *mesh, std::vector<KNX3MeshTM*> &tmList )
|
|
{
|
|
std::vector<KNX3MeshElement*> &meshele = mesh->GetMeshElements();
|
|
|
|
if ( mesh->IsEventBox() )
|
|
{
|
|
K3DResEventBox *pRes = new K3DResEventBox;
|
|
pRes->SetName( mesh->GetMeshName() );
|
|
pRes->SetRes( mesh->GetMeshElements()[0]->GetEventCube(), mesh->GetMatrixAniRes() );
|
|
KEventBoxSeq *pSeq = new KEventBoxSeq;
|
|
pSeq->SetRes( pRes );
|
|
vecEvSeq.push_back( pSeq );
|
|
return;
|
|
}
|
|
|
|
if ( mesh->IsEventPoint() )
|
|
{
|
|
K3DResEventPoint *pResPoint = new K3DResEventPoint;
|
|
pResPoint->SetName( mesh->GetMeshName() );
|
|
pResPoint->SetRes( mesh->GetMatrixAniRes() );
|
|
KEventPointSeq *pSeq = new KEventPointSeq;
|
|
pSeq->SetRes( pResPoint );
|
|
vecEvSeq.push_back( pSeq );
|
|
return;
|
|
}
|
|
|
|
K3DMeshResource *pMeshRes = new K3DMeshResource;
|
|
K3DResVertexAnimation **ppVbAni = new K3DResVertexAnimation*[meshele.size()];
|
|
K3DWeight ** ppWeight = new K3DWeight*[meshele.size()];
|
|
|
|
K3DMatrix * pNodeTM = new K3DMatrix[meshele.size()];
|
|
|
|
if( tmList.size() >0 )
|
|
{
|
|
K3DMeshTM * pMeshTM = new K3DMeshTM[tmList.size()];
|
|
|
|
for( unsigned int i(0); tmList.size()>i; i++ )
|
|
{
|
|
memset( &pMeshTM[i], 0, sizeof(pMeshTM[i]) );
|
|
|
|
memcpy( pMeshTM[i].szName, tmList[i]->szName, sizeof(pMeshTM[i].szName) );
|
|
memcpy( pMeshTM[i].fTM , tmList[i]->baseTM, sizeof(pMeshTM[i].fTM) );
|
|
pMeshTM[i].mTM = K3DMatrix(tmList[i]->baseTM);
|
|
}
|
|
pMeshRes->SetMeshTM( pMeshTM, static_cast<int>(tmList.size()) );
|
|
delete [] pMeshTM;
|
|
}
|
|
|
|
if ( meshele.size() > 0 )
|
|
{
|
|
K3DMatrix iden;
|
|
K3DMatrixIdentity(iden);
|
|
K3DBoundRotCube cube, t_cube;
|
|
for(unsigned int it = 0; it < meshele.size(); ++it )
|
|
{
|
|
t_cube = meshele[it]->GetEventCube();
|
|
t_cube.SetTransform(iden);
|
|
cube.AddCube(t_cube);
|
|
}
|
|
|
|
pMeshRes->SetBound( cube, meshele[0]->GetBoundSphere() );
|
|
}
|
|
pMeshRes->SetName( mesh->GetMeshName() );
|
|
|
|
const char * pName = mesh->GetMeshName();
|
|
|
|
for ( unsigned int n=0 ; n<meshele.size() ; ++n )
|
|
{
|
|
int nUseBoneIndexCount = 0;
|
|
int nWeightCount = 0;
|
|
ppVbAni[n] = new K3DResVertexAnimation;
|
|
ppVbAni[n]->SetIndexBuffer( meshele[n]->GetIndexBuffer() );
|
|
ppVbAni[n]->SetIndexArray ( meshele[n]->GetIndexArray() );
|
|
|
|
ppVbAni[n]->SetPrimitivesInfo(meshele[n]->GetPrimitiveCount(), meshele[n]->GetSimultaneousFrameCount());
|
|
|
|
ppWeight[n] = NULL;
|
|
|
|
KNX3MeshElement *mele = meshele[n];
|
|
ppVbAni[n]->SetKeyCount( mele->GetFrameCount() );
|
|
for ( int j=0 ; j<mele->GetFrameCount() ; ++j )
|
|
{
|
|
KNX3MeshFrame *frame = mele->GetFrame(j);
|
|
K3DResVertexAnimation::Key key;
|
|
key.m_spVB = frame->GetVertexBuffer();
|
|
key.m_spVB_array = frame->GetVertexArray(); //충돌, 높낮이 용
|
|
|
|
key.time = frame->GetFrameTime();
|
|
ppVbAni[n]->SetKey( j, &key ); //Vertex Buffer Add 일어남
|
|
|
|
memcpy( &pNodeTM[n], frame->GetNodeTM(), sizeof(pNodeTM[n]) );
|
|
|
|
//Weight 덩어리가 프레임안에 덩어리루 있다.
|
|
//Weight 값도 추가.
|
|
if( j == 0 ) //처음 프레임에서만, 빼낸다.
|
|
{
|
|
nWeightCount = frame->GetBoneSize(); //가중치 블럭의 수
|
|
if( nWeightCount > 0 )
|
|
{
|
|
if( tmList.size() <= 0 )
|
|
{
|
|
_oprint( "Data Error: Bone weights exist, but the Mesh has no TM. Export failed. Mesh Name %s\n", pName );
|
|
}
|
|
|
|
ppWeight[n] = new K3DWeight[nWeightCount];
|
|
std::vector< KNX3WeightElement * > WeightList = frame->GetWeightList();
|
|
for( size_t a(0); WeightList.size()>a; a++ )
|
|
{
|
|
K3DWeight * pTmp = &(ppWeight[n][a]);
|
|
pTmp->m_nTotal = nWeightCount;
|
|
|
|
//Face Animation이 된다면, 수정해야 한다.
|
|
//사용하는 본의 실제 인덱스...
|
|
nUseBoneIndexCount = frame->GetUseBoneIndexCount();
|
|
if( nUseBoneIndexCount > 0 )
|
|
{
|
|
pTmp->m_nUseBoneCount = nUseBoneIndexCount;
|
|
pTmp->m_pUseBoneList = new int[nUseBoneIndexCount];
|
|
memcpy( pTmp->m_pUseBoneList, frame->GetUseBoneList(), sizeof(int)*nUseBoneIndexCount );
|
|
}
|
|
|
|
KNX3WeightElement * pWE = WeightList[a]; //File 에서 Load 된것
|
|
#ifdef _DEBUG
|
|
K3DWeight * pW = new K3DWeight; //Resource
|
|
pW->m_nWeight = pWE->GetWeightSize();
|
|
strcpy( pTmp->m_szBoneName, pWE->GetBoneName() );
|
|
if( pW->m_nWeight>0 )
|
|
{
|
|
pTmp->m_nWeight= pW->m_nWeight;
|
|
|
|
float* pVertex = pWE->GetVertexIndex();
|
|
float* pWeight = pWE->GetVertexWeight();
|
|
|
|
pW->m_pVertexIndex = new float[pW->m_nWeight];
|
|
pW->m_pVertexWeight = new float[pW->m_nWeight];
|
|
// pW->m_pOffsetVector = new K3DVector[pW->m_nWeight];
|
|
|
|
pTmp->m_pVertexIndex = new float[pW->m_nWeight];
|
|
pTmp->m_pVertexWeight = new float[pW->m_nWeight];
|
|
|
|
for( int n(0); pW->m_nWeight>n; n++ )
|
|
{
|
|
pW->m_pVertexIndex[n] = pVertex[n];
|
|
pW->m_pVertexWeight[n] = pWeight[n];
|
|
pTmp->m_pVertexIndex[n] = pVertex[n];
|
|
pTmp->m_pVertexWeight[n] = pWeight[n];
|
|
}
|
|
// memcpy( pW->m_pVertexIndex , pWE->GetVertexIndex() , sizeof(float)*pW->m_nWeight );
|
|
// memcpy( pW->m_pVertexWeight, pWE->GetVertexWeight(), sizeof(float)*pW->m_nWeight );
|
|
//// memcpy( pW->m_pOffsetVector, pWE->GetOffSetVector(), sizeof(K3DVector)*pW->m_nWeight );
|
|
|
|
// memcpy( pTmp->m_pVertexIndex , pWE->GetVertexIndex() , sizeof(float)*pW->m_nWeight );
|
|
// memcpy( pTmp->m_pVertexWeight, pWE->GetVertexWeight(), sizeof(float)*pW->m_nWeight );
|
|
//// memcpy( pTmp->m_pOffsetVector, pWE->GetOffSetVector(), sizeof(K3DVector)*pW->m_nWeight );
|
|
}
|
|
delete pW;
|
|
#else
|
|
if( pWE->GetWeightSize()>0 )
|
|
{
|
|
pTmp->m_nWeight = pWE->GetWeightSize();
|
|
strcpy( pTmp->m_szBoneName, pWE->GetBoneName() );
|
|
|
|
pTmp->m_pVertexIndex = new float[pWE->GetWeightSize()];
|
|
pTmp->m_pVertexWeight = new float[pWE->GetWeightSize()];
|
|
// pTmp->m_pOffsetVector = new K3DVector[pWE->GetWeightSize()];
|
|
|
|
//Face Animation이 된다면, 수정해야 한다.
|
|
nUseBoneIndexCount = frame->GetUseBoneIndexCount();
|
|
if( nUseBoneIndexCount > 0 )
|
|
{
|
|
SAFE_DELETE_ARRAY(pTmp->m_pUseBoneList);
|
|
pTmp->m_nUseBoneCount = nUseBoneIndexCount;
|
|
pTmp->m_pUseBoneList = new int[nUseBoneIndexCount];
|
|
memcpy( pTmp->m_pUseBoneList, frame->GetUseBoneList(), sizeof(int)*nUseBoneIndexCount );
|
|
}
|
|
|
|
memcpy( pTmp->m_pVertexIndex , pWE->GetVertexIndex() , sizeof(float)*pWE->GetWeightSize() );
|
|
memcpy( pTmp->m_pVertexWeight, pWE->GetVertexWeight(), sizeof(float)*pWE->GetWeightSize() );
|
|
// memcpy( pTmp->m_pOffsetVector, pWE->GetOffSetVector(), sizeof(K3DVector)*pWE->GetWeightSize() );
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
}
|
|
ppVbAni[n]->SetBlendMode( mele->GetBlendMode() );
|
|
ppVbAni[n]->SetMaterial( mele->GetMaterial() );
|
|
|
|
TEXPACK texpack;
|
|
texpack.spTexture = mele->GetTexture();
|
|
texpack.spTexture_Bump = mele->GetBumpTexture();
|
|
texpack.spTexture_Illumin = mele->GetIlluminTexture();
|
|
texpack.spTexture_Specular = mele->GetSpecularTexture();
|
|
#ifdef _SPECULAR_EDITING_
|
|
texpack.spTexture_SpecularColor = mele->GetSpecularColorTexture();
|
|
#else
|
|
texpack.spTexture_SpecularColor = mele->GetSpecularColorTexture();
|
|
#endif
|
|
|
|
ppVbAni[n]->SetTexturePack( &texpack );
|
|
ppVbAni[n]->SetLightMapIndex( mele->GetLightMapIndex() );
|
|
// ppVbAni[n]->SetTexture( mele->GetTexture(), mele->GetSpecularTexture(), mele->GetSpecularColorTexture(), mele->GetIlluminTexture() );
|
|
}
|
|
pMeshRes->SetWeightResource( ppWeight, static_cast<int>(meshele.size()) );
|
|
pMeshRes->SetVBResource( ppVbAni, static_cast<int>(meshele.size()) );
|
|
pMeshRes->SetNodeTM( pNodeTM, static_cast<int>(meshele.size()) );
|
|
delete[] ppVbAni;
|
|
delete[] ppWeight; //Weight 임시 담아 놓은곳.
|
|
delete[] pNodeTM;
|
|
|
|
if ( mesh->IsFX() )
|
|
{
|
|
KNX3FX *fx = mesh->GetFXVector()[0];
|
|
const char *value = fx->GetFxElementByIndeX( 0 )->GetValue( "NXFX" );
|
|
if ( _stricmp( value, "particle" ) == 0 )
|
|
{
|
|
KFXSeq *seq = loadFXParticle( mesh, fx, KFXParticleSeq::KPARTICLE_DEFAULT);
|
|
if ( seq ) vecFXSeq.push_back( seq );
|
|
}
|
|
else if ( _stricmp( value, "billboard" ) == 0 )
|
|
{
|
|
KFXSeq *seq = loadFXBillboard( mesh, fx );
|
|
if ( seq ) vecFXSeq.push_back( seq );
|
|
}
|
|
else if ( _stricmp( value, "gravity_particle" ) == 0 )
|
|
{
|
|
KFXSeq *seq = loadFXParticle( mesh, fx ,KFXParticleSeq::KPARTICLE_GRAVITY);
|
|
if ( seq ) vecFXSeq.push_back( seq );
|
|
}
|
|
else if ( _stricmp( value, "reverse_particle" ) == 0 )
|
|
{
|
|
KFXSeq *seq = loadFXParticle( mesh, fx, KFXParticleSeq::KPARTICLE_REVERSE );
|
|
if ( seq ) vecFXSeq.push_back( seq );
|
|
}
|
|
else if ( _stricmp( value, "after_image" ) == 0 )
|
|
{
|
|
KFXSeq *seq = loadFXAfterImage( mesh, fx );
|
|
if ( seq ) vecFXSeq.push_back( seq );
|
|
}
|
|
|
|
pMeshRes->Discard();
|
|
}
|
|
else
|
|
{
|
|
KMeshSeqObject *meshSeq = new KMeshSeqObject;
|
|
|
|
meshSeq->SetMeshRes( pMeshRes );
|
|
|
|
meshSeq->SetMatrixRes( mesh->GetMatrixAniRes() );
|
|
meshSeq->SetVisibilityRes( mesh->GetVisibilityRes() );
|
|
meshSeq->SetUVAniRes( mesh->GetUVAniRes() );
|
|
|
|
vecMeshSeq.push_back( meshSeq );
|
|
|
|
std::vector<KNX3Mesh*> childmeshes = mesh->GetChild();
|
|
for ( unsigned int i=0 ; i<childmeshes.size() ; ++i )
|
|
{
|
|
loadMesh( vecMeshSeq, vecFXSeq, vecEvSeq, childmeshes[i], tmList );
|
|
}
|
|
}
|
|
}
|
|
|
|
struct KStreamPtr
|
|
{
|
|
KStreamPtr( KStream& st ) : stream( st ) { ptr = st.GetMappedPtr(0); }
|
|
~KStreamPtr() { stream.FreeMappedPtr( ptr ); }
|
|
KStream& stream;
|
|
void* ptr;
|
|
};
|
|
|
|
bool loadNX3( const char * szName, const NX3LoadPack * plodpack, KStream &stream, NX3SET *nx3set )
|
|
{
|
|
unsigned unStartTime = GetSafeTickCount();
|
|
|
|
KNX3ChannelControl nxloader;
|
|
|
|
if ( trf::IsTRFStream( stream ) )
|
|
{
|
|
try
|
|
{
|
|
KStreamPtr ptr( stream );
|
|
trf::Mapper mapper( &KNX3Manager::GetManager()->GetMetaData(), ptr.ptr, stream.GetLength() );
|
|
if ( !nxloader.LoadTRF( plodpack, KDeviceManager::GetDeviceManager()->GetRenderDevice(), mapper.root(), szName ) )
|
|
return false;
|
|
}
|
|
catch ( trf::Exception& /* e */)
|
|
{
|
|
#ifdef _DEBUG
|
|
assert( 0 && "화일 Load Fail. 담당자에게 알려!!!" );
|
|
#endif
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
KBinaryFiler filer;
|
|
if ( !filer.Load( stream ) )
|
|
{
|
|
#ifdef _DEBUG
|
|
assert( 0 && "화일 Load Fail. 담당자에게 알려!!!" );
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
if ( !nxloader.Load( plodpack, KDeviceManager::GetDeviceManager()->GetRenderDevice(), &filer, szName ) )
|
|
return false;
|
|
}
|
|
|
|
nx3set->strProperty = nxloader.GetPropertyString();
|
|
|
|
KNX3MeshChannel *meshch = nxloader.GetMeshChannel();
|
|
if ( meshch )
|
|
{
|
|
std::vector<KSeqObject*> vecMeshSeq;
|
|
std::vector<KSeqObject*> vecFXSeq;
|
|
std::vector<KSeqObject*> vecEvSeq;
|
|
std::vector<KNX3Mesh*> &meshlist = meshch->GetMeshList();
|
|
|
|
for ( size_t i=0 ; i<meshlist.size() ; ++i )
|
|
{
|
|
loadMesh( nx3set->vpMeshSeq, nx3set->vpFXSeq, nx3set->vpEventSeq, meshlist[i], meshch->GetMeshTMList() );
|
|
}
|
|
}
|
|
|
|
KNX3CameraChannel *camch = nxloader.GetCameraChannel();
|
|
if ( camch )
|
|
{
|
|
K3DResCamera *camres = camch->GetCameraRes();
|
|
KCameraSeq *camseq = new KCameraSeq;
|
|
camseq->SetRes( camres );
|
|
nx3set->vpCamSeq.push_back( camseq );
|
|
}
|
|
|
|
// Light
|
|
KNX3LightChannel *litch = nxloader.GetLightChannel();
|
|
if ( litch )
|
|
{
|
|
for ( int n=0 ; n<litch->GetLightCount(); ++n )
|
|
{
|
|
KLightSeq* p = new KLightSeq;
|
|
p->SetRes( litch->GetLight(n)->GetLightRes() );
|
|
nx3set->vpLightSeq.push_back( p );
|
|
}
|
|
|
|
}
|
|
|
|
//Bone 작업 중..
|
|
KNX3BoneChannel * bonech = nxloader.GetBoneChannel();
|
|
if( bonech )
|
|
{
|
|
//이런식으로 되야 된다.
|
|
K3DBoneResource *boneres = bonech->GetBoneRes();
|
|
KBoneSeqObject *boneseq = new KBoneSeqObject;
|
|
|
|
boneseq->SetRes( boneres );
|
|
nx3set->vpBoneSeq.push_back( boneseq );
|
|
}
|
|
|
|
#ifdef _KPATH_EFFECT
|
|
// PathEffect
|
|
KNX3PfxChannel* pfxch = nxloader.GetPfxChannel();
|
|
if(pfxch)
|
|
{
|
|
KResPathEffectChain* pfxres = pfxch->GetRes();
|
|
KSeqPathEffectChain* pfxseq = new KSeqPathEffectChain;
|
|
|
|
pfxseq->SetRes(pfxres);
|
|
nx3set->vpPfxSeq.push_back(pfxseq);
|
|
}
|
|
#endif
|
|
|
|
DWORD dwLoadTime = GetSafeTickCount() - unStartTime;
|
|
if( dwLoadTime > 60 )
|
|
{
|
|
_oprint( "NX3 Load : %s (%dms) (%dKB) ThreadId:%d\n", szName, dwLoadTime, stream.GetLength()/1024, GetCurrentThreadId() );
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//KSpriteManager::SPRITE_SET Implement
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
SPRITE_SET::SPRITE_SET()
|
|
{
|
|
|
|
}
|
|
SPRITE_SET::~SPRITE_SET()
|
|
{
|
|
m_resByAniName.clear();
|
|
m_vtResSpriteAni.clear();
|
|
}
|
|
|
|
|
|
int SPRITE_SET::GetResCount()
|
|
{
|
|
return static_cast<int>(m_vtResSpriteAni.size());
|
|
}
|
|
|
|
int SPRITE_SET::GetSpriteResAniCount( LPCSTR lpszAniName )
|
|
{
|
|
KResSpriteAnimation *resani = GetSpriteResAni( lpszAniName );
|
|
|
|
if ( resani )
|
|
return resani->GetKeyCount();
|
|
return 0;
|
|
}
|
|
|
|
void SPRITE_SET::EraseSpriteResAni( LPCSTR lpszAniName )
|
|
{
|
|
std::vector<KResSpriteAnimationSPtr>::iterator it = m_vtResSpriteAni.begin();
|
|
while( it != m_vtResSpriteAni.end() )
|
|
{
|
|
if( ::_stricmp( lpszAniName, (*it)->GetName() ) == 0 )
|
|
{
|
|
m_vtResSpriteAni.erase( it );
|
|
m_resByAniName.erase( lpszAniName );
|
|
break;
|
|
}
|
|
++it;
|
|
}
|
|
}
|
|
|
|
KResSpriteAnimation* SPRITE_SET::GetSpriteResAni( int nIndex)
|
|
{
|
|
return m_vtResSpriteAni.at(nIndex);
|
|
}
|
|
KResSpriteAnimation* SPRITE_SET::GetSpriteResAni( LPCSTR lpszAniName)
|
|
{
|
|
KResSpriteAnimation* pAni = NULL;
|
|
m_resByAniName.lookup(lpszAniName, pAni);
|
|
return pAni;
|
|
}
|
|
|
|
KResSprite* SPRITE_SET::GetSpriteRes(LPCSTR lpszAniName, int nIndex)
|
|
{
|
|
KResSpriteAnimation * pAni;
|
|
if( m_resByAniName.lookup(lpszAniName, pAni ) )
|
|
{
|
|
if( pAni && !pAni->IsLoaded() )
|
|
{
|
|
KUITextureManager::GetManager()->GetSprAni( m_strResName.c_str(), lpszAniName );
|
|
}
|
|
|
|
return (pAni) ? pAni->GetSpriteByFrame(nIndex) : NULL;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void SPRITE_SET::AddResSpriteAni(KResSpriteAnimation * pRes)
|
|
{
|
|
if( GetSpriteResAni( pRes->GetName() ) )
|
|
{
|
|
ModifyResSpriteAni( pRes );
|
|
return;
|
|
}
|
|
|
|
|
|
THREAD_SYNCRONIZE( g_SpriteAniCS );
|
|
|
|
m_vtResSpriteAni.push_back(KResSpriteAnimationSPtr( pRes ) );
|
|
m_resByAniName.add(pRes->GetName(), pRes);
|
|
}
|
|
|
|
void SPRITE_SET::ModifyResSpriteAni( KResSpriteAnimation* pRes )
|
|
{
|
|
std::vector<KResSpriteAnimationSPtr>::iterator it = m_vtResSpriteAni.begin();
|
|
while( it != m_vtResSpriteAni.end() )
|
|
{
|
|
if( ::_stricmp( pRes->GetName(), (*it)->GetName() ) == 0 )
|
|
{
|
|
(*it)->SetKeyCount( pRes->GetKeyCount() );
|
|
for( int i = 0; i < pRes->GetKeyCount(); i++ )
|
|
{
|
|
KResSpriteAnimation::Key key = pRes->GetKey(i);
|
|
(*it)->SetKey(i, &key );
|
|
}
|
|
|
|
return;
|
|
}
|
|
it++;
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//KSpriteManager Implement
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
KSpriteManager *KSingletoneResourceManager<KSpriteManager>::s_pStaticManager = new KSpriteManager;
|
|
KSpriteManager::KSpriteManager()
|
|
{
|
|
// - prodongi
|
|
#ifdef SPR_LIST_EXTRACTOR
|
|
m_sprListExtractor.initialize();
|
|
#endif
|
|
}
|
|
|
|
KSpriteManager::~KSpriteManager()
|
|
{
|
|
DiscardAll();
|
|
// - prodongi
|
|
#ifdef SPR_LIST_EXTRACTOR
|
|
m_sprListExtractor.closeFile();
|
|
#endif
|
|
}
|
|
|
|
#define MAX_SPR_LIST (6)
|
|
static char * sprArrays[MAX_SPR_LIST] = {
|
|
"01_equip.spr",
|
|
"02_item.spr",
|
|
"03_skill.spr",
|
|
"04_event.spr",
|
|
"05_ui.spr",
|
|
"06_live.spr"
|
|
};
|
|
|
|
bool KSpriteManager::LoadSpriteSet( const char *resname )
|
|
{
|
|
SPRITE_SET *pSet = new SPRITE_SET;
|
|
if (!pSet)
|
|
return false;
|
|
|
|
for (int i=0; i<MAX_SPR_LIST; i++)
|
|
{
|
|
KStream * stream = KFileManager::Instance().CreateStreamFromResource(sprArrays[i]);
|
|
if (stream)
|
|
{
|
|
THREAD_SYNCRONIZE(g_SpriteAniCS);
|
|
|
|
OutputDebugString("Loading Sprite - ");
|
|
OutputDebugString(sprArrays[i]);
|
|
OutputDebugString("\r\n");
|
|
|
|
KSpriteLoader sprloader;
|
|
if (sprloader.Load(*stream))
|
|
{
|
|
int count = sprloader.GetResCount();
|
|
// 2010.04.29 i -> j - prodongi
|
|
//for ( int i=0 ; i<count ; ++i )
|
|
for ( int j=0 ; j<count ; ++j )
|
|
{
|
|
// prodongi
|
|
KResSpriteAnimation *pRes = sprloader.GetRes(j);
|
|
pSet->AddResSpriteAni(pRes);
|
|
|
|
// - prodongi
|
|
#ifdef SPR_LIST_EXTRACTOR
|
|
m_sprListExtractor.extract(pRes, sprArrays[i]);
|
|
#endif
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SAFE_DELETE(pSet);
|
|
return false;
|
|
}
|
|
|
|
KFileManager::Instance().DeleteStream(stream);
|
|
stream = NULL;
|
|
}
|
|
}
|
|
|
|
pSet->m_strResName = resname;
|
|
m_setByName.add(resname, pSet);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
SPRITE_SET* KSpriteManager::GetSpriteSet( const char *resname )
|
|
{
|
|
SPRITE_SET *pSet = NULL;
|
|
if( m_setByName.lookup( resname, pSet ) == false )
|
|
{
|
|
KStream *stream = KFileManager::Instance().CreateStreamFromResource( resname );
|
|
if ( stream )
|
|
{
|
|
THREAD_SYNCRONIZE( g_SpriteAniCS );
|
|
|
|
OutputDebugString( "Loading Sprite - " );
|
|
OutputDebugString( resname );
|
|
OutputDebugString( "\r\n" );
|
|
|
|
pSet = new SPRITE_SET;
|
|
if ( _LoadSpriteSet( *stream, pSet ) )
|
|
{
|
|
|
|
_AddSpriteSet( resname, pSet );
|
|
}
|
|
else
|
|
{
|
|
SAFE_DELETE(pSet);
|
|
}
|
|
|
|
KFileManager::Instance().DeleteStream( stream );
|
|
stream = NULL;
|
|
}
|
|
}
|
|
return pSet;
|
|
}
|
|
|
|
|
|
|
|
SPRITE_SET *KSpriteManager::GetSpriteSet( KStream &Stream, const char *resname )
|
|
{
|
|
SPRITE_SET *pSet = NULL;
|
|
if( m_setByName.lookup( resname, pSet ) == false )
|
|
{
|
|
THREAD_SYNCRONIZE( g_SpriteAniCS );
|
|
|
|
pSet = new SPRITE_SET;
|
|
if ( _LoadSpriteSet( Stream, pSet ) )
|
|
{
|
|
_AddSpriteSet( resname, pSet );
|
|
}
|
|
else
|
|
{
|
|
SAFE_DELETE(pSet);
|
|
}
|
|
}
|
|
return pSet;
|
|
}
|
|
|
|
bool GetIconAniName( const char * pFileName, std::string & strOutAniName )
|
|
{
|
|
std::string strAniName = pFileName;
|
|
|
|
std::string::size_type pos = strAniName.rfind( '.' );
|
|
if( pos != std::string::npos )
|
|
{
|
|
strAniName.erase( pos, strAniName.length()-pos ); //확장자 제거
|
|
pos = std::string::npos;
|
|
|
|
pos = strAniName.rfind( '\\' );
|
|
if( pos != std::string::npos )
|
|
{
|
|
strAniName.erase( 0, pos+1 ); //폴더 제거
|
|
}
|
|
else
|
|
{
|
|
assert(0);
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
assert(0);
|
|
return false;
|
|
}
|
|
|
|
strOutAniName = strAniName;
|
|
return true;
|
|
}
|
|
|
|
void KSpriteManager::AddIconSprite( const char *resname, const char *file_name, bool bEncrypt, bool bUseColorKey, KColor color, bool bLoad )
|
|
{
|
|
SPRITE_SET *pSet = NULL;
|
|
if( m_setByName.lookup( resname, pSet ) == false )
|
|
{
|
|
THREAD_SYNCRONIZE( g_SpriteAniCS );
|
|
|
|
pSet = new SPRITE_SET;
|
|
|
|
_AddSpriteSet( resname, pSet); //스프라이트 셋트 등록
|
|
_AddSpriteAnimation( file_name, pSet, bEncrypt, bUseColorKey, color ); //개별 리소스 등록
|
|
}
|
|
|
|
if( pSet )
|
|
{
|
|
std::string strAniName;
|
|
if( !GetIconAniName( file_name, strAniName ) )
|
|
return;
|
|
|
|
//기존에 있는 것은
|
|
if( !pSet->GetSpriteResAni( strAniName.c_str() ) )
|
|
{
|
|
//_AddSpriteAnimation( file_name, pSet, bEncrypt, bUseColorKey, color ); //개별 리소스 등록
|
|
_AddSpriteAnimation( file_name, pSet, bEncrypt, bUseColorKey, color, bLoad ); // 수정. bintitle.
|
|
}
|
|
|
|
//if( bLoad )
|
|
//{
|
|
// //기존에 있는 것은
|
|
// if( pSet->GetSpriteResAni( strAniName.c_str() ) )
|
|
// {
|
|
// pSet->EraseSpriteResAni( strAniName.c_str() ); // 기존 스프라이트 제거.
|
|
//
|
|
// _AddSpriteAnimation( file_name, pSet, bEncrypt, bUseColorKey, color, bLoad ); // 수정. bintitle.
|
|
// }
|
|
//}
|
|
//else
|
|
//{
|
|
// //기존에 있는 것은
|
|
// if( !pSet->GetSpriteResAni( strAniName.c_str() ) )
|
|
// {
|
|
// //_AddSpriteAnimation( file_name, pSet, bEncrypt, bUseColorKey, color ); //개별 리소스 등록
|
|
// _AddSpriteAnimation( file_name, pSet, bEncrypt, bUseColorKey, color, bLoad ); // 수정. bintitle.
|
|
// }
|
|
//}
|
|
}
|
|
}
|
|
|
|
void KSpriteManager::_AddSpriteAnimation( const char *file_name, SPRITE_SET *pSet, bool bEncrypt, bool bUseColorKey, KColor color, bool bLoad )
|
|
{
|
|
KSpriteLoader sprloader;
|
|
//sprloader.Load_Icon( file_name );
|
|
|
|
if( bLoad )
|
|
sprloader.Load_IconEx( file_name );
|
|
else
|
|
sprloader.Load_Icon( file_name );
|
|
|
|
int count = sprloader.GetResCount();
|
|
for ( int i=0 ; i<count ; ++i )
|
|
{
|
|
KResSpriteAnimation *pRes = sprloader.GetRes(i);
|
|
pRes->SetEncrypt( bEncrypt );
|
|
pRes->SetUseColorKey( bUseColorKey );
|
|
pRes->SetColorKey( color );
|
|
|
|
pSet->AddResSpriteAni(pRes);
|
|
}
|
|
}
|
|
|
|
KResSpriteAnimation* KSpriteManager::GetResSpriteAni(LPCSTR lpszSprName, LPCSTR lpszAniName)
|
|
{
|
|
SPRITE_SET *pSet = GetSpriteSet(lpszSprName);
|
|
|
|
if(pSet)
|
|
{
|
|
return pSet->GetSpriteResAni(lpszAniName);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
int KSpriteManager::GetAnimationFrameCount(LPCSTR lpszSprName, LPCSTR lpszAniName)
|
|
{
|
|
KResSpriteAnimation * pRes = GetResSpriteAni(lpszSprName,lpszAniName);
|
|
|
|
if(pRes)
|
|
return pRes->GetKeyCount();
|
|
|
|
return 0;
|
|
}
|
|
KResSprite* KSpriteManager::GetResSprite(LPCSTR lpszSprName, LPCSTR lpszAniName,int nIndex)
|
|
{
|
|
SPRITE_SET *pSet = GetSpriteSet(lpszSprName);
|
|
|
|
if(pSet)
|
|
{
|
|
KResSpriteAnimation * pRes = pSet->GetSpriteResAni( lpszAniName );
|
|
if( pRes && !pRes->IsLoaded() )
|
|
{
|
|
KUITextureManager::GetManager()->GetSprAni( lpszSprName, lpszAniName );
|
|
}
|
|
|
|
return pSet->GetSpriteRes(lpszAniName,nIndex);
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
// Set 자체를 Reference 하는 객체는 없으므로 이렇게 써도 무방할 듯 하다.
|
|
void KSpriteManager::ReleaseSpriteSet(LPCSTR lpszSprName)
|
|
{
|
|
THREAD_SYNCRONIZE( g_SpriteAniCS );
|
|
|
|
SPRITE_SET *pSet;
|
|
|
|
if ( m_setByName.lookup( lpszSprName, pSet ) == true )
|
|
{
|
|
m_setByName.erase( lpszSprName );
|
|
SAFE_DELETE(pSet);
|
|
}
|
|
|
|
|
|
}
|
|
|
|
void KSpriteManager::PrintList( const char * pOutFileName )
|
|
{
|
|
|
|
}
|
|
|
|
void KSpriteManager::ReloadRes( bool bRepair )
|
|
{
|
|
}
|
|
|
|
void KSpriteManager::DiscardAll()
|
|
{
|
|
SPRITE_SET *pSet;
|
|
bool bRet;
|
|
|
|
THREAD_SYNCRONIZE( g_SpriteAniCS );
|
|
|
|
bRet = m_setByName.get_first_value( pSet );
|
|
while ( bRet )
|
|
{
|
|
SAFE_DELETE(pSet);
|
|
bRet = m_setByName.get_next_value( pSet );
|
|
}
|
|
m_setByName.clear();
|
|
|
|
|
|
}
|
|
|
|
bool KSpriteManager::_LoadSpriteSet( KStream &stream, SPRITE_SET *pSet)
|
|
{
|
|
KSpriteLoader sprloader;
|
|
if ( sprloader.Load( stream ) )
|
|
{
|
|
int count = sprloader.GetResCount();
|
|
for ( int i=0 ; i<count ; ++i )
|
|
{
|
|
KResSpriteAnimation *pRes = sprloader.GetRes(i);
|
|
pSet->AddResSpriteAni(pRes);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool KSpriteManager::_AddSpriteSet( const char *name, SPRITE_SET *pSet)
|
|
{
|
|
THREAD_SYNCRONIZE( g_SpriteAniCS );
|
|
|
|
pSet->m_strResName = name;
|
|
m_setByName.add( name, pSet );
|
|
|
|
return true;
|
|
}
|
|
|
|
// - prodongi
|
|
#ifdef SPR_LIST_EXTRACTOR
|
|
|
|
void sSprListExtractor::initialize()
|
|
{
|
|
assert(!m_file);
|
|
m_file = fopen ("spr.ini", "w");
|
|
if (!m_file)
|
|
{
|
|
assert(0 && "failed create spr.ini file");
|
|
return ;
|
|
}
|
|
|
|
assert(!m_dupliFile);
|
|
m_dupliFile = fopen ("spr_dupli.ini", "w");
|
|
if (!m_dupliFile)
|
|
{
|
|
assert(0 && "failed create spr_dupli.ini file");
|
|
return ;
|
|
}
|
|
}
|
|
|
|
void sSprListExtractor::extract(KResSpriteAnimation *res, char const* sprName)
|
|
{
|
|
std::map<std::string, std::string>::iterator it_m;
|
|
std::vector<std::string>::const_iterator it = res->GetFrame().begin();
|
|
for (; it != res->GetFrame().end(); ++it)
|
|
{
|
|
it_m = m_list.find(it->c_str());
|
|
if (it_m == m_list.end())
|
|
{
|
|
fwrite(it->c_str(), it->length(), 1, m_file);
|
|
fwrite("\n", strlen("\n"), 1, m_file);
|
|
m_list.insert(std::make_pair(*it, sprName));
|
|
}
|
|
else
|
|
{
|
|
sprintf(m_temp, "%s\t, cur:%s, ori:%s", it->c_str(), sprName, it_m->second.c_str());
|
|
fwrite(m_temp, strlen(m_temp), 1, m_dupliFile);
|
|
fwrite("\n", strlen("\n"), 1, m_dupliFile);
|
|
}
|
|
}
|
|
}
|
|
|
|
void sSprListExtractor::closeFile()
|
|
{
|
|
if (m_file) fclose(m_file);
|
|
if (m_dupliFile) fclose(m_dupliFile);
|
|
}
|
|
|
|
#endif |