6e8fbca745
match the genesis editor version 1.3.0.653.
877 lines
22 KiB
C++
877 lines
22 KiB
C++
/****************************************************************************
|
||
Copyright (c) 2011-2013,WebJet Business Division,CYOU
|
||
|
||
http://www.genesis-3d.com.cn
|
||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||
of this software and associated documentation files (the "Software"), to deal
|
||
in the Software without restriction, including without limitation the rights
|
||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||
copies of the Software, and to permit persons to whom the Software is
|
||
furnished to do so, subject to the following conditions:
|
||
|
||
The above copyright notice and this permission notice shall be included in
|
||
all copies or substantial portions of the Software.
|
||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||
THE SOFTWARE.
|
||
****************************************************************************/
|
||
|
||
#include "animation/animation_stdneb.h"
|
||
#include "animation/Animation.h"
|
||
#include "animation/AnimationUtil.h"
|
||
|
||
#include <functional>
|
||
|
||
|
||
#define _VEC_ITERATOR(TYPE, VECTOR, ELEM) \
|
||
Util::Array< TYPE >::Iterator ELEM = VECTOR.Begin();\
|
||
Util::Array< TYPE >::Iterator __end = VECTOR.End();
|
||
#define _FOREACH(ELEM)\
|
||
while (ELEM != __end)\
|
||
{
|
||
|
||
#define _FOREACH_VECTOR_BEGIN(TYPE, VECTOR, ELEM) \
|
||
_VEC_ITERATOR(TYPE, VECTOR, ELEM) \
|
||
_FOREACH(ELEM)
|
||
#define _FOREACH_VECTOR_END(ELEM) \
|
||
++ ELEM;\
|
||
}
|
||
|
||
namespace Animations
|
||
{
|
||
static const float TINY_WEIGHT = 0.0001f;
|
||
static const float NO_WEIGHT = 0.0f;
|
||
static const float FULL_WEIGHT = 1.0f;
|
||
inline void _quaternion_add_blend(Math::quaternion& target, const Math::quaternion& from, float weight)
|
||
{
|
||
float sign = Math::n_sgn(from.dot(target));
|
||
float qx = from.x() * weight * sign;
|
||
float qy = from.y() * weight * sign;
|
||
float qz = from.z() * weight * sign;
|
||
float qw = from.w() * weight * sign;
|
||
target.set_x(target.x() + qx );
|
||
target.set_y(target.y() + qy );
|
||
target.set_z(target.z() + qz );
|
||
target.set_w(target.w() + qw );
|
||
}
|
||
|
||
struct CompareLayers : public std::binary_function<const AnimationLayer*, const AnimationLayer*, std::size_t>
|
||
{
|
||
bool operator() (const AnimationLayer* lhs, const AnimationLayer* rhs) const
|
||
{
|
||
return lhs->GetLayerIndex() < rhs->GetLayerIndex();
|
||
}
|
||
};
|
||
|
||
__ImplementClass( Animations::Animation, 'ANIM', Core::RefCounted);
|
||
|
||
Animation::Animation()
|
||
: m_bUpdateResult(false)
|
||
, m_ClientCount(0)
|
||
, m_bDirty(true)
|
||
,m_LocalTimer(0.0f)
|
||
,m_UpdateTime(0.0f)
|
||
{
|
||
}
|
||
|
||
Animation::~Animation()
|
||
{
|
||
clearAnimClips();
|
||
clearClipControls();
|
||
clearLayers();
|
||
m_ToParentTrans.Clear();
|
||
m_SampledTrans.Clear();
|
||
m_SampledScale.Clear();
|
||
m_SampledRotation.Clear();
|
||
}
|
||
|
||
void Animation::AddAnimClip(const GPtr<AnimationClip> &animClip)
|
||
{
|
||
RemoveAnimClip(animClip->GetName());
|
||
|
||
m_AnimClips.Append(animClip);
|
||
|
||
if (0 == m_AnimationLayers.Size())
|
||
{
|
||
buildLayer(DefaultLayer);
|
||
}
|
||
buildControl(animClip.get(), m_AnimationLayers[DefaultLayer]);
|
||
}
|
||
|
||
void Animation::RemoveAnimClip(const Resources::ResourceId& clipName)
|
||
{
|
||
int index = findClipIndex(clipName);
|
||
if (InvalidIndex != index)
|
||
{
|
||
m_ClipControls[index]->Destroy();
|
||
m_AnimClips.EraseIndex(index);
|
||
n_delete(m_ClipControls[index]);
|
||
m_ClipControls.EraseIndex(index);
|
||
}
|
||
}
|
||
|
||
int Animation::GetAnimClipCount() const
|
||
{
|
||
return m_AnimClips.Size();
|
||
}
|
||
|
||
void Animation::SetLayer(const Resources::ResourceId& name, int layer)
|
||
{
|
||
ClipControl* cc = findControl(name);
|
||
if (cc)
|
||
{
|
||
AnimationLayer* al = findLayer(layer);
|
||
if (NULL == al)
|
||
{
|
||
al = buildLayer(layer);
|
||
}
|
||
cc->BindLayer(al);
|
||
}
|
||
}
|
||
|
||
int Animation::GetLayer(const Resources::ResourceId& name)
|
||
{
|
||
ClipControl* cc = findControl(name);
|
||
|
||
if (cc)
|
||
{
|
||
return cc->GetLayer()->GetLayerIndex();
|
||
}
|
||
|
||
return (int)DefaultLayer;
|
||
}
|
||
|
||
void Animation::SetPlayRate(const Resources::ResourceId& name, float rate)
|
||
{
|
||
ClipControl* cc = findControl(name);
|
||
if (cc)
|
||
{
|
||
cc->SetSpeed(rate);
|
||
}
|
||
}
|
||
|
||
void Animation::SetWeight(const Resources::ResourceId& name, float weight)
|
||
{
|
||
ClipControl* cc = findControl(name);
|
||
if (cc)
|
||
{
|
||
cc->SetWeight(weight);
|
||
}
|
||
}
|
||
|
||
float Animation::GetWeight(const Resources::ResourceId& name)
|
||
{
|
||
ClipControl* cc = findControl(name);
|
||
if (cc)
|
||
{
|
||
return cc->GetWeight();
|
||
}
|
||
|
||
return 0.0f;
|
||
}
|
||
|
||
void Animation::SetWrapMode(const Resources::ResourceId& name, int wrapMode)
|
||
{
|
||
ClipControl* cc = findControl(name);
|
||
if (cc)
|
||
{
|
||
cc->SetWrapMode(wrapMode);
|
||
}
|
||
}
|
||
|
||
int Animation::GetWrapMode(const Resources::ResourceId& name)
|
||
{
|
||
ClipControl* cc = findControl(name);
|
||
if (cc)
|
||
{
|
||
return cc->GetWrapMode();
|
||
}
|
||
return (int)ClipControl::PlayUnknown;
|
||
}
|
||
|
||
|
||
void Animation::PlayAnim(const Resources::ResourceId &name, int playMode)
|
||
{
|
||
CrossFading(name, playMode, 0.0f);
|
||
}
|
||
|
||
void Animation::Stop()
|
||
{
|
||
_FOREACH_VECTOR_BEGIN(ClipControl*, m_ClipControls, node)
|
||
(*node)->FadeOut(0.0f);
|
||
_FOREACH_VECTOR_END(node);
|
||
|
||
m_ToParentTrans.Clear(false);
|
||
}
|
||
|
||
void Animation::Stop(const Resources::ResourceId& name, float time)
|
||
{
|
||
ClipControl* cc = findControl(name);
|
||
if (cc)
|
||
{
|
||
cc->FadeOut(time);
|
||
}
|
||
}
|
||
|
||
void Animation::Pause(const Resources::ResourceId& name)
|
||
{
|
||
ClipControl* cc = findControl(name);
|
||
if (cc)
|
||
{
|
||
cc->Pause();
|
||
}
|
||
}
|
||
|
||
void Animation::Resume(const Resources::ResourceId& name)
|
||
{
|
||
ClipControl* cc = findControl(name);
|
||
if (cc)
|
||
{
|
||
//cc->FadeOut(0.0f);
|
||
cc->FadeIn(0.0f);
|
||
}
|
||
}
|
||
|
||
bool Animation::IsPlaying()
|
||
{
|
||
_FOREACH_VECTOR_BEGIN(ClipControl*, m_ClipControls, node)
|
||
if(ClipControl::US_Playing == (*node)->GetState() || ClipControl::US_End == (*node)->GetState())
|
||
{
|
||
return true;
|
||
}
|
||
_FOREACH_VECTOR_END(node);
|
||
return false;
|
||
}
|
||
|
||
bool Animation::IsPaused()
|
||
{
|
||
_FOREACH_VECTOR_BEGIN(ClipControl*, m_ClipControls, node)
|
||
if(ClipControl::US_Pause == (*node)->GetState())
|
||
{
|
||
return true;
|
||
}
|
||
_FOREACH_VECTOR_END(node);
|
||
return false;
|
||
}
|
||
|
||
bool Animation::IsPlaying(const Resources::ResourceId& name)
|
||
{
|
||
ClipControl* cc = findControl(name);
|
||
if (cc)
|
||
{
|
||
return (ClipControl::US_Playing == cc->GetState() || ClipControl::US_End == cc->GetState());
|
||
}
|
||
return false;
|
||
}
|
||
|
||
bool Animation::Contain(const Resources::ResourceId& name)
|
||
{
|
||
ClipControl* cc = findControl(name);
|
||
return cc != NULL;
|
||
}
|
||
|
||
bool Animation::IsPaused(const Resources::ResourceId& name)
|
||
{
|
||
ClipControl* cc = findControl(name);
|
||
if (cc)
|
||
{
|
||
return ClipControl::US_Pause == cc->GetState();
|
||
}
|
||
return false;
|
||
}
|
||
|
||
void Animation::CrossFading(const Resources::ResourceId &name, int playMode, float fadingTime)
|
||
{
|
||
ClipControl* cc = findControl(name);
|
||
if (cc)
|
||
{
|
||
AnimationLayer* layer = cc->GetLayer();
|
||
m_bDirty = true;
|
||
if (ClipControl::StopAllAnim == playMode)
|
||
{
|
||
AnimationLayers::Iterator it = m_AnimationLayers.Begin();
|
||
while(it != m_AnimationLayers.End())
|
||
{
|
||
if (*it != layer)
|
||
{
|
||
(*it)->FadeOutAll(fadingTime);
|
||
}
|
||
++it;
|
||
}
|
||
cc->FadeIn(fadingTime);
|
||
}
|
||
else if (ClipControl::StopSameAnimLayer == playMode)
|
||
{
|
||
cc->FadeIn(fadingTime);
|
||
}
|
||
}
|
||
}
|
||
|
||
void Animation::Blending(const Resources::ResourceId &name, float targetWeight, float time)
|
||
{
|
||
ClipControl* cc = findControl(name);
|
||
if (cc)
|
||
{
|
||
m_bDirty = true;
|
||
cc->Blend(targetWeight, time);
|
||
}
|
||
}
|
||
|
||
bool Animation::UpdateAnimation(float time)
|
||
{
|
||
m_LocalTimer += time;
|
||
|
||
m_bUpdateResult = false;
|
||
AnimationLayers::Iterator it = m_AnimationLayers.Begin();
|
||
while (it != m_AnimationLayers.End())
|
||
{
|
||
if ((*it)->Update(time))
|
||
{
|
||
m_bUpdateResult = true;
|
||
}
|
||
++it;
|
||
}
|
||
|
||
if (m_ClientCount == 0)
|
||
{
|
||
m_bUpdateResult = false;
|
||
return false;
|
||
}
|
||
|
||
if (m_bUpdateResult)
|
||
{
|
||
if(m_LocalTimer>m_UpdateTime)
|
||
{
|
||
sample();
|
||
m_LocalTimer = 0;
|
||
}
|
||
else
|
||
{
|
||
m_bUpdateResult = false;
|
||
}
|
||
|
||
|
||
}
|
||
else
|
||
{
|
||
m_ToParentTrans.Clear(false);
|
||
}
|
||
|
||
return m_bUpdateResult;
|
||
}
|
||
|
||
void Animation::SetTime(const Resources::ResourceId& name, float time)
|
||
{
|
||
ClipControl* cc = findControl(name);
|
||
if (cc)
|
||
{
|
||
cc->SetTime(time);
|
||
}
|
||
}
|
||
|
||
float Animation::GetWrapTime(const Resources::ResourceId& name)
|
||
{
|
||
ClipControl* cc = findControl(name);
|
||
if (cc)
|
||
{
|
||
return cc->GetCurrentWrapTime();
|
||
}
|
||
|
||
return 0.0f;
|
||
}
|
||
|
||
void Animation::SetNormalizedTime(const Resources::ResourceId& name, float time)
|
||
{
|
||
ClipControl* cc = findControl(name);
|
||
if (cc)
|
||
{
|
||
cc->SetNormalizeTime(time);
|
||
}
|
||
}
|
||
|
||
void Animation::SetEnable(const Resources::ResourceId& name, bool enable)
|
||
{
|
||
///lazy man.
|
||
}
|
||
|
||
bool Animation::IsEnable(const Resources::ResourceId& name)
|
||
{
|
||
///lazy man.
|
||
return false;
|
||
}
|
||
|
||
void Animation::AddAffectedNodes(const Resources::ResourceId &stateName, const Util::String& nodeName, bool recursive)
|
||
{
|
||
ClipControl* cc = findControl(stateName);
|
||
if (cc)
|
||
{
|
||
ClipControl::AddAffectedBones(cc, m_NodeParentIndexVec, m_NodeNameVec, nodeName, recursive);
|
||
}
|
||
}
|
||
|
||
void Animation::RemoveAffectedNodes(const Resources::ResourceId& stateName, const Util::String& nodeName, bool recursive)
|
||
{
|
||
ClipControl* cc = findControl(stateName);
|
||
if (cc)
|
||
{
|
||
ClipControl::RemoveAffectedBones(cc, m_NodeParentIndexVec, m_NodeNameVec, nodeName, recursive);
|
||
}
|
||
}
|
||
|
||
bool Animation::IsAnimNodeAffected( const Resources::ResourceId& stateName, const Util::String& nodeName )
|
||
{
|
||
IndexT index = m_NodeNameVec.FindIndex(nodeName);
|
||
if (InvalidIndex != index)
|
||
{
|
||
ClipControl* cc = findControl(stateName);
|
||
if (cc)
|
||
{
|
||
return cc->IsAffected((Bone)index);
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
|
||
bool Animation::BuildDefaultToRootTrans()
|
||
{
|
||
Math::float3 trans;
|
||
Math::float3 scale;
|
||
Math::quaternion rotation;
|
||
|
||
m_DefaultToRootX.Clear();
|
||
Util::Array<Math::matrix44> defaultToParentTrans;
|
||
Util::Array<Math::float3> defaultTrans;
|
||
Util::Array<Math::float3> defaultScale;
|
||
Util::Array<Math::quaternion> defaultRotation;
|
||
|
||
int nodeCount = m_CheckedNodeList.Size();
|
||
|
||
defaultTrans.Resize(nodeCount, Math::float3(0.0, 0.0, 0.0));
|
||
defaultScale.Resize(nodeCount, Math::float3(0.0, 0.0, 0.0));
|
||
defaultRotation.Resize(nodeCount, Math::quaternion(0.0, 0.0, 0.0, 0.0));
|
||
|
||
//Use m_CheckedNodeList's nodeName<6D><65>find nodes in animClip
|
||
for(int iNode = 0; iNode<nodeCount; ++iNode)
|
||
{
|
||
trans = Math::float3(m_CheckedNodeList[iNode].defPosition.x(),m_CheckedNodeList[iNode].defPosition.y(),m_CheckedNodeList[iNode].defPosition.z());
|
||
scale = Math::float3(m_CheckedNodeList[iNode].defScale.x(),m_CheckedNodeList[iNode].defScale.y(),m_CheckedNodeList[iNode].defScale.z());
|
||
rotation = m_CheckedNodeList[iNode].defRotation;
|
||
|
||
defaultTrans[iNode] = trans;
|
||
defaultScale[iNode] = scale;
|
||
|
||
float sign = Math::n_sgn(rotation.dot(defaultRotation[iNode]));
|
||
|
||
float qx = rotation.x() * sign;
|
||
float qy = rotation.y() * sign;
|
||
float qz = rotation.z() * sign;
|
||
float qw = rotation.w() * sign;
|
||
|
||
|
||
defaultRotation[iNode].set_x( defaultRotation[iNode].x() + qx );
|
||
defaultRotation[iNode].set_y( defaultRotation[iNode].y() + qy );
|
||
defaultRotation[iNode].set_z( defaultRotation[iNode].z() + qz );
|
||
defaultRotation[iNode].set_w( defaultRotation[iNode].w() + qw );
|
||
|
||
if(defaultRotation[iNode].length() != 0)
|
||
defaultRotation[iNode] = defaultRotation[iNode].normalize(defaultRotation[iNode]);
|
||
|
||
Math::float4 trans4(defaultTrans[iNode].x(), defaultTrans[iNode].y(), defaultTrans[iNode].z(), 1.0);
|
||
Math::float4 scale4(defaultScale[iNode].x(), defaultScale[iNode].y(), defaultScale[iNode].z(), 1.0);
|
||
|
||
Math::matrix44 toParent = Math::matrix44::transformation(
|
||
scale4, defaultRotation[iNode], trans4);
|
||
|
||
defaultToParentTrans.Append(toParent);
|
||
|
||
//transform ToParent to ToRoot
|
||
ushort indiceNodeParent = m_CheckedNodeList[iNode].parentIndex;
|
||
if (indiceNodeParent != InvalidBone)
|
||
{
|
||
Math::matrix44 toRootX = Math::matrix44::multiply( defaultToParentTrans[indiceNodeParent], defaultToParentTrans[iNode] );
|
||
defaultToParentTrans[iNode] = toRootX;
|
||
DefaultToRootXInfo defaultInfo;
|
||
defaultInfo.skelName = m_CheckedNodeList[iNode].nodeName;
|
||
defaultInfo.toRootX = toRootX;
|
||
m_DefaultToRootX.Append(defaultInfo);
|
||
}
|
||
else if (indiceNodeParent == InvalidBone)
|
||
{
|
||
//toParent[iNode] = Math::matrix44::multiply(rotx, toParent[iNode]);
|
||
DefaultToRootXInfo defaultInfo;
|
||
defaultInfo.skelName = m_CheckedNodeList[iNode].nodeName;
|
||
defaultInfo.toRootX = defaultToParentTrans[iNode];
|
||
m_DefaultToRootX.Append(defaultInfo);
|
||
}
|
||
|
||
}
|
||
|
||
defaultToParentTrans.Clear(true);
|
||
defaultTrans.Clear(true);
|
||
defaultScale.Clear(true);
|
||
defaultRotation.Clear(true);
|
||
|
||
if(!m_DefaultToRootX.IsEmpty())
|
||
return true;
|
||
else
|
||
return false;
|
||
}
|
||
|
||
void Animation::SetSkelTree( const Util::Array< GPtr<Resources::SkelTreeData> >& skelTree )
|
||
{
|
||
//clean data
|
||
m_NodeNameVec.Clear(false);
|
||
m_NodeParentIndexVec.Clear(false);
|
||
m_CheckedNodeList.Clear(false);
|
||
|
||
//init m_CheckedNodeList
|
||
CheckedNode tempNode;
|
||
m_CheckedNodeList.Resize(skelTree.Size(),tempNode);
|
||
|
||
//find in skelTree<65><65>build NodeNameVec and NodeParentIndexVec
|
||
for(int i = 0; i<skelTree.Size();++i)
|
||
{
|
||
m_CheckedNodeList[i].nodeName = skelTree[i]->name;
|
||
m_NodeNameVec.Append(skelTree[i]->name);
|
||
|
||
ushort parentIndex = InvalidBone;
|
||
if(skelTree[i]->parent.isvalid())
|
||
{
|
||
Util::String parentName = skelTree[i]->parent->name;
|
||
for(int nodeIndex = 0; nodeIndex<i; ++nodeIndex)
|
||
{
|
||
if(m_CheckedNodeList[nodeIndex].nodeName == parentName)
|
||
{
|
||
parentIndex = nodeIndex;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
m_CheckedNodeList[i].parentIndex = parentIndex;
|
||
m_NodeParentIndexVec.Append(parentIndex);
|
||
|
||
//set skeleton's default transform
|
||
m_CheckedNodeList[i].defPosition = Math::float3(skelTree[i]->pos.x(),skelTree[i]->pos.y(),skelTree[i]->pos.z());
|
||
m_CheckedNodeList[i].defRotation = skelTree[i]->rot;
|
||
m_CheckedNodeList[i].defScale = Math::float3(skelTree[i]->scale.x(),skelTree[i]->scale.y(),skelTree[i]->scale.z());
|
||
}
|
||
|
||
ClipControls::Iterator it = m_ClipControls.Begin();
|
||
while(it != m_ClipControls.End())
|
||
{
|
||
(*it)->MatchSkeleton(m_NodeNameVec);
|
||
++it;
|
||
}
|
||
}
|
||
|
||
|
||
inline bool _alloc_weight(float* free_weights, int bone_index, float get_from_free, float& out_take_away)
|
||
{
|
||
float& free = free_weights[bone_index];
|
||
if (free > NO_WEIGHT)
|
||
{
|
||
float take_away = free * get_from_free;
|
||
if (take_away > TINY_WEIGHT)
|
||
{
|
||
if (take_away > free)
|
||
{
|
||
out_take_away = free;
|
||
free = NO_WEIGHT;
|
||
}
|
||
else
|
||
{
|
||
free -= take_away;
|
||
out_take_away = take_away;
|
||
}
|
||
return true;
|
||
}
|
||
}
|
||
out_take_away = NO_WEIGHT;
|
||
return false;
|
||
}
|
||
|
||
inline bool _alloc_weight_force(float* free_weights, int bone_index, float& take_away)
|
||
{
|
||
|
||
if (free_weights[bone_index] > NO_WEIGHT)
|
||
{
|
||
if(free_weights[bone_index] > take_away)
|
||
{
|
||
free_weights[bone_index] -= take_away;
|
||
}
|
||
else
|
||
{
|
||
take_away = free_weights[bone_index];
|
||
free_weights[bone_index] = NO_WEIGHT;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
void Animation::blendFrameDataFromFree(int bone_index, float take_from_free,
|
||
const Math::float3& pos, const Math::quaternion& rotate, const Math::float3& scale)
|
||
{
|
||
float take_away = NO_WEIGHT;
|
||
if(_alloc_weight(&m_FreeWeights[0], bone_index, take_from_free, take_away))
|
||
{
|
||
m_SampledTrans[bone_index] += (pos * take_away);
|
||
m_SampledScale[bone_index] += (scale * take_away);
|
||
_quaternion_add_blend(m_SampledRotation[bone_index], rotate, take_away);
|
||
}
|
||
}
|
||
|
||
void Animation::blendFrameData(int bone_index, float take_force,
|
||
const Math::float3& pos, const Math::quaternion& rotate, const Math::float3& scale)
|
||
{
|
||
float take_away = NO_WEIGHT;
|
||
if(_alloc_weight_force(&m_FreeWeights[0], bone_index, take_force))
|
||
{
|
||
m_SampledTrans[bone_index] += (pos * take_force);
|
||
m_SampledScale[bone_index] += (scale * take_force);
|
||
_quaternion_add_blend(m_SampledRotation[bone_index], rotate, take_force);
|
||
}
|
||
}
|
||
|
||
template<bool check_layer>
|
||
void Animation::blendControl(const ClipControl* cc, int nodeCount)
|
||
{
|
||
Math::float3 trans;
|
||
Math::float3 scale;
|
||
Math::quaternion rotation;
|
||
|
||
float wrap_time = cc->GetCurrentWrapTime();
|
||
float weight = cc->GetCurrentWeight();
|
||
|
||
const Util::Array<Bone>& bones = cc->GetAffectedBones();
|
||
if (bones.Size())
|
||
{
|
||
for (int i = 0; i < bones.Size(); ++i)
|
||
{
|
||
Bone bone = bones[i];
|
||
if(m_FreeWeights[bone] > NO_WEIGHT)
|
||
{
|
||
cc->GetFrameDataNoCheck(wrap_time, bone, trans, rotation, scale);
|
||
if (check_layer)
|
||
{
|
||
blendFrameData(bone, weight * m_LayerWeights[bone], trans, rotation, scale);
|
||
}
|
||
else
|
||
{
|
||
blendFrameDataFromFree(bone, weight, trans, rotation, scale);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
for (int bone_index = 0; bone_index < nodeCount; ++bone_index)
|
||
{
|
||
if(m_FreeWeights[bone_index] > NO_WEIGHT && cc->GetFrameData(wrap_time, bone_index, trans, rotation, scale))
|
||
{
|
||
if (check_layer)
|
||
{
|
||
blendFrameData(bone_index, weight * m_LayerWeights[bone_index], trans, rotation, scale);
|
||
}
|
||
else
|
||
{
|
||
blendFrameDataFromFree(bone_index, weight, trans, rotation, scale);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
void Animation::buildLayerWeight(const ClipControls& activeControls, int nodeCount)
|
||
{
|
||
m_LayerWeights.Clear(false);
|
||
m_LayerWeights.AppendArray(m_FreeWeights);
|
||
//m_LayerWeights.Clear(false);
|
||
//m_LayerWeights.Resize(nodeCount, 0.0f);
|
||
//ClipControls::Iterator it = activeControls.Begin();
|
||
//while(it != activeControls.End())
|
||
//{
|
||
// float weight = (*it)->GetCurrentWeight();
|
||
// const Util::Array<Bone>& bones = (*it)->GetAffectedBones();
|
||
// if (bones.Size())
|
||
// {
|
||
// for (int i = 0; i < bones.Size(); ++i)
|
||
// {
|
||
// Bone bone = bones[i];
|
||
// m_LayerWeights[bone] += (weight * m_FreeWeights[bone]);
|
||
// }
|
||
// }
|
||
// else
|
||
// {
|
||
// for (int bone_index = 0; bone_index < nodeCount; ++bone_index)
|
||
// {
|
||
// if ((*it)->ContainBoneInfo(bone_index))
|
||
// {
|
||
// m_LayerWeights[bone_index] += (weight * m_FreeWeights[bone_index]);
|
||
// }
|
||
// }
|
||
// }
|
||
// ++it;
|
||
//}
|
||
}
|
||
|
||
void Animation::sample()
|
||
{
|
||
int nodeCount = m_NodeNameVec.Size();
|
||
|
||
m_ToParentTrans.Clear(false);
|
||
m_SampledTrans.Clear(false);
|
||
m_SampledScale.Clear(false);
|
||
m_SampledRotation.Clear(false);
|
||
m_FreeWeights.Clear(false);
|
||
|
||
m_SampledTrans.Resize(nodeCount, Math::float3(0.0f, 0.0f, 0.0f));
|
||
m_SampledScale.Resize(nodeCount, Math::float3(0.0f, 0.0f, 0.0f));
|
||
m_SampledRotation.Resize(nodeCount, Math::quaternion(0.0f, 0.0f, 0.0f,0.0f));
|
||
m_FreeWeights.Resize(nodeCount, 1.0f);
|
||
|
||
for (int i = m_AnimationLayers.Size() - 1; i >= 0; --i)
|
||
{
|
||
AnimationLayer* layer = m_AnimationLayers[i];
|
||
ClipControls& activeControls = layer->GetActiveList();
|
||
if (activeControls.Size() == 1)
|
||
{
|
||
blendControl<false>(activeControls[0], nodeCount);
|
||
}
|
||
else if (activeControls.Size() >= 1)
|
||
{
|
||
buildLayerWeight(activeControls, nodeCount);
|
||
|
||
ClipControls::Iterator it = activeControls.Begin();
|
||
while(it != activeControls.End())
|
||
{
|
||
blendControl<true>(*it, nodeCount);
|
||
++it;
|
||
}
|
||
}
|
||
}
|
||
for (int iNode = 0; iNode < nodeCount; ++iNode)
|
||
{
|
||
if (m_FreeWeights[iNode] > NO_WEIGHT)
|
||
{
|
||
m_SampledTrans[iNode] += (m_CheckedNodeList[iNode].defPosition * m_FreeWeights[iNode]);
|
||
m_SampledScale[iNode] += (m_CheckedNodeList[iNode].defScale * m_FreeWeights[iNode]);
|
||
_quaternion_add_blend(m_SampledRotation[iNode], m_CheckedNodeList[iNode].defRotation, m_FreeWeights[iNode]);
|
||
}
|
||
|
||
if(m_SampledRotation[iNode].length() != 0)
|
||
m_SampledRotation[iNode] = m_SampledRotation[iNode].normalize(m_SampledRotation[iNode]);
|
||
|
||
Math::float4 trans4(m_SampledTrans[iNode].x(), m_SampledTrans[iNode].y(), m_SampledTrans[iNode].z(), 1.0);
|
||
Math::float4 scale4(m_SampledScale[iNode].x(), m_SampledScale[iNode].y(), m_SampledScale[iNode].z(), 1.0);
|
||
|
||
Math::matrix44 toParent = Math::matrix44::transformation(
|
||
scale4, m_SampledRotation[iNode], trans4);
|
||
m_ToParentTrans.Append(toParent);
|
||
}
|
||
}
|
||
|
||
void Animation::clearClipControls()
|
||
{
|
||
_FOREACH_VECTOR_BEGIN(ClipControl*, m_ClipControls, node)
|
||
n_delete (*node);
|
||
_FOREACH_VECTOR_END(node);
|
||
|
||
m_ClipControls.Clear();
|
||
}
|
||
|
||
void Animation::clearAnimClips()
|
||
{
|
||
m_AnimClips.Clear();
|
||
}
|
||
|
||
void Animation::clearLayers()
|
||
{
|
||
_FOREACH_VECTOR_BEGIN(AnimationLayer*, m_AnimationLayers, node)
|
||
n_delete (*node);
|
||
_FOREACH_VECTOR_END(node);
|
||
m_AnimationLayers.Clear();
|
||
}
|
||
|
||
void Animation::buildControl(AnimationClip* clip, AnimationLayer* layer)
|
||
{
|
||
ClipControl* cc = n_new(ClipControl);
|
||
m_ClipControls.Append(cc);
|
||
cc->SetClip(clip);
|
||
cc->BindLayer(layer);
|
||
if (m_NodeNameVec.Size())
|
||
{
|
||
cc->MatchSkeleton(m_NodeNameVec);
|
||
}
|
||
}
|
||
|
||
AnimationLayer* Animation::buildLayer(int index)
|
||
{
|
||
n_assert(NULL == findLayer(index));
|
||
AnimationLayer* al = n_new(AnimationLayer);
|
||
al->SetLayerIndex(index);
|
||
m_AnimationLayers.Append(al);
|
||
Util::CustomSortArray<AnimationLayer*, CompareLayers>(m_AnimationLayers);
|
||
return al;
|
||
}
|
||
|
||
AnimationLayer* Animation::findLayer(int index) const
|
||
{
|
||
_FOREACH_VECTOR_BEGIN(AnimationLayer*, m_AnimationLayers, node)
|
||
if((*node)->GetLayerIndex() == index)
|
||
{
|
||
return *node;
|
||
}
|
||
_FOREACH_VECTOR_END(node);
|
||
return NULL;
|
||
}
|
||
|
||
AnimationClip* Animation::findClip(const Resources::ResourceId& name) const
|
||
{
|
||
_FOREACH_VECTOR_BEGIN(GPtr<AnimationClip>, m_AnimClips, node)
|
||
if((*node)->GetName() == name)
|
||
{
|
||
return (*node).get_unsafe();
|
||
}
|
||
_FOREACH_VECTOR_END(node);
|
||
|
||
return NULL;
|
||
}
|
||
|
||
ClipControl* Animation::findControl(const Resources::ResourceId& name) const
|
||
{
|
||
_FOREACH_VECTOR_BEGIN(ClipControl*, m_ClipControls, node)
|
||
if((*node)->GetClip()->GetName() == name)
|
||
{
|
||
return (*node);
|
||
}
|
||
_FOREACH_VECTOR_END(node);
|
||
return NULL;
|
||
}
|
||
|
||
int Animation::findClipIndex(const Resources::ResourceId& name) const
|
||
{
|
||
for (int i = 0; i < m_AnimClips.Size(); ++i)
|
||
{
|
||
if (m_AnimClips[i]->GetName() == name)
|
||
{
|
||
return i;
|
||
}
|
||
}
|
||
return InvalidIndex;
|
||
}
|
||
|
||
void Animation::SetUpdateTime( float updateTime )
|
||
{
|
||
m_UpdateTime = updateTime;
|
||
}
|
||
|
||
} |