522 lines
10 KiB
C++
522 lines
10 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;
|
|
}
|
|
|