From c126cfa1ff2317edae0d79bf1636a48e76a5dfaa Mon Sep 17 00:00:00 2001 From: Alexander Gessler Date: Fri, 10 Aug 2012 22:33:57 +0200 Subject: [PATCH] - fbx: rework material reading to support negative indices (these will be assigned a default material). - fbx: fix uninitialized variable. --- code/FBXConverter.cpp | 53 +++++++++++++++++++++++----------------- code/FBXDocument.h | 4 +-- code/FBXMeshGeometry.cpp | 20 +++++++++++++-- 3 files changed, 51 insertions(+), 26 deletions(-) diff --git a/code/FBXConverter.cpp b/code/FBXConverter.cpp index 6b18e2c28..d7a734852 100644 --- a/code/FBXConverter.cpp +++ b/code/FBXConverter.cpp @@ -100,6 +100,7 @@ public: Converter(aiScene* out, const Document& doc) : out(out) , doc(doc) + , defaultMaterialIndex() { // animations need to be converted first since this will // populate the node_anim_chain_bits map, which is needed @@ -561,7 +562,8 @@ private: // ------------------------------------------------------------------------------------------------ // MeshGeometry -> aiMesh, return mesh index + 1 or 0 if the conversion failed - std::vector ConvertMesh(const MeshGeometry& mesh,const Model& model, const aiMatrix4x4& node_global_transform) + std::vector ConvertMesh(const MeshGeometry& mesh,const Model& model, + const aiMatrix4x4& node_global_transform) { std::vector temp; @@ -580,10 +582,10 @@ private: // one material per mesh maps easily to aiMesh. Multiple material // meshes need to be split. - const std::vector& mindices = mesh.GetMaterialIndices(); + const MatIndexArray& mindices = mesh.GetMaterialIndices(); if (doc.Settings().readMaterials && !mindices.empty()) { - const unsigned int base = mindices[0]; - BOOST_FOREACH(unsigned int index, mindices) { + const MatIndexArray::value_type base = mindices[0]; + BOOST_FOREACH(MatIndexArray::value_type index, mindices) { if(index != base) { return ConvertMeshMultiMaterial(mesh, model, node_global_transform); } @@ -597,7 +599,7 @@ private: // ------------------------------------------------------------------------------------------------ - aiMesh* SetupEmptyMesh(const MeshGeometry& mesh, unsigned int material_index) + aiMesh* SetupEmptyMesh(const MeshGeometry& mesh) { aiMesh* const out_mesh = new aiMesh(); meshes.push_back(out_mesh); @@ -618,10 +620,11 @@ private: // ------------------------------------------------------------------------------------------------ - unsigned int ConvertMeshSingleMaterial(const MeshGeometry& mesh, const Model& model, const aiMatrix4x4& node_global_transform) + unsigned int ConvertMeshSingleMaterial(const MeshGeometry& mesh, const Model& model, + const aiMatrix4x4& node_global_transform) { - const std::vector& mindices = mesh.GetMaterialIndices(); - aiMesh* const out_mesh = SetupEmptyMesh(mesh,mindices.size() ? mindices[0] : static_cast(-1)); + const MatIndexArray& mindices = mesh.GetMaterialIndices(); + aiMesh* const out_mesh = SetupEmptyMesh(mesh); const std::vector& vertices = mesh.GetVertices(); const std::vector& faces = mesh.GetFaceIndexCounts(); @@ -745,15 +748,16 @@ private: // ------------------------------------------------------------------------------------------------ - std::vector ConvertMeshMultiMaterial(const MeshGeometry& mesh, const Model& model, const aiMatrix4x4& node_global_transform) + std::vector ConvertMeshMultiMaterial(const MeshGeometry& mesh, const Model& model, + const aiMatrix4x4& node_global_transform) { - const std::vector& mindices = mesh.GetMaterialIndices(); + const MatIndexArray& mindices = mesh.GetMaterialIndices(); ai_assert(mindices.size()); - std::set had; + std::set had; std::vector indices; - BOOST_FOREACH(unsigned int index, mindices) { + BOOST_FOREACH(MatIndexArray::value_type index, mindices) { if(had.find(index) == had.end()) { indices.push_back(ConvertMeshMultiMaterial(mesh, model, index, node_global_transform)); @@ -766,11 +770,13 @@ private: // ------------------------------------------------------------------------------------------------ - unsigned int ConvertMeshMultiMaterial(const MeshGeometry& mesh, const Model& model, unsigned int index, const aiMatrix4x4& node_global_transform) + unsigned int ConvertMeshMultiMaterial(const MeshGeometry& mesh, const Model& model, + MatIndexArray::value_type index, + const aiMatrix4x4& node_global_transform) { - aiMesh* const out_mesh = SetupEmptyMesh(mesh, index); + aiMesh* const out_mesh = SetupEmptyMesh(mesh); - const std::vector& mindices = mesh.GetMaterialIndices(); + const MatIndexArray& mindices = mesh.GetMaterialIndices(); const std::vector& vertices = mesh.GetVertices(); const std::vector& faces = mesh.GetFaceIndexCounts(); @@ -780,8 +786,9 @@ private: unsigned int count_vertices = 0; // count faces - for(std::vector::const_iterator it = mindices.begin(), - end = mindices.end(), itf = faces.begin(); it != end; ++it, ++itf) + std::vector::const_iterator itf = faces.begin(); + for(MatIndexArray::const_iterator it = mindices.begin(), + end = mindices.end(); it != end; ++it, ++itf) { if ((*it) != index) { continue; @@ -870,8 +877,9 @@ private: unsigned int cursor = 0, in_cursor = 0; - for(std::vector::const_iterator it = mindices.begin(), - end = mindices.end(), itf = faces.begin(); it != end; ++it, ++itf) + itf = faces.begin(); + for(MatIndexArray::const_iterator it = mindices.begin(), + end = mindices.end(); it != end; ++it, ++itf) { const unsigned int pcount = *itf; if ((*it) != index) { @@ -1095,11 +1103,12 @@ private: // ------------------------------------------------------------------------------------------------ - void ConvertMaterialForMesh(aiMesh* out, const Model& model, const MeshGeometry& geo, unsigned int materialIndex) + void ConvertMaterialForMesh(aiMesh* out, const Model& model, const MeshGeometry& geo, + MatIndexArray::value_type materialIndex) { // locate source materials for this mesh const std::vector& mats = model.GetMaterials(); - if (materialIndex >= mats.size()) { + if (materialIndex >= mats.size() || materialIndex < 0) { FBXImporter::LogError("material index out of bounds, setting default material"); out->mMaterialIndex = GetDefaultMaterial(); return; @@ -1229,7 +1238,7 @@ private: continue; } - const std::vector& mats = mesh->GetMaterialIndices(); + const MatIndexArray& mats = mesh->GetMaterialIndices(); if(std::find(mats.begin(),mats.end(),matIndex) == mats.end()) { continue; } diff --git a/code/FBXDocument.h b/code/FBXDocument.h index 71c1e6837..6c0f3606b 100644 --- a/code/FBXDocument.h +++ b/code/FBXDocument.h @@ -387,7 +387,7 @@ private: }; -typedef std::vector MatIndexArray; +typedef std::vector MatIndexArray; /** DOM class for FBX geometry of type "Mesh"*/ @@ -528,7 +528,7 @@ private: const std::string& MappingInformationType, const std::string& ReferenceInformationType); - void ReadVertexDataMaterials(std::vector& materials_out, const Scope& source, + void ReadVertexDataMaterials(MatIndexArray& materials_out, const Scope& source, const std::string& MappingInformationType, const std::string& ReferenceInformationType); diff --git a/code/FBXMeshGeometry.cpp b/code/FBXMeshGeometry.cpp index f828b89b7..1be98216e 100644 --- a/code/FBXMeshGeometry.cpp +++ b/code/FBXMeshGeometry.cpp @@ -261,10 +261,26 @@ void MeshGeometry::ReadVertexData(const std::string& type, int index, const Scop return; } - ReadVertexDataMaterials(materials,source, + std::vector temp_materials; + + ReadVertexDataMaterials(temp_materials,source, MappingInformationType, ReferenceInformationType ); + + // sometimes, there will be only negative entries. Drop the material + // layer in such a case (I guess it means a default material should + // be used). This is what the converter would do anyway, and it + // avoids loosing the material if there are more material layers + // coming of which at least one contains actual data (did observe + // that with one test file). + const size_t count_neg = std::count_if(temp_materials.begin(),temp_materials.end(),std::bind2nd(std::less(),0)); + if(count_neg == temp_materials.size()) { + FBXImporter::LogWarn("ignoring dummy material layer (all entries -1)"); + return; + } + + std::swap(temp_materials, materials); } else if (type == "LayerElementNormal") { if (normals.size() > 0) { @@ -474,7 +490,7 @@ void MeshGeometry::ReadVertexDataBinormals(std::vector& binormals_ou // ------------------------------------------------------------------------------------------------ -void MeshGeometry::ReadVertexDataMaterials(std::vector& materials_out, const Scope& source, +void MeshGeometry::ReadVertexDataMaterials(std::vector& materials_out, const Scope& source, const std::string& MappingInformationType, const std::string& ReferenceInformationType) {