#include "assimp_view.h"
using namespace AssimpView;
SceneAnimator::SceneAnimator( const aiScene* pScene, size_t pAnimIndex)
{
mScene = pScene;
mCurrentAnimIndex = -1;
mAnimEvaluator = NULL;
mRootNode = NULL;
for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
{
const aiMesh* mesh = pScene->mMeshes[i];
for (unsigned int n = 0; n < mesh->mNumBones;++n)
{
const aiBone* bone = mesh->mBones[n];
mBoneNodesByName[bone->mName.data] = pScene->mRootNode->FindNode(bone->mName);
}
}
SetAnimIndex( pAnimIndex);
}
SceneAnimator::~SceneAnimator()
{
delete mRootNode;
delete mAnimEvaluator;
}
void SceneAnimator::SetAnimIndex( size_t pAnimIndex)
{
if( pAnimIndex == mCurrentAnimIndex)
return;
delete mRootNode; mRootNode = NULL;
delete mAnimEvaluator; mAnimEvaluator = NULL;
mNodesByName.clear();
mCurrentAnimIndex = pAnimIndex;
mRootNode = CreateNodeTree( mScene->mRootNode, NULL);
if( mCurrentAnimIndex >= mScene->mNumAnimations)
return;
mAnimEvaluator = new AnimEvaluator( mScene->mAnimations[mCurrentAnimIndex]);
}
void SceneAnimator::Calculate( double pTime)
{
if( !mAnimEvaluator)
return;
mAnimEvaluator->Evaluate( pTime);
UpdateTransforms( mRootNode, mAnimEvaluator->GetTransformations());
}
const aiMatrix4x4& SceneAnimator::GetLocalTransform( const aiNode* node) const
{
NodeMap::const_iterator it = mNodesByName.find( node);
if( it == mNodesByName.end())
return mIdentityMatrix;
return it->second->mLocalTransform;
}
const aiMatrix4x4& SceneAnimator::GetGlobalTransform( const aiNode* node) const
{
NodeMap::const_iterator it = mNodesByName.find( node);
if( it == mNodesByName.end())
return mIdentityMatrix;
return it->second->mGlobalTransform;
}
const std::vector<aiMatrix4x4>& SceneAnimator::GetBoneMatrices( const aiNode* pNode, size_t pMeshIndex )
{
ai_assert( pMeshIndex < pNode->mNumMeshes);
size_t meshIndex = pNode->mMeshes[pMeshIndex];
ai_assert( meshIndex < mScene->mNumMeshes);
const aiMesh* mesh = mScene->mMeshes[meshIndex];
mTransforms.resize( mesh->mNumBones, aiMatrix4x4());
aiMatrix4x4 globalInverseMeshTransform = GetGlobalTransform( pNode);
globalInverseMeshTransform.Inverse();
for( size_t a = 0; a < mesh->mNumBones; ++a)
{
const aiBone* bone = mesh->mBones[a];
const aiMatrix4x4& currentGlobalTransform = GetGlobalTransform( mBoneNodesByName[ bone->mName.data ]);
mTransforms[a] = globalInverseMeshTransform * currentGlobalTransform * bone->mOffsetMatrix;
}
return mTransforms;
}
SceneAnimNode* SceneAnimator::CreateNodeTree( aiNode* pNode, SceneAnimNode* pParent)
{
SceneAnimNode* internalNode = new SceneAnimNode( pNode->mName.data);
internalNode->mParent = pParent;
mNodesByName[pNode] = internalNode;
internalNode->mLocalTransform = pNode->mTransformation;
CalculateGlobalTransform( internalNode);
if( mCurrentAnimIndex < mScene->mNumAnimations)
{
internalNode->mChannelIndex = -1;
const aiAnimation* currentAnim = mScene->mAnimations[mCurrentAnimIndex];
for( unsigned int a = 0; a < currentAnim->mNumChannels; a++)
{
if( currentAnim->mChannels[a]->mNodeName.data == internalNode->mName)
{
internalNode->mChannelIndex = a;
break;
}
}
}
for( unsigned int a = 0; a < pNode->mNumChildren; a++)
{
SceneAnimNode* childNode = CreateNodeTree( pNode->mChildren[a], internalNode);
internalNode->mChildren.push_back( childNode);
}
return internalNode;
}
void SceneAnimator::UpdateTransforms( SceneAnimNode* pNode, const std::vector<aiMatrix4x4>& pTransforms)
{
if( pNode->mChannelIndex != -1)
{
ai_assert( pNode->mChannelIndex < pTransforms.size());
pNode->mLocalTransform = pTransforms[pNode->mChannelIndex];
}
CalculateGlobalTransform( pNode);
for( std::vector<SceneAnimNode*>::iterator it = pNode->mChildren.begin(); it != pNode->mChildren.end(); ++it)
UpdateTransforms( *it, pTransforms);
}
void SceneAnimator::CalculateGlobalTransform( SceneAnimNode* pInternalNode)
{
pInternalNode->mGlobalTransform = pInternalNode->mLocalTransform;
SceneAnimNode* node = pInternalNode->mParent;
while( node)
{
pInternalNode->mGlobalTransform = node->mLocalTransform * pInternalNode->mGlobalTransform;
node = node->mParent;
}
}