Files
bullet3/Extras/FCollada/FCDocument/FCDAnimationClip.cpp
2006-05-25 19:18:29 +00:00

140 lines
4.6 KiB
C++

/*
Copyright (C) 2005-2006 Feeling Software Inc.
MIT License: http://www.opensource.org/licenses/mit-license.php
*/
#include "StdAfx.h"
#include "FCDocument/FCDocument.h"
#include "FCDocument/FCDAnimation.h"
#include "FCDocument/FCDAnimationChannel.h"
#include "FCDocument/FCDAnimationClip.h"
#include "FCDocument/FCDAnimationCurve.h"
#include "FCDocument/FCDAnimated.h"
#include "FUtils/FUDaeParser.h"
#include "FUtils/FUDaeWriter.h"
using namespace FUDaeParser;
using namespace FUDaeWriter;
FCDAnimationClip::FCDAnimationClip(FCDocument* document) : FCDEntity(document, "AnimationClip")
{
start = end = 0.0f;
}
FCDAnimationClip::~FCDAnimationClip()
{
curves.clear();
}
FCDAnimationClip* FCDAnimationClip::Clone()
{
FCDAnimationClip* clone = new FCDAnimationClip(GetDocument());
FCDEntity::Clone(clone);
for(FCDAnimationCurveList::iterator it = curves.begin(); it != curves.end(); ++it)
{
curves.push_back((*it)->Clone());
}
clone->start = start;
clone->end = end;
return clone;
}
FUStatus FCDAnimationClip::LoadFromXML(xmlNode* clipNode)
{
FUStatus status = FCDEntity::LoadFromXML(clipNode);
if (!status) return status;
if (!IsEquivalent(clipNode->name, DAE_ANIMCLIP_ELEMENT))
{
return status.Warning(FS("Unknown element in animation clip library."), clipNode->line);
}
// Read in and verify the clip's time/input bounds
start = FUStringConversion::ToFloat(ReadNodeProperty(clipNode, DAE_START_ATTRIBUTE));
end = FUStringConversion::ToFloat(ReadNodeProperty(clipNode, DAE_END_ATTRIBUTE));
if (end - start < FLT_TOLERANCE)
{
status.Warning(FS("Invalid start/end pair for animation clip: ") + TO_FSTRING(GetDaeId()), clipNode->line);
}
// Read in the <input> elements and segment the corresponding animation curves
xmlNodeList inputNodes;
FindChildrenByType(clipNode, DAE_INSTANCE_ANIMATION_ELEMENT, inputNodes);
for (xmlNodeList::iterator itI = inputNodes.begin(); itI != inputNodes.end(); ++itI)
{
xmlNode* inputNode = (*itI);
// Retrieve the animation for this input
FUUri animationId = ReadNodeUrl(inputNode);
if (animationId.suffix.empty() || !animationId.prefix.empty())
{
return status.Fail(FS("Invalid animation instantiation for animation clip: ") + TO_FSTRING(GetDaeId()), inputNode->line);
}
FCDAnimation* animation = GetDocument()->FindAnimation(animationId.suffix);
if (animation == NULL) continue;
// Retrieve all the curves created under this animation node
FCDAnimationCurveList animationCurves;
animation->GetCurves(animationCurves);
if (animationCurves.empty())
{
status.Warning(FS("No curves instantiated by animation '") + TO_FSTRING(animationId.suffix) + FS("' for animation clip: ") + TO_FSTRING(GetDaeId()), inputNode->line);
}
for (FCDAnimationCurveList::iterator itC = animationCurves.begin(); itC != animationCurves.end(); ++itC)
{
// Keep only newly listed curves
FCDAnimationCurve* curve = *itC;
FCDAnimationCurveList::iterator itF = std::find(curves.begin(), curves.end(), curve);
if (itF == curves.end()) continue;
curve->RegisterAnimationClip(this);
curves.push_back(curve);
}
}
// Check for an empty clip
if (curves.empty())
{
status.Warning(FS("Empty animation clip :") + TO_FSTRING(GetDaeId()), clipNode->line);
}
return status;
}
// Write out the COLLADA animations to the document
xmlNode* FCDAnimationClip::WriteToXML(xmlNode* parentNode) const
{
// Create the <clip> element and write out its start/end information.
xmlNode* clipNode = FCDEntity::WriteToEntityXML(parentNode, DAE_ANIMCLIP_ELEMENT);
AddAttribute(clipNode, DAE_START_ATTRIBUTE, start);
AddAttribute(clipNode, DAE_END_ATTRIBUTE, end);
// Build a list of the animations to instantiate
// from the list of curves for this clip
typedef vector<const FCDAnimation*> FCDAnimationConstList;
FCDAnimationConstList animations;
for (FCDAnimationCurveList::const_iterator itC = curves.begin(); itC != curves.end(); ++itC)
{
const FCDAnimationChannel* channel = (*itC)->GetParent();
if (channel == NULL) continue;
const FCDAnimation* animation = channel->GetParent();
if (std::find(animations.begin(), animations.end(), animation) == animations.end())
{
animations.push_back(animation);
}
}
// Instantiate all the animations
for (FCDAnimationConstList::iterator itA = animations.begin(); itA != animations.end(); ++itA)
{
xmlNode* instanceNode = AddChild(clipNode, DAE_INSTANCE_ANIMATION_ELEMENT);
AddAttribute(instanceNode, DAE_URL_ATTRIBUTE, string("#") + (*itA)->GetDaeId());
}
FCDEntity::WriteToExtraXML(clipNode);
return clipNode;
}