Sfoglia il codice sorgente

- fbx: refactor code to handle FBX vertex data access. Support the same access & indexing types for UVs and normals.

Alexander Gessler 13 anni fa
parent
commit
ffe0ed7926
2 ha cambiato i file con 116 aggiunte e 89 eliminazioni
  1. 108 89
      code/FBXDocument.cpp
  2. 8 0
      code/FBXDocument.h

+ 108 - 89
code/FBXDocument.cpp

@@ -423,6 +423,14 @@ MeshGeometry::MeshGeometry(const Element& element, const std::string& name)
 	}
 }
 
+
+// ------------------------------------------------------------------------------------------------
+MeshGeometry::~MeshGeometry()
+{
+
+}
+
+
 // ------------------------------------------------------------------------------------------------
 void MeshGeometry::ReadLayer(const Scope& layer)
 {
@@ -434,6 +442,7 @@ void MeshGeometry::ReadLayer(const Scope& layer)
 	}
 }
 
+
 // ------------------------------------------------------------------------------------------------
 void MeshGeometry::ReadLayerElement(const Scope& layerElement)
 {
@@ -458,6 +467,7 @@ void MeshGeometry::ReadLayerElement(const Scope& layerElement)
 		<< type << ", index: " << typedIndex);
 }
 
+
 // ------------------------------------------------------------------------------------------------
 void MeshGeometry::ReadVertexData(const std::string& type, int index, const Scope& source)
 {
@@ -477,73 +487,7 @@ void MeshGeometry::ReadVertexData(const std::string& type, int index, const Scop
 			return;
 		}
 
-		std::vector<aiVector2D>& uv_out = uvs[index];
-
-		std::vector<aiVector2D> tempUV;
-		ReadVectorDataArray(tempUV,GetRequiredElement(source,"UV"));
-
-		// handle permutations of Mapping and Reference type - it would be nice to
-		// deal with this more elegantly and with less redundancy, but right
-		// now it seems unavoidable.
-		if (MappingInformationType == "ByVertice" && ReferenceInformationType == "Direct") {	
-			uv_out.resize(vertices.size());
-			for (size_t i = 0, e = tempUV.size(); i < e; ++i) {
-
-				const unsigned int istart = mapping_offsets[i], iend = istart + mapping_counts[i];
-				for (unsigned int j = istart; j < iend; ++j) {
-					uv_out[mappings[j]] = tempUV[i];
-				}
-			}
-		}
-		else if (MappingInformationType == "ByVertice" && ReferenceInformationType == "IndexToDirect") {	
-			uv_out.resize(vertices.size());
-
-			std::vector<int> uvIndices;
-			ReadIntDataArray(uvIndices,GetRequiredElement(source,"UVIndex"));
-
-			for (size_t i = 0, e = uvIndices.size(); i < e; ++i) {
-
-				const unsigned int istart = mapping_offsets[i], iend = istart + mapping_counts[i];
-				for (unsigned int j = istart; j < iend; ++j) {
-					if(static_cast<size_t>(uvIndices[i]) >= tempUV.size()) {
-						DOMError("UV index out of range",&GetRequiredElement(source,"UVIndex"));
-					}
-					uv_out[mappings[j]] = tempUV[uvIndices[i]];
-				}
-			}
-		}
-		else if (MappingInformationType == "ByPolygonVertex" && ReferenceInformationType == "Direct") {	
-			if (tempUV.size() != vertices.size()) {
-				FBXImporter::LogError("size of input UV array unexpected for ByPolygonVertex mapping");
-				return;
-			}
-
-			uv_out.swap(tempUV);
-		}
-		else if (MappingInformationType == "ByPolygonVertex" && ReferenceInformationType == "IndexToDirect") {	
-			uv_out.resize(vertices.size());
-
-			std::vector<int> uvIndices;
-			ReadIntDataArray(uvIndices,GetRequiredElement(source,"UVIndex"));
-			
-			if (uvIndices.size() != vertices.size()) {
-				FBXImporter::LogError("size of input UV array unexpected for ByPolygonVertex mapping");
-				return;
-			}
-
-			unsigned int next = 0;
-			BOOST_FOREACH(int i, uvIndices) {
-				if(static_cast<size_t>(i) >= tempUV.size()) {
-					DOMError("UV index out of range",&GetRequiredElement(source,"UVIndex"));
-				}
-
-				uv_out[next++] = tempUV[i];
-			}
-		}
-		else {
-			FBXImporter::LogError(Formatter::format("ignoring normals, unrecognized access type: ") 
-				<< MappingInformationType << "," << ReferenceInformationType);
-		}
+		ReadVertexDataUV(uvs[index],source,MappingInformationType,ReferenceInformationType);
 	}
 	else if (type == "LayerElementMaterial") {
 		
@@ -562,47 +506,122 @@ void MeshGeometry::ReadVertexData(const std::string& type, int index, const Scop
 		}
 	}
 	else if (type == "LayerElementNormal") {
+		ReadVertexDataNormals(normals,source,MappingInformationType,ReferenceInformationType);
+	}
+}
 
-		std::vector<aiVector3D> tempNormals;
-		ReadVectorDataArray(normals,GetRequiredElement(source,"Normals"));
+// ------------------------------------------------------------------------------------------------
+// Lengthy utility function to read and resolve a FBX vertex data array - that is, the
+// output is in polygon vertex order. This logic is used for reading normals, UVs, colors,
+// tangents ..
+template <typename T>
+void ResolveVertexDataArray(std::vector<T>& data_out, const Scope& source, 
+	const std::string& MappingInformationType,
+	const std::string& ReferenceInformationType,
+	const char* dataElementName,
+	const char* indexDataElementName,
+	size_t vertex_count,
+	const std::vector<unsigned int>& mapping_counts,
+	const std::vector<unsigned int>& mapping_offsets,
+	const std::vector<unsigned int>& mappings)
+{
+	std::vector<T> tempUV;
+	ReadVectorDataArray(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
+	// now it seems unavoidable.
+	if (MappingInformationType == "ByVertice" && ReferenceInformationType == "Direct") {	
+		data_out.resize(vertex_count);
+		for (size_t i = 0, e = tempUV.size(); i < e; ++i) {
+
+			const unsigned int istart = mapping_offsets[i], iend = istart + mapping_counts[i];
+			for (unsigned int j = istart; j < iend; ++j) {
+				data_out[mappings[j]] = tempUV[i];
+			}
+		}
+	}
+	else if (MappingInformationType == "ByVertice" && ReferenceInformationType == "IndexToDirect") {	
+		data_out.resize(vertex_count);
 
-		normals.resize(vertices.size());
+		std::vector<int> uvIndices;
+		ReadIntDataArray(uvIndices,GetRequiredElement(source,indexDataElementName));
 
-		if (MappingInformationType == "ByVertice" && ReferenceInformationType == "Direct") {	
-			
-			for (size_t i = 0, e = tempNormals.size(); i < e; ++i) {
+		for (size_t i = 0, e = uvIndices.size(); i < e; ++i) {
 
-				const unsigned int istart = mapping_offsets[i], iend = istart + mapping_counts[i];
-				for (unsigned int j = istart; j < iend; ++j) {
-					normals[mappings[j]] = tempNormals[i];
+			const unsigned int istart = mapping_offsets[i], iend = istart + mapping_counts[i];
+			for (unsigned int j = istart; j < iend; ++j) {
+				if(static_cast<size_t>(uvIndices[i]) >= tempUV.size()) {
+					DOMError("index out of range",&GetRequiredElement(source,indexDataElementName));
 				}
+				data_out[mappings[j]] = tempUV[uvIndices[i]];
 			}
 		}
-		else if (MappingInformationType == "ByVertice" && ReferenceInformationType == "IndexToDirect") {	
+	}
+	else if (MappingInformationType == "ByPolygonVertex" && ReferenceInformationType == "Direct") {	
+		if (tempUV.size() != vertex_count) {
+			FBXImporter::LogError("length of input data unexpected for ByPolygonVertex mapping");
+			return;
+		}
 
-			std::vector<int> normalIndices;
-			ReadIntDataArray(normalIndices,GetRequiredElement(source,"NormalsIndex"));
-			for (size_t i = 0, e = normalIndices.size(); i < e; ++i) {
+		data_out.swap(tempUV);
+	}
+	else if (MappingInformationType == "ByPolygonVertex" && ReferenceInformationType == "IndexToDirect") {	
+		data_out.resize(vertex_count);
 
-				const unsigned int istart = mapping_offsets[i], iend = istart + mapping_counts[i];
-				for (unsigned int j = istart; j < iend; ++j) {
-					normals[mappings[j]] = tempNormals[normalIndices[i]];
-				}
-			}
+		std::vector<int> uvIndices;
+		ReadIntDataArray(uvIndices,GetRequiredElement(source,indexDataElementName));
+
+		if (uvIndices.size() != vertex_count) {
+			FBXImporter::LogError("length of input data unexpected for ByPolygonVertex mapping");
+			return;
 		}
-		else {
-			FBXImporter::LogError(Formatter::format("ignoring normals, unrecognized access type: ") 
-				<< MappingInformationType << "," << ReferenceInformationType);
+
+		unsigned int next = 0;
+		BOOST_FOREACH(int i, uvIndices) {
+			if(static_cast<size_t>(i) >= tempUV.size()) {
+				DOMError("index out of range",&GetRequiredElement(source,indexDataElementName));
+			}
+
+			data_out[next++] = tempUV[i];
 		}
 	}
+	else {
+		FBXImporter::LogError(Formatter::format("ignoring vertex data channel, unrecognized access type: ") 
+			<< MappingInformationType << "," << ReferenceInformationType);
+	}
 }
 
 // ------------------------------------------------------------------------------------------------
-MeshGeometry::~MeshGeometry()
+void MeshGeometry::ReadVertexDataNormals(std::vector<aiVector3D>& normals_out, const Scope& source, 
+	const std::string& MappingInformationType,
+	const std::string& ReferenceInformationType)
 {
+	ResolveVertexDataArray(normals_out,source,MappingInformationType,ReferenceInformationType,
+		"Normals",
+		"NormalsIndex",
+		vertices.size(),
+		mapping_counts,
+		mapping_offsets,
+		mappings);
+}
+
 
+// ------------------------------------------------------------------------------------------------
+void MeshGeometry::ReadVertexDataUV(std::vector<aiVector2D>& uv_out, const Scope& source, 
+	const std::string& MappingInformationType,
+	const std::string& ReferenceInformationType)
+{
+	ResolveVertexDataArray(uv_out,source,MappingInformationType,ReferenceInformationType,
+		"UV",
+		"UVIndex",
+		vertices.size(),
+		mapping_counts,
+		mapping_offsets,
+		mappings);
 }
 
+
 // ------------------------------------------------------------------------------------------------
 Document::Document(const Parser& parser)
 : parser(parser)

+ 8 - 0
code/FBXDocument.h

@@ -172,6 +172,14 @@ private:
 	void ReadLayerElement(const Scope& layerElement);
 	void ReadVertexData(const std::string& type, int index, const Scope& source);
 
+	void ReadVertexDataUV(std::vector<aiVector2D>& uv_out, const Scope& source, 
+		const std::string& MappingInformationType,
+		const std::string& ReferenceInformationType);
+
+	void ReadVertexDataNormals(std::vector<aiVector3D>& normals_out, const Scope& source, 
+		const std::string& MappingInformationType,
+		const std::string& ReferenceInformationType);
+
 private:
 
 	// cached data arrays