Переглянути джерело

- fbx: further work on DOM, start work on geometry extraction.

Alexander Gessler 13 роки тому
батько
коміт
c0af603f0c
4 змінених файлів з 85 додано та 17 видалено
  1. 69 9
      code/FBXDocument.cpp
  2. 4 3
      code/FBXDocument.h
  3. 2 2
      code/FBXParser.cpp
  4. 10 3
      code/FBXParser.h

+ 69 - 9
code/FBXDocument.cpp

@@ -56,10 +56,22 @@ namespace {
 
 	// ------------------------------------------------------------------------------------------------
 	// signal DOM construction error, this is always unrecoverable. Throws DeadlyImportError.
-	void DOMError(const std::string& message, Element* element = NULL)
+	void DOMError(const std::string& message, const Element* element = NULL)
 	{
-		throw DeadlyImportError(element ? Util::AddTokenText("FBX-DOM",message,element->KeyToken()) : ("FBX-DOM " + message));
+		throw DeadlyImportError(element ? Util::AddTokenText("FBX-DOM",message,&element->KeyToken()) : ("FBX-DOM " + message));
 	}
+
+
+	// ------------------------------------------------------------------------------------------------
+	// extract a required element from a scope, abort if the element cannot be found
+	const Element& GetFixedElementFromScope(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;
+	}
+
 }
 
 namespace Assimp {
@@ -85,13 +97,48 @@ const Object* LazyObject::Get()
 		return object.get();
 	}
 
-	// XXX
-	return NULL;
+	const Token& key = element.KeyToken();
+	const TokenList& tokens = element.Tokens();
+
+	if(tokens.size() < 3) {
+		DOMError("expected at least 3 tokens: id, name and class tag",&element);
+	}
+
+	const char* err;
+	const std::string name = ParseTokenAsString(*tokens[1],err);
+	if (err) {
+		DOMError(err,&element);
+	} 
+
+	const std::string classtag = ParseTokenAsString(*tokens[2],err);
+	if (err) {
+		DOMError(err,&element);
+	} 
+
+	// this needs to be relatively fast since we do it a lot,
+	// so avoid constructing strings all the time. strcmp()
+	// may scan beyond the bounds of the token, but the 
+	// next character is always a colon so false positives
+	// are not possible.
+	const char* obtype = key.begin();
+	if (!strcmp(obtype,"Geometry")) {
+
+		if (!strcmp(classtag.c_str(),"Mesh")) {
+			object = new MeshGeometry(element,name);
+		}
+	}
+
+	if (!object.get()) {
+		DOMError("failed to convert element to DOM object, class: " + classtag + ", name: " + name,&element);
+	}
+
+	return object.get();
 }
 
 // ------------------------------------------------------------------------------------------------
-Object::Object(const Element& element)
+Object::Object(const Element& element, const std::string& name)
 : element(element)
+, name(name)
 {
 
 }
@@ -103,8 +150,8 @@ Object::~Object()
 }
 
 // ------------------------------------------------------------------------------------------------
-Geometry::Geometry(const Element& element)
-: Object(element)
+Geometry::Geometry(const Element& element, const std::string& name)
+: Object(element,name)
 {
 
 }
@@ -116,10 +163,23 @@ Geometry::~Geometry()
 }
 
 // ------------------------------------------------------------------------------------------------
-MeshGeometry::MeshGeometry(const Element& element)
-: Geometry(element)
+MeshGeometry::MeshGeometry(const Element& element, const std::string& name)
+: Geometry(element,name)
 {
+	const Scope* sc = element.Compound();
+	if (!sc) {
+		DOMError("failed to read Geometry object (class: Mesh), no data scope found");
+	}
+
+	// must have Mesh elements:
+	const Element& Vertices = GetFixedElementFromScope(*sc,"Vertices",&element);
+	const Element& PolygonVertexIndex = GetFixedElementFromScope(*sc,"PolygonVertexIndex",&element);
 
+	// optional Mesh elements:
+	const ElementCollection& Layer = sc->GetCollection("Layer");
+	const ElementCollection& LayerElementMaterial = sc->GetCollection("LayerElementMaterial");
+	const ElementCollection& LayerElementUV = sc->GetCollection("LayerElementUV");
+	const ElementCollection& LayerElementNormal = sc->GetCollection("LayerElementNormal");
 }
 
 // ------------------------------------------------------------------------------------------------

+ 4 - 3
code/FBXDocument.h

@@ -88,13 +88,14 @@ class Object
 {
 public:
 
-	Object(const Element& element);
+	Object(const Element& element, const std::string& name);
 	~Object();
 
 public:
 
 protected:
 	const Element& element;
+	const std::string name;
 };
 
 
@@ -103,7 +104,7 @@ class Geometry : public Object
 {
 public:
 
-	Geometry(const Element& element);
+	Geometry(const Element& element, const std::string& name);
 	~Geometry();
 };
 
@@ -114,7 +115,7 @@ class MeshGeometry : public Geometry
 
 public:
 
-	MeshGeometry(const Element& element);
+	MeshGeometry(const Element& element, const std::string& name);
 	~MeshGeometry();
 
 public:

+ 2 - 2
code/FBXParser.cpp

@@ -70,7 +70,7 @@ namespace Assimp {
 namespace FBX {
 
 // ------------------------------------------------------------------------------------------------
-Element::Element(TokenPtr key_token, Parser& parser)
+Element::Element(const Token& key_token, Parser& parser)
 : key_token(key_token)
 {
 	TokenPtr n = NULL;
@@ -140,7 +140,7 @@ Scope::Scope(Parser& parser,bool topLevel)
 		}
 
 		const std::string& str = n->StringContents();
-		elements.insert(ElementMap::value_type(str,new_Element(n,parser)));
+		elements.insert(ElementMap::value_type(str,new_Element(*n,parser)));
 
 		// Element() should stop at the next Key token (or right after a Close token)
 		n = parser.CurrentToken();

+ 10 - 3
code/FBXParser.h

@@ -47,6 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <vector>
 #include <map>
 #include <string>
+#include <utility>
 
 #include <boost/shared_ptr.hpp>
 
@@ -66,6 +67,8 @@ namespace FBX {
 	typedef std::vector< Scope* > ScopeList;
 	typedef std::fbx_unordered_multimap< std::string, Element* > ElementMap;
 
+	typedef std::pair<ElementMap::const_iterator,ElementMap::const_iterator> ElementCollection;
+
 #	define new_Scope new Scope
 #	define new_Element new Element
 
@@ -85,7 +88,7 @@ class Element
 {
 public:
 
-	Element(TokenPtr key_token, Parser& parser);
+	Element(const Token& key_token, Parser& parser);
 	~Element();
 
 public:
@@ -94,7 +97,7 @@ public:
 		return compound.get();
 	}
 
-	TokenPtr KeyToken() const {
+	const Token& KeyToken() const {
 		return key_token;
 	}
 
@@ -104,7 +107,7 @@ public:
 
 private:
 
-	TokenPtr key_token;
+	const Token& key_token;
 	TokenList tokens;
 	boost::scoped_ptr<Scope> compound;
 };
@@ -137,6 +140,10 @@ public:
 		return it == elements.end() ? NULL : (*it).second;
 	}
 
+	ElementCollection GetCollection(const std::string& index) const {
+		return elements.equal_range(index);
+	}
+
 	const ElementMap& Elements() const	{
 		return elements;
 	}