瀏覽代碼

- fbx: refactor parsing code, move all parsing stuff to FBXParser.cpp. Parsing errors now carry the prefix "FBX-Parser".

Alexander Gessler 13 年之前
父節點
當前提交
315285faf0
共有 7 個文件被更改,包括 411 次插入385 次删除
  1. 4 4
      code/FBXAnimation.cpp
  2. 2 2
      code/FBXDeformer.cpp
  3. 0 318
      code/FBXDocumentUtil.cpp
  4. 2 48
      code/FBXDocumentUtil.h
  5. 6 6
      code/FBXMeshGeometry.cpp
  6. 365 7
      code/FBXParser.cpp
  7. 32 0
      code/FBXParser.h

+ 4 - 4
code/FBXAnimation.cpp

@@ -66,8 +66,8 @@ AnimationCurve::AnimationCurve(uint64_t id, const Element& element, const std::s
 	const Element& KeyTime = GetRequiredElement(sc,"KeyTime");
 	const Element& KeyValueFloat = GetRequiredElement(sc,"KeyValueFloat");
 
-	ReadVectorDataArray(keys, KeyTime);
-	ReadVectorDataArray(values, KeyValueFloat);
+	ParseVectorDataArray(keys, KeyTime);
+	ParseVectorDataArray(values, KeyValueFloat);
 
 	if(keys.size() != values.size()) {
 		DOMError("the number of key times does not match the number of keyframe values",&KeyTime);
@@ -80,12 +80,12 @@ AnimationCurve::AnimationCurve(uint64_t id, const Element& element, const std::s
 
 	const Element* KeyAttrDataFloat = sc["KeyAttrDataFloat"];
 	if(KeyAttrDataFloat) {
-		ReadVectorDataArray(attributes, *KeyAttrDataFloat);
+		ParseVectorDataArray(attributes, *KeyAttrDataFloat);
 	}
 
 	const Element* KeyAttrFlags = sc["KeyAttrFlags"];
 	if(KeyAttrFlags) {
-		ReadVectorDataArray(flags, *KeyAttrFlags);
+		ParseVectorDataArray(flags, *KeyAttrFlags);
 	}
 }
 

+ 2 - 2
code/FBXDeformer.cpp

@@ -97,8 +97,8 @@ Cluster::Cluster(uint64_t id, const Element& element, const Document& doc, const
 	}
 
 	if(Indexes) {
-		ReadVectorDataArray(indices,*Indexes);
-		ReadVectorDataArray(weights,*Weights);
+		ParseVectorDataArray(indices,*Indexes);
+		ParseVectorDataArray(weights,*Weights);
 	}
 
 	if(indices.size() != weights.size()) {

+ 0 - 318
code/FBXDocumentUtil.cpp

@@ -45,8 +45,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #ifndef ASSIMP_BUILD_NO_FBX_IMPORTER
 
-#include <functional>
-
 #include "FBXParser.h"
 #include "FBXDocument.h"
 #include "FBXUtil.h"
@@ -96,322 +94,6 @@ void DOMWarning(const std::string& message, const Element* element /*= NULL*/)
 }
 
 
-// ------------------------------------------------------------------------------------------------
-// extract required compound scope
-const Scope& GetRequiredScope(const Element& el)
-{
-	const Scope* const s = el.Compound();
-	if(!s) {
-		DOMError("expected compound scope",&el);
-	}
-
-	return *s;
-}
-
-
-// ------------------------------------------------------------------------------------------------
-// get token at a particular index
-const Token& GetRequiredToken(const Element& el, unsigned int index)
-{
-	const TokenList& t = el.Tokens();
-	if(index >= t.size()) {
-		DOMError(Formatter::format( "missing token at index " ) << index,&el);
-	}
-
-	return *t[index];
-}
-
-
-// ------------------------------------------------------------------------------------------------
-// wrapper around ParseTokenAsID() with DOMError handling
-uint64_t ParseTokenAsID(const Token& t) 
-{
-	const char* err;
-	const uint64_t i = ParseTokenAsID(t,err);
-	if(err) {
-		DOMError(err,t);
-	}
-	return i;
-}
-
-
-// ------------------------------------------------------------------------------------------------
-// wrapper around ParseTokenAsDim() with DOMError handling
-size_t ParseTokenAsDim(const Token& t)
-{
-	const char* err;
-	const size_t i = ParseTokenAsDim(t,err);
-	if(err) {
-		DOMError(err,t);
-	}
-	return i;
-}
-
-
-// ------------------------------------------------------------------------------------------------
-// wrapper around ParseTokenAsFloat() with DOMError handling
-float ParseTokenAsFloat(const Token& t)
-{
-	const char* err;
-	const float i = ParseTokenAsFloat(t,err);
-	if(err) {
-		DOMError(err,t);
-	}
-	return i;
-}
-
-
-// ------------------------------------------------------------------------------------------------
-// wrapper around ParseTokenAsInt() with DOMError handling
-int ParseTokenAsInt(const Token& t)
-{
-	const char* err;
-	const int i = ParseTokenAsInt(t,err);
-	if(err) {
-		DOMError(err,t);
-	}
-	return i;
-}
-
-
-// ------------------------------------------------------------------------------------------------
-// wrapper around ParseTokenAsString() with DOMError handling
-std::string ParseTokenAsString(const Token& t)
-{
-	const char* err;
-	const std::string& i = ParseTokenAsString(t,err);
-	if(err) {
-		DOMError(err,t);
-	}
-	return i;
-}
-
-// ------------------------------------------------------------------------------------------------
-// extract a required element from a scope, abort if the element cannot be found
-const Element& GetRequiredElement(const Scope& sc, const std::string& index, const Element* element /*= NULL*/) 
-{
-	const Element* el = sc[index];
-	if(!el) {
-		DOMError("did not find required element \"" + index + "\"",element);
-	}
-	return *el;
-}
-
-// XXX: tacke code duplication in the various ReadVectorDataArray() overloads below.
-// could use a type traits based solution.
-
-// ------------------------------------------------------------------------------------------------
-// read an array of float3 tuples
-void ReadVectorDataArray(std::vector<aiVector3D>& out, const Element& el)
-{
-	out.clear();
-	const TokenList& tok = el.Tokens();
-	const size_t dim = ParseTokenAsDim(*tok[0]);
-
-	// may throw bad_alloc if the input is rubbish, but this need
-	// not to be prevented - importing would fail but we wouldn't
-	// crash since assimp handles this case properly.
-	out.reserve(dim);
-
-	const Scope& scope = GetRequiredScope(el);
-	const Element& a = GetRequiredElement(scope,"a",&el);
-
-	if (a.Tokens().size() % 3 != 0) {
-		DOMError("number of floats is not a multiple of three (3)",&el);
-	}
-	for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) {
-		aiVector3D v;
-		v.x = ParseTokenAsFloat(**it++);
-		v.y = ParseTokenAsFloat(**it++);
-		v.z = ParseTokenAsFloat(**it++);
-
-		out.push_back(v);
-	}
-}
-
-
-// ------------------------------------------------------------------------------------------------
-// read an array of color4 tuples
-void ReadVectorDataArray(std::vector<aiColor4D>& out, const Element& el)
-{
-	out.clear();
-	const TokenList& tok = el.Tokens();
-	const size_t dim = ParseTokenAsDim(*tok[0]);
-
-	//  see notes in ReadVectorDataArray() above
-	out.reserve(dim);
-
-	const Scope& scope = GetRequiredScope(el);
-	const Element& a = GetRequiredElement(scope,"a",&el);
-
-	if (a.Tokens().size() % 4 != 0) {
-		DOMError("number of floats is not a multiple of four (4)",&el);
-	}
-	for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) {
-		aiColor4D v;
-		v.r = ParseTokenAsFloat(**it++);
-		v.g = ParseTokenAsFloat(**it++);
-		v.b = ParseTokenAsFloat(**it++);
-		v.a = ParseTokenAsFloat(**it++);
-
-		out.push_back(v);
-	}
-}
-
-
-// ------------------------------------------------------------------------------------------------
-// read an array of float2 tuples
-void ReadVectorDataArray(std::vector<aiVector2D>& out, const Element& el)
-{
-	out.clear();
-	const TokenList& tok = el.Tokens();
-	const size_t dim = ParseTokenAsDim(*tok[0]);
-
-	// see notes in ReadVectorDataArray() above
-	out.reserve(dim);
-
-	const Scope& scope = GetRequiredScope(el);
-	const Element& a = GetRequiredElement(scope,"a",&el);
-
-	if (a.Tokens().size() % 2 != 0) {
-		DOMError("number of floats is not a multiple of two (2)",&el);
-	}
-	for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) {
-		aiVector2D v;
-		v.x = ParseTokenAsFloat(**it++);
-		v.y = ParseTokenAsFloat(**it++);
-
-		out.push_back(v);
-	}
-}
-
-
-// ------------------------------------------------------------------------------------------------
-// read an array of ints
-void ReadVectorDataArray(std::vector<int>& 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 int ival = ParseTokenAsInt(**it++);
-		out.push_back(ival);
-	}
-}
-
-
-// ------------------------------------------------------------------------------------------------
-// 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)
-{
-	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 int ival = ParseTokenAsInt(**it++);
-		if(ival < 0) {
-			DOMError("encountered negative integer index");
-		}
-		out.push_back(static_cast<unsigned int>(ival));
-	}
-}
-
-
-// ------------------------------------------------------------------------------------------------
-// read an array of uint64_ts
-void ReadVectorDataArray(std::vector<uint64_t>& 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 uint64_t ival = ParseTokenAsID(**it++);
-		
-		out.push_back(ival);
-	}
-}
-
-
-// ------------------------------------------------------------------------------------------------
-aiMatrix4x4 ReadMatrix(const Element& element)
-{
-	std::vector<float> values;
-	ReadVectorDataArray(values,element);
-
-	if(values.size() != 16) {
-		DOMError("expected 16 matrix elements");
-	}
-
-	aiMatrix4x4 result;
-
-
-	result.a1 = values[0];
-	result.a2 = values[1];
-	result.a3 = values[2];
-	result.a4 = values[3];
-
-	result.b1 = values[4];
-	result.b2 = values[5];
-	result.b3 = values[6];
-	result.b4 = values[7];
-
-	result.c1 = values[8];
-	result.c2 = values[9];
-	result.c3 = values[10];
-	result.c4 = values[11];
-
-	result.d1 = values[12];
-	result.d2 = values[13];
-	result.d3 = values[14];
-	result.d4 = values[15];
-
-	result.Transpose();
-	return result;
-}
-
-
 // ------------------------------------------------------------------------------------------------
 // fetch a property table and the corresponding property template 
 boost::shared_ptr<const PropertyTable> GetPropertyTable(const Document& doc, 

+ 2 - 48
code/FBXDocumentUtil.h

@@ -48,7 +48,8 @@ namespace Assimp {
 namespace FBX {
 namespace Util {
 
-// does not return
+
+/* DOM/Parse error reporting - does not return */
 void DOMError(const std::string& message, const Token& token);
 void DOMError(const std::string& message, const Element* element = NULL);
 
@@ -56,51 +57,6 @@ void DOMError(const std::string& message, const Element* element = NULL);
 void DOMWarning(const std::string& message, const Token& token);
 void DOMWarning(const std::string& message, const Element* element = NULL);
 
-// extract required compound scope
-const Scope& GetRequiredScope(const Element& el);
-// get token at a particular index
-const Token& GetRequiredToken(const Element& el, unsigned int index);
-
-// wrapper around ParseTokenAsID() with DOMError handling
-uint64_t ParseTokenAsID(const Token& t);
-// wrapper around ParseTokenAsDim() with DOMError handling
-size_t ParseTokenAsDim(const Token& t);
-// wrapper around ParseTokenAsFloat() with DOMError handling
-float ParseTokenAsFloat(const Token& t);
-// wrapper around ParseTokenAsInt() with DOMError handling
-int ParseTokenAsInt(const Token& t);
-// wrapper around ParseTokenAsString() with DOMError handling
-std::string ParseTokenAsString(const Token& t);
-
-
-// extract a required element from a scope, abort if the element cannot be found
-const Element& GetRequiredElement(const Scope& sc, const std::string& index, const Element* element = NULL);
-
-// read an array of float3 tuples
-void ReadVectorDataArray(std::vector<aiVector3D>& out, const Element& el);
-
-// read an array of color4 tuples
-void ReadVectorDataArray(std::vector<aiColor4D>& out, const Element& el);
-
-// read an array of float2 tuples
-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);
-
-// read an array of uint64_t's
-void ReadVectorDataArray(std::vector<uint64_t>& out, const Element& el);
-
-
-// read a 4x4 matrix from an array of 16 floats
-aiMatrix4x4 ReadMatrix(const Element& element);
-
 
 // fetch a property table and the corresponding property template 
 boost::shared_ptr<const PropertyTable> GetPropertyTable(const Document& doc, 
@@ -109,8 +65,6 @@ boost::shared_ptr<const PropertyTable> GetPropertyTable(const Document& doc,
 	const Scope& sc);
 
 
-
-
 // ------------------------------------------------------------------------------------------------
 template <typename T>
 inline const T* ProcessSimpleConnection(const Connection& con, 

+ 6 - 6
code/FBXMeshGeometry.cpp

@@ -99,7 +99,7 @@ MeshGeometry::MeshGeometry(uint64_t id, const Element& element, const std::strin
 	const ElementCollection& Layer = sc->GetCollection("Layer");
 
 	std::vector<aiVector3D> tempVerts;
-	ReadVectorDataArray(tempVerts,Vertices);
+	ParseVectorDataArray(tempVerts,Vertices);
 
 	if(tempVerts.empty()) {
 		FBXImporter::LogWarn("encountered mesh with no vertices");
@@ -107,7 +107,7 @@ MeshGeometry::MeshGeometry(uint64_t id, const Element& element, const std::strin
 	}
 
 	std::vector<int> tempFaces;
-	ReadVectorDataArray(tempFaces,PolygonVertexIndex);
+	ParseVectorDataArray(tempFaces,PolygonVertexIndex);
 
 	if(tempFaces.empty()) {
 		FBXImporter::LogWarn("encountered mesh with no faces");
@@ -346,7 +346,7 @@ void ResolveVertexDataArray(std::vector<T>& data_out, const Scope& source,
 	const std::vector<unsigned int>& mappings)
 {
 	std::vector<T> tempUV;
-	ReadVectorDataArray(tempUV,GetRequiredElement(source,dataElementName));
+	ParseVectorDataArray(tempUV,GetRequiredElement(source,dataElementName));
 
 	// handle permutations of Mapping and Reference type - it would be nice to
 	// deal with this more elegantly and with less redundancy, but right
@@ -365,7 +365,7 @@ void ResolveVertexDataArray(std::vector<T>& data_out, const Scope& source,
 		data_out.resize(vertex_count);
 
 		std::vector<int> uvIndices;
-		ReadVectorDataArray(uvIndices,GetRequiredElement(source,indexDataElementName));
+		ParseVectorDataArray(uvIndices,GetRequiredElement(source,indexDataElementName));
 
 		for (size_t i = 0, e = uvIndices.size(); i < e; ++i) {
 
@@ -392,7 +392,7 @@ void ResolveVertexDataArray(std::vector<T>& data_out, const Scope& source,
 		data_out.resize(vertex_count);
 
 		std::vector<int> uvIndices;
-		ReadVectorDataArray(uvIndices,GetRequiredElement(source,indexDataElementName));
+		ParseVectorDataArray(uvIndices,GetRequiredElement(source,indexDataElementName));
 
 		if (uvIndices.size() != vertex_count) {
 			FBXImporter::LogError("length of input data unexpected for ByPolygonVertex mapping");
@@ -500,7 +500,7 @@ void MeshGeometry::ReadVertexDataMaterials(std::vector<int>& materials_out, cons
 	// materials are handled separately. First of all, they are assigned per-face
 	// and not per polyvert. Secondly, ReferenceInformationType=IndexToDirect
 	// has a slightly different meaning for materials.
-	ReadVectorDataArray(materials_out,GetRequiredElement(source,"Materials"));
+	ParseVectorDataArray(materials_out,GetRequiredElement(source,"Materials"));
 
 	if (MappingInformationType == "AllSame") {
 		// easy - same material for all faces

+ 365 - 7
code/FBXParser.cpp

@@ -57,12 +57,53 @@ using namespace Assimp::FBX;
 
 namespace {
 
-// ------------------------------------------------------------------------------------------------
-// signal parsing error, this is always unrecoverable. Throws DeadlyImportError.
-void ParseError(const std::string& message, TokenPtr token)
-{
-	throw DeadlyImportError(token ? Util::AddTokenText("FBX-Parse",message,token) : ("FBX-Parse " + message));
-}
+
+	// ------------------------------------------------------------------------------------------------
+	// signal parse error, this is always unrecoverable. Throws DeadlyImportError.
+	void ParseError(const std::string& message, const Token& token)
+	{
+		throw DeadlyImportError(Util::AddTokenText("FBX-Parser",message,&token));
+	}
+
+	// ------------------------------------------------------------------------------------------------
+	void ParseError(const std::string& message, const Element* element = NULL)
+	{
+		if(element) {
+			ParseError(message,element->KeyToken());
+		}
+		throw DeadlyImportError("FBX-Parser " + message);
+	}
+
+
+	// ------------------------------------------------------------------------------------------------
+	// print warning, do return
+	void ParseWarning(const std::string& message, const Token& token)
+	{
+		if(DefaultLogger::get()) {
+			DefaultLogger::get()->warn(Util::AddTokenText("FBX-Parser",message,&token));
+		}
+	}
+
+	// ------------------------------------------------------------------------------------------------
+	void ParseWarning(const std::string& message, const Element* element = NULL)
+	{
+		if(element) {
+			ParseWarning(message,element->KeyToken());
+			return;
+		}
+		if(DefaultLogger::get()) {
+			DefaultLogger::get()->warn("FBX-Parser: " + message);
+		}
+	}
+
+	// ------------------------------------------------------------------------------------------------
+	void ParseError(const std::string& message, TokenPtr token)
+	{
+		if(token) {
+			ParseError(message, *token);
+		}
+		ParseError(message);
+	}
 
 }
 
@@ -130,7 +171,7 @@ Scope::Scope(Parser& parser,bool topLevel)
 
 	TokenPtr n = parser.AdvanceToNextToken();
 	if(n == NULL) {
-		ParseError("unexpected end of file",NULL);
+		ParseError("unexpected end of file");
 	}
 
 	// note: empty scopes are allowed
@@ -419,6 +460,323 @@ std::string ParseTokenAsString(const Token& t, const char*& err_out)
 	return std::string(s+1,length-2);
 }
 
+
+// ------------------------------------------------------------------------------------------------
+// read an array of float3 tuples
+void ParseVectorDataArray(std::vector<aiVector3D>& out, const Element& el)
+{
+	out.clear();
+	const TokenList& tok = el.Tokens();
+	const size_t dim = ParseTokenAsDim(*tok[0]);
+
+	// may throw bad_alloc if the input is rubbish, but this need
+	// not to be prevented - importing would fail but we wouldn't
+	// crash since assimp handles this case properly.
+	out.reserve(dim);
+
+	const Scope& scope = GetRequiredScope(el);
+	const Element& a = GetRequiredElement(scope,"a",&el);
+
+	if (a.Tokens().size() % 3 != 0) {
+		ParseError("number of floats is not a multiple of three (3)",&el);
+	}
+	for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) {
+		aiVector3D v;
+		v.x = ParseTokenAsFloat(**it++);
+		v.y = ParseTokenAsFloat(**it++);
+		v.z = ParseTokenAsFloat(**it++);
+
+		out.push_back(v);
+	}
+}
+
+
+// ------------------------------------------------------------------------------------------------
+// read an array of color4 tuples
+void ParseVectorDataArray(std::vector<aiColor4D>& out, const Element& el)
+{
+	out.clear();
+	const TokenList& tok = el.Tokens();
+	const size_t dim = ParseTokenAsDim(*tok[0]);
+
+	//  see notes in ParseVectorDataArray() above
+	out.reserve(dim);
+
+	const Scope& scope = GetRequiredScope(el);
+	const Element& a = GetRequiredElement(scope,"a",&el);
+
+	if (a.Tokens().size() % 4 != 0) {
+		ParseError("number of floats is not a multiple of four (4)",&el);
+	}
+	for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) {
+		aiColor4D v;
+		v.r = ParseTokenAsFloat(**it++);
+		v.g = ParseTokenAsFloat(**it++);
+		v.b = ParseTokenAsFloat(**it++);
+		v.a = ParseTokenAsFloat(**it++);
+
+		out.push_back(v);
+	}
+}
+
+
+// ------------------------------------------------------------------------------------------------
+// read an array of float2 tuples
+void ParseVectorDataArray(std::vector<aiVector2D>& out, const Element& el)
+{
+	out.clear();
+	const TokenList& tok = el.Tokens();
+	const size_t dim = ParseTokenAsDim(*tok[0]);
+
+	// see notes in ParseVectorDataArray() above
+	out.reserve(dim);
+
+	const Scope& scope = GetRequiredScope(el);
+	const Element& a = GetRequiredElement(scope,"a",&el);
+
+	if (a.Tokens().size() % 2 != 0) {
+		ParseError("number of floats is not a multiple of two (2)",&el);
+	}
+	for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) {
+		aiVector2D v;
+		v.x = ParseTokenAsFloat(**it++);
+		v.y = ParseTokenAsFloat(**it++);
+
+		out.push_back(v);
+	}
+}
+
+
+// ------------------------------------------------------------------------------------------------
+// read an array of ints
+void ParseVectorDataArray(std::vector<int>& out, const Element& el)
+{
+	out.clear();
+	const TokenList& tok = el.Tokens();
+	const size_t dim = ParseTokenAsDim(*tok[0]);
+
+	// see notes in ParseVectorDataArray()
+	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 int ival = ParseTokenAsInt(**it++);
+		out.push_back(ival);
+	}
+}
+
+
+// ------------------------------------------------------------------------------------------------
+// read an array of floats
+void ParseVectorDataArray(std::vector<float>& out, const Element& el)
+{
+	out.clear();
+	const TokenList& tok = el.Tokens();
+	const size_t dim = ParseTokenAsDim(*tok[0]);
+
+	// see notes in ParseVectorDataArray()
+	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 ParseVectorDataArray(std::vector<unsigned int>& out, const Element& el)
+{
+	out.clear();
+	const TokenList& tok = el.Tokens();
+	const size_t dim = ParseTokenAsDim(*tok[0]);
+
+	// see notes in ParseVectorDataArray()
+	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 int ival = ParseTokenAsInt(**it++);
+		if(ival < 0) {
+			ParseError("encountered negative integer index");
+		}
+		out.push_back(static_cast<unsigned int>(ival));
+	}
+}
+
+
+// ------------------------------------------------------------------------------------------------
+// read an array of uint64_ts
+void ParseVectorDataArray(std::vector<uint64_t>& out, const Element& el)
+{
+	out.clear();
+	const TokenList& tok = el.Tokens();
+	const size_t dim = ParseTokenAsDim(*tok[0]);
+
+	// see notes in ParseVectorDataArray()
+	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 uint64_t ival = ParseTokenAsID(**it++);
+		
+		out.push_back(ival);
+	}
+}
+
+
+// ------------------------------------------------------------------------------------------------
+aiMatrix4x4 ReadMatrix(const Element& element)
+{
+	std::vector<float> values;
+	ParseVectorDataArray(values,element);
+
+	if(values.size() != 16) {
+		ParseError("expected 16 matrix elements");
+	}
+
+	aiMatrix4x4 result;
+
+
+	result.a1 = values[0];
+	result.a2 = values[1];
+	result.a3 = values[2];
+	result.a4 = values[3];
+
+	result.b1 = values[4];
+	result.b2 = values[5];
+	result.b3 = values[6];
+	result.b4 = values[7];
+
+	result.c1 = values[8];
+	result.c2 = values[9];
+	result.c3 = values[10];
+	result.c4 = values[11];
+
+	result.d1 = values[12];
+	result.d2 = values[13];
+	result.d3 = values[14];
+	result.d4 = values[15];
+
+	result.Transpose();
+	return result;
+}
+
+
+// ------------------------------------------------------------------------------------------------
+// wrapper around ParseTokenAsString() with ParseError handling
+std::string ParseTokenAsString(const Token& t)
+{
+	const char* err;
+	const std::string& i = ParseTokenAsString(t,err);
+	if(err) {
+		ParseError(err,t);
+	}
+	return i;
+}
+
+
+// ------------------------------------------------------------------------------------------------
+// extract a required element from a scope, abort if the element cannot be found
+const Element& GetRequiredElement(const Scope& sc, const std::string& index, const Element* element /*= NULL*/) 
+{
+	const Element* el = sc[index];
+	if(!el) {
+		ParseError("did not find required element \"" + index + "\"",element);
+	}
+	return *el;
+}
+
+
+// ------------------------------------------------------------------------------------------------
+// extract required compound scope
+const Scope& GetRequiredScope(const Element& el)
+{
+	const Scope* const s = el.Compound();
+	if(!s) {
+		ParseError("expected compound scope",&el);
+	}
+
+	return *s;
+}
+
+
+// ------------------------------------------------------------------------------------------------
+// get token at a particular index
+const Token& GetRequiredToken(const Element& el, unsigned int index)
+{
+	const TokenList& t = el.Tokens();
+	if(index >= t.size()) {
+		ParseError(Formatter::format( "missing token at index " ) << index,&el);
+	}
+
+	return *t[index];
+}
+
+
+// ------------------------------------------------------------------------------------------------
+// wrapper around ParseTokenAsID() with ParseError handling
+uint64_t ParseTokenAsID(const Token& t) 
+{
+	const char* err;
+	const uint64_t i = ParseTokenAsID(t,err);
+	if(err) {
+		ParseError(err,t);
+	}
+	return i;
+}
+
+
+// ------------------------------------------------------------------------------------------------
+// wrapper around ParseTokenAsDim() with ParseError handling
+size_t ParseTokenAsDim(const Token& t)
+{
+	const char* err;
+	const size_t i = ParseTokenAsDim(t,err);
+	if(err) {
+		ParseError(err,t);
+	}
+	return i;
+}
+
+
+// ------------------------------------------------------------------------------------------------
+// wrapper around ParseTokenAsFloat() with ParseError handling
+float ParseTokenAsFloat(const Token& t)
+{
+	const char* err;
+	const float i = ParseTokenAsFloat(t,err);
+	if(err) {
+		ParseError(err,t);
+	}
+	return i;
+}
+
+
+// ------------------------------------------------------------------------------------------------
+// wrapper around ParseTokenAsInt() with ParseError handling
+int ParseTokenAsInt(const Token& t)
+{
+	const char* err;
+	const int i = ParseTokenAsInt(t,err);
+	if(err) {
+		ParseError(err,t);
+	}
+	return i;
+}
+
+
+
 } // !FBX
 } // !Assimp
 

+ 32 - 0
code/FBXParser.h

@@ -208,6 +208,38 @@ float ParseTokenAsFloat(const Token& t, const char*& err_out);
 int ParseTokenAsInt(const Token& t, const char*& err_out);
 std::string ParseTokenAsString(const Token& t, const char*& err_out);
 
+
+/* wrapper around ParseTokenAsXXX() with DOMError handling */
+uint64_t ParseTokenAsID(const Token& t);
+size_t ParseTokenAsDim(const Token& t);
+float ParseTokenAsFloat(const Token& t);
+int ParseTokenAsInt(const Token& t);
+std::string ParseTokenAsString(const Token& t);
+
+/* read data arrays */
+void ParseVectorDataArray(std::vector<aiVector3D>& out, const Element& el);
+void ParseVectorDataArray(std::vector<aiColor4D>& out, const Element& el);
+void ParseVectorDataArray(std::vector<aiVector2D>& out, const Element& el);
+void ParseVectorDataArray(std::vector<int>& out, const Element& el);
+void ParseVectorDataArray(std::vector<float>& out, const Element& el);
+void ParseVectorDataArray(std::vector<unsigned int>& out, const Element& el);
+void ParseVectorDataArray(std::vector<uint64_t>& out, const Element& e);
+
+
+
+// extract a required element from a scope, abort if the element cannot be found
+const Element& GetRequiredElement(const Scope& sc, const std::string& index, const Element* element = NULL);
+
+// extract required compound scope
+const Scope& GetRequiredScope(const Element& el);
+// get token at a particular index
+const Token& GetRequiredToken(const Element& el, unsigned int index);
+
+
+
+// read a 4x4 matrix from an array of 16 floats
+aiMatrix4x4 ReadMatrix(const Element& element);
+
 } // ! FBX
 } // ! Assimp