522 lines
22 KiB
C++
522 lines
22 KiB
C++
#include "StdAfx.h"
|
||
#include "EtAni.h"
|
||
#include "EtBone.h"
|
||
#include "EtSaveMat.h"
|
||
#include "DebugSet.h"
|
||
|
||
#ifdef _DEBUG
|
||
#define new new(_NORMAL_BLOCK,__FILE__,__LINE__)
|
||
#endif
|
||
|
||
CEtAni::CEtAni(void)
|
||
{
|
||
memset( &m_AniHeader, 0, sizeof(SAniFileHeader) );
|
||
}
|
||
|
||
CEtAni::~CEtAni(void)
|
||
{
|
||
Clear();
|
||
}
|
||
|
||
void CEtAni::Clear()
|
||
{
|
||
SAFE_DELETE_PVEC( m_vecBone );
|
||
}
|
||
|
||
int CEtAni::GetBoneIndex( const char *pBoneName )
|
||
{
|
||
int i;
|
||
|
||
if( strlen( pBoneName ) <= 0 )
|
||
{
|
||
return -1;
|
||
}
|
||
|
||
if( IsReady() )
|
||
{
|
||
for( i = 0; i < ( int )m_vecBone.size(); i++ )
|
||
{
|
||
if( stricmp( pBoneName, m_vecBone[ i ]->GetName() ) == 0 )
|
||
{
|
||
return i;
|
||
}
|
||
}
|
||
|
||
return -1;
|
||
}
|
||
else
|
||
{
|
||
for( i = 0; i < ( int )m_vecCacheBoneName.size(); i++ )
|
||
{
|
||
if( stricmp( pBoneName, m_vecCacheBoneName[ i ].szBoneName.c_str() ) == 0 )
|
||
{
|
||
return ( i + 1 ) << 16;
|
||
}
|
||
}
|
||
m_vecCacheBoneName.resize( m_vecCacheBoneName.size() + 1 );
|
||
m_vecCacheBoneName.back().szBoneName = pBoneName;
|
||
m_vecCacheBoneName.back().nBoneIndex = -1;
|
||
return ( ( ( int )m_vecCacheBoneName.size() ) << 16 );
|
||
}
|
||
}
|
||
|
||
CEtBone *CEtAni::GetBone( int nIndex )
|
||
{
|
||
if( nIndex > 65535 )
|
||
{
|
||
if( !IsReady() )
|
||
{
|
||
return NULL;
|
||
}
|
||
|
||
int nBoneIndex;
|
||
nBoneIndex = ( nIndex >> 16 ) - 1;
|
||
return m_vecBone[ m_vecCacheBoneName[ nBoneIndex ].nBoneIndex ];
|
||
}
|
||
else
|
||
{
|
||
if( nIndex < 0 || nIndex >= (int)m_vecBone.size() ) {
|
||
ASSERT( 0 && "본 인덱스로 구하는데 없는 인덱스입니다." );
|
||
return NULL;
|
||
}
|
||
return m_vecBone[ nIndex ];
|
||
}
|
||
}
|
||
|
||
CEtBone *CEtAni::FindBone( const char *pBoneName )
|
||
{
|
||
if( !IsReady() )
|
||
{
|
||
return NULL;
|
||
}
|
||
|
||
int nBoneIndex;
|
||
|
||
nBoneIndex = GetBoneIndex( pBoneName );
|
||
if( nBoneIndex == -1 )
|
||
{
|
||
return NULL;
|
||
}
|
||
|
||
return m_vecBone[ nBoneIndex ];
|
||
}
|
||
|
||
int CEtAni::ConvertBoneIndex( int nIndex )
|
||
{
|
||
if( nIndex > 65535 )
|
||
{
|
||
return m_vecCacheBoneName[ ( nIndex >> 16 ) - 1 ].nBoneIndex;
|
||
}
|
||
return nIndex;
|
||
}
|
||
|
||
int CEtAni::LoadAni( CStream *pStream )
|
||
{
|
||
int i;
|
||
CEtBone *pBone;
|
||
char szAniName[ 256 ];
|
||
|
||
Clear();
|
||
pStream->Read( &m_AniHeader, sizeof( SAniFileHeader ) );
|
||
pStream->Seek( ANI_HEADER_RESERVED, SEEK_CUR );
|
||
|
||
if( strstr( m_AniHeader.szHeaderString, ANI_FILE_STRING ) == NULL ) return ETERR_FILENOTFOUND;
|
||
|
||
if(m_AniHeader.nVersion > ANI_FILE_VERSION)
|
||
{
|
||
CDebugSet::ToLogFile("EtAni ::127 , Ani version file > 11");
|
||
}
|
||
|
||
for( i = 0; i < m_AniHeader.nAniCount; i++ )
|
||
{
|
||
pStream->Read( szAniName, 256 );
|
||
m_vecAniName.push_back( szAniName );
|
||
}
|
||
|
||
m_vecAniLength.resize( m_AniHeader.nAniCount );
|
||
pStream->Read( &m_vecAniLength[ 0 ], sizeof( int ) * m_AniHeader.nAniCount );
|
||
|
||
for( i = 0; i < m_AniHeader.nBoneCount; i++ )
|
||
{
|
||
pBone = new CEtBone();
|
||
pBone->LoadBone( pStream, m_AniHeader.nAniCount, m_AniHeader.nVersion );
|
||
m_vecBone.push_back( pBone );
|
||
pBone->SetBoneIndex( i );
|
||
}
|
||
|
||
BuildHierarchy();
|
||
for( i = 0; i < m_AniHeader.nBoneCount; i++ )
|
||
{
|
||
if( m_vecBone[ i ]->GetParent() == NULL )
|
||
{
|
||
m_vecBone[ i ]->SetRootBone( true );
|
||
}
|
||
}
|
||
|
||
SetReady( true );
|
||
for( i = 0; i < ( int )m_vecCacheBoneName.size(); i++ )
|
||
{
|
||
m_vecCacheBoneName[ i ].nBoneIndex = GetBoneIndex( m_vecCacheBoneName[ i ].szBoneName.c_str() );
|
||
}
|
||
|
||
return ET_OK;
|
||
}
|
||
|
||
int CEtAni::LoadMultiAni( CStream *pStream )
|
||
{
|
||
int nSize = pStream->Size();
|
||
char *pBuffer = new char[ nSize + 1 ];
|
||
|
||
memset( pBuffer, 0, nSize + 1 );
|
||
pStream->Read( pBuffer, nSize );
|
||
|
||
char *pToken = strtok( pBuffer, "\n\r" );
|
||
while( pToken )
|
||
{
|
||
if( m_vecBone.size() )
|
||
{
|
||
EtAniHandle hLoadAni = ::LoadResource( pToken, RT_ANI, false );
|
||
if( hLoadAni )
|
||
{
|
||
MergeAni( hLoadAni );
|
||
hLoadAni->SetDeleteImmediate( true );
|
||
SAFE_RELEASE_SPTR( hLoadAni );
|
||
}
|
||
}
|
||
else
|
||
{
|
||
CResMngStream *pMainResource = dynamic_cast< CResMngStream * >( pStream );
|
||
if( pMainResource )
|
||
{
|
||
char szFileName[ _MAX_PATH ] = { 0 };
|
||
const char *szOriginalPath = pMainResource->GetAddPath();
|
||
int nLen = (int)strlen(szOriginalPath);
|
||
if( nLen > 0 ) {
|
||
strcpy_s( szFileName, _MAX_PATH, szOriginalPath );
|
||
strcat_s( szFileName, _MAX_PATH, "\\" );
|
||
}
|
||
strcat_s( szFileName, _MAX_PATH, pToken );
|
||
|
||
CResMngStream *pSubAniStream = new CResMngStream( szFileName, true, true );
|
||
if( pSubAniStream )
|
||
{
|
||
if( pSubAniStream->IsValid() )
|
||
{
|
||
LoadAni( pSubAniStream );
|
||
}
|
||
delete pSubAniStream;
|
||
}
|
||
}
|
||
}
|
||
pToken = strtok( NULL, "\n\r" );
|
||
}
|
||
|
||
SAFE_DELETEA( pBuffer );
|
||
|
||
return ET_OK;
|
||
}
|
||
|
||
int CEtAni::LoadResource( CStream *pStream )
|
||
{
|
||
ASSERT( pStream && "Invalid Resource Stream( Animation )" );
|
||
if( pStream == NULL )
|
||
{
|
||
return ETERR_INVALIDRESOURCESTREAM;
|
||
}
|
||
|
||
char szHeaderString[ 256 ];
|
||
bool bMultiAni = false;
|
||
if( pStream->Size() < ANI_HEADER_RESERVED + sizeof( SAniFileHeader ) )
|
||
{
|
||
bMultiAni = true;
|
||
}
|
||
else
|
||
{
|
||
pStream->Read( szHeaderString, 256 );
|
||
if( strstr( szHeaderString, ANI_FILE_STRING ) == NULL )
|
||
{
|
||
bMultiAni = true;
|
||
}
|
||
}
|
||
if( bMultiAni )
|
||
{
|
||
return LoadMultiAni( pStream );
|
||
}
|
||
else
|
||
{
|
||
pStream->Seek( 0, SEEK_SET );
|
||
return LoadAni( pStream );
|
||
}
|
||
}
|
||
|
||
void CEtAni::BuildHierarchy()
|
||
{
|
||
int i, j;
|
||
|
||
for( i = 0; i < m_AniHeader.nBoneCount; i++ )
|
||
{
|
||
for( j = 0; j < m_AniHeader.nBoneCount; j++ )
|
||
{
|
||
const char *pParentName;
|
||
pParentName = m_vecBone[ i ]->GetParentName();
|
||
if( stricmp( pParentName, m_vecBone[ j ]->GetName() ) == 0 )
|
||
{
|
||
m_vecBone[ i ]->SetParent( m_vecBone[ j ] );
|
||
m_vecBone[ j ]->AddChild( m_vecBone[ i ] );
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
void CEtAni::Reset()
|
||
{
|
||
int i;
|
||
|
||
for( i = 0; i < m_AniHeader.nBoneCount; i++ )
|
||
{
|
||
m_vecBone[ i ]->Reset();
|
||
}
|
||
}
|
||
|
||
float CEtAni::CalcCorrectFrame( int nAni, float fFrame )
|
||
{
|
||
if( nAni < 0 || nAni >= m_AniHeader.nAniCount || fFrame < 0.0f )
|
||
{
|
||
ASSERT( 0 && "Invalid Ani Frame!!!( CEtAni::CalcCorrectFrame )" );
|
||
return 0.0f;
|
||
}
|
||
|
||
/*
|
||
fFrame = fmod( fFrame, ( float )GetAniLength( nAni ) );
|
||
if( fFrame > GetLastFrame( nAni ) )
|
||
{
|
||
fFrame -= GetLastFrame( nAni );
|
||
}
|
||
*/
|
||
if( fFrame > ( float )GetAniLength( nAni ) )
|
||
fFrame = ( float )GetAniLength( nAni );
|
||
return fFrame;
|
||
}
|
||
|
||
void CEtAni::SetAni( SBoneAniInfo *pAniInfo, int nBoneIndex )
|
||
{
|
||
if( IsValidBoneIndex( nBoneIndex ) )
|
||
{
|
||
CEtBone *pBone;
|
||
|
||
pAniInfo->fFrame = CalcCorrectFrame( pAniInfo->nAni, pAniInfo->fFrame );
|
||
|
||
if( nBoneIndex == 0 )
|
||
{
|
||
int i;
|
||
|
||
for( i = 0; i < m_AniHeader.nBoneCount; i++ )
|
||
{
|
||
if( m_vecBone[ i ]->IsRootBone() )
|
||
{
|
||
m_vecBone[ i ]->SetAni( pAniInfo );
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
pBone = GetBone( nBoneIndex );
|
||
if( pBone == NULL )
|
||
{
|
||
ASSERT( 0 && "Invalid Bone Index" );
|
||
return;
|
||
}
|
||
pBone->SetAni( pAniInfo );
|
||
}
|
||
}
|
||
}
|
||
|
||
void CEtAni::EnableBlend( int nBoneIndex, bool bEnable )
|
||
{
|
||
if( IsValidBoneIndex( nBoneIndex ) )
|
||
{
|
||
m_vecBone[ nBoneIndex ]->EnableBlend( bEnable );
|
||
}
|
||
}
|
||
|
||
void CEtAni::BlendAni( SBoneAniInfo *pAniInfo, int nBoneIndex )
|
||
{
|
||
if( IsValidBoneIndex( nBoneIndex ) )
|
||
{
|
||
CEtBone *pBone;
|
||
|
||
pAniInfo->fFrame = CalcCorrectFrame( pAniInfo->nAni, pAniInfo->fFrame );
|
||
|
||
if( nBoneIndex == 0 )
|
||
{
|
||
int i;
|
||
|
||
for( i = 0; i < m_AniHeader.nBoneCount; i++ )
|
||
{
|
||
if( m_vecBone[ i ]->IsRootBone() )
|
||
{
|
||
m_vecBone[ i ]->BlendAni( pAniInfo );
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
pBone = GetBone( nBoneIndex );
|
||
if( pBone == NULL )
|
||
{
|
||
ASSERT( 0 && "Invalid Bone Index" );
|
||
return;
|
||
}
|
||
pBone->BlendAni( pAniInfo );
|
||
}
|
||
}
|
||
}
|
||
|
||
int CEtAni::CalcAni( std::vector< EtMatrix > &vecInvWorldMat )
|
||
{
|
||
if( vecInvWorldMat.empty() )
|
||
{
|
||
return -1;
|
||
}
|
||
|
||
if( m_AniHeader.nBoneCount == 0 )
|
||
{
|
||
return -1;
|
||
}
|
||
|
||
int i, nSaveMatStart;
|
||
EtMatrix VertexTransMat;
|
||
|
||
EtMatrix *pLockedMatrices = NULL;
|
||
nSaveMatStart = GetEtSaveMat()->LockMatrix( m_AniHeader.nBoneCount, &pLockedMatrices );
|
||
for( i = 0; i < m_AniHeader.nBoneCount; i++ )
|
||
{
|
||
if( i >= ( int )vecInvWorldMat.size() || i >= (int) m_vecBone.size() )
|
||
{
|
||
break;
|
||
}
|
||
m_vecBone[ i ]->CalcAni();
|
||
EtMatrixMultiply( &VertexTransMat, &vecInvWorldMat[ i ], m_vecBone[ i ]->GetTransMat() );
|
||
pLockedMatrices[ i ] = VertexTransMat;
|
||
m_vecBone[ i ]->SetBoneRotation( NULL );
|
||
m_vecBone[ i ]->SetBoneScale( 1.0f );
|
||
}
|
||
|
||
return nSaveMatStart;
|
||
}
|
||
|
||
void CEtAni::CalcAniDistance( int nAni, float fCurFrame, float fPrevFrame, EtVector3 &DistVec )
|
||
{
|
||
fCurFrame = CalcCorrectFrame( nAni, fCurFrame );
|
||
fPrevFrame = CalcCorrectFrame( nAni, fPrevFrame );
|
||
|
||
if( m_vecBone.empty() )
|
||
{
|
||
DistVec = EtVector3( 0.0f, 0.0f, 0.0f );
|
||
}
|
||
else
|
||
{
|
||
m_vecBone[ 0 ]->CalcAniDistance( nAni, fCurFrame, fPrevFrame, DistVec );
|
||
}
|
||
}
|
||
|
||
void CEtAni::SetCalcPositionFlag( int nFlag )
|
||
{
|
||
CEtBone::SetCalcPositionFlag( nFlag );
|
||
}
|
||
|
||
void CEtAni::CalcRootBoneMat( int nAni, float fFrame, EtMatrix &BoneMat )
|
||
{
|
||
if( m_vecBone.empty() )
|
||
{
|
||
EtMatrixIdentity( &BoneMat );
|
||
}
|
||
else
|
||
{
|
||
m_vecBone[ 0 ]->GetAniRotationMatrix( nAni, fFrame, BoneMat );
|
||
}
|
||
}
|
||
|
||
void CEtAni::SetBoneRotation( int nBoneIndex, EtVector3 *pBoneRotation )
|
||
{
|
||
nBoneIndex = ConvertBoneIndex( nBoneIndex );
|
||
if( IsValidBoneIndex( nBoneIndex ) )
|
||
{
|
||
m_vecBone[ nBoneIndex ]->SetBoneRotation( pBoneRotation );
|
||
}
|
||
}
|
||
|
||
void CEtAni::SetBoneScale( int nBoneIndex, float fScale )
|
||
{
|
||
nBoneIndex = ConvertBoneIndex( nBoneIndex );
|
||
if( IsValidBoneIndex( nBoneIndex ) )
|
||
{
|
||
m_vecBone[ nBoneIndex ]->SetBoneScale( fScale );
|
||
}
|
||
}
|
||
|
||
int CEtAni::Save( const char *pFileName )
|
||
{
|
||
CFileStream Stream( pFileName, CFileStream::OPEN_WRITE );
|
||
|
||
if( !Stream.IsValid() )
|
||
{
|
||
return ETERR_FILECREATEFAIL;
|
||
}
|
||
|
||
SaveAni( &Stream );
|
||
|
||
return ET_OK;
|
||
}
|
||
|
||
int CEtAni::SaveAni( CStream *pStream )
|
||
{
|
||
int i;
|
||
char cReserved[ ANI_HEADER_RESERVED ];
|
||
char szAniName[ 256 ];
|
||
|
||
m_AniHeader.nVersion = ANI_FILE_VERSION;
|
||
pStream->Write( &m_AniHeader, sizeof( SAniFileHeader ) );
|
||
memset( cReserved, 0, ANI_HEADER_RESERVED );
|
||
pStream->Write( cReserved, ANI_HEADER_RESERVED );
|
||
for( i = 0; i < m_AniHeader.nAniCount; i++ )
|
||
{
|
||
memset( szAniName, 0, 256 );
|
||
strcpy( szAniName, m_vecAniName[ i ].c_str() );
|
||
pStream->Write( szAniName, 256 );
|
||
}
|
||
pStream->Write( &m_vecAniLength[ 0 ], sizeof( int ) * m_AniHeader.nAniCount );
|
||
for( i = 0; i < m_AniHeader.nBoneCount; i++ )
|
||
{
|
||
m_vecBone[ i ]->SaveBone( pStream, m_AniHeader.nAniCount );
|
||
}
|
||
|
||
return ET_OK;
|
||
}
|
||
|
||
int CEtAni::MergeAni( CEtAni *pAni )
|
||
{
|
||
int i, nBoneCount;
|
||
|
||
if( pAni->GetBoneCount() != GetBoneCount() )
|
||
{
|
||
return ETERR_DIFFERENTBONECOUNT;
|
||
}
|
||
|
||
for( i = 0; i < pAni->GetAniCount(); i++ )
|
||
{
|
||
m_vecAniName.push_back( pAni->GetAniName( i ) );
|
||
m_vecAniLength.push_back( pAni->GetAniLength( i ) );
|
||
}
|
||
|
||
nBoneCount = pAni->GetBoneCount();
|
||
for( i = 0; i < nBoneCount; i++)
|
||
{
|
||
m_vecBone[ i ]->MergeBone( pAni->FindBone( m_vecBone[ i ]->GetName() ), pAni->GetAniCount() );
|
||
}
|
||
m_AniHeader.nAniCount += pAni->GetAniCount();
|
||
|
||
return ET_OK;
|
||
}
|
||
|