From 67c55990cdf3ffaeb9b0b4121dfb95be6f104012 Mon Sep 17 00:00:00 2001 From: Alexander Gessler Date: Sat, 21 Jul 2012 00:45:37 +0200 Subject: [PATCH] - fbx: initial code to read animations plus the accompanying DOM classes. --- code/CMakeLists.txt | 1 + code/FBXAnimation.cpp | 216 +++++++++++++++++++++++++++++++++++ code/FBXDocument.cpp | 58 ++++++++++ code/FBXDocument.h | 148 +++++++++++++++++++++++- code/FBXDocumentUtil.h | 3 + workspaces/vc9/assimp.vcproj | 4 + 6 files changed, 427 insertions(+), 3 deletions(-) create mode 100644 code/FBXAnimation.cpp diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index 6e6b8cb15..9f5847c01 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -414,6 +414,7 @@ SET(FBX_SRCS FBXMeshGeometry.cpp FBXMaterial.cpp FBXModel.cpp + FBXAnimation.cpp ) SOURCE_GROUP( FBX FILES ${FBX_SRCS}) diff --git a/code/FBXAnimation.cpp b/code/FBXAnimation.cpp new file mode 100644 index 000000000..94aa3b3db --- /dev/null +++ b/code/FBXAnimation.cpp @@ -0,0 +1,216 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2012, assimp team +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the +following conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +---------------------------------------------------------------------- +*/ + +/** @file FBXAnimation.cpp + * @brief Assimp::FBX::AnimationCurve, Assimp::FBX::AnimationCurveNode, + * Assimp::FBX::AnimationLayer, Assimp::FBX::AnimationStack + */ +#include "AssimpPCH.h" + +#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER + +#include "FBXParser.h" +#include "FBXDocument.h" +#include "FBXImporter.h" +#include "FBXImportSettings.h" +#include "FBXDocumentUtil.h" +#include "FBXProperties.h" + +namespace Assimp { +namespace FBX { + + using namespace Util; + +// ------------------------------------------------------------------------------------------------ +AnimationCurve::AnimationCurve(uint64_t id, const Element& element, const std::string& name, const Document& doc) +: Object(id, element, name) +{ + const Scope& sc = GetRequiredScope(element); + const Element& KeyTime = GetRequiredElement(sc,"KeyTime"); + const Element& KeyValueFloat = GetRequiredElement(sc,"KeyValueFloat"); + + ReadVectorDataArray(keys, KeyTime); + ReadVectorDataArray(values, KeyValueFloat); + + if(keys.size() != values.size()) { + DOMError("the number of key times does not match the number of keyframe values",&KeyTime); + } + + + const Element* KeyAttrDataFloat = sc["KeyAttrDataFloat"]; + if(KeyAttrDataFloat) { + ReadVectorDataArray(attributes, *KeyAttrDataFloat); + } + + const Element* KeyAttrFlags = sc["KeyAttrFlags"]; + if(KeyAttrFlags) { + flags = ParseTokenAsInt(GetRequiredToken(*KeyAttrFlags,0)); + } +} + + +// ------------------------------------------------------------------------------------------------ +AnimationCurve::~AnimationCurve() +{ + +} + + +// ------------------------------------------------------------------------------------------------ +AnimationCurveNode::AnimationCurveNode(uint64_t id, const Element& element, const std::string& name, const Document& doc) +: Object(id, element, name) +{ + // resolve attached animation curves + const std::vector& conns = doc.GetConnectionsByDestinationSequenced(ID()); + + BOOST_FOREACH(const Connection* con, conns) { + + // link should go for a property + if (con->PropertyName().length()) { + continue; + } + + const Object* const ob = con->SourceObject(); + if(!ob) { + DOMWarning("failed to read source object for AnimationCurve->AnimationCurveNode link, ignoring",&element); + continue; + } + + const AnimationCurve* const anim = dynamic_cast(ob); + if(!anim) { + DOMWarning("source object for ->AnimationCurveNode link is not an AnimationCurve",&element); + continue; + } + curves[con->PropertyName()] = anim; + } +} + + +// ------------------------------------------------------------------------------------------------ +AnimationCurveNode::~AnimationCurveNode() +{ + +} + + +// ------------------------------------------------------------------------------------------------ +AnimationLayer::AnimationLayer(uint64_t id, const Element& element, const std::string& name, const Document& doc) +: Object(id, element, name) +{ + const Scope& sc = GetRequiredScope(element); + props = GetPropertyTable(doc,"AnimationLayer.FbxAnimLayer",element,sc); + + // resolve attached animation nodes + const std::vector& conns = doc.GetConnectionsByDestinationSequenced(ID()); + nodes.reserve(conns.size()); + + BOOST_FOREACH(const Connection* con, conns) { + + // link should not go to a property + if (con->PropertyName().length()) { + continue; + } + + const Object* const ob = con->SourceObject(); + if(!ob) { + DOMWarning("failed to read source object for AnimationCurveNode->AnimationLayer link, ignoring",&element); + continue; + } + + const AnimationCurveNode* const anim = dynamic_cast(ob); + if(!anim) { + DOMWarning("source object for ->AnimationLayer link is not an AnimationCurveNode",&element); + continue; + } + nodes.push_back(anim); + } +} + + +// ------------------------------------------------------------------------------------------------ +AnimationLayer::~AnimationLayer() +{ + +} + +// ------------------------------------------------------------------------------------------------ +AnimationStack::AnimationStack(uint64_t id, const Element& element, const std::string& name, const Document& doc) +: Object(id, element, name) +{ + const Scope& sc = GetRequiredScope(element); + props = GetPropertyTable(doc,"AnimationStack.FbxAnimStack",element,sc); + + // resolve attached animation layers + const std::vector& conns = doc.GetConnectionsByDestinationSequenced(ID()); + layers.reserve(conns.size()); + + BOOST_FOREACH(const Connection* con, conns) { + + // link should not go to a property + if (con->PropertyName().length()) { + continue; + } + + const Object* const ob = con->SourceObject(); + if(!ob) { + DOMWarning("failed to read source object for AnimationLayer->AnimationStack link, ignoring",&element); + continue; + } + + const AnimationLayer* const anim = dynamic_cast(ob); + if(!anim) { + DOMWarning("source object for ->AnimationStack link is not an AnimationLayer",&element); + continue; + } + layers.push_back(anim); + } +} + + +// ------------------------------------------------------------------------------------------------ +AnimationStack::~AnimationStack() +{ + +} + +} //!FBX +} //!Assimp + +#endif diff --git a/code/FBXDocument.cpp b/code/FBXDocument.cpp index 98bb7ebe1..80deab66d 100644 --- a/code/FBXDocument.cpp +++ b/code/FBXDocument.cpp @@ -307,6 +307,27 @@ void ReadVectorDataArray(std::vector& out, const Element& el) } +// ------------------------------------------------------------------------------------------------ +// read an array of floats +void ReadVectorDataArray(std::vector& out, const Element& el) +{ + out.clear(); + const TokenList& tok = el.Tokens(); + const size_t dim = ParseTokenAsDim(*tok[0]); + + // see notes in ReadVectorDataArray() + out.reserve(dim); + + const Scope& scope = GetRequiredScope(el); + const Element& a = GetRequiredElement(scope,"a",&el); + + for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) { + const float ival = ParseTokenAsFloat(**it++); + out.push_back(ival); + } +} + + // ------------------------------------------------------------------------------------------------ // read an array of uints void ReadVectorDataArray(std::vector& out, const Element& el) @@ -424,6 +445,18 @@ const Object* LazyObject::Get() else if (!strncmp(obtype,"Texture",length)) { object.reset(new Texture(id,element,doc,name)); } + else if (!strncmp(obtype,"AnimationStack",length)) { + object.reset(new AnimationStack(id,element,name,doc)); + } + else if (!strncmp(obtype,"AnimationLayer",length)) { + object.reset(new AnimationLayer(id,element,name,doc)); + } + else if (!strncmp(obtype,"AnimationCurveNode",length)) { + object.reset(new AnimationCurveNode(id,element,name,doc)); + } + else if (!strncmp(obtype,"AnimationCurve",length)) { + object.reset(new AnimationCurve(id,element,name,doc)); + } if (!object.get()) { //DOMError("failed to convert element to DOM object, class: " + classtag + ", name: " + name,&element); @@ -553,6 +586,11 @@ void Document::ReadObjects() } objects[id] = new LazyObject(id, *el.second, *this); + + // grab all animation stacks upfront since there is no listing of them + if(el.first == "AnimationStack") { + animationStacks.push_back(id); + } } } @@ -659,6 +697,26 @@ void Document::ReadConnections() } } +// ------------------------------------------------------------------------------------------------ +const std::vector& Document::AnimationStacks() const +{ + if (animationStacksResolved.empty() && animationStacks.size()) { + return animationStacksResolved; + } + + animationStacksResolved.reserve(animationStacks.size()); + BOOST_FOREACH(uint64_t id, animationStacks) { + LazyObject* const lazy = GetObject(id); + const AnimationStack* stack; + if(!lazy || !(stack = lazy->Get())) { + DOMWarning("failed to read AnimationStack object"); + continue; + } + animationStacksResolved.push_back(stack); + } + + return animationStacksResolved; +} // ------------------------------------------------------------------------------------------------ LazyObject* Document::GetObject(uint64_t id) const diff --git a/code/FBXDocument.h b/code/FBXDocument.h index 54005fd3a..f83c21c98 100644 --- a/code/FBXDocument.h +++ b/code/FBXDocument.h @@ -76,9 +76,9 @@ public: const Object* Get(); template - T* Get() { + const T* Get() { const Object* const ob = Get(); - return ob ? dynamic_cast(ob) : NULL; + return ob ? dynamic_cast(ob) : NULL; } uint64_t ID() const { @@ -125,7 +125,7 @@ protected: }; -/** DOM base class for FBX models */ +/** DOM base class for FBX models (even though its semantics are more "node" than "model" */ class Model : public Object { public: @@ -404,6 +404,144 @@ private: }; + +/** Represents a FBX animation curve (i.e. a 1-dimensional set of keyframes and values therefor) */ +class AnimationCurve : public Object +{ +public: + + AnimationCurve(uint64_t id, const Element& element, const std::string& name, const Document& doc); + ~AnimationCurve(); + +public: + + /** get list of keyframe positions (time). + * Invariant: |GetKeys()| > 0 */ + const std::vector& GetKeys() const { + return keys; + } + + + /** get list of keyframe values. + * Invariant: |GetKeys()| == |GetValues()| && |GetKeys()| > 0*/ + const std::vector& GetValues() const { + return values; + } + + + const std::vector& GetAttributes() const { + return attributes; + } + + unsigned int GetFlags() const { + return flags; + } + +private: + + std::vector keys; + std::vector values; + std::vector attributes; + unsigned int flags; +}; + +// property-name -> animation curve +typedef std::map AnimationCurveMap; + + +/** Represents a FBX animation curve (i.e. a mapping from single animation curves to nodes) */ +class AnimationCurveNode : public Object +{ +public: + + AnimationCurveNode(uint64_t id, const Element& element, const std::string& name, const Document& doc); + ~AnimationCurveNode(); + +public: + + const PropertyTable& Props() const { + ai_assert(props.get()); + return *props.get(); + } + + + const AnimationCurveMap Curves() const { + return curves; + } + + + const Model* TargetNode() const { + return target; + } + +private: + + const Model* target; + boost::shared_ptr props; + AnimationCurveMap curves; +}; + +typedef std::vector AnimationCurveNodeList; + + +/** Represents a FBX animation layer (i.e. a list of node animations) */ +class AnimationLayer : public Object +{ +public: + + AnimationLayer(uint64_t id, const Element& element, const std::string& name, const Document& doc); + ~AnimationLayer(); + +public: + + const PropertyTable& Props() const { + ai_assert(props.get()); + return *props.get(); + } + + const AnimationCurveNodeList& Nodes() const { + return nodes; + } + +private: + + boost::shared_ptr props; + AnimationCurveNodeList nodes; +}; + + +typedef std::vector AnimationLayerList; + + +/** Represents a FBX animation stack (i.e. a list of animation layers) */ +class AnimationStack : public Object +{ +public: + + AnimationStack(uint64_t id, const Element& element, const std::string& name, const Document& doc); + ~AnimationStack(); + +public: + + const PropertyTable& Props() const { + ai_assert(props.get()); + return *props.get(); + } + + + const AnimationLayerList& Layers() const { + return layers; + } + +private: + + boost::shared_ptr props; + AnimationLayerList layers; +}; + + + + /** Represents a link between two FBX objects. */ class Connection { @@ -514,6 +652,8 @@ public: std::vector GetConnectionsBySourceSequenced(uint64_t source) const; std::vector GetConnectionsByDestinationSequenced(uint64_t dest) const; + const std::vector& AnimationStacks() const; + private: void ReadHeader(); @@ -536,6 +676,8 @@ private: std::string creator; unsigned int creationTimeStamp[7]; + std::vector animationStacks; + mutable std::vector animationStacksResolved; }; } diff --git a/code/FBXDocumentUtil.h b/code/FBXDocumentUtil.h index f1656944a..4e0975e0a 100644 --- a/code/FBXDocumentUtil.h +++ b/code/FBXDocumentUtil.h @@ -88,6 +88,9 @@ void ReadVectorDataArray(std::vector& out, const Element& el); // read an array of ints void ReadVectorDataArray(std::vector& out, const Element& el); +// read an array of floats +void ReadVectorDataArray(std::vector& out, const Element& el); + // read an array of uints void ReadVectorDataArray(std::vector& out, const Element& el); diff --git a/workspaces/vc9/assimp.vcproj b/workspaces/vc9/assimp.vcproj index 8df1ee8f2..1e6e03d5c 100644 --- a/workspaces/vc9/assimp.vcproj +++ b/workspaces/vc9/assimp.vcproj @@ -2055,6 +2055,10 @@ + +