Browse Source

- fbx: refactor, move DOM utility functions to separate unit.

Alexander Gessler 13 years ago
parent
commit
ef0dcaaea2
4 changed files with 453 additions and 387 deletions
  1. 1 0
      code/CMakeLists.txt
  2. 0 387
      code/FBXDocument.cpp
  3. 448 0
      code/FBXDocumentUtil.cpp
  4. 4 0
      workspaces/vc9/assimp.vcproj

+ 1 - 0
code/CMakeLists.txt

@@ -418,6 +418,7 @@ SET(FBX_SRCS
 	FBXNodeAttribute.cpp
 	FBXDeformer.cpp
 	FBXBinaryTokenizer.cpp
+	FBXDocumentUtil.cpp
 )
 SOURCE_GROUP( FBX FILES ${FBX_SRCS})
 

+ 0 - 387
code/FBXDocument.cpp

@@ -57,393 +57,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 namespace Assimp {
 namespace FBX {
-namespace Util {
-
-// ------------------------------------------------------------------------------------------------
-// signal DOM construction error, this is always unrecoverable. Throws DeadlyImportError.
-void DOMError(const std::string& message, const Token& token)
-{
-	throw DeadlyImportError(Util::AddTokenText("FBX-DOM",message,&token));
-}
-
-// ------------------------------------------------------------------------------------------------
-void DOMError(const std::string& message, const Element* element /*= NULL*/)
-{
-	if(element) {
-		DOMError(message,element->KeyToken());
-	}
-	throw DeadlyImportError("FBX-DOM " + message);
-}
-
-
-// ------------------------------------------------------------------------------------------------
-// print warning, do return
-void DOMWarning(const std::string& message, const Token& token)
-{
-	if(DefaultLogger::get()) {
-		DefaultLogger::get()->warn(Util::AddTokenText("FBX-DOM",message,&token));
-	}
-}
-
-// ------------------------------------------------------------------------------------------------
-void DOMWarning(const std::string& message, const Element* element /*= NULL*/)
-{
-	if(element) {
-		DOMWarning(message,element->KeyToken());
-		return;
-	}
-	if(DefaultLogger::get()) {
-		DefaultLogger::get()->warn("FBX-DOM: " + message);
-	}
-}
-
-
-// ------------------------------------------------------------------------------------------------
-// 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, 
-	const std::string& templateName, 
-	const Element &element, 
-	const Scope& sc)
-{
-	const Element* const Properties70 = sc["Properties70"];
-	boost::shared_ptr<const PropertyTable> templateProps = boost::shared_ptr<const PropertyTable>(
-		static_cast<const PropertyTable*>(NULL));
-
-	if(templateName.length()) {
-		PropertyTemplateMap::const_iterator it = doc.Templates().find(templateName); 
-		if(it != doc.Templates().end()) {
-			templateProps = (*it).second;
-		}
-	}
-
-	if(!Properties70) {
-		DOMWarning("material property table (Properties70) not found",&element);
-		if(templateProps) {
-			return templateProps;
-		}
-		else {
-			return boost::make_shared<const PropertyTable>();
-		}
-	}
-	return boost::make_shared<const PropertyTable>(*Properties70,templateProps);
-}
-} // !Util
 
 using namespace Util;
 

+ 448 - 0
code/FBXDocumentUtil.cpp

@@ -0,0 +1,448 @@
+/*
+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  FBXDocumentUtil.cpp
+ *  @brief Implementation of the FBX DOM utility functions declared in FBXDocumentUtil.h
+ */
+#include "AssimpPCH.h"
+
+#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER
+
+#include <functional>
+
+#include "FBXParser.h"
+#include "FBXDocument.h"
+#include "FBXUtil.h"
+#include "FBXDocumentUtil.h"
+#include "FBXProperties.h"
+
+namespace Assimp {
+namespace FBX {
+namespace Util {
+
+// ------------------------------------------------------------------------------------------------
+// signal DOM construction error, this is always unrecoverable. Throws DeadlyImportError.
+void DOMError(const std::string& message, const Token& token)
+{
+	throw DeadlyImportError(Util::AddTokenText("FBX-DOM",message,&token));
+}
+
+// ------------------------------------------------------------------------------------------------
+void DOMError(const std::string& message, const Element* element /*= NULL*/)
+{
+	if(element) {
+		DOMError(message,element->KeyToken());
+	}
+	throw DeadlyImportError("FBX-DOM " + message);
+}
+
+
+// ------------------------------------------------------------------------------------------------
+// print warning, do return
+void DOMWarning(const std::string& message, const Token& token)
+{
+	if(DefaultLogger::get()) {
+		DefaultLogger::get()->warn(Util::AddTokenText("FBX-DOM",message,&token));
+	}
+}
+
+// ------------------------------------------------------------------------------------------------
+void DOMWarning(const std::string& message, const Element* element /*= NULL*/)
+{
+	if(element) {
+		DOMWarning(message,element->KeyToken());
+		return;
+	}
+	if(DefaultLogger::get()) {
+		DefaultLogger::get()->warn("FBX-DOM: " + message);
+	}
+}
+
+
+// ------------------------------------------------------------------------------------------------
+// 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, 
+	const std::string& templateName, 
+	const Element &element, 
+	const Scope& sc)
+{
+	const Element* const Properties70 = sc["Properties70"];
+	boost::shared_ptr<const PropertyTable> templateProps = boost::shared_ptr<const PropertyTable>(
+		static_cast<const PropertyTable*>(NULL));
+
+	if(templateName.length()) {
+		PropertyTemplateMap::const_iterator it = doc.Templates().find(templateName); 
+		if(it != doc.Templates().end()) {
+			templateProps = (*it).second;
+		}
+	}
+
+	if(!Properties70) {
+		DOMWarning("material property table (Properties70) not found",&element);
+		if(templateProps) {
+			return templateProps;
+		}
+		else {
+			return boost::make_shared<const PropertyTable>();
+		}
+	}
+	return boost::make_shared<const PropertyTable>(*Properties70,templateProps);
+}
+} // !Util
+} // !FBX
+} // !Assimp
+
+#endif

+ 4 - 0
workspaces/vc9/assimp.vcproj

@@ -2087,6 +2087,10 @@
 						RelativePath="..\..\code\FBXDocument.h"
 						>
 					</File>
+					<File
+						RelativePath="..\..\code\FBXDocumentUtil.cpp"
+						>
+					</File>
 					<File
 						RelativePath="..\..\code\FBXDocumentUtil.h"
 						>