From f9844bbf04b19da1cc8bcdae2ebac3c53f023f1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Tue, 27 Aug 2019 08:31:57 +0200 Subject: [PATCH] [wip] Trade: support mip levels in image import. There's a new level option in each imageND() API, plus an imageNDLevelCount() query to get image level count. TODO: changelog entry TODO: update all plugins --- src/Magnum/Trade/AbstractImporter.cpp | 89 +++++- src/Magnum/Trade/AbstractImporter.h | 88 ++++- .../Trade/Test/AbstractImporterTest.cpp | 300 ++++++++++++++++-- .../AnyImageImporter/AnyImageImporter.cpp | 6 +- .../AnyImageImporter/AnyImageImporter.h | 3 +- .../AnySceneImporter/AnySceneImporter.cpp | 11 +- .../AnySceneImporter/AnySceneImporter.h | 9 +- src/MagnumPlugins/ObjImporter/ObjImporter.cpp | 2 +- src/MagnumPlugins/TgaImporter/TgaImporter.cpp | 4 +- src/MagnumPlugins/TgaImporter/TgaImporter.h | 2 +- 10 files changed, 461 insertions(+), 53 deletions(-) diff --git a/src/Magnum/Trade/AbstractImporter.cpp b/src/Magnum/Trade/AbstractImporter.cpp index 5238df0278..3254374f91 100644 --- a/src/Magnum/Trade/AbstractImporter.cpp +++ b/src/Magnum/Trade/AbstractImporter.cpp @@ -52,7 +52,7 @@ namespace Magnum { namespace Trade { std::string AbstractImporter::pluginInterface() { - return "cz.mosra.magnum.Trade.AbstractImporter/0.3"; + return "cz.mosra.magnum.Trade.AbstractImporter/0.3.1"; } #ifndef CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT @@ -535,6 +535,14 @@ UnsignedInt AbstractImporter::image1DCount() const { UnsignedInt AbstractImporter::doImage1DCount() const { return 0; } +UnsignedInt AbstractImporter::image1DLevelCount(const UnsignedInt id) { + CORRADE_ASSERT(isOpened(), "Trade::AbstractImporter::image1DLevelCount(): no file opened", {}); + CORRADE_ASSERT(id < doImage1DCount(), "Trade::AbstractImporter::image1DLevelCount(): index out of range", {}); + return doImage1DLevelCount(id); +} + +UnsignedInt AbstractImporter::doImage1DLevelCount(UnsignedInt) { return 1; } + Int AbstractImporter::image1DForName(const std::string& name) { CORRADE_ASSERT(isOpened(), "Trade::AbstractImporter::image1DForName(): no file opened", {}); return doImage1DForName(name); @@ -550,13 +558,28 @@ std::string AbstractImporter::image1DName(const UnsignedInt id) { std::string AbstractImporter::doImage1DName(UnsignedInt) { return {}; } -Containers::Optional AbstractImporter::image1D(const UnsignedInt id) { +Containers::Optional AbstractImporter::image1D(const UnsignedInt id, const UnsignedInt level) { CORRADE_ASSERT(isOpened(), "Trade::AbstractImporter::image1D(): no file opened", {}); CORRADE_ASSERT(id < doImage1DCount(), "Trade::AbstractImporter::image1D(): index out of range", {}); - return doImage1D(id); + #ifndef CORRADE_NO_ASSERT + /* Check that non-trivial level is in bounds, failing the import instead of + asserting if the reported level count is zero (indicating an error). + Doing this only if assertions are enabled -- with assertions disabled + (and sane importer implementation), the importer failure happens inside + doImage1D() instead, giving consistent result in both cases. */ + if(level) { + const UnsignedInt levelCount = doImage1DLevelCount(id); + if(!levelCount) { + Error{} << "Trade::AbstractImporter::image1D(): image reported zero levels"; + return {}; + } + CORRADE_ASSERT(level < levelCount, "Trade::AbstractImporter::image1D(): level out of range", {}); + } + #endif + return doImage1D(id, level); } -Containers::Optional AbstractImporter::doImage1D(UnsignedInt) { +Containers::Optional AbstractImporter::doImage1D(UnsignedInt, UnsignedInt) { CORRADE_ASSERT(false, "Trade::AbstractImporter::image1D(): not implemented", {}); } @@ -567,6 +590,14 @@ UnsignedInt AbstractImporter::image2DCount() const { UnsignedInt AbstractImporter::doImage2DCount() const { return 0; } +UnsignedInt AbstractImporter::image2DLevelCount(const UnsignedInt id) { + CORRADE_ASSERT(isOpened(), "Trade::AbstractImporter::image2DLevelCount(): no file opened", {}); + CORRADE_ASSERT(id < doImage2DCount(), "Trade::AbstractImporter::image2DLevelCount(): index out of range", {}); + return doImage2DLevelCount(id); +} + +UnsignedInt AbstractImporter::doImage2DLevelCount(UnsignedInt) { return 1; } + Int AbstractImporter::image2DForName(const std::string& name) { CORRADE_ASSERT(isOpened(), "Trade::AbstractImporter::image2DForName(): no file opened", {}); return doImage2DForName(name); @@ -582,13 +613,28 @@ std::string AbstractImporter::image2DName(const UnsignedInt id) { std::string AbstractImporter::doImage2DName(UnsignedInt) { return {}; } -Containers::Optional AbstractImporter::image2D(const UnsignedInt id) { +Containers::Optional AbstractImporter::image2D(const UnsignedInt id, const UnsignedInt level) { CORRADE_ASSERT(isOpened(), "Trade::AbstractImporter::image2D(): no file opened", {}); CORRADE_ASSERT(id < doImage2DCount(), "Trade::AbstractImporter::image2D(): index out of range", {}); - return doImage2D(id); + #ifndef CORRADE_NO_ASSERT + /* Check that non-trivial level is in bounds, failing the import instead of + asserting if the reported level count is zero (indicating an error). + Doing this only if assertions are enabled -- with assertions disabled + (and sane importer implementation), the importer failure happens inside + doImage1D() instead, giving consistent result in both cases. */ + if(level) { + const UnsignedInt levelCount = doImage2DLevelCount(id); + if(!levelCount) { + Error{} << "Trade::AbstractImporter::image2D(): image reported zero levels"; + return {}; + } + CORRADE_ASSERT(level < levelCount, "Trade::AbstractImporter::image2D(): level out of range", {}); + } + #endif + return doImage2D(id, level); } -Containers::Optional AbstractImporter::doImage2D(UnsignedInt) { +Containers::Optional AbstractImporter::doImage2D(UnsignedInt, UnsignedInt) { CORRADE_ASSERT(false, "Trade::AbstractImporter::image2D(): not implemented", {}); } @@ -599,6 +645,14 @@ UnsignedInt AbstractImporter::image3DCount() const { UnsignedInt AbstractImporter::doImage3DCount() const { return 0; } +UnsignedInt AbstractImporter::image3DLevelCount(const UnsignedInt id) { + CORRADE_ASSERT(isOpened(), "Trade::AbstractImporter::image3DLevelCount(): no file opened", {}); + CORRADE_ASSERT(id < doImage3DCount(), "Trade::AbstractImporter::image3DLevelCount(): index out of range", {}); + return doImage3DLevelCount(id); +} + +UnsignedInt AbstractImporter::doImage3DLevelCount(UnsignedInt) { return 1; } + Int AbstractImporter::image3DForName(const std::string& name) { CORRADE_ASSERT(isOpened(), "Trade::AbstractImporter::image3DForName(): no file opened", {}); return doImage3DForName(name); @@ -614,13 +668,28 @@ std::string AbstractImporter::image3DName(const UnsignedInt id) { std::string AbstractImporter::doImage3DName(UnsignedInt) { return {}; } -Containers::Optional AbstractImporter::image3D(const UnsignedInt id) { +Containers::Optional AbstractImporter::image3D(const UnsignedInt id, const UnsignedInt level) { CORRADE_ASSERT(isOpened(), "Trade::AbstractImporter::image3D(): no file opened", {}); CORRADE_ASSERT(id < doImage3DCount(), "Trade::AbstractImporter::image3D(): index out of range", {}); - return doImage3D(id); + #ifndef CORRADE_NO_ASSERT + /* Check that non-trivial level is in bounds, failing the import instead of + asserting if the reported level count is zero (indicating an error). + Doing this only if assertions are enabled -- with assertions disabled + (and sane importer implementation), the importer failure happens inside + doImage3D() instead, giving consistent result in both cases. */ + if(level) { + const UnsignedInt levelCount = doImage3DLevelCount(id); + if(!levelCount) { + Error{} << "Trade::AbstractImporter::image3D(): image reported zero levels"; + return {}; + } + CORRADE_ASSERT(level < levelCount, "Trade::AbstractImporter::image3D(): level out of range", {}); + } + #endif + return doImage3D(id, level); } -Containers::Optional AbstractImporter::doImage3D(UnsignedInt) { +Containers::Optional AbstractImporter::doImage3D(UnsignedInt, UnsignedInt) { CORRADE_ASSERT(false, "Trade::AbstractImporter::image3D(): not implemented", {}); } diff --git a/src/Magnum/Trade/AbstractImporter.h b/src/Magnum/Trade/AbstractImporter.h index 0c9bb3662f..242283894b 100644 --- a/src/Magnum/Trade/AbstractImporter.h +++ b/src/Magnum/Trade/AbstractImporter.h @@ -181,7 +181,7 @@ checked by the implementation: - All `do*()` implementations working on an opened file are called only if there is any file opened. - All `do*()` implementations taking data ID as parameter are called only if - the ID is from valid range. + the IDs are from valid range. @attention @ref Corrade::Containers::Array instances returned from the plugin @@ -234,7 +234,7 @@ class MAGNUM_TRADE_EXPORT AbstractImporter: public PluginManager::AbstractManagi * @brief Plugin interface * * @code{.cpp} - * "cz.mosra.magnum.Trade.AbstractImporter/0.3" + * "cz.mosra.magnum.Trade.AbstractImporter/0.3.1" * @endcode */ static std::string pluginInterface(); @@ -762,9 +762,19 @@ class MAGNUM_TRADE_EXPORT AbstractImporter: public PluginManager::AbstractManagi * @brief One-dimensional image count * * Expects that a file is opened. + * @see @ref image1DLevelCount() */ UnsignedInt image1DCount() const; + /** + * @brief One-dimensional image mip level count + * @param id Image ID, from range [0, @ref image1DCount()) + * + * Returns at least one level in successful cases, zero on failure. + * Expects that a file is opened. + */ + UnsignedInt image1DLevelCount(UnsignedInt id); + /** * @brief One-dimensional image ID for given name * @@ -786,19 +796,34 @@ class MAGNUM_TRADE_EXPORT AbstractImporter: public PluginManager::AbstractManagi /** * @brief One-dimensional image * @param id Image ID, from range [0, @ref image1DCount()). + * @param level Mip level, from range [0, @ref image1DLevelCount()) * * Returns given image or @ref Containers::NullOpt if importing failed. - * Expects that a file is opened. + * Expects that a file is opened. Non-zero @p level values are checked + * against @ref image1DLevelCount() unless Magnum is built with + * @ref CORRADE_NO_ASSERT. If reported level count is zero, this + * function returns @ref Containers::NullOpt as well, indicating + * an import error. */ - Containers::Optional image1D(UnsignedInt id); + Containers::Optional image1D(UnsignedInt id, UnsignedInt level = 0); /** * @brief Two-dimensional image count * * Expects that a file is opened. + * @see @ref image2DLevelCount() */ UnsignedInt image2DCount() const; + /** + * @brief Two-dimensional image mip level count + * @param id Image ID, from range [0, @ref image2DCount()). + * + * Returns at least one level in successful cases, zero on failure. + * Expects that a file is opened. + */ + UnsignedInt image2DLevelCount(UnsignedInt id); + /** * @brief Two-dimensional image ID for given name * @@ -820,19 +845,34 @@ class MAGNUM_TRADE_EXPORT AbstractImporter: public PluginManager::AbstractManagi /** * @brief Two-dimensional image * @param id Image ID, from range [0, @ref image2DCount()). + * @param level Mip level, from range [0, @ref image2DLevelCount()) * * Returns given image or @ref Containers::NullOpt if importing failed. - * Expects that a file is opened. + * Expects that a file is opened. Non-zero @p level values are checked + * against @ref image2DLevelCount() unless Magnum is built with + * @ref CORRADE_NO_ASSERT. If reported level count is zero, this + * function returns @ref Containers::NullOpt as well, indicating + * an import error. */ - Containers::Optional image2D(UnsignedInt id); + Containers::Optional image2D(UnsignedInt id, UnsignedInt level = 0); /** * @brief Three-dimensional image count * * Expects that a file is opened. + * @see @ref image3DLevelCount() */ UnsignedInt image3DCount() const; + /** + * @brief Three-dimensional image mip level count + * @param id Image ID, from range [0, @ref image3DCount()) + * + * Returns at least one level in successful cases, zero on failure. + * Expects that a file is opened. + */ + UnsignedInt image3DLevelCount(UnsignedInt id); + /** * @brief Three-dimensional image ID for given name * @@ -854,11 +894,16 @@ class MAGNUM_TRADE_EXPORT AbstractImporter: public PluginManager::AbstractManagi /** * @brief Three-dimensional image * @param id Image ID, from range [0, @ref image3DCount()). + * @param level Mip level, from range [0, @ref image3DLevelCount()) * * Returns given image or @ref Containers::NullOpt if importing failed. - * Expects that a file is opened. + * Expects that a file is opened. Non-zero @p level values are checked + * against @ref image3DLevelCount() unless Magnum is built with + * @ref CORRADE_NO_ASSERT. If reported level count is zero, this + * function returns @ref Containers::NullOpt as well, indicating + * an import error. */ - Containers::Optional image3D(UnsignedInt id); + Containers::Optional image3D(UnsignedInt id, UnsignedInt level = 0); /*@}*/ @@ -1176,6 +1221,13 @@ class MAGNUM_TRADE_EXPORT AbstractImporter: public PluginManager::AbstractManagi */ virtual UnsignedInt doImage1DCount() const; + /** + * @brief Implementation for @ref image1DLevelCount() + * + * Default implementation returns @cpp 1 @ce. + */ + virtual UnsignedInt doImage1DLevelCount(UnsignedInt id); + /** * @brief Implementation for @ref image1DForName() * @@ -1191,7 +1243,7 @@ class MAGNUM_TRADE_EXPORT AbstractImporter: public PluginManager::AbstractManagi virtual std::string doImage1DName(UnsignedInt id); /** @brief Implementation for @ref image1D() */ - virtual Containers::Optional doImage1D(UnsignedInt id); + virtual Containers::Optional doImage1D(UnsignedInt id, UnsignedInt level); /** * @brief Implementation for @ref image2DCount() @@ -1200,6 +1252,13 @@ class MAGNUM_TRADE_EXPORT AbstractImporter: public PluginManager::AbstractManagi */ virtual UnsignedInt doImage2DCount() const; + /** + * @brief Implementation for @ref image2DLevelCount() + * + * Default implementation returns @cpp 1 @ce. + */ + virtual UnsignedInt doImage2DLevelCount(UnsignedInt id); + /** * @brief Implementation for @ref image2DForName() * @@ -1215,7 +1274,7 @@ class MAGNUM_TRADE_EXPORT AbstractImporter: public PluginManager::AbstractManagi virtual std::string doImage2DName(UnsignedInt id); /** @brief Implementation for @ref image2D() */ - virtual Containers::Optional doImage2D(UnsignedInt id); + virtual Containers::Optional doImage2D(UnsignedInt id, UnsignedInt level); /** * @brief Implementation for @ref image3DCount() @@ -1224,6 +1283,13 @@ class MAGNUM_TRADE_EXPORT AbstractImporter: public PluginManager::AbstractManagi */ virtual UnsignedInt doImage3DCount() const; + /** + * @brief Implementation for @ref image3DLevelCount() + * + * Default implementation returns @cpp 1 @ce. + */ + virtual UnsignedInt doImage3DLevelCount(UnsignedInt id); + /** * @brief Implementation for @ref image3DForName() * @@ -1239,7 +1305,7 @@ class MAGNUM_TRADE_EXPORT AbstractImporter: public PluginManager::AbstractManagi virtual std::string doImage3DName(UnsignedInt id); /** @brief Implementation for @ref image3D() */ - virtual Containers::Optional doImage3D(UnsignedInt id); + virtual Containers::Optional doImage3D(UnsignedInt id, UnsignedInt level); /** @brief Implementation for @ref importerState() */ virtual const void* doImporterState() const; diff --git a/src/Magnum/Trade/Test/AbstractImporterTest.cpp b/src/Magnum/Trade/Test/AbstractImporterTest.cpp index 2947678984..b7cee4eac3 100644 --- a/src/Magnum/Trade/Test/AbstractImporterTest.cpp +++ b/src/Magnum/Trade/Test/AbstractImporterTest.cpp @@ -204,6 +204,9 @@ struct AbstractImporterTest: TestSuite::Tester { void image1D(); void image1DCountNotImplemented(); void image1DCountNoFile(); + void image1DLevelCountNotImplemented(); + void image1DLevelCountNoFile(); + void image1DLevelCountZero(); void image1DForNameNotImplemented(); void image1DForNameNoFile(); void image1DNameNotImplemented(); @@ -212,10 +215,15 @@ struct AbstractImporterTest: TestSuite::Tester { void image1DNotImplemented(); void image1DNoFile(); void image1DOutOfRange(); + void image1DZeroLevelsReported(); + void image1DLevelOutOfRange(); void image2D(); void image2DCountNotImplemented(); void image2DCountNoFile(); + void image2DLevelCountNotImplemented(); + void image2DLevelCountNoFile(); + void image2DLevelCountZero(); void image2DForNameNotImplemented(); void image2DForNameNoFile(); void image2DNameNotImplemented(); @@ -224,10 +232,15 @@ struct AbstractImporterTest: TestSuite::Tester { void image2DNotImplemented(); void image2DNoFile(); void image2DOutOfRange(); + void image2DZeroLevelsReported(); + void image2DLevelOutOfRange(); void image3D(); void image3DCountNotImplemented(); void image3DCountNoFile(); + void image3DLevelCountNotImplemented(); + void image3DLevelCountNoFile(); + void image3DLevelCountZero(); void image3DForNameNotImplemented(); void image3DForNameNoFile(); void image3DNameNotImplemented(); @@ -236,6 +249,8 @@ struct AbstractImporterTest: TestSuite::Tester { void image3DNotImplemented(); void image3DNoFile(); void image3DOutOfRange(); + void image3DZeroLevelsReported(); + void image3DLevelOutOfRange(); void importerState(); void importerStateNotImplemented(); @@ -399,6 +414,9 @@ AbstractImporterTest::AbstractImporterTest() { &AbstractImporterTest::image1D, &AbstractImporterTest::image1DCountNotImplemented, &AbstractImporterTest::image1DCountNoFile, + &AbstractImporterTest::image1DLevelCountNotImplemented, + &AbstractImporterTest::image1DLevelCountNoFile, + &AbstractImporterTest::image1DLevelCountZero, &AbstractImporterTest::image1DForNameNotImplemented, &AbstractImporterTest::image1DForNameNoFile, &AbstractImporterTest::image1DNameNotImplemented, @@ -407,10 +425,15 @@ AbstractImporterTest::AbstractImporterTest() { &AbstractImporterTest::image1DNotImplemented, &AbstractImporterTest::image1DNoFile, &AbstractImporterTest::image1DOutOfRange, + &AbstractImporterTest::image1DZeroLevelsReported, + &AbstractImporterTest::image1DLevelOutOfRange, &AbstractImporterTest::image2D, &AbstractImporterTest::image2DCountNotImplemented, &AbstractImporterTest::image2DCountNoFile, + &AbstractImporterTest::image2DLevelCountNotImplemented, + &AbstractImporterTest::image2DLevelCountNoFile, + &AbstractImporterTest::image2DLevelCountZero, &AbstractImporterTest::image2DForNameNotImplemented, &AbstractImporterTest::image2DForNameNoFile, &AbstractImporterTest::image2DNameNotImplemented, @@ -419,10 +442,15 @@ AbstractImporterTest::AbstractImporterTest() { &AbstractImporterTest::image2DNotImplemented, &AbstractImporterTest::image2DNoFile, &AbstractImporterTest::image2DOutOfRange, + &AbstractImporterTest::image2DZeroLevelsReported, + &AbstractImporterTest::image2DLevelOutOfRange, &AbstractImporterTest::image3D, &AbstractImporterTest::image3DCountNotImplemented, &AbstractImporterTest::image3DCountNoFile, + &AbstractImporterTest::image3DLevelCountNotImplemented, + &AbstractImporterTest::image3DLevelCountNoFile, + &AbstractImporterTest::image3DLevelCountZero, &AbstractImporterTest::image3DForNameNotImplemented, &AbstractImporterTest::image3DForNameNoFile, &AbstractImporterTest::image3DNameNotImplemented, @@ -431,6 +459,8 @@ AbstractImporterTest::AbstractImporterTest() { &AbstractImporterTest::image3DNotImplemented, &AbstractImporterTest::image3DNoFile, &AbstractImporterTest::image3DOutOfRange, + &AbstractImporterTest::image3DZeroLevelsReported, + &AbstractImporterTest::image3DLevelOutOfRange, &AbstractImporterTest::importerState, &AbstractImporterTest::importerStateNotImplemented, @@ -2613,6 +2643,10 @@ void AbstractImporterTest::image1D() { void doClose() override {} UnsignedInt doImage1DCount() const override { return 8; } + UnsignedInt doImage1DLevelCount(UnsignedInt id) override { + if(id == 7) return 3; + else return {}; + } Int doImage1DForName(const std::string& name) override { if(name == "eighth") return 7; else return -1; @@ -2621,20 +2655,18 @@ void AbstractImporterTest::image1D() { if(id == 7) return "eighth"; else return {}; } - Containers::Optional doImage1D(UnsignedInt id) override { - if(id == 7) return ImageData1D{PixelStorage{}, {}, {}, {}, &state}; + Containers::Optional doImage1D(UnsignedInt id, UnsignedInt level) override { + if(id == 7 && level == 2) return ImageData1D{PixelStorage{}, {}, {}, {}, &state}; else return {}; } } importer; - std::ostringstream out; - Error redirectError{&out}; - CORRADE_COMPARE(importer.image1DCount(), 8); + CORRADE_COMPARE(importer.image1DLevelCount(7), 3); CORRADE_COMPARE(importer.image1DForName("eighth"), 7); CORRADE_COMPARE(importer.image1DName(7), "eighth"); - auto data = importer.image1D(7); + auto data = importer.image1D(7, 2); CORRADE_VERIFY(data); CORRADE_COMPARE(data->importerState(), &state); } @@ -2663,6 +2695,46 @@ void AbstractImporterTest::image1DCountNoFile() { CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::image1DCount(): no file opened\n"); } +void AbstractImporterTest::image1DLevelCountNotImplemented() { + struct: AbstractImporter { + Features doFeatures() const override { return {}; } + bool doIsOpened() const override { return true; } + void doClose() override {} + + UnsignedInt doImage1DCount() const override { return 8; } + } importer; + + CORRADE_COMPARE(importer.image1DLevelCount(7), 1); +} + +void AbstractImporterTest::image1DLevelCountNoFile() { + struct: AbstractImporter { + Features doFeatures() const override { return {}; } + bool doIsOpened() const override { return false; } + void doClose() override {} + } importer; + + std::ostringstream out; + Error redirectError{&out}; + + importer.image1DLevelCount(7); + CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::image1DLevelCount(): no file opened\n"); +} + +void AbstractImporterTest::image1DLevelCountZero() { + struct: AbstractImporter { + Features doFeatures() const override { return {}; } + bool doIsOpened() const override { return true; } + void doClose() override {} + + UnsignedInt doImage1DCount() const override { return 8; } + UnsignedInt doImage1DLevelCount(UnsignedInt) override { return 0; } + } importer; + + /* This indicates an import error, no assertions should be fired */ + CORRADE_COMPARE(importer.image1DLevelCount(7), 0); +} + void AbstractImporterTest::image1DForNameNotImplemented() { struct: AbstractImporter { Features doFeatures() const override { return {}; } @@ -2771,6 +2843,42 @@ void AbstractImporterTest::image1DOutOfRange() { CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::image1D(): index out of range\n"); } +void AbstractImporterTest::image1DZeroLevelsReported() { + struct: AbstractImporter { + Features doFeatures() const override { return {}; } + bool doIsOpened() const override { return true; } + void doClose() override {} + + UnsignedInt doImage1DCount() const override { return 8; } + UnsignedInt doImage1DLevelCount(UnsignedInt) override { return 0; } + } importer; + + std::ostringstream out; + Error redirectError{&out}; + + importer.image1D(7); /* this calls doImage() as level == 0, then asserts */ + CORRADE_VERIFY(!importer.image1D(7, 1)); /* this returns NullOpt */ + CORRADE_COMPARE(out.str(), + "Trade::AbstractImporter::image1D(): not implemented\n" + "Trade::AbstractImporter::image1D(): image reported zero levels\n"); +} + +void AbstractImporterTest::image1DLevelOutOfRange() { + struct: AbstractImporter { + Features doFeatures() const override { return {}; } + bool doIsOpened() const override { return true; } + void doClose() override {} + + UnsignedInt doImage1DCount() const override { return 8; } + } importer; + + std::ostringstream out; + Error redirectError{&out}; + + importer.image1D(7, 1); + CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::image1D(): level out of range\n"); +} + void AbstractImporterTest::image2D() { struct: AbstractImporter { Features doFeatures() const override { return {}; } @@ -2778,6 +2886,10 @@ void AbstractImporterTest::image2D() { void doClose() override {} UnsignedInt doImage2DCount() const override { return 8; } + UnsignedInt doImage2DLevelCount(UnsignedInt id) override { + if(id == 7) return 3; + else return {}; + } Int doImage2DForName(const std::string& name) override { if(name == "eighth") return 7; else return -1; @@ -2786,20 +2898,18 @@ void AbstractImporterTest::image2D() { if(id == 7) return "eighth"; else return {}; } - Containers::Optional doImage2D(UnsignedInt id) override { - if(id == 7) return ImageData2D{PixelStorage{}, {}, {}, {}, &state}; + Containers::Optional doImage2D(UnsignedInt id, UnsignedInt level) override { + if(id == 7 && level == 2) return ImageData2D{PixelStorage{}, {}, {}, {}, &state}; else return {}; } } importer; - std::ostringstream out; - Error redirectError{&out}; - CORRADE_COMPARE(importer.image2DCount(), 8); + CORRADE_COMPARE(importer.image2DLevelCount(7), 3); CORRADE_COMPARE(importer.image2DForName("eighth"), 7); CORRADE_COMPARE(importer.image2DName(7), "eighth"); - auto data = importer.image2D(7); + auto data = importer.image2D(7, 2); CORRADE_VERIFY(data); CORRADE_COMPARE(data->importerState(), &state); } @@ -2828,6 +2938,46 @@ void AbstractImporterTest::image2DCountNoFile() { CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::image2DCount(): no file opened\n"); } +void AbstractImporterTest::image2DLevelCountNotImplemented() { + struct: AbstractImporter { + Features doFeatures() const override { return {}; } + bool doIsOpened() const override { return true; } + void doClose() override {} + + UnsignedInt doImage2DCount() const override { return 8; } + } importer; + + CORRADE_COMPARE(importer.image2DLevelCount(7), 1); +} + +void AbstractImporterTest::image2DLevelCountNoFile() { + struct: AbstractImporter { + Features doFeatures() const override { return {}; } + bool doIsOpened() const override { return false; } + void doClose() override {} + } importer; + + std::ostringstream out; + Error redirectError{&out}; + + importer.image2DLevelCount(7); + CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::image2DLevelCount(): no file opened\n"); +} + +void AbstractImporterTest::image2DLevelCountZero() { + struct: AbstractImporter { + Features doFeatures() const override { return {}; } + bool doIsOpened() const override { return true; } + void doClose() override {} + + UnsignedInt doImage2DCount() const override { return 8; } + UnsignedInt doImage2DLevelCount(UnsignedInt) override { return 0; } + } importer; + + /* This indicates an import error, no assertions should be fired */ + CORRADE_COMPARE(importer.image2DLevelCount(7), 0); +} + void AbstractImporterTest::image2DForNameNotImplemented() { struct: AbstractImporter { Features doFeatures() const override { return {}; } @@ -2936,6 +3086,42 @@ void AbstractImporterTest::image2DOutOfRange() { CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::image2D(): index out of range\n"); } +void AbstractImporterTest::image2DZeroLevelsReported() { + struct: AbstractImporter { + Features doFeatures() const override { return {}; } + bool doIsOpened() const override { return true; } + void doClose() override {} + + UnsignedInt doImage2DCount() const override { return 8; } + UnsignedInt doImage2DLevelCount(UnsignedInt) override { return 0; } + } importer; + + std::ostringstream out; + Error redirectError{&out}; + + importer.image2D(7); /* this calls doImage() as level == 0, then asserts */ + CORRADE_VERIFY(!importer.image2D(7, 1)); /* this returns NullOpt */ + CORRADE_COMPARE(out.str(), + "Trade::AbstractImporter::image2D(): not implemented\n" + "Trade::AbstractImporter::image2D(): image reported zero levels\n"); +} + +void AbstractImporterTest::image2DLevelOutOfRange() { + struct: AbstractImporter { + Features doFeatures() const override { return {}; } + bool doIsOpened() const override { return true; } + void doClose() override {} + + UnsignedInt doImage2DCount() const override { return 8; } + } importer; + + std::ostringstream out; + Error redirectError{&out}; + + importer.image2D(7, 1); + CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::image2D(): level out of range\n"); +} + void AbstractImporterTest::image3D() { struct: AbstractImporter { Features doFeatures() const override { return {}; } @@ -2943,6 +3129,10 @@ void AbstractImporterTest::image3D() { void doClose() override {} UnsignedInt doImage3DCount() const override { return 8; } + UnsignedInt doImage3DLevelCount(UnsignedInt id) override { + if(id == 7) return 3; + else return {}; + } Int doImage3DForName(const std::string& name) override { if(name == "eighth") return 7; else return -1; @@ -2951,20 +3141,18 @@ void AbstractImporterTest::image3D() { if(id == 7) return "eighth"; else return {}; } - Containers::Optional doImage3D(UnsignedInt id) override { - if(id == 7) return ImageData3D{PixelStorage{}, {}, {}, {}, &state}; + Containers::Optional doImage3D(UnsignedInt id, UnsignedInt level) override { + if(id == 7 && level == 2) return ImageData3D{PixelStorage{}, {}, {}, {}, &state}; else return {}; } } importer; - std::ostringstream out; - Error redirectError{&out}; - CORRADE_COMPARE(importer.image3DCount(), 8); + CORRADE_COMPARE(importer.image3DLevelCount(7), 3); CORRADE_COMPARE(importer.image3DForName("eighth"), 7); CORRADE_COMPARE(importer.image3DName(7), "eighth"); - auto data = importer.image3D(7); + auto data = importer.image3D(7, 2); CORRADE_VERIFY(data); CORRADE_COMPARE(data->importerState(), &state); } @@ -2993,6 +3181,46 @@ void AbstractImporterTest::image3DCountNoFile() { CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::image3DCount(): no file opened\n"); } +void AbstractImporterTest::image3DLevelCountNotImplemented() { + struct: AbstractImporter { + Features doFeatures() const override { return {}; } + bool doIsOpened() const override { return true; } + void doClose() override {} + + UnsignedInt doImage3DCount() const override { return 8; } + } importer; + + CORRADE_COMPARE(importer.image3DLevelCount(7), 1); +} + +void AbstractImporterTest::image3DLevelCountNoFile() { + struct: AbstractImporter { + Features doFeatures() const override { return {}; } + bool doIsOpened() const override { return false; } + void doClose() override {} + } importer; + + std::ostringstream out; + Error redirectError{&out}; + + importer.image3DLevelCount(7); + CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::image3DLevelCount(): no file opened\n"); +} + +void AbstractImporterTest::image3DLevelCountZero() { + struct: AbstractImporter { + Features doFeatures() const override { return {}; } + bool doIsOpened() const override { return true; } + void doClose() override {} + + UnsignedInt doImage3DCount() const override { return 8; } + UnsignedInt doImage3DLevelCount(UnsignedInt) override { return 0; } + } importer; + + /* This indicates an import error, no assertions should be fired */ + CORRADE_COMPARE(importer.image3DLevelCount(7), 0); +} + void AbstractImporterTest::image3DForNameNotImplemented() { struct: AbstractImporter { Features doFeatures() const override { return {}; } @@ -3101,6 +3329,42 @@ void AbstractImporterTest::image3DOutOfRange() { CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::image3D(): index out of range\n"); } +void AbstractImporterTest::image3DZeroLevelsReported() { + struct: AbstractImporter { + Features doFeatures() const override { return {}; } + bool doIsOpened() const override { return true; } + void doClose() override {} + + UnsignedInt doImage3DCount() const override { return 8; } + UnsignedInt doImage3DLevelCount(UnsignedInt) override { return 0; } + } importer; + + std::ostringstream out; + Error redirectError{&out}; + + importer.image3D(7); /* this calls doImage() as level == 0, then asserts */ + CORRADE_VERIFY(!importer.image3D(7, 1)); /* this returns NullOpt */ + CORRADE_COMPARE(out.str(), + "Trade::AbstractImporter::image3D(): not implemented\n" + "Trade::AbstractImporter::image3D(): image reported zero levels\n"); +} + +void AbstractImporterTest::image3DLevelOutOfRange() { + struct: AbstractImporter { + Features doFeatures() const override { return {}; } + bool doIsOpened() const override { return true; } + void doClose() override {} + + UnsignedInt doImage3DCount() const override { return 8; } + } importer; + + std::ostringstream out; + Error redirectError{&out}; + + importer.image3D(7, 1); + CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::image3D(): level out of range\n"); +} + void AbstractImporterTest::importerState() { struct: AbstractImporter { Features doFeatures() const override { return {}; } diff --git a/src/MagnumPlugins/AnyImageImporter/AnyImageImporter.cpp b/src/MagnumPlugins/AnyImageImporter/AnyImageImporter.cpp index 797463fbca..6298ac8d84 100644 --- a/src/MagnumPlugins/AnyImageImporter/AnyImageImporter.cpp +++ b/src/MagnumPlugins/AnyImageImporter/AnyImageImporter.cpp @@ -194,9 +194,11 @@ void AnyImageImporter::doOpenData(Containers::ArrayView data) { UnsignedInt AnyImageImporter::doImage2DCount() const { return _in->image2DCount(); } -Containers::Optional AnyImageImporter::doImage2D(const UnsignedInt id) { return _in->image2D(id); } +UnsignedInt AnyImageImporter::doImage2DLevelCount(UnsignedInt id) { return _in->image2DLevelCount(id); } + +Containers::Optional AnyImageImporter::doImage2D(const UnsignedInt id, const UnsignedInt level) { return _in->image2D(id, level); } }} CORRADE_PLUGIN_REGISTER(AnyImageImporter, Magnum::Trade::AnyImageImporter, - "cz.mosra.magnum.Trade.AbstractImporter/0.3") + "cz.mosra.magnum.Trade.AbstractImporter/0.3.1") diff --git a/src/MagnumPlugins/AnyImageImporter/AnyImageImporter.h b/src/MagnumPlugins/AnyImageImporter/AnyImageImporter.h index 403228edc0..09e51a0c37 100644 --- a/src/MagnumPlugins/AnyImageImporter/AnyImageImporter.h +++ b/src/MagnumPlugins/AnyImageImporter/AnyImageImporter.h @@ -121,7 +121,8 @@ class MAGNUM_ANYIMAGEIMPORTER_EXPORT AnyImageImporter: public AbstractImporter { MAGNUM_ANYIMAGEIMPORTER_LOCAL void doOpenData(Containers::ArrayView data) override; MAGNUM_ANYIMAGEIMPORTER_LOCAL UnsignedInt doImage2DCount() const override; - MAGNUM_ANYIMAGEIMPORTER_LOCAL Containers::Optional doImage2D(UnsignedInt id) override; + MAGNUM_ANYIMAGEIMPORTER_LOCAL UnsignedInt doImage2DLevelCount(UnsignedInt id) override; + MAGNUM_ANYIMAGEIMPORTER_LOCAL Containers::Optional doImage2D(UnsignedInt id, UnsignedInt level) override; Containers::Pointer _in; }; diff --git a/src/MagnumPlugins/AnySceneImporter/AnySceneImporter.cpp b/src/MagnumPlugins/AnySceneImporter/AnySceneImporter.cpp index c50cb73bb1..fb5226c58f 100644 --- a/src/MagnumPlugins/AnySceneImporter/AnySceneImporter.cpp +++ b/src/MagnumPlugins/AnySceneImporter/AnySceneImporter.cpp @@ -196,21 +196,24 @@ std::string AnySceneImporter::doTextureName(const UnsignedInt id) { return _in-> Containers::Optional AnySceneImporter::doTexture(const UnsignedInt id) { return _in->texture(id); } UnsignedInt AnySceneImporter::doImage1DCount() const { return _in->image1DCount(); } +UnsignedInt AnySceneImporter::doImage1DLevelCount(UnsignedInt id) { return _in->image1DLevelCount(id); } Int AnySceneImporter::doImage1DForName(const std::string& name) { return _in->image1DForName(name); } std::string AnySceneImporter::doImage1DName(const UnsignedInt id) { return _in->image1DName(id); } -Containers::Optional AnySceneImporter::doImage1D(const UnsignedInt id) { return _in->image1D(id); } +Containers::Optional AnySceneImporter::doImage1D(const UnsignedInt id, const UnsignedInt level) { return _in->image1D(id, level); } UnsignedInt AnySceneImporter::doImage2DCount() const { return _in->image2DCount(); } +UnsignedInt AnySceneImporter::doImage2DLevelCount(UnsignedInt id) { return _in->image2DLevelCount(id); } Int AnySceneImporter::doImage2DForName(const std::string& name) { return _in->image2DForName(name); } std::string AnySceneImporter::doImage2DName(const UnsignedInt id) { return _in->image2DName(id); } -Containers::Optional AnySceneImporter::doImage2D(const UnsignedInt id) { return _in->image2D(id); } +Containers::Optional AnySceneImporter::doImage2D(const UnsignedInt id, const UnsignedInt level) { return _in->image2D(id, level); } UnsignedInt AnySceneImporter::doImage3DCount() const { return _in->image3DCount(); } +UnsignedInt AnySceneImporter::doImage3DLevelCount(UnsignedInt id) { return _in->image3DLevelCount(id); } Int AnySceneImporter::doImage3DForName(const std::string& name) { return _in->image3DForName(name); } std::string AnySceneImporter::doImage3DName(const UnsignedInt id) { return _in->image3DName(id); } -Containers::Optional AnySceneImporter::doImage3D(const UnsignedInt id) { return _in->image3D(id); } +Containers::Optional AnySceneImporter::doImage3D(const UnsignedInt id, const UnsignedInt level) { return _in->image3D(id, level); } }} CORRADE_PLUGIN_REGISTER(AnySceneImporter, Magnum::Trade::AnySceneImporter, - "cz.mosra.magnum.Trade.AbstractImporter/0.3") + "cz.mosra.magnum.Trade.AbstractImporter/0.3.1") diff --git a/src/MagnumPlugins/AnySceneImporter/AnySceneImporter.h b/src/MagnumPlugins/AnySceneImporter/AnySceneImporter.h index fd84f79ea7..7065c07623 100644 --- a/src/MagnumPlugins/AnySceneImporter/AnySceneImporter.h +++ b/src/MagnumPlugins/AnySceneImporter/AnySceneImporter.h @@ -176,19 +176,22 @@ class MAGNUM_ANYSCENEIMPORTER_EXPORT AnySceneImporter: public AbstractImporter { MAGNUM_ANYSCENEIMPORTER_LOCAL Containers::Optional doTexture(UnsignedInt id) override; MAGNUM_ANYSCENEIMPORTER_LOCAL UnsignedInt doImage1DCount() const override; + MAGNUM_ANYSCENEIMPORTER_LOCAL UnsignedInt doImage1DLevelCount(UnsignedInt id) override; MAGNUM_ANYSCENEIMPORTER_LOCAL Int doImage1DForName(const std::string& name) override; MAGNUM_ANYSCENEIMPORTER_LOCAL std::string doImage1DName(UnsignedInt id) override; - MAGNUM_ANYSCENEIMPORTER_LOCAL Containers::Optional doImage1D(UnsignedInt id) override; + MAGNUM_ANYSCENEIMPORTER_LOCAL Containers::Optional doImage1D(UnsignedInt id, UnsignedInt level) override; MAGNUM_ANYSCENEIMPORTER_LOCAL UnsignedInt doImage2DCount() const override; + MAGNUM_ANYSCENEIMPORTER_LOCAL UnsignedInt doImage2DLevelCount(UnsignedInt id) override; MAGNUM_ANYSCENEIMPORTER_LOCAL Int doImage2DForName(const std::string& name) override; MAGNUM_ANYSCENEIMPORTER_LOCAL std::string doImage2DName(UnsignedInt id) override; - MAGNUM_ANYSCENEIMPORTER_LOCAL Containers::Optional doImage2D(UnsignedInt id) override; + MAGNUM_ANYSCENEIMPORTER_LOCAL Containers::Optional doImage2D(UnsignedInt id, UnsignedInt level) override; MAGNUM_ANYSCENEIMPORTER_LOCAL UnsignedInt doImage3DCount() const override; + MAGNUM_ANYSCENEIMPORTER_LOCAL UnsignedInt doImage3DLevelCount(UnsignedInt id) override; MAGNUM_ANYSCENEIMPORTER_LOCAL Int doImage3DForName(const std::string& name) override; MAGNUM_ANYSCENEIMPORTER_LOCAL std::string doImage3DName(UnsignedInt id) override; - MAGNUM_ANYSCENEIMPORTER_LOCAL Containers::Optional doImage3D(UnsignedInt id) override; + MAGNUM_ANYSCENEIMPORTER_LOCAL Containers::Optional doImage3D(UnsignedInt id, UnsignedInt level) override; Containers::Pointer _in; }; diff --git a/src/MagnumPlugins/ObjImporter/ObjImporter.cpp b/src/MagnumPlugins/ObjImporter/ObjImporter.cpp index a5ef336926..998374e127 100644 --- a/src/MagnumPlugins/ObjImporter/ObjImporter.cpp +++ b/src/MagnumPlugins/ObjImporter/ObjImporter.cpp @@ -448,4 +448,4 @@ Containers::Optional ObjImporter::doMesh3D(UnsignedInt id) { }} CORRADE_PLUGIN_REGISTER(ObjImporter, Magnum::Trade::ObjImporter, - "cz.mosra.magnum.Trade.AbstractImporter/0.3") + "cz.mosra.magnum.Trade.AbstractImporter/0.3.1") diff --git a/src/MagnumPlugins/TgaImporter/TgaImporter.cpp b/src/MagnumPlugins/TgaImporter/TgaImporter.cpp index 2e5ed082b9..bd0e096528 100644 --- a/src/MagnumPlugins/TgaImporter/TgaImporter.cpp +++ b/src/MagnumPlugins/TgaImporter/TgaImporter.cpp @@ -71,7 +71,7 @@ void TgaImporter::doOpenData(const Containers::ArrayView data) { UnsignedInt TgaImporter::doImage2DCount() const { return 1; } -Containers::Optional TgaImporter::doImage2D(UnsignedInt) { +Containers::Optional TgaImporter::doImage2D(UnsignedInt, UnsignedInt) { /* Check if the file is long enough */ if(_in.size() < std::streamoff(sizeof(Implementation::TgaHeader))) { Error() << "Trade::TgaImporter::image2D(): the file is too short:" << _in.size() << "bytes"; @@ -149,4 +149,4 @@ Containers::Optional TgaImporter::doImage2D(UnsignedInt) { }} CORRADE_PLUGIN_REGISTER(TgaImporter, Magnum::Trade::TgaImporter, - "cz.mosra.magnum.Trade.AbstractImporter/0.3") + "cz.mosra.magnum.Trade.AbstractImporter/0.3.1") diff --git a/src/MagnumPlugins/TgaImporter/TgaImporter.h b/src/MagnumPlugins/TgaImporter/TgaImporter.h index 5156aa9f5d..b3ee689bbd 100644 --- a/src/MagnumPlugins/TgaImporter/TgaImporter.h +++ b/src/MagnumPlugins/TgaImporter/TgaImporter.h @@ -89,7 +89,7 @@ class MAGNUM_TGAIMPORTER_EXPORT TgaImporter: public AbstractImporter { void MAGNUM_TGAIMPORTER_LOCAL doOpenData(Containers::ArrayView data) override; void MAGNUM_TGAIMPORTER_LOCAL doClose() override; UnsignedInt MAGNUM_TGAIMPORTER_LOCAL doImage2DCount() const override; - Containers::Optional MAGNUM_TGAIMPORTER_LOCAL doImage2D(UnsignedInt id) override; + Containers::Optional MAGNUM_TGAIMPORTER_LOCAL doImage2D(UnsignedInt id, UnsignedInt level) override; Containers::Array _in; };