Files
2026-06-01 12:46:52 +02:00

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