genesis-3d_engine/Engine/addons/animation/ClipControl.cc

639 lines
13 KiB
C++
Raw Normal View History

#include "animation/animation_stdneb.h"
#include "ClipControl.h"
#include "AnimationLayer.h"
#include "Animation.h"
#include "AnimationUtil.h"
namespace Animations
{
static const float MinSpeed = 0.0001f;
static const float MinClipEnd = 0.001f;
inline float _cal_weight(float numerator, float denominator)
{
float a = numerator / denominator;
a = Math::n_clamp(a, 0.0f, 1.0f);
return a;
}
const float ClipControl::BlendTestMark = 0.001f;
const float ClipControl::BlendTimeDefault = 0.3f;
ClipControl::ClipControl()
:m_WrapMode(PlayOnce)
,m_Speed(1.0f)
,m_Weight(1.0f)
,m_OldWeight(1.0f)
,m_BlendState(BlendOff)
,m_UpdateState(US_Stop)
,m_FadeTime(BlendTestMark)
,m_BlendWeightTime(BlendTestMark)
,m_FadeCounter(0.0f)
,m_BlendWeightCounter(0.0f)
,m_TimeCounter(0.0f)
,m_CurrentWeight(0.0f)
,m_CurrentWrapTime(0.0f)
,m_Layer(NULL)
,m_Clip(NULL)
{
}
ClipControl::~ClipControl()
{
Destroy();
}
void ClipControl::BindLayer(AnimationLayerPtr layer)
{
AnimationLayer::ClipControls activeList;
IndexT foundIndex = InvalidIndex;
if (m_Layer != NULL)
{
activeList = m_Layer->GetActiveList();
foundIndex = activeList.FindIndex(this);
UnbindLayer();
}
m_Layer = layer;
m_Layer->_AddControl(this);
if(InvalidIndex != foundIndex)
{
m_Layer->_AddActive(this);
}
}
void ClipControl::UnbindLayer()
{
if (m_Layer)
{
m_Layer->_RemoveActive(this);
m_Layer->_RemoveControl(this);
m_Layer = NULL;
}
}
void ClipControl::MatchSkeleton(const Util::Array<Util::String>& boneNames)
{
int bone_count = boneNames.Size();
m_SkeletonMatch.Resize(bone_count, InvalidBone);
for(int ske_bone = 0; ske_bone < bone_count; ++ske_bone)
{
int ani_bone = m_Clip->GetNodeIndex(boneNames[ske_bone]);
if (InvalidIndex != ani_bone)
{
m_SkeletonMatch[ske_bone] = ani_bone;
}
}
}
void ClipControl::Destroy()
{
UnbindLayer();
}
void ClipControl::Update(float time)
{
if (US_NoTickBegin < m_UpdateState )
{
return;
}
float a = time * m_Speed;
m_TimeCounter += a;
updateWrap();
if (BlendOff != m_BlendState)
{
updateBlend(a);
updateCurrentWeight();
}
}
void ClipControl::SetNormalizeTime(float time)
{
SetTime(time * m_Duration + m_StartTime);
}
void ClipControl::SetTime(float time)
{
updateWrap();
float wrap_time = m_CurrentWrapTime;
float bias = time - wrap_time;
m_TimeCounter = time;
if (BIT_FLAG_IS_OPEN(m_BlendState, BlendingFadeIn))
{
m_FadeCounter += bias;
}
else if (BIT_FLAG_IS_OPEN(m_BlendState, BlendingFadeOut))
{
m_FadeCounter += bias;
}
if (BIT_FLAG_IS_OPEN(m_BlendState, BlendingWeight))
{
m_BlendWeightCounter += bias;
}
}
void ClipControl::SetSpeed(float speed)
{
m_Speed = speed;
if (m_Speed < MinSpeed)
{
m_Speed = MinSpeed;
}
}
void ClipControl::updateBlend(float time)
{
if (BIT_FLAG_IS_OPEN(m_BlendState, BlendingFadeIn))
{
m_FadeCounter += time;
if (m_FadeCounter >= m_FadeTime)
{
m_FadeCounter = m_FadeTime;
m_BlendState = BIT_FlAG_DELETE(m_BlendState, BlendingFadeIn);
}
}
else if (BIT_FLAG_IS_OPEN(m_BlendState, BlendingFadeOut))
{
m_FadeCounter += time;
if (m_FadeCounter >= m_FadeTime)
{
stop();
return;
}
}
if (BIT_FLAG_IS_OPEN(m_BlendState, BlendingWeight))
{
m_BlendWeightCounter += time;
if (m_BlendWeightCounter >= m_BlendWeightTime)
{
m_BlendWeightCounter = m_BlendWeightTime;
m_BlendState = BIT_FlAG_DELETE(m_BlendState, BlendingWeight);
}
}
}
void ClipControl::updateWrap()
{
switch (m_WrapMode)
{
case PlayOnce:
{
if(m_TimeCounter > m_Duration)
{
stop();
m_CurrentWrapTime = m_EndTime;
}
else
{
float residue = m_Duration - m_TimeCounter;
if (residue < m_FadeTime && (!BIT_FLAG_IS_OPEN(m_BlendState, BlendingFadeOut)))
{
fadeOut(residue);
}
m_CurrentWrapTime = m_TimeCounter + m_StartTime;
}
}
break;
case PlayLoop:
{
m_CurrentWrapTime = Animations::Loop(m_TimeCounter, m_StartTime, m_EndTime);
}
break;
case PlayMirror:
{
m_CurrentWrapTime = Animations::Mirror(m_TimeCounter, m_StartTime, m_EndTime);
}
break;
case PlayClamp:
{
if (m_TimeCounter >= m_EndTime)
{
m_UpdateState = US_End;
m_CurrentWrapTime = m_EndTime;
}
else
{
m_CurrentWrapTime = m_TimeCounter + m_StartTime;
}
}
break;
default:
{
m_CurrentWrapTime = 0.0f;
}
break;
}
}
void ClipControl::stop()
{
m_UpdateState = US_Stop;
m_TimeCounter = 0.0f;
m_FadeTime = BlendTestMark;
m_BlendWeightTime = BlendTestMark;
m_FadeCounter = 0.0f;
m_BlendWeightCounter = 0.0f;
m_OldWeight = m_Weight;
m_CurrentWeight = 0.0f;
//m_CurrentWrapTime = 0.0f;
m_BlendState = BlendOff;
m_Layer->_RemoveActive(this);
}
void ClipControl::Pause()
{
m_UpdateState = US_Pause;
}
void ClipControl::play()
{
m_UpdateState = US_Playing;
}
void ClipControl::replay()
{
stop();
play();
}
void ClipControl::Blend(float weight, float time /* = BlendTestMark */)
{
if (US_Pause == m_UpdateState)
{
play();
}
else if (US_Stop == m_UpdateState)
{
play();
m_Layer->_AddActive(this);
}
else if (US_End == m_UpdateState)
{
replay();
}
if (time > BlendTestMark)
{
if (BIT_FLAG_IS_OPEN(m_BlendState, BlendingWeight))
{
m_OldWeight = getCurrentBlendingWeight();
m_Weight = weight;
m_BlendWeightCounter = 0.0f;
m_BlendWeightTime = time;
}
else
{
m_OldWeight = m_Weight;
m_Weight = weight;
m_CurrentWeight = weight;
m_BlendState = BIT_FlAG_APPEND(m_BlendState, BlendingWeight);
m_BlendWeightCounter = 0.0f;
m_BlendWeightTime = time;
}
}
else
{
m_OldWeight = m_Weight;
m_Weight = weight;
m_CurrentWeight = weight;
m_BlendWeightTime = BlendTestMark;
m_BlendWeightCounter = BlendTestMark;
m_BlendState = BIT_FlAG_DELETE(m_BlendState, BlendingWeight);
}
}
void ClipControl::FadeIn(float time /* = BlendTestMark */)
{
switch(m_UpdateState)
{
case US_Pause:
{
play();
}
break;
case US_Stop:
{
play();
fadeIn(time);
}
break;
case US_End:
{
replay();
fadeIn(time);
}
break;
case US_Playing:
{
if (BIT_FLAG_IS_OPEN(m_BlendState, BlendingFadeOut))
{
fadeIn(time);
}
}
break;
default:
break;
}
m_Layer->_FadeOutOther(this, time);
m_Layer->_AddActive(this);
}
void ClipControl::FadeOut(float time /* = BlendTestMark */)
{
switch(m_UpdateState)
{
case US_Pause:
{
play();
fadeOut(time);
}
break;
case US_Stop:
{
}
break;
case US_End:
{
fadeOut(time);
}
break;
case US_Playing:
{
fadeOut(time);
}
break;
default:
break;
}
}
void ClipControl::fadeIn(float time)
{
if (time > BlendTestMark)
{
if (BIT_FLAG_IS_OPEN(m_BlendState, BlendingFadeIn))
{
m_FadeCounter = time * _cal_weight(m_FadeCounter, m_FadeTime);
}
else if (BIT_FLAG_IS_OPEN(m_BlendState, BlendingFadeOut))
{
m_FadeCounter = time * (1.0f - _cal_weight(m_FadeCounter, m_FadeTime));
}
else
{
m_FadeCounter = 0.0f;
}
m_BlendState = BIT_FlAG_APPEND(m_BlendState, BlendingFadeIn);
m_FadeTime = time;
}
else
{
m_FadeTime = BlendTestMark;
m_FadeCounter = BlendTestMark;
m_BlendState = BIT_FlAG_DELETE(m_BlendState, BlendingFadeIn);
m_CurrentWeight = m_Weight;
}
m_BlendState = BIT_FlAG_DELETE(m_BlendState, BlendingFadeOut);
}
void ClipControl::fadeOut(float time)
{
if (time > BlendTestMark)
{
if (BIT_FLAG_IS_OPEN(m_BlendState, BlendingFadeIn))
{
m_BlendState = BIT_FlAG_APPEND(m_BlendState, BlendingFadeOut);
m_FadeCounter = time * (1.0f - _cal_weight(m_FadeCounter, m_FadeTime));
}
else if (BIT_FLAG_IS_OPEN(m_BlendState, BlendingFadeOut))
{
m_FadeCounter = time * _cal_weight(m_FadeCounter, m_FadeTime);
}
else
{
m_BlendState = BIT_FlAG_APPEND(m_BlendState, BlendingFadeOut);
m_FadeCounter = 0.0f;
}
m_FadeTime = time;
m_BlendState = BIT_FlAG_DELETE(m_BlendState, BlendingFadeIn);
}
else
{
stop();
}
}
float ClipControl::getCurrentBlendingWeight() const
{
return Math::n_lerp(m_OldWeight, m_Weight, _cal_weight(m_BlendWeightCounter, m_BlendWeightTime));
}
void ClipControl::updateCurrentWeight()
{
if (US_Stop == m_UpdateState)
{
m_CurrentWeight = 0.0f;
return;
}
else if (BlendOff == m_BlendState)
{
m_CurrentWeight = m_Weight;
return;
}
if (BIT_FLAG_IS_OPEN(m_BlendState, BlendingWeight))
{
m_CurrentWeight = getCurrentBlendingWeight();
}
else
{
m_CurrentWeight = m_Weight;
}
if (BIT_FLAG_IS_OPEN(m_BlendState, BlendingFadeIn))
{
m_CurrentWeight *= _cal_weight(m_FadeCounter, m_FadeTime);
}
else if (BIT_FLAG_IS_OPEN(m_BlendState, BlendingFadeOut))
{
m_CurrentWeight *= (1.0f - _cal_weight(m_FadeCounter, m_FadeTime));
}
}
int ClipControl::GetFrameCount() const
{
return (m_Duration * m_Clip->GetSampleRate());
}
int ClipControl::GetCurrentFrame() const
{
return ((m_CurrentWrapTime - m_StartTime) * m_Clip->GetSampleRate());
}
bool ClipControl::GetFrameData(float time, int bone_index, Math::float3& pos, Math::quaternion& rotate, Math::float3& scale) const
{
if (InvalidBone != m_SkeletonMatch[bone_index])
{
pos = m_Clip->GetAnimNodeTrans(time, m_SkeletonMatch[bone_index]);
rotate = m_Clip->GetAnimNodeRotation(time, m_SkeletonMatch[bone_index]);
scale = m_Clip->GetAnimNodeScale(time, m_SkeletonMatch[bone_index]);
return true;
}
return false;
}
void ClipControl::GetFrameDataNoCheck(float time, Bone bone, Math::float3& pos, Math::quaternion& rotate, Math::float3& scale) const
{
pos = m_Clip->GetAnimNodeTrans(time, m_SkeletonMatch[bone]);
rotate = m_Clip->GetAnimNodeRotation(time, m_SkeletonMatch[bone]);
scale = m_Clip->GetAnimNodeScale(time, m_SkeletonMatch[bone]);
}
AnimationNode* ClipControl::GetNode(Bone bone) const
{
if (m_SkeletonMatch[bone] != InvalidBone)
{
return m_Clip->GetNode(bone).get_unsafe();
}
return NULL;
}
void ClipControl::SetClip(const AnimationClipPtr& clip)
{
m_Clip = clip;
m_StartTime = clip->GetStartTime();
m_EndTime = clip->GetEndTime();
if (m_EndTime < MinClipEnd)
{
m_EndTime = MinClipEnd;
}
m_Duration = clip->GetClipDuration();
}
bool ClipControl::IsAffected(Bone bone) const
{
if (0 == m_AffectedBones.Size())
{
return true;
}
return InvalidIndex != m_AffectedBones.FindIndex(bone);
}
bool ClipControl::IsRunning() const
{
return US_Stop != m_UpdateState;
}
void ClipControl::AddAffectedBones(ClipControl* cc, const Util::Array<ushort>& boneTree, const Util::Array<Util::String>& boneNames, const Util::String& name, bool child)
{
n_assert(NULL != cc);
n_assert(boneTree.Size() == boneNames.Size());
IndexT bone_index = boneNames.FindIndex(name);
if (InvalidIndex != bone_index)
{
if (child)
{
cc->addBoneTree(boneTree, bone_index);
}
else
{
cc->addAffectedBone((Bone)bone_index);
}
}
}
void ClipControl::RemoveAffectedBones(ClipControl* cc, const Util::Array<ushort>& boneTree, const Util::Array<Util::String>& boneNames, const Util::String& name, bool child)
{
n_assert(NULL != cc);
n_assert(boneTree.Size() == boneNames.Size());
IndexT bone_index = boneNames.FindIndex(name);
if (InvalidIndex != bone_index)
{
if (child)
{
cc->removeBoneTree(boneTree, bone_index);
}
else
{
cc->removeAffectedBone((Bone)bone_index);
}
}
}
void ClipControl::clearAllAffectedBones()
{
m_AffectedBones.Clear();
}
void ClipControl::addAffectedBone(Bone bone)
{
if (InvalidBone == m_SkeletonMatch[bone])
{
return;
}
for (int i = 0; i < m_AffectedBones.Size(); ++i)
{
if (m_AffectedBones[i] == bone)
{
return;
}
else if (m_AffectedBones[i] > bone)
{
m_AffectedBones.Insert(i, bone);
return;
}
}
m_AffectedBones.Append(bone);
}
void ClipControl::addBoneTree(const Util::Array<ushort>& boneTree, Bone root)
{
Util::Array<Bone> array;
array.Append(root);
findClidNodes(boneTree, root, array);
Util::Array<Bone>::Iterator it = array.Begin();
while(it != array.End())
{
addAffectedBone(*it);
++it;
}
}
void ClipControl::removeAffectedBone(Bone bone)
{
IndexT index = m_AffectedBones.FindIndex(bone);
if (InvalidIndex != index)
{
m_AffectedBones.EraseIndex(index);
}
}
void ClipControl::removeBoneTree(const Util::Array<ushort>& boneTree, Bone root)
{
Util::Array<Bone> array;
array.Append(root);
findClidNodes(boneTree, root, array);
Util::Array<Bone>::Iterator it = array.Begin();
while(it != array.End())
{
removeAffectedBone(*it);
++it;
}
}
void ClipControl::findClidNodes(const Util::Array<ushort>& boneTree, Bone root, Util::Array<Bone>& array)
{
for (int bone = root + 1; bone < boneTree.Size(); ++bone)
{
if (boneTree[bone] == root)
{
array.Append(bone);
findClidNodes(boneTree, bone, array);
}
}
}
}