- fbx: initial code to read animations plus the accompanying DOM classes.
parent
ab93c6f38e
commit
67c55990cd
|
@ -414,6 +414,7 @@ SET(FBX_SRCS
|
|||
FBXMeshGeometry.cpp
|
||||
FBXMaterial.cpp
|
||||
FBXModel.cpp
|
||||
FBXAnimation.cpp
|
||||
)
|
||||
SOURCE_GROUP( FBX FILES ${FBX_SRCS})
|
||||
|
||||
|
|
|
@ -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<const Connection*>& 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<const AnimationCurve*>(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<const Connection*>& 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<const AnimationCurveNode*>(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<const Connection*>& 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<const AnimationLayer*>(ob);
|
||||
if(!anim) {
|
||||
DOMWarning("source object for ->AnimationStack link is not an AnimationLayer",&element);
|
||||
continue;
|
||||
}
|
||||
layers.push_back(anim);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AnimationStack::~AnimationStack()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
} //!FBX
|
||||
} //!Assimp
|
||||
|
||||
#endif
|
|
@ -307,6 +307,27 @@ void ReadVectorDataArray(std::vector<int>& out, const Element& el)
|
|||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// read an array of floats
|
||||
void ReadVectorDataArray(std::vector<float>& 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<unsigned int>& 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<const AnimationStack*>& 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<AnimationStack>())) {
|
||||
DOMWarning("failed to read AnimationStack object");
|
||||
continue;
|
||||
}
|
||||
animationStacksResolved.push_back(stack);
|
||||
}
|
||||
|
||||
return animationStacksResolved;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
LazyObject* Document::GetObject(uint64_t id) const
|
||||
|
|
|
@ -76,9 +76,9 @@ public:
|
|||
const Object* Get();
|
||||
|
||||
template <typename T>
|
||||
T* Get() {
|
||||
const T* Get() {
|
||||
const Object* const ob = Get();
|
||||
return ob ? dynamic_cast<T*>(ob) : NULL;
|
||||
return ob ? dynamic_cast<const T*>(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<float>& GetKeys() const {
|
||||
return keys;
|
||||
}
|
||||
|
||||
|
||||
/** get list of keyframe values.
|
||||
* Invariant: |GetKeys()| == |GetValues()| && |GetKeys()| > 0*/
|
||||
const std::vector<float>& GetValues() const {
|
||||
return values;
|
||||
}
|
||||
|
||||
|
||||
const std::vector<float>& GetAttributes() const {
|
||||
return attributes;
|
||||
}
|
||||
|
||||
unsigned int GetFlags() const {
|
||||
return flags;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
std::vector<float> keys;
|
||||
std::vector<float> values;
|
||||
std::vector<float> attributes;
|
||||
unsigned int flags;
|
||||
};
|
||||
|
||||
// property-name -> animation curve
|
||||
typedef std::map<std::string, const AnimationCurve*> 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<const PropertyTable> props;
|
||||
AnimationCurveMap curves;
|
||||
};
|
||||
|
||||
typedef std::vector<const AnimationCurveNode*> 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<const PropertyTable> props;
|
||||
AnimationCurveNodeList nodes;
|
||||
};
|
||||
|
||||
|
||||
typedef std::vector<const AnimationLayer*> 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<const PropertyTable> props;
|
||||
AnimationLayerList layers;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/** Represents a link between two FBX objects. */
|
||||
class Connection
|
||||
{
|
||||
|
@ -514,6 +652,8 @@ public:
|
|||
std::vector<const Connection*> GetConnectionsBySourceSequenced(uint64_t source) const;
|
||||
std::vector<const Connection*> GetConnectionsByDestinationSequenced(uint64_t dest) const;
|
||||
|
||||
const std::vector<const AnimationStack*>& AnimationStacks() const;
|
||||
|
||||
private:
|
||||
|
||||
void ReadHeader();
|
||||
|
@ -536,6 +676,8 @@ private:
|
|||
std::string creator;
|
||||
unsigned int creationTimeStamp[7];
|
||||
|
||||
std::vector<uint64_t> animationStacks;
|
||||
mutable std::vector<const AnimationStack*> animationStacksResolved;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -88,6 +88,9 @@ void ReadVectorDataArray(std::vector<aiVector2D>& out, const Element& el);
|
|||
// read an array of ints
|
||||
void ReadVectorDataArray(std::vector<int>& out, const Element& el);
|
||||
|
||||
// read an array of floats
|
||||
void ReadVectorDataArray(std::vector<float>& out, const Element& el);
|
||||
|
||||
// read an array of uints
|
||||
void ReadVectorDataArray(std::vector<unsigned int>& out, const Element& el);
|
||||
|
||||
|
|
|
@ -2055,6 +2055,10 @@
|
|||
<Filter
|
||||
Name="fbx"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\code\FBXAnimation.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\code\FBXCompileConfig.h"
|
||||
>
|
||||
|
|
Loading…
Reference in New Issue