420 lines
10 KiB
C++
420 lines
10 KiB
C++
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Crytek Engine Source File.
|
|
// Copyright (C), Crytek Studios, 2002.
|
|
// -------------------------------------------------------------------------
|
|
// File name: animsequence.cpp
|
|
// Version: v1.00
|
|
// Created: 29/4/2002 by Timur.
|
|
// Compilers: Visual Studio.NET
|
|
// Description:
|
|
// -------------------------------------------------------------------------
|
|
// History:
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "StdAfx.h"
|
|
#include "AnimSequence.h"
|
|
#include "SceneNode.h"
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
CAnimSequence::CAnimSequence( IMovieSystem *pMovieSystem )
|
|
{
|
|
m_pMovieSystem = pMovieSystem;
|
|
m_flags = 0;
|
|
m_pSceneNode=NULL;
|
|
m_timeRange.Set( 0,10 );
|
|
m_bPaused = false;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CAnimSequence::SetName( const char *name )
|
|
{
|
|
m_name = name;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
const char* CAnimSequence::GetName()
|
|
{
|
|
return m_name.c_str();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CAnimSequence::SetFlags( int flags )
|
|
{
|
|
m_flags = flags;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
int CAnimSequence::GetFlags() const
|
|
{
|
|
return m_flags;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
int CAnimSequence::GetNodeCount() const
|
|
{
|
|
return m_nodes.size();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
IAnimNode* CAnimSequence::GetNode( int index ) const
|
|
{
|
|
assert( index >= 0 && index < (int)m_nodes.size() );
|
|
return m_nodes[index].node;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
IAnimBlock* CAnimSequence::GetAnimBlock( int index ) const
|
|
{
|
|
assert( index >= 0 && index < (int)m_nodes.size() );
|
|
return m_nodes[index].anim;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool CAnimSequence::AddNode( IAnimNode *node )
|
|
{
|
|
assert( node != 0 );
|
|
|
|
// Check if this node already in sequence.
|
|
for (int i = 0; i < (int)m_nodes.size(); i++)
|
|
{
|
|
if (node == m_nodes[i].node)
|
|
{
|
|
// Fail to add node second time.
|
|
return false;
|
|
}
|
|
}
|
|
|
|
ANode an;
|
|
an.node = node;
|
|
an.anim = new CAnimBlock;//node->CreateAnimBlock();
|
|
an.anim->SetTimeRange( m_timeRange );
|
|
an.node->SetAnimBlock( an.anim );
|
|
m_nodes.push_back( an );
|
|
|
|
return true;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CAnimSequence::RemoveNode( IAnimNode *node )
|
|
{
|
|
assert( node != 0 );
|
|
for (int i = 0; i < (int)m_nodes.size(); i++)
|
|
{
|
|
if (node == m_nodes[i].node)
|
|
{
|
|
if (node->GetAnimBlock() == m_nodes[i].anim)
|
|
node->SetAnimBlock( 0 );
|
|
m_nodes.erase( m_nodes.begin()+i );
|
|
if (node && (node==m_pSceneNode))
|
|
m_pSceneNode=NULL;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
IAnimNode* CAnimSequence::AddSceneNode()
|
|
{
|
|
if (m_pSceneNode)
|
|
return NULL;
|
|
m_pSceneNode=new CAnimSceneNode(GetMovieSystem());
|
|
m_pSceneNode->SetName("Scene");
|
|
AddNode(m_pSceneNode);
|
|
return m_pSceneNode;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CAnimSequence::RemoveAll()
|
|
{
|
|
m_nodes.clear();
|
|
m_pSceneNode=NULL;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CAnimSequence::Reset()
|
|
{
|
|
// Animation sequence should not be animated on Reset.
|
|
Activate();
|
|
|
|
SAnimContext ec;
|
|
ec.bSingleFrame = true;
|
|
ec.bResetting = true;
|
|
ec.sequence = this;
|
|
ec.time = m_timeRange.start;
|
|
Animate( ec );
|
|
|
|
Deactivate();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CAnimSequence::Pause()
|
|
{
|
|
if (m_bPaused)
|
|
return;
|
|
m_bPaused = true;
|
|
// Detach animation block from all nodes in this sequence.
|
|
for (AnimNodes::iterator it = m_nodes.begin(); it != m_nodes.end(); ++it)
|
|
{
|
|
it->node->Pause();
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CAnimSequence::Resume()
|
|
{
|
|
if (!m_bPaused)
|
|
return;
|
|
m_bPaused = false;
|
|
// Detach animation block from all nodes in this sequence.
|
|
for (AnimNodes::iterator it = m_nodes.begin(); it != m_nodes.end(); ++it)
|
|
{
|
|
it->node->Resume();
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CAnimSequence::Animate( SAnimContext &ec )
|
|
{
|
|
ec.sequence = this;
|
|
// Evaluate all animation nodes in sequence.
|
|
for (AnimNodes::iterator it = m_nodes.begin(); it != m_nodes.end(); ++it)
|
|
{
|
|
// Make sure correct animation block is binded to node.
|
|
IAnimBlock *ablock = it->anim;
|
|
if (it->node->GetAnimBlock() != ablock)
|
|
{
|
|
ablock->SetTimeRange( m_timeRange );
|
|
it->node->SetAnimBlock( ablock );
|
|
}
|
|
// Animate node.
|
|
it->node->Animate( ec );
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CAnimSequence::Activate()
|
|
{
|
|
// Assign animation block to all nodes in this sequence.
|
|
for (AnimNodes::iterator it = m_nodes.begin(); it != m_nodes.end(); ++it)
|
|
{
|
|
IAnimBlock *ablock = it->anim;
|
|
ablock->SetTimeRange( m_timeRange );
|
|
it->node->SetAnimBlock( ablock );
|
|
}
|
|
|
|
// If this sequence is cut scene disable player.
|
|
if (m_flags & CUT_SCENE)
|
|
{
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CAnimSequence::Deactivate()
|
|
{
|
|
// Detach animation block from all nodes in this sequence.
|
|
for (AnimNodes::iterator it = m_nodes.begin(); it != m_nodes.end(); ++it)
|
|
{
|
|
it->node->Reset();
|
|
it->node->SetAnimBlock( 0 );
|
|
}
|
|
// If this sequence is cut scene, enable player.
|
|
if (m_flags & CUT_SCENE)
|
|
{
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CAnimSequence::Serialize( XmlNodeRef &xmlNode,bool bLoading, bool bLoadEmptyTracks )
|
|
{
|
|
if (bLoading)
|
|
{
|
|
// Load.
|
|
RemoveAll();
|
|
|
|
Range timeRange;
|
|
const char *name = xmlNode->getAttr( "Name" );
|
|
xmlNode->getAttr( "Flags",m_flags );
|
|
xmlNode->getAttr( "StartTime",timeRange.start );
|
|
xmlNode->getAttr( "EndTime",timeRange.end );
|
|
|
|
SetName( name );
|
|
SetTimeRange( timeRange );
|
|
// Loading.
|
|
XmlNodeRef nodes = xmlNode->findChild( "Nodes" );
|
|
if (nodes)
|
|
{
|
|
int id;
|
|
int type;
|
|
for (int i = 0; i < nodes->getChildCount(); i++)
|
|
{
|
|
XmlNodeRef xn = nodes->getChild(i);
|
|
xn->getAttr( "Id",id );
|
|
IAnimNode *node=NULL;
|
|
if (!id) // scene-node-id
|
|
{
|
|
if (m_pSceneNode)
|
|
node=m_pSceneNode;
|
|
else
|
|
node=AddSceneNode();
|
|
}else
|
|
{
|
|
node = m_pMovieSystem->GetNode(id);
|
|
}
|
|
if (!node)
|
|
{
|
|
if (!xn->getAttr( "Type",type ))
|
|
continue;
|
|
node = m_pMovieSystem->CreateNode( type );
|
|
if (!node)
|
|
continue;
|
|
const char *sName = xn->getAttr( "Name" );
|
|
if (sName)
|
|
node->SetName(sName);
|
|
}
|
|
|
|
// Add nodes to sequence and intialize its animation block for this sequence.
|
|
if (node!=m_pSceneNode)
|
|
AddNode(node);
|
|
|
|
IAnimBlock *ablock = node->GetAnimBlock();
|
|
if (ablock)
|
|
{
|
|
ablock->Serialize( node,xn,bLoading,bLoadEmptyTracks );
|
|
}
|
|
}
|
|
}
|
|
Deactivate();
|
|
//ComputeTimeRange();
|
|
}
|
|
else
|
|
{
|
|
xmlNode->setAttr( "Name",GetName() );
|
|
xmlNode->setAttr( "Flags",m_flags );
|
|
xmlNode->setAttr( "StartTime",m_timeRange.start );
|
|
xmlNode->setAttr( "EndTime",m_timeRange.end );
|
|
|
|
// Save.
|
|
XmlNodeRef nodes = xmlNode->newChild( "Nodes" );
|
|
int num = GetNodeCount();
|
|
for (int i = 0; i < num; i++)
|
|
{
|
|
IAnimNode *node = GetNode(i);
|
|
if (!node)
|
|
continue;
|
|
XmlNodeRef xn = nodes->newChild( "Node" );
|
|
xn->setAttr( "Id",node->GetId() );
|
|
xn->setAttr( "Type",node->GetType() );
|
|
xn->setAttr( "Name",node->GetName() );
|
|
|
|
IAnimBlock *ablock = GetAnimBlock(i);
|
|
if (!ablock)
|
|
continue;
|
|
|
|
ablock->Serialize( node,xn,bLoading );
|
|
}
|
|
/*
|
|
for (AnimNodes::iterator it = m_nodes.begin(); it != m_nodes.end(); ++it)
|
|
{
|
|
IAnimNode *node = it->node;
|
|
if (!node)
|
|
continue;
|
|
IAnimBlock *ablock = it->anim;
|
|
XmlNodeRef xn = nodes->newChild( "Node" );
|
|
xn->setAttr( "Id",node->GetId() );
|
|
}
|
|
*/
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CAnimSequence::SetTimeRange( Range timeRange )
|
|
{
|
|
m_timeRange = timeRange;
|
|
// Set this time range for every track in animation.
|
|
// Set time range to be in range of largest animation track.
|
|
for (AnimNodes::iterator it = m_nodes.begin(); it != m_nodes.end(); ++it)
|
|
{
|
|
IAnimBlock *ablock = it->anim;
|
|
if (!ablock)
|
|
continue;
|
|
ablock->SetTimeRange( timeRange );
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CAnimSequence::ScaleTimeRange( const Range &timeRange )
|
|
{
|
|
// Calculate scale ratio.
|
|
float scale = timeRange.Length() / m_timeRange.Length();
|
|
m_timeRange = timeRange;
|
|
|
|
// Set time range to be in range of largest animation track.
|
|
for (AnimNodes::iterator it = m_nodes.begin(); it != m_nodes.end(); ++it)
|
|
{
|
|
IAnimBlock *ablock = it->anim;
|
|
if (!ablock)
|
|
continue;
|
|
|
|
int paramCount = ablock->GetTrackCount();
|
|
for (int paramIndex = 0; paramIndex < paramCount; paramIndex++)
|
|
{
|
|
int trackType;
|
|
IAnimTrack *pTrack;
|
|
if (!ablock->GetTrackInfo( paramIndex,trackType,&pTrack ))
|
|
continue;
|
|
if (pTrack)
|
|
{
|
|
int nkey = pTrack->GetNumKeys();
|
|
for (int k = 0; k < nkey; k++)
|
|
{
|
|
float keytime = pTrack->GetKeyTime(k);
|
|
keytime = keytime*scale;
|
|
pTrack->SetKeyTime(k,keytime);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CAnimSequence::ComputeTimeRange()
|
|
{
|
|
Range timeRange;
|
|
//timeRange.start = FLT_MAX;
|
|
//timeRange.end = FLT_MIN;
|
|
|
|
timeRange = m_timeRange;
|
|
|
|
// Set time range to be in range of largest animation track.
|
|
for (AnimNodes::iterator it = m_nodes.begin(); it != m_nodes.end(); ++it)
|
|
{
|
|
IAnimBlock *ablock = it->anim;
|
|
if (!ablock)
|
|
continue;
|
|
|
|
int paramCount = ablock->GetTrackCount();
|
|
for (int paramIndex = 0; paramIndex < paramCount; paramIndex++)
|
|
{
|
|
int trackType;
|
|
IAnimTrack *pTrack;
|
|
if (!ablock->GetTrackInfo( paramIndex,trackType,&pTrack ))
|
|
continue;
|
|
if (pTrack)
|
|
{
|
|
int nkey = pTrack->GetNumKeys();
|
|
if (nkey > 0)
|
|
{
|
|
timeRange.start = min( timeRange.start,pTrack->GetKeyTime(0) );
|
|
timeRange.end = max( timeRange.end,pTrack->GetKeyTime(nkey-1) );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (timeRange.start > 0)
|
|
timeRange.start = 0;
|
|
|
|
m_timeRange = timeRange;
|
|
} |