Prechádzať zdrojové kódy

- fbx: initial code to read animations plus the accompanying DOM classes.

Alexander Gessler 13 rokov pred
rodič
commit
67c55990cd

+ 1 - 0
code/CMakeLists.txt

@@ -414,6 +414,7 @@ SET(FBX_SRCS
 	FBXMeshGeometry.cpp
 	FBXMaterial.cpp
 	FBXModel.cpp
+	FBXAnimation.cpp
 )
 SOURCE_GROUP( FBX FILES ${FBX_SRCS})
 

+ 216 - 0
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<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

+ 58 - 0
code/FBXDocument.cpp

@@ -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

+ 145 - 3
code/FBXDocument.h

@@ -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;
 };
 
 }

+ 3 - 0
code/FBXDocumentUtil.h

@@ -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);
 

+ 4 - 0
workspaces/vc9/assimp.vcproj

@@ -2055,6 +2055,10 @@
 				<Filter
 					Name="fbx"
 					>
+					<File
+						RelativePath="..\..\code\FBXAnimation.cpp"
+						>
+					</File>
 					<File
 						RelativePath="..\..\code\FBXCompileConfig.h"
 						>