DragonNest/Common/RT Cut Scene Core/DnCutScenePlayer.cpp
2024-12-19 09:48:26 +08:00

1576 lines
No EOL
56 KiB
C++

#include "StdAfx.h"
#include "DnCutScenePlayer.h"
#include "EtWorld.h"
#include "EtWorldProp.h"
#include "EtWorldSector.h"
#include "EtSoundEngine.h"
#include "EtUIXML.h"
#include "EtAniKey.h"
#ifdef _DEBUG
#define new new(_NORMAL_BLOCK,__FILE__,__LINE__)
#endif
CDnCutScenePlayer::CDnCutScenePlayer(void) : m_pCutSceneData( NULL ),
m_iNowLiveSequence( 0 ),
m_StartTime( 0 ),
m_pWorld( NULL ),
m_pLastProcessedActionSeq( NULL ), // 지속 애니메이션 처리를 위해 마지막으로 재생했던 액션을 받아둠
m_pActorProcessor( NULL ),
m_WholeSceneLength( 0 ),
m_bSceneEnd( false ),
m_pDOFFilter( NULL ),
m_pLiveSubtitleSequence( NULL ),
m_PrevTime(0)
{
}
CDnCutScenePlayer::~CDnCutScenePlayer(void)
{
for_each( m_vlpSequenceDB.begin(), m_vlpSequenceDB.end(), DeleteData<S_SEQUENCE*>() );
}
void CDnCutScenePlayer::Initialize( IDnCutSceneDataReader* pCutSceneData )
{
m_pCutSceneData = pCutSceneData;
}
void CDnCutScenePlayer::Clear( void )
{
m_vlhParticles.clear();
for_each( m_vlpSequenceDB.begin(), m_vlpSequenceDB.end(), DeleteData<S_SEQUENCE*>() );
//for_each( m_vlpActors.begin(), m_vlpActors.end(), DeleteData<S_CS_ACTOR_INFO*>() );
//m_vlpActors.clear();
//m_mapActors.clear();
m_pLastProcessedActionSeq = NULL;
m_vlpSequenceDB.clear();
m_dLiveSequences.clear();
m_iNowLiveSequence = 0;
m_pLiveSubtitleSequence = NULL;
m_vlpFirstActionSequence.clear();
}
void CDnCutScenePlayer::MakeUpSequences( ICustomActorProcessor* pCustomActorProcessor )
{
S_SEQUENCE* apPrevSequence[ SEQUENCE_COUNT ];
ZeroMemory( &apPrevSequence, sizeof(apPrevSequence) );
m_setProcessedTrigger.clear();
m_pActorProcessor = pCustomActorProcessor;
int iNumActor = m_pActorProcessor->GetNumActors();//(int)m_vlpActors.size();
for( int iActor = 0; iActor < iNumActor; ++iActor )
{
S_CS_ACTOR_INFO* pActorObject = m_pActorProcessor->GetActorInfoByIndex( iActor );//m_vlpActors.at( iActor );
if( NULL == pActorObject->pActor ) // 퀘스트 컷신 중 파티에 없는 녀석은 NULL 로 들어가 있게 됨. 컷신 재생에서 빠집니다.
continue;
// 셋팅된대로 라이트맵 영향 관련 플래그 셋팅한다.
if( pActorObject->hObject )
pActorObject->hObject->EnableLightMapInfluence( m_pCutSceneData->GetThisActorsInfluenceLightmap( pActorObject->strActorName.c_str() ) );
ZeroMemory( &apPrevSequence, sizeof(apPrevSequence) );
int iNumAction = m_pCutSceneData->GetThisActorsActionNum( pActorObject->strActorName.c_str() );
for( int iAction = 0; iAction < iNumAction; ++iAction )
{
// 키 정보와 데이터 정보를 따로 받아둔다.
const ActionInfo* pActionInfo = m_pCutSceneData->GetThisActorsActionInfoByIndex( pActorObject->strActorName.c_str(), iAction );
S_ACTION_SEQUENCE* pNewSequence = new CDnCutScenePlayer::S_ACTION_SEQUENCE;
pNewSequence->pActionInfo = new ActionInfo( *pActionInfo );
pNewSequence->dwStartTime = DWORD(pActionInfo->fStartTime * 1000.0f ); // 초 단위이므로..
pNewSequence->dwTimeLength = DWORD(pActionInfo->fTimeLength * 1000.0f );
pNewSequence->pAniObjectInfoToPlay = m_pActorProcessor->GetActorInfoByName( pActionInfo->strActorName.c_str() );//m_mapActors[ pActionInfo->strActorName ];
//assert( pNewSequence->pAniObjectInfoToPlay );
if( pNewSequence->pAniObjectInfoToPlay )
{
pNewSequence->pAniObjectInfoToPlay->vDefaultPos = m_pCutSceneData->GetRegResPos( pActionInfo->strActorName.c_str() );
pNewSequence->pAniObjectInfoToPlay->fDefaultYRotation = m_pCutSceneData->GetRegResRot( pActionInfo->strActorName.c_str() );
pNewSequence->pPrevSequence = apPrevSequence[ ACTION_SEQUENCE ];
// 만약 바로 전의 액션이 continue 라면 시간 길이를 이 액션 시작 시간까지 늘려준다.
if( pNewSequence->pPrevSequence )
{
pNewSequence->pPrevSequence->pNextSequence = pNewSequence;
if( ActionInfo::AT_CONTINUE == static_cast<S_ACTION_SEQUENCE*>(pNewSequence->pPrevSequence)->pActionInfo->iActionType )
pNewSequence->pPrevSequence->dwTimeLength = pNewSequence->dwStartTime - pNewSequence->pPrevSequence->dwStartTime;
}
apPrevSequence[ ACTION_SEQUENCE ] = pNewSequence;
m_vlpSequenceDB.push_back( pNewSequence );
// 첫번째 액션은 따로 보관해둔다.
if( 0 == iAction )
m_vlpFirstActionSequence.push_back( pNewSequence );
}
else
delete pNewSequence;
}
// 액션이 없는 액터는 첫번째 액션도 없으므로 NULL로 벡터에 넣어둔다.
if( 0 == iNumAction )
m_vlpFirstActionSequence.push_back( NULL );
int iNumKey = m_pCutSceneData->GetThisActorsKeyNum( pActorObject->strActorName.c_str() );
for( int iKey = 0; iKey < iNumKey; ++iKey )
{
const KeyInfo* pKeyInfo = m_pCutSceneData->GetThisActorsKeyInfoByIndex( pActorObject->strActorName.c_str(), iKey );
S_KEY_SEQUENCE* pNewSequence = new CDnCutScenePlayer::S_KEY_SEQUENCE;
pNewSequence->pKeyInfo = new KeyInfo( *pKeyInfo );
pNewSequence->dwStartTime = DWORD(pKeyInfo->fStartTime * 1000.0f );
pNewSequence->dwTimeLength = DWORD(pKeyInfo->fTimeLength * 1000.0f );
pNewSequence->pAniObjectInfoToPlay = m_pActorProcessor->GetActorInfoByName( pKeyInfo->strActorName.c_str() );//m_mapActors[ pKeyInfo->strActorName ];
//assert( pNewSequence->pAniObjectInfoToPlay );
if( pNewSequence->pAniObjectInfoToPlay )
{
pNewSequence->pPrevSequence = apPrevSequence[ KEY_SEQUENCE ];
if( apPrevSequence[ KEY_SEQUENCE ] )
pNewSequence->pPrevSequence->pNextSequence = pNewSequence;
apPrevSequence[ KEY_SEQUENCE ] = pNewSequence;
m_vlpSequenceDB.push_back( pNewSequence );
}
else
delete pNewSequence;
}
}
// 이벤트 관련 데이터 추가. 카메라의 단위는 ms 단위임.
for( int iEventType = 0; iEventType < EventInfo::TYPE_COUNT; ++iEventType )
{
int iNumEvent = m_pCutSceneData->GetThisTypesEventNum( iEventType );
for( int iEvent = 0; iEvent < iNumEvent; ++iEvent )
{
const EventInfo* pNowEventInfo = m_pCutSceneData->GetEventInfoByIndex( iEventType, iEvent );
S_SEQUENCE* pNewSequence = NULL;
switch( pNowEventInfo->iType )
{
case EventInfo::CAMERA:
{
S_CAM_EVENT_SEQUENCE* pCamSequence = new S_CAM_EVENT_SEQUENCE;
pCamSequence->pCamEventInfo = new CamEventInfo;
pCamSequence->pCamEventInfo->copy_from( pNowEventInfo );
pNewSequence = pCamSequence;
pNewSequence->pPrevSequence = apPrevSequence[ CAM_EVENT_SEQUENCE ];
if( apPrevSequence[ CAM_EVENT_SEQUENCE ] )
pNewSequence->pPrevSequence->pNextSequence = pNewSequence;
apPrevSequence[ CAM_EVENT_SEQUENCE ] = pNewSequence;
// 특정 액터를 추적하는 카메라라면 해당 액터의 포인터를 물려준다.
//if( CamEventInfo::TRACE_ACTOR == pCamSequence->pCamEventInfo->iTraceType /*||
// CamEventInfo::TRACE_ACTOR_ONLY_LOOKAT == pNewSequence->pCamEventInfo->iTraceType*/ )
//{
// if( false == pCamSequence->pCamEventInfo->strActorToTrace.empty() )
// {
// pCamSequence->pAniObjectInfoToPlay = m_pActorProcessor->GetActorInfoByName( pCamSequence->pCamEventInfo->strActorToTrace.c_str() );
// assert( pCamSequence->pAniObjectInfoToPlay );
// }
//}
//else
pCamSequence->pAniObjectInfoToPlay = NULL;
}
break;
case EventInfo::PARTICLE:
{
S_PARTICLE_EVENT_SEQUENCE* pParticleSequence = new S_PARTICLE_EVENT_SEQUENCE;
pParticleSequence->pParticleEventInfo = new ParticleEventInfo;
pParticleSequence->pParticleEventInfo->copy_from( pNowEventInfo );
pNewSequence = pParticleSequence;
pNewSequence->pPrevSequence = apPrevSequence[ PARTICLE_EVENT_SEQUENCE ];
if( apPrevSequence[ PARTICLE_EVENT_SEQUENCE ] )
pNewSequence->pPrevSequence->pNextSequence = pNewSequence;
apPrevSequence[ PARTICLE_EVENT_SEQUENCE ] = pNewSequence;
}
break;
//case EventInfo::SOUND:
// {
// S_SOUND_EVENT_SEQUENCE* pSoundSequence = new S_SOUND_EVENT_SEQUENCE;
// pSoundSequence->pSoundEventInfo = new SoundEventInfo;
// pSoundSequence->pSoundEventInfo->copy_from( pNowEventInfo );
// pNewSequence = pSoundSequence;
// pNewSequence->pPrevSequence = apPrevSequence[ SOUND_EVENT_SEQUENCE ];
// if( apPrevSequence[ SOUND_EVENT_SEQUENCE ] )
// pNewSequence->pPrevSequence->pNextSequence = pNewSequence;
// apPrevSequence [ SOUND_EVENT_SEQUENCE ] = pNewSequence;
// }
// break;
case EventInfo::DOF:
{
S_DOF_EVENT_SEQUENCE* pDofEventSequence = new S_DOF_EVENT_SEQUENCE;
pDofEventSequence->pDofEventInfo = new DofEventInfo;
pDofEventSequence->pDofEventInfo->copy_from( pNowEventInfo );
pNewSequence = pDofEventSequence;
pNewSequence->pPrevSequence = apPrevSequence[ DOF_EVENT_SEQUENCE ];
if( apPrevSequence[ DOF_EVENT_SEQUENCE ] )
pNewSequence->pPrevSequence->pNextSequence = pNewSequence;
apPrevSequence[ DOF_EVENT_SEQUENCE ] = pNewSequence;
//S_DOF_EVENT_SEQUENCE* pPrevDofEventSequence = static_cast<S_DOF_EVENT_SEQUENCE*>(pDofEventSequence->pPrevSequence);
//DofEventInfo* pDofEventInfo = pDofEventSequence->pDofEventInfo;
//if( pPrevDofEventSequence && pDofEventInfo->bUseNowValueAsStart )
//{
// DofEventInfo* pPrevDofEventInfo = pPrevDofEventSequence->pDofEventInfo;
// pDofEventInfo->fNearStartFrom = pPrevDofEventInfo->fNearStartDest;
// pDofEventInfo->fNearEndFrom = pPrevDofEventInfo->fNearEndDest;
// pDofEventInfo->fFarStartFrom = pPrevDofEventInfo->fFarStartDest;
// pDofEventInfo->fFarEndFrom = pPrevDofEventInfo->fFarEndDest;
// pDofEventInfo->fFocusDistFrom = pPrevDofEventInfo->fFocusDistDest;
// pDofEventInfo->fNearBlurSizeFrom = pPrevDofEventInfo->fNearBlurSizeDest;
// pDofEventInfo->fFarBlurSizeFrom = pPrevDofEventInfo->fFarBlurSizeDest;
//}
}
break;
case EventInfo::FADE:
{
S_FADE_EVENT_SEQUENCE* pFadeEventSequence = new S_FADE_EVENT_SEQUENCE;
pFadeEventSequence->pFadeEventInfo = new FadeEventInfo;
pFadeEventSequence->pFadeEventInfo->copy_from( pNowEventInfo );
pNewSequence = pFadeEventSequence;
pNewSequence->pPrevSequence = apPrevSequence[ FADE_EVENT_SEQUENCE ];
if( apPrevSequence[ FADE_EVENT_SEQUENCE ] )
pNewSequence->pPrevSequence->pNextSequence = pNewSequence;
apPrevSequence[ FADE_EVENT_SEQUENCE ] = pNewSequence;
}
break;
case EventInfo::PROP:
{
// TODO: 액션 프랍에게 특정 액션 시켜줘야 한다. 이건 클라이언트하고도 관련이 있군.
S_PROP_EVENT_SEQUENCE* pPropActionSequence = new S_PROP_EVENT_SEQUENCE;
pPropActionSequence->pPropEventInfo = new PropEventInfo;
pPropActionSequence->pPropEventInfo->copy_from( pNowEventInfo );
pNewSequence = pPropActionSequence;
pNewSequence->pPrevSequence = apPrevSequence[ PROP_EVENT_SEQUENCE ];
if( apPrevSequence[ PROP_EVENT_SEQUENCE ] )
pNewSequence->pPrevSequence->pNextSequence = pNewSequence;
apPrevSequence[ PROP_EVENT_SEQUENCE ] = pNewSequence;
}
break;
case EventInfo::SOUND_1:
case EventInfo::SOUND_2:
case EventInfo::SOUND_3:
case EventInfo::SOUND_4:
case EventInfo::SOUND_5:
case EventInfo::SOUND_6:
case EventInfo::SOUND_7:
case EventInfo::SOUND_8:
{
int iSequenceIndex = SOUND_EVENT_1_SEQUENCE + (pNowEventInfo->iType-EventInfo::SOUND_1);
S_SOUND_EVENT_SEQUENCE* pSoundSequence = new S_SOUND_EVENT_SEQUENCE;
pSoundSequence->pSoundEventInfo = new SoundEventInfo;
pSoundSequence->iType = iSequenceIndex;
pSoundSequence->pSoundEventInfo->copy_from( pNowEventInfo );
pNewSequence = pSoundSequence;
pNewSequence->pPrevSequence = apPrevSequence[ iSequenceIndex ];
if( apPrevSequence[ iSequenceIndex ] )
pNewSequence->pPrevSequence->pNextSequence = pNewSequence;
apPrevSequence [ iSequenceIndex ] = pNewSequence;
}
break;
case EventInfo::SUBTITLE:
{
S_SUBTITLE_EVENT_SEQUENCE* pSubtitleSequence = new S_SUBTITLE_EVENT_SEQUENCE;
pSubtitleSequence->pSubtitleEventInfo = new SubtitleEventInfo;
pSubtitleSequence->pSubtitleEventInfo->copy_from( pNowEventInfo );
pNewSequence = pSubtitleSequence;
pNewSequence->pPrevSequence = apPrevSequence[ SUBTITLE_EVENT_SEQUENCE ];
if( apPrevSequence[ SUBTITLE_EVENT_SEQUENCE ] )
pNewSequence->pPrevSequence->pNextSequence = pNewSequence;
apPrevSequence[ SUBTITLE_EVENT_SEQUENCE ] = pNewSequence;
}
break;
//#ifdef PRE_ADD_FILTEREVENT
case EventInfo::COLORFILTER:
{
S_COLORFILTER_EVENT_SEQUENCE* pColorFilterSequence = new S_COLORFILTER_EVENT_SEQUENCE;
pColorFilterSequence->pEventInfo = new ColorFilterEventInfo;
pColorFilterSequence->pEventInfo->copy_from( pNowEventInfo );
pNewSequence = pColorFilterSequence;
pNewSequence->pPrevSequence = apPrevSequence[ COLORFILTER_EVENT_SEQUENCE ];
if( apPrevSequence[ COLORFILTER_EVENT_SEQUENCE ] )
pNewSequence->pPrevSequence->pNextSequence = pNewSequence;
apPrevSequence[ COLORFILTER_EVENT_SEQUENCE ] = pNewSequence;
}
break;
//#endif PRE_ADD_FILTEREVENT
}
pNewSequence->dwStartTime = DWORD(pNowEventInfo->fStartTime * 1000.0f);
pNewSequence->dwTimeLength = DWORD(pNowEventInfo->fTimeLength * 1000.0f);
m_vlpSequenceDB.push_back( pNewSequence );
}
}
set<string>::iterator iter = m_setHideActor.begin();
for( ; iter != m_setHideActor.end(); ++iter )
{
m_pActorProcessor->GetActorInfoByName( iter->c_str() )->bHided = true;
}
}
void CDnCutScenePlayer::StartPlay( LOCAL_TIME StartTime )
{
assert( m_pWorld && "월드 객체가 셋팅이 안되어 있습니다." );
m_StartTime = StartTime;
m_PrevTime = StartTime;
m_WholeSceneLength = 0;
m_bSceneEnd = false;
// 시퀀스 DB 는 반드시 시간 순서대로 정렬되어 있어야 한다.
struct SortByStartTime : public binary_function<const S_SEQUENCE*, const S_SEQUENCE*, bool>
{
bool operator () ( const S_SEQUENCE* pA, const S_SEQUENCE* pB )
{
return pA->dwStartTime < pB->dwStartTime;
}
};
// 가장 긴 시간 뽑아내자.
int iNumSequence = (int)m_vlpSequenceDB.size();
for( int iSequence = 0; iSequence < iNumSequence; ++iSequence )
{
const S_SEQUENCE* pSequence = m_vlpSequenceDB.at( iSequence );
DWORD dwThisSeqEndTime = pSequence->dwStartTime+pSequence->dwTimeLength;
if( dwThisSeqEndTime > m_WholeSceneLength )
m_WholeSceneLength = dwThisSeqEndTime;
}
sort( m_vlpSequenceDB.begin(), m_vlpSequenceDB.end(), SortByStartTime() );
// 맨 처음 액션들을 0 프레임으로 초기화.
for( int iActor = 0; iActor < m_pActorProcessor->GetNumActors(); ++iActor )
{
S_ACTION_SEQUENCE* pActionSequence = m_vlpFirstActionSequence.at( iActor );
if( NULL == pActionSequence )
continue;
S_CS_ACTOR_INFO* pActorInfo = m_pActorProcessor->GetActorInfoByIndex( iActor );
if( false == pActionSequence->pActionInfo->strAnimationName.empty() )
{
//int iAniIndex = m_pActorProcessor->GetActionIndex( iActor, pActionSequence->pActionInfo->strAnimationName.c_str() );
//if( -1 != iAniIndex )
//{
// pActorInfo->hObject->SetAniFrame( pActorInfo->vlAniIndex[ iAniIndex ], 0.0f );
//}
if( pActorInfo->hObject && pActionSequence->pActionInfo->iAnimationIndex < (int)pActorInfo->vlAniIndex.size() )
{
pActorInfo->hObject->SetAniFrame( pActorInfo->vlAniIndex[ pActionSequence->pActionInfo->iAnimationIndex ], 0.0f );
}
}
}
// 프로젝션 행렬을 백업해둔다. Scene 재생 중에 FOV가 바뀔 수 있기 때문에.
m_matOriProj = *(m_hCamera->GetProjMat());
}
void CDnCutScenePlayer::ResetLiveSequences( void )
{
m_dLiveSequences.clear();
m_iNowLiveSequence = 0;
}
void CDnCutScenePlayer::_CalcRotateFront( S_CS_ACTOR_INFO* pActorInfo, EtVector3& vDir )
{
// 캐릭터가 바라보는 디폴트 방향
EtVector3 vCharDefaultDir( 0.0f, 0.0f, 1.0f );
EtVec3Normalize( &vDir, &vDir );
if( fabs(vDir.x-vCharDefaultDir.x) < 0.0001f )
vDir.x = vCharDefaultDir.x;
if( fabs(vDir.z-vCharDefaultDir.z) < 0.0001f )
vDir.z = vCharDefaultDir.z;
float fDot = EtVec3Dot( &vDir, &vCharDefaultDir );
float fRot = EtAcos( fDot );
if( vDir.x > 0.0f )
fRot = -fRot;
float fDegree = fRot * (180.0f/ET_PI);
pActorInfo->fRotYDegree = fDegree;
//EtMatrixRotationY( &pActorInfo->matRotY, fRot );
}
void CDnCutScenePlayer::_BeginParticleEvent( S_SEQUENCE* pParticleEvent )
{
// 파티클 생성
S_PARTICLE_EVENT_SEQUENCE* pParticleSequence = static_cast<S_PARTICLE_EVENT_SEQUENCE*>(pParticleEvent);
assert( -1 != pParticleSequence->pParticleEventInfo->iParticleDataIndex && "파티클 데이터 없음!" );
if( -1 != pParticleSequence->pParticleEventInfo->iParticleDataIndex )
{
pParticleSequence->crossWorld.SetPosition( pParticleSequence->pParticleEventInfo->vPos );
pParticleSequence->hParticle = EternityEngine::CreateBillboardEffect( pParticleSequence->pParticleEventInfo->iParticleDataIndex,
pParticleSequence->crossWorld );
pParticleSequence->hParticle->SetCullDist( 1000000.0f );
//pParticleSequence->hParticle->SetWorldMat( );
//pParticleSequence->hParticle->EnableIterate( );
pParticleSequence->hParticle->Show( true );
m_vlhParticles.push_back( pParticleSequence->hParticle );
}
}
void CDnCutScenePlayer::_BeginSoundEvent( S_SEQUENCE* pSoundEvent )
{
S_SOUND_EVENT_SEQUENCE* pSoundSequence = static_cast<S_SOUND_EVENT_SEQUENCE*>(pSoundEvent);
assert( -1 != pSoundSequence->pSoundEventInfo->iSoundDataIndex && "사운드 데이터 없음!" );
if( -1 != pSoundSequence->pSoundEventInfo->iSoundDataIndex )
{
pSoundSequence->hSound = CEtSoundEngine::GetInstance().PlaySound( "NULL", pSoundSequence->pSoundEventInfo->iSoundDataIndex, false, true );
//m_hCurChannel->SetVolume( pSound->fVolume );
//m_hCurChannel->SetRollOff( 3, 0.0f, 1.0f, pSound->fRange * pSound->fRollOff, 1.0f, pSound->fRange, 0.0f );
//m_hCurChannel->SetPosition( Cross.m_vPosition );
if( !pSoundSequence->hSound )
return;
pSoundSequence->hSound->SetPriority(0);
pSoundSequence->hSound->SetVolume( pSoundSequence->pSoundEventInfo->fVolume );
pSoundSequence->hSound->Resume();
m_vlhPlayingChannel.push_back( pSoundSequence->hSound );
}
}
void CDnCutScenePlayer::_BeginFadeEvent( S_SEQUENCE* pFadeEvent )
{
S_FADE_EVENT_SEQUENCE* pFadeSequence = static_cast<S_FADE_EVENT_SEQUENCE*>(pFadeEvent);
assert( -1 != pFadeSequence->pFadeEventInfo->iFadeKind && "페이드 인 아웃 정보가 잘못 되었음!" );
if( -1 != pFadeSequence->pFadeEventInfo->iFadeKind )
{
DWORD dwColor = D3DCOLOR_ARGB( 0, pFadeSequence->pFadeEventInfo->iColorRed,
pFadeSequence->pFadeEventInfo->iColorGreen, pFadeSequence->pFadeEventInfo->iColorBlue );
switch( pFadeSequence->pFadeEventInfo->iFadeKind )
{
case FadeEventInfo::FADE_IN:
m_pActorProcessor->FadeIn( 1.0f / pFadeSequence->pFadeEventInfo->fTimeLength, dwColor );
//CEtSoundEngine::GetInstance().FadeVolume( NULL, 1.0f, 0.3f, false );
break;
case FadeEventInfo::FADE_OUT:
m_pActorProcessor->FadeOut( 1.0f / pFadeSequence->pFadeEventInfo->fTimeLength, dwColor );
//CEtSoundEngine::GetInstance().FadeVolume( NULL, 0.0f, 0.3f, false );
break;
}
}
}
void CDnCutScenePlayer::_BeginSubtitleEvent( S_SEQUENCE* pEvent )
{
S_SUBTITLE_EVENT_SEQUENCE* pSubtitleEvent = static_cast<S_SUBTITLE_EVENT_SEQUENCE*>(pEvent);
const wchar_t* pSubtitle = GetEtUIXML().GetUIString( CEtUIXML::idCategory1, pSubtitleEvent->pSubtitleEventInfo->iUIStringID );
m_pActorProcessor->ShowSubtitle( pSubtitle );
m_pLiveSubtitleSequence = pSubtitleEvent;
}
// PRE_ADD_FILTEREVENT
//void CDnCutScenePlayer::_BeginColorFilterEvent( S_SEQUENCE* pEvent )
//{
// S_COLORFILTER_EVENT_SEQUENCE* pColorFilterEvent = static_cast<S_COLORFILTER_EVENT_SEQUENCE*>(pEvent);
// //const wchar_t* pSubtitle = GetEtUIXML().GetUIString( CEtUIXML::idCategory1, pColorFilterEvent->pEventInfo->iUIStringID );
// //m_pActorProcessor->ShowSubtitle( pSubtitle );
// m_pLiveSubtitleSequence = pColorFilterEvent;
//}
void CDnCutScenePlayer::_ProcessPropActionEvent( S_SEQUENCE* pPropActionEvent, LOCAL_TIME AbsoluteTime, LOCAL_TIME ElapsedTime )
{
S_PROP_EVENT_SEQUENCE* pPropSequence = static_cast<S_PROP_EVENT_SEQUENCE*>(pPropActionEvent);
// 현재 프레임을 계산해서 셋팅해줌..
LOCAL_TIME LiveElapsedTime = ElapsedTime - pPropSequence->dwStartTime;
float fLiveElapsedTime = (float)LiveElapsedTime * 0.001f;
float fFrame = fLiveElapsedTime * pPropSequence->pPropEventInfo->fSpeed;
CEtWorldSector* pSector = m_pWorld->GetSector( 0.0f, 0.0f );
CEtWorldProp* pProp = pSector->GetPropFromCreateUniqueID( pPropSequence->pPropEventInfo->iPropID );
if( pProp )
{
if (false == pPropSequence->pPropEventInfo->strActionName.empty())
{
m_pActorProcessor->SetPropAction( pProp, pPropSequence->pPropEventInfo->strActionName.c_str(), AbsoluteTime, fFrame );
}
m_pActorProcessor->ShowProp( pProp, pPropSequence->pPropEventInfo->bShow );
//pProp->GetObjectHandle()->ShowObject( pPropSequence->pPropEventInfo->bShow );
}
}
int CDnCutScenePlayer::_SearchFOVOffsetIndex( vector<SCameraFOVKey>& vlCamFOV, int iFrame )
{
int iNumFOV = (int)vlCamFOV.size();
if( 0 == iFrame || 1 == iNumFOV )
return 0;
int iResult = 0;
int iStartIndex = 0;
int iEndIndex = iNumFOV-1;
int iCenterIndex = 0;
do
{
iCenterIndex = iStartIndex + (iEndIndex-iStartIndex) / 2;
if( iFrame < vlCamFOV.at( iCenterIndex ).nTime ) // 왼쪽 구간
{
//iResult =
iEndIndex = iCenterIndex;
}
else // 오른쪽 구간
{
//iResult =
iStartIndex = iCenterIndex;
}
if( iCenterIndex == iNumFOV-2 )
break;
} while ( !(vlCamFOV.at(iCenterIndex).nTime <= iFrame &&
iFrame < vlCamFOV.at(iCenterIndex+1).nTime) );
iResult = iCenterIndex;
return iResult;
}
int CDnCutScenePlayer::_SearchRotOffsetIndex( vector<SCameraRotationKey>& vlCamRotation, int iFrame )
{
int iNumRots = (int)vlCamRotation.size();
if( 0 == iFrame || 1 == iNumRots )
return 0;
int iResult = 0;
int iStartIndex = 0;
int iEndIndex = iNumRots-1;
int iCenterIndex = 0;
do
{
iCenterIndex = iStartIndex + (iEndIndex-iStartIndex) / 2;
if( iFrame < vlCamRotation.at( iCenterIndex ).nTime ) // 왼쪽 구간
{
//iResult =
iEndIndex = iCenterIndex;
}
else // 오른쪽 구간
{
//iResult =
iStartIndex = iCenterIndex;
}
if( iCenterIndex == iNumRots-2 )
break;
} while ( !(vlCamRotation.at(iCenterIndex).nTime <= iFrame &&
iFrame < vlCamRotation.at(iCenterIndex+1).nTime) );
iResult = iCenterIndex;
return iResult;
}
int CDnCutScenePlayer::_SearchPosOffsetIndex( vector<SCameraPositionKey>& vlCamPosition, int iFrame )
{
int iNumPos = (int)vlCamPosition.size();
if( 0 == iFrame || 1 == iNumPos )
return 0;
int iResult = 0;
int iStartIndex = 0;
int iEndIndex = iNumPos-1;
int iCenterIndex = 0;
do
{
iCenterIndex = iStartIndex + (iEndIndex-iStartIndex) / 2;
if( iFrame < vlCamPosition.at( iCenterIndex ).nTime ) // 왼쪽 구간
{
//iResult =
iEndIndex = iCenterIndex;
}
else // 오른쪽 구간
{
//iResult =
iStartIndex = iCenterIndex;
}
if( iCenterIndex == iNumPos-2 )
break;
} while ( !(vlCamPosition.at(iCenterIndex).nTime <= iFrame &&
iFrame < vlCamPosition.at(iCenterIndex+1).nTime) );
iResult = iCenterIndex;
return iResult;
}
void CDnCutScenePlayer::_ProcessActors( LOCAL_TIME AbsoluteTime, LOCAL_TIME ElapsedTime )
{
// TODO: 행동이 끝난 액터들중 지속 애니메이션을 갖고 있는 애들은 계속 업데이트 하고 있어야 한다.
// 이걸 기본 애니메이션 설정으로 할 것인지 어떨 건지는 봐야 알겠다.
float fDelta = float(AbsoluteTime - m_PrevTime) * 0.001f;
//int iNumActors = (int)m_vlpActors.size();
int iNumActors = m_pActorProcessor->GetNumActors();
for( int iActor = 0; iActor < iNumActors; ++iActor )
{
S_CS_ACTOR_INFO* pActorInfo = m_pActorProcessor->GetActorInfoByIndex( iActor );//m_vlpActors.at( iActor );
//assert( pActorInfo->iNowAniIndex != -1 && "CDnCutScenePlayer::Process() -> 애니메이션 인덱스가 잘못되었습니다." );
int iAniIndex = m_pActorProcessor->GetActionIndex( iActor, pActorInfo->strNowActionName.c_str() );
if( -1 == iAniIndex )
{
// 액션이 없을 때 -1이 리턴된다. 액션이름이 아예 없는 경우라면 0번 인덱스로 대체해준다.
// 안그러면 여기 continue 에서 걸려서 이 액터의 위치가 갱신되지 않는다.
if( pActorInfo->strNowActionName.empty() )
iAniIndex = 0;
else
continue;
}
if( iAniIndex >= (int)pActorInfo->vlAniIndex.size() || pActorInfo->vlAniIndex[ iAniIndex ] == -1 )
continue;
float fAniLength = (float)pActorInfo->hObject->GetLastFrame( pActorInfo->vlAniIndex[ iAniIndex ] );
//pActorInfo->fFrame += fDelta*pActorInfo->fAnimationSpeed;
switch( pActorInfo->iAnimationType )
{
case ActionInfo::AT_ONCE:
{
if( pActorInfo->fFrame > fAniLength )
{
pActorInfo->fFrame = fAniLength;
pActorInfo->bElapsed = true;
}
else
if( pActorInfo->fFrame < 0.0f )
pActorInfo->fFrame = 0.0f;
}
break;
case ActionInfo::AT_REPEAT:
{
float fOverElapse = pActorInfo->fFrame / fAniLength;
if( pActorInfo->fFrame > fAniLength )
{
//pActorInfo->fFrame = 0.0f;
pActorInfo->fFrame = pActorInfo->fFrame - int(fOverElapse)*fAniLength;
pActorInfo->bElapsed = true;
}
else
if( pActorInfo->fFrame < 0.0f )
{
pActorInfo->fFrame = pActorInfo->fFrame - int(fOverElapse)*fAniLength;
pActorInfo->fFrame += fAniLength;
//pActorInfo->fFrame = fAniLength;
}
}
break;
case ActionInfo::AT_CONTINUE:
{
LOCAL_TIME LiveElapsedTime = ElapsedTime - pActorInfo->dwSequenceStartTime;
pActorInfo->fSequenceLiveElapsedSec = float(LiveElapsedTime) * 0.001f;
pActorInfo->fFrame = pActorInfo->fSequenceLiveElapsedSec * pActorInfo->fAnimationSpeed;
float fOverElapse = pActorInfo->fFrame / fAniLength;
if( pActorInfo->fFrame > fAniLength )
{
pActorInfo->fFrame = pActorInfo->fFrame - int(fOverElapse)*fAniLength;
pActorInfo->bElapsed = true;
}
else
if( pActorInfo->fFrame < 0.0f )
{
pActorInfo->fFrame = pActorInfo->fFrame - int(fOverElapse)*fAniLength;
pActorInfo->fFrame += fAniLength;
}
}
break;
}
// TODO: 액션 파일에서 구간 루프 처리된 것을 동일하게 처리
if( NULL != m_pLastProcessedActionSeq )
{
if( 0 < m_pLastProcessedActionSeq->pActionInfo->iNextActionFrame )
{
if( pActorInfo->bElapsed )
{
if( (int)pActorInfo->fFrame < m_pLastProcessedActionSeq->pActionInfo->iNextActionFrame )
pActorInfo->fFrame += (float)m_pLastProcessedActionSeq->pActionInfo->iNextActionFrame;
}
}
}
float fFinalRotYDegree = pActorInfo->fRotYDegree + pActorInfo->fNowRotProceed;
//float fFinalRotYDegree = 180.0f + ( pActorInfo->fNowRotProceed - pActorInfo->fRotYDegree );
EtMatrixRotationY( &pActorInfo->matRotY, -(fFinalRotYDegree*ET_PI / 180.0f) );
float fScale = m_pActorProcessor->GetActorScale( iActor );
if( fScale != 1.0f )
{
// 스케일 먹였을 때와 안 먹였을 때의 bip_01 의 차이값 만큼 보정해준다. 스케일 먹였어도 원래 스케일의 Y 값만큼만 ani distance 가 이동되기 때문이다.
//pActorInfo->hObject->GetAniHandle()->GetBone( 0 )->GetAniKey( pActorInfo->vlAniIndex[ iAniIndex ] )->CalcPosition( vDefaultPos, 0.0f );
pActorInfo->hObject->SetCalcPositionFlag( CALC_POSITION_Y );
}
if( pActorInfo->bUseAniDistance )
{
//pActorInfo->hObject->CalcAniDistance( pActorInfo->vlAniIndex.at(pActorInfo->iNowAniIndex),
// pActorInfo->fFrame, 0.0f, pActorInfo->vAniDistanceOffset );
m_pActorProcessor->CalcAniDistance( pActorInfo, pActorInfo->fFrame, 0.0f, pActorInfo->vAniDistanceOffset );
if( fScale != 1.0f )
pActorInfo->vAniDistanceOffset.y = 0.0f;
EtVec3TransformCoord( &pActorInfo->vAniDistanceOffset, &pActorInfo->vAniDistanceOffset, &pActorInfo->matRotY );
if( pActorInfo->bFitAniDistanceYToMap )
{
EtVector3 vFinalPos = pActorInfo->vPos + pActorInfo->vAniDistanceOffset;
pActorInfo->vAniDistanceOffset.y = m_pWorld->GetHeight( vFinalPos.x, vFinalPos.z ) + pActorInfo->vAniDistanceOffset.y - pActorInfo->vPos.y;
}
//else
// pActorInfo->vAniDistanceOffset.y = 0.0f;
}
else
{
// Key에 YPosToMap 이 켜져있다면 Y 값만 계산해서 넣어주어야 정확하게 높이가 맞는다.
// 맵 높이 및 AniDistanct 의 y 값 높이까지 감안해야 한다.
if( pActorInfo->bKeyUseYPosToMap )
{
m_pActorProcessor->CalcAniDistance( pActorInfo, pActorInfo->fFrame, 0.0f, pActorInfo->vAniDistanceOffset );
if( fScale != 1.0f )
pActorInfo->vAniDistanceOffset.y = 0.0f;
pActorInfo->vAniDistanceOffset.y = m_pWorld->GetHeight( pActorInfo->vPos.x, pActorInfo->vPos.z ) + pActorInfo->vAniDistanceOffset.y - pActorInfo->vPos.y;
pActorInfo->vAniDistanceOffset.x = pActorInfo->vAniDistanceOffset.z = 0.0f;
}
else
pActorInfo->vAniDistanceOffset = EtVector3( 0.0f, 0.0f, 0.0f );
}
EtMatrix matScale;
EtMatrixScaling( &matScale, fScale, fScale, fScale );
pActorInfo->matExFinal.Identity();
pActorInfo->matExFinal.RotateYaw( fFinalRotYDegree/*pActorInfo->fRotYDegree*/ );
pActorInfo->matExFinal.SetPosition( pActorInfo->vPos + pActorInfo->vAniDistanceOffset );
EtMatrix matWorld( pActorInfo->matExFinal );
matWorld = matScale * matWorld;
pActorInfo->matExFinal = matWorld;
set<string>::iterator iter = m_setHideActor.find( pActorInfo->strActorName );
if( iter != m_setHideActor.end() )
pActorInfo->hObject->ShowObject( false );
}
m_pActorProcessor->Process( ElapsedTime, fDelta );
}
void CDnCutScenePlayer::_UpdateSequence( LOCAL_TIME AbsoluteTime, LOCAL_TIME ElapsedTime )
{
if( m_vlpSequenceDB.empty() )
return;
// 절대 시간 기준으로 현재 시간에 맞는 화면을 곧바로 만들어준다.
// Ani Distance 때문에 액터는 따로 감안해서 계산을 해줘야 함.
// 액터같은 경우는 회전 -> 키 -> 액션 순으로 업데이트 해주어야 한다.
S_SEQUENCE* apProcessingSequence[ SEQUENCE_COUNT ];
ZeroMemory( apProcessingSequence, sizeof(apProcessingSequence) );
int iNumActor = m_pActorProcessor->GetNumActors();
for( int i = 0; i < iNumActor; ++i )
{
S_CS_ACTOR_INFO* pActorInfo = m_pActorProcessor->GetActorInfoByIndex( i );
pActorInfo->vPos = pActorInfo->vDefaultPos;
pActorInfo->fRotYDegree = pActorInfo->fDefaultYRotation;
pActorInfo->vPrevPos = EtVector3( 0.0f, 0.0f, 0.0f );
pActorInfo->fNowRotProceed = 0.0f;
}
//deque<S_SEQUENCE*> dOpenSequences;
S_SEQUENCE* pProcessSequence = m_vlpSequenceDB.at( 0 );
int iSequence = 0;
//int iCount = 0;
while( pProcessSequence )
{
DWORD dwEndTime = pProcessSequence->dwStartTime + pProcessSequence->dwTimeLength;
if( pProcessSequence->dwStartTime < ElapsedTime )
{
// 액터를 제어하는 시퀀스 관련.. 현재 끝나는 어떤 시퀀스에 따라 결과를 해당 액터에 반영해 준다.
switch( pProcessSequence->iType )
{
case ACTION_SEQUENCE:
{
S_ACTION_SEQUENCE* pActionSequence = static_cast<S_ACTION_SEQUENCE*>(pProcessSequence);
S_CS_ACTOR_INFO* pActorInfo = pActionSequence->pAniObjectInfoToPlay;
//if( 0 == iCount )
// OutputDebug( "[좌표] (%2.2f %2.2f, %2.2f)\n", pActorInfo->vPos.x, pActorInfo->vPos.y, pActorInfo->vPos.z );
//++iCount;
m_pLastProcessedActionSeq = pActionSequence;
pActorInfo->dwSequenceStartTime = pActionSequence->dwStartTime;
pActorInfo->iNowAniIndex = pActionSequence->pActionInfo->iAnimationIndex;
bool bActionChanged = (pActorInfo->strNowActionName != pActionSequence->pActionInfo->strAnimationName);
pActorInfo->strNowActionName = pActionSequence->pActionInfo->strAnimationName;
pActorInfo->iAnimationType = pActionSequence->pActionInfo->iActionType;
pActorInfo->fAnimationSpeed = pActionSequence->pActionInfo->fAnimationSpeed;
if( pActionSequence->pActionInfo->bUseStartRotation )
pActorInfo->fRotYDegree = pActionSequence->pActionInfo->fStartRotation;
if( pActionSequence->pActionInfo->bUseStartPosition )
pActorInfo->vPos = pActionSequence->pActionInfo->vStartPos;
pActorInfo->bUseAniDistance = pActionSequence->pActionInfo->bUseAniDistance;
if( pActorInfo->bUseAniDistance )
pActorInfo->bFitAniDistanceYToMap = pActionSequence->pActionInfo->bFitAniDistanceYToMap;
else
pActorInfo->bFitAniDistanceYToMap = false;
bool bEndedSequence = dwEndTime <= ElapsedTime;
if( bEndedSequence ) // 진행이 끝난 시퀀스, AniDistance 까지 처리토록 한다.
{
pActorInfo->fFrame = ((float)pActionSequence->dwTimeLength * 0.001f) * pActorInfo->fAnimationSpeed;
// Y 로테이션 값도 있으면 적용 시켜줌... 그러나 로테이션이 길게 겹쳐져 있는 경우 제대로 출력 안될 것이다..
float fFinalRotYDegree = pActorInfo->fRotYDegree + pActorInfo->fNowRotProceed;
EtMatrixRotationY( &pActorInfo->matRotY, -(fFinalRotYDegree*ET_PI / 180.0f) );
if( pActorInfo->bUseAniDistance )
{
//pActorInfo->hObject->CalcAniDistance( pActorInfo->vlAniIndex.at(pActorInfo->iNowAniIndex),
// pActorInfo->fFrame, 0.0f, pActorInfo->vAniDistanceOffset );
m_pActorProcessor->CalcAniDistance( pActorInfo, pActorInfo->fFrame, 0.0f, pActorInfo->vAniDistanceOffset );
float fScale = m_pActorProcessor->GetActorScale( pActorInfo->iActorIndexInProcessorVector );
if( fScale != 1.0f )
pActorInfo->vAniDistanceOffset.y = 0.0f;
EtVec3TransformCoord( &pActorInfo->vAniDistanceOffset, &pActorInfo->vAniDistanceOffset, &pActorInfo->matRotY );
if( pActorInfo->bFitAniDistanceYToMap )
{
EtVector3 vFinalPos = pActorInfo->vPos + pActorInfo->vAniDistanceOffset;
pActorInfo->vAniDistanceOffset.y = m_pWorld->GetHeight( vFinalPos.x, vFinalPos.z ) + pActorInfo->vAniDistanceOffset.y - pActorInfo->vPos.y;
}
//===
// pActorInfo->vAniDistanceOffset.y = 0.0f;
}
else
pActorInfo->vAniDistanceOffset = EtVector3( 0.0f, 0.0f, 0.0f );
pActorInfo->vPos += pActorInfo->vAniDistanceOffset;
pActorInfo->vAniDistanceOffset = EtVector3( 0.0f, 0.0f, 0.0f );
// continue 액션 타입이라면 그대로 유지시켜준다.
// 혹은 뒤에 액션이 없는 경우도 마찬가지..
//if( ActionInfo::AT_CONTINUE != pActorInfo->iAnimationType &&
// pActionSequence->pNextSequence != NULL )
//{;
pActorInfo->bUseAniDistance = false;
//}
pActorInfo->pNowActionSequence = NULL;
}
else
{
LOCAL_TIME LiveElapsedTime = ElapsedTime - pActionSequence->dwStartTime;
pActorInfo->fSequenceLiveElapsedSec = (float)LiveElapsedTime * 0.001f;
pActorInfo->fFrame = pActorInfo->fSequenceLiveElapsedSec * pActionSequence->pActionInfo->fAnimationSpeed;
//if( bActionChanged )
// m_pActorProcessor->OnChangeAction( pActorInfo );
pActorInfo->pNowActionSequence = pProcessSequence;
apProcessingSequence[ ACTION_SEQUENCE ] = pProcessSequence;
}
}
break;
case KEY_SEQUENCE:
{
S_KEY_SEQUENCE* pKeySequence = static_cast<S_KEY_SEQUENCE*>(pProcessSequence);
LOCAL_TIME LiveElapsed = ElapsedTime - pKeySequence->dwStartTime;
float fNowProceed = 1.0f;
bool bEndedSequence = dwEndTime <= ElapsedTime;
if( bEndedSequence )
{
fNowProceed = 1.0f;
}
else
{
fNowProceed = float(LiveElapsed) / float(pKeySequence->dwTimeLength);
apProcessingSequence[ KEY_SEQUENCE ] = pProcessSequence;
}
const KeyInfo* pKeyInfo = pKeySequence->pKeyInfo;
switch( pKeySequence->pKeyInfo->iKeyType )
{
case KeyInfo::MOVE:
{
EtVector3 vDir = pKeyInfo->vDestPos - pKeyInfo->vStartPos;
EtVector3 vNewPos = pKeyInfo->vStartPos + vDir*fNowProceed;
EtVector3 vPrevPos = pKeySequence->pAniObjectInfoToPlay->vPrevPos; // 여기서 사용할 이전 위치 정보는 복사해두고,
// 저장할 이전 위치 정보는 지금 업데이트 한다.
//pKeyObject->pAniObjectInfoToPlay->vPrevPos = pKeyObject->pAniObjectInfoToPlay->crossPos.GetPosition();
pKeySequence->pAniObjectInfoToPlay->vPrevPos = pKeyInfo->vStartPos + vDir*(fNowProceed*0.99f);
if( pKeyInfo->bRotateFront )
{
if( vNewPos != vPrevPos )
{
EtVector3 vTangent = vNewPos - vPrevPos;
_CalcRotateFront( pKeySequence->pAniObjectInfoToPlay, vTangent );
}
}
// _ProcessActors() 에서 계산됨.
//if( pKeyInfo->bFitYPosToMap )
//{
// vNewPos.y = m_pWorld->GetHeight( vNewPos.x, vNewPos.z );
//}
pKeySequence->pAniObjectInfoToPlay->vPos = vNewPos;
pKeySequence->pAniObjectInfoToPlay->bKeyUseYPosToMap = pKeyInfo->bFitYPosToMap;
//pKeyObject->pAniObjectInfoToPlay->matExFinalPos.SetPosition( vNewPos );
if( bEndedSequence )
{
S_CS_ACTOR_INFO* pActorInfo = pKeySequence->pAniObjectInfoToPlay;
pActorInfo->vPos = pKeyInfo->vDestPos;
// y 값을 맞추는 플래그가 켜져있다면 따로 anidistance 계산해서 맞춰줌.
if( pActorInfo->bKeyUseYPosToMap )
{
// Y 로테이션 값도 있으면 적용 시켜줌... 그러나 로테이션이 길게 겹쳐져 있는 경우 제대로 출력 안될 것이다..
float fFinalRotYDegree = pActorInfo->fRotYDegree + pActorInfo->fNowRotProceed;
float fScale = m_pActorProcessor->GetActorScale( pActorInfo->iActorIndexInProcessorVector );
if( fScale != 1.0f )
pActorInfo->vAniDistanceOffset.y = 0.0f;
m_pActorProcessor->CalcAniDistance( pActorInfo, pActorInfo->fFrame, 0.0f, pActorInfo->vAniDistanceOffset );
pActorInfo->vAniDistanceOffset.y = m_pWorld->GetHeight( pActorInfo->vPos.x, pActorInfo->vPos.z ) + pActorInfo->vAniDistanceOffset.y - pActorInfo->vPos.y;
}
else
pActorInfo->vAniDistanceOffset = EtVector3( 0.0f, 0.0f, 0.0f );
pActorInfo->vPos.y += pActorInfo->vAniDistanceOffset.y;
pActorInfo->vAniDistanceOffset = EtVector3( 0.0f, 0.0f, 0.0f );
pActorInfo->bKeyUseYPosToMap = false;
}
}
break;
case KeyInfo::MULTI_MOVE:
{
// 우선 LiveElapsedTime 을 기반으로 서브 키를 찾는다.
float fNowStartTime = 0.0f;
int iNumSubKey = (int)pKeySequence->pKeyInfo->vlMoveKeys.size();
const SubKey* pNowSubKey = NULL;
float fNowSubKeyProceed = 0.0f;
int iNowStartSubKey = -1;
for( int iKey = 0; iKey < iNumSubKey; ++iKey )
{
const SubKey& Key = pKeyInfo->vlMoveKeys.at( iKey );
float fLiveElapsed = (float)LiveElapsed * 0.001f;
if( fNowStartTime < fLiveElapsed && fLiveElapsed < fNowStartTime+Key.fTimeLength )
{
pNowSubKey = &Key;
fNowSubKeyProceed = (fLiveElapsed - fNowStartTime) / Key.fTimeLength;
iNowStartSubKey = iKey;
break;
}
fNowStartTime += Key.fTimeLength;
}
if( -1 != iNowStartSubKey )
{
EtVector3 vNewPos;
EtVector3 vArgs[ 4 ];
int iLeaveCount = (int)pKeyInfo->vlMoveKeys.size() - iNowStartSubKey - 1;
// 처음 시작 인덱스
if( 0 == iNowStartSubKey )
{
vArgs[ 0 ] = pKeyInfo->vlMoveKeys.at( iNowStartSubKey ).vPos;
vArgs[ 1 ] = pKeyInfo->vlMoveKeys.at( iNowStartSubKey ).vPos;
vArgs[ 2 ] = pKeyInfo->vlMoveKeys.at( iNowStartSubKey+1 ).vPos;
vArgs[ 3 ] = pKeyInfo->vlMoveKeys.at( iNowStartSubKey+1 ).vPos;
}
else
if( 0 == iLeaveCount ) // 맨 끝 인덱스
{
vArgs[ 0 ] = pKeyInfo->vlMoveKeys.at( iNowStartSubKey ).vPos;
vArgs[ 1 ] = pKeyInfo->vlMoveKeys.at( iNowStartSubKey ).vPos;
vArgs[ 2 ] = pKeyInfo->vlMoveKeys.at( iNowStartSubKey ).vPos;
vArgs[ 3 ] = pKeyInfo->vlMoveKeys.at( iNowStartSubKey ).vPos;
}
else
if( 1 == iLeaveCount )
{
vArgs[ 0 ] = pKeyInfo->vlMoveKeys.at( iNowStartSubKey ).vPos;
vArgs[ 1 ] = pKeyInfo->vlMoveKeys.at( iNowStartSubKey ).vPos;
vArgs[ 2 ] = pKeyInfo->vlMoveKeys.at( iNowStartSubKey+1 ).vPos;
vArgs[ 3 ] = pKeyInfo->vlMoveKeys.at( iNowStartSubKey+1 ).vPos;
}
else
//if( 2 < iLeaveCount )
{
vArgs[ 0 ] = pKeyInfo->vlMoveKeys.at( iNowStartSubKey-1 ).vPos;
vArgs[ 1 ] = pKeyInfo->vlMoveKeys.at( iNowStartSubKey ).vPos;
vArgs[ 2 ] = pKeyInfo->vlMoveKeys.at( iNowStartSubKey+1 ).vPos;
vArgs[ 3 ] = pKeyInfo->vlMoveKeys.at( iNowStartSubKey+2 ).vPos;
}
if( pKeyInfo->bFitYPosToMap )
{
for( int i = 0; i < 4; ++i )
vArgs[ i ].y = 0.0f;
}
EtVec3CatmullRom( &vNewPos, &vArgs[ 0 ], &vArgs[ 1 ], &vArgs[ 2 ], &vArgs[ 3 ], fNowSubKeyProceed );
EtVector3 vPrevPos = pKeySequence->pAniObjectInfoToPlay->vPrevPos; // 여기서 사용할 이전 위치 정보는 복사해두고,
if( pKeyInfo->bFitYPosToMap )
{
vNewPos.y = 0.0f;
vPrevPos.y = 0.0f;
}
EtVector3 vDir = vNewPos - vPrevPos;
pKeySequence->pAniObjectInfoToPlay->vPrevPos = vNewPos;
if( pKeyInfo->bRotateFront )
{
if( vNewPos != vPrevPos )
{
EtVector3 vTangent = vNewPos - vPrevPos;
_CalcRotateFront( pKeySequence->pAniObjectInfoToPlay, vTangent );
}
}
//if( pKeyInfo->bFitYPosToMap )
// vNewPos.y = m_pWorld->GetHeight( vNewPos.x, vNewPos.z );
pKeySequence->pAniObjectInfoToPlay->vPos = vNewPos;
pKeySequence->pAniObjectInfoToPlay->bKeyUseYPosToMap = pKeyInfo->bFitYPosToMap;
//pKeyObject->pAniObjectInfoToPlay->matExFinalPos.SetPosition( vNewPos );
if( bEndedSequence )
{
if( pKeyInfo->bRotateFront )
{
EtVector3 vDirInner = pKeyInfo->vlMoveKeys.back().vPos - pKeyInfo->vlMoveKeys.at(pKeyInfo->vlMoveKeys.size()-2).vPos;
_CalcRotateFront( pKeySequence->pAniObjectInfoToPlay, vDirInner );
}
EtVector3 vNewPosInner = pKeySequence->pKeyInfo->vlMoveKeys.back().vPos;
//if( pKeyInfo->bFitYPosToMap )
// vNewPosInner.y = m_pWorld->GetHeight( vNewPosInner.x, vNewPosInner.z );
S_CS_ACTOR_INFO* pActorInfo = pKeySequence->pAniObjectInfoToPlay;
pKeySequence->pAniObjectInfoToPlay->vPos = vNewPosInner;
// y 값을 맞추는 플래그가 켜져있다면 따로 anidistance 계산해서 맞춰줌.
if( pActorInfo->bKeyUseYPosToMap )
{
// Y 로테이션 값도 있으면 적용 시켜줌... 그러나 로테이션이 길게 겹쳐져 있는 경우 제대로 출력 안될 것이다..
float fFinalRotYDegree = pActorInfo->fRotYDegree + pActorInfo->fNowRotProceed;
float fScale = m_pActorProcessor->GetActorScale( pActorInfo->iActorIndexInProcessorVector );
if( fScale != 1.0f )
pActorInfo->vAniDistanceOffset.y = 0.0f;
m_pActorProcessor->CalcAniDistance( pActorInfo, pActorInfo->fFrame, 0.0f, pActorInfo->vAniDistanceOffset );
pActorInfo->vAniDistanceOffset.y = m_pWorld->GetHeight( pActorInfo->vPos.x, pActorInfo->vPos.z ) + pActorInfo->vAniDistanceOffset.y - pActorInfo->vPos.y;
}
else
pActorInfo->vAniDistanceOffset = EtVector3( 0.0f, 0.0f, 0.0f );
pActorInfo->vPos.y += pActorInfo->vAniDistanceOffset.y;
pActorInfo->vAniDistanceOffset = EtVector3( 0.0f, 0.0f, 0.0f );
pActorInfo->bKeyUseYPosToMap = false;
}
}
}
break;
case KeyInfo::ROTATION:
{
float fRotDeltaToDest = pKeyInfo->fRotDegree - pKeySequence->pAniObjectInfoToPlay->fRotYDegree;
pKeySequence->pAniObjectInfoToPlay->fNowRotProceed = (fRotDeltaToDest * fNowProceed);
if( bEndedSequence )
{
pKeySequence->pAniObjectInfoToPlay->fRotYDegree += pKeySequence->pAniObjectInfoToPlay->fNowRotProceed;
pKeySequence->pAniObjectInfoToPlay->fNowRotProceed = 0.0f;
}
}
break;
case KeyInfo::HIDE:
pKeySequence->pAniObjectInfoToPlay->hObject->ShowObject( false );
break;
case KeyInfo::SHOW:
pKeySequence->pAniObjectInfoToPlay->hObject->ShowObject( true );
break;
default:
break;
}
if( bEndedSequence )
pKeySequence->pAniObjectInfoToPlay->pNowKeySequence = NULL;
}
//_UpdateKeySequence( pProcessSequence );
break;
case CAM_EVENT_SEQUENCE:
{
S_CAM_EVENT_SEQUENCE* pCamEventSequence = static_cast<S_CAM_EVENT_SEQUENCE*>(pProcessSequence);
CCameraData* pCamData = pCamEventSequence->pCamEventInfo->pCameraData;
EtVector3 vCamPos( 0.0f, 0.0f, 0.0f );
EtVector3 vUp( 0.0f, 1.0f, 0.0f );
EtVector3 vLookAt( 0.0f, 0.0f, 0.0f );
// 현재 프레임을 계산한다.
LOCAL_TIME LiveElapsedTime = ElapsedTime - pCamEventSequence->dwStartTime;
float fLiveElapsedTime = (float)LiveElapsedTime * 0.001f;
float fFrame = fLiveElapsedTime * pCamEventSequence->pCamEventInfo->fSpeed;
EtMatrix matCamera;
// 우선 FOV 처리를 먼저
if( pCamData->m_Header.nFOVKeyCount > 0 )
{
pCamEventSequence->fFOVKeyFrame = fFrame;
if( (int)pCamEventSequence->fFOVKeyFrame > pCamData->m_vecFOV.back().nTime-1 )
pCamEventSequence->fFOVKeyFrame = (float)pCamData->m_vecFOV.back().nTime-1;
int iFOVOffsetIndex = _SearchFOVOffsetIndex( pCamData->m_vecFOV, (int)pCamEventSequence->fFOVKeyFrame );
const SCameraFOVKey& StartCamFOVKey = pCamData->m_vecFOV.at( iFOVOffsetIndex );
const SCameraFOVKey& EndCamFOVKey = pCamData->m_vecFOV.at( iFOVOffsetIndex+1 );
float fNowCamFOVProceed = float(pCamEventSequence->fFOVKeyFrame-(float)StartCamFOVKey.nTime) / float(EndCamFOVKey.nTime - StartCamFOVKey.nTime);
float fNowFOV = StartCamFOVKey.fFOV + ((EndCamFOVKey.fFOV-StartCamFOVKey.fFOV)*fNowCamFOVProceed);
EtMatrix matNewProj;
EtMatrixPerspectiveFovLH( &matNewProj, fNowFOV, m_hCamera->GetAspectRatio(),
m_hCamera->GetCameraNear(), m_hCamera->GetCameraFar() );
m_hCamera->SetProjMat( matNewProj );
}
// 카메라 위치 이동 키 처리
if( pCamData->m_Header.nPositionKeyCount > 0 )
{
pCamEventSequence->fPosKeyFrame = fFrame;
if( (int)pCamEventSequence->fRotKeyFrame > pCamData->m_vecPosition.back().nTime-1 )
pCamEventSequence->fRotKeyFrame = float(pCamData->m_vecPosition.back().nTime-1);
int iPosOffsetIndex = _SearchPosOffsetIndex( pCamData->m_vecPosition, (int)pCamEventSequence->fPosKeyFrame );
const SCameraPositionKey& StartCamPosKey = pCamData->m_vecPosition.at( iPosOffsetIndex );
const SCameraPositionKey& EndCamPosKey = pCamData->m_vecPosition.at( iPosOffsetIndex+1 );
float fNowCamPosProceed = float(pCamEventSequence->fPosKeyFrame-(float)StartCamPosKey.nTime) / float(EndCamPosKey.nTime - StartCamPosKey.nTime);
EtVec3Lerp( &vCamPos, &(StartCamPosKey.vPosition), &(EndCamPosKey.vPosition), fNowCamPosProceed );
// 카메라 시작 오프셋 값
vCamPos += pCamEventSequence->pCamEventInfo->vCamStartOffset;
vLookAt += pCamEventSequence->pCamEventInfo->vCamStartOffset;
}
EtQuat qCamRot;
EtQuaternionIdentity( &qCamRot );
if( pCamData->m_Header.nRotationKeyCount > 0 )
{
pCamEventSequence->fRotKeyFrame = fFrame;
if( (int)pCamEventSequence->fRotKeyFrame > pCamData->m_vecRotation.back().nTime-1 )
pCamEventSequence->fRotKeyFrame = float(pCamData->m_vecRotation.back().nTime-1);
int iRotOffsetIndex = _SearchRotOffsetIndex( pCamData->m_vecRotation, (int)pCamEventSequence->fRotKeyFrame );
// 회전 키
const SCameraRotationKey& StartRotKey = pCamData->m_vecRotation.at( iRotOffsetIndex );
const SCameraRotationKey& EndRotKey = pCamData->m_vecRotation.at( iRotOffsetIndex+1 );
float fRotKeyProceed = float(pCamEventSequence->fRotKeyFrame-(float)StartRotKey.nTime) / float(EndRotKey.nTime - StartRotKey.nTime);
EtQuaternionSlerp( &qCamRot, &StartRotKey.qRotation, &EndRotKey.qRotation, fRotKeyProceed );
}
EtMatrixTransformation( &matCamera, NULL, NULL, NULL, NULL, &qCamRot, &vCamPos );
m_hCamera->Update( &matCamera );
// 보여주는 액터와 아닌 액터들 show/hide 처리
if( false == pCamEventSequence->pCamEventInfo->mapActorsShowHide.empty() )
{
map<string, bool>& mapActorsShowHide = pCamEventSequence->pCamEventInfo->mapActorsShowHide;
map<string, bool>::iterator iter = mapActorsShowHide.begin();
for( iter; iter != mapActorsShowHide.end(); ++iter )
{
S_CS_ACTOR_INFO* pActorInfo = m_pActorProcessor->GetActorInfoByName( iter->first.c_str() );
//if( pActorInfo ) pActorInfo->hObject->ShowObject( iter->second );
// #54681 - 플레이어캐릭터의 Hide처리.
if( pActorInfo )
{
if( pActorInfo->bPlayer ) // 플레이어.
{
if( pActorInfo->pActor )
m_pActorProcessor->ShowEffect( pActorInfo->pActor, iter->second );
}
else // 그외.
{
if( pActorInfo->hObject )
pActorInfo->hObject->ShowObject( iter->second );
}
}
}
}
}
//_UpdateCamEventSequence( pProcessSequence );
break;
case DOF_EVENT_SEQUENCE:
{
if( !m_pDOFFilter )
{
break;
}
S_DOF_EVENT_SEQUENCE* pDofEventSequence = static_cast<S_DOF_EVENT_SEQUENCE*>(pProcessSequence);
DofEventInfo* pDofEventInfo = pDofEventSequence->pDofEventInfo;
// 현재 프레임을 계산한다
LOCAL_TIME WholeTime = pDofEventSequence->dwTimeLength;
LOCAL_TIME LiveElapsedTime = ElapsedTime - pDofEventSequence->dwStartTime;
//float fLiveElapsedTime = (float)LiveElapsedTime * 0.001f;
float fProceed = 0.0f;
if( WholeTime > LiveElapsedTime )
fProceed = (float)LiveElapsedTime / (float)WholeTime;
else
fProceed = 1.0f;
float fNearStart = pDofEventInfo->fNearStartFrom + (pDofEventInfo->fNearStartDest-pDofEventInfo->fNearStartFrom)*fProceed;
float fNearEnd = pDofEventInfo->fNearEndFrom + (pDofEventInfo->fNearEndDest-pDofEventInfo->fNearEndFrom)*fProceed;
float fFarStart = pDofEventInfo->fFarStartFrom + (pDofEventInfo->fFarStartDest-pDofEventInfo->fFarStartFrom)*fProceed;
float fFarEnd = pDofEventInfo->fFarEndFrom + (pDofEventInfo->fFarEndDest-pDofEventInfo->fFarEndFrom)*fProceed;
float fFocusDist = pDofEventInfo->fFocusDistFrom + (pDofEventInfo->fFocusDistDest-pDofEventInfo->fFocusDistFrom)*fProceed;
float fNearBlurSize = pDofEventInfo->fNearBlurSizeFrom + (pDofEventInfo->fNearBlurSizeDest-pDofEventInfo->fNearBlurSizeFrom)*fProceed;
float fFarBlurSize = pDofEventInfo->fFarBlurSizeFrom + (pDofEventInfo->fFarBlurSizeDest-pDofEventInfo->fFarBlurSizeFrom)*fProceed;
m_pDOFFilter->SetNearDOFStart( fNearStart );
m_pDOFFilter->SetNearDOFEnd( fNearEnd );
m_pDOFFilter->SetFarDOFStart( fFarStart );
m_pDOFFilter->SetFarDOFEnd( fFarEnd );
m_pDOFFilter->SetFocusDistance( fFocusDist );
m_pDOFFilter->SetNearBlurSize( fNearBlurSize );
m_pDOFFilter->SetFarBlurSize( fFarBlurSize );
}
break;
case PARTICLE_EVENT_SEQUENCE:
{
set<S_SEQUENCE*>::iterator iter = m_setProcessedTrigger.find( pProcessSequence );
if( m_setProcessedTrigger.end() == iter )
{
_BeginParticleEvent( pProcessSequence );
m_setProcessedTrigger.insert( pProcessSequence );
apProcessingSequence[ PARTICLE_EVENT_SEQUENCE ] = pProcessSequence;
}
}
//_UpdateParticleSequence( pProcessSequence );
break;
//case SOUND_EVENT_SEQUENCE:
// {
// set<S_SEQUENCE*>::iterator iter = m_setProcessedTrigger.find( pProcessSequence );
// if( m_setProcessedTrigger.end() == iter )
// {
// _BeginSoundEvent( pProcessSequence );
// m_setProcessedTrigger.insert( pProcessSequence );
// apProcessingSequence[ SOUND_EVENT_SEQUENCE ] = pProcessSequence;
// }
// }
// //_UpdateSoundEventSequence( pProcessSequence );
// break;
case FADE_EVENT_SEQUENCE:
{
set<S_SEQUENCE*>::iterator iter = m_setProcessedTrigger.find( pProcessSequence );
if( m_setProcessedTrigger.end() == iter )
{
_BeginFadeEvent( pProcessSequence );
m_setProcessedTrigger.insert( pProcessSequence );
apProcessingSequence[ FADE_EVENT_SEQUENCE ] = pProcessSequence;
}
}
//_UpdateFadeEventSequence( pProcessSequence );
break;
case PROP_EVENT_SEQUENCE:
{
set<S_SEQUENCE*>::iterator iter = m_setProcessedTrigger.find( pProcessSequence );
if( m_setProcessedTrigger.end() == iter )
{
_ProcessPropActionEvent( pProcessSequence, AbsoluteTime, ElapsedTime );
m_setProcessedTrigger.insert( pProcessSequence );
apProcessingSequence[ PROP_EVENT_SEQUENCE ] = pProcessSequence;
}
}
break;
case SOUND_EVENT_1_SEQUENCE:
case SOUND_EVENT_2_SEQUENCE:
case SOUND_EVENT_3_SEQUENCE:
case SOUND_EVENT_4_SEQUENCE:
case SOUND_EVENT_5_SEQUENCE:
case SOUND_EVENT_6_SEQUENCE:
case SOUND_EVENT_7_SEQUENCE:
case SOUND_EVENT_8_SEQUENCE:
{
set<S_SEQUENCE*>::iterator iter = m_setProcessedTrigger.find( pProcessSequence );
if( m_setProcessedTrigger.end() == iter )
{
_BeginSoundEvent( pProcessSequence );
m_setProcessedTrigger.insert( pProcessSequence );
int iSequenceIndex = SOUND_EVENT_1_SEQUENCE + (pProcessSequence->iType-SOUND_EVENT_1_SEQUENCE);
apProcessingSequence[ iSequenceIndex ] = pProcessSequence;
}
}
break;
case SUBTITLE_EVENT_SEQUENCE:
{
if( m_pLiveSubtitleSequence == NULL ||
(m_pLiveSubtitleSequence->pSubtitleEventInfo->iUIStringID !=
static_cast<S_SUBTITLE_EVENT_SEQUENCE*>(pProcessSequence)->pSubtitleEventInfo->iUIStringID) )
{
m_pActorProcessor->HideSubtitle();
_BeginSubtitleEvent( pProcessSequence );
apProcessingSequence[ SUBTITLE_EVENT_SEQUENCE ] = pProcessSequence;
}
}
break;
//#ifdef PRE_ADD_FILTEREVENT
case COLORFILTER_EVENT_SEQUENCE:
{
S_COLORFILTER_EVENT_SEQUENCE * pColorFilterEventSequence = static_cast<S_COLORFILTER_EVENT_SEQUENCE*>(pProcessSequence);
ColorFilterEventInfo * pCFEventInfo = pColorFilterEventSequence->pEventInfo;
//DofEventInfo* pDofEventInfo = pDofEventSequence->pDofEventInfo;
// 현재 프레임을 계산한다
LOCAL_TIME WholeTime = pColorFilterEventSequence->dwTimeLength;
LOCAL_TIME LiveElapsedTime = ElapsedTime - pColorFilterEventSequence->dwStartTime;
//float fLiveElapsedTime = (float)LiveElapsedTime * 0.001f;
float fProceed = 0.0f;
if( WholeTime > LiveElapsedTime )
fProceed = (float)LiveElapsedTime / (float)WholeTime;
else
fProceed = 1.0f;
//static_cast<CDnCutSceneWorld *>(m_pWorld)->SetSceneAbsoluteColor( pCFEventInfo->vColor, pCFEventInfo->fVolume );
m_pWorld->SetSceneAbsoluteColor( pCFEventInfo->bMonochrome, pCFEventInfo->vColor, pCFEventInfo->fVolume );
}
break;
//#endif PRE_ADD_FILTEREVENT
}
}
// 시작 시간이 ElapsedTime 넘어간 경우는 패스
++iSequence;
bool bDBEnd = false;
bDBEnd = (iSequence >= (int)m_vlpSequenceDB.size());
if( bDBEnd )
break;
pProcessSequence = m_vlpSequenceDB.at( iSequence );
}
}
void CDnCutScenePlayer::_ProcessSubtitle( LOCAL_TIME ElapsedTime )
{
if( m_pLiveSubtitleSequence )
{
// 시간 다 되면 자막을 숨김
if( ElapsedTime - m_pLiveSubtitleSequence->dwStartTime > m_pLiveSubtitleSequence->dwTimeLength )
{
m_pActorProcessor->HideSubtitle();
}
}
}
void CDnCutScenePlayer::Process( LOCAL_TIME AbsoluteTime )
{
LOCAL_TIME ElapsedTime = AbsoluteTime - m_StartTime;
if( false == IsEndScene() )
{
//_FigureOutEndSeuqnces(ElapsedTime);
//_FigureOutLiveSequences(ElapsedTime);
_UpdateSequence( AbsoluteTime, ElapsedTime );
//_ProcessSequences(ElapsedTime);
_ProcessActors(AbsoluteTime, ElapsedTime);
_ProcessSubtitle( ElapsedTime );
if( m_WholeSceneLength < ElapsedTime )
{
StopPlay();
}
}
m_PrevTime = AbsoluteTime;
}
void CDnCutScenePlayer::ResetPlayingSoundChannels( void )
{
// 재생중인 사운드 정지.. 지금은 함수가 없으므로 볼륨을 0으로 줄인다.
int iNumPlayingChannel = (int)m_vlhPlayingChannel.size();
for( int i = 0; i < iNumPlayingChannel; ++i )
{
EtSoundChannelHandle hChannel = m_vlhPlayingChannel.at(i);
if( hChannel )
CEtSoundEngine::GetInstance().RemoveChannel( hChannel );
}
m_vlhPlayingChannel.clear();
}
void CDnCutScenePlayer::StopPlay()
{
if( m_bSceneEnd == true ) return;
m_bSceneEnd = true;
// 프로젝션 행렬을 원상 복구 시켜준다.
m_hCamera->SetProjMat( m_matOriProj );
ResetPlayingSoundChannels();
m_pActorProcessor->OnEndPlayScene();
//#ifdef PRE_ADD_FILTEREVENT
m_pWorld->SetSceneAbsoluteColor( false, EtVector3(1.0f,1.0f,1.0f), 1.0f );
//#endif // PRE_ADD_FILTEREVENT
}