From 8ee4d08d8711fc09a1edbe14ad8243c4657defc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Tue, 4 Mar 2014 21:24:45 +0100 Subject: [PATCH] ObjImporter: the indices are actually global to whole file. There just isn't any sane and easily parsable format. --- src/MagnumPlugins/ObjImporter/ObjImporter.cpp | 99 ++++++++++++------- .../ObjImporter/Test/missingData.obj | 8 +- .../ObjImporter/Test/moreMeshes.obj | 18 ++-- .../ObjImporter/Test/optionalCoordinates.obj | 6 +- .../ObjImporter/Test/wrongIndexCount.obj | 6 +- .../ObjImporter/Test/wrongNumberCount.obj | 10 +- .../ObjImporter/Test/wrongNumbers.obj | 6 +- 7 files changed, 96 insertions(+), 57 deletions(-) diff --git a/src/MagnumPlugins/ObjImporter/ObjImporter.cpp b/src/MagnumPlugins/ObjImporter/ObjImporter.cpp index 1d223fcae..dbcb66361 100644 --- a/src/MagnumPlugins/ObjImporter/ObjImporter.cpp +++ b/src/MagnumPlugins/ObjImporter/ObjImporter.cpp @@ -43,7 +43,7 @@ namespace Magnum { namespace Trade { struct ObjImporter::File { std::unordered_map meshesForName; std::vector meshNames; - std::vector> meshes; + std::vector> meshes; std::unique_ptr in; }; @@ -115,11 +115,20 @@ void ObjImporter::doOpenData(Containers::ArrayReference dat } void ObjImporter::parseMeshNames() { - bool hasData = false; - std::string name; - std::streampos begin = 0; + /* First mesh starts at the beginning, its indices start from 1. The end + offset will be updated to proper value later. */ + UnsignedInt positionIndexOffset = 1; + UnsignedInt normalIndexOffset = 1; + UnsignedInt textureCoordinateIndexOffset = 1; + _file->meshes.emplace_back(0, 0, positionIndexOffset, normalIndexOffset, textureCoordinateIndexOffset); + + /* The first mesh doesn't have name by default but we might find it later, + so we need to track whether there are any data before first name */ + bool thisIsFirstMeshAndItHasNoData = true; + _file->meshNames.emplace_back(); + while(_file->in->good()) { - /* The previous object ends at the beginning of this line */ + /* The previous object might end at the beginning of this line */ const std::streampos end = _file->in->tellg(); /* Comment line */ @@ -132,31 +141,56 @@ void ObjImporter::parseMeshNames() { std::string keyword; *_file->in >> keyword; - /* Object name */ + /* Mesh name */ if(keyword == "o") { - /* If there was any previous object, this is name of new object, - save the previous one */ - if(hasData) { + std::string name; + std::getline(*_file->in, name); + name = Utility::String::trim(name); + + /* This is the name of first mesh */ + if(thisIsFirstMeshAndItHasNoData) { + thisIsFirstMeshAndItHasNoData = false; + + /* Update its name and add it to name map */ + if(!name.empty()) _file->meshesForName.emplace(name, _file->meshes.size() - 1); + _file->meshNames.back() = std::move(name); + + /* Update its begin offset to be more precise */ + std::get<0>(_file->meshes.back()) = _file->in->tellg(); + + /* Otherwise this is a name of new mesh */ + } else { + /* Set end of the previous one */ + std::get<1>(_file->meshes.back()) = end; + + /* Save name and offset of the new one. The end offset will be + updated later. */ if(!name.empty()) _file->meshesForName.emplace(name, _file->meshes.size()); _file->meshNames.emplace_back(std::move(name)); - _file->meshes.emplace_back(begin, end); - - /* Otherwise it's the name of first object (there weren't any data - before) */ - } else hasData = true; + _file->meshes.emplace_back(_file->in->tellg(), 0, positionIndexOffset, textureCoordinateIndexOffset, normalIndexOffset); + } - /* Get name of new object, the object then starts at the next line */ - std::getline(*_file->in, name); - name = Utility::String::trim(name); - begin = _file->in->tellg(); continue; - } - /* If there are any data before the first name, it means that the first - object can be unnamed */ - if(!hasData) for(const std::string& data: {"v", "vt", "vn", "p", "l", "f"}) { + /* If there are any data/indices before the first name, it means that + the first object is unnamed. We need to check for them. */ + + /* Vertex data, update index offset for the following meshes */ + } else if(keyword == "v") { + ++positionIndexOffset; + thisIsFirstMeshAndItHasNoData = false; + } else if(keyword == "vt") { + ++textureCoordinateIndexOffset; + thisIsFirstMeshAndItHasNoData = false; + } else if(keyword == "vn") { + ++normalIndexOffset; + thisIsFirstMeshAndItHasNoData = false; + + /* Index data, just mark that we found something for first unnamed + object */ + } else if(thisIsFirstMeshAndItHasNoData) for(const std::string& data: {"p", "l", "f"}) { if(keyword == data) { - hasData = true; + thisIsFirstMeshAndItHasNoData = false; break; } } @@ -165,12 +199,10 @@ void ObjImporter::parseMeshNames() { ignoreLine(*_file->in); } - /* Add also the last object */ + /* Set end of the last object */ _file->in->clear(); _file->in->seekg(0, std::ios::end); - if(!name.empty()) _file->meshesForName.emplace(name, _file->meshes.size()); - _file->meshNames.emplace_back(std::move(name)); - _file->meshes.emplace_back(begin, _file->in->tellg()); + std::get<1>(_file->meshes.back()) = _file->in->tellg(); } UnsignedInt ObjImporter::doMesh3DCount() const { return _file->meshes.size(); } @@ -185,9 +217,10 @@ std::string ObjImporter::doMesh3DName(UnsignedInt id) { } std::optional ObjImporter::doMesh3D(UnsignedInt id) { - /* Seek the file */ + /* Seek the file, set mesh parsing parameters */ std::streampos begin, end; - std::tie(begin, end) = _file->meshes[id]; + UnsignedInt positionIndexOffset, textureCoordinateIndexOffset, normalIndexOffset; + std::tie(begin, end, positionIndexOffset, textureCoordinateIndexOffset, normalIndexOffset) = _file->meshes[id]; _file->in->seekg(begin); std::optional primitive; @@ -311,18 +344,16 @@ std::optional ObjImporter::doMesh3D(UnsignedInt id) { return std::nullopt; } - /* Indices in OBJ file start from 1 */ - /* Position indices */ - positionIndices.push_back(std::stoul(indices[0])-1); + positionIndices.push_back(std::stoul(indices[0]) - positionIndexOffset); /* Texture coordinates */ if(indices.size() == 2 || (indices.size() == 3 && !indices[1].empty())) - textureCoordinateIndices.push_back(std::stoul(indices[1])-1); + textureCoordinateIndices.push_back(std::stoul(indices[1]) - textureCoordinateIndexOffset); /* Normal indices */ if(indices.size() == 3) - normalIndices.push_back(std::stoul(indices[2])-1); + normalIndices.push_back(std::stoul(indices[2]) - normalIndexOffset); } /* Ignore unsupported keywords, error out on unknown keywords */ diff --git a/src/MagnumPlugins/ObjImporter/Test/missingData.obj b/src/MagnumPlugins/ObjImporter/Test/missingData.obj index e86b403bc..554d520b9 100644 --- a/src/MagnumPlugins/ObjImporter/Test/missingData.obj +++ b/src/MagnumPlugins/ObjImporter/Test/missingData.obj @@ -6,18 +6,18 @@ v 1 2 3 o MissingNormalData v 1 2 3 -p 1//1 +p 3//3 o MissingNormalIndices v 1 2 3 vn 1 2 3 -p 1 +p 4 o MissingTextureData v 1 2 3 -p 1/1 +p 5/1 o MissingTextureIndices v 1 2 3 vt 1 2 -p 1 +p 6 diff --git a/src/MagnumPlugins/ObjImporter/Test/moreMeshes.obj b/src/MagnumPlugins/ObjImporter/Test/moreMeshes.obj index 256cc06d8..e4820d5b9 100644 --- a/src/MagnumPlugins/ObjImporter/Test/moreMeshes.obj +++ b/src/MagnumPlugins/ObjImporter/Test/moreMeshes.obj @@ -2,20 +2,26 @@ o PointMesh v 0.5 2 3 v 0 1.5 1 -p 1 -p 2 +vn 0.5 2 3 +vn 0 1.5 1 +p 1//1 +p 2//2 # Lines o LineMesh v 0.5 2 3 v 0 1.5 1 -l 1 2 -l 2 1 +vt 0.5 2 +vt 0 1.5 +l 3/1 4/2 +l 4/2 3/1 # Triangles o TriangleMesh v 0.5 2 3 v 0 1.5 1 v 2 3 5.5 -f 1 2 3 -f 3 2 1 +vt 0.5 2 +vn 0.5 2 3 +f 5/3/3 6/3/3 7/3/3 +f 7/3/3 6/3/3 5/3/3 diff --git a/src/MagnumPlugins/ObjImporter/Test/optionalCoordinates.obj b/src/MagnumPlugins/ObjImporter/Test/optionalCoordinates.obj index 6fe88d715..7e9132465 100644 --- a/src/MagnumPlugins/ObjImporter/Test/optionalCoordinates.obj +++ b/src/MagnumPlugins/ObjImporter/Test/optionalCoordinates.obj @@ -5,13 +5,13 @@ p 1 o SupportedTextureW v 1.5 2 3 vt 0.5 0.7 0.0 -p 1/1 +p 2/1 o UnsupportedPositionW v 1.5 2 3 0.8 -p 1 +p 3 o UnsupportedTextureW v 1.5 2 3 vt 0.5 0.7 0.5 -p 1/1 +p 4/2 diff --git a/src/MagnumPlugins/ObjImporter/Test/wrongIndexCount.obj b/src/MagnumPlugins/ObjImporter/Test/wrongIndexCount.obj index 960ef3c10..0a98d1573 100644 --- a/src/MagnumPlugins/ObjImporter/Test/wrongIndexCount.obj +++ b/src/MagnumPlugins/ObjImporter/Test/wrongIndexCount.obj @@ -8,6 +8,6 @@ p 1//1 o ShortTextureIndices v 1 2 3 vt 1 2 -p 1/1 -p 1 -p 1/1 +p 2/2 +p 2 +p 2/2 diff --git a/src/MagnumPlugins/ObjImporter/Test/wrongNumberCount.obj b/src/MagnumPlugins/ObjImporter/Test/wrongNumberCount.obj index c0797fb47..4bfab647f 100644 --- a/src/MagnumPlugins/ObjImporter/Test/wrongNumberCount.obj +++ b/src/MagnumPlugins/ObjImporter/Test/wrongNumberCount.obj @@ -10,20 +10,20 @@ v 0.5 1 2 0.0 3.5 o InvalidIndices v 1 2 3 -p 1/1/1/1 +p 4/1/1/1 o WrongPointIndices v 1 2 3 -p 1 1 +p 5 5 o WrongLineIndices v 1 2 3 -l 1 +l 6 o WrongTriangleIndices v 1 2 3 -f 1 1 +f 7 7 o PolygonIndices v 1 2 3 -f 1 1 1 1 +f 8 8 8 8 diff --git a/src/MagnumPlugins/ObjImporter/Test/wrongNumbers.obj b/src/MagnumPlugins/ObjImporter/Test/wrongNumbers.obj index c795997c2..ce6589a05 100644 --- a/src/MagnumPlugins/ObjImporter/Test/wrongNumbers.obj +++ b/src/MagnumPlugins/ObjImporter/Test/wrongNumbers.obj @@ -8,12 +8,14 @@ p bleh o PositionIndexOutOfRange v 1 0 2 -p 2 +# Should be 3 +p 1 o TextureIndexOutOfRange v 1 0 2 vt 0 1 -p 1/2 +# Should be 4/1 +p 4/2 o ZeroIndex v 1 0 2