588 lines
17 KiB
C++
588 lines
17 KiB
C++
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Crytek Character Animation source code
|
|
//
|
|
// History:
|
|
// Taken over by Sergiy Migdalskiy (no previous history record here)
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "stdafx.h"
|
|
//#include "CryAnimation.h"
|
|
#include "CryBone.h"
|
|
#include "CryModelState.h"
|
|
#include "CryModEffector.h"
|
|
#include "CryModEffAnimation.h"
|
|
#include "CryModel.h"
|
|
#include "CVars.h"
|
|
|
|
CCryModEffAnimation::CCryModEffAnimation (CryModelState* pParent):
|
|
// m_bMatrixPlusInUse(false),
|
|
m_fAnimTime (0.0f),
|
|
m_nAnimId (-1),
|
|
m_fBlendInTime (0.0f),
|
|
m_fBlendOutTime (0.0f),
|
|
m_fOrigBlendOutTime (0.0f),
|
|
m_pParent (pParent),
|
|
m_fStopTime (0)
|
|
{
|
|
m_uFlags.bLoop = 0;
|
|
m_arrFadeAnims.reserve(2);
|
|
}
|
|
|
|
bool CCryModEffAnimation::IsStopped()
|
|
{
|
|
return (m_nAnimId < 0) && m_arrFadeAnims.empty();
|
|
}
|
|
|
|
// does this animation effector actively plays some animations?
|
|
bool CCryModEffAnimation::isActive ()
|
|
{
|
|
return m_nAnimId >= 0;
|
|
}
|
|
|
|
|
|
// this calls all the necessary callbacks
|
|
void CCryModEffAnimation::OnTimeChanged (int nAnimId, float fPrevTime, float fAnimTime,float fSpeed)
|
|
{
|
|
if (g_GetCVars()->ca_DisableAnimEvents())
|
|
return;
|
|
|
|
ICharInstanceSink * pSink = m_pParent->getAnimationEventSink(nAnimId);
|
|
const AnimData& rAnim = m_pParent->getAnimationSet()->getAnimation(nAnimId);
|
|
|
|
typedef CryModelState::AnimEventArray AnimEventArray;
|
|
const AnimEventArray& arrEvents = m_pParent->getAnimEvents(nAnimId);
|
|
// TODO: make binary search or iterator
|
|
if(pSink && !arrEvents.empty() && fPrevTime != fAnimTime)
|
|
{
|
|
bool bSecondPass = false;
|
|
float fSecondPassEnd;
|
|
|
|
if (m_uFlags.bLoop
|
|
&& rAnim.fStart < rAnim.fStop
|
|
&& (fSpeed >= 0 ? fAnimTime > rAnim.fStop : fAnimTime < rAnim.fStart)
|
|
)
|
|
{
|
|
bSecondPass = true;
|
|
if (fSpeed >= 0)
|
|
{
|
|
fSecondPassEnd = rAnim.fStart + cry_fmod(fAnimTime - rAnim.fStart, rAnim.getLength());
|
|
fAnimTime = rAnim.fStop;
|
|
}
|
|
else
|
|
{
|
|
fSecondPassEnd = rAnim.fStop - cry_fmod(rAnim.fStop - fAnimTime, rAnim.getLength());
|
|
fAnimTime = rAnim.fStart;
|
|
}
|
|
}
|
|
|
|
AnimEventArray::const_iterator it;
|
|
for(it = arrEvents.begin(); it != arrEvents.end(); ++it)
|
|
{
|
|
float fTriggerTime = it->fTime;
|
|
// this condition takes into account both variants, when the previous and current event are forward- or backward-playing
|
|
if ( (fPrevTime <= fTriggerTime && fTriggerTime < fAnimTime)
|
|
|| (fPrevTime >= fTriggerTime && fTriggerTime > fAnimTime))
|
|
{
|
|
DEFINE_PROFILER_SECTION("AllCallbacks");
|
|
pSink->OnAnimationEvent (rAnim.strName.c_str(), it->UserData);
|
|
if(g_GetCVars()->ca_Debug())
|
|
g_GetLog()->Log("\004 %p->OnAnimationEvent (\"%s\",frame:%d,time:%g, trigger time: %g, time change: %g to %g)", m_pParent, rAnim.strName.c_str(), g_GetIRenderer()->GetFrameID(), fAnimTime, fTriggerTime, fPrevTime, fAnimTime);
|
|
}
|
|
}
|
|
|
|
if (bSecondPass)
|
|
{
|
|
fAnimTime = fSecondPassEnd;
|
|
fPrevTime = fSpeed >= 0 ? rAnim.fStart : rAnim.fStop;
|
|
|
|
for(it = arrEvents.begin(); it != arrEvents.end(); ++it)
|
|
{
|
|
float fTriggerTime = it->fTime;
|
|
if ( (fPrevTime <= fTriggerTime && fTriggerTime < fAnimTime)
|
|
|| (fPrevTime >= fTriggerTime && fTriggerTime > fAnimTime))
|
|
{
|
|
DEFINE_PROFILER_SECTION("AllCallbacks");
|
|
pSink->OnAnimationEvent (rAnim.strName.c_str(), it->UserData);
|
|
if(g_GetCVars()->ca_Debug())
|
|
g_GetLog()->Log("\004 %p->OnAnimationEvent(2nd) (\"%s\",frame:%d,time:%g, trigger time: %g, time change: %g to %g)", m_pParent, rAnim.strName.c_str(), g_GetIRenderer()->GetFrameID(), fAnimTime, fTriggerTime, fPrevTime, fAnimTime);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// returns fVal/fBase, clamped between 0 and 1
|
|
float blendValue (float fVal, float fBase)
|
|
{
|
|
if (!(fVal > 0)) // this will also account for (impossible here) nans..
|
|
return 0;
|
|
else
|
|
if (!(fVal < fBase))
|
|
return 1;
|
|
else
|
|
return fVal/fBase;
|
|
}
|
|
|
|
|
|
void CCryModEffAnimation::SetNoLoop()
|
|
{
|
|
m_uFlags.bLoop = 0;
|
|
}
|
|
|
|
void CCryModEffAnimation::SetNoLoopNoBlendOut()
|
|
{
|
|
m_fBlendOutTime = 0;
|
|
m_uFlags.bLoop = 0;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Adds the current time of the animation
|
|
// Loops the animation if necessary
|
|
// Triggers all the necessary events (end animation and alike)
|
|
// Processes blending
|
|
// Returns the current animation time as it should be passed to the controller
|
|
unsigned CCryModEffAnimation::Tick(
|
|
float fDeltaTime,
|
|
const std::vector<ICharInstanceSink *>& arrSinks,
|
|
CAnimationLayerInfoArray& arrOutLayers
|
|
)
|
|
{
|
|
//Validator validator(this);
|
|
if(m_nAnimId < 0)
|
|
return TickFadingAnims(fDeltaTime,1,arrOutLayers);
|
|
|
|
CryModelAnimationContainer* pAnimations = m_pParent->getAnimationSet();
|
|
|
|
pAnimations->OnAnimationTick (m_nAnimId);
|
|
const AnimData& rCurrentAnimation = pAnimations->getAnimation(m_nAnimId);
|
|
|
|
// First animation
|
|
|
|
float fStart = m_fStartTime;
|
|
float fStop = m_fStopTime;
|
|
|
|
ICharInstanceSink * pCharInstanceSink = m_pParent->getAnimationEventSink(m_nAnimId);
|
|
|
|
if (!m_uFlags.bLoop && m_fAnimTime >= fStop + m_fBlendOutTime && fDeltaTime > 0)
|
|
{
|
|
// we have already applied the last frame of the last animation, so stop
|
|
stop();
|
|
return TickFadingAnims(fDeltaTime,1,arrOutLayers); // no animation
|
|
}
|
|
|
|
float fPrevTime = m_fAnimTime;
|
|
m_fAnimTime += fDeltaTime;
|
|
|
|
OnTimeChanged (m_nAnimId, fPrevTime, m_fAnimTime, fDeltaTime);
|
|
|
|
float fCurrentTime;
|
|
|
|
if(m_fAnimTime > fStop || m_fAnimTime < fStart)
|
|
{
|
|
if(m_uFlags.bLoop)
|
|
{
|
|
if (fStop > fStart)
|
|
{
|
|
if (fDeltaTime >= 0)
|
|
m_fAnimTime = fStart + cry_fmod(m_fAnimTime - fStart, fStop-fStart);
|
|
else
|
|
m_fAnimTime = fStop - cry_fmod(fStop - m_fAnimTime, fStop-fStart);
|
|
}
|
|
else
|
|
{
|
|
if (fDeltaTime >= 0)
|
|
m_fAnimTime = rCurrentAnimation.fStop;
|
|
else
|
|
m_fAnimTime = rCurrentAnimation.fStart;
|
|
}
|
|
}
|
|
|
|
if (g_GetCVars()->ca_Debug())
|
|
g_GetLog()->Log ("\003 %p->OnEndAnimation (%s)", m_pParent, rCurrentAnimation.strName.c_str());
|
|
// The animation time intersected the stop time.
|
|
// NOTE: this callback is not called a few times, if there were a few intersection (e.g. per frame)
|
|
// because of a few cycles of animation passed.
|
|
if(pCharInstanceSink)
|
|
{
|
|
DEFINE_PROFILER_SECTION("AllCallbacks");
|
|
pCharInstanceSink->OnEndAnimation (rCurrentAnimation.strName.c_str());
|
|
}
|
|
|
|
if (!m_uFlags.bLoop)
|
|
{
|
|
if (g_GetCVars()->ca_TickVersion())
|
|
{
|
|
m_fAnimTime = fPrevTime;
|
|
stop();
|
|
return TickFadingAnims(fDeltaTime,1,arrOutLayers);
|
|
}
|
|
else
|
|
{
|
|
fCurrentTime = fDeltaTime >= 0 ? fStop : fStart;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fCurrentTime = m_fAnimTime;
|
|
|
|
// in the looped animation, we don't have to have blend out time.
|
|
// When the animation is looped, it ends only when another animation starts,
|
|
// which will take care of blending this animation out (the new animation
|
|
// will blend itself in)
|
|
m_fBlendOutTime = 0;
|
|
}
|
|
}
|
|
else
|
|
fCurrentTime = m_fAnimTime;
|
|
|
|
// what weight to use to blend the bone to the orientation/position dictated by the controller?
|
|
// by default, it's 1, meaning fully replace the O/P of the bone with the one from the controller
|
|
float fBlendWeight = 1;
|
|
|
|
// Compute the current blend factor
|
|
assert (m_fBlendInTime >= m_fBlendInCountdown);
|
|
if (m_fBlendInCountdown > 0)
|
|
{
|
|
m_fBlendInCountdown -= (float)fabs(fDeltaTime);
|
|
if (m_fBlendInCountdown < 0)
|
|
m_fBlendInCountdown = 0;
|
|
|
|
fBlendWeight = blendValue(m_fBlendInTime - m_fBlendInCountdown, m_fBlendInTime);
|
|
if (!m_uFlags.bLoop)
|
|
{
|
|
if (fDeltaTime >= 0)
|
|
{
|
|
if (!(m_fAnimTime < fStop))
|
|
m_fAnimTime = fStop;
|
|
}
|
|
else
|
|
{
|
|
if (!(m_fAnimTime > fStart))
|
|
m_fAnimTime = fStart;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
if (m_fBlendOutTime > 0)
|
|
{
|
|
if (fDeltaTime >= 0)
|
|
{
|
|
if (m_fAnimTime > fStop)
|
|
fBlendWeight = blendValue((fStop + m_fBlendOutTime) - m_fAnimTime, m_fBlendOutTime);
|
|
}
|
|
else
|
|
{
|
|
if (m_fAnimTime < fStart)
|
|
fBlendWeight = blendValue(m_fAnimTime - (fStart - m_fBlendOutTime), m_fBlendOutTime);
|
|
}
|
|
}
|
|
|
|
unsigned numFadingAnimations = 0;
|
|
|
|
if (g_GetCVars()->ca_TickVersion() >= 2)
|
|
{
|
|
if (fBlendWeight >= 0.99f)
|
|
m_arrFadeAnims.clear();
|
|
else
|
|
numFadingAnimations = TickFadingAnims(fDeltaTime, 1-fBlendWeight, arrOutLayers, m_fBlendInCountdown == 0);
|
|
}
|
|
else
|
|
numFadingAnimations = TickFadingAnims(fDeltaTime, 1-fBlendWeight, arrOutLayers);
|
|
|
|
//m_fAnimTime = fCurrentTime;
|
|
arrOutLayers.push_back(CAnimationLayerInfo(m_nAnimId, fCurrentTime*getTicksPerSecond(), fBlendWeight));
|
|
|
|
return 1 + numFadingAnimations;
|
|
}
|
|
|
|
|
|
float CCryModEffAnimation::getBlending()const
|
|
{
|
|
if (m_fBlendInCountdown > 0)
|
|
return (m_fBlendInTime - m_fBlendInCountdown) / m_fBlendInTime;
|
|
else
|
|
if (m_fBlendOutTime > 0 && m_fAnimTime > m_fStopTime)
|
|
return (m_fStopTime + m_fBlendOutTime - m_fAnimTime) / m_fBlendOutTime;
|
|
else
|
|
return 1;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Clocks all fading subanimations and adds the animation layers
|
|
// deletes expired fading animations
|
|
unsigned CCryModEffAnimation::TickFadingAnims (float fDelta, float fWeightLeft, CAnimationLayerInfoArray& arrLayers, bool bFade)
|
|
{
|
|
g_arrLocalLayers.clear();
|
|
|
|
FadingAnimArray::iterator it;
|
|
for (it = m_arrFadeAnims.begin(); it != m_arrFadeAnims.end() && fWeightLeft > 0;)
|
|
{
|
|
if (it->Tick (fDelta, bFade))
|
|
{
|
|
if (it->fBlending >= fWeightLeft)
|
|
g_arrLocalLayers.push_back(CAnimationLayerInfo(it->nAnimId, it->fTime*getTicksPerSecond(), 1));
|
|
else
|
|
g_arrLocalLayers.push_back(CAnimationLayerInfo(it->nAnimId, it->fTime*getTicksPerSecond(), blendValue(it->fBlending , fWeightLeft)));
|
|
fWeightLeft -= it->fBlending;
|
|
++it;
|
|
}
|
|
else
|
|
it = m_arrFadeAnims.erase(it);
|
|
}
|
|
|
|
if (!m_arrFadeAnims.empty() && it != m_arrFadeAnims.end())
|
|
m_arrFadeAnims.erase(it, m_arrFadeAnims.end());
|
|
|
|
for (int i = (int)g_arrLocalLayers.size() - 1; i >= 0; --i)
|
|
arrLayers.push_back(g_arrLocalLayers[i]);
|
|
|
|
return (int)m_arrFadeAnims.size();
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// returns the number of any animation currently being played
|
|
// this can be the current animation, including animation of fadeout, if the
|
|
// layer doesn't have the current animation played, but has an animation fading out
|
|
int CCryModEffAnimation::GetAnyCurrentAnimation()const
|
|
{
|
|
if (m_nAnimId < 0)
|
|
{
|
|
for (unsigned i = 0; i < m_arrFadeAnims.size(); ++i)
|
|
if (m_arrFadeAnims[i].nAnimId >= 0)
|
|
return m_arrFadeAnims[i].nAnimId;
|
|
return -1; // no animations found at all
|
|
}
|
|
else
|
|
return m_nAnimId;
|
|
}
|
|
|
|
|
|
float CCryModEffAnimation::GetPhase()const
|
|
{
|
|
if (m_nAnimId >= 0)
|
|
{
|
|
CryModelAnimationContainer* pAnimations = m_pParent->getAnimationSet();
|
|
const AnimData& anim = pAnimations->getAnimation(m_nAnimId);
|
|
if (anim.bLoop && anim.fStart < anim.fStop)
|
|
// only if the old animation is looped, and the new animation is looped, we use the phase
|
|
return (m_fAnimTime - anim.fStart) / anim.getLength();
|
|
else
|
|
return 0; // there's no phase in non-looped (or 0-length) animation by the current definition
|
|
}
|
|
else
|
|
return 0;// by default, there's no phase for non-existing non-playing animation
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Starts new animation
|
|
// Blends with the existing pose of the bone if necessary
|
|
void CCryModEffAnimation::StartAnimation (unsigned nAnimID, float fBlendInTime, float fBlendOutTime, CCryModEffAnimation* pSynchronizeWith, float fSpeed, unsigned nStartAnimFlags)
|
|
{
|
|
if (nAnimID < 0)
|
|
{
|
|
Reset();
|
|
return;
|
|
}
|
|
|
|
m_nStartAnimFlags = nStartAnimFlags;
|
|
CryModelAnimationContainer* pAnimations = m_pParent->getAnimationSet();
|
|
pAnimations->OnAnimationStart (nAnimID);
|
|
// the animation might have changed
|
|
const AnimData &anim = pAnimations->getAnimation(nAnimID);
|
|
|
|
// ignore multiple requests to start the same animation unless the animation has already been played long enough (50% of the time)
|
|
if (nAnimID == m_nAnimId)
|
|
{
|
|
if (g_GetCVars()->ca_RestartBehaviour() == 0)
|
|
{
|
|
if (fSpeed >= 0 ? m_fAnimTime < (anim.fStart+anim.fStop)/2 : m_fAnimTime > (anim.fStart+anim.fStop)/2)
|
|
return;
|
|
}
|
|
else // with behaviour 1 always restart
|
|
return;
|
|
}
|
|
|
|
// the phase of the old animation, 0..1, used to achieve smoother blending if the animations are
|
|
// similar loops (only if they're both loops)
|
|
float fOldAnimationPhase = pSynchronizeWith->GetPhase();
|
|
|
|
// call OnEnd for animation we drop
|
|
if (m_nAnimId >= 0)
|
|
{
|
|
if (g_GetCVars()->ca_Debug())
|
|
{
|
|
const AnimData& animOld = pAnimations->getAnimation(m_nAnimId);
|
|
g_GetLog()->LogToFile ("\005Overriding existing animation #%u \"%s\" [%f..%f] at time %f", m_nAnimId, animOld.strName.c_str(), animOld.fStart, animOld.fStop, m_fAnimTime);
|
|
}
|
|
|
|
ICharInstanceSink * pCharInstanceSink = m_pParent->getAnimationEventSink(m_nAnimId);
|
|
if (pCharInstanceSink)
|
|
{
|
|
DEFINE_PROFILER_SECTION("AllCallbacks");
|
|
const char* szAnimName = pAnimations->getAnimation(m_nAnimId).strName.c_str();
|
|
if (g_GetCVars()->ca_Debug())
|
|
g_GetLog()->Log ("\003 %p->OnEndAnimation (%s)", m_pParent, szAnimName);
|
|
pCharInstanceSink->OnEndAnimation (szAnimName);
|
|
}
|
|
}
|
|
|
|
this->stop();
|
|
|
|
m_fStartTime = anim.fStart;
|
|
m_fStopTime = anim.fStop;
|
|
m_uFlags.bLoop = anim.bLoop ? 1 : 0;
|
|
|
|
// set new animation
|
|
m_nAnimId = nAnimID;
|
|
|
|
m_fAnimTime = anim.bLoop ? anim.fStart + fOldAnimationPhase * anim.getLength() : fSpeed > 0 ? m_fStartTime : m_fStopTime;
|
|
|
|
// start blending from old to new if blending allowed
|
|
m_fBlendInCountdown = m_fBlendInTime = fBlendInTime;
|
|
m_fOrigBlendOutTime = m_fBlendOutTime = fBlendOutTime;
|
|
|
|
ICharInstanceSink* pSink = m_pParent->getAnimationEventSink(nAnimID);
|
|
|
|
if (pSink)
|
|
{
|
|
DEFINE_PROFILER_SECTION("AllCallbacks");
|
|
const char *szAnimName = anim.strName.c_str();
|
|
if (g_GetCVars()->ca_Debug())
|
|
g_GetLog()->Log ("\003 %p->OnStartAnimation (%s)", m_pParent, szAnimName);
|
|
pSink->OnStartAnimation (szAnimName);
|
|
}
|
|
}
|
|
|
|
void CCryModEffAnimation::stop ()
|
|
{
|
|
if (m_nAnimId < 0)
|
|
return;
|
|
|
|
if (m_fOrigBlendOutTime > 0)
|
|
{
|
|
FadingAnim anim;
|
|
anim.fBlending = getBlending();
|
|
anim.fBlendOutSpeed = 1/m_fOrigBlendOutTime;
|
|
anim.fTime = m_fAnimTime;
|
|
anim.nAnimId = m_nAnimId;
|
|
anim.bLoop = m_uFlags.bLoop?true:false;
|
|
|
|
anim.bRun = anim.bLoop || (m_nStartAnimFlags&CryCharAnimationParams::FLAGS_ALIGNED);
|
|
|
|
CryModelAnimationContainer* pAnimations = m_pParent->getAnimationSet();
|
|
const AnimData& rCurrentAnimation = pAnimations->getAnimation(m_nAnimId);
|
|
anim.fLoopEnd = rCurrentAnimation.fStop;
|
|
anim.fLoopLength = rCurrentAnimation.getLength();
|
|
|
|
m_arrFadeAnims.insert(m_arrFadeAnims.begin(), anim);
|
|
}
|
|
|
|
// small safety check in case the queue gets really long...
|
|
if (g_GetCVars()->ca_TickVersion() >= 2 && m_arrFadeAnims.size() > 8)
|
|
m_arrFadeAnims.resize (8);
|
|
|
|
//m_uFlags.bLoop = 0;
|
|
//m_fStopTime = m_fAnimTime;
|
|
//m_fBlendOutTime = m_fOrigBlendOutTime;
|
|
m_nAnimId = -1;
|
|
}
|
|
|
|
// forcibly sets the current time of the animation, in seconds
|
|
void CCryModEffAnimation::SetCurrentTime (float fTime)
|
|
{
|
|
//m_fBlendInTime = m_fBlendOutTime = 0;
|
|
if (m_nAnimId < 0)
|
|
return;
|
|
|
|
// filter out the out-of-range values
|
|
if (fTime < m_fStartTime)
|
|
fTime = m_fStartTime;
|
|
else
|
|
if (fTime > m_fStopTime)
|
|
fTime = m_fStopTime;
|
|
|
|
m_arrFadeAnims.clear();
|
|
|
|
float fPrevTime = m_fAnimTime;
|
|
m_fAnimTime = fTime;
|
|
|
|
// so as to avoid calling extra callbacks
|
|
OnTimeChanged (m_nAnimId, fPrevTime, m_fAnimTime, fTime-fPrevTime);
|
|
}
|
|
|
|
void CCryModEffAnimation::Reset()
|
|
{
|
|
m_fBlendInCountdown = m_fBlendInTime = m_fBlendOutTime = 0.f;
|
|
m_nAnimId = -1;
|
|
m_arrFadeAnims.clear();
|
|
}
|
|
|
|
float CCryModEffAnimation::getTicksPerSecond()const
|
|
{
|
|
CryModelAnimationContainer* pAnimations = m_pParent->getAnimationSet();
|
|
return pAnimations->getTicksPerSecond();
|
|
}
|
|
|
|
// ticks the fading animation; returns false when the animation completely fades out
|
|
bool CCryModEffAnimation::FadingAnim::Tick (float fDeltaTime, bool bFade)
|
|
{
|
|
if (bRun)
|
|
{
|
|
if (bLoop)
|
|
{
|
|
if (fLoopLength)
|
|
{
|
|
float fLoopStart = fLoopEnd - fLoopLength;
|
|
if (fDeltaTime > 0)
|
|
fTime = fLoopStart + cry_fmod ((fTime + fDeltaTime) - fLoopStart, fLoopLength);
|
|
else
|
|
fTime = fLoopEnd - cry_fmod (fLoopEnd - (fTime + fDeltaTime), fLoopLength);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fTime += fDeltaTime;
|
|
}
|
|
}
|
|
|
|
if (bFade)
|
|
fBlending -= cry_fabsf(fDeltaTime*fBlendOutSpeed);
|
|
return fBlending > 0;
|
|
}
|
|
|
|
void CCryModEffAnimation::initClass()
|
|
{
|
|
g_arrLocalLayers.reserve (3);
|
|
}
|
|
|
|
string CCryModEffAnimation::dump()
|
|
{
|
|
CryModelAnimationContainer* pAnimations = m_pParent->getAnimationSet();
|
|
const AnimData& rAnim = pAnimations->getAnimation(m_nAnimId);
|
|
string strResult;
|
|
char szBuf[0x100];
|
|
strResult += "main \"" + rAnim.strName + "\"";
|
|
sprintf (szBuf, " t=%.2f", m_fAnimTime);
|
|
strResult += szBuf;
|
|
if (!m_arrFadeAnims.empty())
|
|
{
|
|
strResult += ", fade";
|
|
for (FadingAnimArray::iterator it = m_arrFadeAnims.begin(); it != m_arrFadeAnims.end(); ++it)
|
|
{
|
|
const AnimData& fadeAnim = pAnimations->getAnimation(it->nAnimId);
|
|
sprintf (szBuf, " \"%s\" (t=%.2f b=%.2f)", fadeAnim.strName.c_str(), it->fTime, it->fBlending);
|
|
strResult += szBuf;
|
|
}
|
|
}
|
|
return strResult;
|
|
}
|
|
|
|
void CCryModEffAnimation::deinitClass()
|
|
{
|
|
g_arrLocalLayers.clear();
|
|
}
|
|
CAnimationLayerInfoArray CCryModEffAnimation::g_arrLocalLayers;
|