Files
FC1/CryMovie/EntityNode.cpp
romkazvo 34d6c5d489 123
2023-08-07 19:29:24 +08:00

1007 lines
27 KiB
C++

////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2001.
// -------------------------------------------------------------------------
// File name: entitynode.cpp
// Version: v1.00
// Created: 23/4/2002 by Timur.
// Compilers: Visual C++ 7.0
// Description:
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#include "StdAfx.h"
#include "EntityNode.h"
#include "EventTrack.h"
#include "CharacterTrack.h"
#include "AnimSplineTrack.h"
#include "ExprTrack.h"
#include "BoolTrack.h"
#include "isystem.h"
#include "ilog.h"
#include "Movie.h"
#include <ISound.h>
#include <ILipSync.h>
#include <ICryAnimation.h>
#include <CryCharMorphParams.h>
#include <IGame.h>
//////////////////////////////////////////////////////////////////////////
namespace
{
//////////////////////////////////////////////////////////////////////////
Matrix44 Vector2Matrix( const Vec3 &dir,const Vec3 &up,float rollAngle=0 )
{
Matrix44 M;
// LookAt transform.
Vec3d xAxis,yAxis,zAxis;
Vec3d upVector = up;
yAxis = GetNormalized(-dir);
//if (zAxis.x == 0.0 && zAxis.z == 0) up.Set( -zAxis.y,0,0 ); else up.Set( 0,1.0f,0 );
xAxis = GetNormalized((upVector.Cross(yAxis)));
zAxis = GetNormalized(xAxis.Cross(yAxis));
// OpenGL kind of matrix.
M[0][0] = xAxis.x;
M[1][0] = yAxis.x;
M[2][0] = zAxis.x;
M[3][0] = 0;
M[0][1] = xAxis.y;
M[1][1] = yAxis.y;
M[2][1] = zAxis.y;
M[3][1] = 0;
M[0][2] = xAxis.z;
M[1][2] = yAxis.z;
M[2][2] = zAxis.z;
M[3][2] = 0;
M[0][3] = 0;
M[1][3] = 0;
M[2][3] = 0;
M[3][3] = 1;
if (rollAngle != 0)
{
Matrix44 RollMtx;
RollMtx.SetIdentity();
float s = cry_sinf(rollAngle);
float c = cry_cosf(rollAngle);
RollMtx[0][0] = c; RollMtx[2][0] = -s;;
RollMtx[0][2] = s; RollMtx[2][2] = c;
// Matrix multiply.
M = RollMtx * M;
}
return M;
}
bool s_nodeParamsInitialized = false;
std::vector<IAnimNode::SParamInfo> s_nodeParams;
void AddSupportedParam( std::vector<IAnimNode::SParamInfo> &nodeParams,const char *sName,int paramId,EAnimValue valueType )
{
IAnimNode::SParamInfo param;
param.name = sName;
param.paramId = paramId;
param.valueType = valueType;
nodeParams.push_back( param );
}
};
//////////////////////////////////////////////////////////////////////////
CAnimEntityNode::CAnimEntityNode( IMovieSystem *sys )
: CAnimNode(sys)
{
m_dwSupportedTracks = PARAM_BIT(APARAM_POS)|PARAM_BIT(APARAM_ROT)|PARAM_BIT(APARAM_SCL)|
PARAM_BIT(APARAM_EVENT)|PARAM_BIT(APARAM_VISIBLE)|
PARAM_BIT(APARAM_SOUND1)|PARAM_BIT(APARAM_SOUND2)|PARAM_BIT(APARAM_SOUND3)|
PARAM_BIT(APARAM_CHARACTER1)|PARAM_BIT(APARAM_CHARACTER2)|PARAM_BIT(APARAM_CHARACTER3)|
PARAM_BIT(APARAM_EXPRESSION1)|PARAM_BIT(APARAM_EXPRESSION2)|PARAM_BIT(APARAM_EXPRESSION3);
m_entity = 0;
m_EntityId = 0;
m_target=NULL;
m_pMovie=sys;
m_bMatrixValid = 0;
m_bMatrixInWorldSpace = 0;
m_worldTM.SetIdentity();
m_pos(0,0,0);
m_scale(1,1,1);
m_visible = true;
m_lastEntityKey = -1;
m_lastCharacterKey[0] = -1;
m_lastCharacterKey[1] = -1;
m_lastCharacterKey[2] = -1;
for (int i=0;i<ENTITY_SOUNDTRACKS;i++)
{
m_SoundInfo[i].nLastKey=-1;
m_SoundInfo[i].pSound=NULL;
m_SoundInfo[i].sLastFilename="";
}
if (!s_nodeParamsInitialized)
{
s_nodeParamsInitialized = true;
AddSupportedParams( s_nodeParams );
}
}
//////////////////////////////////////////////////////////////////////////
void CAnimEntityNode::AddSupportedParams( std::vector<IAnimNode::SParamInfo> &nodeParams )
{
AddSupportedParam( nodeParams,"Position",APARAM_POS,AVALUE_VECTOR );
AddSupportedParam( nodeParams,"Rotation",APARAM_ROT,AVALUE_QUAT );
AddSupportedParam( nodeParams,"Scale",APARAM_SCL,AVALUE_VECTOR );
AddSupportedParam( nodeParams,"Visibility",APARAM_VISIBLE,AVALUE_BOOL );
AddSupportedParam( nodeParams,"Event",APARAM_EVENT,AVALUE_EVENT );
AddSupportedParam( nodeParams,"Sound1",APARAM_SOUND1,AVALUE_SOUND );
AddSupportedParam( nodeParams,"Sound2",APARAM_SOUND2,AVALUE_SOUND );
AddSupportedParam( nodeParams,"Sound3",APARAM_SOUND3,AVALUE_SOUND );
AddSupportedParam( nodeParams,"Animation1",APARAM_CHARACTER1,AVALUE_CHARACTER );
AddSupportedParam( nodeParams,"Animation2",APARAM_CHARACTER2,AVALUE_CHARACTER );
AddSupportedParam( nodeParams,"Animation3",APARAM_CHARACTER3,AVALUE_CHARACTER );
AddSupportedParam( nodeParams,"Expression1",APARAM_EXPRESSION1,AVALUE_EXPRESSION );
AddSupportedParam( nodeParams,"Expression2",APARAM_EXPRESSION2,AVALUE_EXPRESSION );
AddSupportedParam( nodeParams,"Expression3",APARAM_EXPRESSION3,AVALUE_EXPRESSION );
}
//////////////////////////////////////////////////////////////////////////
void CAnimEntityNode::CreateDefaultTracks()
{
CreateTrack(APARAM_POS);
CreateTrack(APARAM_ROT);
};
//////////////////////////////////////////////////////////////////////////
CAnimEntityNode::~CAnimEntityNode()
{
ReleaseSounds();
}
//////////////////////////////////////////////////////////////////////////
int CAnimEntityNode::GetParamCount() const
{
return s_nodeParams.size();
}
//////////////////////////////////////////////////////////////////////////
bool CAnimEntityNode::GetParamInfo( int nIndex, SParamInfo &info ) const
{
if (nIndex >= 0 && nIndex < s_nodeParams.size())
{
info = s_nodeParams[nIndex];
return true;
}
return false;
}
//////////////////////////////////////////////////////////////////////////
bool CAnimEntityNode::GetParamInfoFromId( int paramId, SParamInfo &info ) const
{
for (int i = 0; i < s_nodeParams.size(); i++)
{
if (s_nodeParams[i].paramId == paramId)
{
info = s_nodeParams[i];
return true;
}
}
return false;
}
//////////////////////////////////////////////////////////////////////////
void CAnimEntityNode::SetEntity( IEntity *entity )
{
m_entity = entity;
if (m_entity)
m_EntityId = m_entity->GetId();
else
m_EntityId = 0;
}
//////////////////////////////////////////////////////////////////////////
IEntity* CAnimEntityNode::GetEntity()
{
if (!m_entity)
ResolveEntity();
return m_entity;
}
/*
//////////////////////////////////////////////////////////////////////////
IAnimBlock* CAnimEntityNode::CreateAnimBlock()
{
// Assign entity tracks to this anim node.
IAnimBlock *block = new CAnimBlock;
CreateTrack(block, APARAM_POS);
CreateTrack(block, APARAM_ROT);
return block;
};*/
//////////////////////////////////////////////////////////////////////////
bool CAnimEntityNode::ResolveEntity()
{
IEntitySystem *pEntitySystem=GetMovieSystem()->GetSystem()->GetIEntitySystem();
if (!pEntitySystem)
return false;
m_entity = pEntitySystem->GetEntity(m_EntityId);
return (m_entity != NULL);
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
void CAnimEntityNode::Animate( SAnimContext &ec )
{
CAnimBlock *anim = (CAnimBlock*)GetAnimBlock();
if (!anim)
return;
if (!m_entity)
{
if (!ResolveEntity())
return;
}
Vec3 pos = m_pos;
Quat rotate = m_rotate;
Vec3 scale = m_scale;
IAnimTrack *posTrack = NULL;
IAnimTrack *rotTrack = NULL;
IAnimTrack *sclTrack = NULL;
if (!ec.bResetting)
{
StopExpressions();
}
int paramCount = anim->GetTrackCount();
for (int paramIndex = 0; paramIndex < paramCount; paramIndex++)
{
int trackType;
IAnimTrack *pTrack;
if (!anim->GetTrackInfo( paramIndex,trackType,&pTrack ))
continue;
switch (trackType)
{
case APARAM_POS:
posTrack = pTrack;
posTrack->GetValue( ec.time,pos );
break;
case APARAM_ROT:
rotTrack = pTrack;
rotTrack->GetValue( ec.time,rotate );
break;
case APARAM_SCL:
sclTrack = pTrack;
sclTrack->GetValue( ec.time,scale );
break;
case APARAM_EVENT:
if (!ec.bResetting)
{
CEventTrack *entityTrack = (CEventTrack*)pTrack;
IEventKey key;
int entityKey = entityTrack->GetActiveKey(ec.time,&key);
// If key is different or if time is standing exactly on key time.
//if ((entityKey != m_lastEntityKey || key.time == ec.time) && (!ec.bSingleFrame))
if (entityKey != m_lastEntityKey || key.time == ec.time)
{
m_lastEntityKey = entityKey;
if (entityKey >= 0)
{
if (!ec.bSingleFrame || key.time == ec.time) // If Single frame update key time must match current time.
ApplyEventKey( entityTrack,entityKey,key );
}
}
}
break;
case APARAM_VISIBLE:
if (!ec.bResetting)
{
IAnimTrack *visTrack = pTrack;
bool visible = m_visible;
visTrack->GetValue( ec.time,visible );
m_entity->Hide(!visible);
m_visible = visible;
}
break;
//////////////////////////////////////////////////////////////////////////
case APARAM_SOUND1:
case APARAM_SOUND2:
case APARAM_SOUND3:
if (!ec.bResetting)
{
int nSoundIndex = trackType - APARAM_SOUND1;
CSoundTrack *pSoundTrack = (CSoundTrack*)pTrack;
ISoundKey key;
int nSoundKey = pSoundTrack->GetActiveKey(ec.time, &key);
if (nSoundKey!=m_SoundInfo[nSoundIndex].nLastKey || key.time==ec.time || nSoundKey==-1)
{
if (!ec.bSingleFrame || key.time == ec.time) // If Single frame update key time must match current time.
{
m_SoundInfo[nSoundIndex].nLastKey=nSoundKey;
ApplySoundKey( pSoundTrack,nSoundKey,nSoundIndex, key, ec);
}
}
}
break;
//////////////////////////////////////////////////////////////////////////
case APARAM_CHARACTER1:
case APARAM_CHARACTER2:
case APARAM_CHARACTER3:
if (!ec.bResetting)
{
int index = trackType - APARAM_CHARACTER1;
CCharacterTrack *pCharTrack = (CCharacterTrack*)pTrack;
AnimateCharacterTrack( pCharTrack,ec,index );
}
break;
//////////////////////////////////////////////////////////////////////////
case APARAM_EXPRESSION1:
case APARAM_EXPRESSION2:
case APARAM_EXPRESSION3:
if (!ec.bResetting)
{
CExprTrack *pExpTrack = (CExprTrack*)pTrack;
AnimateExpressionTrack( pExpTrack,ec );
}
break;
};
}
if (!ec.bResetting)
{
//////////////////////////////////////////////////////////////////////////
// If not restting animation sequence.
//////////////////////////////////////////////////////////////////////////
if (!ec.bSingleFrame)
{
IPhysicalEntity *pEntityPhysics = m_entity->GetPhysics();
if (pEntityPhysics)
{
if (ec.time - m_time < 0.1f)
{
float timeStep = ec.time - m_time;
float rtimeStep = timeStep>1E-5f ? 1.0f/timeStep : 0.0f;
pe_action_set_velocity asv;
asv.v = (pos - m_pos)*rtimeStep;
asv.w = (rotate*!m_rotate).v*(rtimeStep*2);
pEntityPhysics->Action(&asv);
}
}
}
} // not single frame
bool bMatrixModified = false;
bool bPosModified = (m_pos != pos);
bool bAnglesModified = (m_rotate.v != rotate.v) || (m_rotate.w != rotate.w);
if (bPosModified || bAnglesModified || (m_scale != scale) || (m_target!=NULL))
{
InvalidateTM();
bMatrixModified = true;
m_pos = pos;
m_scale = scale;
m_rotate = rotate;
}
m_time = ec.time;
if (bMatrixModified)
{
/*
if (m_target)
{
Matrix Mat;
GetWorldTM(Mat);
Quat q(Mat);
Vec3 angles = q.GetEulerAngles();
angles = RAD2DEG(angles);
angles = angles;
}
*/
if (m_callback)
{
if (m_target)
{
// To Update m_rotate member for Editor.
Matrix44 Mat;
GetWorldTM(Mat);
}
m_callback->OnNodeAnimated();
}
else // no callback specified, so lets move the entity directly
{
if (bPosModified && posTrack)
m_entity->SetPos(m_pos,false);
if (m_target)
{
Matrix44 Mat;
GetWorldTM(Mat);
//CHAMGED_BY_IVO
//Quat q(Mat);
//Quat q = CovertMatToQuat<float>( GetTransposed44(Mat) );
Quat q = Quat( GetTransposed44(Mat) );
Vec3 angles = Ang3::GetAnglesXYZ(Matrix33(q));
angles = RAD2DEG(angles);
m_entity->SetAngles(angles);
}else
{
if (bAnglesModified && rotTrack)
m_entity->SetAngles( RAD2DEG(Ang3::GetAnglesXYZ(Matrix33(m_rotate))) );
}
if (sclTrack)
m_entity->SetScale(m_scale.x);
}
}
}
//////////////////////////////////////////////////////////////////////////
void CAnimEntityNode::ReleaseSounds()
{
// stop all sounds
for (int i=0;i<ENTITY_SOUNDTRACKS;i++)
{
if (m_SoundInfo[i].pSound)
m_SoundInfo[i].pSound->Stop();
m_SoundInfo[i].pSound = NULL;
m_SoundInfo[i].nLastKey=-1;
if (!m_SoundInfo[i].sLastFilename.empty())
m_SoundInfo[i].sLastFilename = "";
}
}
//////////////////////////////////////////////////////////////////////////
void CAnimEntityNode::Reset()
{
m_lastEntityKey = -1;
m_lastCharacterKey[0] = -1;
m_lastCharacterKey[1] = -1;
m_lastCharacterKey[2] = -1;
ReleaseSounds();
ReleaseAllAnims();
m_entity = NULL;
}
//////////////////////////////////////////////////////////////////////////
void CAnimEntityNode::Pause()
{
ReleaseSounds();
}
//////////////////////////////////////////////////////////////////////////
void CAnimEntityNode::CalcLocalMatrix()
{
if (m_target)
{
// Calculate loookat matrix.
float fRollAngle = 0;
Matrix44 trgTM;
m_target->GetWorldTM(trgTM);
Vec3 pos = m_pos;
IAnimNode *pParent = GetParent();
if (pParent)
{
// Get our world position.
Matrix44 parentTM;
pParent->GetWorldTM(parentTM);
pos = parentTM.TransformPointOLD(pos);
}
Vec3 camDirection = trgTM.GetTranslationOLD() - pos;
m_worldTM = Vector2Matrix( camDirection,Vec3(0,0,-1),fRollAngle );
// Rotate.. Assign to quaternion actual rotation.
//QUAT_CHANGED_BY_IVO
//m_rotate = Quat(m_worldTM);
//m_rotate = CovertMatToQuat<float>( GetTransposed44(m_worldTM) );
m_rotate = Quat( GetTransposed44(m_worldTM) );
// Translate matrix.
m_worldTM[3][0] = m_pos.x;
m_worldTM[3][1] = m_pos.y;
m_worldTM[3][2] = m_pos.z;
m_worldTM[3][3] = 1.0f;
m_bMatrixInWorldSpace = true;
m_bMatrixValid = true;
}
else
{
// Calculate PRS (Pos-Rotation-Scale) Transform.
//Q2M_CHANGED_BY_IVO
//m_rotate.GetMatrix( m_worldTM );
m_worldTM = GetTransposed44( Matrix44(m_rotate) );
//SCALE_CHANGED_BY_IVO
//m_worldTM.ScaleMatrix( m_scale.x,m_scale.y,m_scale.z );
m_worldTM=Matrix33::CreateScale( Vec3(m_scale.x,m_scale.y,m_scale.z) ) * m_worldTM;
// Translate matrix.
m_worldTM[3][0] = m_pos.x;
m_worldTM[3][1] = m_pos.y;
m_worldTM[3][2] = m_pos.z;
m_worldTM[3][3] = 1.0f;
m_bMatrixInWorldSpace = false;
m_bMatrixValid = true;
}
}
//////////////////////////////////////////////////////////////////////////
void CAnimEntityNode::GetWorldTM( Matrix44 &tm )
{
if (!m_bMatrixValid)
{
CalcLocalMatrix();
}
if (!m_bMatrixInWorldSpace)
{
IAnimNode *parent = GetParent();
if (parent)
{
Matrix44 parentTM;
parent->GetWorldTM(parentTM);
m_worldTM = m_worldTM * parentTM;
}
m_bMatrixInWorldSpace = true;
}
tm = m_worldTM;
}
//////////////////////////////////////////////////////////////////////////
void CAnimEntityNode::InvalidateTM()
{
m_bMatrixInWorldSpace = false;
m_bMatrixValid = false;
}
/*
//////////////////////////////////////////////////////////////////////////
Vec3 CAnimEntityNode::GetPos( float time )
{
Vec3 pos(0,0,0);
IAnimBlock *anim = GetAnimBlock();
if (!anim)
return pos;
IAnimTrack *posTrack = anim->GetTrack(APARAM_POS);
if (posTrack)
posTrack->GetValue( time,pos );
return pos;
}
//////////////////////////////////////////////////////////////////////////
Quat CAnimEntityNode::GetRotate( float time )
{
Quat q;
IAnimBlock *anim = GetAnimBlock();
if (!anim)
return q;
IAnimTrack *rotTrack = anim->GetTrack(APARAM_ROT);
if (rotTrack)
rotTrack->GetValue( time,q );
return q;
}
//////////////////////////////////////////////////////////////////////////
Vec3 CAnimEntityNode::GetScale( float time )
{
Vec3 scl(1,1,1);
IAnimBlock *anim = GetAnimBlock();
if (!anim)
return scl;
IAnimTrack *sclTrack = anim->GetTrack(APARAM_SCL);
if (sclTrack)
sclTrack->GetValue( time,scl );
return scl;
}
*/
//////////////////////////////////////////////////////////////////////////
void CAnimEntityNode::SetPos( float time,const Vec3 &pos )
{
bool bDefault = !(m_pMovieSystem->IsRecording() && (m_flags&ANODE_FLAG_SELECTED)); // Only selected nodes can be recorded
IAnimBlock *anim = GetAnimBlock();
if (anim)
{
IAnimTrack *posTrack = anim->GetTrack(APARAM_POS);
if (posTrack)
{
posTrack->SetValue( time,pos,bDefault );
if (bDefault && posTrack->GetNumKeys() > 0)
{
// Track is not empty. offset all keys by move ammount.
Vec3 offset = pos - m_pos;
// Iterator over all keys.
ITcbKey key;
for (int i = 0; i < posTrack->GetNumKeys(); i++)
{
// Offset each key.
posTrack->GetKey(i,&key);
key.SetVec3( key.GetVec3()+offset );
posTrack->SetKey(i,&key);
}
}
}
}
m_pos = pos;
InvalidateTM();
}
//////////////////////////////////////////////////////////////////////////
void CAnimEntityNode::SetRotate( float time,const Quat &quat )
{
m_rotate = quat;
InvalidateTM();
bool bDefault = !(m_pMovieSystem->IsRecording() && (m_flags&ANODE_FLAG_SELECTED)); // Only selected nodes can be recorded
IAnimBlock *anim = GetAnimBlock();
if (anim)
{
IAnimTrack *rotTrack = anim->GetTrack(APARAM_ROT);
if (rotTrack)
rotTrack->SetValue( time,m_rotate,bDefault );
}
}
//////////////////////////////////////////////////////////////////////////
void CAnimEntityNode::SetScale( float time,const Vec3 &scale )
{
m_scale = scale;
InvalidateTM();
bool bDefault = !(m_pMovieSystem->IsRecording() && (m_flags&ANODE_FLAG_SELECTED)); // Only selected nodes can be recorded
IAnimBlock *anim = GetAnimBlock();
if (anim)
{
IAnimTrack *sclTrack = anim->GetTrack(APARAM_SCL);
if (sclTrack)
sclTrack->SetValue( time,scale,bDefault );
}
}
//////////////////////////////////////////////////////////////////////////
void CAnimEntityNode::ApplyEventKey( CEventTrack *track,int keyIndex,IEventKey &key )
{
if (!m_entity)
return;
if (*key.animation) // if there is an animation
{
// Start playing animation.
m_entity->StartAnimation( 0,key.animation,0,0 );
ICryCharInstance *pCharacter = m_entity->GetCharInterface()->GetCharacter(0);
if (pCharacter)
{
IAnimationSet* pAnimations = pCharacter->GetModel()->GetAnimationSet();
assert (pAnimations);
float duration = pAnimations->GetLength( key.animation );
if (duration != key.duration)
{
key.duration = duration;
track->SetKey( keyIndex,&key );
}
}
//char str[1024];
//sprintf( str,"StartAnim: %s",key.animation );
//GetMovieSystem()->GetSystem()->GetILog()->LogToConsole( str );
}
if (*key.event) // if there's an event
{
// Fire event on Entity.
m_entity->CallEventHandler(key.event);
}
//m_entity->Hide( key.hidden );
}
//////////////////////////////////////////////////////////////////////////
void CAnimEntityNode::ApplySoundKey( IAnimTrack *pTrack,int nCurrKey,int nLayer, ISoundKey &key, SAnimContext &ec )
{
if (m_SoundInfo[nLayer].nLastKey==-1)
{
if (m_SoundInfo[nLayer].pSound)
m_SoundInfo[nLayer].pSound->Stop();
m_SoundInfo[nLayer].pSound=NULL;
return;
}
if (((strcmp(m_SoundInfo[nLayer].sLastFilename.c_str(), key.pszFilename)) || (!m_SoundInfo[nLayer].pSound)))
{
int flags = 0;
//if (key.bStream)
//flags |= FLAG_SOUND_STREAM;
//else
flags |= FLAG_SOUND_LOAD_SYNCHRONOUSLY; // Allways synchronously for now.
if (key.bLoop)
flags |= FLAG_SOUND_LOOP;
if (key.b3DSound)
{
// 3D sound.
flags |= FLAG_SOUND_3D|FLAG_SOUND_RADIUS;
}
else
{
// 2D sound.
flags |= FLAG_SOUND_2D|FLAG_SOUND_STEREO|FLAG_SOUND_16BITS;
}
// we have a different sound now
if (m_SoundInfo[nLayer].pSound)
m_SoundInfo[nLayer].pSound->Stop();
m_SoundInfo[nLayer].pSound=m_pMovie->GetSystem()->GetISoundSystem()->LoadSound(key.pszFilename, flags | FLAG_SOUND_UNSCALABLE );
m_SoundInfo[nLayer].sLastFilename=key.pszFilename;
if (m_SoundInfo[nLayer].pSound)
{
m_SoundInfo[nLayer].nLength=m_SoundInfo[nLayer].pSound->GetLengthMs();
key.fDuration = ((float)m_SoundInfo[nLayer].nLength) / 1000.0f;
pTrack->SetKey( nCurrKey,&key ); // Update key duration.
}
}else
{
if (m_SoundInfo[nLayer].pSound)
m_SoundInfo[nLayer].pSound->Stop();
}
if (!m_SoundInfo[nLayer].pSound)
return;
m_SoundInfo[nLayer].pSound->SetSoundPriority( MOVIE_SOUND_PRIORITY );
m_SoundInfo[nLayer].pSound->SetVolume(key.nVolume);
if (key.b3DSound)
{
// 3D sound.
m_SoundInfo[nLayer].pSound->SetPosition( m_entity->GetPos() );
m_SoundInfo[nLayer].pSound->SetMinMaxDistance( key.inRadius,key.outRadius );
}
else
{
// 2D sound.
m_SoundInfo[nLayer].pSound->SetPan(key.nPan);
}
int nOffset=(int)((ec.time-key.time)*1000.0f);
if (nOffset < m_SoundInfo[nLayer].nLength)
{
//return;
m_SoundInfo[nLayer].pSound->SetCurrentSamplePos(nOffset, true);
}
((CMovieSystem*)m_pMovie)->OnPlaySound( m_SoundInfo[nLayer].pSound );
if (!m_SoundInfo[nLayer].pSound->IsPlaying())
m_SoundInfo[nLayer].pSound->Play();
}
//////////////////////////////////////////////////////////////////////////
void CAnimEntityNode::ReleaseAllAnims()
{
ResolveEntity(); // Resolve entity here as it may get deleted already.
if (!m_entity)
return;
ICryCharInstance *pCharacter = m_entity->GetCharInterface()->GetCharacter(0);
if (!pCharacter)
return;
ICryAnimationSet* pAnimations = pCharacter->GetModel()->GetAnimationSet();
assert(pAnimations);
for (TStringSetIt It=m_setAnimationSinks.begin();It!=m_setAnimationSinks.end();++It)
{
const char *pszName=(*It).c_str();
pCharacter->RemoveAnimationEventSink(pszName, this);
pAnimations->UnloadAnimation(pszName);
}
m_setAnimationSinks.clear();
}
//////////////////////////////////////////////////////////////////////////
void CAnimEntityNode::OnEndAnimation(const char *sAnimation)
{
if (!m_entity)
return;
TStringSetIt It=m_setAnimationSinks.find(sAnimation);
if (It==m_setAnimationSinks.end())
return; // this anim was not started by us...
m_setAnimationSinks.erase(It);
ICryCharInstance *pCharacter = m_entity->GetCharInterface()->GetCharacter(0);
if (!pCharacter)
return;
ICryAnimationSet* pAnimations = pCharacter->GetModel()->GetAnimationSet();
assert(pAnimations);
pCharacter->RemoveAnimationEventSink(sAnimation, this);
pAnimations->UnloadAnimation(sAnimation);
}
//////////////////////////////////////////////////////////////////////////
void CAnimEntityNode::AnimateCharacterTrack( class CCharacterTrack* track,SAnimContext &ec,int layer )
{
ICryCharInstance *pCharacter = m_entity->GetCharInterface()->GetCharacter(0);
if (!pCharacter)
return;
ICharacterKey key;
int currKey = track->GetActiveKey(ec.time,&key);
// If key is different or if time is standing exactly on key time.
if (currKey != m_lastCharacterKey[layer] || key.time == ec.time || ec.time < m_time)
{
m_lastCharacterKey[layer] = currKey;
if (strlen(key.animation) > 0)
{
// retrieve the animation collection for the model
ICryAnimationSet* pAnimations = pCharacter->GetModel()->GetAnimationSet();
assert (pAnimations);
if (key.bUnload)
{
m_setAnimationSinks.insert(TStringSetIt::value_type(key.animation));
pCharacter->AddAnimationEventSink(key.animation, this);
}
// Start playing animation.
m_entity->StartAnimation( 0,key.animation,layer,key.blendTime );
int animId = pAnimations->Find( key.animation );
// pCharacter->EnableTimeUpdate(false);
pCharacter->SetAnimationSpeed(layer, 0.0f); // stop anim this way, so we dont block all other running anims
float duration = pAnimations->GetLength(animId) + pAnimations->GetStart(animId);
if (duration != key.duration)
{
key.duration = duration;
track->SetKey( currKey,&key );
}
/*
if (key.bLoop)
{
if (animId >= 0)
pAnimations->SetLoop( animId,key.bLoop );
}
*/
}
}
// Animate.
if (currKey >= 0)
{
float t = ec.time - key.time;
t = key.startTime + t*key.speed;
if (t < key.duration || key.bLoop)
{
if (key.bLoop)
{
t = fmod(t,key.duration);
}
// Start playing animation.
//m_character->EnableTimeUpdate(false);
pCharacter->SetLayerTime(layer,t);
}
}
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
void CAnimEntityNode::StopExpressions()
{
if (m_setExpressions.empty())
return;
IEntityCharacter *pEntChar=m_entity->GetCharInterface();
if (!pEntChar)
return;
ILipSync *pLipSync=pEntChar->GetLipSyncInterface();
if (!pLipSync)
return;
for (TStringSetIt It=m_setExpressions.begin();It!=m_setExpressions.end();++It)
{
pLipSync->StopExpression((*It).c_str());
}
m_setExpressions.clear();
}
void CAnimEntityNode::AnimateExpressionTrack(CExprTrack *pTrack, SAnimContext &ec)
{
IExprKey Key;
int nKeys=pTrack->GetNumKeys();
// we go through all the keys, since expressions may overlap
for (int nKey=0;nKey<nKeys;nKey++)
{
pTrack->GetKey(nKey, &Key);
if ((!Key.pszName) || (!strlen(Key.pszName)))
return;
IEntityCharacter *pEntChar=m_entity->GetCharInterface();
if (!pEntChar)
return;
ILipSync *pLipSync=pEntChar->GetLipSyncInterface();
if (pLipSync)
{
float fKeyLentgh=Key.fBlendIn+Key.fHold+Key.fBlendOut;
float fOffset=ec.time-Key.time;
if ((Key.time>ec.time) || (fOffset>=fKeyLentgh))
{
// pLipSync->StopExpression(Key.pszName);
continue;
}
CryCharMorphParams MorphParams;
MorphParams.fAmplitude=Key.fAmp;
MorphParams.fBlendIn=Key.fBlendIn;
MorphParams.fBlendOut=Key.fBlendOut;
MorphParams.fLength=Key.fHold;
MorphParams.fStartTime=fOffset;
if (pLipSync->DoExpression(Key.pszName, MorphParams, false))
m_setExpressions.insert(Key.pszName);
}
}
}
//////////////////////////////////////////////////////////////////////////
void CAnimEntityNode::SetTarget( IAnimNode *node )
{
IAnimNode *prevTarget = m_target;
m_target = node;
if (prevTarget != m_target)
InvalidateTM();
}
//////////////////////////////////////////////////////////////////////////
IAnimNode* CAnimEntityNode::GetTarget() const
{
return m_target;
}
//////////////////////////////////////////////////////////////////////////
void CAnimEntityNode::SetAnimBlock( IAnimBlock *block )
{
CAnimNode::SetAnimBlock(block);
if (block)
{
// Initialize new block with default track values.
// Used exlusively in Editor.
IAnimTrack *posTrack = block->GetTrack(APARAM_POS);
IAnimTrack *rotTrack = block->GetTrack(APARAM_ROT);
IAnimTrack *sclTrack = block->GetTrack(APARAM_SCL);
if (posTrack)
posTrack->SetValue( 0,m_pos,true );
if (rotTrack)
rotTrack->SetValue( 0,m_rotate,true );
if (sclTrack)
sclTrack->SetValue( 0,m_scale,true );
}
}
//////////////////////////////////////////////////////////////////////////
void CAnimEntityNode::Serialize( XmlNodeRef &xmlNode,bool bLoading )
{
CAnimNode::Serialize( xmlNode,bLoading );
if (bLoading)
{
xmlNode->getAttr( "Pos",m_pos );
xmlNode->getAttr( "Rotate",m_rotate );
xmlNode->getAttr( "Scale",m_scale );
xmlNode->getAttr( "EntityId",m_EntityId );
}
else
{
xmlNode->setAttr( "Pos",m_pos );
xmlNode->setAttr( "Rotate",m_rotate );
xmlNode->setAttr( "Scale",m_scale );
xmlNode->setAttr( "EntityId",m_EntityId );
}
}