#include "Managers/AnimationManager.h"
#include "Animators/IAnimator.h"
#include "Records/Mesh.h"
#include "Util/QStack.h"
#include "Util/Flag.h"
#include "Game/Game.h"
#include <vector>
IMP_SINGLETON(AnimationManager);
using namespace std;
AnimationManager::AnimationManager()
{}
AnimationManager::~AnimationManager()
{}
int AnimationManager::initiate()
{
return 1;}
int AnimationManager::update()
{
AnimatorIterator animatorIt = m_animators.begin();
NodeListMapIterator nodeListIt = m_animationNodeLists.begin(); while(nodeListIt != m_animationNodeLists.end())
{
AnimationNodeList * nodeList = nodeListIt->second;
IAnimator *animator = animatorIt->second;
collapseNodes( nodeList );
animator->processNodes( nodeList );
++nodeListIt;
++animatorIt;
}
return 1;}
int AnimationManager::shutdown()
{ for(NodeListMapIterator i = m_animationNodeLists.begin(); i != m_animationNodeLists.end(); ++i)
{
AnimationNodeList * nodes = i->second;
if(nodes)
{
AnimationNodeIterator j = nodes->begin();
while(j != nodes->end())
{
AnimationNode *node = *j;
++j;
destroyAnimationNode(node);
}
nodes->clear();
delete nodes;
}
}
m_animationNodeLists.clear(); for(AnimationSetIterator i = m_animationSets.begin(); i != m_animationSets.end(); ++i)
{
AnimationSet *animationSet = i->second;
AnimatorIterator animatorIt = m_animators.find( animationSet->animatorHash );
if(animatorIt != m_animators.end())
{
IAnimator *animator = animatorIt->second;
animator->destroyAnimationSet( animationSet );
}
}
m_animationSets.clear(); for(AnimatorIterator i = m_animators.begin(); i != m_animators.end(); ++i)
{
IAnimator *animator = i->second;
if(animator)
delete animator;
}
m_animators.clear();
return 1;
}
AnimationSet *AnimationManager::createAnimationSet(string fileName, hash32 animatorHash, void *data)
{
AnimationSet *animationSet = NULL;
AnimationSetIterator it;
bool setExists;
pair<AnimationSetIterator,bool> result; result = m_animationSets.insert( pair<string,AnimationSet*>(fileName,(AnimationSet*)NULL) );
it = result.first;
setExists = !result.second; if(setExists)
{
animationSet = it->second;
++animationSet->refCount;
} else
{ AnimatorIterator animatorIt = m_animators.find( animatorHash );
if(animatorIt != m_animators.end())
{
IAnimator *animator = animatorIt->second;
animationSet = animator->createAnimationSet(fileName,data);
if(animationSet != NULL)
{
animationSet->animatorHash = animatorHash;
animationSet->refCount = 1;
animationSet->parentListPos = it;
it->second = animationSet;
}
}
}
return animationSet;
}
void AnimationManager::destroyAnimationSet(AnimationSet *set)
{
if(!set)
return; --set->refCount; if(!set->refCount)
{ AnimatorIterator animatorIt = m_animators.find( set->animatorHash );
if(animatorIt != m_animators.end())
{
IAnimator *animator = animatorIt->second;
animator->destroyAnimationSet( set );
m_animationSets.erase( set->parentListPos );
}
}
}
AnimationNode *AnimationManager::createAnimationNode(AnimationNode *parent, Mesh *mesh, int flags, float weight)
{
if(!CF(flags,ANF_HEADER) && !mesh->animationHeader)
return NULL;
Mesh::Shared *shared = mesh->shared;
AnimationSet *set = shared->animationSet;
AnimationNode *node = new AnimationNode;
AnimationNode::HeaderInfo *headerInfo = NULL;
bool is_header = CF(flags,ANF_HEADER);
hash32 animatorHash = set->animatorHash; if(is_header)
{
AnimationNodeList * nodes = m_animationNodeLists[ animatorHash ];
nodes->push_back(node);
node->parentList = nodes;
node->parentListPos = --nodes->end();
headerInfo = new AnimationNode::HeaderInfo();
headerInfo->mesh = mesh;
mesh->animationHeader = node;
} else
{
if(parent == NULL)
parent = mesh->animationHeader;
AnimationNodeList & nodes = parent->children;
parent->children.push_back(node);
node->parentList = &nodes;
node->parentListPos = --nodes.end();
}
node->weight = weight;
node->flags = flags;
node->progress = 0.0f;
node->rate = 0.0f;
node->headerInfo = headerInfo;
return node;
}
void AnimationManager::destroyAnimationNode(AnimationNode *node)
{
if(!node)
return;
AnimationNode::HeaderInfo *headerInfo = node->headerInfo;
AnimationNodeList *list = node->parentList;
if(headerInfo)
delete headerInfo; list->erase(node->parentListPos); _destroyAnimationNode(node);
}
void AnimationManager::collapseNodes(AnimationNodeList *nodes)
{
Game *game = Game::getGlobal();
float elapsed = game->getElapsed(); for(AnimationNodeIterator i = nodes->begin(); i != nodes->end(); ++i)
{
AnimationNode *header = *i;
collapseTree(header,elapsed);
}
}
void AnimationManager::collapseTree(AnimationNode *header, float elapsed)
{
AnimationNode::HeaderInfo *headerInfo = header->headerInfo;
QStack<AnimationNode> treeExpansion;
QStack<AnimationNode> & animationStack = headerInfo->animationStack;
if(header->weight == 0.0f)
return; header->collapsedWeight = header->weight; treeExpansion.push(header);
while(!treeExpansion.empty())
{
AnimationNode *node = treeExpansion.pop(); AnimationNodeList & children = node->children;
int & flags = node->flags;
float weight = node->weight;
float collapsedWeight = node->collapsedWeight;
float childWeightTotal = 0.0f;
float multiplier;
float & progress = node->progress;
bool is_header = CF(flags,ANF_HEADER);
bool is_looping = CF(flags,ANF_LOOPING);
bool is_animation = CF(flags,ANF_ANIMATION);
bool is_dead = CF(flags,ANF_DEAD);
progress += node->rate*elapsed; if(progress >= 1.0f)
{
if(is_looping)
{
while(progress >= 1.0f)
progress -= 1.0f;
}
else
{
progress = 1.0f;
flags |= ANF_DEAD;
}
} if(is_animation)
animationStack.push(node);
else
{ for(AnimationNodeIterator j = children.begin(); j != children.end(); ++j)
{
AnimationNode *child = *j;
childWeightTotal += child->weight;
}
if(childWeightTotal > 0.0f)
{ multiplier = collapsedWeight / childWeightTotal; for(AnimationNodeIterator j = children.begin(); j != children.end(); ++j)
{
AnimationNode *child = *j;
child->collapsedWeight = child->weight * multiplier;
treeExpansion.push(child);
}
}
}
}
}void AnimationManager::_destroyAnimationNode(AnimationNode *node)
{
if(!node)
return;
AnimationNodeList & children = node->children;
for(AnimationNodeIterator i = children.begin(); i != children.end(); ++i)
_destroyAnimationNode(*i);
children.clear();
delete node;
}