diff --git a/src/Magnum/Trade/AbstractImporter.cpp b/src/Magnum/Trade/AbstractImporter.cpp index 337b8578e1..28439b2d7b 100644 --- a/src/Magnum/Trade/AbstractImporter.cpp +++ b/src/Magnum/Trade/AbstractImporter.cpp @@ -38,6 +38,7 @@ #include "Magnum/Trade/CameraData.h" #include "Magnum/Trade/ImageData.h" #include "Magnum/Trade/LightData.h" +#include "Magnum/Trade/MeshData.h" #include "Magnum/Trade/MeshData2D.h" #include "Magnum/Trade/MeshData3D.h" #include "Magnum/Trade/ObjectData2D.h" @@ -402,6 +403,38 @@ Containers::Pointer AbstractImporter::doObject3D(UnsignedInt) { CORRADE_ASSERT(false, "Trade::AbstractImporter::object3D(): not implemented", {}); } +UnsignedInt AbstractImporter::meshCount() const { + CORRADE_ASSERT(isOpened(), "Trade::AbstractImporter::meshCount(): no file opened", {}); + return doMeshCount(); +} + +UnsignedInt AbstractImporter::doMeshCount() const { return 0; } + +Int AbstractImporter::meshForName(const std::string& name) { + CORRADE_ASSERT(isOpened(), "Trade::AbstractImporter::meshForName(): no file opened", {}); + return doMeshForName(name); +} + +Int AbstractImporter::doMeshForName(const std::string&) { return -1; } + +std::string AbstractImporter::meshName(const UnsignedInt id) { + CORRADE_ASSERT(isOpened(), "Trade::AbstractImporter::meshName(): no file opened", {}); + CORRADE_ASSERT(id < doMeshCount(), "Trade::AbstractImporter::meshName(): index" << id << "out of range for" << doMeshCount() << "entries", {}); + return doMeshName(id); +} + +std::string AbstractImporter::doMeshName(UnsignedInt) { return {}; } + +Containers::Optional AbstractImporter::mesh(const UnsignedInt id) { + CORRADE_ASSERT(isOpened(), "Trade::AbstractImporter::mesh(): no file opened", {}); + CORRADE_ASSERT(id < doMeshCount(), "Trade::AbstractImporter::mesh(): index" << id << "out of range for" << doMeshCount() << "entries", {}); + return doMesh(id); +} + +Containers::Optional AbstractImporter::doMesh(UnsignedInt) { + CORRADE_ASSERT(false, "Trade::AbstractImporter::mesh(): not implemented", {}); +} + UnsignedInt AbstractImporter::mesh2DCount() const { CORRADE_ASSERT(isOpened(), "Trade::AbstractImporter::mesh2DCount(): no file opened", {}); return doMesh2DCount(); diff --git a/src/Magnum/Trade/AbstractImporter.h b/src/Magnum/Trade/AbstractImporter.h index ef9c3624a0..773ca8d25e 100644 --- a/src/Magnum/Trade/AbstractImporter.h +++ b/src/Magnum/Trade/AbstractImporter.h @@ -117,8 +117,8 @@ expose internal state through various accessors: imported by @ref image1D(), @ref image2D() or @ref image3D() - @ref LightData::importerState() can expose importer state for a light imported by @ref light() -- @ref MeshData3D::importerState() can expose importer state for a mesh - imported by @ref mesh2D() or @ref mesh3D() +- @ref MeshData::importerState() can expose importer state for a mesh + imported by @ref mesh() - @ref ObjectData3D::importerState() can expose importer state for an object imported by @ref object2D() or @ref object3D() - @ref SceneData::importerState() can expose importer state for a scene @@ -650,6 +650,40 @@ class MAGNUM_TRADE_EXPORT AbstractImporter: public PluginManager::AbstractManagi */ Containers::Pointer object3D(UnsignedInt id); + /** + * @brief Mesh count + * + * Expects that a file is opened. + */ + UnsignedInt meshCount() const; + + /** + * @brief Mesh ID for given name + * + * If no mesh for given name exists, returns @cpp -1 @ce. Expects that + * a file is opened. + * @see @ref meshName() + */ + Int meshForName(const std::string& name); + + /** + * @brief Mesh name + * @param id Mesh ID, from range [0, @ref meshCount()). + * + * Expects that a file is opened. + * @see @ref meshForName() + */ + std::string meshName(UnsignedInt id); + + /** + * @brief Mesh + * @param id Mesh ID, from range [0, @ref meshCount()). + * + * Returns given mesh or @ref Containers::NullOpt if importing failed. + * Expects that a file is opened. + */ + Containers::Optional mesh(UnsignedInt id); + /** * @brief Two-dimensional mesh count * @@ -1097,6 +1131,30 @@ class MAGNUM_TRADE_EXPORT AbstractImporter: public PluginManager::AbstractManagi /** @brief Implementation for @ref object3D() */ virtual Containers::Pointer doObject3D(UnsignedInt id); + /** + * @brief Implementation for @ref meshCount() + * + * Default implementation returns @cpp 0 @ce. + */ + virtual UnsignedInt doMeshCount() const; + + /** + * @brief Implementation for @ref meshForName() + * + * Default implementation returns @cpp -1 @ce. + */ + virtual Int doMeshForName(const std::string& name); + + /** + * @brief Implementation for @ref meshName() + * + * Default implementation returns empty string. + */ + virtual std::string doMeshName(UnsignedInt id); + + /** @brief Implementation for @ref mesh() */ + virtual Containers::Optional doMesh(UnsignedInt id); + /** * @brief Implementation for @ref mesh2DCount() * diff --git a/src/Magnum/Trade/Test/AbstractImporterTest.cpp b/src/Magnum/Trade/Test/AbstractImporterTest.cpp index e8415339e6..ce3c64b16e 100644 --- a/src/Magnum/Trade/Test/AbstractImporterTest.cpp +++ b/src/Magnum/Trade/Test/AbstractImporterTest.cpp @@ -37,6 +37,7 @@ #include "Magnum/Trade/CameraData.h" #include "Magnum/Trade/ImageData.h" #include "Magnum/Trade/LightData.h" +#include "Magnum/Trade/MeshData.h" #include "Magnum/Trade/MeshData2D.h" #include "Magnum/Trade/MeshData3D.h" #include "Magnum/Trade/MeshObjectData2D.h" @@ -156,6 +157,18 @@ struct AbstractImporterTest: TestSuite::Tester { void object3DNoFile(); void object3DOutOfRange(); + void mesh(); + void meshCountNotImplemented(); + void meshCountNoFile(); + void meshForNameNotImplemented(); + void meshForNameNoFile(); + void meshNameNotImplemented(); + void meshNameNoFile(); + void meshNameOutOfRange(); + void meshNotImplemented(); + void meshNoFile(); + void meshOutOfRange(); + void mesh2D(); void mesh2DCountNotImplemented(); void mesh2DCountNoFile(); @@ -356,6 +369,18 @@ AbstractImporterTest::AbstractImporterTest() { &AbstractImporterTest::object3DNoFile, &AbstractImporterTest::object3DOutOfRange, + &AbstractImporterTest::mesh, + &AbstractImporterTest::meshCountNotImplemented, + &AbstractImporterTest::meshCountNoFile, + &AbstractImporterTest::meshForNameNotImplemented, + &AbstractImporterTest::meshForNameNoFile, + &AbstractImporterTest::meshNameNotImplemented, + &AbstractImporterTest::meshNameNoFile, + &AbstractImporterTest::meshNameOutOfRange, + &AbstractImporterTest::meshNotImplemented, + &AbstractImporterTest::meshNoFile, + &AbstractImporterTest::meshOutOfRange, + &AbstractImporterTest::mesh2D, &AbstractImporterTest::mesh2DCountNotImplemented, &AbstractImporterTest::mesh2DCountNoFile, @@ -2019,6 +2044,175 @@ void AbstractImporterTest::object3DOutOfRange() { CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::object3D(): index 8 out of range for 8 entries\n"); } +void AbstractImporterTest::mesh() { + struct: AbstractImporter { + Features doFeatures() const override { return {}; } + bool doIsOpened() const override { return true; } + void doClose() override {} + + UnsignedInt doMeshCount() const override { return 8; } + Int doMeshForName(const std::string& name) override { + if(name == "eighth") return 7; + else return -1; + } + std::string doMeshName(UnsignedInt id) override { + if(id == 7) return "eighth"; + else return {}; + } + Containers::Optional doMesh(UnsignedInt id) override { + if(id == 7) return MeshData{{}, {}, &state}; + else return {}; + } + } importer; + + std::ostringstream out; + Error redirectError{&out}; + + CORRADE_COMPARE(importer.meshCount(), 8); + CORRADE_COMPARE(importer.meshForName("eighth"), 7); + CORRADE_COMPARE(importer.meshName(7), "eighth"); + + auto data = importer.mesh(7); + CORRADE_VERIFY(data); + CORRADE_COMPARE(data->importerState(), &state); +} + +void AbstractImporterTest::meshCountNotImplemented() { + struct: AbstractImporter { + Features doFeatures() const override { return {}; } + bool doIsOpened() const override { return true; } + void doClose() override {} + } importer; + + CORRADE_COMPARE(importer.meshCount(), 0); +} + +void AbstractImporterTest::meshCountNoFile() { + struct: AbstractImporter { + Features doFeatures() const override { return {}; } + bool doIsOpened() const override { return false; } + void doClose() override {} + } importer; + + std::ostringstream out; + Error redirectError{&out}; + + importer.meshCount(); + CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::meshCount(): no file opened\n"); +} + +void AbstractImporterTest::meshForNameNotImplemented() { + struct: AbstractImporter { + Features doFeatures() const override { return {}; } + bool doIsOpened() const override { return true; } + void doClose() override {} + } importer; + + CORRADE_COMPARE(importer.meshForName(""), -1); +} + +void AbstractImporterTest::meshForNameNoFile() { + struct: AbstractImporter { + Features doFeatures() const override { return {}; } + bool doIsOpened() const override { return false; } + void doClose() override {} + } importer; + + std::ostringstream out; + Error redirectError{&out}; + + importer.meshForName(""); + CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::meshForName(): no file opened\n"); +} + +void AbstractImporterTest::meshNameNotImplemented() { + struct: AbstractImporter { + Features doFeatures() const override { return {}; } + bool doIsOpened() const override { return true; } + void doClose() override {} + + UnsignedInt doMeshCount() const override { return 8; } + } importer; + + CORRADE_COMPARE(importer.meshName(7), ""); +} + +void AbstractImporterTest::meshNameNoFile() { + struct: AbstractImporter { + Features doFeatures() const override { return {}; } + bool doIsOpened() const override { return false; } + void doClose() override {} + } importer; + + std::ostringstream out; + Error redirectError{&out}; + + importer.meshName(42); + CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::meshName(): no file opened\n"); +} + +void AbstractImporterTest::meshNameOutOfRange() { + struct: AbstractImporter { + Features doFeatures() const override { return {}; } + bool doIsOpened() const override { return true; } + void doClose() override {} + + UnsignedInt doMeshCount() const override { return 8; } + } importer; + + std::ostringstream out; + Error redirectError{&out}; + + importer.meshName(8); + CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::meshName(): index 8 out of range for 8 entries\n"); +} + +void AbstractImporterTest::meshNotImplemented() { + struct: AbstractImporter { + Features doFeatures() const override { return {}; } + bool doIsOpened() const override { return true; } + void doClose() override {} + + UnsignedInt doMeshCount() const override { return 8; } + } importer; + + std::ostringstream out; + Error redirectError{&out}; + + importer.mesh(7); + CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::mesh(): not implemented\n"); +} + +void AbstractImporterTest::meshNoFile() { + struct: AbstractImporter { + Features doFeatures() const override { return {}; } + bool doIsOpened() const override { return false; } + void doClose() override {} + } importer; + + std::ostringstream out; + Error redirectError{&out}; + + importer.mesh(42); + CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::mesh(): no file opened\n"); +} + +void AbstractImporterTest::meshOutOfRange() { + struct: AbstractImporter { + Features doFeatures() const override { return {}; } + bool doIsOpened() const override { return true; } + void doClose() override {} + + UnsignedInt doMeshCount() const override { return 8; } + } importer; + + std::ostringstream out; + Error redirectError{&out}; + + importer.mesh(8); + CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::mesh(): index 8 out of range for 8 entries\n"); +} + void AbstractImporterTest::mesh2D() { struct: AbstractImporter { Features doFeatures() const override { return {}; }