From 6ddb1c9aa7554247f1214b22de583b81a6748759 Mon Sep 17 00:00:00 2001 From: acgessler Date: Sun, 1 Jul 2012 14:38:14 +0200 Subject: [PATCH] - fbx: refactor code --- code/FBXConverter.cpp | 4 +- code/FBXDocument.cpp | 438 +----- code/FBXDocumentUtil.h | 93 ++ code/FBXMeshGeometry.cpp | 493 +++++++ workspaces/vc9/assimp.vcproj | 2604 +++++++++++++++++----------------- 5 files changed, 1900 insertions(+), 1732 deletions(-) create mode 100644 code/FBXDocumentUtil.h create mode 100644 code/FBXMeshGeometry.cpp diff --git a/code/FBXConverter.cpp b/code/FBXConverter.cpp index c833d3f02..61a307ff6 100644 --- a/code/FBXConverter.cpp +++ b/code/FBXConverter.cpp @@ -38,8 +38,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- */ -/** @file FBXDocument.cpp - * @brief Implementation of the FBX DOM classes +/** @file FBXConverter.cpp + * @brief Implementation of the FBX DOM -> aiScene converter */ #include "AssimpPCH.h" diff --git a/code/FBXDocument.cpp b/code/FBXDocument.cpp index b94460e6f..56ac480cb 100644 --- a/code/FBXDocument.cpp +++ b/code/FBXDocument.cpp @@ -50,11 +50,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "FBXUtil.h" #include "FBXImporter.h" #include "FBXImportSettings.h" +#include "FBXDocumentUtil.h" namespace Assimp { namespace FBX { - -namespace { +namespace Util { // ------------------------------------------------------------------------------------------------ // signal DOM construction error, this is always unrecoverable. Throws DeadlyImportError. @@ -64,7 +64,7 @@ void DOMError(const std::string& message, const Token& token) } // ------------------------------------------------------------------------------------------------ -void DOMError(const std::string& message, const Element* element = NULL) +void DOMError(const std::string& message, const Element* element /*= NULL*/) { if(element) { DOMError(message,element->KeyToken()); @@ -165,7 +165,7 @@ 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) +const Element& GetRequiredElement(const Scope& sc, const std::string& index, const Element* element /*= NULL*/) { const Element* el = sc[index]; if(!el) { @@ -304,8 +304,9 @@ void ReadVectorDataArray(std::vector& out, const Element& el) out.push_back(static_cast(ival)); } } -} // end anon. +} // !Util +using namespace Util; // ------------------------------------------------------------------------------------------------ LazyObject::LazyObject(const Element& element, const ImportSettings& settings) @@ -390,433 +391,6 @@ Geometry::~Geometry() } -// ------------------------------------------------------------------------------------------------ -MeshGeometry::MeshGeometry(const Element& element, const std::string& name, const ImportSettings& settings) -: 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 = GetRequiredElement(*sc,"Vertices",&element); - const Element& PolygonVertexIndex = GetRequiredElement(*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"); - - std::vector tempVerts; - ReadVectorDataArray(tempVerts,Vertices); - - if(tempVerts.empty()) { - FBXImporter::LogWarn("encountered mesh with no vertices"); - return; - } - - std::vector tempFaces; - ReadVectorDataArray(tempFaces,PolygonVertexIndex); - - if(tempFaces.empty()) { - FBXImporter::LogWarn("encountered mesh with no faces"); - return; - } - - vertices.reserve(tempFaces.size()); - faces.reserve(tempFaces.size() / 3); - - mapping_offsets.resize(tempVerts.size()); - mapping_counts.resize(tempVerts.size(),0); - mappings.resize(tempFaces.size()); - - const size_t vertex_count = tempVerts.size(); - - // generate output vertices, computing an adjacency table to - // preserve the mapping from fbx indices to *this* indexing. - unsigned int count = 0; - BOOST_FOREACH(int index, tempFaces) { - const int absi = index < 0 ? (-index - 1) : index; - if(static_cast(absi) >= vertex_count) { - DOMError("polygon vertex index out of range",&PolygonVertexIndex); - } - - vertices.push_back(tempVerts[absi]); - ++count; - - ++mapping_counts[absi]; - - if (index < 0) { - faces.push_back(count); - count = 0; - } - } - - unsigned int cursor = 0; - for (size_t i = 0, e = tempVerts.size(); i < e; ++i) { - mapping_offsets[i] = cursor; - cursor += mapping_counts[i]; - - mapping_counts[i] = 0; - } - - cursor = 0; - BOOST_FOREACH(int index, tempFaces) { - const int absi = index < 0 ? (-index - 1) : index; - mappings[mapping_offsets[absi] + mapping_counts[absi]++] = cursor; - } - - // if settings.readAllLayers is true: - // * read all layers, try to load as many vertex channels as possible - // if settings.readAllLayers is false: - // * read only the layer with index 0, but warn about any further layers - for (ElementMap::const_iterator it = Layer.first; it != Layer.second; ++it) { - const TokenList& tokens = (*it).second->Tokens(); - - const char* err; - const int index = ParseTokenAsInt(*tokens[0], err); - if(err) { - DOMError(err,&element); - } - - if(settings.readAllLayers || index == 0) { - const Scope& layer = GetRequiredScope(*(*it).second); - ReadLayer(layer); - } - else { - FBXImporter::LogWarn("ignoring additional geometry layers"); - } - } -} - - -// ------------------------------------------------------------------------------------------------ -MeshGeometry::~MeshGeometry() -{ - -} - - -// ------------------------------------------------------------------------------------------------ -void MeshGeometry::ReadLayer(const Scope& layer) -{ - const ElementCollection& LayerElement = layer.GetCollection("LayerElement"); - for (ElementMap::const_iterator eit = LayerElement.first; eit != LayerElement.second; ++eit) { - const Scope& elayer = GetRequiredScope(*(*eit).second); - - ReadLayerElement(elayer); - } -} - - -// ------------------------------------------------------------------------------------------------ -void MeshGeometry::ReadLayerElement(const Scope& layerElement) -{ - const Element& Type = GetRequiredElement(layerElement,"Type"); - const Element& TypedIndex = GetRequiredElement(layerElement,"TypedIndex"); - - const std::string& type = ParseTokenAsString(GetRequiredToken(Type,0)); - const int typedIndex = ParseTokenAsInt(GetRequiredToken(TypedIndex,0)); - - const Scope& top = GetRequiredScope(element); - const ElementCollection candidates = top.GetCollection(type); - - for (ElementMap::const_iterator it = candidates.first; it != candidates.second; ++it) { - const int index = ParseTokenAsInt(GetRequiredToken(*(*it).second,0)); - if(index == typedIndex) { - ReadVertexData(type,typedIndex,GetRequiredScope(*(*it).second)); - return; - } - } - - FBXImporter::LogError(Formatter::format("failed to resolve vertex layer element: ") - << type << ", index: " << typedIndex); -} - - -// ------------------------------------------------------------------------------------------------ -void MeshGeometry::ReadVertexData(const std::string& type, int index, const Scope& source) -{ - const std::string& MappingInformationType = ParseTokenAsString(GetRequiredToken( - GetRequiredElement(source,"MappingInformationType"),0) - ); - - const std::string& ReferenceInformationType = ParseTokenAsString(GetRequiredToken( - GetRequiredElement(source,"ReferenceInformationType"),0) - ); - - if (type == "LayerElementUV") { - if(index >= AI_MAX_NUMBER_OF_TEXTURECOORDS) { - FBXImporter::LogError(Formatter::format("ignoring UV layer, maximum number of UV channels exceeded: ") - << index << " (limit is " << AI_MAX_NUMBER_OF_TEXTURECOORDS << ")" ); - return; - } - - ReadVertexDataUV(uvs[index],source, - MappingInformationType, - ReferenceInformationType - ); - } - else if (type == "LayerElementMaterial") { - if (materials.size() > 0) { - FBXImporter::LogError("ignoring additional material layer"); - return; - } - - ReadVertexDataMaterials(materials,source, - MappingInformationType, - ReferenceInformationType - ); - } - else if (type == "LayerElementNormal") { - if (normals.size() > 0) { - FBXImporter::LogError("ignoring additional normal layer"); - return; - } - - ReadVertexDataNormals(normals,source, - MappingInformationType, - ReferenceInformationType - ); - } - else if (type == "LayerElementTangent") { - if (tangents.size() > 0) { - FBXImporter::LogError("ignoring additional tangent layer"); - return; - } - - ReadVertexDataTangents(tangents,source, - MappingInformationType, - ReferenceInformationType - ); - } - else if (type == "LayerElementBinormal") { - if (binormals.size() > 0) { - FBXImporter::LogError("ignoring additional binormal layer"); - return; - } - - ReadVertexDataBinormals(binormals,source, - MappingInformationType, - ReferenceInformationType - ); - } - else if (type == "LayerElementColor") { - if(index >= AI_MAX_NUMBER_OF_COLOR_SETS) { - FBXImporter::LogError(Formatter::format("ignoring vertex color layer, maximum number of color sets exceeded: ") - << index << " (limit is " << AI_MAX_NUMBER_OF_COLOR_SETS << ")" ); - return; - } - - ReadVertexDataColors(colors[index],source, - MappingInformationType, - ReferenceInformationType - ); - } -} - -// ------------------------------------------------------------------------------------------------ -// 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 -void ResolveVertexDataArray(std::vector& 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& mapping_counts, - const std::vector& mapping_offsets, - const std::vector& mappings) -{ - std::vector 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); - - std::vector uvIndices; - ReadVectorDataArray(uvIndices,GetRequiredElement(source,indexDataElementName)); - - 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(uvIndices[i]) >= tempUV.size()) { - DOMError("index out of range",&GetRequiredElement(source,indexDataElementName)); - } - data_out[mappings[j]] = tempUV[uvIndices[i]]; - } - } - } - else if (MappingInformationType == "ByPolygonVertex" && ReferenceInformationType == "Direct") { - if (tempUV.size() != vertex_count) { - FBXImporter::LogError(Formatter::format("length of input data unexpected for ByPolygon mapping: ") - << tempUV.size() << ", expected " << vertex_count - ); - return; - } - - data_out.swap(tempUV); - } - else if (MappingInformationType == "ByPolygonVertex" && ReferenceInformationType == "IndexToDirect") { - data_out.resize(vertex_count); - - std::vector uvIndices; - ReadVectorDataArray(uvIndices,GetRequiredElement(source,indexDataElementName)); - - if (uvIndices.size() != vertex_count) { - FBXImporter::LogError("length of input data unexpected for ByPolygonVertex mapping"); - return; - } - - unsigned int next = 0; - BOOST_FOREACH(int i, uvIndices) { - if(static_cast(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, access type not implemented: ") - << MappingInformationType << "," << ReferenceInformationType); - } -} - -// ------------------------------------------------------------------------------------------------ -void MeshGeometry::ReadVertexDataNormals(std::vector& 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& 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); -} - - -// ------------------------------------------------------------------------------------------------ -void MeshGeometry::ReadVertexDataColors(std::vector& colors_out, const Scope& source, - const std::string& MappingInformationType, - const std::string& ReferenceInformationType) -{ - ResolveVertexDataArray(colors_out,source,MappingInformationType,ReferenceInformationType, - "Color", - "ColorIndex", - vertices.size(), - mapping_counts, - mapping_offsets, - mappings); -} - - -// ------------------------------------------------------------------------------------------------ -void MeshGeometry::ReadVertexDataTangents(std::vector& tangents_out, const Scope& source, - const std::string& MappingInformationType, - const std::string& ReferenceInformationType) -{ - ResolveVertexDataArray(tangents_out,source,MappingInformationType,ReferenceInformationType, - "Tangent", - "TangentIndex", - vertices.size(), - mapping_counts, - mapping_offsets, - mappings); -} - - -// ------------------------------------------------------------------------------------------------ -void MeshGeometry::ReadVertexDataBinormals(std::vector& binormals_out, const Scope& source, - const std::string& MappingInformationType, - const std::string& ReferenceInformationType) -{ - ResolveVertexDataArray(binormals_out,source,MappingInformationType,ReferenceInformationType, - "Binormal", - "BinormalIndex", - vertices.size(), - mapping_counts, - mapping_offsets, - mappings); -} - -// ------------------------------------------------------------------------------------------------ -void MeshGeometry::ReadVertexDataMaterials(std::vector& materials_out, const Scope& source, - const std::string& MappingInformationType, - const std::string& ReferenceInformationType) -{ - const size_t face_count = faces.size(); - ai_assert(face_count); - - // 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")); - - if (MappingInformationType == "AllSame") { - // easy - same material for all faces - if (materials_out.empty()) { - FBXImporter::LogError(Formatter::format("expected material index, ignoring")); - return; - } - else if (materials_out.size() > 1) { - FBXImporter::LogWarn(Formatter::format("expected only a single material index, ignoring all except the first one")); - materials_out.clear(); - } - - materials.assign(vertices.size(),materials_out[0]); - } - else if (MappingInformationType == "ByPolygon" && ReferenceInformationType == "IndexToDirect") { - materials.resize(face_count); - - if(materials_out.size() != face_count) { - FBXImporter::LogError(Formatter::format("length of input data unexpected for ByPolygon mapping: ") - << materials_out.size() << ", expected " << face_count - ); - return; - } - } - else { - FBXImporter::LogError(Formatter::format("ignoring material assignments, access type not implemented: ") - << MappingInformationType << "," << ReferenceInformationType); - } -} - // ------------------------------------------------------------------------------------------------ Document::Document(const Parser& parser, const ImportSettings& settings) diff --git a/code/FBXDocumentUtil.h b/code/FBXDocumentUtil.h new file mode 100644 index 000000000..631560c3d --- /dev/null +++ b/code/FBXDocumentUtil.h @@ -0,0 +1,93 @@ +/* +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.h + * @brief FBX internal utilities used by the DOM reading code + */ +#ifndef INCLUDED_AI_FBX_DOCUMENT_UTIL_H +#define INCLUDED_AI_FBX_DOCUMENT_UTIL_H + +namespace Assimp { +namespace FBX { +namespace Util { + +void DOMError(const std::string& message, const Token& token); +void DOMError(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& out, const Element& el); + +// read an array of color4 tuples +void ReadVectorDataArray(std::vector& out, const Element& el); + +// read an array of float2 tuples +void ReadVectorDataArray(std::vector& out, const Element& el); + +// read an array of ints +void ReadVectorDataArray(std::vector& out, const Element& el); + +// read an array of uints +void ReadVectorDataArray(std::vector& out, const Element& el); + +} //!Util +} //!FBX +} //!Assimp + +#endif diff --git a/code/FBXMeshGeometry.cpp b/code/FBXMeshGeometry.cpp new file mode 100644 index 000000000..479f40338 --- /dev/null +++ b/code/FBXMeshGeometry.cpp @@ -0,0 +1,493 @@ +/* +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 FBXMeshGeometry.cpp + * @brief FBX::MeshGeometry implementation + */ +#include "AssimpPCH.h" + +#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER + +#include "FBXParser.h" +#include "FBXDocument.h" +#include "FBXImporter.h" +#include "FBXImportSettings.h" +#include "FBXDocumentUtil.h" + + +namespace Assimp { +namespace FBX { + + using namespace Util; + +// ------------------------------------------------------------------------------------------------ +MeshGeometry::MeshGeometry(const Element& element, const std::string& name, const ImportSettings& settings) +: 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 = GetRequiredElement(*sc,"Vertices",&element); + const Element& PolygonVertexIndex = GetRequiredElement(*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"); + + std::vector tempVerts; + ReadVectorDataArray(tempVerts,Vertices); + + if(tempVerts.empty()) { + FBXImporter::LogWarn("encountered mesh with no vertices"); + return; + } + + std::vector tempFaces; + ReadVectorDataArray(tempFaces,PolygonVertexIndex); + + if(tempFaces.empty()) { + FBXImporter::LogWarn("encountered mesh with no faces"); + return; + } + + vertices.reserve(tempFaces.size()); + faces.reserve(tempFaces.size() / 3); + + mapping_offsets.resize(tempVerts.size()); + mapping_counts.resize(tempVerts.size(),0); + mappings.resize(tempFaces.size()); + + const size_t vertex_count = tempVerts.size(); + + // generate output vertices, computing an adjacency table to + // preserve the mapping from fbx indices to *this* indexing. + unsigned int count = 0; + BOOST_FOREACH(int index, tempFaces) { + const int absi = index < 0 ? (-index - 1) : index; + if(static_cast(absi) >= vertex_count) { + DOMError("polygon vertex index out of range",&PolygonVertexIndex); + } + + vertices.push_back(tempVerts[absi]); + ++count; + + ++mapping_counts[absi]; + + if (index < 0) { + faces.push_back(count); + count = 0; + } + } + + unsigned int cursor = 0; + for (size_t i = 0, e = tempVerts.size(); i < e; ++i) { + mapping_offsets[i] = cursor; + cursor += mapping_counts[i]; + + mapping_counts[i] = 0; + } + + cursor = 0; + BOOST_FOREACH(int index, tempFaces) { + const int absi = index < 0 ? (-index - 1) : index; + mappings[mapping_offsets[absi] + mapping_counts[absi]++] = cursor; + } + + // if settings.readAllLayers is true: + // * read all layers, try to load as many vertex channels as possible + // if settings.readAllLayers is false: + // * read only the layer with index 0, but warn about any further layers + for (ElementMap::const_iterator it = Layer.first; it != Layer.second; ++it) { + const TokenList& tokens = (*it).second->Tokens(); + + const char* err; + const int index = ParseTokenAsInt(*tokens[0], err); + if(err) { + DOMError(err,&element); + } + + if(settings.readAllLayers || index == 0) { + const Scope& layer = GetRequiredScope(*(*it).second); + ReadLayer(layer); + } + else { + FBXImporter::LogWarn("ignoring additional geometry layers"); + } + } +} + + +// ------------------------------------------------------------------------------------------------ +MeshGeometry::~MeshGeometry() +{ + +} + + +// ------------------------------------------------------------------------------------------------ +void MeshGeometry::ReadLayer(const Scope& layer) +{ + const ElementCollection& LayerElement = layer.GetCollection("LayerElement"); + for (ElementMap::const_iterator eit = LayerElement.first; eit != LayerElement.second; ++eit) { + const Scope& elayer = GetRequiredScope(*(*eit).second); + + ReadLayerElement(elayer); + } +} + + +// ------------------------------------------------------------------------------------------------ +void MeshGeometry::ReadLayerElement(const Scope& layerElement) +{ + const Element& Type = GetRequiredElement(layerElement,"Type"); + const Element& TypedIndex = GetRequiredElement(layerElement,"TypedIndex"); + + const std::string& type = ParseTokenAsString(GetRequiredToken(Type,0)); + const int typedIndex = ParseTokenAsInt(GetRequiredToken(TypedIndex,0)); + + const Scope& top = GetRequiredScope(element); + const ElementCollection candidates = top.GetCollection(type); + + for (ElementMap::const_iterator it = candidates.first; it != candidates.second; ++it) { + const int index = ParseTokenAsInt(GetRequiredToken(*(*it).second,0)); + if(index == typedIndex) { + ReadVertexData(type,typedIndex,GetRequiredScope(*(*it).second)); + return; + } + } + + FBXImporter::LogError(Formatter::format("failed to resolve vertex layer element: ") + << type << ", index: " << typedIndex); +} + + +// ------------------------------------------------------------------------------------------------ +void MeshGeometry::ReadVertexData(const std::string& type, int index, const Scope& source) +{ + const std::string& MappingInformationType = ParseTokenAsString(GetRequiredToken( + GetRequiredElement(source,"MappingInformationType"),0) + ); + + const std::string& ReferenceInformationType = ParseTokenAsString(GetRequiredToken( + GetRequiredElement(source,"ReferenceInformationType"),0) + ); + + if (type == "LayerElementUV") { + if(index >= AI_MAX_NUMBER_OF_TEXTURECOORDS) { + FBXImporter::LogError(Formatter::format("ignoring UV layer, maximum number of UV channels exceeded: ") + << index << " (limit is " << AI_MAX_NUMBER_OF_TEXTURECOORDS << ")" ); + return; + } + + ReadVertexDataUV(uvs[index],source, + MappingInformationType, + ReferenceInformationType + ); + } + else if (type == "LayerElementMaterial") { + if (materials.size() > 0) { + FBXImporter::LogError("ignoring additional material layer"); + return; + } + + ReadVertexDataMaterials(materials,source, + MappingInformationType, + ReferenceInformationType + ); + } + else if (type == "LayerElementNormal") { + if (normals.size() > 0) { + FBXImporter::LogError("ignoring additional normal layer"); + return; + } + + ReadVertexDataNormals(normals,source, + MappingInformationType, + ReferenceInformationType + ); + } + else if (type == "LayerElementTangent") { + if (tangents.size() > 0) { + FBXImporter::LogError("ignoring additional tangent layer"); + return; + } + + ReadVertexDataTangents(tangents,source, + MappingInformationType, + ReferenceInformationType + ); + } + else if (type == "LayerElementBinormal") { + if (binormals.size() > 0) { + FBXImporter::LogError("ignoring additional binormal layer"); + return; + } + + ReadVertexDataBinormals(binormals,source, + MappingInformationType, + ReferenceInformationType + ); + } + else if (type == "LayerElementColor") { + if(index >= AI_MAX_NUMBER_OF_COLOR_SETS) { + FBXImporter::LogError(Formatter::format("ignoring vertex color layer, maximum number of color sets exceeded: ") + << index << " (limit is " << AI_MAX_NUMBER_OF_COLOR_SETS << ")" ); + return; + } + + ReadVertexDataColors(colors[index],source, + MappingInformationType, + ReferenceInformationType + ); + } +} + + +// ------------------------------------------------------------------------------------------------ +// 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 +void ResolveVertexDataArray(std::vector& 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& mapping_counts, + const std::vector& mapping_offsets, + const std::vector& mappings) +{ + std::vector 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); + + std::vector uvIndices; + ReadVectorDataArray(uvIndices,GetRequiredElement(source,indexDataElementName)); + + 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(uvIndices[i]) >= tempUV.size()) { + DOMError("index out of range",&GetRequiredElement(source,indexDataElementName)); + } + data_out[mappings[j]] = tempUV[uvIndices[i]]; + } + } + } + else if (MappingInformationType == "ByPolygonVertex" && ReferenceInformationType == "Direct") { + if (tempUV.size() != vertex_count) { + FBXImporter::LogError(Formatter::format("length of input data unexpected for ByPolygon mapping: ") + << tempUV.size() << ", expected " << vertex_count + ); + return; + } + + data_out.swap(tempUV); + } + else if (MappingInformationType == "ByPolygonVertex" && ReferenceInformationType == "IndexToDirect") { + data_out.resize(vertex_count); + + std::vector uvIndices; + ReadVectorDataArray(uvIndices,GetRequiredElement(source,indexDataElementName)); + + if (uvIndices.size() != vertex_count) { + FBXImporter::LogError("length of input data unexpected for ByPolygonVertex mapping"); + return; + } + + unsigned int next = 0; + BOOST_FOREACH(int i, uvIndices) { + if(static_cast(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, access type not implemented: ") + << MappingInformationType << "," << ReferenceInformationType); + } +} + +// ------------------------------------------------------------------------------------------------ +void MeshGeometry::ReadVertexDataNormals(std::vector& 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& 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); +} + + +// ------------------------------------------------------------------------------------------------ +void MeshGeometry::ReadVertexDataColors(std::vector& colors_out, const Scope& source, + const std::string& MappingInformationType, + const std::string& ReferenceInformationType) +{ + ResolveVertexDataArray(colors_out,source,MappingInformationType,ReferenceInformationType, + "Color", + "ColorIndex", + vertices.size(), + mapping_counts, + mapping_offsets, + mappings); +} + + +// ------------------------------------------------------------------------------------------------ +void MeshGeometry::ReadVertexDataTangents(std::vector& tangents_out, const Scope& source, + const std::string& MappingInformationType, + const std::string& ReferenceInformationType) +{ + ResolveVertexDataArray(tangents_out,source,MappingInformationType,ReferenceInformationType, + "Tangent", + "TangentIndex", + vertices.size(), + mapping_counts, + mapping_offsets, + mappings); +} + + +// ------------------------------------------------------------------------------------------------ +void MeshGeometry::ReadVertexDataBinormals(std::vector& binormals_out, const Scope& source, + const std::string& MappingInformationType, + const std::string& ReferenceInformationType) +{ + ResolveVertexDataArray(binormals_out,source,MappingInformationType,ReferenceInformationType, + "Binormal", + "BinormalIndex", + vertices.size(), + mapping_counts, + mapping_offsets, + mappings); +} + + +// ------------------------------------------------------------------------------------------------ +void MeshGeometry::ReadVertexDataMaterials(std::vector& materials_out, const Scope& source, + const std::string& MappingInformationType, + const std::string& ReferenceInformationType) +{ + const size_t face_count = faces.size(); + ai_assert(face_count); + + // 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")); + + if (MappingInformationType == "AllSame") { + // easy - same material for all faces + if (materials_out.empty()) { + FBXImporter::LogError(Formatter::format("expected material index, ignoring")); + return; + } + else if (materials_out.size() > 1) { + FBXImporter::LogWarn(Formatter::format("expected only a single material index, ignoring all except the first one")); + materials_out.clear(); + } + + materials.assign(vertices.size(),materials_out[0]); + } + else if (MappingInformationType == "ByPolygon" && ReferenceInformationType == "IndexToDirect") { + materials.resize(face_count); + + if(materials_out.size() != face_count) { + FBXImporter::LogError(Formatter::format("length of input data unexpected for ByPolygon mapping: ") + << materials_out.size() << ", expected " << face_count + ); + return; + } + } + else { + FBXImporter::LogError(Formatter::format("ignoring material assignments, access type not implemented: ") + << MappingInformationType << "," << ReferenceInformationType); + } +} + +} // !FBX +} // !Assimp + +#endif + diff --git a/workspaces/vc9/assimp.vcproj b/workspaces/vc9/assimp.vcproj index 4972bb3b5..817304dcb 100644 --- a/workspaces/vc9/assimp.vcproj +++ b/workspaces/vc9/assimp.vcproj @@ -1,7 +1,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + @@ -2087,6 +2091,10 @@ RelativePath="..\..\code\FBXImportSettings.h" > + + @@ -2247,14 +2255,6 @@ UsePrecompiledHeader="0" /> - - - @@ -2279,14 +2279,6 @@ UsePrecompiledHeader="0" /> - - - @@ -2311,6 +2303,22 @@ UsePrecompiledHeader="0" /> + + + + + + @@ -2445,14 +2453,6 @@ PrecompiledHeaderThrough="AssimpPCH.h" /> - - - @@ -2480,14 +2480,6 @@ PrecompiledHeaderThrough="AssimpPCH.h" /> - - - @@ -2515,6 +2507,22 @@ PrecompiledHeaderThrough="AssimpPCH.h" /> + + + + + + @@ -2822,14 +2830,6 @@ UsePrecompiledHeader="0" /> - - - @@ -2838,14 +2838,6 @@ UsePrecompiledHeader="0" /> - - - @@ -2854,14 +2846,6 @@ UsePrecompiledHeader="0" /> - - - @@ -2870,14 +2854,6 @@ UsePrecompiledHeader="0" /> - - - @@ -2886,14 +2862,6 @@ UsePrecompiledHeader="0" /> - - - @@ -2902,14 +2870,6 @@ UsePrecompiledHeader="0" /> - - - @@ -2919,7 +2879,7 @@ /> + + + + + + + + + + + + + + + + + + - - - @@ -2982,14 +2982,6 @@ UsePrecompiledHeader="0" /> - - - @@ -2998,14 +2990,6 @@ UsePrecompiledHeader="0" /> - - - @@ -3014,14 +2998,6 @@ UsePrecompiledHeader="0" /> - - - @@ -3030,14 +3006,6 @@ UsePrecompiledHeader="0" /> - - - @@ -3046,14 +3014,6 @@ UsePrecompiledHeader="0" /> - - - @@ -3063,7 +3023,7 @@ /> + + + + + + + + + + + + + + + + + + - - - @@ -3114,14 +3114,6 @@ UsePrecompiledHeader="0" /> - - - @@ -3130,14 +3122,6 @@ UsePrecompiledHeader="0" /> - - - @@ -3146,14 +3130,6 @@ UsePrecompiledHeader="0" /> - - - @@ -3162,14 +3138,6 @@ UsePrecompiledHeader="0" /> - - - @@ -3178,14 +3146,6 @@ UsePrecompiledHeader="0" /> - - - @@ -3195,7 +3155,7 @@ /> + + + + + + + + + + + + + + + + + + - - - @@ -3254,14 +3254,6 @@ UsePrecompiledHeader="0" /> - - - @@ -3270,14 +3262,6 @@ UsePrecompiledHeader="0" /> - - - @@ -3286,14 +3270,6 @@ UsePrecompiledHeader="0" /> - - - @@ -3302,14 +3278,6 @@ UsePrecompiledHeader="0" /> - - - @@ -3318,14 +3286,6 @@ UsePrecompiledHeader="0" /> - - - @@ -3335,7 +3295,7 @@ /> + + + + + + + + + + + + + + + + + + - - - @@ -3394,14 +3394,6 @@ UsePrecompiledHeader="0" /> - - - @@ -3410,14 +3402,6 @@ UsePrecompiledHeader="0" /> - - - @@ -3426,14 +3410,6 @@ UsePrecompiledHeader="0" /> - - - @@ -3442,14 +3418,6 @@ UsePrecompiledHeader="0" /> - - - @@ -3458,14 +3426,6 @@ UsePrecompiledHeader="0" /> - - - @@ -3475,7 +3435,7 @@ /> + + + + + + + + + + + + + + + + + + - - - @@ -3530,14 +3530,6 @@ UsePrecompiledHeader="0" /> - - - @@ -3546,14 +3538,6 @@ UsePrecompiledHeader="0" /> - - - @@ -3562,14 +3546,6 @@ UsePrecompiledHeader="0" /> - - - @@ -3578,14 +3554,6 @@ UsePrecompiledHeader="0" /> - - - @@ -3594,14 +3562,6 @@ UsePrecompiledHeader="0" /> - - - @@ -3611,7 +3571,7 @@ /> + + + + + + + + + + + + + + + + + + - - - @@ -3666,14 +3666,6 @@ UsePrecompiledHeader="0" /> - - - @@ -3682,14 +3674,6 @@ UsePrecompiledHeader="0" /> - - - @@ -3698,14 +3682,6 @@ UsePrecompiledHeader="0" /> - - - @@ -3714,14 +3690,6 @@ UsePrecompiledHeader="0" /> - - - @@ -3730,14 +3698,6 @@ UsePrecompiledHeader="0" /> - - - @@ -3747,7 +3707,7 @@ /> + + + + + + + + + + + + + + + + + + - - - @@ -3802,14 +3802,6 @@ UsePrecompiledHeader="0" /> - - - @@ -3818,14 +3810,6 @@ UsePrecompiledHeader="0" /> - - - @@ -3834,14 +3818,6 @@ UsePrecompiledHeader="0" /> - - - @@ -3850,14 +3826,6 @@ UsePrecompiledHeader="0" /> - - - @@ -3866,14 +3834,6 @@ UsePrecompiledHeader="0" /> - - - @@ -3883,7 +3843,7 @@ /> + + + + + + + + + + + + + + + + + + - - - @@ -3950,14 +3950,6 @@ UsePrecompiledHeader="0" /> - - - @@ -3966,14 +3958,6 @@ UsePrecompiledHeader="0" /> - - - @@ -3982,14 +3966,6 @@ UsePrecompiledHeader="0" /> - - - @@ -3998,14 +3974,6 @@ UsePrecompiledHeader="0" /> - - - @@ -4014,14 +3982,6 @@ UsePrecompiledHeader="0" /> - - - @@ -4031,7 +3991,7 @@ /> + + + + + + + + + + + + + + + + + + - - - @@ -4090,14 +4090,6 @@ UsePrecompiledHeader="0" /> - - - @@ -4106,14 +4098,6 @@ UsePrecompiledHeader="0" /> - - - @@ -4122,14 +4106,6 @@ UsePrecompiledHeader="0" /> - - - @@ -4138,14 +4114,6 @@ UsePrecompiledHeader="0" /> - - - @@ -4154,14 +4122,6 @@ UsePrecompiledHeader="0" /> - - - @@ -4171,7 +4131,7 @@ /> + + + + + + + + + + + + + + + + + + - - - @@ -4230,14 +4230,6 @@ UsePrecompiledHeader="0" /> - - - @@ -4246,14 +4238,6 @@ UsePrecompiledHeader="0" /> - - - @@ -4262,14 +4246,6 @@ UsePrecompiledHeader="0" /> - - - @@ -4278,14 +4254,6 @@ UsePrecompiledHeader="0" /> - - - @@ -4294,14 +4262,6 @@ UsePrecompiledHeader="0" /> - - - @@ -4311,7 +4271,7 @@ /> + + + + + + + + + + + + + + + + + + - - - @@ -4366,14 +4366,6 @@ UsePrecompiledHeader="0" /> - - - @@ -4382,14 +4374,6 @@ UsePrecompiledHeader="0" /> - - - @@ -4398,14 +4382,6 @@ UsePrecompiledHeader="0" /> - - - @@ -4414,14 +4390,6 @@ UsePrecompiledHeader="0" /> - - - @@ -4430,14 +4398,6 @@ UsePrecompiledHeader="0" /> - - - @@ -4447,7 +4407,7 @@ /> + + + + + + + + + + + + + + + + + + - - - @@ -4506,14 +4506,6 @@ UsePrecompiledHeader="0" /> - - - @@ -4522,14 +4514,6 @@ UsePrecompiledHeader="0" /> - - - @@ -4538,14 +4522,6 @@ UsePrecompiledHeader="0" /> - - - @@ -4554,14 +4530,6 @@ UsePrecompiledHeader="0" /> - - - @@ -4570,14 +4538,6 @@ UsePrecompiledHeader="0" /> - - - @@ -4587,7 +4547,7 @@ /> + + + + + + + + + + + + + + + + + + - - - @@ -4642,14 +4642,6 @@ UsePrecompiledHeader="0" /> - - - @@ -4658,14 +4650,6 @@ UsePrecompiledHeader="0" /> - - - @@ -4674,14 +4658,6 @@ UsePrecompiledHeader="0" /> - - - @@ -4690,14 +4666,6 @@ UsePrecompiledHeader="0" /> - - - @@ -4706,14 +4674,6 @@ UsePrecompiledHeader="0" /> - - - @@ -4723,7 +4683,7 @@ /> + + + + + + + + + + + + + + + + + + - - - @@ -4778,14 +4778,6 @@ UsePrecompiledHeader="0" /> - - - @@ -4794,14 +4786,6 @@ UsePrecompiledHeader="0" /> - - - @@ -4810,14 +4794,6 @@ UsePrecompiledHeader="0" /> - - - @@ -4826,14 +4802,6 @@ UsePrecompiledHeader="0" /> - - - @@ -4842,14 +4810,6 @@ UsePrecompiledHeader="0" /> - - - @@ -4859,7 +4819,7 @@ /> + + + + + + + + + + + + + + + + + + - - - @@ -4922,14 +4922,6 @@ UsePrecompiledHeader="0" /> - - - @@ -4938,14 +4930,6 @@ UsePrecompiledHeader="0" /> - - - @@ -4954,14 +4938,6 @@ UsePrecompiledHeader="0" /> - - - @@ -4970,14 +4946,6 @@ UsePrecompiledHeader="0" /> - - - @@ -4986,14 +4954,6 @@ UsePrecompiledHeader="0" /> - - - @@ -5003,7 +4963,7 @@ /> + + + + + + + + + + + + + + + + + +