Browse Source

ObjImporter: the indices are actually global to whole file.

There just isn't any sane and easily parsable format.
pull/51/head
Vladimír Vondruš 12 years ago
parent
commit
8ee4d08d87
  1. 99
      src/MagnumPlugins/ObjImporter/ObjImporter.cpp
  2. 8
      src/MagnumPlugins/ObjImporter/Test/missingData.obj
  3. 18
      src/MagnumPlugins/ObjImporter/Test/moreMeshes.obj
  4. 6
      src/MagnumPlugins/ObjImporter/Test/optionalCoordinates.obj
  5. 6
      src/MagnumPlugins/ObjImporter/Test/wrongIndexCount.obj
  6. 10
      src/MagnumPlugins/ObjImporter/Test/wrongNumberCount.obj
  7. 6
      src/MagnumPlugins/ObjImporter/Test/wrongNumbers.obj

99
src/MagnumPlugins/ObjImporter/ObjImporter.cpp

@ -43,7 +43,7 @@ namespace Magnum { namespace Trade {
struct ObjImporter::File {
std::unordered_map<std::string, UnsignedInt> meshesForName;
std::vector<std::string> meshNames;
std::vector<std::pair<std::streampos, std::streampos>> meshes;
std::vector<std::tuple<std::streampos, std::streampos, UnsignedInt, UnsignedInt, UnsignedInt>> meshes;
std::unique_ptr<std::istream> in;
};
@ -115,11 +115,20 @@ void ObjImporter::doOpenData(Containers::ArrayReference<const unsigned char> 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<MeshData3D> 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<MeshPrimitive> primitive;
@ -311,18 +344,16 @@ std::optional<MeshData3D> 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 */

8
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

18
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

6
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

6
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

10
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

6
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

Loading…
Cancel
Save