diff --git a/doc/changelog.dox b/doc/changelog.dox index 34c758338..1fdb2e31b 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -1097,7 +1097,8 @@ See also: consistent with @ref Trade::SceneData::findFieldId(). - Added @ref Trade::MeshData::attributeId() that returns ID of an attribute in a set of attributes of the same name -- @relativeref{Trade,ObjImporter} now supports quads and negative indices +- @relativeref{Trade,ObjImporter} now supports quads and negative indices and + is able to optionally skip index array merging on import - Added @ref Trade::TextureType::Texture1DArray, @relativeref{Trade::TextureType,Texture2DArray} and @relativeref{Trade::TextureType,CubeMapArray} in order to be able to diff --git a/src/MagnumPlugins/ObjImporter/ObjImporter.conf b/src/MagnumPlugins/ObjImporter/ObjImporter.conf index e69de29bb..7cbb1fb1f 100644 --- a/src/MagnumPlugins/ObjImporter/ObjImporter.conf +++ b/src/MagnumPlugins/ObjImporter/ObjImporter.conf @@ -0,0 +1,7 @@ +# [configuration_] +[configuration] +# Merge the per-attribute index arrays into a single index buffer. If disabled, +# the resulting mesh will be non-indexed, with vertex data duplicated according +# to per-attribute index arrays. +mergeIndexArrays=true +# [configuration_] diff --git a/src/MagnumPlugins/ObjImporter/ObjImporter.cpp b/src/MagnumPlugins/ObjImporter/ObjImporter.cpp index c5ba91e68..94cdb3bed 100644 --- a/src/MagnumPlugins/ObjImporter/ObjImporter.cpp +++ b/src/MagnumPlugins/ObjImporter/ObjImporter.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include "Magnum/Mesh.h" #include "Magnum/MeshTools/RemoveDuplicates.h" @@ -558,12 +559,20 @@ Containers::Optional ObjImporter::doMesh(const UnsignedInt id, Unsigne return Containers::NullOpt; } - /* Merge index arrays. If any of the attributes was not there, the whole - index array has zeros, not affecting the uniqueness in any way. */ - Containers::Array indexData{NoInit, indices.size()*sizeof(UnsignedInt)}; - const auto indexDataI = Containers::arrayCast(indexData); - const std::size_t vertexCount = MeshTools::removeDuplicatesInPlaceInto( - Containers::arrayCast<2, char>(arrayView(indices)), indexDataI); + /* Merge index arrays, unless disabled. If any of the attributes was not + there, the whole index array has zeros, not affecting the uniqueness in + any way. */ + Containers::Array indexData; + std::size_t vertexCount; + if(configuration().value("mergeIndexArrays")) { + indexData = Containers::Array{NoInit, indices.size()*sizeof(UnsignedInt)}; + const auto indexDataI = Containers::arrayCast(indexData); + vertexCount = MeshTools::removeDuplicatesInPlaceInto( + Containers::arrayCast<2, char>(arrayView(indices)), indexDataI); + + /* If merging was disabled, this behaves like if all index tuples were + unique. No other change needed. */ + } else vertexCount = indices.size(); /* Allocate attribute and vertex data */ std::size_t attributeCount = 1; @@ -609,8 +618,13 @@ Containers::Optional ObjImporter::doMesh(const UnsignedInt id, Unsigne } CORRADE_INTERNAL_ASSERT(offset == stride && attributeIndex == attributeCount); + /* If mergeIndexArrays was disabled, indexData is nullptr and the mesh is + not indexed */ + const auto meshIndices = indexData ? + Trade::MeshIndexData{MeshIndexType::UnsignedInt, indexData} : + Trade::MeshIndexData{}; return MeshData{*primitive, - Utility::move(indexData), Trade::MeshIndexData{indexDataI}, + Utility::move(indexData), meshIndices, Utility::move(vertexData), Utility::move(attributeData)}; } diff --git a/src/MagnumPlugins/ObjImporter/ObjImporter.h b/src/MagnumPlugins/ObjImporter/ObjImporter.h index ff7e6ed00..9bcacb0e7 100644 --- a/src/MagnumPlugins/ObjImporter/ObjImporter.h +++ b/src/MagnumPlugins/ObjImporter/ObjImporter.h @@ -101,9 +101,13 @@ information. @section Trade-ObjImporter-behavior Behavior and limitations Meshes are imported as @ref MeshPrimitive::Triangles with -@ref MeshIndexType::UnsignedInt indices, interleaved @ref VertexFormat::Vector3 -positions with optional @ref VertexFormat::Vector3 normals and -@ref VertexFormat::Vector2 texture coordinates, if present in the source file. +@ref VertexFormat::Vector3 positions interleaved with optional +@ref VertexFormat::Vector3 normals and @ref VertexFormat::Vector2 texture +coordinates, if present in the source file. By default the per-attribute index +arrays are merged into a single @ref MeshIndexType::UnsignedInt index buffer. +If you disable the @cb{.ini} mergeIndexArrays @ce @ref Trade-ObjImporter-configuration "configuration option", +the resulting mesh will be nonindexed, with the vertex data duplicated +according to per-attribute index arrays. Negative indices (where @cpp -1 @ce is the last position / texture coordinate / normal known at given point in the file, @cpp -2 @ce is the second-to-last, @@ -112,6 +116,16 @@ supported. Quads are converted to two triangles, higher-order polygons are not supported. Material properties are currently not supported. + +@section Trade-ObjImporter-configuration Plugin-specific configuration + +It's possible to tune various import options through @ref configuration(). See +below for all options and their default values: + +@snippet MagnumPlugins/ObjImporter/ObjImporter.conf configuration_ + +See @ref plugins-configuration for more information and an example showing how +to edit the configuration values. */ class MAGNUM_OBJIMPORTER_EXPORT ObjImporter: public AbstractImporter { public: diff --git a/src/MagnumPlugins/ObjImporter/Test/ObjImporterTest.cpp b/src/MagnumPlugins/ObjImporter/Test/ObjImporterTest.cpp index 4913470df..48db6406c 100644 --- a/src/MagnumPlugins/ObjImporter/Test/ObjImporterTest.cpp +++ b/src/MagnumPlugins/ObjImporter/Test/ObjImporterTest.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -56,6 +57,7 @@ struct ObjImporterTest: TestSuite::Tester { void meshNormals(); void meshTextureCoordinatesNormals(); + void meshNoMergeIndexArrays(); void meshNegativeIndices(); void meshQuads(); @@ -199,6 +201,7 @@ ObjImporterTest::ObjImporterTest() { &ObjImporterTest::meshNormals, &ObjImporterTest::meshTextureCoordinatesNormals, + &ObjImporterTest::meshNoMergeIndexArrays, &ObjImporterTest::meshNegativeIndices, &ObjImporterTest::meshQuads, @@ -455,6 +458,55 @@ void ObjImporterTest::meshTextureCoordinatesNormals() { TestSuite::Compare::Container); } +void ObjImporterTest::meshNoMergeIndexArrays() { + Containers::Pointer importer = _manager.instantiate("ObjImporter"); + importer->configuration().setValue("mergeIndexArrays", false); + CORRADE_VERIFY(importer->openFile(Utility::Path::join(OBJIMPORTER_TEST_DIR, "mesh-texture-coordinates-normals.obj"))); + CORRADE_COMPARE(importer->meshCount(), 1); + + /* Same as meshTextureCoordinatesNormals() but with the index array used + to duplicate the vertex data */ + + const Containers::Optional data = importer->mesh(0); + CORRADE_VERIFY(data); + CORRADE_VERIFY(!data->isIndexed()); + CORRADE_COMPARE(data->primitive(), MeshPrimitive::Lines); + CORRADE_COMPARE(data->attributeCount(), 3); + CORRADE_COMPARE_AS(data->attribute(MeshAttribute::Position), + Containers::arrayView({ + {0.5f, 2.0f, 3.0f}, + {0.0f, 1.5f, 1.0f}, + {0.5f, 2.0f, 3.0f}, + {0.0f, 1.5f, 1.0f}, + {0.0f, 1.5f, 1.0f}, + {0.5f, 2.0f, 3.0f}, + {0.0f, 1.5f, 1.0f}, + {0.5f, 2.0f, 3.0f}, + }), TestSuite::Compare::Container); + CORRADE_COMPARE_AS(data->attribute(MeshAttribute::TextureCoordinates), + Containers::arrayView({ + {1.0f, 0.5f}, + {1.0f, 0.5f}, + {0.5f, 1.0f}, + {0.5f, 1.0f}, + {1.0f, 0.5f}, + {1.0f, 0.5f}, + {0.5f, 1.0f}, + {0.5f, 1.0f}, + }), TestSuite::Compare::Container); + CORRADE_COMPARE_AS(data->attribute(MeshAttribute::Normal), + Containers::arrayView({ + {1.0f, 0.5f, 3.5f}, + {0.5f, 1.0f, 0.5f}, + {0.5f, 1.0f, 0.5f}, + {1.0f, 0.5f, 3.5f}, + {0.5f, 1.0f, 0.5f}, + {1.0f, 0.5f, 3.5f}, + {0.5f, 1.0f, 0.5f}, + {0.5f, 1.0f, 0.5f}, + }), TestSuite::Compare::Container); +} + void ObjImporterTest::meshNegativeIndices() { Containers::Pointer importer = _manager.instantiate("ObjImporter"); CORRADE_VERIFY(importer->openFile(Utility::Path::join(OBJIMPORTER_TEST_DIR, "mesh-negative-indices.obj")));